diff --git a/addons/medical/dev/watchVariable.sqf b/addons/medical/dev/watchVariable.sqf index a0e064595ab..7684c1a17d9 100644 --- a/addons/medical/dev/watchVariable.sqf +++ b/addons/medical/dev/watchVariable.sqf @@ -150,9 +150,8 @@ GVAR(dev_watchVariableRunning) = true; }; _return pushBack format ["Adjusts: [HR %1][PS %2][PR %3]", _hrTargetAdjustment toFixed 2, _painSupressAdjustment toFixed 2, _peripheralResistanceAdjustment toFixed 2]; { - private _medicationCount = [_unit, _x, true] call EFUNC(medical_status,getMedicationCount); - private _medicationEffectiveness = [_unit, _x, false] call EFUNC(medical_status,getMedicationCount); - _return pushBack format ["-%1: C: %2 - E: %3", _x, _medicationCount toFixed 2, _medicationEffectiveness toFixed 2]; + ([_unit, _x, false] call EFUNC(medical_status,getMedicationCount)) params ["_medicationDose", "_medicationEffectiveness"]; + _return pushBack format ["-%1: D: %2 - E: %3", _x, _medicationDose toFixed 2, _medicationEffectiveness toFixed 2]; } forEach _uniqueMedications; _return pushBack "------- Medications Raw: -------"; _return append _rawMedications; diff --git a/addons/medical_statemachine/functions/fnc_handleStateUnconscious.sqf b/addons/medical_statemachine/functions/fnc_handleStateUnconscious.sqf index aa93d449329..a9a20ec91c7 100644 --- a/addons/medical_statemachine/functions/fnc_handleStateUnconscious.sqf +++ b/addons/medical_statemachine/functions/fnc_handleStateUnconscious.sqf @@ -36,7 +36,7 @@ if (EGVAR(medical,spontaneousWakeUpChance) > 0) then { private _wakeUpCheckInterval = SPONTANEOUS_WAKE_UP_INTERVAL; if (EGVAR(medical,spontaneousWakeUpEpinephrineBoost) > 1) then { - private _epiEffectiveness = [_unit, "Epinephrine", false] call EFUNC(medical_status,getMedicationCount); + private _epiEffectiveness = ([_unit, "Epinephrine", false] call EFUNC(medical_status,getMedicationCount)) select 1; _wakeUpCheckInterval = _wakeUpCheckInterval * linearConversion [0, 1, _epiEffectiveness, 1, 1 / EGVAR(medical,spontaneousWakeUpEpinephrineBoost), true]; TRACE_2("epiBoost",_epiEffectiveness,_wakeUpCheckInterval); }; diff --git a/addons/medical_status/XEH_PREP.hpp b/addons/medical_status/XEH_PREP.hpp index 77f9712eb17..967332da2e2 100644 --- a/addons/medical_status/XEH_PREP.hpp +++ b/addons/medical_status/XEH_PREP.hpp @@ -1,6 +1,7 @@ PREP(addInventoryActions); PREP(addMedicationAdjustment); PREP(adjustPainLevel); +PREP(getAllMedicationCount); PREP(getBloodLoss); PREP(getBloodPressure); PREP(getBloodVolumeChange); diff --git a/addons/medical_status/functions/fnc_addMedicationAdjustment.sqf b/addons/medical_status/functions/fnc_addMedicationAdjustment.sqf index 8770eaf0aec..b49da8cd131 100644 --- a/addons/medical_status/functions/fnc_addMedicationAdjustment.sqf +++ b/addons/medical_status/functions/fnc_addMedicationAdjustment.sqf @@ -1,6 +1,6 @@ #include "..\script_component.hpp" /* - * Author: BaerMitUmlaut, PabstMirror + * Author: BaerMitUmlaut, PabstMirror, Cplhardcore * Adds a medication and it's effects * * Arguments: @@ -11,17 +11,18 @@ * 4: Heart Rate Adjust * 5: Pain Suppress Adjust * 6: Flow Adjust + * 7: Dose of medication * * Return Value: * None * * Example: - * [player, "Morphine", 120, 60, -10, 0.8, -10] call ace_medical_status_fnc_addMedicationAdjustment + * [player, "Morphine", 120, 60, -10, 0.8, -10, 1] call ace_medical_status_fnc_addMedicationAdjustment * * Public: No */ -params ["_unit", "_medication", "_timeToMaxEffect", "_maxTimeInSystem", "_hrAdjust", "_painAdjust", "_flowAdjust"]; -TRACE_7("addMedicationAdjustment",_unit,_medication,_timeToMaxEffect,_maxTimeInSystem,_hrAdjust,_painAdjust,_flowAdjust); +params ["_unit", "_medication", "_timeToMaxEffect", "_maxTimeInSystem", "_hrAdjust", "_painAdjust", "_flowAdjust", "_dose"]; +TRACE_8("addMedicationAdjustment",_unit,_medication,_timeToMaxEffect,_maxTimeInSystem,_hrAdjust,_painAdjust,_flowAdjust,_dose); if (_maxTimeInSystem <= 0) exitWith { WARNING_1("bad value for _maxTimeInSystem - %1",_this); }; _timeToMaxEffect = _timeToMaxEffect max 1; @@ -29,6 +30,5 @@ _timeToMaxEffect = _timeToMaxEffect max 1; private _adjustments = _unit getVariable [VAR_MEDICATIONS, []]; -_adjustments pushBack [_medication, CBA_missionTime, _timeToMaxEffect, _maxTimeInSystem, _hrAdjust, _painAdjust, _flowAdjust]; - +_adjustments pushBack [_medication, CBA_missionTime, _timeToMaxEffect, _maxTimeInSystem, _hrAdjust, _painAdjust, _flowAdjust, _dose]; _unit setVariable [VAR_MEDICATIONS, _adjustments, true]; diff --git a/addons/medical_status/functions/fnc_getAllMedicationCount.sqf b/addons/medical_status/functions/fnc_getAllMedicationCount.sqf new file mode 100644 index 00000000000..2ee4989c2c8 --- /dev/null +++ b/addons/medical_status/functions/fnc_getAllMedicationCount.sqf @@ -0,0 +1,27 @@ +#include "..\script_component.hpp" +/* + * Author: PabstMirror, Cplhardcore + * Gets effective count of all medications in a unit's system + * (each medication dose is scaled from 0..1 based on time till max effect and max time in system) + * + * Arguments: + * 0: The patient + * 1: Get raw count (true) or effect ratio (false) (default: true) + * + * Return Value: + * Array of medication counts : + * 0: Medication Name + * 1: Dose Count + * 2: Medication effectiveness (0-1) + * + * Example: + * [player] call ace_medical_status_fnc_getAllMedicationCount + * + * Public: Yes + */ + +params ["_target", ["_getCount", true]]; + +private _medicationClasses = (_target getVariable [VAR_MEDICATIONS, []]) apply {_x select 0}; +_medicationClasses = _medicationClasses arrayIntersect _medicationClasses; +_medicationClasses apply {[_x] + ([_target, _x, _getCount] call FUNC(getMedicationCount))} // return diff --git a/addons/medical_status/functions/fnc_getMedicationCount.sqf b/addons/medical_status/functions/fnc_getMedicationCount.sqf index e98707c7212..85b14982e39 100644 --- a/addons/medical_status/functions/fnc_getMedicationCount.sqf +++ b/addons/medical_status/functions/fnc_getMedicationCount.sqf @@ -1,16 +1,18 @@ #include "..\script_component.hpp" /* - * Author: PabstMirror + * Author: PabstMirror, Cplhardcore * Gets effective count of medications in a unit's system * (each medication dose is scaled from 0..1 based on time till max effect and max time in system) * * Arguments: * 0: The patient * 1: Medication (not case sensitive) - * 2: Get raw count (true) or effect ratio (false) (default: true) + * 2: Get raw count (true) or effect ratio (false) (default: true) + * + * Returns Value: + * 0: Dose Count + * 1: Medication effectiveness (0-1) * - * Return Value: - * Medication count (float) * * Example: * [player, "Epinephrine"] call ace_medical_status_fnc_getMedicationCount @@ -20,20 +22,23 @@ params ["_target", "_medication", ["_getCount", true]]; -private _return = 0; +private _effectiveness = 0; +private _medDose = 0; { - _x params ["_xMed", "_timeAdded", "_timeTillMaxEffect", "_maxTimeInSystem"]; + _x params ["_xMed", "_timeAdded", "_timeTillMaxEffect", "_maxTimeInSystem", "", "", "", "_dose"]; if (_xMed == _medication) then { private _timeInSystem = CBA_missionTime - _timeAdded; - if (_getCount) then { - // just return effective count, a medication will always start at 1 and only drop after reaching timeTilMaxEffect - _return = _return + linearConversion [_timeTillMaxEffect, _maxTimeInSystem, _timeInSystem, 1, 0, true]; + _medDose = _medDose + _dose; + _effectiveness = if (_getCount) then { + // returns effective count, a medication will always start at 1 and only drop after reaching timeTilMaxEffect + _effectiveness + linearConversion [_timeTillMaxEffect, _maxTimeInSystem, _timeInSystem, 1, 0, true] } else { // as used in handleUnitVitals, a medication effectiveness will start low, ramp up to timeTillMaxEffect, and then drop off - _return = _return + (((_timeInSystem / _timeTillMaxEffect) ^ 2) min 1) * (_maxTimeInSystem - _timeInSystem) / _maxTimeInSystem; + _effectiveness + (((_timeInSystem / _timeTillMaxEffect) ^ 2) min 1) * (_maxTimeInSystem - _timeInSystem) / _maxTimeInSystem }; }; } forEach (_target getVariable [VAR_MEDICATIONS, []]); -TRACE_4("getMedicationCount",_target,_medication,_getCount,_return); -_return +TRACE_5("getMedicationCount",_target,_medication,_getCount,_effectiveness,_medDose); + +[_medDose, _effectiveness] // return diff --git a/addons/medical_treatment/ACE_Medical_Treatment.hpp b/addons/medical_treatment/ACE_Medical_Treatment.hpp index 267a45dd445..0ac0c454a3b 100644 --- a/addons/medical_treatment/ACE_Medical_Treatment.hpp +++ b/addons/medical_treatment/ACE_Medical_Treatment.hpp @@ -565,12 +565,14 @@ class ADDON { timeInSystem = 120; // How long until the maximum effect is reached timeTillMaxEffect = 30; - // How many of this type of medication can be in the system before the patient can possibly overdose? + // How many doses of this medication can be in the system before the patient can possibly overdose? maxDose = 4; // The number of doses over maxDose where there is a chance to overdose. // Example with maxDose = 4 and maxDoseDeviation = 2: Dose 4: Safe | Dose 5 and 6: Possible overdose | Dose 7: Guaranteed overdose maxDoseDeviation = 2; - // Function to execute upon overdose. Arguments passed to call back are 0: unit , 1: medicationClassName + // The dose of the medication, to allow for different dose amounts of the same medication + dose = 1; + // Function to execute upon overdose. Arguments passed to call back are 0: Patient , 1: Medication classname , 2: Medication dosage , 3: Overdose threshold , 4: Incompatible medication that caused overdose (can be the medication itself) (default: "") onOverDose = ""; // The viscosity of a fluid is a measure of its resistance to gradual deformation by shear stress or tensile stress. For liquids, it corresponds to the informal concept of "thickness". This value will increase/decrease the viscoty of the blood with the percentage given. Where 100 = max. Using the minus will decrease viscosity viscosityChange = 0; @@ -584,6 +586,7 @@ class ADDON { timeInSystem = 1800; timeTillMaxEffect = 30; maxDose = 4; + dose = 1; incompatibleMedication[] = {}; viscosityChange = -10; }; @@ -595,6 +598,7 @@ class ADDON { timeInSystem = 120; timeTillMaxEffect = 10; maxDose = 9; + dose = 1; incompatibleMedication[] = {}; }; class Adenosine { @@ -605,6 +609,7 @@ class ADDON { timeInSystem = 120; timeTillMaxEffect = 15; maxDose = 5; + dose = 1; incompatibleMedication[] = {}; }; class PainKillers { @@ -615,6 +620,7 @@ class ADDON { timeInSystem = 420; timeTillMaxEffect = 60; maxDose = 5; + dose = 1; incompatibleMedication[] = {}; viscosityChange = 5; }; diff --git a/addons/medical_treatment/XEH_PREP.hpp b/addons/medical_treatment/XEH_PREP.hpp index 709c97952f4..d7165b59705 100644 --- a/addons/medical_treatment/XEH_PREP.hpp +++ b/addons/medical_treatment/XEH_PREP.hpp @@ -48,6 +48,7 @@ PREP(loadUnit); PREP(medication); PREP(medicationLocal); PREP(onMedicationUsage); +PREP(overDose); PREP(placeBodyBagInGrave); PREP(placeInBodyBag); PREP(placeInBodyBagOrGrave); diff --git a/addons/medical_treatment/functions/fnc_medicationLocal.sqf b/addons/medical_treatment/functions/fnc_medicationLocal.sqf index 18ef4e4d680..b48d7f3be4f 100644 --- a/addons/medical_treatment/functions/fnc_medicationLocal.sqf +++ b/addons/medical_treatment/functions/fnc_medicationLocal.sqf @@ -1,6 +1,6 @@ #include "..\script_component.hpp" /* - * Author: Glowbal, mharis001 + * Author: Glowbal, mharis001, Cplhardcore * Local callback for administering medication to a patient. * * Arguments: @@ -65,13 +65,12 @@ private _medicationConfig = _defaultConfig >> _classname; private _painReduce = GET_NUMBER(_medicationConfig >> "painReduce",getNumber (_defaultConfig >> "painReduce")); private _timeInSystem = GET_NUMBER(_medicationConfig >> "timeInSystem",getNumber (_defaultConfig >> "timeInSystem")); private _timeTillMaxEffect = GET_NUMBER(_medicationConfig >> "timeTillMaxEffect",getNumber (_defaultConfig >> "timeTillMaxEffect")); -private _maxDose = GET_NUMBER(_medicationConfig >> "maxDose",getNumber (_defaultConfig >> "maxDose")); -private _maxDoseDeviation = GET_NUMBER(_medicationConfig >> "maxDoseDeviation",getNumber (_defaultConfig >> "maxDoseDeviation")); private _viscosityChange = GET_NUMBER(_medicationConfig >> "viscosityChange",getNumber (_defaultConfig >> "viscosityChange")); private _hrIncreaseLow = GET_ARRAY(_medicationConfig >> "hrIncreaseLow",getArray (_defaultConfig >> "hrIncreaseLow")); private _hrIncreaseNormal = GET_ARRAY(_medicationConfig >> "hrIncreaseNormal",getArray (_defaultConfig >> "hrIncreaseNormal")); private _hrIncreaseHigh = GET_ARRAY(_medicationConfig >> "hrIncreaseHigh",getArray (_defaultConfig >> "hrIncreaseHigh")); private _incompatibleMedication = GET_ARRAY(_medicationConfig >> "incompatibleMedication",getArray (_defaultConfig >> "incompatibleMedication")); +private _dose = GET_NUMBER(_medicationConfig >> "dose",getNumber (_defaultConfig >> "dose")); private _heartRate = GET_HEART_RATE(_patient); private _hrIncrease = [_hrIncreaseLow, _hrIncreaseNormal, _hrIncreaseHigh] select (floor ((0 max _heartRate min 110) / 55)); @@ -80,7 +79,7 @@ private _heartRateChange = _minIncrease + random (_maxIncrease - _minIncrease); // Adjust the medication effects and add the medication to the list TRACE_3("adjustments",_heartRateChange,_painReduce,_viscosityChange); -[_patient, _className, _timeTillMaxEffect, _timeInSystem, _heartRateChange, _painReduce, _viscosityChange] call EFUNC(medical_status,addMedicationAdjustment); +[_patient, _className, _timeTillMaxEffect, _timeInSystem, _heartRateChange, _painReduce, _viscosityChange, _dose] call EFUNC(medical_status,addMedicationAdjustment); // Check for medication compatiblity -[_patient, _className, _maxDose, _maxDoseDeviation, _incompatibleMedication] call FUNC(onMedicationUsage); +[_patient, _className, _incompatibleMedication] call FUNC(onMedicationUsage); diff --git a/addons/medical_treatment/functions/fnc_onMedicationUsage.sqf b/addons/medical_treatment/functions/fnc_onMedicationUsage.sqf index cd26d154242..668e353f60c 100644 --- a/addons/medical_treatment/functions/fnc_onMedicationUsage.sqf +++ b/addons/medical_treatment/functions/fnc_onMedicationUsage.sqf @@ -1,68 +1,50 @@ #include "..\script_component.hpp" /* - * Author: Glowbal + * Author: Glowbal, Cplhardcore * Handles the medication given to a patient. * * Arguments: - * 0: The patient + * 0: Patient * 1: Medication Treatment classname - * 2: Max dose (0 to ignore) - * 3: Max dose deviation - * 3: Incompatable medication > + * 2: Incompatible medication > * * Return Value: * None * * Example: - * [player, "morphine", 4, 2, [["x", 1]]] call ace_medical_treatment_fnc_onMedicationUsage + * [player, "morphine", [["x", 1]]] call ace_medical_treatment_fnc_onMedicationUsage * * Public: No */ -params ["_target", "_className", "_maxDose", "_maxDoseDeviation", "_incompatibleMedication"]; -TRACE_5("onMedicationUsage",_target,_className,_maxDose,_maxDoseDeviation,_incompatibleMedication); - -private _overdosedMedications = []; +params ["_target", "_className", "_incompatibleMedication"]; +TRACE_3("onMedicationUsage",_target,_className,_incompatibleMedication); // Check for overdose from current medication +private _defaultConfig = configFile >> QUOTE(ADDON) >> "Medication"; +private _medicationConfig = _defaultConfig >> _classname; +private _maxDose = GET_NUMBER(_medicationConfig >> "maxDose",getNumber (_defaultConfig >> "maxDose")); + if (_maxDose > 0) then { - private _currentDose = [_target, _className] call EFUNC(medical_status,getMedicationCount); + private _maxDoseDeviation = GET_NUMBER(_medicationConfig >> "maxDoseDeviation",getNumber (_defaultConfig >> "maxDoseDeviation")); + private _currentDose = [_target, _className] call EFUNC(medical_status,getMedicationCount) select 0; // Because both {floor random 0} and {floor random 1} return 0 if (_maxDoseDeviation > 0) then { _maxDoseDeviation = _maxDoseDeviation + 1; }; - if (_currentDose > _maxDose + (floor random _maxDoseDeviation)) then { + private _limit = _maxDose + (floor random _maxDoseDeviation); + if (_currentDose > _limit) then { TRACE_1("exceeded max dose",_currentDose); - _overdosedMedications pushBackUnique _className; + [_target, _classname, _currentDose, _limit, _classname] call FUNC(overDose); }; }; // Check incompatible medication (format [med,limit]) { _x params ["_xMed", "_xLimit"]; - private _inSystem = [_target, _xMed] call EFUNC(medical_status,getMedicationCount); - if (_inSystem> _xLimit) then { - _overdosedMedications pushBackUnique _xMed; + private _inSystem = ([_target, _xMed] call EFUNC(medical_status,getMedicationCount)) select 0; + if (_inSystem > _xLimit) then { + [_target, _classname, _inSystem, _xLimit, _xMed] call FUNC(overDose); }; } forEach _incompatibleMedication; - -if (_overdosedMedications isNotEqualTo []) then { - private _medicationConfig = (configFile >> "ace_medical_treatment" >> "Medication"); - private _onOverDose = getText (_medicationConfig >> "onOverDose"); - if (isClass (_medicationConfig >> _className)) then { - _medicationConfig = (_medicationConfig >> _className); - if (isText (_medicationConfig >> "onOverDose")) then { _onOverDose = getText (_medicationConfig >> "onOverDose"); }; - }; - TRACE_2("overdose",_overdosedMedications,_onOverDose); - if (_onOverDose == "") exitWith { - TRACE_1("CriticalVitals Event",_target); // make unconscious - [QEGVAR(medical,CriticalVitals), _target] call CBA_fnc_localEvent; - }; - if (isNil _onOverDose) then { - _onOverDose = compile _onOverDose; - } else { - _onOverDose = missionNamespace getVariable _onOverDose; - }; - [_target, _className, _overdosedMedications] call _onOverDose; -}; diff --git a/addons/medical_treatment/functions/fnc_overDose.sqf b/addons/medical_treatment/functions/fnc_overDose.sqf new file mode 100644 index 00000000000..d7c03f8269d --- /dev/null +++ b/addons/medical_treatment/functions/fnc_overDose.sqf @@ -0,0 +1,48 @@ +#include "..\script_component.hpp" +/* + * Author: Cplhardcore + * Handles the overdose effects of a medication. + * + * Arguments: + * 0: Patient + * 1: Medication classname + * 2: Medication dosage + * 3: Overdose threshold + * 4: Incompatible medication that caused overdose (can be the medication itself) (default: "") + * + * Return Value: + * None + * + * Example: + * [player, "morphine", 5, 3, "morphine"] call ace_medical_treatment_fnc_overDose + * + * Public: No + */ + +params ["_unit", "_classname", "_dose", "_limit", "_incompatibleMed"]; + +private _medicationConfig = configFile >> QUOTE(ADDON) >> "Medication"; +private _onOverDose = getText (_medicationConfig >> "onOverDose"); + +if (isClass _medicationConfig) then { + _medicationConfig = _medicationConfig >> _classname; + if (isText (_medicationConfig >> "onOverDose")) then { + _onOverDose = getText (_medicationConfig >> "onOverDose"); + }; +}; +TRACE_2("overdose",_classname,_onOverDose); + +[QEGVAR(medical,overdose), [_unit, _classname, _dose, _limit, _incompatibleMed]] call CBA_fnc_localEvent; + +if (_onOverDose == "") exitWith { + TRACE_1("CriticalVitals Event",_unit); + [QEGVAR(medical,CriticalVitals), _unit] call CBA_fnc_localEvent; +}; + +_onOverDose = if (missionNamespace isNil _onOverDose) then { + compile _onOverDose +} else { + missionNamespace getVariable _onOverDose +}; + +[_unit, _classname, _dose, _limit, _incompatibleMed] call _onOverDose diff --git a/docs/wiki/framework/events-framework.md b/docs/wiki/framework/events-framework.md index bcbbb6283ef..8d1940a1213 100644 --- a/docs/wiki/framework/events-framework.md +++ b/docs/wiki/framework/events-framework.md @@ -45,6 +45,7 @@ The vehicle events will also have the following local variables available `_gunn |`ace_treatmentFailed` | [_caller, _target, _selectionName, _className, _itemUser, _usedItem, _createLitter] | Local | Listen | Treatment action has been interrupted (local on the _caller) | |`ace_medical_handleUnitVitals` | [_unit, _deltaT] | Local | Listen | Vitals update ran for unit, _deltaT is the time elapsed since the previous vitals update (local to _unit) | |`ace_medical_treatment_bandaged` | [_medic, _patient, _bodyPart, _className, _itemUser, _usedItem, _createLitter, _bandageEffectiveness] | Local | Listen | _medic has bandaged _patient, the array can be modified to change treatment parameters (local to _medic) | +|`ace_medical_overdose` | [_unit, _medication, _medicationDose, _overdoseThreshold, _incompatibleMed] | Local | Listen | _unit has overdosed on _medication by _overdoseThreshold - _medicationDose, overdoseThreshold was determined by _incompatibleMed (can be _medication itself or mixed incompatible medication) | ### 2.3 Interaction Menu (`ace_interact_menu`) MenuType: 0 = Interaction, 1 = Self Interaction