Medical Rewrite - Continued (#4744)

This commit is contained in:
ulteq 2016-12-05 21:34:20 +01:00 committed by GitHub
parent 9cba0baade
commit a5ce5b4a34
61 changed files with 657 additions and 1672 deletions

View File

@ -6,15 +6,15 @@ class ACE_Medical_StateMachine {
onState = QUOTE(DFUNC(handleStateDefault));
class Injury {
targetState = "Injured";
events[] = {QGVAR(TakenInjury)};
events[] = {QGVAR(Injury)};
};
class CriticalInjuryOrVitals {
targetState = "Unconscious";
events[] = {QGVAR(InjuryCritical), QGVAR(CriticalVitals)};
events[] = {QGVAR(CriticalInjury), QGVAR(CriticalVitals)};
};
class FatalInjury {
targetState = "FatalInjury";
events[] = {QGVAR(InjuryFatal)};
events[] = {QGVAR(FatalInjury)};
};
};
class Injured {
@ -23,13 +23,9 @@ class ACE_Medical_StateMachine {
targetState = "Default";
events[] = {QGVAR(FullHeal)};
};
class LastWoundTreated {
targetState = "Default";
events[] = {QGVAR(LastWoundTreated)};
};
class CriticalInjuryOrVitals {
targetState = "Unconscious";
events[] = {QGVAR(InjuryCritical), QGVAR(CriticalVitals)};
events[] = {QGVAR(CriticalInjury), QGVAR(CriticalVitals)};
};
class FatalVitals {
targetState = "CardiacArrest";
@ -37,30 +33,25 @@ class ACE_Medical_StateMachine {
};
class FatalInjury {
targetState = "FatalInjury";
events[] = {QGVAR(InjuryFatal)};
events[] = {QGVAR(FatalInjury)};
};
};
class Unconscious {
onState = QUOTE(DFUNC(handleStateUnconscious));
onStateEntered = QUOTE(DFUNC(enteredUnconsciousState));
onStateLeaving = "_this setVariable ['ACE_isUnconscious', false, true];";
class WakeUpFromKnockDown {
onStateEntered = QUOTE([ARR_2(_this,(true))] call FUNC(setUnconscious));
onStateLeaving = QUOTE([ARR_2(_this,(false))] call FUNC(setUnconscious));
class WakeUp {
targetState = "Injured";
condition = QUOTE(_this call FUNC(hasStableVitals));
events[] = {QGVAR(MinUnconsciousTimer)};
};
class WakeUpStable {
targetState = "Injured";
condition = "unitUnconsciousTimer >= MinUnconsciousTimer";
events[] = {QGVAR(VitalsWentStable)};
events[] = {QGVAR(WakeUp)};
};
class FatalTransitions {
targetState = "CardiacArrest";
events[] = {QGVAR(FatalVitals), QGVAR(UnconsciousTimerRanOut)};
events[] = {QGVAR(FatalVitals)};
};
class FatalInjury {
targetState = "FatalInjury";
events[] = {QGVAR(InjuryFatal)};
events[] = {QGVAR(FatalInjury)};
};
};
class FatalInjury {
@ -81,19 +72,19 @@ class ACE_Medical_StateMachine {
};
class CardiacArrest {
onStateEntered = QUOTE(DFUNC(enteredStateCardiacArrest));
onStateLeaving = '_this setVariable [QGVAR(cardiacArrestStart), nil]';
class TimerRanOut {
onStateLeaving = QUOTE(DFUNC(leftStateCardiacArrest));
class Timeout {
targetState = "Dead";
condition = QUOTE(DFUNC(conditionCardiacArrestTimer));
};
class Reanimated {
class Reanimation {
targetState = "Unconscious";
events[] = {QGVAR(CPRSucceeded)};
};
class Execution {
targetState = "Dead";
condition = QUOTE(DFUNC(conditionExecutionDeath));
events[] = {QGVAR(InjuryFatal)};
events[] = {QGVAR(FatalInjury)};
};
};
class Dead {

View File

@ -1,17 +1,9 @@
class ACE_Settings {
class GVAR(level) {
category = CSTRING(Category_Medical);
displayName = CSTRING(MedicalSettings_level_DisplayName);
description = CSTRING(MedicalSettings_level_Description);
value = 1;
typeName = "SCALAR";
values[] = {"Disabled", "Basic", "Advanced"};
};
class GVAR(medicSetting) {
category = CSTRING(Category_Medical);
displayName = CSTRING(MedicalSettings_medicSetting_DisplayName);
description = CSTRING(MedicalSettings_medicSetting_Description);
value = 1;
value = 0;
typeName = "SCALAR";
values[] = {"Disabled", "Normal", "Advanced"};
};
@ -26,15 +18,10 @@ class ACE_Settings {
category = CSTRING(Category_Medical);
displayName = CSTRING(AdvancedMedicalSettings_enableFor_DisplayName);
description = CSTRING(AdvancedMedicalSettings_enableFor_Description);
value = 0;
value = 1;
typeName = "SCALAR";
values[] = {"Players only", "Players and AI"};
};
class GVAR(enableOverdosing) {
category = CSTRING(Category_Medical);
typeName = "BOOL";
value = 1;
};
class GVAR(bleedingCoefficient) {
category = CSTRING(Category_Medical);
displayName = CSTRING(MedicalSettings_bleedingCoefficient_DisplayName);
@ -49,22 +36,12 @@ class ACE_Settings {
typeName = "SCALAR";
value = 1;
};
class GVAR(enableAirway) {
category = CSTRING(Category_Medical);
typeName = "BOOL";
value = false;
};
class GVAR(enableFractures) {
category = CSTRING(Category_Medical);
typeName = "BOOL";
value = false;
};
class GVAR(enableAdvancedWounds) {
category = CSTRING(Category_Medical);
displayName = CSTRING(AdvancedMedicalSettings_enableAdvancedWounds_DisplayName);
description = CSTRING(AdvancedMedicalSettings_enableAdvancedWounds_Description);
typeName = "BOOL";
value = false;
value = 1;
};
class GVAR(enableVehicleCrashes) {
category = CSTRING(Category_Medical);
@ -80,6 +57,8 @@ class ACE_Settings {
typeName = "BOOL";
value = 1;
};
// Use those for handleIncapacitation?
class GVAR(playerDamageThreshold) {
category = CSTRING(Category_Medical);
displayName = CSTRING(MedicalSettings_playerDamageThreshold_DisplayName);
@ -94,11 +73,13 @@ class ACE_Settings {
typeName = "SCALAR";
value = 1;
};
class GVAR(enableUnconsciousnessAI) {
category = CSTRING(Category_Medical);
displayName = CSTRING(MedicalSettings_enableUnconsciousnessAI_DisplayName);
description = CSTRING(MedicalSettings_enableUnconsciousnessAI_Description);
value = 1;
value = 2;
typeName = "SCALAR";
values[] = {"Disabled", "50/50", "Enabled"};
};
@ -148,7 +129,7 @@ class ACE_Settings {
displayName = CSTRING(BasicMedicalSettings_medicSetting_basicEpi_DisplayName);
description = CSTRING(BasicMedicalSettings_medicSetting_basicEpi_Description);
typeName = "SCALAR";
value = 1;
value = 0;
values[] = {"Anyone", "Medics only", "Doctors only"};
};
class GVAR(medicSetting_PAK) {
@ -156,7 +137,7 @@ class ACE_Settings {
displayName = CSTRING(AdvancedMedicalSettings_medicSetting_PAK_DisplayName);
description = CSTRING(AdvancedMedicalSettings_medicSetting_PAK_Description);
typeName = "SCALAR";
value = 1;
value = 0;
values[] = {"Anyone", "Medics only", "Doctors only"};
};
class GVAR(medicSetting_SurgicalKit) {
@ -164,7 +145,7 @@ class ACE_Settings {
displayName = CSTRING(AdvancedMedicalSettings_medicSetting_SurgicalKit_DisplayName);
description = CSTRING(AdvancedMedicalSettings_medicSetting_SurgicalKit_Description);
typeName = "SCALAR";
value = 1;
value = 0;
values[] = {"Anyone", "Medics only", "Doctors only"};
};
class GVAR(consumeItem_PAK) {
@ -172,7 +153,7 @@ class ACE_Settings {
displayName = CSTRING(AdvancedMedicalSettings_consumeItem_PAK_DisplayName);
description = CSTRING(AdvancedMedicalSettings_consumeItem_PAK_Description);
typeName = "SCALAR";
value = 0;
value = 1;
values[] = {"No", "Yes"};
};
class GVAR(consumeItem_SurgicalKit) {
@ -180,7 +161,7 @@ class ACE_Settings {
displayName = CSTRING(AdvancedMedicalSettings_consumeItem_SurgicalKit_DisplayName);
description = CSTRING(AdvancedMedicalSettings_consumeItem_SurgicalKit_Description);
typeName = "SCALAR";
value = 0;
value = 1;
values[] = {"No", "Yes"};
};
class GVAR(useLocation_basicEpi) {
@ -196,7 +177,7 @@ class ACE_Settings {
displayName = CSTRING(AdvancedMedicalSettings_useLocation_PAK_DisplayName);
description = CSTRING(AdvancedMedicalSettings_useLocation_PAK_Description);
typeName = "SCALAR";
value = 3;
value = 0;
values[] = {CSTRING(AdvancedMedicalSettings_anywhere), CSTRING(AdvancedMedicalSettings_vehicle), CSTRING(AdvancedMedicalSettings_facility), CSTRING(AdvancedMedicalSettings_vehicleAndFacility), ECSTRING(common,Disabled)};
};
class GVAR(useLocation_SurgicalKit) {
@ -204,38 +185,23 @@ class ACE_Settings {
displayName = CSTRING(AdvancedMedicalSettings_useLocation_SurgicalKit_DisplayName);
description = CSTRING(AdvancedMedicalSettings_useLocation_SurgicalKit_Description);
typeName = "SCALAR";
value = 2;
value = 0;
values[] = {CSTRING(AdvancedMedicalSettings_anywhere), CSTRING(AdvancedMedicalSettings_vehicle), CSTRING(AdvancedMedicalSettings_facility), CSTRING(AdvancedMedicalSettings_vehicleAndFacility), ECSTRING(common,Disabled)};
};
class GVAR(useCondition_PAK) {
class GVAR(fullHealLocation_PAK) {
category = CSTRING(Category_Medical);
displayName = CSTRING(AdvancedMedicalSettings_useCondition_PAK_DisplayName);
description = CSTRING(AdvancedMedicalSettings_useCondition_PAK_Description);
displayName = CSTRING(AdvancedMedicalSettings_fullHealLocation_PAK_DisplayName);
description = CSTRING(AdvancedMedicalSettings_fullHealLocation_PAK_Description);
typeName = "SCALAR";
value = 0;
values[] = {"Anytime", "Stable"};
value = 3;
values[] = {CSTRING(AdvancedMedicalSettings_anywhere), CSTRING(AdvancedMedicalSettings_vehicle), CSTRING(AdvancedMedicalSettings_facility), CSTRING(AdvancedMedicalSettings_vehicleAndFacility), ECSTRING(common,Disabled)};
};
class GVAR(useCondition_SurgicalKit) {
class GVAR(fieldEffectiveness_PAK) {
category = CSTRING(Category_Medical);
displayName = CSTRING(AdvancedMedicalSettings_useCondition_SurgicalKit_DisplayName);
description = CSTRING(AdvancedMedicalSettings_useCondition_SurgicalKit_Description);
displayName = CSTRING(MedicalSettings_fieldEffectiveness_PAK_DisplayName);
description = CSTRING(MedicalSettings_fieldEffectiveness_PAK_Description);
typeName = "SCALAR";
value = 0;
values[] = {"Anytime", "Stable"};
};
class GVAR(keepLocalSettingsSynced) {
category = CSTRING(Category_Medical);
displayName = CSTRING(MedicalSettings_keepLocalSettingsSynced_DisplayName);
description = CSTRING(MedicalSettings_keepLocalSettingsSynced_Description);
typeName = "BOOL";
value = 1;
};
class GVAR(healHitPointAfterAdvBandage) {
category = CSTRING(Category_Medical);
displayName = CSTRING(AdvancedMedicalSettings_healHitPointAfterAdvBandage_DisplayName);
description = CSTRING(AdvancedMedicalSettings_healHitPointAfterAdvBandage_Description);
typeName = "BOOL";
value = 0;
value = 0.9;
};
class GVAR(painIsOnlySuppressed) {
category = CSTRING(Category_Medical);

View File

@ -1,35 +1,41 @@
PREP(addDamageToUnit);
PREP(addStateHandler);
PREP(adjustPainLevel);
PREP(conditionCardiacArrestTimer);
PREP(conditionExecutionDeath);
PREP(enteredStateCardiacArrest);
PREP(enteredStateFatalInjury);
PREP(getBloodLoss);
PREP(getBloodPressure);
PREP(getBloodVolumeChange);
PREP(getCardiacOutput);
PREP(getHeartRateChange);
PREP(handleIncapacitation);
PREP(handleKilled);
PREP(handleLocal);
PREP(handleMedications);
PREP(handleStateDefault);
PREP(handleStateInjured);
PREP(handleStateUnconscious);
PREP(handleUnitVitals);
PREP(hasStableVitals);
PREP(hasTourniquetAppliedTo);
PREP(init);
PREP(install);
PREP(isBeingCarried);
PREP(isBeingDragged);
PREP(isInMedicalFacility);
PREP(isInMedicalVehicle);
PREP(isInStableCondition);
PREP(isMedic);
PREP(isMedicalVehicle);
// PREP(hasMedicalEnabled);
PREP(enteredStateCardiacArrest);
PREP(leavingStateCardiacArrest);
PREP(enteredStateFatalInjury);
PREP(conditionExecutionDeath);
PREP(transitionSecondChance);
PREP(handleStateDefault);
PREP(handleStateInjured);
PREP(handleStateUnconscious);
PREP(handleUnitVitals);
PREP(handleMedications);
PREP(addPain);
PREP(setUnconscious);
PREP(leftStateCardiacArrest);
PREP(moduleAssignMedicRoles);
PREP(moduleAssignMedicalVehicle);
PREP(serverRemoveBody);
PREP(setCardiacArrest);
PREP(setDead);
PREP(hasTourniquetAppliedTo);
PREP(setUnconscious);
PREP(showBloodEffect);
PREP(transitionSecondChance);

View File

@ -1,33 +0,0 @@
/*
* Author: commy2
* Adds or removes pain to/from unit.
*
* Arguments:
* 0: Unit <OBJECT>
* 1: Pain to add. Negative to remove <NUMBER>
*
* Return Value:
* Nothing
*
* Example:
* [player, 0.5] call ace_medical_fnc_addPain
*
* Public: No
*/
#include "script_component.hpp"
params ["_unit", "_painToAdd"];
private _pain = _unit getVariable [QEGVAR(medical,pain), 0];
if (_pain > 0) then {
_pain = _pain + (_painToAdd min 1) * (1 - _pain);
} else {
_pain = (_pain + _painToAdd) max 0;
};
_unit setVariable [QEGVAR(medical,pain), _pain];
if (_painToAdd > 0 && {_pain >= PAIN_UNCONSCIOUS}) then {
[_unit, true, PAIN_KNOCK_OUT_DURATION] call FUNC(setUnconscious);
};

View File

@ -1,13 +1,13 @@
/*
* Author: PabstMirror
* Interface to allow external modules to safely adjust pain levels.
* Interface to allow external modules to affect the pain level
*
* Arguments:
* 0: The patient <OBJECT>
* 1: Added ammount of pain (can be negative) <NUMBER>
* 1: Desired pain level (0 .. 1) <NUMBER>
*
* Return Value:
* The new pain level <NUMBER>
* nothing
*
* Example:
* [guy, 0.5] call ace_medical_fnc_adjustPainLevel
@ -16,21 +16,14 @@
*/
#include "script_component.hpp"
private ["_pain"];
params ["_unit", "_desiredPainLevel"];
params ["_unit", "_addedPain"];
//Only run on local units:
if (!local _unit) exitWith {ERROR("unit is not local");};
TRACE_3("ACE_DEBUG: adjustPainLevel Called",_unit, _pain, _addedPain);
if (!local _unit) exitWith { ERROR("unit is not local"); };
//Ignore if medical system disabled:
if (GVAR(level) == 0) exitWith {};
TRACE_2("ACE_DEBUG: adjustPainLevel Called",_unit,_desiredPainLevel);
private _pain = ((_unit getVariable [QGVAR(pain), 0]) + _addedPain) max 0;
private _pain = _unit getVariable [QGVAR(pain), 0];
_pain = 0 max (_pain max _desiredPainLevel) min 1;
_unit setVariable [QGVAR(pain), _pain];
//Start up the vital watching (if not already running)
// [_unit] call FUNC(addVitalLoop);
_pain;

View File

@ -1,192 +0,0 @@
/*
* Author: Glowbal
* Displays the patient information for given unit.
*
* Arguments:
* 0: The Unit <OBJECT>
* 1: Show <BOOL> (default: true)
* 2: Selection <NUMBER> (default: 0)
*
* ReturnValue:
* None
*
* Public: No
*/
#include "script_component.hpp"
#define MAX_DISTANCE 10
// Exit for basic medical
if (GVAR(level) < 2) exitWith {};
params ["_target", ["_show", true], ["_selectionN", 0]];
GVAR(currentSelectedSelectionN) = [0, _selectionN] select (IS_SCALAR(_selectionN));
GVAR(displayPatientInformationTarget) = [ObjNull, _target] select _show;
if (_show) then {
("ACE_MedicalRscDisplayInformation" call BIS_fnc_rscLayer) cutRsc [QGVAR(DisplayInformation),"PLAIN"];
[{
private ["_target", "_display", "_alphaLevel", "_damaged", "_availableSelections", "_openWounds", "_selectionBloodLoss", "_red", "_green", "_blue", "_alphaLevel", "_allInjuryTexts", "_lbCtrl", "_genericMessages"];
params ["_args", "_idPFH"];
_args params ["_target", "_selectionN"];
if (GVAR(displayPatientInformationTarget) != _target || GVAR(currentSelectedSelectionN) != _selectionN) exitwith {
[_idPFH] call CBA_fnc_removePerFrameHandler;
};
if (ACE_player distance _target > MAX_DISTANCE) exitwith {
("ACE_MedicalRscDisplayInformation" call BIS_fnc_rscLayer) cutText ["","PLAIN"];
[_idPFH] call CBA_fnc_removePerFrameHandler;
[QEGVAR(common,displayTextStructured), [[LSTRING(DistanceToFar), [_target] call EFUNC(common,getName)], 1.75, ACE_player], [ACE_player]] call CBA_fnc_targetEvent;
};
disableSerialization;
private _display = uiNamespace getVariable QGVAR(DisplayInformation);
if (isnil "_display") exitwith {
[_idPFH] call CBA_fnc_removePerFrameHandler;
};
private _allInjuryTexts = [];
private _genericMessages = [];
private _partText = [LSTRING(Head), LSTRING(Torso), LSTRING(LeftArm) ,LSTRING(RightArm) ,LSTRING(LeftLeg), LSTRING(RightLeg)] select _selectionN;
_genericMessages pushback [localize _partText, [1, 1, 1, 1]];
if (_target getVariable[QGVAR(isBleeding), false]) then {
_genericMessages pushback [localize LSTRING(Status_Bleeding), [1, 0.1, 0.1, 1]];
};
if (_target getVariable[QGVAR(hasLostBlood), 0] > 1) then {
_genericMessages pushback [localize LSTRING(Status_Lost_Blood), [1, 0.1, 0.1, 1]];
};
if (((_target getVariable [QGVAR(tourniquets), [0,0,0,0,0,0]]) select _selectionN) > 0) then {
_genericMessages pushback [localize LSTRING(Status_Tourniquet_Applied), [0.77, 0.51, 0.08, 1]];
};
if (_target getVariable[QGVAR(hasPain), false]) then {
_genericMessages pushback [localize LSTRING(Status_Pain), [1, 1, 1, 1]];
};
private _totalIvVolume = 0;
private _bloodBags = _unit getVariable [QGVAR(ivBags), []];
{
_x params ["_bagVolumeRemaining"];
_totalIvVolume = _totalIvVolume + _bagVolumeRemaining;
} foreach _bloodBags;
if (_totalIvVolume >= 1) then {
_genericMessages pushback [format[localize LSTRING(receivingIvVolume), floor _totalIvVolume], [1, 1, 1, 1]];
};
private _damaged = [false, false, false, false, false, false];
private _selectionBloodLoss = [0,0,0,0,0,0];
private _openWounds = _target getVariable [QGVAR(openWounds), []];
{
_x params ["", "_x1", "_selectionX", "_amountOf", "_x4"];
// Find how much this bodypart is bleeding
if (_amountOf > 0) then {
_damaged set [_selectionX, true];
_selectionBloodLoss set [_selectionX, (_selectionBloodLoss select _selectionX) + (20 * (_x4 * _amountOf))];
if (_selectionN == _selectionX) then {
// Collect the text to be displayed for this injury [ Select injury class type definition - select the classname DisplayName (6th), amount of injuries for this]
if (_amountOf >= 1) then {
// TODO localization
_allInjuryTexts pushback [format["%2x %1", (EGVAR(medical_damage,woundsData) select _x1) select 6, ceil _amountOf], [1,1,1,1]];
} else {
// TODO localization
_allInjuryTexts pushback [format["Partial %1", (EGVAR(medical_damage,woundsData) select _x1) select 6], [1,1,1,1]];
};
};
};
} foreach _openWounds;
private _bandagedwounds = _target getVariable [QGVAR(bandagedWounds), []];
{
_x params ["", "", "_selectionX", "_amountOf", "_x4"];
// Find how much this bodypart is bleeding
if !(_damaged select _selectionX) then {
_selectionBloodLoss set [_selectionX, (_selectionBloodLoss select _selectionX) + (20 * (_x4 * _amountOf))];
};
if (_selectionN == _selectionX) then {
// Collect the text to be displayed for this injury [ Select injury class type definition - select the classname DisplayName (6th), amount of injuries for this]
if (_amountOf > 0) then {
if (_amountOf >= 1) then {
// TODO localization
_allInjuryTexts pushback [format["[B] %2x %1", (EGVAR(medical_damage,woundsData) select (_x select 1)) select 6, ceil _amountOf], [0.88,0.7,0.65,1]];
} else {
// TODO localization
_allInjuryTexts pushback [format["[B] Partial %1", (EGVAR(medical_damage,woundsData) select (_x select 1)) select 6], [0.88,0.7,0.65,1]];
};
};
};
} foreach _bandagedwounds;
// Handle the body image coloring
private _availableSelections = [50,51,52,53,54,55];
{
private _total = _x;
private _red = 1;
private _green = 1;
private _blue = 1;
if (_total > 0) then {
if (_damaged select _forEachIndex) then {
_green = (0.9 - _total) max 0;
_blue = _green;
} else {
_green = (0.9 - _total) max 0;
_red = _green;
//_blue = _green;
};
};
(_display displayCtrl (_availableSelections select _foreachIndex)) ctrlSetTextColor [_red, _green, _blue, 1.0];
} foreach _selectionBloodLoss;
private _lbCtrl = (_display displayCtrl 200);
lbClear _lbCtrl;
{
_x params ["_add", "_color"];
_lbCtrl lbAdd _add;
_lbCtrl lbSetColor [_foreachIndex, _color];
} foreach _genericMessages;
private _amountOfGeneric = count _genericMessages;
{
_x params ["_add", "_color"];
_lbCtrl lbAdd _add;
_lbCtrl lbSetColor [_foreachIndex + _amountOfGeneric, _color];
} foreach _allInjuryTexts;
if (count _allInjuryTexts == 0) then {
_lbCtrl lbAdd (localize LSTRING(NoInjuriesBodypart));
};
private _logCtrl = (_display displayCtrl 302);
lbClear _logCtrl;
private _logs = _target getVariable [QGVAR(logFile_Activity), []];
{
_x params ["_message", "_moment", "_type", "_arguments"];
if (isLocalized _message) then {
_message = localize _message;
};
{
if (_x isEqualType "" && {isLocalized _x}) then {
_arguments set [_foreachIndex, localize _x];
};
} foreach _arguments;
_message = format([_message] + _arguments);
_logCtrl lbAdd format["%1 %2", _moment, _message];
} foreach _logs;
private _triageStatus = [_target] call EFUNC(medical_treatment,getTriageStatus);
(_display displayCtrl 303) ctrlSetText (_triageStatus select 0);
(_display displayCtrl 303) ctrlSetBackgroundColor (_triageStatus select 2);
}, 0, [_target, GVAR(currentSelectedSelectionN)]] call CBA_fnc_addPerFrameHandler;
} else {
("ACE_MedicalRscDisplayInformation" call BIS_fnc_rscLayer) cutText ["","PLAIN"];
};

View File

@ -11,6 +11,9 @@
* Public: No
*/
#include "script_component.hpp"
params ["_unit"];
_unit setVariable [QGVAR(cardiacArrestStart), CBA_missionTime];
[_unit] call FUNC(setCardiacArrest);

View File

@ -1,23 +0,0 @@
/*
* Author: Glowbal
* Handle entering an unconscious state.
*
* Arguments:
* 0: The unit that will be put in an unconscious state <OBJECT>
* 1: Set unconsciouns <BOOL> (default: true)
* 2: Minimum unconscious time <NUMBER> (default: (round(random(10)+5)))
* 3: Force AI Unconscious (skip random death chance) <BOOL> (default: false)
*
* ReturnValue:
* nil
*
* Public: no
*/
#include "script_component.hpp"
#define DEFAULT_DELAY (round(random(10)+5))
params ["_unit", "_event", "_args"];
[_unit, true] call FUNC(setUnconscious);

View File

@ -6,7 +6,7 @@
* 0: The Unit <OBJECT>
*
* ReturnValue:
* Total blood loss of unit <NUMBER>
* Total blood loss of unit (liter per second) <NUMBER>
*
* Public: No
*/
@ -14,18 +14,26 @@
params ["_unit"];
private _totalBloodLoss = 0;
private _bloodLoss = 0;
private _limbBleeding = 0;
private _bodyBleeding = 0;
private _tourniquets = _unit getVariable [QGVAR(tourniquets), [0,0,0,0,0,0]];
{
if (_tourniquets select (_x select 2) == 0) then {
// total bleeding ratio * percentage of injury left
_totalBloodLoss = _totalBloodLoss + ((_x select 4) * (_x select 3));
_x params ["", "", "_bodyPart", "_percentage", "_bleeeding"];
if (_bodyPart == 1) then {
_bodyBleeding = _bodyBleeding + (_bleeeding * _percentage);
} else {
if (_tourniquets select _bodyPart == 0) then {
_limbBleeding = _limbBleeding + (_bleeeding * _percentage);
};
};
} forEach (_unit getVariable [QGVAR(openWounds), []]);
{
_totalBloodLoss = _totalBloodLoss + ((_x select 4) * (_x select 3));
} forEach (_unit getVariable [QGVAR(internalWounds), []]);
private _cardiacOutput = [_unit] call FUNC(getCardiacOutput);
_totalBloodLoss * ((_unit getVariable [QGVAR(bleedingCoefficient), GVAR(bleedingCoefficient)]) max 0) * DEFAULT_BLOOD_VOLUME / 100;
// limb bleeding is scaled down based on the amount of body bleeding and limited by the current cardiac output
_limbBleeding = 0 max (_limbBleeding * (1 - (_bodyBleeding min 1))) min 1;
_bloodLoss = (_bodyBleeding + _limbBleeding) * _cardiacOutput;
_bloodLoss * (_unit getVariable [QGVAR(bleedingCoefficient), GVAR(bleedingCoefficient)])

View File

@ -1,6 +1,6 @@
/*
* Author: Glowbal
* Calculates the blood volume change and decreases the IVs given to the unit.
* Calculate the blood pressure of a unit.
*
* Arguments:
* 0: The Unit <OBJECT>
@ -15,17 +15,15 @@
#include "script_component.hpp"
// Value is taken because with cardic output and resistance at default values, it will put blood pressure High at 120.
#define MODIFIER_BP_HIGH 0.229
#define MODIFIER_BP_HIGH 13.7142792
// Value is taken because with cardic output and resistance at default values, it will put blood pressure Low at 80.
#define MODIFIER_BP_LOW 0.1524
#define MODIFIER_BP_LOW 9.1428528
params ["_unit"];
private _cardiacOutput = [_unit] call FUNC(getCardiacOutput);
private _resistance = _unit getVariable [QGVAR(peripheralResistance), 100];
private _bloodPressure = _cardiacOutput * _resistance;
private _bloodPressureHigh = (_cardiacOutput * MODIFIER_BP_HIGH) * _resistance;
private _bloodPressureLow = (_cardiacOutput * MODIFIER_BP_LOW) * _resistance;
[_bloodPressureLow max 0, _bloodPressureHigh max 0]
[round(_bloodPressure * MODIFIER_BP_LOW), round(_bloodPressure * MODIFIER_BP_HIGH)]

View File

@ -4,47 +4,49 @@
*
* Arguments:
* 0: The Unit <OBJECT>
* 1: Global Sync Values (bloodbags) <BOOL>
* 1: Time since last update <NUMBER>
* 2: Global Sync Values (bloodbags) <BOOL>
*
* ReturnValue:
* Blood volume change (in % total) <NUMBER>
* Blood volume change (liters per second) <NUMBER>
*
* Public: No
*/
#include "script_component.hpp"
params ["_unit", "_syncValues"];
params ["_unit", "_deltaT", "_syncValues"];
private _bloodVolume = _unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME];
private _bloodVolumeChange = -(_unit call FUNC(getBloodLoss));
private _bloodVolumeChange = -_deltaT * (_unit call FUNC(getBloodLoss));
if (!isNil {_unit getVariable QGVAR(ivBags)}) then {
if (_bloodVolume < DEFAULT_BLOOD_VOLUME) then {
private _bloodBags = _unit getVariable [QGVAR(ivBags), []];
private _bloodBags = _unit getVariable [QGVAR(ivBags), []];
_bloodBags = _bloodBags apply {
_x params ["_bagVolumeRemaining"];
_bloodBags = _bloodBags apply {
_x params ["_bagVolumeRemaining"];
private _bagChange = IV_CHANGE_PER_SECOND min _bagVolumeRemaining; // absolute value of the change in miliLiters
if (GVAR(advancedIVBags)) then {
private _bagChange = _deltaT * (IV_CHANGE_PER_SECOND min _bagVolumeRemaining); // absolute value of the change in miliLiters
_bagVolumeRemaining = _bagVolumeRemaining - _bagChange;
_bloodVolumeChange = _bloodVolumeChange + (_bagChange / 1000);
if (_bagVolumeRemaining < 0.01) then {
[]
} else {
[_bagVolumeRemaining];
[_bagVolumeRemaining]
};
};
_bloodBags = _bloodBags - [[]]; // remove empty bags
if (_bloodBags isEqualTo []) then {
_unit setVariable [QGVAR(ivBags), nil, true]; // no bags left - clear variable (always globaly sync this)
} else {
_unit setVariable [QGVAR(ivBags), _bloodBags, _syncValues];
_bloodVolumeChange = _bloodVolumeChange + (_bagVolumeRemaining / 1000);
[]
};
};
_bloodBags = _bloodBags - [[]]; // remove empty bags
if (_bloodBags isEqualTo []) then {
_unit setVariable [QGVAR(ivBags), nil, true]; // no bags left - clear variable (always globaly sync this)
} else {
_unit setVariable [QGVAR(ivBags), nil, true]; // blood volume = 100% - clear variable (always globaly sync this)
_unit setVariable [QGVAR(ivBags), _bloodBags, _syncValues];
};
};

View File

@ -6,7 +6,7 @@
* 0: The Unit <OBJECT>
*
* ReturnValue:
* Current cardiac output <NUMBER>
* Current cardiac output (liter per second) <NUMBER>
*
* Public: No
*/
@ -14,8 +14,7 @@
#include "script_component.hpp"
/*
Cardiac output (Q or or CO ) is the volume of blood being pumped by the heart, in particular by a left or right ventricle in the CBA_missionTime interval of one minute. CO may be measured in many ways, for example dm3/min (1 dm3 equals 1 litre).
Cardiac output (Q or or CO ) is the volume of blood being pumped by the heart, in particular by a left or right ventricle in the CBA_missionTime interval of one second. CO may be measured in many ways, for example dm3/min (1 dm3 equals 1 litre).
Source: http://en.wikipedia.org/wiki/Cardiac_output
*/
@ -24,4 +23,10 @@
params ["_unit"];
((_unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME]) / MODIFIER_CARDIAC_OUTPUT) + ((_unit getVariable [QGVAR(heartRate), 80]) / 80 - 1);
if (_unit getVariable [QGVAR(inCardiacArrest), false]) exitWith { 0 };
private _bloodVolume = ((_unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME]) / DEFAULT_BLOOD_VOLUME) * 100;
private _heartRate = _unit getVariable [QGVAR(heartRate), 80];
private _cardiacOutput = ((_bloodVolume / MODIFIER_CARDIAC_OUTPUT) + ((_heartRate / 80) - 1)) / 60;
(0 max _cardiacOutput)

View File

@ -13,15 +13,11 @@
#include "script_component.hpp"
#define HEART_RATE_MODIFIER 0.02
params ["_unit"];
private _hrIncrease = 0;
if (!(_unit getVariable [QGVAR(inCardiacArrest),false])) then {
private _heartRate = _unit getVariable [QGVAR(heartRate), 80];
private _bloodLoss = [_unit] call FUNC(getBloodLoss);
if (!(_unit getVariable [QGVAR(inCardiacArrest),false])) then {
private _adjustment = _unit getVariable [QGVAR(heartRateAdjustments), []];
{
_x params ["_values", "_time", "_callBack"];
@ -49,36 +45,37 @@ if (!(_unit getVariable [QGVAR(inCardiacArrest),false])) then {
_adjustment = _adjustment - [ObjNull];
_unit setVariable [QGVAR(heartRateAdjustments), _adjustment];
private _bloodVolume = _unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME];
if (_bloodVolume > 75) then {
if (_bloodLoss > 0.0) then {
if (_bloodLoss < 0.5) then {
if (_heartRate < 126) then {
_hrIncrease = _hrIncrease + 0.05;
};
} else {
if (_bloodLoss < 1) then {
if (_heartRate < 161) then {
_hrIncrease = _hrIncrease + 0.1;
};
} else {
if (_heartRate < 220) then {
_hrIncrease = _hrIncrease + 0.15;
};
if (!(_unit getVariable [QGVAR(inCardiacArrest), false])) then {
private _heartRate = (_unit getVariable [QGVAR(heartRate), 80]);
private _bloodVolume = _unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME];
if (_bloodVolume > BLOOD_VOLUME_CLASS_4_HEMORRHAGE) then {
private _hrChange = 0;
([_unit] call FUNC(getBloodPressure)) params ["_bloodPressureL", "_bloodPressureH"];
private _meanBP = (2/3) * _bloodPressureH + (1/3) * _bloodPressureL;
private _pain = _unit getVariable [QGVAR(pain), 0];
private _hasPain = _unit getVariable [QGVAR(hasPain), false];
private _targetBP = 107;
private _targetHR = 80;
if (_bloodVolume < BLOOD_VOLUME_CLASS_3_HEMORRHAGE) then {
_targetBP = _targetBP * (_bloodVolume / DEFAULT_BLOOD_VOLUME);
};
if (_hasPain && {_pain > 0.2}) then {
_targetHR = 130;
};
if (_heartRate < _targetHR) then {
_hrChange = round(_targetHR - _heartRate) / 2;
};
if ((_meanBP > _targetBP && {_heartRate > _targetHR}) || {_bloodVolume < BLOOD_VOLUME_CLASS_2_HEMORRHAGE && {_heartRate < 200}}) then {
_hrChange = 2 * round(_targetBP - _meanBP);
if (_hrChange < 0) then {
_hrChange = _hrChange / 20;
};
};
_hrIncrease = _hrIncrease + _hrChange;
} else {
// Stabalize it
if (_heartRate < (60 + round(random(10)))) then {
_hrIncrease = _hrIncrease + HEART_RATE_MODIFIER;
} else {
if (_heartRate > (77 + round(random(10)))) then {
_hrIncrease = _hrIncrease - HEART_RATE_MODIFIER;
};
};
_hrIncrease = _hrIncrease - (random 5) * round(_heartRate / 10);
};
} else {
_hrIncrease = _hrIncrease - HEART_RATE_MODIFIER;
};
};
_hrIncrease

View File

@ -0,0 +1,45 @@
/*
* Author: Ruthberg
* Handle incapacitation due to damage and pain
*
* Arguments:
* 0: The Unit <OBJECT>
*
* ReturnValue:
* nothing
*
* Public: No
*/
#include "script_component.hpp"
params ["_unit"];
private _pain = _unit getVariable [QGVAR(pain), 0];
private _headDamage = 0;
private _bodyDamage = 0;
{
_x params ["", "", "_bodyPart", "", "", "_damage"];
switch (_bodyPart) do {
case 0: {
_headDamage = _headDamage + _damage;
};
case 1: {
if (_damage > PENETRATION_THRESHOLD) then {
_bodyDamage = _bodyDamage + _damage;
};
};
};
} forEach (_unit getVariable [QGVAR(openWounds), []]);
// todo: use an ace settings for the thresholds
if (_headDamage > 0.50) then {
[QGVAR(CriticalInjury), _unit] call CBA_fnc_localEvent;
};
if (_bodyDamage > 1.05) then {
[QGVAR(CriticalInjury), _unit] call CBA_fnc_localEvent;
};
if ((_pain >= PAIN_UNCONSCIOUS) && {random 1 < 0.1}) then {
[QGVAR(CriticalInjury), _unit] call CBA_fnc_localEvent;
};

View File

@ -17,8 +17,6 @@ params ["_unit"];
if (!local _unit) exitWith {};
_unit setVariable [QGVAR(pain), 0];
if (GVAR(level) >= 2) then {
_unit setVariable [QGVAR(heartRate), 0];
_unit setVariable [QGVAR(bloodPressure), [0, 0]];
_unit setVariable [QGVAR(airwayStatus), 0];
};
_unit setVariable [QGVAR(heartRate), 0];
_unit setVariable [QGVAR(bloodPressure), [0, 0]];
_unit setVariable [QGVAR(airwayStatus), 0];

View File

@ -17,17 +17,10 @@
params ["_unit", "_local"];
if (_local) then {
// If the unit had a loop tracking its vitals, restart it locally
if (_unit getVariable [QGVAR(addedToUnitLoop),false]) then {
[_unit, true] call FUNC(addVitalLoop);
};
if ((_unit getVariable ["ACE_isUnconscious",false]) && {count (_unit getVariable [QGVAR(unconsciousArguments), []]) >= 6}) then {
private _arguments = (_unit getVariable [QGVAR(unconsciousArguments), []]);
_arguments set [2, CBA_missionTime];
//[DFUNC(unconsciousPFH), 0.1, _arguments ] call CBA_fnc_addPerFrameHandler;
_unit setVariable [QGVAR(unconsciousArguments), nil, true];
};
};

View File

@ -1,24 +1,19 @@
#include "script_component.hpp"
params ["_unit", "_stateName", "_lastTime"];
params ["_unit", "_stateName"];
// If the unit died the loop is finished
if (!alive _unit) exitWith {};
// If locality changed, broadcast the last medical state and finish the local loop
if (!local _unit) exitWith {
if (GVAR(level) >= 2) then {
_unit setVariable [QGVAR(heartRate), _unit getVariable [QGVAR(heartRate), 80], true];
_unit setVariable [QGVAR(bloodPressure), _unit getVariable [QGVAR(bloodPressure), [80, 120]], true];
};
_unit setVariable [QGVAR(heartRate), _unit getVariable [QGVAR(heartRate), 80], true];
_unit setVariable [QGVAR(bloodPressure), _unit getVariable [QGVAR(bloodPressure), [80, 120]], true];
_unit setVariable [QGVAR(bloodVolume), _unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME], true];
};
systemChat format["handling state default for unit: %1", _this];
[_unit, CBA_missionTime - _lastTime] call FUNC(handleUnitVitals);
[_unit] call FUNC(handleUnitVitals);
private _pain = _unit getVariable [QGVAR(pain), 0];
if (_pain > (_unit getVariable [QGVAR(painSuppress), 0])) then {

View File

@ -1,22 +1,19 @@
#include "script_component.hpp"
params ["_unit", "_stateName", "_lastTime"];
params ["_unit", "_stateName"];
// If the unit died the loop is finished
if (!alive _unit) exitWith {};
// If locality changed, broadcast the last medical state and finish the local loop
if (!local _unit) exitWith {
if (GVAR(level) >= 2) then {
_unit setVariable [QGVAR(heartRate), _unit getVariable [QGVAR(heartRate), 80], true];
_unit setVariable [QGVAR(bloodPressure), _unit getVariable [QGVAR(bloodPressure), [80, 120]], true];
};
_unit setVariable [QGVAR(heartRate), _unit getVariable [QGVAR(heartRate), 80], true];
_unit setVariable [QGVAR(bloodPressure), _unit getVariable [QGVAR(bloodPressure), [80, 120]], true];
_unit setVariable [QGVAR(bloodVolume), _unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME], true];
};
[_unit, CBA_missionTime - _lastTime] call FUNC(handleUnitVitals);
[_unit] call FUNC(handleUnitVitals);
private _pain = _unit getVariable [QGVAR(pain), 0];
if (_pain > (_unit getVariable [QGVAR(painSuppress), 0])) then {

View File

@ -1,22 +1,19 @@
#include "script_component.hpp"
params ["_unit", "_stateName", "_lastTime"];
params ["_unit", "_stateName"];
// If the unit died the loop is finished
if (!alive _unit) exitWith {};
// If locality changed, broadcast the last medical state and finish the local loop
if (!local _unit) exitWith {
if (GVAR(level) >= 2) then {
_unit setVariable [QGVAR(heartRate), _unit getVariable [QGVAR(heartRate), 80], true];
_unit setVariable [QGVAR(bloodPressure), _unit getVariable [QGVAR(bloodPressure), [80, 120]], true];
};
_unit setVariable [QGVAR(heartRate), _unit getVariable [QGVAR(heartRate), 80], true];
_unit setVariable [QGVAR(bloodPressure), _unit getVariable [QGVAR(bloodPressure), [80, 120]], true];
_unit setVariable [QGVAR(bloodVolume), _unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME], true];
};
[_unit, CBA_missionTime - _lastTime] call FUNC(handleUnitVitals);
[_unit] call FUNC(handleUnitVitals);
private _pain = _unit getVariable [QGVAR(pain), 0];
if (_pain > (_unit getVariable [QGVAR(painSuppress), 0])) then {

View File

@ -12,27 +12,33 @@
*/
#include "script_component.hpp"
params ["_unit", "_interval"];
TRACE_3("ACE_DEBUG",_unit,_interval,_unit);
params ["_unit"];
if (_interval == 0) exitWith {};
private _lastTimeUpdated = _unit getVariable [QGVAR(lastTimeUpdated), CBA_missionTime];
private _deltaT = CBA_missionTime - _lastTimeUpdated;
_unit setVariable [QGVAR(lastTimeUpdated), CBA_missionTime];
TRACE_2("ACE_DEBUG",_unit,_deltaT);
if (_deltaT == 0) exitWith {};
private _lastTimeValuesSynced = _unit getVariable [QGVAR(lastMomentValuesSynced), 0];
private _syncValues = (CBA_missionTime - _lastTimeValuesSynced >= 10 + floor(random(10))) && GVAR(keepLocalSettingsSynced);
private _syncValues = (CBA_missionTime - _lastTimeValuesSynced) >= (10 + floor(random(10)));
if (_syncValues) then {
_unit setVariable [QGVAR(lastMomentValuesSynced), CBA_missionTime];
};
private _bloodVolume = (_unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME]) + ([_unit, _syncValues] call FUNC(getBloodVolumeChange));
_bloodVolume = (_bloodVolume max 0) min DEFAULT_BLOOD_VOLUME;
private _bloodVolume = (_unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME]) + ([_unit, _deltaT, _syncValues] call FUNC(getBloodVolumeChange));
_bloodVolume = 0 max _bloodVolume min DEFAULT_BLOOD_VOLUME;
// @todo: replace this and the rest of the setVariable with EFUNC(common,setApproximateVariablePublic)
_unit setVariable [QGVAR(bloodVolume), _bloodVolume, _syncValues];
TRACE_3("ACE_DEBUG",_bloodVolume,_syncValues,_unit);
// Set variables for synchronizing information across the net
if (_bloodVolume < BLOOD_VOLUME_HAS_LOST_SOME) then {
if (_bloodVolume < BLOOD_VOLUME_HAS_LOST_MUCH) then {
if (_bloodVolume < BLOOD_VOLUME_CLASS_1_HEMORRHAGE) then {
if (_bloodVolume < BLOOD_VOLUME_CLASS_3_HEMORRHAGE) then {
if (_unit getVariable [QGVAR(hasLostBlood), 0] != 2) then {
_unit setVariable [QGVAR(hasLostBlood), 2, true];
};
@ -52,7 +58,7 @@ TRACE_3("ACE_DEBUG",_bloodLoss,_unit getVariable QGVAR(isBleeding),_unit);
if (_bloodLoss > 0) then {
_unit setVariable [QGVAR(bloodloss), _bloodLoss, _syncValues];
[QGVAR(TakenInjury), _unit] call CBA_fnc_localEvent;
[QGVAR(Injury), _unit] call CBA_fnc_localEvent;
if !(_unit getVariable [QGVAR(isBleeding), false]) then {
_unit setVariable [QGVAR(isBleeding), true, true];
@ -75,75 +81,55 @@ if (_painStatus > (_unit getVariable [QGVAR(painSuppress), 0])) then {
};
};
if (_bloodVolume < BLOOD_VOLUME_DEAD) exitWith {
[_unit, "bloodloss"] call FUNC(setDead);
TRACE_6("ACE_DEBUG_ADVANCED_VITALS",_painStatus,_bloodVolume,_unit getVariable QGVAR(hasPain),_unit getVariable QGVAR(morphine),_syncValues,_unit);
// Handle pain due tourniquets, that have been applied more than 120 s ago
private _oldTourniquets = (_unit getVariable [QGVAR(tourniquets), []]) select {_x > 0 && {CBA_missionTime - _x > 120}};
// Increase pain at a rate of 0.001 units/s per old tourniquet
_painStatus = _painStatus + (count _oldTourniquets) * 0.001 * _deltaT;
private _heartRate = (_unit getVariable [QGVAR(heartRate), 80]) + _deltaT * ([_unit] call FUNC(getHeartRateChange));
_unit setVariable [QGVAR(heartRate), 0 max _heartRate, _syncValues];
private _bloodPressure = [_unit] call FUNC(getBloodPressure);
_unit setVariable [QGVAR(bloodPressure), _bloodPressure, _syncValues];
private _cardiacOutput = [_unit] call FUNC(getCardiacOutput);
if (_bloodLoss > BLOOD_LOSS_KNOCK_OUT_THRESHOLD * _cardiacOutput) then {
[QGVAR(CriticalVitals), _unit] call CBA_fnc_localEvent;
};
if ([_unit] call EFUNC(common,isAwake)) then {
if (_bloodVolume < BLOOD_VOLUME_UNCONSCIOUS && {random 1 < BLOOD_LOSS_KNOCK_OUT_CHANCE}) exitWith {
[_unit, true, BLOOD_LOSS_KNOCK_OUT_DURATION] call FUNC(setUnconscious);
};
#ifdef DEBUG_MODE_FULL
if (!isPlayer _unit) then {
private _cardiacArrest = _unit getVariable [QGVAR(inCardiacArrest), false];
hintSilent format["blood volume: %1, blood loss: [%2, %3]\nhr: %4, bp: %5, pain: %6", round(_bloodVolume * 100) / 100, round(_bloodLoss * 1000) / 1000, round((_bloodLoss / _cardiacOutput) * 100) / 100, round(_heartRate), _bloodPressure, round(_painStatus * 100) / 100];
};
#endif
_unit setVariable [QGVAR(pain), 0 max (_painStatus - _deltaT * PAIN_REDUCTION_SPEED), _syncValues];
TRACE_8("ACE_DEBUG_ADVANCED_VITALS",_painStatus,PAIN_REDUCTION_SPEED,_heartRate,_bloodVolume,_bloodPressure,_deltaT,_syncValues,_unit);
_bloodPressure params ["_bloodPressureL", "_bloodPressureH"];
if (_bloodPressureL < 40) then {
[QGVAR(CriticalVitals), _unit] call CBA_fnc_localEvent;
};
if ((_heartRate < 20) || {_heartRate > 220} || {_bloodPressureH < 50}) then {
[QGVAR(FatalVitals), _unit] call CBA_fnc_localEvent;
};
/*
if (GVAR(level) == 1) then {
TRACE_5("ACE_DEBUG_BASIC_VITALS",_painStatus,_unit getVariable QGVAR(hasPain),_unit getVariable QGVAR(morphine),_syncValues,_unit);
// reduce pain
if (_painStatus > 0) then {
_unit setVariable [QGVAR(pain), (_painStatus - 0.001 * _interval) max 0, _syncValues];
};
//// reduce painkillers
//if (_unit getVariable [QGVAR(morphine), 0] > 0) then {
// _unit setVariable [QGVAR(morphine), ((_unit getVariable [QGVAR(morphine), 0]) - 0.0015 * _interval) max 0, _syncValues];
//};
};
*/
// handle advanced medical, with vitals
/*
if (GVAR(level) >= 2) then {
TRACE_6("ACE_DEBUG_ADVANCED_VITALS",_painStatus,_bloodVolume, _unit getVariable QGVAR(hasPain),_unit getVariable QGVAR(morphine),_syncValues,_unit);
// Handle pain due tourniquets, that have been applied more than 120 s ago
private _oldTourniquets = (_unit getVariable [QGVAR(tourniquets), []]) select {_x > 0 && {CBA_missionTime - _x > 120}};
// Increase pain at a rate of 0.001 units/s per old tourniquet
_painStatus = _painStatus + (count _oldTourniquets) * 0.001 * _interval;
// Set the vitals
private _heartRate = (_unit getVariable [QGVAR(heartRate), 80]) + (([_unit] call FUNC(getHeartRateChange)) * _interval);
_unit setVariable [QGVAR(heartRate), _heartRate max 0, _syncValues];
private _bloodPressure = [_unit] call FUNC(getBloodPressure);
_unit setVariable [QGVAR(bloodPressure), _bloodPressure, _syncValues];
_painReduce = [0.001, 0.002] select (_painStatus > 5);
// @todo: replace this and the rest of the setVariable with EFUNC(common,setApproximateVariablePublic)
_unit setVariable [QGVAR(pain), (_painStatus - _painReduce * _interval) max 0, _syncValues];
TRACE_8("ACE_DEBUG_ADVANCED_VITALS",_painStatus,_painReduce,_heartRate,_bloodVolume,_bloodPressure,_interval,_syncValues,_unit);
// Check vitals for medical status
// TODO check for in revive state instead of variable
_bloodPressure params ["_bloodPressureL", "_bloodPressureH"];
if (!(_unit getVariable [QGVAR(inCardiacArrest),false])) then {
if (_heartRate < 10 || _bloodPressureH < 30 || _bloodVolume < BLOOD_VOLUME_CARDIAC_ARREST) then {
[_unit, true, 10+ random(20)] call FUNC(setUnconscious); // safety check to ensure unconsciousness for units if they are not dead already.
};
if ((_bloodPressureH > 260)
|| {_bloodPressureL < 40 && ({_heartRate > 190})}
|| {(_bloodPressureH > 145 && {_heartRate > 150})}) then {
if (random(1) > 0.7) then {
[_unit] call FUNC(setCardiacArrest);
// Handle spontaneous wakeup from unconsciousness
if (_unit getVariable [QGVAR(isUnconscious), false]) then {
if (_unit call FUNC(hasStableVitals)) then {
private _lastWakeUpCheck = _unit getVariable [QGVAR(lastWakeUpCheck), CBA_missionTime];
if (CBA_missionTime - _lastWakeUpCheck > SPONTANEOUS_WAKE_UP_INTERVAL) then {
_unit setVariable [QGVAR(lastWakeUpCheck), CBA_missionTime];
if ((random 1) < SPONTANEOUS_WAKE_UP_CHANCE) then {
[QGVAR(WakeUp), _unit] call CBA_fnc_localEvent;
};
};
if (_heartRate > 200 || (_heartRate < 20)) then {
[_unit] call FUNC(setCardiacArrest);
};
} else {
// Unstable vitals, procrastinate the next wakeup check
_unit setVariable [QGVAR(lastWakeUpCheck), CBA_missionTime];
};
};
*/

View File

@ -0,0 +1,32 @@
/*
* Author: Ruthberg
* Check if a unit has stable vitals (required to become conscious)
*
* Arguments:
* 0: The patient <OBJECT>
*
* Return Value:
* Has stable vitals <BOOL>
*
* Public: No
*/
#include "script_component.hpp"
params ["_unit"];
if (_unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME] < BLOOD_VOLUME_CLASS_2_HEMORRHAGE) exitWith { false };
if (_unit getVariable [QGVAR(inCardiacArrest), false]) exitWith { false };
private _cardiacOutput = [_unit] call FUNC(getCardiacOutput);
private _bloodLoss = _unit call FUNC(getBloodLoss);
if (_bloodLoss > (BLOOD_LOSS_KNOCK_OUT_THRESHOLD * _cardiacOutput) / 2) exitWith { false };
private _bloodPressure = [_unit] call FUNC(getBloodPressure);
_bloodPressure params ["_bloodPressureL", "_bloodPressureH"];
if (_bloodPressureL < 50 || {_bloodPressureH < 60}) exitWith { false };
private _heartRate = (_unit getVariable [QGVAR(heartRate), 80]);
if (_heartRate < 40) exitWith { false };
true

View File

@ -20,7 +20,8 @@ if (damage _unit > 0) then {
_unit setVariable [QGVAR(pain), 0, true];
_unit setVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME, true];
_unit setVariable ["ACE_isUnconscious", false, true]; // TODO this is done based on state
_unit setVariable [QGVAR(isUnconscious), false, true];
_unit setVariable [QGVAR(partialHealCounter), 0, true];
// tourniquets
_unit setVariable [QGVAR(tourniquets), [0,0,0,0,0,0], true];
@ -29,7 +30,7 @@ _unit setVariable [QGVAR(occludedMedications), nil, true]; //Delayed Medications
// wounds and injuries
_unit setVariable [QGVAR(openWounds), [], true];
_unit setVariable [QGVAR(bandagedWounds), [], true];
_unit setVariable [QGVAR(internalWounds), [], true];
_unit setVariable [QGVAR(stitchedWounds), [], true];
// vitals
_unit setVariable [QGVAR(heartRate), 80];
@ -37,9 +38,6 @@ _unit setVariable [QGVAR(heartRateAdjustments), []];
_unit setVariable [QGVAR(bloodPressure), [80, 120]];
_unit setVariable [QGVAR(peripheralResistance), 100];
// fractures
_unit setVariable [QGVAR(fractures), [], true];
// triage card and logs
// TODO move to treatment
//_unit setVariable [QGVAR(triageLevel), 0, true];
@ -51,14 +49,8 @@ _unit setVariable [QGVAR(ivBags), nil, true];
// damage storage
_unit setVariable [QGVAR(bodyPartStatus), [0,0,0,0,0,0], true];
// airway
_unit setVariable [QGVAR(airwayStatus), 100];
_unit setVariable [QGVAR(airwayOccluded), false];
_unit setVariable [QGVAR(airwayCollapsed), false];
// generic medical admin
_unit setVariable [QGVAR(addedToUnitLoop), false, true]; // TODO this is replaced by unit state
_unit setVariable [QGVAR(inCardiacArrest), false, true]; // TODO this is no longer present
_unit setVariable [QGVAR(inCardiacArrest), false, true];
_unit setVariable [QGVAR(hasLostBlood), 0, true];
_unit setVariable [QGVAR(isBleeding), false, true];
_unit setVariable [QGVAR(hasPain), false, true];

View File

@ -15,10 +15,9 @@
params ["_unit"];
private _totalBloodLoss = 0;
{
// total bleeding ratio * percentage of injury left
_totalBloodLoss = _totalBloodLoss + ((_x select 4) * (_x select 3));
} forEach (_unit getVariable [QGVAR(openWounds), []]);
if (!alive _unit) exitWith { false };
if (_unit call FUNC(getBloodLoss) > 0) exitWith { false };
if (!(_unit call FUNC(hasStableVitals))) exitWith { false };
if (_unit getVariable [QGVAR(isUnconscious), false]) exitWith { false };
(_totalBloodLoss == 0);
true

View File

@ -16,13 +16,14 @@
params ["_unit"];
if (_unit getVariable [QGVAR(inCardiacArrest),false]) exitWith {};
_unit setVariable [QGVAR(inCardiacArrest), true,true];
_unit setVariable [QGVAR(heartRate), 0];
if (_unit getVariable [QGVAR(inCardiacArrest), false]) exitWith {};
_unit setVariable [QGVAR(inCardiacArrest), true, true];
_unit setVariable [QGVAR(heartRate), 0, true];
["ace_cardiacArrestEntered", [_unit]] call CBA_fnc_localEvent;
[_unit, true] call FUNC(setUnconscious);
[QEGVAR(medical,InjuryCritical), _unit] call CBA_fnc_localEvent;
private _timeInCardiacArrest = 120 + round(random(600));
[{
@ -30,13 +31,13 @@ private _timeInCardiacArrest = 120 + round(random(600));
_args params ["_unit", "_startTime", "_timeInCardiacArrest"];
private _heartRate = _unit getVariable [QGVAR(heartRate), 80];
if (_heartRate > 0 || !alive _unit) exitWith {
if (_heartRate > 20 || !alive _unit) exitWith {
[_idPFH] call CBA_fnc_removePerFrameHandler;
_unit setVariable [QGVAR(inCardiacArrest), nil,true];
_unit setVariable [QGVAR(inCardiacArrest), nil, true];
};
if (CBA_missionTime - _startTime >= _timeInCardiacArrest) exitWith {
[_idPFH] call CBA_fnc_removePerFrameHandler;
_unit setVariable [QGVAR(inCardiacArrest), nil,true];
_unit setVariable [QGVAR(inCardiacArrest), nil, true];
[_unit] call FUNC(setDead);
};
}, 1, [_unit, CBA_missionTime, _timeInCardiacArrest] ] call CBA_fnc_addPerFrameHandler;

View File

@ -5,8 +5,6 @@
* Arguments:
* 0: The unit that will be put in an unconscious state <OBJECT>
* 1: Set unconsciouns <BOOL> (default: true)
* 2: Minimum unconscious time <NUMBER> (default: (round(random(10)+5)))
* 3: Force AI Unconscious (skip random death chance) <BOOL> (default: false)
*
* ReturnValue:
* Success? <BOOLEAN>
@ -23,20 +21,15 @@ if !(EGVAR(common,settingsInitFinished)) exitWith {
EGVAR(common,runAtSettingsInitialized) pushBack [FUNC(setUnconscious), _this];
};
params ["_unit", ["_knockOut", true], ["_minUnconsciousTime", DEFAULT_KNOCK_OUT_DELAY], ["_force", false]];
params ["_unit", ["_knockOut", true]];
if (isNull _unit || {!(_unit isKindOf "CAManBase")}) exitWith {false};
if (!local _unit) exitWith {
[QGVAR(setUnconscious), [_unit, _knockOut, _minUnconsciousTime, _force], _unit] call CBA_fnc_targetEvent;
[QGVAR(setUnconscious), [_unit, _knockOut], _unit] call CBA_fnc_targetEvent;
true
};
// use maximum for wake up time
if (_knockOut) then {
_unit setVariable [QGVAR(wakeUpTime), (CBA_missionTime + _minUnconsciousTime) max (_unit getVariable [QGVAR(wakeUpTime), 0])];
};
if (_knockOut isEqualTo (_unit getVariable [QGVAR(isUnconscious), false])) exitWith {false};
// --- wake up
@ -55,6 +48,7 @@ if !(_knockOut) exitWith {
// --- knock out
_unit setVariable [QGVAR(isUnconscious), true, true];
_unit setVariable [QGVAR(lastWakeUpCheck), CBA_missiontime];
if (_unit == ACE_player) then {
if (visibleMap) then {openMap false};
@ -64,39 +58,8 @@ if (_unit == ACE_player) then {
};
};
// if we have unconsciousness for AI disabled, we will kill the unit instead
/*
private _isDead = false;
if (!([_unit, GVAR(remoteControlledAI)] call EFUNC(common,isPlayer)) && !_force) then {
_enableUncon = _unit getVariable [QGVAR(enableUnconsciousnessAI), GVAR(enableUnconsciousnessAI)];
if (_enableUncon == 0 or {_enableUncon == 1 and (random 1) < 0.5}) then {
[_unit, true] call FUNC(setDead);
_isDead = true;
};
};
if (_isDead) exitWith {};
*/
[_unit, true] call EFUNC(medical_engine,setUnconsciousAnim);
[QGVAR(Unconscious), _unit] call CBA_fnc_localEvent;
["ace_unconscious", [_unit, true]] call CBA_fnc_globalEvent;
// auto wake up
[{
params ["_unit"];
private _time = _unit getVariable [QGVAR(wakeUpTime), 0];
!(_unit getVariable [QGVAR(isUnconscious), false]) || {CBA_missionTime > _time}
}, {
params ["_unit"];
if (_unit getVariable [QGVAR(isUnconscious), false]) then {
[_unit, false] call FUNC(setUnconscious);
};
}, _unit] call CBA_fnc_waitUntilAndExecute;
true

View File

@ -1,145 +0,0 @@
/*
* Author: Glowbal
* PFH logic for unconscious state
*
* Arguments:
* 0: PFEH - Args
* 0: The unit that will be put in an unconscious state <OBJECT>
* 1: unitPos (stance) <STRING>
* 2: Starting Time <NUMBER>
* 3: Minimum Waiting Time <NUMBER>
* 4: Has Moved Out <BOOL>
* 5: Parachute Check <BOOL>
* 1: PFEH ID <NUMBER>
*
* ReturnValue:
* None
*
* Public: yes
*/
#include "script_component.hpp"
private ["_unit", "_minWaitingTime", "_slotInfo", "_hasMovedOut", "_parachuteCheck", "_args", "_originalPos", "_startingTime", "_awakeInVehicleAnimation", "_oldVehicleAnimation", "_vehicle"];
params ["_args", "_idPFH"];
_args params ["_unit", "_originalPos", "_startingTime", "_minWaitingTime", "_hasMovedOut", "_parachuteCheck"];
TRACE_6("ACE_DEBUG_Unconscious_PFH",_unit, _originalPos, _startingTime, _minWaitingTime, _hasMovedOut, _parachuteCheck);
if (!alive _unit) exitWith {
if ("ACE_FakePrimaryWeapon" in (weapons _unit)) then {
TRACE_1("Removing fake weapon [on death]",_unit);
_unit removeWeapon "ACE_FakePrimaryWeapon";
};
if (GVAR(moveUnitsFromGroupOnUnconscious)) then {
[_unit, false, "ACE_isUnconscious", side group _unit] call EFUNC(common,switchToGroupSide);
};
[_unit, "setCaptive", "ace_unconscious", false] call EFUNC(common,statusEffect_set);
[_unit, false] call EFUNC(common,disableAI);
//_unit setUnitPos _originalPos;
//_unit setUnconscious false;
[_unit, "isUnconscious"] call EFUNC(common,unmuteUnit);
["ace_unconscious", [_unit, false]] call CBA_fnc_globalEvent;
TRACE_3("ACE_DEBUG_Unconscious_Exit",_unit, (!alive _unit) , "ace_unconscious");
[_idPFH] call CBA_fnc_removePerFrameHandler;
};
// In case the unit is no longer in an unconscious state, we are going to check if we can already reset the animation
if !(_unit getVariable ["ACE_isUnconscious",false]) exitWith {
TRACE_7("ACE_DEBUG_Unconscious_PFH",_unit, _args, [_unit] call EFUNC(medical_treatment,isBeingCarried), [_unit] call EFUNC(medical_treatment,isBeingDragged), _idPFH, _unit getVariable QGVAR(unconsciousArguments),animationState _unit);
// TODO, handle this with carry instead, so we can remove the PFH here.
// Wait until the unit isn't being carried anymore, so we won't end up with wierd animations
if !(([_unit] call EFUNC(medical_treatment,isBeingCarried)) || ([_unit] call EFUNC(medical_treatment,isBeingDragged))) then {
if ("ACE_FakePrimaryWeapon" in (weapons _unit)) then {
TRACE_1("Removing fake weapon [on wakeup]",_unit);
_unit removeWeapon "ACE_FakePrimaryWeapon";
};
if (vehicle _unit == _unit) then {
if (animationState _unit == "AinjPpneMstpSnonWrflDnon") then {
[_unit,"AinjPpneMstpSnonWrflDnon_rolltofront", 2] call EFUNC(common,doAnimation);
[_unit,"amovppnemstpsnonwnondnon", 1] call EFUNC(common,doAnimation);
} else {
[_unit,"amovppnemstpsnonwnondnon", 2] call EFUNC(common,doAnimation);
};
} else {
_vehicle = vehicle _unit;
_oldVehicleAnimation = _unit getVariable [QGVAR(vehicleAwakeAnim), []];
_awakeInVehicleAnimation = "";
if (((count _oldVehicleAnimation) > 0) && {(_oldVehicleAnimation select 0) == _vehicle}) then {
_awakeInVehicleAnimation = _oldVehicleAnimation select 1;
};
//Make sure we have a valid, non-terminal animation:
if ((_awakeInVehicleAnimation != "") && {(getNumber (configFile >> "CfgMovesMaleSdr" >> "States" >> _awakeInVehicleAnimation >> "terminal")) == 0}) then {
[_unit, _awakeInVehicleAnimation, 2] call EFUNC(common,doAnimation);
} else {
//Don't have a valid animation saved, reset the unit animation with a moveInXXX
TRACE_1("No Valid Animation, doing seat reset", _awakeInVehicleAnimation);
_slotInfo = [];
{if ((_x select 0) == _unit) exitWith {_slotInfo = _x;};} forEach (fullCrew _vehicle);
if (_slotInfo isEqualTo []) exitWith {ERROR("No _slotInfo?");};
//Move the unit out:
_unit setPosASL ((getPosASL _unit) vectorAdd [0,0,100]);
//Move the unit back into old seat:
if ((_slotInfo select 1) == "driver") then {
_unit moveInDriver _vehicle;
} else {
if ((_slotInfo select 1) == "cargo") then {
_unit moveInCargo [_vehicle, (_slotInfo select 2)];
} else {
_unit moveInTurret [_vehicle, (_slotInfo select 3)];
};
};
};
};
_unit setVariable [QGVAR(vehicleAwakeAnim), nil];
["ace_unconscious", [_unit, false]] call CBA_fnc_globalEvent;
// EXIT PFH
[_idPFH] call CBA_fnc_removePerFrameHandler;
};
if (!_hasMovedOut) then {
// Reset the unit back to the previous captive state.
[_unit, "setCaptive", "ace_unconscious", false] call EFUNC(common,statusEffect_set);
// Swhich the unit back to its original group
//Unconscious units shouldn't be put in another group #527:
if (GVAR(moveUnitsFromGroupOnUnconscious)) then {
[_unit, false, "ACE_isUnconscious", side group _unit] call EFUNC(common,switchToGroupSide);
};
[_unit, false] call EFUNC(common,disableAI);
_unit setUnitPos _originalPos; // This is not position but stance (DOWN, MIDDLE, UP)
_unit setUnconscious false;
[_unit, "isUnconscious"] call EFUNC(common,unmuteUnit);
// ensure this statement runs only once
_args set [4, true];
};
};
if (_parachuteCheck) then {
if !(vehicle _unit isKindOf "ParachuteBase") then {
[_unit, [_unit] call EFUNC(common,getDeathAnim), 1, true] call EFUNC(common,doAnimation);
_args set [5, false];
};
};
if (!local _unit) exitWith {
TRACE_6("ACE_DEBUG_Unconscious_PFH",_unit, _args, _startingTime, _minWaitingTime, _idPFH, _unit getVariable QGVAR(unconsciousArguments));
_args set [3, _minWaitingTime - (CBA_missionTime - _startingTime)];
_unit setVariable [QGVAR(unconsciousArguments), _args, true];
[_idPFH] call CBA_fnc_removePerFrameHandler;
};
// Ensure we are waiting at least a minimum period before checking if we can wake up the unit again, allows for temp knock outs
if ((CBA_missionTime - _startingTime) >= _minWaitingTime) exitWith {
TRACE_2("ACE_DEBUG_Unconscious_Temp knock outs",_unit, [_unit] call FUNC(getUnconsciousCondition));
if (!([_unit] call FUNC(getUnconsciousCondition))) then {
//_unit setVariable ["ACE_isUnconscious", false, true];
[QGVAR(MinUnconsciousTimer), _unit] call CBA_fnc_localEvent;
};
};

View File

@ -17,28 +17,30 @@
// 0.077 l/kg * 80kg = 6.16l
#define DEFAULT_BLOOD_VOLUME 6.0 // in liters
#define BLOOD_VOLUME_HAS_LOST_SOME 5.700 // lost 5% blood, Class I Hemorrhage
#define BLOOD_VOLUME_HAS_LOST_MUCH 5.100 // lost 15% blood, Class II Hemorrhage
#define BLOOD_VOLUME_UNCONSCIOUS 4.200 // lost 30% blood, Class III Hemorrhage
#define BLOOD_VOLUME_DEAD 3.600 // lost 40% blood, Class IV Hemorrhage
#define BLOOD_VOLUME_CARDIAC_ARREST 1.2 // TBD
#define BLOOD_VOLUME_CLASS_1_HEMORRHAGE 6.000 // lost less than 15% blood, Class I Hemorrhage
#define BLOOD_VOLUME_CLASS_2_HEMORRHAGE 5.100 // lost more than 15% blood, Class II Hemorrhage
#define BLOOD_VOLUME_CLASS_3_HEMORRHAGE 4.200 // lost more than 30% blood, Class III Hemorrhage
#define BLOOD_VOLUME_CLASS_4_HEMORRHAGE 3.600 // lost more than 40% blood, Class IV Hemorrhage
// IV Change per second calculation:
// 250ml should take 60 seconds to fill. 250ml/60s = 4.166ml/s.
#define IV_CHANGE_PER_SECOND ([1000, 4.166] select GVAR(advancedIVBags)) // in milliliters per second
// 250 ml should take 60 seconds to fill. 250 ml / 60 s ~ 4.1667 ml/s.
#define IV_CHANGE_PER_SECOND 4.1667 // in milliliters per second
// chance per second to get knocked out due to blood loss
#define BLOOD_LOSS_KNOCK_OUT_CHANCE 0.1 // 10%
// Minimum amount of damage required for penetrating wounds (also minDamage for velocity wounds)
#define PENETRATION_THRESHOLD 0.35
// duration in seconds to stay knocked out due to blood loss
#define BLOOD_LOSS_KNOCK_OUT_DURATION (15 + random 20)
// --- unconsciousness
#define DEFAULT_KNOCK_OUT_DELAY (5 + random 10)
// To be replaced by a proper blood pressure calculation
#define BLOOD_LOSS_KNOCK_OUT_THRESHOLD 0.5 // 50% of cardiac output
// --- pain
#define PAIN_UNCONSCIOUS 0.7
#define PAIN_UNCONSCIOUS 0.5
// duration in seconds to stay knocked out due to pain
#define PAIN_KNOCK_OUT_DURATION (15 + random 20)
#define PAIN_KNOCK_OUT_DURATION (5 + random 10)
// Pain reduction per second
#define PAIN_REDUCTION_SPEED 0.001
// Chance to wake up when vitals are stable (checked once every SPONTANEOUS_WAKE_UP_INTERVAL seconds)
#define SPONTANEOUS_WAKE_UP_CHANCE 0.1
#define SPONTANEOUS_WAKE_UP_INTERVAL 10

View File

@ -2942,31 +2942,17 @@
<Italian>Coefficiente che modifica l'intensità del dolore</Italian>
<Japanese>この係数では痛みの強さを変更できます</Japanese>
</Key>
<Key ID="STR_ACE_Medical_MedicalSettings_keepLocalSettingsSynced_DisplayName">
<English>Sync status</English>
<Russian>Синхронизация статуса</Russian>
<Polish>Synchronizuj status</Polish>
<Spanish>Sincronizador estado</Spanish>
<German>Status synchronisieren</German>
<Czech>Synchronizovat status</Czech>
<Portuguese>Sincronizar estado</Portuguese>
<French>Status de la synchronisation</French>
<Hungarian>Szinkronizációs állapot</Hungarian>
<Italian>Sincronizza stato</Italian>
<Japanese>同期状態</Japanese>
<Key ID="STR_ACE_Medical_MedicalSettings_fullHealLocation_PAK_DisplayName">
<English>Full Heal Locations</English>
</Key>
<Key ID="STR_ACE_Medical_MedicalSettings_keepLocalSettingsSynced_Description">
<English>Keep unit status synced. Recommended on.</English>
<Russian>Синхронизировать статус юнитов. Рекомендуется включить.</Russian>
<Polish>Utrzymuj synchronizację statusu jednostek. Zalecane zostawienie tej opcji włączonej.</Polish>
<Spanish>Mantener el estado de la unidad sincronizado. Recomendado activado</Spanish>
<German>Status der Einheit synchron halten. Sollte aktiviert bleiben.</German>
<Czech>Udržuje status jednotky synchronizovaný. Doporučeno zapnout.</Czech>
<Portuguese>Mater o estado da unidade sincronizado. Recomendado ativado.</Portuguese>
<French>Garder l'unité synchronisée, Recommandé sur oui.</French>
<Hungarian>Egységállapotok szinkronizálása. Javasolt a bekapcsolása.</Hungarian>
<Italian>Mantieni lo stato delle unità sincronizzato. Consigliato attivo.</Italian>
<Japanese>ユニット状態の同期を続けます。有効化を推奨。</Japanese>
<Key ID="STR_ACE_Medical_MedicalSettings_fullHealLocation_PAK_Description">
<English>Where does the PAK perform a full heal?</English>
</Key>
<Key ID="STR_ACE_Medical_MedicalSettings_fieldEffectiveness_PAK_DisplayName">
<English>PAK effectiveness</English>
</Key>
<Key ID="STR_ACE_Medical_MedicalSettings_fieldEffectiveness_PAK_Description">
<English>PAK effectiveness when used outside of medical facilities</English>
</Key>
<Key ID="STR_ACE_Medical_MedicalSettings_Module_Description">
<English>Provides a medical system for both players and AI.</English>

View File

@ -6,7 +6,7 @@
if ((GVAR(enabledFor) == 1) && {!isServer} && {hasInterface}) exitWith {}; // 1: Don't Run on non-hc Clients
// Only run for AI that does not have to deal with advanced medical
if (EGVAR(medical,enableFor) == 1 || {hasInterface && {EGVAR(medical,level) == 2}}) exitWith {};
if (EGVAR(medical,enableFor) == 1 || {hasInterface}) exitWith {};
["ace_firedNonPlayer", {
_unit setVariable [QGVAR(lastFired), CBA_missionTime];

View File

@ -1,229 +1,86 @@
// bleeding - maximum possible bleeding rate for a given wound type (0 .. 1)
// pain - maximum possible pain level for a given wound type (0 .. 1)
class ACE_Medical_Injuries {
// Defines all the possible injury types for advanced medical
// Defines all the possible injury types
class wounds {
// Source: Scarle
// Also called scrapes, they occur when the skin is rubbed away by friction against another rough surface (e.g. rope burns and skinned knees).
class Abrasion {
name = CSTRING(Abrasion);
selections[] = {"All"};
bleedingRate = 0.0001;
pain = 0.01;
causes[] = {"falling", "ropeburn", "vehiclecrash", "unknown"};
bleeding = 0.001;
pain = 0.4;
minDamage = 0.01;
class Minor {
name = CSTRING(Abrasion_Minor);
minDamage = 0.01;
maxDamage = 0.2;
bleedingRate = 0.0001;
};
class Medium {
name = CSTRING(Abrasion_Medium);
minDamage = 0.2;
maxDamage = 0.3;
bleedingRate = 0.00015;
};
class Large {
name = CSTRING(Abrasion_Large);
minDamage = 0.3;
maxDamage = 0.5;
bleedingRate = 0.0002;
};
maxDamage = 0.30;
};
// Occur when an entire structure or part of it is forcibly pulled away, such as the loss of a permanent tooth or an ear lobe. Explosions, gunshots, and animal bites may cause avulsions.
class Avulsions {
name = CSTRING(Avulsion);
selections[] = {"All"};
bleedingRate = 0.01;
pain = 0.3;
causes[] = {"explosive", "vehiclecrash", "grenade", "shell", "bullet", "backblast", "bite"};
minDamage = 0.2;
class Minor {
name = CSTRING(Avulsion_Minor);
minDamage = 0.2;
maxDamage = 0.3;
bleedingRate = 0.01;
};
class Medium {
name = CSTRING(Avulsion_Medium);
minDamage = 0.3;
maxDamage = 0.6;
bleedingRate = 0.02;
};
class Large {
name = CSTRING(Avulsion_Large);
minDamage = 0.5;
bleedingRate = 0.05;
};
bleeding = 0.5;
pain = 1.0;
minDamage = 4;
causeLimping = 1;
};
// Also called bruises, these are the result of a forceful trauma that injures an internal structure without breaking the skin. Blows to the chest, abdomen, or head with a blunt instrument (e.g. a football or a fist) can cause contusions.
class Contusion {
name = CSTRING(Contusion);
selections[] = {"All"};
bleedingRate = 0.0;
pain = 0.05;
causes[] = {"bullet", "backblast", "punch", "vehiclecrash", "falling"};
minDamage = 0.01;
maxDamage = 0.1;
class Minor {
name = CSTRING(Contusion_Minor);
minDamage = 0.01;
maxDamage = 0.1;
};
class Medium {
name = CSTRING(Contusion_Medium);
minDamage = 0.1;
maxDamage = 0.15;
};
class Large {
name = CSTRING(Contusion_Large);
minDamage = 0.15;
maxDamage = 0.2;
};
bleeding = 0.0;
pain = 0.3;
minDamage = 0.02;
maxDamage = 0.35;
};
// Occur when a heavy object falls onto a person, splitting the skin and shattering or tearing underlying structures.
class CrushWound {
name = CSTRING(Crush);
selections[] = {"All"};
bleedingRate = 0.01;
pain = 0.1;
causes[] = {"falling", "vehiclecrash", "punch", "unknown"};
bleeding = 0.1;
pain = 0.8;
minDamage = 0.1;
class Minor {
name = CSTRING(Crush_Minor);
minDamage = 0.1;
maxDamage = 0.45;
bleedingRate = 0.005;
};
class Medium {
name = CSTRING(Crush_Medium);
minDamage = 0.4;
maxDamage = 0.7;
bleedingRate = 0.007;
};
class Large {
name = CSTRING(Crush_Large);
minDamage = 0.6;
bleedingRate = 0.0095;
};
causeLimping = 1;
};
// Slicing wounds made with a sharp instrument, leaving even edges. They may be as minimal as a paper cut or as significant as a surgical incision.
class Cut {
name = CSTRING(Cut);
selections[] = {"All"};
bleedingRate = 0.01;
pain = 0.075;
causes[] = {"vehiclecrash", "grenade", "explosive", "shell", "backblast", "stab", "unknown"};
bleeding = 0.04;
pain = 0.1;
minDamage = 0.1;
class Minor {
name = CSTRING(Cut_Minor);
minDamage = 0.1;
maxDamage = 0.3;
bleedingRate = 0.005;
};
class Medium {
name = CSTRING(Cut_Medium);
minDamage = 0.3;
maxDamage = 0.65;
bleedingRate = 0.02;
};
class Large {
name = CSTRING(Cut_Large);
minDamage = 0.65;
bleedingRate = 0.05;
};
};
// Also called tears, these are separating wounds that produce ragged edges. They are produced by a tremendous force against the body, either from an internal source as in childbirth, or from an external source like a punch.
class Laceration {
name = CSTRING(Laceration);
selections[] = {"All"};
bleedingRate = 0.01;
pain = 0.075;
causes[] = {"vehiclecrash", "punch"};
bleeding = 0.05;
pain = 0.2;
minDamage = 0.01;
class Minor {
name = CSTRING(Laceration_Minor);
minDamage = 0.1;
maxDamage = 0.5;
bleedingRate = 0.005;
};
class Medium {
name = CSTRING(Laceration_Medium);
minDamage = 0.5;
maxDamage = 0.7;
bleedingRate = 0.01;
};
class Large {
name = CSTRING(Laceration_Large);
minDamage = 0.7;
bleedingRate = 0.03;
};
};
// Also called velocity wounds, they are caused by an object entering the body at a high speed, typically a bullet or small peices of shrapnel.
class velocityWound {
name = CSTRING(VelocityWound);
selections[] = {"All"};
bleedingRate = 0.01;
pain = 0.2;
causes[] = {"bullet", "grenade","explosive", "shell", "unknown"};
minDamage = 0.15;
class Minor {
name = CSTRING(VelocityWound_Minor);
minDamage = 0.15;
maxDamage = 0.3;
bleedingRate = 0.025;
};
class Medium {
name = CSTRING(VelocityWound_Medium);
minDamage = 0.3;
maxDamage = 0.75;
bleedingRate = 0.05;
};
class Large {
name = CSTRING(VelocityWound_Large);
minDamage = 0.75;
bleedingRate = 0.1;
};
bleeding = 1.0;
pain = 0.9;
minDamage = 0.35;
causeLimping = 1;
};
// Deep, narrow wounds produced by sharp objects such as nails, knives, and broken glass.
class punctureWound {
name = CSTRING(PunctureWound);
selections[] = {"All"};
bleedingRate = 0.01;
pain = 0.075;
causes[] = {"stab", "grenade"};
minDamage = 0.01;
class Minor {
name = CSTRING(PunctureWound_Minor);
minDamage = 0.01;
maxDamage = 0.5;
bleedingRate = 0.01;
};
class Medium {
name = CSTRING(PunctureWound_Medium);
minDamage = 0.5;
maxDamage = 0.75;
bleedingRate = 0.03;
};
class Large {
name = CSTRING(PunctureWound_Large);
minDamage = 0.65;
bleedingRate = 0.08;
};
};
};
class fractures {
class Femur {
name = CSTRING(Femur);
selections[] = {"Head", "Body"};
pain = 0.2;
causes[] = {"Bullet", "VehicleCrash", "Backblast", "Explosive", "Shell", "Grenade"};
minDamage = 0.5;
bleeding = 0.1;
pain = 0.4;
minDamage = 0.02;
causeLimping = 1;
};
};
class damageTypes {
// thresholds[] {{<min damage>, <max number of wounds>}, {...}}
thresholds[] = {{0.1, 1}};
selectionSpecific = 1;
lethalDamage = 0.01;
class bullet {
// above damage, amount. Put the highest threshold to the left and lower the threshold with the elements to the right of it.
@ -243,14 +100,12 @@ class ACE_Medical_Injuries {
selectionSpecific = 0;
};
class vehiclecrash {
thresholds[] = {{0.25, 5}, {0.05, 1}};
thresholds[] = {{0.5, 5}, {0.3, 2}, {0.05, 1}};
selectionSpecific = 0;
lethalDamage = 0.2;
};
class backblast {
thresholds[] = {{1, 6}, {0.55, 5}, {0, 2}};
selectionSpecific = 0;
lethalDamage = 1;
};
class stab {
thresholds[] = {{0.1, 1}};
@ -261,9 +116,8 @@ class ACE_Medical_Injuries {
selectionSpecific = 1;
};
class falling {
thresholds[] = {{0.1, 1}};
thresholds[] = {{0.6, 4}, {0.35, 2}, {0.1, 1}};
selectionSpecific = 1;
lethalDamage = 0.4;
};
class ropeburn {
thresholds[] = {{0.1, 1}};

View File

@ -2,8 +2,4 @@
PREP(parseConfigForInjuries);
PREP(getTypeOfDamage);
PREP(airwayHandler);
PREP(fracturesHandler);
PREP(internalInjuriesHandler);
PREP(woundsHandler);
PREP(woundsHandlerSQF);

View File

@ -6,18 +6,11 @@ ADDON = false;
call FUNC(parseConfigForInjuries);
// decide which woundsHandler to use by whether the extension is present or not
if ("ace_medical" callExtension "version" != "") then {
DFUNC(woundsHandlerActive) = FUNC(woundsHandler);
} else {
DFUNC(woundsHandlerActive) = FUNC(woundsHandlerSQF);
};
[QEGVAR(medical_engine,woundReceived), {
params ["_unit", "_woundedHitPoint", "_receivedDamage", "", "_ammo"];
private _typeOfDamage = _ammo call FUNC(getTypeOfDamage);
[_unit, _woundedHitPoint, _receivedDamage, _ammo, _typeOfDamage] call FUNC(woundsHandlerActive); // TODO also support the sqf variant
[_unit, _woundedHitPoint, _receivedDamage, _ammo, _typeOfDamage] call FUNC(woundsHandler);
[_unit, EGVAR(medical,STATE_MACHINE)] call EFUNC(medical,addStateHandler);
}] call CBA_fnc_addEventHandler;

View File

@ -1,31 +0,0 @@
/*
* Author: Glowbal
* Handling of the airway injuries upon the handleDamage eventhandler.
*
* Arguments:
* 0: Unit That Was Hit <OBJECT>
* 1: Name Of Body Part <STRING>
* 2: Amount Of Damage <NUMBER>
* 3: Shooter or source of the damage <OBJECT>
* 4: Type of the damage done <STRING>
*
* Return Value:
* None
*
* Public: No
*/
#include "script_component.hpp"
params ["_unit", "_bodyPart", "_amountOfDamage", "_sourceOfDamage", "_typeOfDamage"];
private _partIndex = ALL_BODY_PARTS find toLower _bodyPart;
if (_partIndex > 1) exitWith {};
if (_amountOfDamage > 0.5) then {
if (random(1) >= 0.8) then {
if !(_unit getVariable[QGVAR(airwayCollapsed), false]) then {
_unit setVariable [QGVAR(airwayCollapsed), true, true];
};
};
};

View File

@ -1,70 +0,0 @@
/*
* Author: Glowbal
* Handling of the fracture injuries upon the handleDamage eventhandler.
*
* Arguments:
* 0: Unit That Was Hit <OBJECT>
* 1: Name Of Body Part <STRING>
* 2: Amount Of Damage <NUMBER>
* 3: Shooter or source of the damage <OBJECT>
* 4: Type of the damage done <STRING>
*
* Return Value:
* None <NIL>
*
* Public: No
*/
#include "script_component.hpp"
params ["_unit", "_bodyPart", "_amountOfDamage", "_sourceOfDamage", "_typeOfDamage"];
private _partIndex = ALL_BODY_PARTS find toLower _bodyPart;
private _fractureType = 1;
if (_amountOfDamage > 0.05) then {
// TODO specify fractures based off typeOfInjury details better.
switch (_typeOfDamage) do {
case "Bullet": {
_fractureType = round(random(2));
};
case "Grenade": {
_fractureType = round(random(2));
if (_fractureType < 1) then {
_fractureType = 1;
};
};
case "Explosive": {
_fractureType = round(random(2));
if (_fractureType < 1) then {
_fractureType = 1;
};
};
case "Shell": {
_fractureType = round(random(2));
if (_fractureType < 1) then {
_fractureType = 1;
};
};
case "Unknown": {
_fractureType = round(random(1));
};
case "VehicleCrash": {
_fractureType = round(random(0));
};
default {
_fractureType = round(random(1));
};
};
private _fractures = _unit getVariable[QGVAR(fractures), []];
private _fractureID = 1;
private _amountOf = count _fractures;
if (_amountOf > 0) then {
_fractureID = (_fractures select (_amountOf - 1) select 0) + 1;
};
_fractures pushBack [_fractureID, _fractureType, _partIndex, 1 /* percentage treated */];
_unit setVariable [QGVAR(fractures), _fractures, true];
};

View File

@ -1,23 +0,0 @@
/*
* Author: Glowbal
* Handling of the internal injuries upon the handleDamage eventhandler.
*
* Arguments:
* 0: Unit That Was Hit <OBJECT>
* 1: Name Of Body Part <STRING>
* 2: Amount Of Damage <NUMBER>
* 3: Shooter or source of the damage <OBJECT>
* 4: Type of the damage done <STRING>
*
* Return Value:
* None
*
* Public: No
*/
#include "script_component.hpp"
params ["_unit", "_bodyPart", "_amountOfDamage", "_sourceOfDamage", "_typeOfDamage"];
// private _partIndex = ALL_BODY_PARTS find toLower _bodyPart;
// TODO implement internal injuries

View File

@ -12,55 +12,6 @@
*/
#include "script_component.hpp"
private _fnc_getAnyFromConfig = {
params ["_config", "_default"];
if (_default isEqualType []) exitWith {
GET_ARRAY(_config,_default)
};
if (_default isEqualType 0) exitWith {
GET_NUMBER(_config,_default)
};
if (_default isEqualType "") exitWith {
GET_STRING(_config,_default)
};
_default
};
private _fnc_parseSubClassWounds = {
params ["_subClass"];
private _subClassConfig = _entry >> _subClass;
if (isClass _subClassConfig) exitWith {
private _subClassSelections = [_subClassConfig >> "selections", _selections] call _fnc_getAnyFromConfig;
private _subClassCauses = [_subClassConfig >> "causes", _causes] call _fnc_getAnyFromConfig;
if (count _subClassSelections > 0 && {count _subClassCauses > 0}) then {
// constructs a type name, such as: 'woundMinor'
GVAR(woundClassNames) pushBack (_className + configName _subClassConfig);
GVAR(woundsData) pushBack [
_classID,
_subClassSelections,
[_subClassConfig >> "bleedingRate", _bleedingRate] call _fnc_getAnyFromConfig,
[_subClassConfig >> "pain", _pain] call _fnc_getAnyFromConfig,
[[_subClassConfig >> "minDamage", _minDamage] call _fnc_getAnyFromConfig, [_subClassConfig >> "maxDamage", _maxDamage] call _fnc_getAnyFromConfig],
_subClassCauses,
[_subClassConfig >> "name", _displayName + " " + _subClass] call _fnc_getAnyFromConfig
];
_classID = _classID + 1;
};
true
};
false
};
private _injuriesConfigRoot = configFile >> "ACE_Medical_Injuries";
// --- parse wounds
@ -74,36 +25,28 @@ private _classID = 0;
private _entry = _x;
private _className = configName _entry;
private _selections = GET_ARRAY(_entry >> "selections",[]);
private _bleedingRate = GET_NUMBER(_entry >> "bleedingRate",0);
private _selections = GET_ARRAY(_entry >> "selections",["All"]);
private _bleeding = GET_NUMBER(_entry >> "bleeding",0);
private _pain = GET_NUMBER(_entry >> "pain",0);
private _minDamage = GET_NUMBER(_entry >> "minDamage",0);
private _maxDamage = GET_NUMBER(_entry >> "maxDamage",-1);
private _causes = GET_ARRAY(_entry >> "causes",[]);
private _displayName = GET_STRING(_entry >> "name",_className); // @todo, don't translate in config
private _causeLimping = GET_NUMBER(_entry >> "causeLimping",0);
// TODO instead of hardcoding minor, medium and large just go through all sub classes recursively until none are found
if !("Minor" call _fnc_parseSubClassWounds || "Medium" call _fnc_parseSubClassWounds || "Large" call _fnc_parseSubClassWounds) then {
// There were no subclasses, so we will add this one instead.
if (count _selections > 0 && {count _causes > 0}) then {
GVAR(woundClassNames) pushBack _className;
GVAR(woundsData) pushBack [_classID, _selections, _bleedingRate, _pain, [_minDamage, _maxDamage], _causes, _displayName];
_classID = _classID + 1;
};
if (count _causes > 0) then {
GVAR(woundClassNames) pushBack _className;
GVAR(woundsData) pushBack [_classID, _selections, _bleeding, _pain, [_minDamage, _maxDamage], _causes, _displayName, _causeLimping];
_classID = _classID + 1;
};
} forEach configProperties [_woundsConfig, "isClass _x"];
// --- parse fractures
//GVAR(fractureClassNames) = []; // unused
// --- parse damage types
GVAR(allDamageTypes) = []; // @todo, currently unused by handle damage (was GVAR(allAvailableDamageTypes))
GVAR(lethalDamages) = []; // @todo, currently unused by handle damage (was GVAR(minLethalDamages))
GVAR(allDamageTypesData) = [] call CBA_fnc_createNamespace;
// minimum lethal damage collection, mapped to damageTypes
private _damageTypesConfig = _injuriesConfigRoot >> "damageTypes";
private _lethalDamageDefault = getNumber (_damageTypesConfig >> "lethalDamage");
private _thresholdsDefault = getArray (_damageTypesConfig >> "thresholds");
private _selectionSpecificDefault = getNumber (_damageTypesConfig >> "selectionSpecific");
@ -113,7 +56,6 @@ private _selectionSpecificDefault = getNumber (_damageTypesConfig >> "selectionS
private _className = configName _entry;
GVAR(allDamageTypes) pushBack _className;
GVAR(lethalDamages) pushBack GET_NUMBER(_entry >> "lethalDamage",_lethalDamageDefault);
// Check if this type is in the causes of a wound class, if so, we will store the wound types for this damage type
private _woundTypes = [];
@ -138,7 +80,7 @@ private _selectionSpecificDefault = getNumber (_damageTypesConfig >> "selectionS
private _extensionArgs = format [
"addDamageType,%1,%2,%3,%4,%5",
_className,
GVAR(lethalDamages) select _forEachIndex,
1, //@todo remove 'minLethalDamage' from extension
_minDamageThresholds,
_amountThresholds,
_selectionSpecific

View File

@ -36,25 +36,43 @@ private _woundsCreated = [];
call compile _extensionOutput;
// todo: Make the pain and bleeding calculations part of the extension again
private _painLevel = 0;
{
_x params ["", "_woundClassIDToAdd", "_bodyPartNToAdd"];
_x params ["", "_woundClassIDToAdd", "_bodyPartNToAdd", "", "_bleeding"];
_foundIndex = -1;
{
// Check if we have an id of the given class on the given bodypart already
if ((_woundClassIDToAdd isEqualTo (_x select 1)) && {_bodyPartNToAdd isEqualTo (_x select 2)}) exitWith {
_foundIndex = _forEachIndex;
};
} forEach _openWounds;
if (_foundIndex < 0) then {
// Since it is a new injury, we will have to add it to the open wounds array to store it
_openWounds pushBack _x;
// The higher the nastiness likelihood the higher the change to get a painful and bloody wound
private _nastinessLikelihood = if (_damage > 1) then {
(_damage ^ 0.33)
} else {
// We already have one of these, so we are just going to increase the number that we have of it with a new one.
private _injury = _openWounds select _foundIndex;
_injury set [3, (_injury select 3) + 1];
(0.1 max _damage)
};
private _bloodiness = 0.01 + 0.99 * (1 - random[0, 1, 0.9]) ^ (1 / _nastinessLikelihood);
private _painfullness = 0.05 + 0.95 * (1 - random[0, 1, 0.5]) ^ (1 / _nastinessLikelihood);
_bleeding = _bleeding * _bloodiness;
_x set [4, _bleeding];
_x set [5, _damage];
private _pain = ((GVAR(woundsData) select _woundClassIDToAdd) select 3) * _painfullness;
_painLevel = _painLevel max _pain;
#ifdef DEBUG_MODE_FULL
systemChat format["%1, damage: %2, peneration: %3, bleeding: %4, pain: %5", _bodyPart, round(_damage * 100) / 100, _damage > PENETRATION_THRESHOLD, round(_bleeding * 1000) / 1000, round(_pain * 1000) / 1000];
#endif
if (_bodyPartNToAdd == 0 && {_damage > 1}) then {
[QEGVAR(medical,FatalInjury), _unit] call CBA_fnc_localEvent;
};
// todo `forceWalk` based on leg damage
private _causeLimping = (GVAR(woundsData) select _woundClassIDToAdd) select 7;
if (_causeLimping == 1 && {_damage > 0.3} && {_bodyPartNToAdd > 3}) then {
[_unit, true] call EFUNC(medical_engine,setLimping);
};
_openWounds pushBack _x;
} forEach _woundsCreated;
_unit setVariable [QEGVAR(medical,openWounds), _openWounds, true];
@ -64,9 +82,10 @@ _unit setVariable [QEGVAR(medical,openWounds), _openWounds, true];
// Only update if new wounds have been created
if (count _woundsCreated > 0) then {
_unit setVariable [QEGVAR(medical,lastUniqueWoundID), _woundID, true];
[_unit] call EFUNC(medical,handleIncapacitation);
};
[_unit, _painToAdd] call EFUNC(medical,addPain);
[_unit, "hit", PAIN_TO_SCREAM(_painToAdd)] call EFUNC(medical_engine,playInjuredSound);
[_unit, _painLevel] call EFUNC(medical,adjustPainLevel);
[_unit, "hit", PAIN_TO_SCREAM(_painLevel)] call EFUNC(medical_engine,playInjuredSound);
TRACE_5("exit",_unit, _painToAdd, _unit getVariable QEGVAR(medical,pain), _unit getVariable QEGVAR(medical,openWounds),_woundsCreated);
TRACE_5("exit",_unit,_painLevel,_unit getVariable QEGVAR(medical,pain),_unit getVariable QEGVAR(medical,openWounds),_woundsCreated);

View File

@ -1,141 +0,0 @@
/*
* Author: Glowbal, commy2
* Handling of the open wounds & injuries upon the handleDamage eventhandler.
*
* Arguments:
* 0: Unit That Was Hit <OBJECT>
* 1: Name Of Body Part <STRING>
* 2: Amount Of Damage <NUMBER>
* 3: Shooter or source of the damage <OBJECT>
* 4: Type of the damage done <STRING>
*
* Return Value:
* None
*
* Public: No
*/
#include "script_component.hpp"
params ["_unit", "_bodyPart", "_damage", "_typeOfProjectile", "_typeOfDamage"];
TRACE_5("start",_unit,_bodyPart,_damage,_typeOfProjectile,_typeOfDamage);
// Convert the selectionName to a number and ensure it is a valid selection.
private _bodyPartN = ALL_BODY_PARTS find toLower _bodyPart;
if (_bodyPartN < 0) exitWith {};
if (_typeOfDamage isEqualTo "") then {
_typeOfDamage = "unknown";
};
// Get the damage type information. Format: [typeDamage thresholds, selectionSpecific, woundTypes]
// WoundTypes are the available wounds for this damage type. Format [[classID, selections, bleedingRate, pain], ..]
private _damageTypeInfo = [GVAR(allDamageTypesData) getVariable _typeOfDamage] param [0, [[], false, []]];
_damageTypeInfo params ["_thresholds", "_isSelectionSpecific", "_woundTypes"];
// It appears we are dealing with an unknown type of damage.
if (count _woundTypes == 0) then {
// grabbing the configuration for unknown damage type
_damageTypeInfo = [GVAR(allDamageTypesData) getVariable "unknown"] param [0, [[], false, []]];
_woundTypes = _damageTypeInfo select 2;
};
// find the available injuries for this damage type and damage amount
private _highestPossibleSpot = -1;
private _highestPossibleDamage = -1;
private _allPossibleInjuries = [];
{
_x params ["", "_selections", "", "", "_damageExtrema"];
_damageExtrema params ["_minDamage", "_maxDamage"];
// Check if the damage is higher as the min damage for the specific injury
if (_damage >= _minDamage && {_damage <= _maxDamage || _maxDamage < 0}) then {
// Check if the injury can be applied to the given selection name
if ("All" in _selections || _bodyPart in _selections) then { // @todo, this is case sensitive!
// Find the wound which has the highest minimal damage, so we can use this later on for adding the correct injuries
if (_minDamage > _highestPossibleDamage) then {
_highestPossibleSpot = _forEachIndex;
_highestPossibleDamage = _minDamage;
};
// Store the valid possible injury for the damage type, damage amount and selection
_allPossibleInjuries pushBack _x;
};
};
} forEach _woundTypes;
// No possible wounds available for this damage type or damage amount.
if (_highestPossibleSpot < 0) exitWith {};
// Administration for open wounds and ids
private _openWounds = _unit getVariable [QEGVAR(medical,openWounds), []];
private _woundID = _unit getVariable [QGVAR(lastUniqueWoundID), 1];
private _painToAdd = 0;
private _woundsCreated = [];
{
if (_x select 0 <= _damage) exitWith {
for "_i" from 0 to ((_x select 1)-1) do {
// Find the injury we are going to add. Format [ classID, allowdSelections, bleedingRate, injuryPain]
private _oldInjury = if (random 1 >= 0.85) then {
_woundTypes select _highestPossibleSpot
} else {
selectRandom _allPossibleInjuries
};
_oldInjury params ["_woundClassIDToAdd", "", "_injuryBleedingRate", "_injuryPain"];
private _bodyPartNToAdd = [floor random 6, _bodyPartN] select _isSelectionSpecific; // 6 == count ALL_BODY_PARTS
// If the injury type is selection part specific, we will check if one of those injury types already exists and find the spot for it..
private _foundIndex = -1;
if (_isSelectionSpecific) then {
{
// Check if we have an id of the given class on the given bodypart already
if ((_woundClassIDToAdd isEqualTo (_x select 1)) && {_bodyPartNToAdd isEqualTo (_x select 2)}) exitWith {
_foundIndex = _forEachIndex;
};
} forEach _openWounds;
};
private _injury = [];
if (_foundIndex < 0) then {
// Create a new injury. Format [ID, classID, bodypart, percentage treated, bleeding rate]
_injury = [_woundID, _woundClassIDToAdd, _bodyPartNToAdd, 1, _injuryBleedingRate];
// Since it is a new injury, we will have to add it to the open wounds array to store it
_openWounds pushBack _injury;
// New injuries will also increase the wound ID
_woundID = _woundID + 1;
} else {
// We already have one of these, so we are just going to increase the number that we have of it with a new one.
_injury = _openWounds select _foundIndex;
_injury set [3, (_injury select 3) + 1];
};
// Store the injury so we can process it later correctly.
_woundsCreated pushBack _injury;
// Collect the pain that is caused by this injury
_painToAdd = _injuryPain + _painToAdd;
};
};
} forEach _thresholds;
_unit setVariable [QEGVAR(medical,openWounds), _openWounds, true];
[_unit, _bodyPart] call EFUNC(medical_engine,updateBodyPartVisuals);
// Only update if new wounds have been created
if (count _woundsCreated > 0) then {
_unit setVariable [QGVAR(lastUniqueWoundID), _woundID, true];
};
[_unit, _painToAdd] call EFUNC(medical,addPain);
[_unit, "hit", PAIN_TO_SCREAM(_painToAdd)] call EFUNC(medical_engine,playInjuredSound);
TRACE_5("exit",_unit, _painToAdd, _unit getVariable QEGVAR(medical,pain), _unit getVariable QEGVAR(medical,openWounds),_woundsCreated);

View File

@ -18,8 +18,8 @@
#ifdef DEBUG_MODE_FULL
[QGVAR(woundReceived), {
diag_log _this;
systemChat str _this;
//diag_log _this;
//systemChat str _this;
}] call CBA_fnc_addEventHandler;
#endif

View File

@ -104,7 +104,13 @@ if (_hitPoint isEqualTo "ace_hdbracket") exitWith {
// Check for falling damage.
if (_ammo isEqualTo "") then {
if (velocity _unit select 2 < -2) then {
_woundedHitPoint = selectRandom ["LeftLeg", "RightLeg"];
if (_receivedDamage < 0.35) then {
// Less than ~ 5 m
_woundedHitPoint = selectRandom ["LeftLeg", "RightLeg"];
} else {
// More than ~ 5 m
_woundedHitPoint = selectRandom ["LeftLeg", "RightLeg", "Body", "Head"];
};
_ammo = "#falling";
} else {
// Assume collision damage.

View File

@ -44,22 +44,22 @@ switch (toLower _bodyPart) do {
};
private _openWounds = _unit getVariable QEGVAR(medical,openWounds);
private _bloodLossOnAffectedBodyParts = 0;
private _damageOnAffectedBodyParts = 0;
{
private _bloodLossOnBodyPart = 0;
private _damageOnBodyPart = 0;
private _partIndex = ALL_BODY_PARTS find toLower _x;
{
_x params ["", "", "_bodyPartN", "_amountOf", "_percentageOpen"];
_x params ["", "", "_bodyPartN", "", "_bleeding", "_damage"];
if (_bodyPartN isEqualTo _partIndex) then {
_bloodLossOnBodyPart = _bloodLossOnBodyPart + (_amountOf * _percentageOpen);
_damageOnBodyPart = _damageOnBodyPart + _damage;
};
} forEach _openWounds;
// report maximum of both legs or arms
_bloodLossOnAffectedBodyParts = _bloodLossOnAffectedBodyParts max _bloodLossOnBodyPart;
_damageOnAffectedBodyParts = _damageOnAffectedBodyParts max _damageOnBodyPart;
} forEach _affectedBodyParts;
[_unit, _bodyPart, _bloodLossOnAffectedBodyParts > 0] call FUNC(damageBodyPart);
[_unit, _bodyPart, _damageOnAffectedBodyParts > 0.35] call FUNC(damageBodyPart);

View File

@ -48,7 +48,7 @@ class CfgVehicles {
displayName = ECSTRING(medical,Actions_Medical);
runOnHover = 1;
exceptions[] = {"isNotInside", "isNotSitting"};
statement = QUOTE([ARR_3(_target, true, 0)] call EFUNC(medical_treatment,displayPatientInformation));
statement = QUOTE([ARR_3(_target,1,0)] call EFUNC(medical_treatment,displayPatientInformation));
condition = "true";
icon = QPATHTOEF(medical,UI\icons\medical_cross.paa);
#include "InteractionBodyParts.hpp"

View File

@ -2,7 +2,7 @@ class ACE_Head {
displayName = ECSTRING(interaction,Head);
icon = QPATHTOEF(medical,UI\icons\medical_cross.paa);
exceptions[] = {"isNotInside", "isNotSitting"};
statement = QUOTE([ARR_3(_target, true, 0)] call EFUNC(medical_treatment,displayPatientInformation));
statement = QUOTE([ARR_3(_target,1,0)] call EFUNC(medical_treatment,displayPatientInformation));
modifierFunction = QUOTE([ARR_4(_target,_player,0,_this select 3)] call FUNC(modifyAction));
condition = "true";
runOnHover = 1;
@ -13,7 +13,7 @@ class ACE_Torso {
condition = "true";
runOnHover = 1;
exceptions[] = {"isNotInside", "isNotSitting"};
statement = QUOTE([ARR_3(_target, true, 1)] call EFUNC(medical_treatment,displayPatientInformation));
statement = QUOTE([ARR_3(_target,1,1)] call EFUNC(medical_treatment,displayPatientInformation));
modifierFunction = QUOTE([ARR_4(_target,_player,1,_this select 3)] call FUNC(modifyAction));
showDisabled = 1;
priority = 2;
@ -23,7 +23,7 @@ class ACE_ArmLeft {
displayName = ECSTRING(interaction,ArmLeft);
runOnHover = 1;
exceptions[] = {"isNotInside", "isNotSitting"};
statement = QUOTE([ARR_3(_target, true, 2)] call EFUNC(medical_treatment,displayPatientInformation));
statement = QUOTE([ARR_3(_target,1,2)] call EFUNC(medical_treatment,displayPatientInformation));
modifierFunction = QUOTE([ARR_4(_target,_player,2,_this select 3)] call FUNC(modifyAction));
condition = "true";
icon = QPATHTOEF(medical,UI\icons\medical_cross.paa);
@ -32,7 +32,7 @@ class ACE_ArmRight {
displayName = ECSTRING(interaction,ArmRight);
runOnHover = 1;
exceptions[] = {"isNotInside", "isNotSitting"};
statement = QUOTE([ARR_3(_target, true, 3)] call EFUNC(medical_treatment,displayPatientInformation));
statement = QUOTE([ARR_3(_target,1,3)] call EFUNC(medical_treatment,displayPatientInformation));
modifierFunction = QUOTE([ARR_4(_target,_player,3,_this select 3)] call FUNC(modifyAction));
condition = "true";
icon = QPATHTOEF(medical,UI\icons\medical_cross.paa);
@ -41,7 +41,7 @@ class ACE_LegLeft {
displayName = ECSTRING(interaction,LegLeft);
runOnHover = 1;
exceptions[] = {"isNotInside", "isNotSitting"};
statement = QUOTE([ARR_3(_target, true, 4)] call EFUNC(medical_treatment,displayPatientInformation));
statement = QUOTE([ARR_3(_target,1,4)] call EFUNC(medical_treatment,displayPatientInformation));
modifierFunction = QUOTE([ARR_4(_target,_player,4,_this select 3)] call FUNC(modifyAction));
condition = "true";
icon = QPATHTOEF(medical,UI\icons\medical_cross.paa);
@ -50,7 +50,7 @@ class ACE_LegRight {
displayName = ECSTRING(interaction,LegRight);
runOnHover = 1;
exceptions[] = {"isNotInside", "isNotSitting"};
statement = QUOTE([ARR_3(_target, true, 5)] call EFUNC(medical_treatment,displayPatientInformation));
statement = QUOTE([ARR_3(_target,1,5)] call EFUNC(medical_treatment,displayPatientInformation));
modifierFunction = QUOTE([ARR_4(_target,_player,5,_this select 3)] call FUNC(modifyAction));
condition = "true";
icon = QPATHTOEF(medical,UI\icons\medical_cross.paa);

View File

@ -7,7 +7,7 @@ GVAR(lastOpenedOn) = -1;
GVAR(pendingReopen) = false;
["ace_settingsInitialized", {
if (EGVAR(medical,level) > 0 && {EGVAR(medical,menuTypeStyle) == 0}) then {
if (EGVAR(medical,menuTypeStyle) == 0) then {
[] call FUNC(collectActions3D);
};
}] call CBA_fnc_addEventHandler;

View File

@ -4,8 +4,9 @@
*
* Arguments:
* 0: selection bloodloss <ARRAY>
* 1: damaged (array of bools) <ARRAY>
* 2: display <DISPLAY>
* 1: selection damage <ARRAY>
* 2: selection torniquet <ARRAY>
* 3: display <DISPLAY>
*
* Return Value:
* None
@ -17,7 +18,7 @@
*/
#include "script_component.hpp"
params ["_selectionBloodLoss", "_damaged", "_display"];
params ["_selectionBloodLoss", "_selectionDamage", "_selectionTourniquet", "_display"];
// Handle the body image coloring
private _availableSelections = [50, 51, 52, 53, 54, 55];
@ -26,16 +27,22 @@ private _availableSelections = [50, 51, 52, 53, 54, 55];
private _green = 1;
private _blue = 1;
if (_x > 0) then {
if (_damaged select _forEachIndex) then {
_green = (0.9 - _x) max 0;
private _torniquet = _selectionTourniquet select _forEachIndex;
if (_torniquet > 0) then {
_red = 0.77;
_green = 0.51;
_blue = 0.08;
} else {
private _bloodLoss = _selectionBloodLoss select _forEachIndex;
if (_bloodLoss > 0) then {
_green = 0 max (0.9 - _bloodLoss);
_blue = _green;
} else {
_green = (0.9 - _x) max 0;
private _damage = _selectionDamage select _forEachIndex;
_green = 0 max (0.9 - _damage);
_red = _green;
//_blue = _green;
};
};
(_display displayCtrl (_availableSelections select _forEachIndex)) ctrlSetTextColor [_red, _green, _blue, 1.0];
} forEach _selectionBloodLoss;
(_display displayCtrl _x) ctrlSetTextColor [_red, _green, _blue, 1.0];
} forEach _availableSelections;

View File

@ -18,15 +18,13 @@
params ["_target", "_display"];
private ["_allInjuryTexts", "_bandagedwounds", "_damaged", "_genericMessages", "_logs", "_openWounds", "_part", "_partText", "_pointDamage", "_selectionBloodLoss", "_selectionN", "_severity", "_totalIvVolume", "_triageStatus"];
if (isNil "_display" || {isNull _display}) exitWith {ERROR("No display");};
_selectionN = GVAR(selectedBodyPart);
private _selectionN = GVAR(selectedBodyPart);
if (_selectionN < 0 || {_selectionN > 5}) exitWith {};
_genericMessages = [];
_partText = [ELSTRING(medical,Head), ELSTRING(medical,Torso), ELSTRING(medical,LeftArm) ,ELSTRING(medical,RightArm) ,ELSTRING(medical,LeftLeg), ELSTRING(medical,RightLeg)] select _selectionN;
private _genericMessages = [];
private _partText = [ELSTRING(medical,Head), ELSTRING(medical,Torso), ELSTRING(medical,LeftArm) ,ELSTRING(medical,RightArm) ,ELSTRING(medical,LeftLeg), ELSTRING(medical,RightLeg)] select _selectionN;
_genericMessages pushBack [localize _partText, [1, 1, 1, 1]];
if (_target getVariable [QEGVAR(medical,isBleeding), false]) then {
@ -45,7 +43,7 @@ if (_target getVariable [QEGVAR(medical,hasPain), false]) then {
_genericMessages pushBack [localize ELSTRING(medical,Status_Pain), [1, 1, 1, 1]];
};
_totalIvVolume = 0;
private _totalIvVolume = 0;
private _bloodBags = _target getVariable [QEGVAR(medical,ivBags), []];
{
_x params ["_bagVolumeRemaining"];
@ -56,96 +54,64 @@ if (_totalIvVolume >= 1) then {
_genericMessages pushBack [format [localize ELSTRING(medical,receivingIvVolume), floor _totalIvVolume], [1, 1, 1, 1]];
};
_damaged = [false, false, false, false, false, false];
_selectionBloodLoss = [0, 0, 0, 0, 0, 0];
private _selectionTourniquet = _target getVariable [QEGVAR(medical,tourniquets), [0,0,0,0,0,0]];
private _selectionBloodLoss = [0, 0, 0, 0, 0, 0];
private _selectionDamage = [0, 0, 0, 0, 0, 0];
private _allInjuryTexts = [];
_allInjuryTexts = [];
if (EGVAR(medical,level) >= 2) then { // && {([_target] call EFUNC(medical,hasMedicalEnabled))}
_openWounds = _target getVariable [QEGVAR(medical,openWounds), []];
private "_amountOf";
{
_amountOf = _x select 3;
// Find how much this bodypart is bleeding
{
_x params ["", "_woundClassID", "_bodyPartN", "_amountOf", "_bleeding", "_damage"];
_selectionBloodLoss set [_bodyPartN, (_selectionBloodLoss select _bodyPartN) + (20 * (_bleeding * _amountOf))];
_selectionDamage set [_bodyPartN, (_selectionDamage select _bodyPartN) + _damage];
if (_selectionN == _bodyPartN) then {
// Collect the text to be displayed for this injury [ Select injury class type definition - select the classname DisplayName (6th), amount of injuries for this]
if (_amountOf > 0) then {
_damaged set [_x select 2, true];
_selectionBloodLoss set [_x select 2, (_selectionBloodLoss select (_x select 2)) + (20 * ((_x select 4) * _amountOf))];
if (_selectionN == (_x select 2)) then {
// Collect the text to be displayed for this injury [ Select injury class type definition - select the classname DisplayName (6th), amount of injuries for this]
if (_amountOf >= 1) then {
// TODO localization
_allInjuryTexts pushBack [format["%2x %1", (EGVAR(medical,AllWoundInjuryTypes) select (_x select 1)) select 6, ceil _amountOf], [1,1,1,1]];
} else {
// TODO localization
_allInjuryTexts pushBack [format["Partial %1", (EGVAR(medical,AllWoundInjuryTypes) select (_x select 1)) select 6], [1,1,1,1]];
};
if (_amountOf >= 1) then {
// TODO localization
_allInjuryTexts pushBack [format["%2x %1", (EGVAR(medical_damage,woundsData) select _woundClassID) select 6, ceil _amountOf], [1,1,1,1]];
} else {
// TODO localization
_allInjuryTexts pushBack [format["Partial %1", (EGVAR(medical_damage,woundsData) select _woundClassID) select 6], [1,1,1,1]];
};
};
} forEach _openWounds;
_bandagedwounds = _target getVariable [QEGVAR(medical,bandagedWounds), []];
{
_amountOf = _x select 3;
// Find how much this bodypart is bleeding
if !(_damaged select (_x select 2)) then {
_selectionBloodLoss set [_x select 2, (_selectionBloodLoss select (_x select 2)) + (20 * ((_x select 4) * _amountOf))];
};
if (_selectionN == (_x select 2)) then {
// Collect the text to be displayed for this injury [ Select injury class type definition - select the classname DisplayName (6th), amount of injuries for this]
if (_amountOf > 0) then {
if (_amountOf >= 1) then {
// TODO localization
_allInjuryTexts pushBack [format ["[B] %2x %1", (EGVAR(medical,AllWoundInjuryTypes) select (_x select 1)) select 6, ceil _amountOf], [0.88,0.7,0.65,1]];
} else {
// TODO localization
_allInjuryTexts pushBack [format ["[B] Partial %1", (EGVAR(medical,AllWoundInjuryTypes) select (_x select 1)) select 6], [0.88,0.7,0.65,1]];
};
};
};
} forEach _bandagedwounds;
} else {
// Add all bleeding from wounds on selection
_openWounds = _target getVariable [QEGVAR(medical,openWounds), []];
private "_amountOf";
{
_amountOf = _x select 3;
// Find how much this bodypart is bleeding
if (_amountOf > 0) then {
_damaged set [_x select 2, true];
_selectionBloodLoss set [_x select 2, (_selectionBloodLoss select (_x select 2)) + (20 * ((_x select 4) * _amountOf))];
};
} forEach _openWounds;
_bandagedwounds = _target getVariable [QEGVAR(medical,bandagedWounds), []];
{
_amountOf = _x select 3;
// Find how much this bodypart is bleeding
if !(_damaged select (_x select 2)) then {
_selectionBloodLoss set [_x select 2, (_selectionBloodLoss select (_x select 2)) + (20 * ((_x select 4) * _amountOf))];
};
} forEach _bandagedwounds;
private _bloodLossOnSelection = _selectionBloodLoss select _selectionN;
if (_bloodLossOnSelection > 0) then {
private _severity = switch (true) do {
case (_bloodLossOnSelection > 0.5): {localize ELSTRING(medical,HeavilyWounded)};
case (_bloodLossOnSelection > 0.1): {localize ELSTRING(medical,LightlyWounded)};
default {localize ELSTRING(medical,VeryLightlyWounded)};
};
private _part = localize ([
ELSTRING(medical,Head),
ELSTRING(medical,Torso),
ELSTRING(medical,LeftArm),
ELSTRING(medical,RightArm),
ELSTRING(medical,LeftLeg),
ELSTRING(medical,RightLeg)
] select _selectionN);
_allInjuryTexts pushBack [format ["%1 %2", _severity, toLower _part], [1,1,1,1]];
};
};
} forEach (_target getVariable [QEGVAR(medical,openWounds), []]);
[_selectionBloodLoss, _damaged, _display] call FUNC(updateBodyImage);
{
_x params ["", "_woundClassID", "_bodyPartN", "_amountOf", "_bleeding", "_damage"];
_selectionDamage set [_bodyPartN, (_selectionDamage select _bodyPartN) + _damage];
if (_selectionN == _bodyPartN) then {
// Collect the text to be displayed for this injury [ Select injury class type definition - select the classname DisplayName (6th), amount of injuries for this]
if (_amountOf > 0) then {
if (_amountOf >= 1) then {
// TODO localization
_allInjuryTexts pushBack [format ["[B] %2x %1", (EGVAR(medical_damage,woundsData) select _woundClassID) select 6, ceil _amountOf], [0.88,0.7,0.65,1]];
} else {
// TODO localization
_allInjuryTexts pushBack [format ["[B] Partial %1", (EGVAR(medical_damage,woundsData) select _woundClassID) select 6], [0.88,0.7,0.65,1]];
};
};
};
} forEach (_target getVariable [QEGVAR(medical,bandagedWounds), []]);
{
_x params ["", "_woundClassID", "_bodyPartN", "_amountOf", "_bleeding", "_damage"];
_selectionDamage set [_bodyPartN, (_selectionDamage select _bodyPartN) + _damage];
if (_selectionN == _bodyPartN) then {
// Collect the text to be displayed for this injury [ Select injury class type definition - select the classname DisplayName (6th), amount of injuries for this]
if (_amountOf > 0) then {
if (_amountOf >= 1) then {
// TODO localization
_allInjuryTexts pushBack [format ["[S] %2x %1", (EGVAR(medical_damage,woundsData) select _woundClassID) select 6, ceil _amountOf], [0.7,0.7,0.7,1]];
} else {
// TODO localization
_allInjuryTexts pushBack [format ["[S] Partial %1", (EGVAR(medical_damage,woundsData) select _woundClassID) select 6], [0.7,0.7,0.7,1]];
};
};
};
} forEach (_target getVariable [QEGVAR(medical,stitchedWounds), []]);
[_selectionBloodLoss, _selectionDamage, _selectionTourniquet, _display] call FUNC(updateBodyImage);
[_display, _genericMessages, _allInjuryTexts] call FUNC(updateInformationLists);
[_display, _target getVariable [QEGVAR(medical,logFile_activity_view), []]] call FUNC(updateActivityLog);

View File

@ -13,7 +13,6 @@ class GVAR(Actions) {
treatmentTimeSelfCoef = 1;
items[] = {{"ACE_fieldDressing", "ACE_packingBandage", "ACE_elasticBandage", "ACE_quikclot"}};
condition = QUOTE(!EGVAR(medical,advancedBandages));
patientStateCondition = 0;
itemConsumed = 1;
callbackSuccess = QFUNC(treatmentBandage);
callbackFailure = "";
@ -76,7 +75,7 @@ class GVAR(Actions) {
displayNameProgress = ECSTRING(medical,Applying_Tourniquet);
allowedSelections[] = {"LeftArm", "RightArm", "LeftLeg", "RightLeg"};
items[] = {"ACE_tourniquet"};
treatmentTime = 4;
treatmentTime = 5;
callbackSuccess = QFUNC(treatmentTourniquet);
condition = QUOTE(EGVAR(medical,advancedBandages) && {!([ARR_2(_target,_bodyPart)] call EFUNC(medical,hasTourniquetAppliedTo))});
litter[] = {};
@ -97,7 +96,7 @@ class GVAR(Actions) {
category = "medication";
items[] = {"ACE_morphine"};
condition = "";
treatmentTime = 10;
treatmentTime = 9;
callbackSuccess = QFUNC(treatmentMedication);
animationCaller = "AinvPknlMstpSnonWnonDnon_medic1";
litter[] = { {"All", "", {"ACE_MedicalLitter_morphine"}} };
@ -106,12 +105,14 @@ class GVAR(Actions) {
class Adenosine: Morphine {
displayName = ECSTRING(medical,Inject_Adenosine);
displayNameProgress = ECSTRING(medical,Injecting_Adenosine);
condition = QEGVAR(medical,advancedMedication);
items[] = {"ACE_adenosine"};
litter[] = { {"All", "", {"ACE_MedicalLitter_adenosine"}} };
};
class Atropine: Morphine {
displayName = ECSTRING(medical,Inject_Atropine);
displayNameProgress = ECSTRING(medical,Injecting_Atropine);
condition = QEGVAR(medical,advancedMedication);
items[] = {"ACE_atropine"};
litter[] = { {"All", "", {"ACE_MedicalLitter_atropine"}} };
};
@ -205,6 +206,7 @@ class GVAR(Actions) {
class CheckBloodPressure: CheckPulse {
displayName = ECSTRING(medical,Actions_CheckBloodPressure);
displayNameProgress = ECSTRING(medical,Check_Bloodpressure_Content);
allowedSelections[] = {"LeftArm", "RightArm", "LeftLeg", "RightLeg"};
callbackSuccess = QFUNC(actionCheckBloodPressure);
};
class CheckResponse: CheckPulse {
@ -258,48 +260,42 @@ class GVAR(Actions) {
litter[] = {};
};
/*
class Advanced {
class SurgicalKit: fieldDressing {
displayName = ECSTRING(medical,Use_SurgicalKit);
displayNameProgress = ECSTRING(medical,Stitching);
category = "advanced";
items[] = {"ACE_surgicalKit"};
treatmentLocations[] = {QEGVAR(medical,useLocation_SurgicalKit)};
allowSelfTreatment = 0;
requiredMedic = QEGVAR(medical,medicSetting_SurgicalKit);
patientStateCondition = QEGVAR(medical,useCondition_SurgicalKit);
treatmentTime = QUOTE(count (_target getVariable [ARR_2('EGVAR(medical,bandagedWounds)',[])]) * 5);
callbackSuccess = "";
callbackProgress = QFUNC(treatmentSurgicalKit_onProgress);
itemConsumed = QEGVAR(medical,consumeItem_SurgicalKit);
animationCaller = "AinvPknlMstpSnonWnonDnon_medic1";
litter[] = { {"All", "", {"ACE_MedicalLitter_gloves"} }};
};
class PersonalAidKit: fieldDressing {
displayName = ECSTRING(medical,Use_Aid_Kit);
displayNameProgress = ECSTRING(medical,TreatmentAction);
category = "advanced";
items[] = {"ACE_personalAidKit"};
treatmentLocations[] = {QEGVAR(medical,useLocation_PAK)};
allowSelfTreatment = 0;
requiredMedic = QEGVAR(medical,medicSetting_PAK);
patientStateCondition = QEGVAR(medical,useCondition_PAK);
treatmentTime = QUOTE(_target call FUNC(treatmentFullHealTreatmentTime));
callbackSuccess = QFUNC(treatmentFullHeal);
itemConsumed = QEGVAR(medical,consumeItem_PAK);
animationPatient = "";
animationPatientUnconscious = "AinjPpneMstpSnonWrflDnon_rolltoback";
animationCaller = "AinvPknlMstpSlayW[wpn]Dnon_medicOther";
animationCallerProne = "AinvPpneMstpSlayW[wpn]Dnon_medicOther";
animationCallerSelf = "";
animationCallerSelfProne = "";
litter[] = { {"All", "", {"ACE_MedicalLitter_gloves"}},
{"All", "_bloodLossOnBodyPart > 0", {{"ACE_MedicalLitterBase", "ACE_MedicalLitter_bandage1", "ACE_MedicalLitter_bandage2", "ACE_MedicalLitter_bandage3"}}},
{"All", "_bloodLossOnBodyPart > 0", {{"ACE_MedicalLitterBase", "ACE_MedicalLitter_bandage1", "ACE_MedicalLitter_bandage2", "ACE_MedicalLitter_bandage3"}}},
{"All", "_bloodLossOnBodyPart <= 0", {"ACE_MedicalLitter_clean"}}
};
class SurgicalKit: fieldDressing {
displayName = ECSTRING(medical,Use_SurgicalKit);
displayNameProgress = ECSTRING(medical,Stitching);
category = "advanced";
items[] = {"ACE_surgicalKit"};
treatmentLocations[] = {QEGVAR(medical,useLocation_SurgicalKit)};
allowSelfTreatment = 0;
requiredMedic = QEGVAR(medical,medicSetting_SurgicalKit);
treatmentTime = QUOTE(count (_target getVariable [ARR_2('EGVAR(medical,bandagedWounds)',[])]) * 5);
callbackSuccess = "";
callbackProgress = QFUNC(treatmentSurgicalKit_onProgress);
itemConsumed = QEGVAR(medical,consumeItem_SurgicalKit);
animationCaller = "AinvPknlMstpSnonWnonDnon_medic1";
litter[] = { {"All", "", {"ACE_MedicalLitter_gloves"} }};
};
class PersonalAidKit: BasicBandage {
displayName = ECSTRING(medical,Use_Aid_Kit);
displayNameProgress = ECSTRING(medical,TreatmentAction);
category = "advanced";
condition = QUOTE(_target call EFUNC(medical,isInStableCondition));
items[] = {"ACE_personalAidKit"};
treatmentLocations[] = {QEGVAR(medical,useLocation_PAK)};
requiredMedic = QEGVAR(medical,medicSetting_PAK);
treatmentTime = QUOTE(_target call FUNC(treatmentFullHealTreatmentTime));
callbackSuccess = QFUNC(treatmentFullHeal);
itemConsumed = QEGVAR(medical,consumeItem_PAK);
animationPatient = "";
animationPatientUnconscious = "AinjPpneMstpSnonWrflDnon_rolltoback";
animationCaller = "AinvPknlMstpSlayW[wpn]Dnon_medicOther";
animationCallerProne = "AinvPpneMstpSlayW[wpn]Dnon_medicOther";
animationCallerSelf = "";
animationCallerSelfProne = "";
litter[] = { {"All", "", {"ACE_MedicalLitter_gloves"}},
{"All", "_bloodLossOnBodyPart > 0", {{"ACE_MedicalLitterBase", "ACE_MedicalLitter_bandage1", "ACE_MedicalLitter_bandage2", "ACE_MedicalLitter_bandage3"}}},
{"All", "_bloodLossOnBodyPart > 0", {{"ACE_MedicalLitterBase", "ACE_MedicalLitter_bandage1", "ACE_MedicalLitter_bandage2", "ACE_MedicalLitter_bandage3"}}},
{"All", "_bloodLossOnBodyPart <= 0", {"ACE_MedicalLitter_clean"}}
};
};
*/
};

View File

@ -75,18 +75,6 @@ if (isText (_config >> "condition")) then {
if !(_condition) exitWith {false};
private _patientStateCondition = 0;
if (isNumber (_config >> "patientStateCondition")) then {
_patientStateCondition = getNumber (_config >> "patientStateCondition");
} else {
if (isText (_config >> "patientStateCondition")) then {
_patientStateCondition = missionNamespace getVariable [getText (_config >> "patientStateCondition"), 0];
};
};
if (_patientStateCondition == 1 && {!([_target] call EFUNC(medical,isInStableCondition))}) exitWith {false};
// check allowed locations
private _locations = getArray (_config >> "treatmentLocations") apply {toLower _x};

View File

@ -20,38 +20,19 @@ _unit removeItems "FirstAidKit";
private _countMedikit = {_x == "Medikit"} count items _unit;
_unit removeItems "Medikit";
if (EGVAR(medical,level) >= 2) then {
// --- advanced
for "" from 1 to _countFirstAidKit do {
_unit addItem "ACE_fieldDressing";
_unit addItem "ACE_packingBandage";
_unit addItem "ACE_morphine";
_unit addItem "ACE_tourniquet";
};
for "" from 1 to _countMedikit do {
_unit addItemToBackpack "ACE_fieldDressing";
_unit addItemToBackpack "ACE_packingBandage";
_unit addItemToBackpack "ACE_packingBandage";
_unit addItemToBackpack "ACE_epinephrine";
_unit addItemToBackpack "ACE_morphine";
_unit addItemToBackpack "ACE_salineIV_250";
_unit addItemToBackpack "ACE_tourniquet";
};
} else {
// --- basic
for "" from 1 to _countFirstAidKit do {
_unit addItem "ACE_fieldDressing";
_unit addItem "ACE_fieldDressing";
_unit addItem "ACE_morphine";
};
for "" from 1 to _countMedikit do {
_unit addItemToBackpack "ACE_epinephrine";
_unit addItemToBackpack "ACE_epinephrine";
_unit addItemToBackpack "ACE_epinephrine";
_unit addItemToBackpack "ACE_epinephrine";
_unit addItemToBackpack "ACE_bloodIV";
_unit addItemToBackpack "ACE_bloodIV";
};
for "_i" from 1 to _countFirstAidKit do {
_unit addItem "ACE_fieldDressing";
_unit addItem "ACE_packingBandage";
_unit addItem "ACE_morphine";
_unit addItem "ACE_tourniquet";
};
for "_i" from 1 to _countMedikit do {
_unit addItemToBackpack "ACE_fieldDressing";
_unit addItemToBackpack "ACE_packingBandage";
_unit addItemToBackpack "ACE_packingBandage";
_unit addItemToBackpack "ACE_epinephrine";
_unit addItemToBackpack "ACE_morphine";
_unit addItemToBackpack "ACE_salineIV_250";
_unit addItemToBackpack "ACE_tourniquet";
};

View File

@ -4,7 +4,7 @@
*
* Arguments:
* 0: The Unit <OBJECT>
* 1: Show <BOOL> (default: true)
* 1: Show <NUMBER> (default: 0)
* 2: Selection <NUMBER> (default: 0)
*
* ReturnValue:
@ -16,15 +16,12 @@
#include "script_component.hpp"
#define MAX_DISTANCE 10
// Exit for basic medical
if (EGVAR(medical,level) < 2) exitWith {};
params ["_target", ["_show", true], ["_selectionN", 0]];
params ["_target", ["_show", 0], ["_selectionN", 0]];
GVAR(currentSelectedSelectionN) = [0, _selectionN] select (IS_SCALAR(_selectionN));
GVAR(displayPatientInformationTarget) = [ObjNull, _target] select _show;
if (_show) then {
if (_show == 1) then {
("ACE_MedicalRscDisplayInformation" call BIS_fnc_rscLayer) cutRsc [QGVAR(DisplayInformation),"PLAIN"];
[{
@ -94,10 +91,10 @@ if (_show) then {
// Collect the text to be displayed for this injury [ Select injury class type definition - select the classname DisplayName (6th), amount of injuries for this]
if (_amountOf >= 1) then {
// TODO localization
_allInjuryTexts pushback [format["%2x %1", (EGVAR(medical,AllWoundInjuryTypes) select _x1) select 6, ceil _amountOf], [1,1,1,1]];
_allInjuryTexts pushback [format["%2x %1", (EGVAR(medical_damage,woundsData) select _x1) select 6, ceil _amountOf], [1,1,1,1]];
} else {
// TODO localization
_allInjuryTexts pushback [format["Partial %1", (EGVAR(medical,AllWoundInjuryTypes) select _x1) select 6], [1,1,1,1]];
_allInjuryTexts pushback [format["Partial %1", (EGVAR(medical_damage,woundsData) select _x1) select 6], [1,1,1,1]];
};
};
};
@ -115,10 +112,10 @@ if (_show) then {
if (_amountOf > 0) then {
if (_amountOf >= 1) then {
// TODO localization
_allInjuryTexts pushback [format["[B] %2x %1", (EGVAR(medical,AllWoundInjuryTypes) select (_x select 1)) select 6, ceil _amountOf], [0.88,0.7,0.65,1]];
_allInjuryTexts pushback [format["[B] %2x %1", (EGVAR(medical_damage,woundsData) select (_x select 1)) select 6, ceil _amountOf], [0.88,0.7,0.65,1]];
} else {
// TODO localization
_allInjuryTexts pushback [format["[B] Partial %1", (EGVAR(medical,AllWoundInjuryTypes) select (_x select 1)) select 6], [0.88,0.7,0.65,1]];
_allInjuryTexts pushback [format["[B] Partial %1", (EGVAR(medical_damage,woundsData) select (_x select 1)) select 6], [0.88,0.7,0.65,1]];
};
};
};

View File

@ -74,8 +74,9 @@ private _bandagedInjury = [];
} forEach _bandagedWounds;
if !(_exist) then {
// [ID, classID, bodypart, percentage treated, bloodloss rate]
_bandagedInjury = [_injury select 0, _injury select 1, _injury select 2, _impact, _injury select 4];
// [ID, classID, bodypart, percentage treated, bloodloss, damage]
_bandagedInjury = +_injury;
_bandagedInjury set [3, _impact];
_bandagedWounds pushBack _bandagedInjury;
};

View File

@ -43,7 +43,7 @@ if (!_foundEntry) then {
private _usedMeds = _target getVariable [_variable, 0];
if (_usedMeds >= floor (_maxDosage + round(random(2))) && _maxDosage >= 1 && GVAR(enableOverdosing)) then {
if (_usedMeds >= floor (_maxDosage + round(random(2))) && _maxDosage >= 1) then {
[_target] call EFUNC(medical,setDead);
};
@ -58,7 +58,7 @@ private _hasOverDosed = 0;
} forEach _allUsedMedication;
} forEach _incompatabileMeds;
if (_hasOverDosed > 0 && GVAR(enableOverdosing)) then {
if (_hasOverDosed > 0) then {
private _medicationConfig = (configFile >> "ace_medical_treatment" >> "Medication");
private _onOverDose = getText (_medicationConfig >> "onOverDose");
if (isClass (_medicationConfig >> _className)) then {

View File

@ -156,6 +156,8 @@ if (isNumber (_config >> "treatmentTime")) then {
};
TRACE_1("",_treatmentTime);
if (_treatmentTime == 0) exitWith { false };
// speed up animation depending on treatment time
if (!isNil "_animDuration") then {
[QEGVAR(common,setAnimSpeedCoef), [_caller, _animDuration / _treatmentTime]] call CBA_fnc_globalEvent;

View File

@ -99,96 +99,9 @@ _openWounds set [_mostEffectiveSpot, _mostEffectiveInjury];
_target setVariable [QEGVAR(medical,openWounds), _openWounds, true];
[_target, _bodyPart] call EFUNC(medical_engine,updateBodyPartVisuals);
// Handle the reopening of bandaged wounds
if (_impact > 0 && {EGVAR(medical,level) >= 2} && {EGVAR(medical,enableAdvancedWounds)}) then {
if (_impact > 0 && {EGVAR(medical,enableAdvancedWounds)}) then {
[_target, _impact, _partIndex, _mostEffectiveSpot, _mostEffectiveInjury, _bandage] call FUNC(handleBandageOpening);
};
// If all wounds to a body part have been bandaged, reset damage to that body part to zero
// so that the body part functions normally and blood is removed from the uniform.
// Arma combines left and right arms into a single body part (HitHands), same with left and right legs (HitLegs).
// Arms are actually hands.
if (EGVAR(medical,healHitPointAfterAdvBandage) || {EGVAR(medical,level) < 2}) then {
// Get the list of the wounds the target is currently suffering from.
private _currentWounds = _target getVariable [QEGVAR(medical,openWounds), []];
// Tally of unbandaged wounds to each body part.
private _headWounds = 0;
private _bodyWounds = 0;
private _leftArmWounds = 0;
private _leftLegWounds = 0;
private _rightArmWounds = 0;
private _rightLegWounds = 0;
// Loop through all current wounds and add up the number of unbandaged wounds on each body part.
{
_x params ["", "", "_partIndex", "_numOpenWounds", "_bloodLoss"];
// Use switch/case for early termination if wounded limb is found before all six are checked.
// Number of wounds multiplied by blood loss will return zero for a fully
// bandaged body part, not incrementing the wound counter; or it will return
// some other number which will increment the wound counter.
switch (_partIndex) do {
// Head
case 0: {
_headWounds = _headWounds + (_numOpenWounds * _bloodLoss);
};
// Body
case 1: {
_bodyWounds = _bodyWounds + (_numOpenWounds * _bloodLoss);
};
// Left Arm
case 2: {
_leftArmWounds = _leftArmWounds + (_numOpenWounds * _bloodLoss);
};
// Right Arm
case 3: {
_rightArmWounds = _rightArmWounds + (_numOpenWounds * _bloodLoss);
};
// Left Leg
case 4: {
_leftLegWounds = _leftLegWounds + (_numOpenWounds * _bloodLoss);
};
// Right Leg
case 5: {
_rightLegWounds = _rightLegWounds + (_numOpenWounds * _bloodLoss);
};
};
} forEach _currentWounds;
// ["Head", "Body", "LeftArm", "RightArm", "LeftLeg", "RightLeg"]
private _bodyStatus = _target getVariable [QEGVAR(medical,bodyPartStatus), [0,0,0,0,0,0]];
// Any body part that has no wounds is healed to full health
if (_headWounds == 0) then {
_bodyStatus set [0, 0];
};
if (_bodyWounds == 0) then {
_bodyStatus set [1, 0];
};
if (_leftArmWounds == 0) then {
_bodyStatus set [2, 0];
};
if (_rightArmWounds == 0) then {
_bodyStatus set [3, 0];
};
if (_leftLegWounds == 0) then {
_bodyStatus set [4, 0];
};
if (_rightLegWounds == 0) then {
_bodyStatus set [5, 0];
};
_target setVariable [QEGVAR(medical,bodyPartStatus), _bodyStatus, true];
//[_target] call EFUNC(medical_damage,setDamage);
};
true

View File

@ -24,10 +24,11 @@ if (_target getVariable [QEGVAR(medical,inReviveState), false]) then {
};
};
if (EGVAR(medical,level) > 1 && {(random 1) >= 0.6}) then {
if ({(random 1) >= 0.6) then {
_target setVariable [QEGVAR(medical,inCardiacArrest), nil,true];
_target setVariable [QEGVAR(medical,heartRate), 40];
_target setVariable [QEGVAR(medical,bloodPressure), [50,70]];
[QGVAR(CPRSucceeded), _target] call CBA_fnc_localEvent;
};
[_target, "activity", ELSTRING(medical,Activity_CPR), [[_caller, false, true] call EFUNC(common,getName)]] call FUNC(addToLog);

View File

@ -15,7 +15,42 @@
params ["_caller", "_target"];
if (alive _target) exitWith {
if (!alive _target) exitWith {};
private _fullHealLocation = EGVAR(medical,fullHealLocation_PAK);
private _partialHeal = _fullHealLocation > 0; // Full heal not everywhere
if (_partialHeal) then {
private _medFacility = ([_caller] call EFUNC(medical,isInMedicalFacility)) || {[_target] call EFUNC(medical,isInMedicalFacility)};
private _medVeh = ([_caller] call EFUNC(medical,isInMedicalVehicle)) || {[_target] call EFUNC(medical,isInMedicalVehicle)};
switch (_fullHealLocation) do {
case 1: { _partialHeal = !_medFacility; };
case 2: { _partialHeal = !_medVeh; };
case 3: { _partialHeal = !_medFacility && {!_medVeh}; };
};
};
if (_partialHeal) then {
private _partialHealCounter = _target getVariable [QGVAR(partialHealCounter), 0];
_partialHealCounter = _partialHealCounter + 1;
_target setVariable [QGVAR(partialHealCounter), _partialHealCounter, true];
private _effectiveness = (0 max EGVAR(medical,fieldEffectiveness_PAK) min 1) ^ _partialHealCounter;
private _persistentDamage = 1 - _effectiveness;
private _openWounds = _target getVariable [QEGVAR(medical,openWounds), []];
private _bandagedWounds = _target getVariable [QEGVAR(medical,bandagedWounds), []];
private _stitchedWounds = _target getVariable [QEGVAR(medical,stitchedWounds), []];
{
_x params ["", "", "", "", "_bleeding", "_damage"];
_x set [6, _damage min _persistentDamage];
} forEach (_openWounds + _bandagedWounds + _stitchedWounds);
// todo: only reset limping if leg damage was reduced enough
[_unit, false] call EFUNC(medical_engine,setLimping);
_target setDamage ((damage _target) min _persistentDamage);
} else {
_target setVariable [QEGVAR(medical,pain), 0, true];
_target setVariable [QEGVAR(medical,morphine), 0, true];
_target setVariable [QEGVAR(medical,bloodVolume), DEFAULT_BLOOD_VOLUME, true];
@ -26,7 +61,7 @@ if (alive _target) exitWith {
// wounds and injuries
_target setVariable [QEGVAR(medical,openWounds), [], true];
_target setVariable [QEGVAR(medical,bandagedWounds), [], true];
_target setVariable [QEGVAR(medical,internalWounds), [], true];
_target setVariable [QEGVAR(medical,stitchedWounds), [], true];
// vitals
_target setVariable [QEGVAR(medical,heartRate), 80];
@ -34,30 +69,22 @@ if (alive _target) exitWith {
_target setVariable [QEGVAR(medical,bloodPressure), [80, 120]];
_target setVariable [QEGVAR(medical,peripheralResistance), 100];
// fractures
_target setVariable [QEGVAR(medical,fractures), []];
// IVs
_target setVariable [QEGVAR(medical,ivBags), nil, true];
// damage storage
_target setVariable [QEGVAR(medical,bodyPartStatus), [0,0,0,0,0,0], true];
// airway
_target setVariable [QEGVAR(medical,airwayStatus), 100, true];
_target setVariable [QEGVAR(medical,airwayOccluded), false, true];
_target setVariable [QEGVAR(medical,airwayCollapsed), false, true];
// generic medical admin
_target setVariable [QEGVAR(medical,addedToUnitLoop), false, true];
_target setVariable [QEGVAR(medical,inCardiacArrest), false, true];
_target setVariable [QEGVAR(medical,inReviveState), false, true];
_target setVariable ["ACE_isUnconscious", false, true];
_target setVariable [QEGVAR(medical,isUnconscious), false, true];
_target setVariable [QEGVAR(medical,hasLostBlood), 0, true];
_target setVariable [QEGVAR(medical,isBleeding), false, true];
_target setVariable [QEGVAR(medical,hasPain), false, true];
_target setVariable [QEGVAR(medical,painSuppress), 0, true];
_target setVariable [QGVAR(partialHealCounter), 0, true];
// medication
private _allUsedMedication = _target getVariable [QEGVAR(medical,allUsedMedication), []];
@ -65,9 +92,13 @@ if (alive _target) exitWith {
_target setVariable [_x select 0, nil];
} forEach _allUsedMedication;
[_unit, false] call EFUNC(medical_engine,setLimping);
// Resetting damage
_target setDamage 0;
[_target, "activity", ELSTRING(medical,Activity_fullHeal), [[_caller, false, true] call EFUNC(common,getName)]] call FUNC(addToLog);
[_target, "activity_view", ELSTRING(medical,Activity_fullHeal), [[_caller, false, true] call EFUNC(common,getName)]] call FUNC(addToLog); // TODO expand message
};
[QEGVAR(medical,FullHeal), _target] call CBA_fnc_localEvent;
[_target, "activity", ELSTRING(medical,Activity_fullHeal), [[_caller, false, true] call EFUNC(common,getName)]] call FUNC(addToLog);
[_target, "activity_view", ELSTRING(medical,Activity_fullHeal), [[_caller, false, true] call EFUNC(common,getName)]] call FUNC(addToLog); // TODO expand message

View File

@ -32,7 +32,7 @@ if !(EGVAR(medical,advancedMedication)) exitWith {
};
if (_className == "Epinephrine") exitWith {
[_target, false] call EFUNC(medical,setUnconscious);
[QEGVAR(medical,WakeUp), _target] call CBA_fnc_localEvent;
};
};

View File

@ -20,14 +20,17 @@ params ["_args", "_elapsedTime", "_totalTime"];
_args params ["_caller", "_target"];
private _bandagedWounds = _target getVariable [QEGVAR(medical,bandagedWounds), []];
private _stitchedWounds = _target getVariable [QEGVAR(medical,stitchedWounds), []];
//In case two people stitch up one patient and the last wound has already been closed we can stop already
if (count _bandagedWounds == 0) exitWith { false };
//Has enough time elapsed that we can close another wound?
if (_totalTime - _elapsedTime <= (count _bandagedWounds - 1) * 5) then {
_bandagedWounds deleteAt 0;
private _treatedWound = _bandagedWounds deleteAt 0;
_stitchedWounds pushBack _treatedWound;
_target setVariable [QEGVAR(medical,bandagedWounds), _bandagedWounds, true];
_target setVariable [QEGVAR(medical,stitchedWounds), _stitchedWounds, true];
};
true

View File

@ -16,9 +16,6 @@
params ["_target", "_tourniquetItem", "_bodyPart"];
//If we're not already tracking vitals, start:
[_target] call EFUNC(medical,addVitalLoop);
private _partIndex = ALL_BODY_PARTS find toLower _bodyPart;
// Place a tourniquet on the bodypart

View File

@ -68,9 +68,4 @@ _args call _callback;
_args pushBack _bloodLossOnBodyPart;
_args call FUNC(litterCreate);
//If we're not already tracking vitals, start:
if !(_target getVariable [QGVAR(addedToUnitLoop),false]) then {
[_target] call FUNC(addVitalLoop);
};
["ace_treatmentSucceded", [_caller, _target, _bodyPart, _className]] call CBA_fnc_localEvent;