blood and unconsciousness fixes

This commit is contained in:
commy2 2016-10-12 21:59:32 +02:00
parent be71e6fa7b
commit a5d070f829
11 changed files with 93 additions and 82 deletions

View File

@ -257,11 +257,6 @@ class ACE_Settings {
typeName = "BOOL"; typeName = "BOOL";
value = 0; value = 0;
}; };
class GVAR(moveUnitsFromGroupOnUnconscious) {
category = CSTRING(Category_Medical);
typeName = "BOOL";
value = 0;
};
class GVAR(menuTypeStyle) { class GVAR(menuTypeStyle) {
category = CSTRING(Category_Medical); category = CSTRING(Category_Medical);
displayName = CSTRING(menuTypeDisplay); displayName = CSTRING(menuTypeDisplay);

View File

@ -10,19 +10,17 @@
* *
* Public: No * Public: No
*/ */
#include "script_component.hpp" #include "script_component.hpp"
// TODO Only use this calculation if medium or higher, otherwise use vanilla calculations (for basic medical).
params ["_unit"]; params ["_unit"];
private _totalBloodLoss = 0; private _totalBloodLoss = 0;
private _tourniquets = _unit getVariable [QGVAR(tourniquets), [0,0,0,0,0,0]]; private _tourniquets = _unit getVariable [QGVAR(tourniquets), [0,0,0,0,0,0]];
{ {
if ((_tourniquets select (_x select 2)) == 0) then { if (_tourniquets select (_x select 2) == 0) then {
// total bleeding ratio * percentage of injury left // total bleeding ratio * percentage of injury left
_totalBloodLoss = _totalBloodLoss + ((_x select 4) * (_x select 3)); _totalBloodLoss = _totalBloodLoss + ((_x select 4) * (_x select 3));
// (((BLOODLOSS_SMALL_WOUNDS * (_x select 0))) + ((BLOODLOSS_MEDIUM_WOUNDS * (_x select 1))) + ((BLOODLOSS_LARGE_WOUNDS * (_x select 2))) * (_cardiacOutput / DEFAULT_CARDIAC_OUTPUT));
}; };
} forEach (_unit getVariable [QGVAR(openWounds), []]); } forEach (_unit getVariable [QGVAR(openWounds), []]);

View File

@ -11,29 +11,33 @@
* *
* Public: No * Public: No
*/ */
#include "script_component.hpp" #include "script_component.hpp"
params ["_unit", "_syncValues"]; params ["_unit", "_syncValues"];
private _bloodVolume = _unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME]; private _bloodVolume = _unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME];
private _bloodVolumeChange = -([_unit] call FUNC(getBloodLoss)); private _bloodVolumeChange = -(_unit call FUNC(getBloodLoss));
if (!isNil {_unit getVariable QGVAR(ivBags)}) then { if (!isNil {_unit getVariable QGVAR(ivBags)}) then {
if (_bloodVolume < 100) then { if (_bloodVolume < DEFAULT_BLOOD_VOLUME) then {
private _bloodBags = _unit getVariable [QGVAR(ivBags), []]; private _bloodBags = _unit getVariable [QGVAR(ivBags), []];
_bloodBags = _bloodBags apply { _bloodBags = _bloodBags apply {
_x params ["_bagVolumeRemaining"]; _x params ["_bagVolumeRemaining"];
private _bagChange = IV_CHANGE_PER_SECOND min _bagVolumeRemaining; // absolute value of the change in miliLiters private _bagChange = IV_CHANGE_PER_SECOND min _bagVolumeRemaining; // absolute value of the change in miliLiters
_bagVolumeRemaining = _bagVolumeRemaining - _bagChange; _bagVolumeRemaining = _bagVolumeRemaining - _bagChange;
_bloodVolumeChange = _bloodVolumeChange + _bagChange; _bloodVolumeChange = _bloodVolumeChange + (_bagChange / 1000);
if (_bagVolumeRemaining < 0.01) then { if (_bagVolumeRemaining < 0.01) then {
[] []
} else { } else {
[_bagVolumeRemaining]; [_bagVolumeRemaining];
}; };
}; };
_bloodBags = _bloodBags - [[]]; // remove empty bags _bloodBags = _bloodBags - [[]]; // remove empty bags
if (_bloodBags isEqualTo []) then { if (_bloodBags isEqualTo []) then {
_unit setVariable [QGVAR(ivBags), nil, true]; // no bags left - clear variable (always globaly sync this) _unit setVariable [QGVAR(ivBags), nil, true]; // no bags left - clear variable (always globaly sync this)
} else { } else {
@ -44,4 +48,4 @@ if (!isNil {_unit getVariable QGVAR(ivBags)}) then {
}; };
}; };
_bloodVolumeChange; _bloodVolumeChange

View File

@ -14,16 +14,18 @@
params ["_unit", "_interval"]; params ["_unit", "_interval"];
TRACE_3("ACE_DEBUG",_unit,_interval,_unit); TRACE_3("ACE_DEBUG",_unit,_interval,_unit);
if (_interval == 0) exitWith {}; if (_interval == 0) exitWith {};
private _lastTimeValuesSynced = _unit getVariable [QGVAR(lastMomentValuesSynced), 0]; 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))) && GVAR(keepLocalSettingsSynced);
if (_syncValues) then { if (_syncValues) then {
_unit setVariable [QGVAR(lastMomentValuesSynced), CBA_missionTime]; _unit setVariable [QGVAR(lastMomentValuesSynced), CBA_missionTime];
}; };
private _bloodVolume = (_unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME]) + ([_unit, _syncValues] call FUNC(getBloodVolumeChange)); private _bloodVolume = (_unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME]) + ([_unit, _syncValues] call FUNC(getBloodVolumeChange));
_bloodVolume = _bloodVolume max 0; _bloodVolume = (_bloodVolume max 0) min DEFAULT_BLOOD_VOLUME;
_unit setVariable [QGVAR(bloodVolume), _bloodVolume, _syncValues]; _unit setVariable [QGVAR(bloodVolume), _bloodVolume, _syncValues];
@ -45,12 +47,13 @@ if (_bloodVolume < BLOOD_VOLUME_HAS_LOST_SOME) then {
}; };
}; };
TRACE_3("ACE_DEBUG",[_unit] call FUNC(getBloodLoss),_unit getVariable QGVAR(isBleeding),_unit); private _bloodLoss = _unit call FUNC(getBloodLoss);
private _bloodLoss = [_unit] call FUNC(getBloodLoss); TRACE_3("ACE_DEBUG",_bloodLoss,_unit getVariable QGVAR(isBleeding),_unit);
if (_bloodLoss > 0) then { if (_bloodLoss > 0) then {
_unit setVariable [QGVAR(bloodloss), _bloodLoss, _syncValues]; _unit setVariable [QGVAR(bloodloss), _bloodLoss, _syncValues];
[_unit, "TakenInjury"] call FUNC(stateEvent); [_unit, "TakenInjury"] call FUNC(stateEvent);
if !(_unit getVariable [QGVAR(isBleeding), false]) then { if !(_unit getVariable [QGVAR(isBleeding), false]) then {
_unit setVariable [QGVAR(isBleeding), true, true]; _unit setVariable [QGVAR(isBleeding), true, true];
}; };
@ -77,13 +80,12 @@ if (_bloodVolume < BLOOD_VOLUME_DEAD) exitWith {
}; };
if ([_unit] call EFUNC(common,isAwake)) then { if ([_unit] call EFUNC(common,isAwake)) then {
if (_bloodVolume < BLOOD_VOLUME_UNCONSCIOUS) then { if (_bloodVolume < BLOOD_VOLUME_UNCONSCIOUS && {random 1 < BLOOD_LOSS_KNOCK_OUT_CHANCE}) exitWith {
if (random(1) > 0.9) then { [_unit, true, BLOOD_LOSS_KNOCK_OUT_DURATION] call FUNC(setUnconscious);
[_unit, true, 15 + random(20)] call FUNC(setUnconscious);
};
}; };
}; };
/*
if (GVAR(level) == 1) then { if (GVAR(level) == 1) then {
TRACE_5("ACE_DEBUG_BASIC_VITALS",_painStatus,_unit getVariable QGVAR(hasPain),_unit getVariable QGVAR(morphine),_syncValues,_unit); TRACE_5("ACE_DEBUG_BASIC_VITALS",_painStatus,_unit getVariable QGVAR(hasPain),_unit getVariable QGVAR(morphine),_syncValues,_unit);
// reduce pain // reduce pain
@ -96,8 +98,10 @@ if (GVAR(level) == 1) then {
_unit setVariable [QGVAR(morphine), ((_unit getVariable [QGVAR(morphine), 0]) - 0.0015 * _interval) max 0, _syncValues]; _unit setVariable [QGVAR(morphine), ((_unit getVariable [QGVAR(morphine), 0]) - 0.0015 * _interval) max 0, _syncValues];
}; };
}; };
*/
// handle advanced medical, with vitals // handle advanced medical, with vitals
/*
if (GVAR(level) >= 2) then { if (GVAR(level) >= 2) then {
TRACE_6("ACE_DEBUG_ADVANCED_VITALS",_painStatus,_bloodVolume, _unit getVariable QGVAR(hasPain),_unit getVariable QGVAR(morphine),_syncValues,_unit); TRACE_6("ACE_DEBUG_ADVANCED_VITALS",_painStatus,_bloodVolume, _unit getVariable QGVAR(hasPain),_unit getVariable QGVAR(morphine),_syncValues,_unit);
@ -142,3 +146,4 @@ if (GVAR(level) >= 2) then {
}; };
}; };
}; };
*/

View File

@ -9,7 +9,7 @@
* 3: Force AI Unconscious (skip random death chance) <BOOL> (default: false) * 3: Force AI Unconscious (skip random death chance) <BOOL> (default: false)
* *
* ReturnValue: * ReturnValue:
* nil * Success? <BOOLEAN>
* *
* Example: * Example:
* [bob, true] call ace_medical_fnc_setUnconscious; * [bob, true] call ace_medical_fnc_setUnconscious;
@ -19,36 +19,43 @@
#include "script_component.hpp" #include "script_component.hpp"
#define DEFAULT_DELAY (round(random(10)+5))
// only run this after the settings are initialized // only run this after the settings are initialized
if !(EGVAR(common,settingsInitFinished)) exitWith { if !(EGVAR(common,settingsInitFinished)) exitWith {
EGVAR(common,runAtSettingsInitialized) pushBack [FUNC(setUnconscious), _this]; EGVAR(common,runAtSettingsInitialized) pushBack [FUNC(setUnconscious), _this];
}; };
params ["_unit", ["_set", true], ["_minUnconsciousTime", DEFAULT_DELAY], ["_force", false]]; params ["_unit", ["_knockOut", true], ["_minUnconsciousTime", DEFAULT_KNOCK_OUT_DELAY], ["_force", false]];
if (_set isEqualTo (_unit getVariable ["ACE_isUnconscious", false])) exitWith {}; if (isNull _unit || {!(_unit isKindOf "CAManBase")}) exitWith {false};
if !(_set) exitWith { if (!local _unit) exitWith {
_unit setVariable ["ACE_isUnconscious", false, true]; [QGVAR(setUnconscious), [_unit, _knockOut, _minUnconsciousTime, _force], _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
if !(_knockOut) exitWith {
_unit setVariable [QGVAR(isUnconscious), false, true];
if (_unit getVariable [QGVAR(inReviveState), false]) then { if (_unit getVariable [QGVAR(inReviveState), false]) then {
_unit setVariable [QGVAR(inReviveState), nil, true]; _unit setVariable [QGVAR(inReviveState), nil, true];
}; };
[_unit, false] call EFUNC(medical_engine,setUnconsciousAnim); [_unit, false] call EFUNC(medical_engine,setUnconsciousAnim);
["ace_unconscious", [_unit, false]] call CBA_fnc_globalEvent; ["ace_unconscious", [_unit, false]] call CBA_fnc_globalEvent;
true
}; };
if (isNull _unit || {!(_unit isKindOf "CAManBase")}) exitWith {}; // --- knock out
_unit setVariable [QGVAR(isUnconscious), true, true];
if (!local _unit) exitWith {
[QGVAR(setUnconscious), [_unit, _set, _minUnconsciousTime, _force], _unit] call CBA_fnc_targetEvent;
};
_unit setVariable ["ACE_isUnconscious", true, true];
if (_unit == ACE_player) then { if (_unit == ACE_player) then {
if (visibleMap) then {openMap false}; if (visibleMap) then {openMap false};
@ -59,6 +66,7 @@ if (_unit == ACE_player) then {
}; };
// if we have unconsciousness for AI disabled, we will kill the unit instead // if we have unconsciousness for AI disabled, we will kill the unit instead
/*
private _isDead = false; private _isDead = false;
if (!([_unit, GVAR(remoteControlledAI)] call EFUNC(common,isPlayer)) && !_force) then { if (!([_unit, GVAR(remoteControlledAI)] call EFUNC(common,isPlayer)) && !_force) then {
@ -71,37 +79,25 @@ if (!([_unit, GVAR(remoteControlledAI)] call EFUNC(common,isPlayer)) && !_force)
}; };
if (_isDead) exitWith {}; if (_isDead) exitWith {};
*/
// So the AI does not get stuck, we are moving the unit to a temp group on its own. [_unit, true] call EFUNC(medical_engine,setUnconsciousAnim);
// Unconscious units shouldn't be put in another group #527: [_unit, "Unconscious", []] call FUNC(stateEvent);
if (GVAR(moveUnitsFromGroupOnUnconscious)) then { ["ace_unconscious", [_unit, true]] call CBA_fnc_globalEvent;
[_unit, true, "ACE_isUnconscious", side group _unit] call EFUNC(common,switchToGroupSide);
};
// Delay Unconscious so the AI dont instant stop shooting on the unit #3121 // auto wake up
[{ [{
params ["_unit"]; params ["_unit"];
if (_unit getVariable ["ACE_isUnconscious", false]) then { private _time = _unit getVariable [QGVAR(wakeUpTime), 0];
[_unit, "setCaptive", "ace_unconscious", true] call EFUNC(common,statusEffect_set);
};
}, _unit, 3] call CBA_fnc_waitAndExecute;
[_unit, true] call EFUNC(medical_engine,setUnconsciousAnim); !(_unit getVariable [QGVAR(isUnconscious), false]) || {CBA_missionTime > _time}
[_unit, "Unconscious", []] call FUNC(stateEvent);
["ace_unconscious", [_unit, true]] call CBA_fnc_globalEvent;
// auto wake up, testing @todo
[{
params ["_unit", "_time"];
!(_unit getVariable ["ACE_isUnconscious", false]) || {CBA_missionTime > _time}
}, { }, {
params ["_unit"]; params ["_unit"];
if (_unit getVariable ["ACE_isUnconscious", false]) then { if (_unit getVariable [QGVAR(isUnconscious), false]) then {
[_unit, false] call FUNC(setUnconscious); [_unit, false] call FUNC(setUnconscious);
}; };
}, [_unit, CBA_missionTime + _minUnconsciousTime]] call CBA_fnc_waitUntilAndExecute; }, _unit] call CBA_fnc_waitUntilAndExecute;
true

View File

@ -19,14 +19,22 @@
// 0.077 l/kg * 80kg = 6.16l // 0.077 l/kg * 80kg = 6.16l
#define DEFAULT_BLOOD_VOLUME 6.0 // in liters #define DEFAULT_BLOOD_VOLUME 6.0 // in liters
#define BLOOD_VOLUME_HAS_LOST_SOME 5.900 // lost 100ml #define BLOOD_VOLUME_HAS_LOST_SOME 5.700 // lost 5% blood, Class I Hemorrhage
#define BLOOD_VOLUME_HAS_LOST_MUCH 5.500 // lost 500ml #define BLOOD_VOLUME_HAS_LOST_MUCH 5.100 // lost 15% blood, Class II Hemorrhage
#define BLOOD_VOLUME_UNCONSCIOUS 3.6 // in liters #define BLOOD_VOLUME_UNCONSCIOUS 4.200 // lost 30% blood, Class III Hemorrhage
#define BLOOD_VOLUME_DEAD 1.8 // in liters #define BLOOD_VOLUME_DEAD 3.600 // lost 40% blood, Class IV Hemorrhage
#define BLOOD_VOLUME_CARDIAC_ARREST 1.2 // in liters #define BLOOD_VOLUME_CARDIAC_ARREST 1.2 // TBD
// IV Change per second calculation: // IV Change per second calculation:
// 250ml should take 60 seconds to fill. 250/60 = 4.166. // 250ml should take 60 seconds to fill. 250ml/60s = 4.166ml/s.
// Basic medical is 10x (will take 6 seconds for 250ml) #define IV_CHANGE_PER_SECOND 4.166 // in milliliters per second
#define IV_CHANGE_PER_SECOND ([41.66, 4.166] select (GVAR(level) >= 2))
// chance per second to get knocked out due to blood loss
#define BLOOD_LOSS_KNOCK_OUT_CHANCE 0.1 // 10%
// 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)

View File

@ -50,6 +50,6 @@ if (_isUnconscious) then {
if (animationState _unit == "unconscious" && {lifeState _unit != "INCAPACITATED"}) then { if (animationState _unit == "unconscious" && {lifeState _unit != "INCAPACITATED"}) then {
[_unit, "AmovPpneMstpSnonWnonDnon", 2] call EFUNC(common,doAnimation); [_unit, "AmovPpneMstpSnonWnonDnon", 2] call EFUNC(common,doAnimation);
}; };
}, _unit] call CBA_fnc_execNextFrame; }, _unit, 0.5] call CBA_fnc_waitAndExecute;
}; };
}; };

View File

@ -1,5 +1,5 @@
class ACE_Medical_Treatment { class ADDON {
class Bandaging { class Bandaging {
// Field dressing is normal average treatment // Field dressing is normal average treatment
// packing bandage is average treatment, higher reopen change, longer reopening delay // packing bandage is average treatment, higher reopen change, longer reopening delay

View File

@ -54,7 +54,7 @@ class GVAR(Actions) {
treatmentLocations[] = {QGVAR(useLocation_basicEpi)}; treatmentLocations[] = {QGVAR(useLocation_basicEpi)};
}; };
class BloodIV: Bandage { class BloodIV: Bandage {
displayName = ECSTRING(medical,Transfuse_Blood); displayName = ECSTRING(medical,Actions_Blood4_1000);
displayNameProgress = ECSTRING(medical,Transfusing_Blood); displayNameProgress = ECSTRING(medical,Transfusing_Blood);
allowedSelections[] = {"LeftArm", "RightArm", "LeftLeg", "RightLeg"}; allowedSelections[] = {"LeftArm", "RightArm", "LeftLeg", "RightLeg"};
allowSelfTreatment = 0; allowSelfTreatment = 0;
@ -62,17 +62,16 @@ class GVAR(Actions) {
requiredMedic = 1; requiredMedic = 1;
treatmentTime = 12; treatmentTime = 12;
items[] = {"ACE_bloodIV"}; items[] = {"ACE_bloodIV"};
callbackSuccess = QFUNC(treatmentBloodbag); callbackSuccess = QFUNC(treatmentIV);
// callbackSuccess = QFUNC(treatmentIV);
animationCaller = "AinvPknlMstpSnonWnonDnon_medic1"; animationCaller = "AinvPknlMstpSnonWnonDnon_medic1";
litter[] = {}; litter[] = {};
}; };
class BloodIV_500: BloodIV { class BloodIV_500: BloodIV {
category = "advanced"; displayName = ECSTRING(medical,Actions_Blood4_500);
items[] = {"ACE_bloodIV_500"}; items[] = {"ACE_bloodIV_500"};
}; };
class BloodIV_250: BloodIV { class BloodIV_250: BloodIV {
category = "advanced"; displayName = ECSTRING(medical,Actions_Blood4_250);
items[] = {"ACE_bloodIV_250"}; items[] = {"ACE_bloodIV_250"};
}; };
class BodyBag: Bandage { class BodyBag: Bandage {

View File

@ -12,7 +12,6 @@ if (isServer) then {
[QGVAR(treatmentMorphineLocal), FUNC(treatmentMorphineLocal)] call CBA_fnc_addEventHandler; [QGVAR(treatmentMorphineLocal), FUNC(treatmentMorphineLocal)] call CBA_fnc_addEventHandler;
//[QGVAR(treatmentEpipenLocal), FUNC(treatmentEpipenLocal)] call CBA_fnc_addEventHandler; //[QGVAR(treatmentEpipenLocal), FUNC(treatmentEpipenLocal)] call CBA_fnc_addEventHandler;
[QGVAR(treatmentMedicationLocal), FUNC(treatmentMedicationLocal)] call CBA_fnc_addEventHandler; [QGVAR(treatmentMedicationLocal), FUNC(treatmentMedicationLocal)] call CBA_fnc_addEventHandler;
[QGVAR(treatmentBloodbagLocal), FUNC(treatmentBloodbagLocal)] call CBA_fnc_addEventHandler;
[QGVAR(treatmentIVLocal), FUNC(treatmentIVLocal)] call CBA_fnc_addEventHandler; [QGVAR(treatmentIVLocal), FUNC(treatmentIVLocal)] call CBA_fnc_addEventHandler;
[QGVAR(treatmentCPRLocal), FUNC(treatmentCPRLocal)] call CBA_fnc_addEventHandler; [QGVAR(treatmentCPRLocal), FUNC(treatmentCPRLocal)] call CBA_fnc_addEventHandler;
[QGVAR(treatmentFullHealLocal), FUNC(treatmentFullHealLocal)] call CBA_fnc_addEventHandler; [QGVAR(treatmentFullHealLocal), FUNC(treatmentFullHealLocal)] call CBA_fnc_addEventHandler;

View File

@ -22,18 +22,25 @@ private _bloodVolume = _target getVariable [QEGVAR(medical,bloodVolume), DEFAULT
if (_bloodVolume >= DEFAULT_BLOOD_VOLUME) exitWith {}; if (_bloodVolume >= DEFAULT_BLOOD_VOLUME) exitWith {};
// Find the proper attributes for the used IV // Find the proper attributes for the used IV
private _config = (configFile >> "ace_medical_treatment" >> "IV"); private _config = configFile >> QUOTE(ADDON) >> "IV";
private _volumeAdded = getNumber (_config >> "volume"); private _volumeAdded = getNumber (_config >> "volume");
private _typeOf = getText (_config >> "type"); private _type = getText (_config >> "type");
if (isClass (_config >> _treatmentClassname)) then { if (isClass (_config >> _treatmentClassname)) then {
_config = (_config >> _treatmentClassname); _config = _config >> _treatmentClassname;
if (isNumber (_config >> "volume")) then { _volumeAdded = getNumber (_config >> "volume");};
if (isText (_config >> "type")) then { _typeOf = getText (_config >> "type"); }; if (isNumber (_config >> "volume")) then {
_volumeAdded = getNumber (_config >> "volume");
};
if (isText (_config >> "type")) then {
_type = getText (_config >> "type");
};
} else { } else {
ERROR("IV Treatment Classname not found"); ERROR("IV Treatment Classname not found");
}; };
private _bloodBags = _target getVariable [QEGVAR(medical,ivBags), []]; private _bloodBags = _target getVariable [QEGVAR(medical,ivBags), []];
_bloodBags pushBack [_volumeAdded]; // Future BagType: [_volumeAdded, _typeOf] _bloodBags pushBack [_volumeAdded]; // Future BagType: [_volumeAdded, _type]
_target setVariable [QEGVAR(medical,ivBags), _bloodBags, true]; _target setVariable [QEGVAR(medical,ivBags), _bloodBags, true];