Merge branch 'limping' into medical-treatment-work-rebaseLimping

This commit is contained in:
PabstMirror
2019-04-26 11:50:20 -05:00
70 changed files with 759 additions and 390 deletions

View File

@ -211,7 +211,7 @@ for "_dataIndex" from 0 to 9 do {
};
case 9: {
for "_subIndex" from 0 to 4 do {
for "_subIndex" from 0 to 5 do {
private _item = (_loadout select _dataIndex) select _subIndex;
if (_item != "") then {

View File

@ -19,8 +19,8 @@
//Status Effect EHs:
[QGVAR(setStatusEffect), {_this call FUNC(statusEffect_set)}] call CBA_fnc_addEventHandler;
["forceWalk", false, ["ACE_SwitchUnits", "ACE_Attach", "ACE_dragging", "ACE_Explosives", "ACE_Ladder", "ACE_Sandbag", "ACE_refuel", "ACE_rearm", "ACE_Trenches"]] call FUNC(statusEffect_addType);
["blockSprint", false, []] call FUNC(statusEffect_addType);
["forceWalk", false, ["ace_advanced_fatigue", "ACE_SwitchUnits", "ACE_Attach", "ACE_dragging", "ACE_Explosives", "ACE_Ladder", "ACE_Sandbag", "ACE_refuel", "ACE_rearm", "ACE_Trenches"]] call FUNC(statusEffect_addType);
["blockSprint", false, ["ace_advanced_fatigue", "ace_medical_fracture"]] call FUNC(statusEffect_addType);
["setCaptive", true, [QEGVAR(captives,Handcuffed), QEGVAR(captives,Surrendered)]] call FUNC(statusEffect_addType);
["blockDamage", false, ["fixCollision", "ACE_cargo"]] call FUNC(statusEffect_addType);
["blockEngine", false, ["ACE_Refuel"]] call FUNC(statusEffect_addType);

View File

@ -6,7 +6,7 @@
* Arguments:
* 0: Namespace <OBJECT><LOCATION><MISSIONNAMESPACE>
* 1: Number Set ID <STRING>
* 2: Operation (sum, product, min, max, avg) <STRING>
* 2: Operation (sum, product, min, max, avg) (Case Sensitive) <STRING>
*
* Return Value:
* Value <NUMBER>
@ -19,11 +19,19 @@
*/
params ["_namespace", "_setID", "_op"];
TRACE_3("params",_namespace,_setID,_op);
TRACE_3("arithmeticGetResult",_namespace,_setID,_op);
private _data = (_namespace getVariable _setID) param [2, []];
switch (_op) do {
case ("max"): {
private _result = -1e99;
{
_result = _result max (call _x);
nil
} count _data;
_result // return
};
case ("sum"): {
private _result = 0;
{
@ -48,14 +56,6 @@ switch (_op) do {
} count _data;
_result // return
};
case ("max"): {
private _result = -1e99;
{
_result = _result max (call _x);
nil
} count _data;
_result // return
};
case ("avg"): {
private _result = 0;
{

View File

@ -1,12 +1,12 @@
// #define DEBUG_MODE_FULL
#include "script_component.hpp"
[QEGVAR(medical,setUnconscious), LINKFUNC(setUnconscious)] call CBA_fnc_addEventHandler;
if (!hasInterface) exitWith {};
[missionNamespace, "ACE_setCustomAimCoef", QUOTE(ADDON), {
private _pain = GET_PAIN_PERCEIVED(ACE_player);
linearConversion [0, 1, _pain, 1, 5, true];
(linearConversion [0, 1, GET_PAIN_PERCEIVED(ACE_player), 1, 5, true]) + (ACE_player getVariable [QEGVAR(medical_engine,aimFracture), 0])
}] call EFUNC(common,arithmeticSetSource);
#ifdef DEBUG_MODE_FULL

View File

@ -6,7 +6,7 @@ class CfgPatches {
units[] = {};
weapons[] = {};
requiredVersion = REQUIRED_VERSION;
requiredAddons[] = {"ace_common"};
requiredAddons[] = {"ace_medical_engine"};
author = ECSTRING(common,ACETeam);
authors[] = {"Glowbal", "KoffeinFlummi","Arcanum417"};
url = ECSTRING(main,URL);

View File

@ -3,7 +3,8 @@
["medical", {
// Hide when patient display is up because they might overlap
if (!isNull EGVAR(medical_gui,displayPatientInformationTarget)) exitWith {""};
private _display = uiNamespace getVariable [QEGVAR(medical_gui,RscPatientInfo), displayNull];
if (!isNull _display) exitWith {"Paused"};
private _unit = cursorTarget;
if (!(_unit isKindOf "CAManBase")) then {_unit = cursorObject};
@ -27,10 +28,13 @@
// Blood:
private _bloodVolume = GET_BLOOD_VOLUME(_unit);
private _woundBleeding = GET_WOUND_BLEEDING(_unit);
private _bloodLoss = GET_BLOOD_LOSS(_unit);
private _secondsToHeartstop = if (_bloodLoss != 0) then {format ["[<t color ='#FF9999'>Time Left:</t> %1 sec]", (((_bloodVolume - BLOOD_VOLUME_CLASS_4_HEMORRHAGE) max 0) / _bloodLoss) toFixed 1]} else {""};
_return pushBack format ["Blood: %1", _bloodVolume toFixed 3];
_return pushBack format [" - [Loss: %1] %2", _bloodLoss toFixed 5, _secondsToHeartstop];
private _hemorrhage = GET_HEMORRHAGE(_unit);
private _isBleeding = if (IS_BLEEDING(_unit)) then {"<t color ='#FF9999'>Bleeding</t>"} else {""};
private _secondsToHeartstop = if (_bloodLoss != 0) then {format ["[<t color ='#FF9999'>Time Left:</t> %1 sec]", (((_bloodVolume - BLOOD_VOLUME_CLASS_4_HEMORRHAGE) max 0) / _bloodLoss) toFixed 0]} else {""};
_return pushBack format ["Blood: %1 [Hemorrhage: %2] %3", _bloodVolume toFixed 3, _hemorrhage, _isBleeding];
_return pushBack format [" - [W: %1 T: %2] %3", _woundBleeding toFixed 4, _bloodLoss toFixed 4, _secondsToHeartstop];
// Heart:
private _cardiacOutput = [_unit] call EFUNC(medical_status,getCardiacOutput);
@ -43,15 +47,23 @@
private _pain = GET_PAIN(_unit);
private _painSuppress = GET_PAIN_SUPPRESS(_unit);
private _painLevel = GET_PAIN_PERCEIVED(_unit);
_return pushBack format ["Effective Pain: %1", _painLevel toFixed 3];
private _isInPain = IS_IN_PAIN(_unit);
_return pushBack format ["Effective Pain: %1 [%2]", _painLevel toFixed 3, _isInPain];
_return pushBack format [" - [Pain: %1] [Suppress: %2]", _pain toFixed 3, _painSuppress toFixed 3];
// Damage:
private _damage = _unit getVariable [QEGVAR(medical,bodyPartDamage), [0,0,0,0,0,0]];
private _limping = if (_unit getVariable [QEGVAR(medical,isLimping), false]) then {"[<t color ='#FFCC22'> Limping </t>]"} else {""};
_return pushBack format ["Damage: [H: %1] [B: %2] %3", (_damage select 0) toFixed 2, (_damage select 1) toFixed 2, _limping];
_return pushBack format ["Damage: [H: %1] [B: %2] %3", (_damage select 0) toFixed 2, (_damage select 1) toFixed 2];
_return pushBack format ["[LA:%1] [RA: %2] [LL:%3] [RL: %4]", (_damage select 2) toFixed 2, (_damage select 3) toFixed 2, (_damage select 4) toFixed 2, (_damage select 5) toFixed 2];
_return pushBack format ["Hitpoints: [HHed:%1] [HBod: %2]", (_unit getHitPointDamage "HitHead") toFixed 2, (_unit getHitPointDamage "HitBody") toFixed 2];
_return pushBack format ["[HHnd:%1] [HLeg: %2] %3", (_unit getHitPointDamage "HitHands") toFixed 2, (_unit getHitPointDamage "HitLegs") toFixed 2, _limping];
private _fractures = _unit getVariable [QEGVAR(medical,fractures), [0,0,0,0,0,0]];
private _canSprint = if (isSprintAllowed _unit) then {""} else {"[<t color ='#FFCC22'>Sprint Blocked</t>]"};
_return pushBack format ["Fractures: %1 %2", _fractures, _canSprint];
// Tourniquets:
_return pushBack "------- Tourniquets: -------";
@ -75,10 +87,25 @@
_return pushBack "------- Wounds: -------";
private _wounds = _unit getVariable [QEGVAR(medical,openWounds), []];
{
_x params ["", "_xClassID", "_xBodyPartN", "_xAmountOf", "_xBleeding", "_xDamage", "_xCategory"];
_return pushBack format ["%1: [%2-%3] [x%4] [Bld: %5] [Dmg: %6]", ALL_SELECTIONS select _xBodyPartN, _xClassID, _xCategory, _xAmountOf toFixed 1, _xBleeding toFixed 4, _xDamage toFixed 2];
_x params ["_xClassID", "_xBodyPartN", "_xAmountOf", "_xBleeding", "_xDamage"];
_return pushBack format ["%1: [%2] [x%3] [Bld: %4] [Dmg: %5]", ALL_SELECTIONS select _xBodyPartN, _xClassID, _xAmountOf toFixed 1, _xBleeding toFixed 4, _xDamage toFixed 2];
} forEach _wounds;
// Bandaged Wounds:
_return pushBack "------- Bandaged Wounds: -------";
private _wounds = _unit getVariable [QEGVAR(medical,bandagedWounds), []];
{
_x params ["_xClassID", "_xBodyPartN", "_xAmountOf", "_xBleeding", "_xDamage"];
_return pushBack format ["%1: [%2] [x%3] [Bld: %4] [Dmg: %5]", ALL_SELECTIONS select _xBodyPartN, _xClassID, _xAmountOf toFixed 1, _xBleeding toFixed 4, _xDamage toFixed 2];
} forEach _wounds;
// Stitched Wounds:
_return pushBack "------- Stitched Wounds: -------";
private _wounds = _unit getVariable [QEGVAR(medical,stitchedWounds), []];
{
_x params ["_xClassID", "_xBodyPartN", "_xAmountOf", "_xBleeding", "_xDamage"];
_return pushBack format ["%1: [%2] [x%3] [Bld: %4] [Dmg: %5]", ALL_SELECTIONS select _xBodyPartN, _xClassID, _xAmountOf toFixed 1, _xBleeding toFixed 4, _xDamage toFixed 2];
} forEach _wounds;
// IVs:
_return pushBack "------- IVs: -------";
@ -88,10 +115,43 @@
_return pushBack format ["%1: %2 [%3 ml]", ALL_SELECTIONS select _xBodyPartN, _xType, _xVolumeAdded];
} forEach _ivBags;
// Medications:
_return pushBack "------- Medications: -------";
private _hrTargetAdjustment = 0;
private _painSupressAdjustment = 0;
private _peripheralResistanceAdjustment = 0;
private _medicationCounts = [];
private _rawMedications = (_unit getVariable [VAR_MEDICATIONS, []]) apply {
_x params ["_medication", "_timeAdded", "_timeTillMaxEffect", "_maxTimeInSystem", "_hrAdjust", "_painAdjust", "_flowAdjust"];
private _timeInSystem = CBA_missionTime - _timeAdded;
private _index = _medicationCounts find _medication;
if (_index < 0) then {
_index = _medicationCounts pushBack _medication;
_medicationCounts pushBack 0
};
_medicationCounts set [(_index + 1), (_medicationCounts select (_index + 1)) + linearConversion [_timeTillMaxEffect, _maxTimeInSystem, _timeInSystem, 1, 0, true]];
private _effectRatio = (((_timeInSystem / _timeTillMaxEffect) ^ 2) min 1) * (_maxTimeInSystem - _timeInSystem) / _maxTimeInSystem;
_hrTargetAdjustment = _hrTargetAdjustment + _hrAdjust * _effectRatio;
_painSupressAdjustment = _painSupressAdjustment + _painAdjust * _effectRatio;
_peripheralResistanceAdjustment = _peripheralResistanceAdjustment + _flowAdjust * _effectRatio;
format ["%1 [%2 / %3][%4][%5,%6,%7]",_medication,_timeInSystem toFixed 0,_maxTimeInSystem toFixed 0, _effectRatio toFixed 2, _hrAdjust toFixed 1, _painAdjust toFixed 2, _flowAdjust toFixed 1];
};
_return pushBack format ["Adjusts: [HR %1][PS %2][PR %3]", _hrTargetAdjustment toFixed 2, _painSupressAdjustment toFixed 2, _peripheralResistanceAdjustment toFixed 2];
for "_i" from 0 to (count _medicationCounts) - 1 step 2 do {
_return pushBack format ["-%1: %2", _medicationCounts select _i, _medicationCounts select _i + 1];
};
_return pushBack "------- Medications Raw: -------";
_return append _rawMedications;
if (_unit isEqualTo ACE_player) then {
_return pushBack format ["ACE_setCustomAimCoef: %1", [missionNamespace, "ACE_setCustomAimCoef", "max"] call ace_common_fnc_arithmeticGetResult];
};
// Footer:
_return pushBack "</t>";
// Return:
_return joinString "<br/>"
}, [30]] call EFUNC(common,watchVariable);
}, [40]] call EFUNC(common,watchVariable);

View File

@ -23,7 +23,7 @@
// #define DEBUG_TESTRESULTS
params [["_unit", objNull, [objNull]], ["_damageToAdd", -1, [0]], ["_bodyPart", "", [""]], ["_typeOfDamage", "", [""]], ["_instigator", objNull, [objNull]]];
TRACE_5("params",_unit,_damageToAdd,_bodyPart,_typeOfDamage,_instigator);
TRACE_5("addDamageToUnit",_unit,_damageToAdd,_bodyPart,_typeOfDamage,_instigator);
private _bodyPartIndex = ALL_BODY_PARTS find (toLower _bodyPart);
if (isNull _unit || {!local _unit} || {!alive _unit}) exitWith {ERROR_1("addDamageToUnit - badUnit %1", _this); false};

View File

@ -24,7 +24,7 @@ if !(EGVAR(common,settingsInitFinished)) exitWith {
EGVAR(common,runAtSettingsInitialized) pushBack [FUNC(setUnconscious), _this];
};
params ["_unit", ["_knockOut", true, [false]], ["_minWaitingTime", 0, [0]], ["_forcedWakup", false, [false]]];
params [["_unit", objNull, [objNull]], ["_knockOut", true, [false]], ["_minWaitingTime", 0, [0]], ["_forcedWakup", false, [false]]];
TRACE_4("setUnconscious",_unit,_knockOut,_minWaitingTime,_forcedWakup);
if ((isNull _unit) || {!alive _unit} || {!(_unit isKindOf "CAManBase")}) exitWith {
@ -33,7 +33,7 @@ if ((isNull _unit) || {!alive _unit} || {!(_unit isKindOf "CAManBase")}) exitWit
};
if (!local _unit) exitWith {
[QEGVAR(medical,setUnconscious), [_unit, _knockOut], _unit] call CBA_fnc_targetEvent;
[QEGVAR(medical,setUnconscious), _this, _unit] call CBA_fnc_targetEvent;
true
};

View File

@ -12,3 +12,23 @@ private _categoryArray = [LELSTRING(medical,Category), "?"];
{[QGVAR(spontaneousWakeUpChance), _this] call EFUNC(common,cbaSettings_settingChanged)},
true // Needs mission restart
] call CBA_settings_fnc_init;
[
QEGVAR(medical,limping), "LIST",
[LSTRING(setting_limping_DisplayName), LSTRING(setting_limping_Description)],
_categoryArray,
[[0,1,2],[LELSTRING(common,disabled), LLSTRING(setting_limping_limpOnOpenWounds), LLSTRING(setting_limping_limpRequiresStitching)], 1], // [values, titles, defaultIndex]
true, // isGlobal
{[QEGVAR(medical,limping), _this] call EFUNC(common,cbaSettings_settingChanged)},
true // Needs mission restart
] call CBA_settings_fnc_init;
[
QEGVAR(medical,fractures), "LIST",
[LSTRING(setting_fractures_DisplayName), LSTRING(setting_fractures_Description)],
_categoryArray,
[[0,1,2],[LELSTRING(common,disabled), LLSTRING(setting_fractures_splintHealsFully), LLSTRING(setting_fractures_splintHasEffects)], 1], // [values, titles, defaultIndex]
true, // isGlobal
{[QEGVAR(medical,fractures), _this] call EFUNC(common,cbaSettings_settingChanged)},
true // Needs mission restart
] call CBA_settings_fnc_init;

View File

@ -14,5 +14,5 @@
#define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL
#endif
#include "\z\ace\addons\main\script_macros.hpp"
#include "\z\ace\addons\medical_engine\script_macros_medical.hpp"
#include "\z\ace\addons\main\script_macros.hpp"

View File

@ -481,5 +481,29 @@
<Korean>뚜껑 닫기</Korean>
<Polish>Zamknij pokrywę</Polish>
</Key>
<Key ID="STR_ACE_Medical_setting_limping_DisplayName">
<English>Limping</English>
</Key>
<Key ID="STR_ACE_Medical_setting_limping_Description">
<English>Limp when unit has leg wounds...(todo)</English>
</Key>
<Key ID="STR_ACE_Medical_setting_limping_limpOnOpenWounds">
<English>Limp on open wounds</English>
</Key>
<Key ID="STR_ACE_Medical_setting_limping_limpRequiresStitching">
<English>Limp on open or bandaged wounds</English>
</Key>
<Key ID="STR_ACE_Medical_setting_fractures_DisplayName">
<English>Fractues</English>
</Key>
<Key ID="STR_ACE_Medical_setting_fractures_Description">
<English>Limp fractures... (todo)</English>
</Key>
<Key ID="STR_ACE_Medical_setting_fractures_splintHealsFully">
<English>Splints fully heal fractures</English>
</Key>
<Key ID="STR_ACE_Medical_setting_fractures_splintHasEffects">
<English>Splints heal (but cannot sprint)</English>
</Key>
</Package>
</Project>

View File

@ -14,5 +14,5 @@
#define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL_AI
#endif
#include "\z\ace\addons\main\script_macros.hpp"
#include "\z\ace\addons\medical_engine\script_macros_medical.hpp"
#include "\z\ace\addons\main\script_macros.hpp"

View File

@ -14,8 +14,8 @@
#define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL_BLOOD
#endif
#include "\z\ace\addons\main\script_macros.hpp"
#include "\z\ace\addons\medical_engine\script_macros_medical.hpp"
#include "\z\ace\addons\main\script_macros.hpp"
#define MAX_BLOOD_OBJECTS 500
#define BLOOD_OBJECT_LIFETIME 900

View File

@ -36,6 +36,7 @@ class ACE_Medical_Injuries {
pain = 0.8;
minDamage = 0.1;
causeLimping = 1;
causeFracture = 1;
};
// Slicing wounds made with a sharp instrument, leaving even edges. They may be as minimal as a paper cut or as significant as a surgical incision.
class Cut {
@ -59,6 +60,7 @@ class ACE_Medical_Injuries {
pain = 0.9;
minDamage = 0.35;
causeLimping = 1;
causeFracture = 1;
};
// Deep, narrow wounds produced by sharp objects such as nails, knives, and broken glass.
class PunctureWound {

View File

@ -17,11 +17,13 @@ addMissionEventHandler ["Loaded",{
}];
// decide which woundsHandler to use by whether the extension is present or not
if ("ace_medical" callExtension "version" != "") then {
DFUNC(woundsHandlerActive) = LINKFUNC(woundsHandler);
} else {
// if ("ace_medical" callExtension "version" != "") then {
// DFUNC(woundsHandlerActive) = LINKFUNC(woundsHandler);
// } else {
INFO("Using woundsHandlerSQF");
DFUNC(woundsHandlerActive) = LINKFUNC(woundsHandlerSQF);
};
// };
[QEGVAR(medical,woundReceived), {
params ["_unit", "_woundedHitPoint", "_receivedDamage", "", "_ammo"];

View File

@ -24,7 +24,7 @@ _bodyPartDamage params ["_headDamage", "_bodyDamage", "_leftArmDamage", "_rightA
// Exclude non penetrating body damage
{
_x params ["", "", "_bodyPartN", "_amountOf", "", "_damage"];
_x params ["", "_bodyPartN", "_amountOf", "", "_damage"];
if (_bodyPartN == 1 && {_damage < PENETRATION_THRESHOLD}) then {
_bodyDamage = _bodyDamage - (_amountOf * _damage);
};

View File

@ -18,7 +18,7 @@
private _injuriesConfigRoot = configFile >> "ACE_Medical_Injuries";
// --- parse wounds
GVAR(woundClassNames) = [];
GVAR(woundClassNamesComplex) = []; // index = 10 * classID + category; [will contain nils] e.g. ["aMinor", "aMed", "aLarge", nil, nil..."bMinor"]
GVAR(woundsData) = []; // @todo classTypes are strings currently. Convert them to unqiue IDs instead.
private _woundsConfig = _injuriesConfigRoot >> "wounds";
@ -34,17 +34,20 @@ private _classID = 0;
private _minDamage = GET_NUMBER(_entry >> "minDamage",0);
private _maxDamage = GET_NUMBER(_entry >> "maxDamage",-1);
private _causes = GET_ARRAY(_entry >> "causes",[]);
private _causeLimping = GET_NUMBER(_entry >> "causeLimping",0);
private _causeLimping = 1 == GET_NUMBER(_entry >> "causeLimping",0);
private _causeFracture = 1 == GET_NUMBER(_entry >> "causeFracture",0);
if !(_causes isEqualTo []) then {
GVAR(woundClassNames) pushBack _className;
GVAR(woundsData) pushBack [_classID, _selections, _bleeding, _pain, [_minDamage, _maxDamage], _causes, _className, _causeLimping];
GVAR(woundsData) pushBack [_classID, _selections, _bleeding, _pain, [_minDamage, _maxDamage], _causes, _className, _causeLimping, _causeFracture];
{
GVAR(woundClassNamesComplex) set [10 * _classID + _forEachIndex, format ["%1%2", _className, _x]];
} forEach ["Minor", "Medium", "Large"];
_classID = _classID + 1;
};
} forEach configProperties [_woundsConfig, "isClass _x"];
// --- parse damage types
GVAR(allDamageTypes) = []; // @todo, currently unused by handle damage (was GVAR(allAvailableDamageTypes))
GVAR(allDamageTypesData) = [] call CBA_fnc_createNamespace;
// minimum lethal damage collection, mapped to damageTypes
@ -57,8 +60,6 @@ private _selectionSpecificDefault = getNumber (_damageTypesConfig >> "selectionS
private _entry = _x;
private _className = configName _entry;
GVAR(allDamageTypes) pushBack _className;
// Check if this type is in the causes of a wound class, if so, we will store the wound types for this damage type
private _woundTypes = [];
{

View File

@ -18,6 +18,8 @@
* Public: No
*/
WARNING("this function needs to be updated for changes to woundsHandlerSQF");
params ["_unit", "_bodyPart", "_damage", "_typeOfDamage"];
TRACE_5("start",_unit,_bodyPart,_damage,_typeOfDamage);
@ -129,6 +131,8 @@ private _bodyPartVisParams = [_unit, false, false, false, false]; // params arra
_unit setVariable [QEGVAR(medical,openWounds), _openWounds, true];
_unit setVariable [QEGVAR(medical,bodyPartDamage), _bodyPartDamage, true];
[_unit] call EFUNC(medical_status,updateWoundBloodLoss);
_bodyPartVisParams call EFUNC(medical_engine,updateBodyPartVisuals);
[QEGVAR(medical,injured), [_unit, _painLevel]] call CBA_fnc_localEvent;

View File

@ -19,17 +19,14 @@
*/
params ["_unit", "_bodyPart", "_damage", "_typeOfDamage"];
TRACE_4("start",_unit,_bodyPart,_damage,_typeOfDamage);
TRACE_4("woundsHandlerSQF",_unit,_bodyPart,_damage,_typeOfDamage);
// Convert the selectionName to a number and ensure it is a valid selection.
private _bodyPartN = ALL_BODY_PARTS find toLower _bodyPart;
if (_bodyPartN < 0) exitWith {};
if (_bodyPartN < 0) exitWith { ERROR_1("invalid body part %1",_bodyPart); };
if (_typeOfDamage isEqualTo "") then {
_typeOfDamage = "unknown";
};
if (isNil {GVAR(allDamageTypesData) getVariable _typeOfDamage} ) then {
if ((_typeOfDamage isEqualTo "") || {isNil {GVAR(allDamageTypesData) getVariable _typeOfDamage}}) then {
WARNING_1("damage type [%1] not found",_typeOfDamage);
_typeOfDamage = "unknown";
};
@ -65,22 +62,22 @@ private _allPossibleInjuries = [];
} forEach _woundTypes;
// No possible wounds available for this damage type or damage amount.
if (_highestPossibleSpot < 0) exitWith {};
if (_highestPossibleSpot < 0) exitWith { TRACE_2("no wounds possible",_damage,_highestPossibleSpot); };
// Administration for open wounds and ids
private _openWounds = _unit getVariable [QEGVAR(medical,openWounds), []];
private _woundID = _unit getVariable [QEGVAR(medical,lastUniqueWoundID), 1]; // Unique wound ids are not used anywhere: ToDo Remove from openWounds array
private _updateDamageEffects = false;
private _painLevel = 0;
private _critialDamage = false;
private _bodyPartDamage = _unit getVariable [QEGVAR(medical,bodyPartDamage), [0,0,0,0,0,0]];
private _bodyPartVisParams = [_unit, false, false, false, false]; // params array for EFUNC(medical_engine,updateBodyPartVisuals);
private _woundsCreated = [];
{
_x params ["_thresholdMinDam", "_thresholdWoundCount"];
if (_thresholdMinDam <= _damage) exitWith {
private _woundDamage = _damage / (_thresholdWoundCount max 1); // If the damage creates multiple wounds
for "_i" from 0 to (_thresholdWoundCount-1) do {
for "_i" from 1 to _thresholdWoundCount do {
// Find the injury we are going to add. Format [ classID, allowdSelections, bleedingRate, injuryPain]
private _oldInjury = if (random 1 >= 0.85) then {
_woundTypes select _highestPossibleSpot
@ -88,15 +85,13 @@ private _woundsCreated = [];
selectRandom _allPossibleInjuries
};
_oldInjury params ["_woundClassIDToAdd", "", "_injuryBleedingRate", "_injuryPain"];
_oldInjury params ["_woundClassIDToAdd", "", "_injuryBleedingRate", "_injuryPain", "", "", "", "_causeLimping", "_causeFracture"];
private _bodyPartNToAdd = [floor random 6, _bodyPartN] select _isSelectionSpecific; // 6 == count ALL_BODY_PARTS
_bodyPartDamage set [_bodyPartNToAdd, (_bodyPartDamage select _bodyPartNToAdd) + _woundDamage];
_bodyPartVisParams set [[1,2,3,3,4,4] select _bodyPartNToAdd, true]; // Mark the body part index needs updating
// Create a new injury. Format [ID, classID, bodypart, percentage treated, bleeding rate]
private _injury = [_woundID, _woundClassIDToAdd, _bodyPartNToAdd, 1, _injuryBleedingRate];
// The higher the nastiness likelihood the higher the change to get a painful and bloody wound
private _nastinessLikelihood = linearConversion [0, 20, (_woundDamage / _thresholdWoundCount), 0.5, 30, true];
@ -110,76 +105,86 @@ private _woundsCreated = [];
// wound category (minor [0..0.5], medium[0.5..1.0], large[1.0+])
private _category = floor linearConversion [0, 1, _bleedingModifier, 0, 2, true];
// wound category (minor, medium, large)
private _category = floor ((0 max _bleeding min 0.1) / 0.05);
private _classComplex = 10 * _woundClassIDToAdd + _category;
_injury set [4, _bleeding];
_injury set [5, _woundDamage];
_injury set [6, _category];
// Create a new injury. Format [0:classComplex, 1:bodypart, 2:amountOf, 3:bleedingRate, 4:woundDamage]
private _injury = [_classComplex, _bodyPartNToAdd, 1, _bleeding, _woundDamage];
if (_bodyPartNToAdd == 0 || {_bodyPartNToAdd == 1 && {_woundDamage > PENETRATION_THRESHOLD}}) then {
_critialDamage = true;
};
#ifdef DEBUG_MODE_FULL
#ifdef DEBUG_MODE_FULL
systemChat format["%1, damage: %2, peneration: %3, bleeding: %4, pain: %5", _bodyPart, _woundDamage toFixed 2, _woundDamage > PENETRATION_THRESHOLD, _bleeding toFixed 3, _pain toFixed 3];
#endif
#endif
// Emulate damage to vital organs
switch (true) do {
// Fatal damage to the head is guaranteed death
case (_bodyPartNToAdd == 0 && {_woundDamage >= HEAD_DAMAGE_THRESHOLD}): {
case (_bodyPartNToAdd == 0 && {_woundDamage >= HEAD_DAMAGE_THRESHOLD}): {
TRACE_1("lethal headshot",_woundDamage toFixed 2);
[QEGVAR(medical,FatalInjury), _unit] call CBA_fnc_localEvent;
};
// Fatal damage to torso has various results based on organ hit
case (_bodyPartNToAdd == 1 && {_woundDamage >= ORGAN_DAMAGE_THRESHOLD}): {
case (_bodyPartNToAdd == 1 && {_woundDamage >= ORGAN_DAMAGE_THRESHOLD}): {
// Heart shot is lethal
if (random 1 < HEART_HIT_CHANCE) then {
TRACE_1("lethal heartshot",_woundDamage toFixed 2);
[QEGVAR(medical,FatalInjury), _unit] call CBA_fnc_localEvent;
};
};
};
// todo `forceWalk` based on leg damage
private _causeLimping = (GVAR(woundsData) select _woundClassIDToAdd) select 7;
if (_causeLimping == 1 && {_woundDamage > LIMPING_DAMAGE_THRESHOLD} && {_bodyPartNToAdd > 3}) then {
[_unit, true] call EFUNC(medical_engine,setLimping);
case (_causeFracture && {EGVAR(medical,fractures) > 0} && {_bodyPartNToAdd > 1} && {_woundDamage > FRACTURE_DAMAGE_THRESHOLD}): {
TRACE_1("limb fracture",_bodyPartNToAdd);
// todo: play sound?
private _fractures = _unit getVariable [QEGVAR(medical,fractures), [0,0,0,0,0,0]];
_fractures set [_bodyPartNToAdd, 1];
_unit setVariable [QEGVAR(medical,fractures), _fractures, true];
[QEGVAR(medical,fracture), [_unit, _bodyPartNToAdd]] call CBA_fnc_localEvent; // local event for fracture
_updateDamageEffects = true;
};
case (_causeLimping && {EGVAR(medical,limping) > 0} && {_bodyPartNToAdd > 3} && {_woundDamage > LIMPING_DAMAGE_THRESHOLD}): {
_updateDamageEffects = true;
};
};
// if possible merge into existing wounds
private _createNewWound = true;
{
_x params ["", "_classID", "_bodyPartN", "_oldAmountOf", "_oldBleeding", "_oldDamage", "_oldCategory"];
if (_woundClassIDToAdd == _classID && {_bodyPartNToAdd == _bodyPartN && {(_woundDamage < PENETRATION_THRESHOLD) isEqualTo (_oldDamage < PENETRATION_THRESHOLD)}}) then {
if (_oldCategory == _category) exitWith {
private _newAmountOf = _oldAmountOf + 1;
_x set [3, _newAmountOf];
private _newBleeding = (_oldAmountOf * _oldBleeding + _bleeding) / _newAmountOf;
_x set [4, _newBleeding];
private _newDamage = (_oldAmountOf * _oldDamage + _woundDamage) / _newAmountOf;
_x set [5, _newDamage];
_createNewWound = false;
};
_x params ["_classID", "_bodyPartN", "_oldAmountOf", "_oldBleeding", "_oldDamage"];
if (
(_classComplex == _classID) &&
{_bodyPartNToAdd == _bodyPartN} &&
{(_bodyPartNToAdd != 1) || {(_woundDamage < PENETRATION_THRESHOLD) isEqualTo (_oldDamage < PENETRATION_THRESHOLD)}} && // penetrating body damage is handled differently
{(_bodyPartNToAdd > 3) || {!_causeLimping} || {(_woundDamage <= LIMPING_DAMAGE_THRESHOLD) isEqualTo (_oldDamage <= LIMPING_DAMAGE_THRESHOLD)}} // ensure limping damage is stacked correctly
) exitWith {
TRACE_2("merging with existing wound",_injury,_x);
private _newAmountOf = _oldAmountOf + 1;
_x set [2, _newAmountOf];
private _newBleeding = (_oldAmountOf * _oldBleeding + _bleeding) / _newAmountOf;
_x set [3, _newBleeding];
private _newDamage = (_oldAmountOf * _oldDamage + _woundDamage) / _newAmountOf;
_x set [4, _newDamage];
_createNewWound = false;
};
} forEach _openWounds;
if (_createNewWound) then {
TRACE_1("adding new wound",_injury);
_openWounds pushBack _injury;
};
// New injuries will also increase the wound ID
_woundID = _woundID + 1;
// Store the injury so we can process it later correctly.
_woundsCreated pushBack _injury;
};
};
} forEach _thresholds;
if (_updateDamageEffects) then {
[_unit] call EFUNC(medical_engine,updateDamageEffects);
};
_unit setVariable [QEGVAR(medical,openWounds), _openWounds, true];
_unit setVariable [QEGVAR(medical,bodyPartDamage), _bodyPartDamage, true];
[_unit] call EFUNC(medical_status,updateWoundBloodLoss);
_bodyPartVisParams call EFUNC(medical_engine,updateBodyPartVisuals);
[QEGVAR(medical,injured), [_unit, _painLevel]] call CBA_fnc_localEvent;
@ -188,4 +193,4 @@ if (_critialDamage || {_painLevel > PAIN_UNCONSCIOUS}) then {
[_unit] call FUNC(handleIncapacitation);
};
TRACE_5("exit",_unit,_painLevel,GET_PAIN(_unit),_unit getVariable QEGVAR(medical,openWounds),_woundsCreated);
TRACE_4("exit",_unit,_painLevel,GET_PAIN(_unit),_unit getVariable QEGVAR(medical,openWounds));

View File

@ -14,5 +14,5 @@
#define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL_DAMAGE
#endif
#include "\z\ace\addons\main\script_macros.hpp"
#include "\z\ace\addons\medical_engine\script_macros_medical.hpp"
#include "\z\ace\addons\main\script_macros.hpp"

View File

@ -1,6 +1,6 @@
PREP(handleDamage);
PREP(damageBodyPart);
PREP(updateBodyPartVisuals);
PREP(setLimping);
PREP(updateDamageEffects);
PREP(setStructuralDamage);
PREP(setUnconsciousAnim);

View File

@ -1,5 +1,12 @@
#include "script_component.hpp"
[QGVAR(updateDamageEffects), LINKFUNC(updateDamageEffects)] call CBA_fnc_addEventHandler;
["unit", {
params ["_new"];
[_new] call FUNC(updateDamageEffects); // Run on new controlled unit to update QGVAR(aimFracture)
}, true] call CBA_fnc_addPlayerEventHandler;
["CAManBase", "init", {
params ["_unit"];

View File

@ -1,30 +0,0 @@
#include "script_component.hpp"
/*
* Author: commy2
* Forces a unit to limp or not.
*
* Arguments:
* 0: Unit <OBJECT>
* 1: Limping (optional, default: true) <BOOLEAN>
*
* Return Value:
* None
*
* Example:
* [player, true] call ace_medical_engine_fnc_setLimping
*
* Public: No
*/
params [["_unit", objNull, [objNull]], ["_isLimping", true, [false]]];
if (!local _unit) exitWith {
ERROR("Unit not local or null");
};
_unit setVariable [QEGVAR(medical,isLimping), _isLimping, true];
// refresh
private _isDamaged = _unit getHitPointDamage "HitLegs" >= DAMAGED_MIN_THRESHOLD && {_unit getHitPointDamage "HitLegs" != LIMPING_MIN_DAMAGE};
[_unit, "Legs", _isDamaged] call FUNC(damageBodyPart);

View File

@ -0,0 +1,67 @@
#include "script_component.hpp"
/*
* Author: commy2, PabstMirror
* Updates damage effects for limping and fractures
*
* Arguments:
* 0: Unit <OBJECT>
* 1: Limping (optional, default: true) <BOOLEAN>
*
* Return Value:
* None
*
* Example:
* [player] call ace_medical_engine_fnc_updateDamageEffects
*
* Public: No
*/
params [["_unit", objNull, [objNull]]];
if (!local _unit) exitWith { ERROR("Unit not local or null"); };
private _isLimping = false;
if (EGVAR(medical,fractures) > 0) then {
private _fractures = _unit getVariable [QEGVAR(medical,fractures), [0,0,0,0,0,0]];
TRACE_1("",_fractures);
if (((_fractures select 4) == 1) || {(_fractures select 5) == 1}) then {
TRACE_1("limping because of fracture",_fractures);
_isLimping = true;
};
private _aimFracture = 0;
if ((_fractures select 2) == 1) then { _aimFracture = _aimFracture + 4; };
if ((_fractures select 3) == 1) then { _aimFracture = _aimFracture + 4; };
if (EGVAR(medical,fractures) == 2) then { // the limp with a splint will still cause effects
private _isSprintBlocked = ((_fractures select 4) == -1) || {(_fractures select 5) == -1}; // block sprinting if we have a leg splint on
if (_isSprintBlocked || {!isSprintAllowed _unit}) then { // only update status effect if we need to
TRACE_1("updating status effect",_isSprintBlocked);
[_unit, "blockSprint", QEGVAR(medical,fracture), _isSprintBlocked] call EFUNC(common,statusEffect_set);
};
if ((_fractures select 2) == 1) then { _aimFracture = _aimFracture + 2; };
if ((_fractures select 3) == 1) then { _aimFracture = _aimFracture + 2; };
};
_unit setVariable [QGVAR(aimFracture), _aimFracture, false]; // local only var, used in ace_medical's postInit to set ACE_setCustomAimCoef
};
if (!_isLimping && {EGVAR(medical,limping) > 0}) then {
private _woundsToCheck = _unit getVariable [QEGVAR(medical,openWounds), []];
if (EGVAR(medical,limping) == 2) then {
_woundsToCheck = _woundsToCheck + (_unit getVariable [QEGVAR(medical,bandagedWounds), []]); // do not append
};
{
_x params ["_xClassID", "_xBodyPartN", "_xAmountOf", "", "_xDamage"];
if ((_xBodyPartN > 3) && {_xAmountOf > 0} && {_xDamage > LIMPING_DAMAGE_THRESHOLD} && {
(EGVAR(medical_damage,woundsData) select (_xClassID / 10)) select 7}) exitWith { // select _causeLimping from woundsData
TRACE_1("limping because of wound",_x);
_isLimping = true;
};
} forEach _woundsToCheck;
};
_unit setVariable [QEGVAR(medical,isLimping), _isLimping, true];
// refresh
private _isDamaged = _unit getHitPointDamage "HitLegs" >= DAMAGED_MIN_THRESHOLD && {_unit getHitPointDamage "HitLegs" != LIMPING_MIN_DAMAGE};
[_unit, "Legs", _isDamaged] call FUNC(damageBodyPart);

View File

@ -14,8 +14,8 @@
#define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL_ENGINE
#endif
#include "\z\ace\addons\main\script_macros.hpp"
#include "\z\ace\addons\medical_engine\script_macros_medical.hpp"
#include "\z\ace\addons\main\script_macros.hpp"
#include "\z\ace\addons\medical_engine\script_macros_config.hpp"
#define PRELOAD_CLASS(class) \

View File

@ -1,3 +1,7 @@
#define DEBUG_MODE_FULL
#define DISABLE_COMPILE_CACHE
#define ENABLE_PERFORMANCE_COUNTERS
#define ALL_BODY_PARTS ["head", "body", "leftarm", "rightarm", "leftleg", "rightleg"]
#define ALL_SELECTIONS ["head", "body", "hand_l", "hand_r", "leg_l", "leg_r"]
@ -70,12 +74,15 @@
// Minimum leg damage required for limping
#define LIMPING_DAMAGE_THRESHOLD 0.30
// Minimum limb damage required for fracture
#define FRACTURE_DAMAGE_THRESHOLD 0.50
// Minimum body part damage required for blood effect on uniform
#define VISUAL_BODY_DAMAGE_THRESHOLD 0.35
// Empty wound data, used for some default return values
// [ID, classID, bodypartIndex, amountOf, bloodloss, damage, category]
#define EMPTY_WOUND [-1, -1, -1, 0, 0, 0, 0]
// [classID, bodypartIndex, amountOf, bloodloss, damage]
#define EMPTY_WOUND [-1, -1, 0, 0, 0]
// Base time to bandage each wound category
#define BANDAGE_TIME_S 4
@ -108,6 +115,7 @@
// Defined here for easy consistency with GETVAR/SETVAR (also a list for reference)
#define VAR_BLOOD_PRESS QEGVAR(medical,bloodPressure)
#define VAR_BLOOD_VOL QEGVAR(medical,bloodVolume)
#define VAR_WOUND_BLEEDING QEGVAR(medical,woundBleeding)
#define VAR_CRDC_ARRST QEGVAR(medical,inCardiacArrest)
#define VAR_HEART_RATE QEGVAR(medical,heartRate)
#define VAR_PAIN QEGVAR(medical,pain)
@ -115,13 +123,10 @@
#define VAR_PERIPH_RES QEGVAR(medical,peripheralResistance)
#define VAR_UNCON "ACE_isUnconscious"
// These variables track gradual adjustments (from medication, etc.)
#define VAR_HEART_RATE_ADJ QEGVAR(medical,heartRateAdjustments)
#define VAR_PAIN_SUPP_ADJ QEGVAR(medical,painSuppressAdjustments)
#define VAR_PERIPH_RES_ADJ QEGVAR(medical,peripheralResistanceAdjustments)
#define VAR_MEDICATIONS QEGVAR(medical,medications)
// These variables track the current state of status values above
#define VAR_HEMORRHAGE QEGVAR(medical,hemorrhage)
#define VAR_IN_PAIN QEGVAR(medical,inPain)
#define VAR_IS_BLEEDING QEGVAR(medical,isBleeding)
#define VAR_TOURNIQUET QEGVAR(medical,tourniquets)
@ -129,13 +134,14 @@
// Retrieval macros for common unit values
// Defined for easy consistency and speed
#define GET_BLOOD_VOLUME(unit) (unit getVariable [VAR_BLOOD_VOL,DEFAULT_BLOOD_VOLUME])
#define GET_WOUND_BLEEDING(unit) (unit getVariable [VAR_WOUND_BLEEDING,0])
#define GET_HEART_RATE(unit) (unit getVariable [VAR_HEART_RATE,DEFAULT_HEART_RATE])
#define GET_HEMORRHAGE(unit) (unit getVariable [VAR_HEMORRHAGE,0])
#define GET_PAIN(unit) (unit getVariable [VAR_PAIN,0])
#define GET_PAIN_SUPPRESS(unit) (unit getVariable [VAR_PAIN_SUPP,0])
#define GET_TOURNIQUETS(unit) (unit getVariable [VAR_TOURNIQUET, DEFAULT_TOURNIQUET_VALUES])
#define IN_CRDC_ARRST(unit) (unit getVariable [VAR_CRDC_ARRST,false])
#define IS_BLEEDING(unit) (unit getVariable [VAR_IS_BLEEDING,false])
#define IS_BLEEDING(unit) (GET_WOUND_BLEEDING(unit) > 0)
#define IS_IN_PAIN(unit) (unit getVariable [VAR_IN_PAIN,false])
#define IS_UNCONSCIOUS(unit) (unit getVariable [VAR_UNCON,false])

View File

@ -14,8 +14,8 @@
#define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL_FEEDBACK
#endif
#include "\z\ace\addons\main\script_macros.hpp"
#include "\z\ace\addons\medical_engine\script_macros_medical.hpp"
#include "\z\ace\addons\main\script_macros.hpp"
#define EMPTY_SOUND {"A3\Sounds_F\dummysound.wss",1,1}
#define NAMESPACE_NULL locationNull

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -25,7 +25,7 @@ private _bloodLossOnBodyPart = 0;
// Add all bleeding from wounds on selection
{
_x params ["", "", "_bodyPartN", "_amountOf", "_bleeding"];
_x params ["", "_bodyPartN", "_amountOf", "_bleeding"];
if (_bodyPartN == _partIndex) then {
_bloodLossOnBodyPart = _bloodLossOnBodyPart + (_amountOf * _bleeding);

View File

@ -20,16 +20,17 @@ params ["_ctrlGroup", "_target"];
// Get tourniquets, damage, and blood loss for target
private _tourniquets = GET_TOURNIQUETS(_target);
private _fractures = _target getVariable [QEGVAR(medical,fractures), [0,0,0,0,0,0]];
private _bodyPartDamage = _target getVariable [QEGVAR(medical,bodyPartDamage), [0, 0, 0, 0, 0, 0]];
private _bodyPartBloodLoss = [0, 0, 0, 0, 0, 0];
{
_x params ["", "", "_bodyPartN", "_amountOf", "_bleeding"];
_x params ["", "_bodyPartN", "_amountOf", "_bleeding"];
_bodyPartBloodLoss set [_bodyPartN, (_bodyPartBloodLoss select _bodyPartN) + (_bleeding * _amountOf)];
} forEach (_target getVariable [QEGVAR(medical,openWounds), []]);
{
_x params ["_bodyPartIDC", ["_tourniquetIDC", -1]];
_x params ["_bodyPartIDC", ["_tourniquetIDC", -1], ["_fractureIDC", -1]];
// Show or hide the tourniquet icon
if (_tourniquetIDC != -1) then {
@ -37,6 +38,27 @@ private _bodyPartBloodLoss = [0, 0, 0, 0, 0, 0];
private _ctrlTourniquet = _ctrlGroup controlsGroupCtrl _tourniquetIDC;
_ctrlTourniquet ctrlShow _hasTourniquet;
};
// Show or hide fractrue/bones
if (_fractureIDC != -1) then {
private _ctrlBone = _ctrlGroup controlsGroupCtrl _fractureIDC;
switch (_fractures select _forEachIndex) do {
case (0): {
_ctrlBone ctrlShow false;
};
case (1): {
_ctrlBone ctrlShow true;
_ctrlBone ctrlSetTextColor [1, 0, 0, 1];
};
case (-1): {
if (EGVAR(medical,fractures) == 2) then {
_ctrlBone ctrlShow true;
_ctrlBone ctrlSetTextColor [0, 0, 1, 1];
} else {
_ctrlBone ctrlShow false;
};
};
};
};
// Update body part color based on blood loss and damage
private _bloodLoss = _bodyPartBloodLoss select _forEachIndex;
@ -50,10 +72,10 @@ private _bodyPartBloodLoss = [0, 0, 0, 0, 0, 0];
private _ctrlBodyPart = _ctrlGroup controlsGroupCtrl _bodyPartIDC;
_ctrlBodyPart ctrlSetTextColor _bodyPartColor;
} forEach [
[IDC_BODY_HEAD],
[IDC_BODY_TORSO],
[IDC_BODY_ARMLEFT, IDC_BODY_ARMLEFT_T],
[IDC_BODY_ARMRIGHT, IDC_BODY_ARMRIGHT_T],
[IDC_BODY_LEGLEFT, IDC_BODY_LEGLEFT_T],
[IDC_BODY_LEGRIGHT, IDC_BODY_LEGRIGHT_T]
[IDC_BODY_HEAD],
[IDC_BODY_TORSO],
[IDC_BODY_ARMLEFT, IDC_BODY_ARMLEFT_T, IDC_BODY_ARMLEFT_B],
[IDC_BODY_ARMRIGHT, IDC_BODY_ARMRIGHT_T, IDC_BODY_ARMRIGHT_B],
[IDC_BODY_LEGLEFT, IDC_BODY_LEGLEFT_T, IDC_BODY_LEGLEFT_B],
[IDC_BODY_LEGRIGHT, IDC_BODY_LEGRIGHT_T, IDC_BODY_LEGRIGHT_B]
];

View File

@ -58,6 +58,14 @@ switch (GET_HEMORRHAGE(_target)) do {
if (HAS_TOURNIQUET_APPLIED_ON(_target,_selectionN)) then {
_entries pushBack [localize LSTRING(Status_Tourniquet_Applied), [0.77, 0.51, 0.08, 1]];
};
switch ((_target getVariable [QEGVAR(medical,fractures), [0,0,0,0,0,0]]) select _selectionN) do {
case (1): {_entries pushBack [localize LSTRING(Status_Fractured), [1, 0, 0, 1]];};
case (-1): {
if (EGVAR(medical,fractures) == 2) then { // Ignore if the split has no effect
_entries pushBack [localize LSTRING(Status_SplintApplied), [1, 1, 1, 1]];
};
};
};
// Indicate the amount of pain the unit is in
if ([_target] call EFUNC(common,isAwake)) then {
@ -93,7 +101,9 @@ if (_totalIvVolume >= 1) then {
private _woundEntries = [];
private _fnc_getWoundDescription = {
private _className = EGVAR(medical_damage,woundsData) select _woundClassID select 6;
private _classIndex = _woundClassID / 10;
private _category = _woundClassID % 10;
private _className = EGVAR(medical_damage,woundsData) select _classIndex select 6;
private _suffix = ["Minor", "Medium", "Large"] select _category;
private _woundName = localize format [ELSTRING(medical_damage,%1_%2), _className, _suffix];
if (_amountOf >= 1) then {
@ -104,7 +114,7 @@ private _fnc_getWoundDescription = {
};
{
_x params ["", "_woundClassID", "_bodyPartN", "_amountOf", "", "", "_category"];
_x params ["_woundClassID", "_bodyPartN", "_amountOf"];
if (_selectionN == _bodyPartN) then {
if (_amountOf > 0) then {
_woundEntries pushBack [call _fnc_getWoundDescription, [1, 1, 1, 1]];
@ -117,14 +127,14 @@ private _fnc_getWoundDescription = {
} forEach (_target getVariable [QEGVAR(medical,openWounds), []]);
{
_x params ["", "_woundClassID", "_bodyPartN", "_amountOf", "", "", "_category"];
_x params ["_woundClassID", "_bodyPartN", "_amountOf"];
if (_selectionN == _bodyPartN && {_amountOf > 0}) then {
_woundEntries pushBack [format ["[B] %1", call _fnc_getWoundDescription], [0.88, 0.7, 0.65, 1]];
};
} forEach (_target getVariable [QEGVAR(medical,bandagedWounds), []]);
{
_x params ["", "_woundClassID", "_bodyPartN", "_amountOf", "", "", "_category"];
_x params ["_woundClassID", "_bodyPartN", "_amountOf"];
if (_selectionN == _bodyPartN && {_amountOf > 0}) then {
_woundEntries pushBack [format ["[S] %1", call _fnc_getWoundDescription], [0.7, 0.7, 0.7, 1]];
};

View File

@ -45,6 +45,24 @@ class GVAR(BodyImage): RscControlsGroupNoScrollbars {
idc = IDC_BODY_LEGRIGHT;
text = QPATHTOF(data\body_image\leg_right.paa);
};
class ArmLeftB: Background {
idc = IDC_BODY_ARMLEFT_B;
text = QPATHTOF(data\body_image\arm_left_bonel.paa);
colorText[] = {0, 0, 0.8, 1};
show = 0;
};
class ArmRightB: ArmLeftB {
idc = IDC_BODY_ARMRIGHT_B;
text = QPATHTOF(data\body_image\arm_right_boner.paa);
};
class LegLeftB: ArmLeftB {
idc = IDC_BODY_LEGLEFT_B;
text = QPATHTOF(data\body_image\leg_left_bonel.paa);
};
class LegRightB: ArmLeftB {
idc = IDC_BODY_LEGRIGHT_B;
text = QPATHTOF(data\body_image\leg_right_boner.paa);
};
class ArmLeftT: Background {
idc = IDC_BODY_ARMLEFT_T;
text = QPATHTOF(data\body_image\arm_left_t.paa);
@ -549,6 +567,22 @@ class RscTitles {
w = POS_W(8.5);
h = POS_H(8.5);
};
class ArmLeftB: ArmLeftB {
w = POS_W(8.5);
h = POS_H(8.5);
};
class ArmRightB: ArmRightB {
w = POS_W(8.5);
h = POS_H(8.5);
};
class LegLeftB: LegLeftB {
w = POS_W(8.5);
h = POS_H(8.5);
};
class LegRightB: LegRightB {
w = POS_W(8.5);
h = POS_H(8.5);
};
class ArmLeftT: ArmLeftT {
w = POS_W(8.5);
h = POS_H(8.5);

View File

@ -14,8 +14,8 @@
#define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL_GUI
#endif
#include "\z\ace\addons\main\script_macros.hpp"
#include "\z\ace\addons\medical_engine\script_macros_medical.hpp"
#include "\z\ace\addons\main\script_macros.hpp"
#include "\a3\ui_f\hpp\defineResincl.inc"
#include "\a3\ui_f\hpp\defineDIKCodes.inc"
@ -67,6 +67,10 @@
#define IDC_BODY_ARMRIGHT_T 6040
#define IDC_BODY_LEGLEFT_T 6045
#define IDC_BODY_LEGRIGHT_T 6050
#define IDC_BODY_ARMLEFT_B 6055
#define IDC_BODY_ARMRIGHT_B 6060
#define IDC_BODY_LEGRIGHT_B 6065
#define IDC_BODY_LEGLEFT_B 6070
#define IDC_TRIAGE_STATUS 7000
#define IDC_TRIAGE_SELECT 7100

View File

@ -775,6 +775,12 @@
<Chinesesimp>大量失血</Chinesesimp>
<Chinese>大量失血</Chinese>
</Key>
<Key ID="STR_ACE_Medical_GUI_Status_Fractured">
<English>Fractured</English>
</Key>
<Key ID="STR_ACE_Medical_GUI_Status_SplintApplied">
<English>Splint Applied</English>
</Key>
<!--
Strings above match Blood2 but seem to differ in some languages, determine which is best to use
-->

Binary file not shown.

View File

@ -14,5 +14,5 @@
#define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL_STATEMACHINE
#endif
#include "\z\ace\addons\main\script_macros.hpp"
#include "\z\ace\addons\medical_engine\script_macros_medical.hpp"
#include "\z\ace\addons\main\script_macros.hpp"

View File

@ -1,4 +1,4 @@
PREP(addHeartRateAdjustment);
PREP(addMedicationAdjustment);
PREP(adjustPainLevel);
PREP(getBloodLoss);
PREP(getBloodPressure);
@ -12,3 +12,4 @@ PREP(isInStableCondition);
PREP(setCardiacArrest);
PREP(setDead);
PREP(setUnconscious);
PREP(updateWoundBloodLoss);

View File

@ -1,21 +0,0 @@
#include "script_component.hpp"
/*
* Author: BaerMitUmlaut
* Adds a heart rate adjustment that will take effect over time.
*
* Arguments:
* 0: The Unit <OBJECT>
* 1: Heart rate change <NUMBER>
* 2: Time in system for the adjustment to reach its peak <NUMBER>
* 3: Duration the adjustment will have an effect <NUMVER>
*
* Return Value:
* None
*/
params ["_unit", "_change", "_timeToMaxEffect", "_maxTimeInSystem"];
private _adjustments = _unit getVariable [VAR_HEART_RATE_ADJ,[]];
// The last number indicates the time the adjustment is already in the system
_adjustments pushBack [_change, _timeToMaxEffect, _maxTimeInSystem, 0];
_unit setVariable [VAR_HEART_RATE_ADJ, _adjustments];

View File

@ -0,0 +1,32 @@
#include "script_component.hpp"
/*
* Author: BaerMitUmlaut, PabstMirror
* Adds a medication and it's effects
*
* Arguments:
* 0: The Unit <OBJECT>
* 1: Medication <STRING>
* 2: Time in system for the adjustment to reach its peak <NUMBER>
* 3: Duration the adjustment will have an effect <NUMVER>
* 4: Heart Rate Adjust <NUMVER>
* 5: Pain Suppress Adjust <NUMVER>
* 6: Flow Adjust <NUMVER>
*
* Return Value:
* None
*
* Example:
* [player, "Morphine", 120, 60, -10, 0.8, -10] call ace_medical_status_fnc_addMedicationAdjustment
*/
params ["_unit", "_medication", "_timeToMaxEffect", "_maxTimeInSystem", "_hrAdjust", "_painAdjust", "_flowAdjust"];
TRACE_7("addMedicationAdjustment",_unit,_medication,_timeToMaxEffect,_maxTimeInSystem,_hrAdjust,_painAdjust,_flowAdjust);
if (_maxTimeInSystem <= 0) exitWith { WARNING_1("bad value for _maxTimeInSystem - %1",_this); };
_timeToMaxEffect = _timeToMaxEffect max 1;
private _adjustments = _unit getVariable [VAR_MEDICATIONS, []];
_adjustments pushBack [_medication, CBA_missionTime, _timeToMaxEffect, _maxTimeInSystem, _hrAdjust, _painAdjust, _flowAdjust];
_unit setVariable [VAR_MEDICATIONS, _adjustments, true];

View File

@ -10,31 +10,16 @@
* Total blood loss of unit <NUMBER>
*
* Example:
* [bob] call ace_medical_status_fnc_getBloodLoss
* [player] call ace_medical_status_fnc_getBloodLoss
*
* Public: No
*/
params ["_unit"];
private _tourniquets = GET_TOURNIQUETS(_unit);
private _bodyPartBleeding = [0,0,0,0,0,0];
{
_x params ["", "", "_bodyPart", "_amountOf", "_bleeeding"];
if (_tourniquets select _bodyPart == 0) then {
_bodyPartBleeding set [_bodyPart, (_bodyPartBleeding select _bodyPart) + (_amountOf * _bleeeding)];
};
} forEach (_unit getVariable [QEGVAR(medical,openWounds), []]);
if (_bodyPartBleeding isEqualTo [0,0,0,0,0,0]) exitWith { 0 };
_bodyPartBleeding params ["_headBleeding", "_bodyBleeding", "_leftArmBleeding", "_rightArmBleeding", "_leftLegBleeding", "_rightLegBleeding"];
private _bodyBleedingRate = ((_headBleeding min 0.9) + (_bodyBleeding min 1.0)) min 1.0;
private _limbBleedingRate = ((_leftArmBleeding min 0.3) + (_rightArmBleeding min 0.3) + (_leftLegBleeding min 0.5) + (_rightLegBleeding min 0.5)) min 1.0;
// limb bleeding is scaled down based on the amount of body bleeding
_limbBleedingRate = _limbBleedingRate * (1 - _bodyBleedingRate);
private _woundBleeding = GET_WOUND_BLEEDING(_unit);
if (_woundBleeding == 0) exitWith {0};
private _cardiacOutput = [_unit] call FUNC(getCardiacOutput);
((_bodyBleedingRate + _limbBleedingRate) * _cardiacOutput * EGVAR(medical,bleedingCoefficient))
(_woundBleeding * _cardiacOutput * EGVAR(medical,bleedingCoefficient))

View File

@ -19,7 +19,6 @@
params ["_unit", "_deltaT", "_syncValues"];
private _bloodVolume = GET_BLOOD_VOLUME(_unit);
private _bloodVolumeChange = -_deltaT * GET_BLOOD_LOSS(_unit);
if (!isNil {_unit getVariable QEGVAR(medical,ivBags)}) then {

View File

@ -21,12 +21,12 @@
*/
// to limit the amount of complex calculations necessary, we take a set modifier to calculate Stroke Volume.
#define MODIFIER_CARDIAC_OUTPUT 19.04761
#define MODIFIER_CARDIAC_OUTPUT 0.1904761
params ["_unit"];
private _bloodVolume = (GET_BLOOD_VOLUME(_unit) / DEFAULT_BLOOD_VOLUME) * 100;
private _bloodVolumeRatio = (GET_BLOOD_VOLUME(_unit) / DEFAULT_BLOOD_VOLUME);
private _heartRate = GET_HEART_RATE(_unit);
private _cardiacOutput = ((_bloodVolume / MODIFIER_CARDIAC_OUTPUT) + ((_heartRate / DEFAULT_HEART_RATE) - 1)) / 60;
private _cardiacOutput = ((_bloodVolumeRatio / MODIFIER_CARDIAC_OUTPUT) + ((_heartRate / DEFAULT_HEART_RATE) - 1)) / 60;
(0 max _cardiacOutput)

View File

@ -26,19 +26,15 @@ if (damage _unit > 0) then {
// - Blood and heart ----------------------------------------------------------
_unit setVariable [VAR_BLOOD_VOL, DEFAULT_BLOOD_VOLUME, true];
_unit setVariable [VAR_HEART_RATE, DEFAULT_HEART_RATE, true];
_unit setVariable [VAR_HEART_RATE_ADJ, [], true];
_unit setVariable [VAR_BLOOD_PRESS, [80, 120], true];
_unit setVariable [VAR_PERIPH_RES, DEFAULT_PERIPH_RES, true];
_unit setVariable [VAR_PERIPH_RES_ADJ, [], true];
_unit setVariable [VAR_CRDC_ARRST, false, true];
_unit setVariable [VAR_HEMORRHAGE, 0, true];
_unit setVariable [VAR_IS_BLEEDING, false, true];
// - Pain ---------------------------------------------------------------------
_unit setVariable [VAR_PAIN, 0, true];
_unit setVariable [VAR_IN_PAIN, false, true];
_unit setVariable [VAR_PAIN_SUPP, 0, true];
_unit setVariable [VAR_PAIN_SUPP_ADJ, [], true];
// - Wounds -------------------------------------------------------------------
_unit setVariable [QEGVAR(medical,openWounds), [], true];
@ -65,11 +61,7 @@ _unit setVariable [QEGVAR(medical,bodyPartStatus), [0,0,0,0,0,0], true];
#endif
// medication
private _allUsedMedication = _unit getVariable [QEGVAR(medical,allUsedMedication), []];
{
_unit setVariable [_x select 0, nil];
} forEach _allUsedMedication;
_unit setVariable [QEGVAR(medical,allUsedMedication), [], true];
_unit setVariable [VAR_MEDICATIONS, [], true];
// TODO move to treatment
private _logs = _unit getVariable [QEGVAR(medical,allLogs), []];

View File

@ -19,5 +19,5 @@ params ["_unit"];
(alive _unit
&& {!IS_UNCONSCIOUS(_unit)}
&& {GET_BLOOD_LOSS(_unit) == 0}
&& {GET_WOUND_BLEEDING(_unit) == 0}
&& {_unit call FUNC(hasStableVitals)})

View File

@ -0,0 +1,42 @@
#include "script_component.hpp"
/*
* Author: Glowbal
* Update total wound bleeding based on open wounds and tourniquets
*
* Arguments:
* 0: The Unit <OBJECT>
*
* Return Value:
* Nothing
*
* Example:
* [player] call ace_medical_status_fnc_updateWoundBloodLoss
*
* Public: No
*/
params ["_unit"];
private _tourniquets = GET_TOURNIQUETS(_unit);
private _bodyPartBleeding = [0,0,0,0,0,0];
{
_x params ["", "_bodyPart", "_amountOf", "_bleeeding"];
if (_tourniquets select _bodyPart == 0) then {
_bodyPartBleeding set [_bodyPart, (_bodyPartBleeding select _bodyPart) + (_amountOf * _bleeeding)];
};
} forEach (_unit getVariable [QEGVAR(medical,openWounds), []]);
if (_bodyPartBleeding isEqualTo [0,0,0,0,0,0]) then {
TRACE_1("updateWoundBloodLoss-none",_unit);
_unit setVariable [VAR_WOUND_BLEEDING, 0, true];
} else {
_bodyPartBleeding params ["_headBleeding", "_bodyBleeding", "_leftArmBleeding", "_rightArmBleeding", "_leftLegBleeding", "_rightLegBleeding"];
private _bodyBleedingRate = ((_headBleeding min 0.9) + (_bodyBleeding min 1.0)) min 1.0;
private _limbBleedingRate = ((_leftArmBleeding min 0.3) + (_rightArmBleeding min 0.3) + (_leftLegBleeding min 0.5) + (_rightLegBleeding min 0.5)) min 1.0;
// limb bleeding is scaled down based on the amount of body bleeding
_limbBleedingRate = _limbBleedingRate * (1 - _bodyBleedingRate);
TRACE_3("updateWoundBloodLoss-bleeding",_unit,_bodyBleedingRate,_limbBleedingRate);
_unit setVariable [VAR_WOUND_BLEEDING, _bodyBleedingRate + _limbBleedingRate, true];
};

View File

@ -14,5 +14,5 @@
#define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL_STATUS
#endif
#include "\z\ace\addons\main\script_macros.hpp"
#include "\z\ace\addons\medical_engine\script_macros_medical.hpp"
#include "\z\ace\addons\main\script_macros.hpp"

View File

@ -91,6 +91,19 @@ class GVAR(actions) {
condition = QUOTE([ARR_2(_patient,_bodyPart)] call FUNC(hasTourniquetAppliedTo));
callbackSuccess = QFUNC(tourniquetRemove);
};
// --- splint
class Splint: BasicBandage {
displayName = CSTRING(Apply_Splint);
displayNameProgress = CSTRING(Applying_Splint);
category = "bandage";
icon = QPATHTOEF(medical_gui,ui\splint.paa);
allowedSelections[] = {"LeftArm", "RightArm", "LeftLeg", "RightLeg"};
items[] = {"ACE_splint"};
treatmentTime = 7;
callbackSuccess = QFUNC(splint);
condition = QUOTE(call FUNC(splintCondition));
litter[] = {};
};
// - Syringes -------------------------------------------------------------
class Morphine: FieldDressing {

View File

@ -69,6 +69,17 @@ class CfgWeapons {
mass = 2;
};
};
class ACE_splint: ACE_ItemCore {
scope = 2;
author = ECSTRING(common,ACETeam);
displayName = CSTRING(splint_Display);
picture = QPATHTOF(ui\items\tourniquet_x_ca.paa);
model = QPATHTOF(data\tourniquet.p3d);
descriptionShort = CSTRING(splint_Desc_Short);
class ItemInfo: CBA_MiscItem_ItemInfo {
mass = 2;
};
};
class ACE_morphine: ACE_ItemCore {
scope = 2;
author = ECSTRING(common,ACETeam);

View File

@ -36,6 +36,10 @@ PREP(tourniquet);
PREP(tourniquetLocal);
PREP(tourniquetRemove);
PREP(splint);
PREP(splintCondition);
PREP(splintLocal);
// misc
PREP(addToLog);
PREP(addToTriageCard);

View File

@ -16,6 +16,7 @@ if (isServer) then {
[QGVAR(treatmentIVLocal), FUNC(treatmentIVLocal)] call CBA_fnc_addEventHandler;
[QGVAR(treatmentCPRLocal), FUNC(treatmentCPRLocal)] call CBA_fnc_addEventHandler;
[QGVAR(treatmentFullHealLocal), FUNC(treatmentFullHealLocal)] call CBA_fnc_addEventHandler;
[QGVAR(treatmentSplintLocal), FUNC(splintLocal)] call CBA_fnc_addEventHandler;
// action events
[QGVAR(checkPulseLocal), FUNC(checkPulseLocal)] call CBA_fnc_addEventHandler;

View File

@ -34,9 +34,10 @@ _targetWound params ["_wound", "_woundIndex", "_effectiveness"];
if (_effectiveness == -1) exitWith {};
// Find the impact this bandage has and reduce the amount this injury is present
private _amountOf = _wound select 3;
private _amountOf = _wound select 2;
private _impact = _effectiveness min _amountOf;
_wound set [3, _amountOf - _impact];
_amountOf = _amountOf - _impact;
_wound set [2, _amountOf];
_openWounds set [_woundIndex, _wound];
_patient setVariable [QEGVAR(medical,openWounds), _openWounds, true];
@ -45,3 +46,10 @@ _patient setVariable [QEGVAR(medical,openWounds), _openWounds, true];
if (_impact > 0 && {GVAR(advancedBandages) && {GVAR(woundReopening)}}) then {
[_patient, _impact, _partIndex, _woundIndex, _wound, _bandage] call FUNC(handleBandageOpening);
};
// Check if we fixed limping from this treatment
if ((EGVAR(medical,limping) == 1) && {_partIndex > 3} && {_amountOf <= 0} && {_target getVariable [QEGVAR(medical,isLimping), false]}) then {
[_patient] call EFUNC(medical_engine,updateDamageEffects);
};
true

View File

@ -28,7 +28,7 @@ private _index = ALL_BODY_PARTS find toLower _bodyPart;
private _canBandage = false;
{
_x params ["", "", "_bodyPartN", "_amountOf", "_bleeding"];
_x params ["", "_bodyPartN", "_amountOf", "_bleeding"];
// If any single wound on the bodypart is bleeding bandaging can go ahead
if (_bodyPartN == _index && {_amountOf * _bleeding > 0}) exitWith {

View File

@ -37,15 +37,14 @@ private _woundIndex = -1;
private _effectivenessFound = -1;
{
_x params ["", "_classID", "_partIndexN", "_amountOf", "_bleeding", "_damage", "_category"];
_x params ["_classID", "_partIndexN", "_amountOf", "_bleeding", "_damage"];
// Ignore wounds on other bodyparts
if (_partIndexN == _partIndex) then {
private _woundEffectiveness = _effectiveness;
// Select the classname from the wound classname storage
private _suffix = ["Minor", "Medium", "Large"] select _category;
private _className = format ["%1%2", EGVAR(medical_damage,woundClassNames) select _classID, _suffix];
private _className = EGVAR(medical_damage,woundClassNamesComplex) select _classID;
// Get the effectiveness of the bandage on this wound type
if (isClass (_config >> _className)) then {

View File

@ -22,11 +22,13 @@ if (_partIndex < 0) exitWith { 0 };
private _targetWound = [_patient, _bandage, _partIndex] call FUNC(findMostEffectiveWound);
_targetWound params ["_wound", "_woundIndex", "_effectiveness"];
TRACE_3("findMostEffectiveWound",_wound,_woundIndex,_effectiveness);
// Everything is patched up on this body part already
if (_wound isEqualTo EMPTY_WOUND) exitWith { 0 };
_wound params ["", "", "", "_amountOf", "_bloodloss", "_damage", "_category"];
_wound params ["_classID", "", "_amountOf", "_bloodloss", "_damage"];
private _category = (_classID % 10);
// Base bandage time is based on wound size and remaining percentage
private _bandageTime = ([

View File

@ -18,13 +18,11 @@
*/
params ["_target", "_impact", "_part", "_injuryIndex", "_injury", "_bandage"];
TRACE_6("handleBandageOpening",_target,_impact,_part,_injuryIndex,_injury,_bandage);
private _classID = _injury select 1;
private _bodyPartN = _injury select 2;
private _category = _injury select 6;
private _postfix = ["Minor", "Medium", "Large"] select _category;
private _className = format ["%1%2", EGVAR(medical_damage,woundClassNames) select _classID, _postfix];
_injury params ["_classID", "_bodyPartN"];
private _className = EGVAR(medical_damage,woundClassNamesComplex) select _classID;
private _reopeningChance = DEFAULT_BANDAGE_REOPENING_CHANCE;
private _reopeningMinDelay = DEFAULT_BANDAGE_REOPENING_MIN_DELAY;
private _reopeningMaxDelay = DEFAULT_BANDAGE_REOPENING_MAX_DELAY;
@ -63,22 +61,27 @@ TRACE_5("configs",_bandage,_className,_reopeningChance,_reopeningMinDelay,_reope
private _bandagedWounds = _target getVariable [QEGVAR(medical,bandagedWounds), []];
private _exist = false;
{
_x params ["", "_id", "_partN", "_amountOf", "_bleeding", "_damage", "_oldCategory"];
if (_id == _classID && {_partN == _bodyPartN && {_oldCategory == _category}}) exitWith {
_x set [3, _amountOf + _impact];
_bandagedWounds set [_forEachIndex, _x];
_x params ["_id", "_partN", "_amountOf"];
if (_id == _classID && {_partN == _bodyPartN}) exitWith {
_x set [2, _amountOf + _impact];
TRACE_2("adding to existing bandagedWound",_id,_partN);
_exist = true;
};
} forEach _bandagedWounds;
if (!_exist) then {
TRACE_2("adding new bandagedWound",_classID,_bodyPartN);
private _bandagedInjury = +_injury;
_bandagedInjury set [3, _impact];
_bandagedInjury set [2, _impact];
_bandagedWounds pushBack _bandagedInjury;
};
_target setVariable [QEGVAR(medical,bandagedWounds), _bandagedWounds, true];
// _reopeningChance = 1;
// _reopeningMinDelay = 5;
// _reopeningMaxDelay = 6;
TRACE_1("",_reopeningChance);
// Check if we are ever going to reopen this
if (random 1 <= _reopeningChance) then {
@ -86,33 +89,42 @@ if (random 1 <= _reopeningChance) then {
TRACE_1("Will open",_delay);
[{
params ["_target", "_impact", "_part", "_injuryIndex", "_injury"];
TRACE_5("params",_target,_impact,_part,_injuryIndex,_injury);
TRACE_5("reopen delay finished",_target,_impact,_part,_injuryIndex,_injury);
private _openWounds = _target getVariable [QEGVAR(medical,openWounds), []];
if (count _openWounds - 1 < _injuryIndex) exitWith {};
if (count _openWounds - 1 < _injuryIndex) exitWith { TRACE_2("index bounds",_injuryIndex,count _openWounds); };
_injury params ["_classID", "_bodyPartN"];
_injury params ["", "_classID", "_bodyPartN"];
private _selectedInjury = _openWounds select _injuryIndex;
if (_selectedInjury select 1 == _classID && {_selectedInjury select 2 == _bodyPartN}) then { // matching the IDs
_selectedInjury params ["_selClassID", "_selBodyPart", "_selAmmount"];
if ((_selClassID == _classID) && {_selBodyPart == _bodyPartN}) then { // matching the IDs
private _bandagedWounds = _target getVariable [QEGVAR(medical,bandagedWounds), []];
private _exist = false;
{
_x params ["", "_id", "_partN", "_amountOf", "_bleeding", "_damage", "_oldCategory"];
if (_id == _classID && {_partN == _bodyPartN && {_oldCategory == _category}}) exitWith {
_x set [3, 0 max (_amountOf - _impact)];
_bandagedWounds set [_forEachIndex, _x];
_x params ["_id", "_partN", "_amountOf"];
if ((_id == _classID) && {_partN == _bodyPartN}) exitWith {
TRACE_2("bandagedWound exists",_id,_classID);
_x set [2, 0 max (_amountOf - _impact)];
_exist = true;
};
} forEach _bandagedWounds;
if (_exist) then {
TRACE_2("Reopening Wound",_bandagedWounds,_openWounds);
_selectedInjury set [3, (_selectedInjury select 3) + _impact];
_openWounds set [_injuryIndex, _selectedInjury];
_selectedInjury set [2, _selAmmount + _impact];
_target setVariable [QEGVAR(medical,bandagedWounds), _bandagedWounds, true];
_target setVariable [QEGVAR(medical,openWounds), _openWounds, true];
[_target] call EFUNC(medical_status,updateWoundBloodLoss);
// Check if we gained limping from this wound re-opening
if ((EGVAR(medical,limping) == 1) && {_bodyPartN > 3}) then {
[_target] call EFUNC(medical_engine,updateDamageEffects);
};
};
} else {
TRACE_3("no match",_selectedInjury,_classID,_bodyPartN);
};
}, [_target, _impact, _part, _injuryIndex, +_injury], _delay] call CBA_fnc_waitAndExecute;
};

View File

@ -6,69 +6,69 @@
* Arguments:
* 0: The patient <OBJECT>
* 1: Medication Treatment classname <STRING>
* 2: The medication treatment variablename <STRING>
* 3: Max dosage <NUMBER>
* 4: Incompatable medication <ARRAY<STRING>>
* 2: Max dosage <NUMBER>
* 3: Incompatable medication <ARRAY<STRING>>
*
* Return Value:
* None
*
* Example:
* [bob, "classname", "varname", 5, 6, ["stuff"]] call ace_medical_treatment_fnc_onMedicationUsage
* [player, "morphine", 4, [["x", 1]]] call ace_medical_treatment_fnc_onMedicationUsage
*
* Public: No
*/
params ["_target", "_className", "_variable", "_maxDosage", "_incompatabileMeds"];
TRACE_5("params",_target,_className,_variable,_maxDosage,_incompatabileMeds);
params ["_target", "_className", "_maxDosage", "_incompatabileMeds"];
TRACE_4("onMedicationUsage",_target,_className,_maxDosage,_incompatabileMeds);
private _foundEntry = false;
private _allUsedMedication = _target getVariable [QEGVAR(medical,allUsedMedication), []];
{
_x params ["_variableX", "_allMedsFromClassname"];
if (_variableX == _variable) exitWith {
if !(_className in _allMedsFromClassname) then {
_allMedsFromClassname pushBack _className;
_x set [1, _allMedsFromClassname];
_allUsedMedication set [_forEachIndex, _x];
_target setVariable [QEGVAR(medical,allUsedMedication), _allUsedMedication];
};
_foundEntry = true;
};
} forEach _allUsedMedication;
if (!_foundEntry) then {
_allUsedMedication pushBack [_variable, [_className]];
_target setVariable [QEGVAR(medical,allUsedMedication), _allUsedMedication];
};
private _usedMeds = _target getVariable [_variable, 0];
if (_usedMeds >= floor (_maxDosage + round(random(2))) && {_maxDosage >= 1}) then {
[QEGVAR(medical,CriticalVitals), _target] call CBA_fnc_localEvent;
};
private _hasOverDosed = 0;
{
_x params ["_med", "_limit"];
private _fnc_getMedicationCount = {
params ["_target", "_medication"];
private _return = 0;
{
_x params ["", "_classNamesUsed"];
if ({_x == _med} count _classNamesUsed > _limit) then {
_hasOverDosed = _hasOverDosed + 1;
_x params ["_xMed", "_timeAdded", "_timeTillMaxEffect", "_maxTimeInSystem"];
if (_xMed == _medication) then {
private _timeInSystem = CBA_missionTime - _timeAdded;
_return = _return + linearConversion [_timeTillMaxEffect, _maxTimeInSystem, _timeInSystem, 1, 0, true];
};
} forEach _allUsedMedication;
} forEach (_target getVariable [VAR_MEDICATIONS, []]);
TRACE_2("getMedicationCount",_medication,_return);
_return
};
private _overdosedMedications = [];
// Check for overdose from current medication
private _currentDose = [_target, _className] call _fnc_getMedicationCount;
if (_currentDose >= floor (_maxDosage + round(random(2))) && {_maxDosage >= 1}) then {
TRACE_1("exceeded max dose",_currentDose);
_overdosedMedications pushBackUnique _className;
};
// Check incompatible medication (format [med,limit])
{
_x params ["_xMed", "_xLimit"];
private _inSystem = [_target, _xMed] call _fnc_getMedicationCount;
if (_inSystem> _xLimit) then {
_overdosedMedications pushBackUnique _xMed;
};
} forEach _incompatabileMeds;
if (_hasOverDosed > 0) then {
if ((count _overdosedMedications) > 0) then {
private _medicationConfig = (configFile >> "ace_medical_treatment" >> "Medication");
private _onOverDose = getText (_medicationConfig >> "onOverDose");
if (isClass (_medicationConfig >> _className)) then {
_medicationConfig = (_medicationConfig >> _className);
if (isText (_medicationConfig >> "onOverDose")) then { _onOverDose = getText (_medicationConfig >> "onOverDose"); };
if (isText (_medicationConfig >> "onOverDose")) then { _onOverDose = getText (_medicationConfig >> "onOverDose"); };
};
TRACE_2("overdose",_overdosedMedications,_onOverDose);
if (_onOverDose == "") exitWith {
TRACE_1("CriticalVitals Event",_target); // make unconscious
[QEGVAR(medical,CriticalVitals), _target] call CBA_fnc_localEvent;
};
if (isNil _onOverDose) then {
_onOverDose = compile _onOverDose;
} else {
_onOverDose = missionNamespace getVariable _onOverDose;
};
[_target, _className] call _onOverDose;
[_target, _className, _overdosedMedications] call _onOverDose;
};

View File

@ -0,0 +1,25 @@
#include "script_component.hpp"
/*
* Author: PabstMirror
* Apply a splint to the patient
*
* Arguments:
* 0: The medic <OBJECT>
* 1: The patient <OBJECT>
* 2: Body part <STRING>
*
* Return Value:
* Nothing
*
* Example:
* [player, cursorObject, "LeftLeg"] call ace_medical_treatment_fnc_splint
*
* Public: No
*/
params ["_caller", "_target", "_bodyPart"];
TRACE_3("splint",_caller,_target,_bodyPart);
private _partIndex = ALL_BODY_PARTS find toLower _bodyPart;
[QGVAR(treatmentSplintLocal), [_caller, _target, _partIndex], _target] call CBA_fnc_targetEvent;

View File

@ -0,0 +1,25 @@
#include "script_component.hpp"
/*
* Author: PabstMirror
* Can apply a splint to the patient
*
* Arguments:
* 0: The medic <OBJECT>
* 1: The patient <OBJECT>
* 2: Body part <STRING>
*
* Return Value:
* Nothing
*
* Example:
* [player, cursorObject, "LeftLeg"] call ace_medical_treatment_fnc_splintCondition
*
* Public: No
*/
params ["", "_target", "_bodyPart"];
private _partIndex = ALL_BODY_PARTS find toLower _bodyPart;
private _fractures = _unit getVariable [QEGVAR(medical,fractures), [0,0,0,0,0,0]];
(_fractures select _partIndex) == 1

View File

@ -0,0 +1,31 @@
#include "script_component.hpp"
/*
* Author: PabstMirror
* Apply a splint to the patient
*
* Arguments:
* 0: The medic <OBJECT>
* 1: The patient <OBJECT>
* 2: Body part index <NUMBER>
*
* Return Value:
* Nothing
*
* Example:
* [player, cursorObject, 4] call ace_medical_treatment_fnc_splintLocal
*
* Public: No
*/
params ["_caller", "_target", "_bodyPartNum"];
TRACE_3("splintLocal",_caller,_target,_bodyPart);
// Place a tourniquet on the bodypart
private _fractures = _target getVariable [QEGVAR(medical,fractures), [0,0,0,0,0,0]];
_fractures set [_bodyPartNum, -1];
_target setVariable [QEGVAR(medical,fractures), _fractures, true];
// Check if we fixed limping from this treatment
[_target] call EFUNC(medical_engine,updateDamageEffects);
// toDo: AddToLog:

View File

@ -39,13 +39,15 @@ _target setVariable [QEGVAR(medical,openWounds), [], true];
_target setVariable [QEGVAR(medical,bandagedWounds), [], true];
_target setVariable [QEGVAR(medical,stitchedWounds), [], true];
_target setVariable [QEGVAR(medical,isLimping), false, true];
_target setVariable [QEGVAR(medical,fractures), [0,0,0,0,0,0], true];
// - Update wound bleeding
[_target] call EFUNC(medical_status,updateWoundBloodLoss);
// vitals
_target setVariable [VAR_HEART_RATE, DEFAULT_HEART_RATE, true];
_target setVariable [VAR_HEART_RATE_ADJ, [], true];
_target setVariable [VAR_BLOOD_PRESS, [80, 120], true];
_target setVariable [VAR_PERIPH_RES, DEFAULT_PERIPH_RES, true];
_target setVariable [VAR_PERIPH_RES_ADJ, [], true];
// IVs
_target setVariable [QEGVAR(medical,ivBags), nil, true];
@ -60,22 +62,16 @@ _target setVariable [QEGVAR(medical,bodyPartStatus), [0,0,0,0,0,0], true];
_target setVariable [VAR_CRDC_ARRST, false, true];
_target setVariable [VAR_UNCON, false, true];
_target setVariable [VAR_HEMORRHAGE, 0, true];
_target setVariable [VAR_IS_BLEEDING, false, true];
_target setVariable [VAR_IN_PAIN, false, true];
_target setVariable [VAR_PAIN_SUPP, 0, true];
_target setVariable [VAR_PAIN_SUPP_ADJ, [], true];
// medication
private _allUsedMedication = _target getVariable [QEGVAR(medical,allUsedMedication), []];
{
_target setVariable [_x select 0, nil];
} forEach _allUsedMedication;
_target setVariable [VAR_MEDICATIONS, [], true];
// Reset triage card since medication is all reset
_target setVariable [QEGVAR(medical,triageCard), [], true];
[_target, false] call EFUNC(medical_engine,setLimping);
[_target] call EFUNC(medical_engine,updateDamageEffects);
// Resetting damage
_target setDamage 0;

View File

@ -2,8 +2,8 @@
#define COMPONENT_BEAUTIFIED Medical Treatment
#include "\z\ace\addons\main\script_mod.hpp"
#define DEBUG_MODE_FULL
#define DISABLE_COMPILE_CACHE
// #define DEBUG_MODE_FULL
// #define DISABLE_COMPILE_CACHE
// #define ENABLE_PERFORMANCE_COUNTERS
#ifdef DEBUG_ENABLED_MEDICAL_TREATMENT
@ -14,8 +14,8 @@
#define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL_TREATMENT
#endif
#include "\z\ace\addons\main\script_macros.hpp"
#include "\z\ace\addons\medical_engine\script_macros_medical.hpp"
#include "\z\ace\addons\main\script_macros.hpp"
#define GET_FUNCTION(var,cfg) \
private var = getText (cfg); \

View File

@ -646,6 +646,12 @@
<Chinesesimp>用于压迫静脉与动脉的血液流动, 达到减缓失血速度的目的</Chinesesimp>
<Chinese>用於壓迫靜脈與動脈的血液流動, 達到減緩失血速度的目的</Chinese>
</Key>
<Key ID="STR_ACE_Medical_treatment_splint_Display">
<English>Splint</English>
</Key>
<Key ID="STR_ACE_Medical_treatment_splint_Desc_Short">
<English>Stabilizes a fractured limb</English>
</Key>
<Key ID="STR_ACE_Medical_treatment_Morphine_Display">
<English>Morphine autoinjector</English>
<German>Morphium-Autoinjektor</German>
@ -1841,6 +1847,12 @@
<Chinesesimp>移除军用止血带</Chinesesimp>
<Chinese>移除軍用止血帶</Chinese>
</Key>
<Key ID="STR_ACE_Medical_treatment_Apply_Splint">
<English>Apply Splint</English>
</Key>
<Key ID="STR_ACE_Medical_treatment_Applying_Splint">
<English>Applying Splint...</English>
</Key>
<Key ID="STR_ACE_Medical_treatment_Actions_Diagnose">
<English>Diagnose</English>
<German>Diagnose</German>

View File

@ -51,17 +51,7 @@ if (_hemorrhage != GET_HEMORRHAGE(_unit)) then {
_unit setVariable [VAR_HEMORRHAGE, _hemorrhage, true];
};
private _bloodLoss = GET_BLOOD_LOSS(_unit);
if (_bloodLoss > 0) then {
_unit setVariable [QGVAR(bloodloss), _bloodLoss, _syncValues];
if !IS_BLEEDING(_unit) then {
_unit setVariable [VAR_IS_BLEEDING, true, true];
};
} else {
if IS_BLEEDING(_unit) then {
_unit setVariable [VAR_IS_BLEEDING, false, true];
};
};
private _woundBloodLoss = GET_WOUND_BLEEDING(_unit);
private _inPain = GET_PAIN_PERCEIVED(_unit) > 0;
if !(_inPain isEqualTo IS_IN_PAIN(_unit)) then {
@ -80,17 +70,43 @@ if (_tourniquetPain > 0) then {
[_unit, _tourniquetPain] call EFUNC(medical_status,adjustPainLevel);
};
private _heartRate = [_unit, _deltaT, _syncValues] call FUNC(updateHeartRate);
[_unit, _deltaT, _syncValues] call FUNC(updatePainSuppress);
[_unit, _deltaT, _syncValues] call FUNC(updatePeripheralResistance);
// Get Medication Adjustments:
private _hrTargetAdjustment = 0;
private _painSupressAdjustment = 0;
private _peripheralResistanceAdjustment = 0;
private _adjustments = _unit getVariable [VAR_MEDICATIONS,[]];
if !(_adjustments isEqualTo []) then {
private _deleted = false;
{
_x params ["_medication", "_timeAdded", "_timeTillMaxEffect", "_maxTimeInSystem", "_hrAdjust", "_painAdjust", "_flowAdjust"];
private _timeInSystem = CBA_missionTime - _timeAdded;
if (_timeInSystem >= _maxTimeInSystem) then {
_deleted = true;
_adjustments set [_forEachIndex, objNull];
} else {
private _effectRatio = (((_timeInSystem / _timeTillMaxEffect) ^ 2) min 1) * (_maxTimeInSystem - _timeInSystem) / _maxTimeInSystem;
if (_hrAdjust != 0) then { _hrTargetAdjustment = _hrTargetAdjustment + _hrAdjust * _effectRatio; };
if (_painAdjust != 0) then { _painSupressAdjustment = _painSupressAdjustment + _painAdjust * _effectRatio; };
if (_hrAdjust != 0) then { _peripheralResistanceAdjustment = _peripheralResistanceAdjustment + _flowAdjust * _effectRatio; };
};
} forEach _adjustments;
if (_deleted) then {
_unit setVariable [VAR_MEDICATIONS, _adjustments - [objNull], true];
_syncValues = true;
};
};
private _heartRate = [_unit, _hrTargetAdjustment, _deltaT, _syncValues] call FUNC(updateHeartRate);
[_unit, _painSupressAdjustment, _deltaT, _syncValues] call FUNC(updatePainSuppress);
[_unit, _peripheralResistanceAdjustment, _deltaT, _syncValues] call FUNC(updatePeripheralResistance);
private _bloodPressure = GET_BLOOD_PRESSURE(_unit);
_unit setVariable [VAR_BLOOD_PRESS, _bloodPressure, _syncValues];
_bloodPressure params ["_bloodPressureL", "_bloodPressureH"];
private _cardiacOutput = [_unit] call EFUNC(medical_status,getCardiacOutput);
// Statements are ordered by most lethal first.
switch (true) do {
case (_bloodVolume < BLOOD_VOLUME_FATAL): {
@ -114,11 +130,11 @@ switch (true) do {
[QEGVAR(medical,FatalVitals), _unit] call CBA_fnc_localEvent;
};
case (_heartRate < 30): { // With a heart rate below 30 but bigger than 20 there is a chance to enter the cardiac arrest state
private _nextCheck = _unit getVariable [QGVAR(lastCheckCriticalHeartRate), CBA_missionTime];
private _nextCheck = _unit getVariable [QGVAR(nextCheckCriticalHeartRate), CBA_missionTime];
private _enterCardiacArrest = false;
if (CBA_missionTime >= _nextCheck) then {
_enterCardiacArrest = random 1 < (0.4 + 0.6*(30 - _heartRate)/10); // Variable chance of getting into cardiac arrest.
_unit setVariable [QGVAR(lastCheckCriticalHeartRate), CBA_missionTime + 5];
_unit setVariable [QGVAR(nextCheckCriticalHeartRate), CBA_missionTime + 5];
};
if (_enterCardiacArrest) then {
TRACE_2("Heart rate critical. Cardiac arrest",_unit,_heartRate);
@ -128,10 +144,10 @@ switch (true) do {
[QEGVAR(medical,CriticalVitals), _unit] call CBA_fnc_localEvent;
};
};
case (_bloodLoss / EGVAR(medical,bleedingCoefficient) > BLOOD_LOSS_KNOCK_OUT_THRESHOLD * _cardiacOutput): {
case (_woundBloodLoss > BLOOD_LOSS_KNOCK_OUT_THRESHOLD): {
[QEGVAR(medical,CriticalVitals), _unit] call CBA_fnc_localEvent;
};
case (_bloodLoss > 0): {
case (_woundBloodLoss > 0): {
[QEGVAR(medical,LoweredVitals), _unit] call CBA_fnc_localEvent;
};
case (_inPain): {
@ -140,9 +156,10 @@ switch (true) do {
};
#ifdef DEBUG_MODE_FULL
private _cardiacOutput = [_unit] call EFUNC(medical_status,getCardiacOutput);
if (!isPlayer _unit) then {
private _painLevel = _unit getVariable [VAR_PAIN, 0];
hintSilent format["blood volume: %1, blood loss: [%2, %3]\nhr: %4, bp: %5, pain: %6", round(_bloodVolume * 100) / 100, round(_bloodLoss * 1000) / 1000, round((_bloodLoss / (0.001 max _cardiacOutput)) * 100) / 100, round(_heartRate), _bloodPressure, round(_painLevel * 100) / 100];
hintSilent format["blood volume: %1, blood loss: [%2, %3]\nhr: %4, bp: %5, pain: %6", round(_bloodVolume * 100) / 100, round(_woundBloodLoss * 1000) / 1000, round((_woundBloodLoss / (0.001 max _cardiacOutput)) * 100) / 100, round(_heartRate), _bloodPressure, round(_painLevel * 100) / 100];
};
#endif

View File

@ -5,42 +5,20 @@
*
* Arguments:
* 0: The Unit <OBJECT>
* 1: Time since last update <NUMBER>
* 2: Sync value? <BOOL>
* 1: Heart Rate Adjustments <NUMBER>
* 2: Time since last update <NUMBER>
* 3: Sync value? <BOOL>
*
* ReturnValue:
* Current Heart Rate <NUMBER>
*
* Example:
* [player, 1, false] call ace_medical_vitals_fnc_updateHeartRate
* [player, 0, 1, false] call ace_medical_vitals_fnc_updateHeartRate
*
* Public: No
*/
params ["_unit", "_deltaT", "_syncValue"];
private _hrTargetAdjustment = 0;
private _adjustments = _unit getVariable [VAR_HEART_RATE_ADJ,[]];
if !(_adjustments isEqualTo []) then {
{
_x params ["_value", "_timeTillMaxEffect", "_maxTimeInSystem", "_timeInSystem"];
if (_value != 0 && {_maxTimeInSystem > 0}) then {
if (_timeInSystem >= _maxTimeInSystem) then {
_adjustments set [_forEachIndex, nil];
} else {
_timeInSystem = _timeInSystem + _deltaT;
private _effectRatio = ((_timeInSystem / (1 max _timeTillMaxEffect)) ^ 2) min 1;
_hrTargetAdjustment = _hrTargetAdjustment + _value * _effectRatio * (_maxTimeInSystem - _timeInSystem) / _maxTimeInSystem;
_x set [3, _timeInSystem];
};
} else {
_adjustments set [_forEachIndex, nil];
};
} forEach _adjustments;
_unit setVariable [VAR_HEART_RATE_ADJ, _adjustments - [nil], _syncValue];
};
params ["_unit", "_hrTargetAdjustment", "_deltaT", "_syncValue"];
private _heartRate = GET_HEART_RATE(_unit);

View File

@ -5,45 +5,26 @@
*
* Arguments:
* 0: The Unit <OBJECT>
* 1: Time since last update <NUMBER>
* 2: Sync value? <BOOL>
* 1: Pain Suppress Adjustments <NUMBER>
* 2: Time since last update <NUMBER>
* 3: Sync value? <BOOL>
*
* Return Value:
* None
*
* Example:
* [player, 0, 1, false] call ace_medical_vitals_fnc_updatePainSuppress
*
* Public: No
*/
params ["_unit", "_deltaT", "_syncValue"];
params ["_unit", "_painSupressAdjustment", "_deltaT", "_syncValue"];
private _painSupressAdjustment = 0;
private _adjustments = _unit getVariable [VAR_PAIN_SUPP_ADJ, []];
if !(_adjustments isEqualTo []) then {
{
_x params ["_value", "_timeTillMaxEffect", "_maxTimeInSystem", "_timeInSystem"];
if (_value != 0 && {_maxTimeInSystem > 0}) then {
if (_timeInSystem >= _maxTimeInSystem) then {
_adjustments set [_forEachIndex, nil];
} else {
_timeInSystem = _timeInSystem + _deltaT;
private _effectRatio = ((_timeInSystem / (1 max _timeTillMaxEffect)) ^ 2) min 1;
_painSupressAdjustment = _painSupressAdjustment + _value * _effectRatio * (_maxTimeInSystem - _timeInSystem) / _maxTimeInSystem;
_x set [3, _timeInSystem];
};
} else {
_adjustments set [_forEachIndex, nil];
};
} forEach _adjustments;
_unit setVariable [VAR_PAIN_SUPP_ADJ, _adjustments - [nil], (_syncValue || {_adjustments isEqualTo []})]; // always sync on last run
_unit setVariable [VAR_PAIN_SUPP, 0 max _painSupressAdjustment, _syncValue];
};
_unit setVariable [VAR_PAIN_SUPP, 0 max _painSupressAdjustment, _syncValue];
// Handle continuous pain reduction
private _pain = GET_PAIN(_unit);
_unit setVariable [QEGVAR(medical_status,pain), 0 max (_pain - _deltaT / PAIN_FADE_TIME), _syncValue];
_unit setVariable [VAR_PAIN, 0 max (_pain - _deltaT / PAIN_FADE_TIME), _syncValue];
// Handles simple medication
if (isNil QEGVAR(medical_treatment,advancedMedication) || {!EGVAR(medical_treatment,advancedMedication)}) then {

View File

@ -5,39 +5,19 @@
*
* Arguments:
* 0: The Unit <OBJECT>
* 1: Time since last update <NUMBER>
* 2: Sync value? <BOOL>
* 1: Peripheral Resistance Adjustments <NUMBER>
* 2: Time since last update <NUMBER>
* 3: Sync value? <BOOL>
*
* Return Value:
* None
*
* Example:
* [player, 0, 1, false] call ace_medical_vitals_fnc_updatePeripheralResistance
*
* Public: No
*/
params ["_unit", "_deltaT", "_syncValue"];
params ["_unit", "_peripheralResistanceAdjustment", "_deltaT", "_syncValue"];
private _peripheralResistanceAdjustment = 0;
private _adjustments = _unit getVariable [VAR_PERIPH_RES_ADJ, []];
if !(_adjustments isEqualTo []) then {
{
_x params ["_value", "_timeTillMaxEffect", "_maxTimeInSystem", "_timeInSystem"];
if (_value != 0 && {_maxTimeInSystem > 0}) then {
if (_timeInSystem >= _maxTimeInSystem) then {
_adjustments set [_forEachIndex, nil];
} else {
_timeInSystem = _timeInSystem + _deltaT;
private _effectRatio = ((_timeInSystem / (1 max _timeTillMaxEffect)) ^ 2) min 1;
_peripheralResistanceAdjustment = _peripheralResistanceAdjustment + _value * _effectRatio * (_maxTimeInSystem - _timeInSystem) / _maxTimeInSystem;
_x set [3, _timeInSystem];
};
} else {
_adjustments set [_forEachIndex, nil];
};
} forEach _adjustments;
_unit setVariable [VAR_PERIPH_RES_ADJ, _adjustments - [nil], _syncValue];
// always sync on last run
_unit setVariable [VAR_PERIPH_RES, 0 max (DEFAULT_PERIPH_RES + _peripheralResistanceAdjustment), _syncValue || {_adjustments isEqualTo []}];
};
_unit setVariable [VAR_PERIPH_RES, 0 max (DEFAULT_PERIPH_RES + _peripheralResistanceAdjustment), _syncValue];

View File

@ -14,5 +14,5 @@
#define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL_VITALS
#endif
#include "\z\ace\addons\main\script_macros.hpp"
#include "\z\ace\addons\medical_engine\script_macros_medical.hpp"
#include "\z\ace\addons\main\script_macros.hpp"