Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Medical - Change medical to use hashmaps for wound storage #8926

Merged
merged 5 commits into from
Jun 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions addons/medical/dev/watchVariable.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -95,24 +95,33 @@ GVAR(dev_watchVariableRunning) = true;
_return pushBack "------- Open Wounds: -------";
private _wounds = GET_OPEN_WOUNDS(_unit);
{
_x params ["_xClassID", "_xBodyPartN", "_xAmountOf", "_xBleeding", "_xDamage"];
_return pushBack format ["%1: [%2] [x%3] [Bld: %4] [Dmg: %5]", ALL_SELECTIONS select _xBodyPartN, _xClassID, _xAmountOf toFixed 1, _xBleeding toFixed 4, _xDamage toFixed 2];
private _bodyPart = _x;
{
_x params ["_xClassID", "_xAmountOf", "_xBleeding", "_xDamage"];
_return pushBack format ["%1: [%2] [x%3] [Bld: %4] [Dmg: %5]", _bodyPart, _xClassID, _xAmountOf toFixed 1, _xBleeding toFixed 4, _xDamage toFixed 2];
} forEach _y;
} forEach _wounds;

// Bandaged Wounds:
_return pushBack "------- Bandaged Wounds: -------";
private _wounds = GET_BANDAGED_WOUNDS(_unit);
{
_x params ["_xClassID", "_xBodyPartN", "_xAmountOf", "_xBleeding", "_xDamage"];
_return pushBack format ["%1: [%2] [x%3] [Bld: %4] [Dmg: %5]", ALL_SELECTIONS select _xBodyPartN, _xClassID, _xAmountOf toFixed 1, _xBleeding toFixed 4, _xDamage toFixed 2];
private _bodyPart = _x;
{
_x params ["_xClassID", "_xAmountOf", "_xBleeding", "_xDamage"];
_return pushBack format ["%1: [%2] [x%3] [Bld: %4] [Dmg: %5]", _bodyPart, _xClassID, _xAmountOf toFixed 1, _xBleeding toFixed 4, _xDamage toFixed 2];
} forEach _y;
} forEach _wounds;

// Stitched Wounds:
_return pushBack "------- Stitched Wounds: -------";
private _wounds = GET_STITCHED_WOUNDS(_unit);
{
_x params ["_xClassID", "_xBodyPartN", "_xAmountOf", "_xBleeding", "_xDamage"];
_return pushBack format ["%1: [%2] [x%3] [Bld: %4] [Dmg: %5]", ALL_SELECTIONS select _xBodyPartN, _xClassID, _xAmountOf toFixed 1, _xBleeding toFixed 4, _xDamage toFixed 2];
private _bodyPart = _x;
{
_x params ["_xClassID", "_xAmountOf", "_xBleeding", "_xDamage"];
_return pushBack format ["%1: [%2] [x%3] [Bld: %4] [Dmg: %5]", _bodyPart, _xClassID, _xAmountOf toFixed 1, _xBleeding toFixed 4, _xDamage toFixed 2];
} forEach _y;
} forEach _wounds;

// IVs:
Expand Down
22 changes: 19 additions & 3 deletions addons/medical/functions/fnc_deserializeState.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,22 @@ if !(_unit getVariable [QGVAR(initialized), false]) exitWith {

private _state = [_json] call CBA_fnc_parseJSON;

// Migration from old array wounding storage serialized in old versions (<= 3.16.0)
{
if ((_state getVariable [_x, createHashMap]) isEqualType []) then {
private _migratedWounds = createHashMap;

{
_x params ["_class", "_bodyPartIndex", "_amountOf", "_bleeding", "_damage"];

private _partWounds = _migratedWounds getOrDefault [ALL_BODY_PARTS select _bodyPartIndex, [], true];
_partWounds pushBack [_class, _amountOf, _bleeding, _damage];
} forEach (_state getVariable _x);

_state setVariable [_x, _migratedWounds];
};
} forEach [VAR_OPEN_WOUNDS, VAR_BANDAGED_WOUNDS, VAR_STITCHED_WOUNDS];

// Set medical variables
{
_x params ["_var", "_default"];
Expand All @@ -57,9 +73,9 @@ private _state = [_json] call CBA_fnc_parseJSON;
[VAR_PAIN, 0],
[VAR_IN_PAIN, false],
[VAR_PAIN_SUPP, 0],
[VAR_OPEN_WOUNDS, []],
[VAR_BANDAGED_WOUNDS, []],
[VAR_STITCHED_WOUNDS, []],
[VAR_OPEN_WOUNDS, createHashMap],
[VAR_BANDAGED_WOUNDS, createHashMap],
[VAR_STITCHED_WOUNDS, createHashMap],
[VAR_FRACTURES, DEFAULT_FRACTURE_VALUES],
// State transition should handle this
// [VAR_UNCON, false],
Expand Down
6 changes: 3 additions & 3 deletions addons/medical/functions/fnc_serializeState.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ private _state = [] call CBA_fnc_createNamespace;
[VAR_PAIN, 0],
[VAR_IN_PAIN, false],
[VAR_PAIN_SUPP, 0],
[VAR_OPEN_WOUNDS, []],
[VAR_BANDAGED_WOUNDS, []],
[VAR_STITCHED_WOUNDS, []],
[VAR_OPEN_WOUNDS, createHashMap],
[VAR_BANDAGED_WOUNDS, createHashMap],
[VAR_STITCHED_WOUNDS, createHashMap],
[VAR_FRACTURES, DEFAULT_FRACTURE_VALUES],
// State transition should handle this
// [VAR_UNCON, false],
Expand Down
10 changes: 6 additions & 4 deletions addons/medical_ai/functions/fnc_healingLogic.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ private _treatmentTime = 6;
switch (true) do {
case (GET_WOUND_BLEEDING(_target) > 0): {
// Select first bleeding wound and bandage it
private _openWounds = GET_OPEN_WOUNDS(_target);
private _selection = "?";
{
_x params ["", "_index", "_amount", "_percentage"];
if ((_amount * _percentage) > 0) exitWith { _selection = ALL_BODY_PARTS select _index; };
} forEach _openWounds;
private _foundBleeding = _y findIf {
_x params ["", "_amount", "_percentage"];
(_amount * _percentage) > 0
};
if (_foundBleeding != -1) exitWith { _selection = _x; };
} forEach GET_OPEN_WOUNDS(_target);
_treatmentEvent = QEGVAR(medical_treatment,bandageLocal);
_treatmentTime = 5;
_treatmentArgs = [_target, _selection, "FieldDressing"];
Expand Down
6 changes: 3 additions & 3 deletions addons/medical_damage/functions/fnc_handleIncapacitation.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ _bodyPartDamage params ["_headDamage", "_bodyDamage", "_leftArmDamage", "_rightA

// Exclude non penetrating body damage
{
_x params ["", "_bodyPartN", "_amountOf", "", "_damage"];
if (_bodyPartN == 1 && {_damage < PENETRATION_THRESHOLD}) then {
_x params ["", "_amountOf", "", "_damage"];
if (_damage < PENETRATION_THRESHOLD) then {
_bodyDamage = _bodyDamage - (_amountOf * _damage);
};
} forEach GET_OPEN_WOUNDS(_unit);
} forEach (GET_OPEN_WOUNDS(_unit) getOrDefault ["body", []]);

private _damageThreshold = GET_DAMAGE_THRESHOLD(_unit);

Expand Down
29 changes: 15 additions & 14 deletions addons/medical_damage/functions/fnc_woundsHandlerBase.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,13 @@ private _bodyPartVisParams = [_unit, false, false, false, false]; // params arra
// process wounds separately for each body part hit
{ // forEach _allDamages
_x params ["_damage", "_bodyPart"];
_bodyPart = toLower _bodyPart;

// silently ignore structural damage
if (_bodyPart == "#structural") then {continue};

// Convert the selectionName to a number and ensure it is a valid selection.
private _bodyPartNToAdd = ALL_BODY_PARTS find toLower _bodyPart;
private _bodyPartNToAdd = ALL_BODY_PARTS find _bodyPart;
if (_bodyPartNToAdd < 0) then {
ERROR_1("invalid body part %1",_bodyPart);
continue
Expand Down Expand Up @@ -84,7 +85,7 @@ private _bodyPartVisParams = [_unit, false, false, false, false]; // params arra
};
GVAR(woundDetails) get _woundTypeToAdd params ["","_injuryBleedingRate","_injuryPain","_causeLimping","_causeFracture"];
private _woundClassIDToAdd = GVAR(woundClassNames) find _woundTypeToAdd;

// Add a bit of random variance to wounds
private _woundDamage = _dmgPerWound * _dmgMultiplier * random [0.9, 1, 1.1];

Expand All @@ -99,7 +100,7 @@ private _bodyPartVisParams = [_unit, false, false, false, false]; // params arra
// Config specifies bleeding and pain for worst possible wound
// Worse wound correlates to higher damage, damage is not capped at 1
private _woundSize = linearConversion [0.1, _worstDamage, _woundDamage * _sizeMultiplier, LARGE_WOUND_THRESHOLD^3, 1, true];

private _pain = _woundSize * _painMultiplier * _injuryPain;
_painLevel = _painLevel + _pain;

Expand All @@ -112,10 +113,10 @@ private _bodyPartVisParams = [_unit, false, false, false, false]; // params arra

private _classComplex = 10 * _woundClassIDToAdd + _category;

// Create a new injury. Format [0:classComplex, 1:bodypart, 2:amountOf, 3:bleedingRate, 4:woundDamage]
private _injury = [_classComplex, _bodyPartNToAdd, 1, _bleeding, _woundDamage];
// Create a new injury. Format [0:classComplex, 1:amountOf, 2:bleedingRate, 3:woundDamage]
private _injury = [_classComplex, 1, _bleeding, _woundDamage];

if (_bodyPartNToAdd == 0 || {_bodyPartNToAdd == 1 && {_woundDamage > PENETRATION_THRESHOLD}}) then {
if (_bodyPart isEqualTo "head" || {_bodyPart isEqualTo "body" && {_woundDamage > PENETRATION_THRESHOLD}}) then {
_criticalDamage = true;
};
if ([_unit, _bodyPartNToAdd, _bodyPartDamage, _woundDamage] call FUNC(determineIfFatal)) then {
Expand Down Expand Up @@ -158,28 +159,28 @@ private _bodyPartVisParams = [_unit, false, false, false, false]; // params arra

// if possible merge into existing wounds
private _createNewWound = true;
private _existingWounds = _openWounds getOrDefault [_bodyPart, [], true];
{
_x params ["_classID", "_bodyPartN", "_oldAmountOf", "_oldBleeding", "_oldDamage"];
_x params ["_classID", "_oldAmountOf", "_oldBleeding", "_oldDamage"];
if (
(_classComplex == _classID) &&
{_bodyPartNToAdd == _bodyPartN} &&
{(_bodyPartNToAdd != 1) || {(_woundDamage < PENETRATION_THRESHOLD) isEqualTo (_oldDamage < PENETRATION_THRESHOLD)}} && // penetrating body damage is handled differently
{(_bodyPart isNotEqualTo "body") || {(_woundDamage < PENETRATION_THRESHOLD) isEqualTo (_oldDamage < PENETRATION_THRESHOLD)}} && // penetrating body damage is handled differently
{(_bodyPartNToAdd > 3) || {!_causeLimping} || {(_woundDamage <= LIMPING_DAMAGE_THRESHOLD) isEqualTo (_oldDamage <= LIMPING_DAMAGE_THRESHOLD)}} // ensure limping damage is stacked correctly
) exitWith {
TRACE_2("merging with existing wound",_injury,_x);
private _newAmountOf = _oldAmountOf + 1;
_x set [2, _newAmountOf];
_x set [1, _newAmountOf];
private _newBleeding = (_oldAmountOf * _oldBleeding + _bleeding) / _newAmountOf;
_x set [3, _newBleeding];
_x set [2, _newBleeding];
private _newDamage = (_oldAmountOf * _oldDamage + _woundDamage) / _newAmountOf;
_x set [4, _newDamage];
_x set [3, _newDamage];
_createNewWound = false;
};
} forEach _openWounds;
} forEach _existingWounds;

if (_createNewWound) then {
TRACE_1("adding new wound",_injury);
_openWounds pushBack _injury;
_existingWounds pushBack _injury;
};
_createdWounds = true;
};
Expand Down
25 changes: 19 additions & 6 deletions addons/medical_engine/functions/fnc_updateDamageEffects.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,31 @@ if (EGVAR(medical,fractures) > 0) then {
};

if (!_isLimping && {EGVAR(medical,limping) > 0}) then {
private _woundsToCheck = GET_OPEN_WOUNDS(_unit);
private _openWounds = GET_OPEN_WOUNDS(_unit);

// Want a copy of combined arrays to prevent wound mixing
private _legWounds = (_openWounds getOrDefault ["leftleg", []])
+ (_openWounds getOrDefault ["rightleg", []]);

if (EGVAR(medical,limping) == 2) then {
_woundsToCheck = _woundsToCheck + GET_BANDAGED_WOUNDS(_unit); // do not append
private _bandagedWounds = GET_BANDAGED_WOUNDS(_unit);
_legWounds = _legWounds
+ (_bandagedWounds getOrDefault ["leftleg", []])
+ (_bandagedWounds getOrDefault ["rightleg", []]);
};

{
_x params ["_xClassID", "_xBodyPartN", "_xAmountOf", "", "_xDamage"];
if ((_xBodyPartN > 3) && {_xAmountOf > 0} && {_xDamage > LIMPING_DAMAGE_THRESHOLD} && {
(EGVAR(medical_damage,woundDetails) get (_xClassID / 10)) select 3}) exitWith { // select _causeLimping from woundDetails
_x params ["_xClassID", "_xAmountOf", "", "_xDamage"];
if (
(_xAmountOf > 0)
&& {_xDamage > LIMPING_DAMAGE_THRESHOLD}
// select _causeLimping from woundDetails
&& {(EGVAR(medical_damage,woundDetails) get (_xClassID / 10)) select 3}
) exitWith {
TRACE_1("limping because of wound",_x);
_isLimping = true;
};
} forEach _woundsToCheck;
} forEach _legWounds;
};
_unit setVariable [QEGVAR(medical,isLimping), _isLimping, true];

Expand Down
10 changes: 5 additions & 5 deletions addons/medical_engine/script_macros_medical.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@
#define VISUAL_BODY_DAMAGE_THRESHOLD 0.35

// Empty wound data, used for some default return values
// [classID, bodypartIndex, amountOf, bloodloss, damage]
#define EMPTY_WOUND [-1, -1, 0, 0, 0]
// [classID, amountOf, bloodloss, damage]
#define EMPTY_WOUND [-1, 0, 0, 0]

// Base time to bandage each wound category
#define BANDAGE_TIME_S 4
Expand Down Expand Up @@ -173,9 +173,9 @@
#define IS_BLEEDING(unit) (GET_WOUND_BLEEDING(unit) > 0)
#define IS_IN_PAIN(unit) (unit getVariable [VAR_IN_PAIN, false])
#define IS_UNCONSCIOUS(unit) (unit getVariable [VAR_UNCON, false])
#define GET_OPEN_WOUNDS(unit) (unit getVariable [VAR_OPEN_WOUNDS, []])
#define GET_BANDAGED_WOUNDS(unit) (unit getVariable [VAR_BANDAGED_WOUNDS, []])
#define GET_STITCHED_WOUNDS(unit) (unit getVariable [VAR_STITCHED_WOUNDS, []])
#define GET_OPEN_WOUNDS(unit) (unit getVariable [VAR_OPEN_WOUNDS, createHashMap])
#define GET_BANDAGED_WOUNDS(unit) (unit getVariable [VAR_BANDAGED_WOUNDS, createHashMap])
#define GET_STITCHED_WOUNDS(unit) (unit getVariable [VAR_STITCHED_WOUNDS, createHashMap])
#define GET_DAMAGE_THRESHOLD(unit) (unit getVariable [QEGVAR(medical,damageThreshold), [EGVAR(medical,AIDamageThreshold),EGVAR(medical,playerDamageThreshold)] select (isPlayer unit)])

// The following function calls are defined here just for consistency
Expand Down
12 changes: 6 additions & 6 deletions addons/medical_gui/InteractionBodyParts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class ACE_Head {
exceptions[] = {"isNotInside", "isNotSitting"};
ACTION_CONDITION
statement = QUOTE([ARR_2(_target,0)] call FUNC(displayPatientInformation));
modifierFunction = QUOTE([ARR_3(_target,0,_this select 3)] call FUNC(modifyAction));
modifierFunction = QUOTE([ARR_3(_target,""head"",_this select 3)] call FUNC(modifyAction));
runOnHover = 1;
};
class ACE_Torso {
Expand All @@ -15,7 +15,7 @@ class ACE_Torso {
exceptions[] = {"isNotInside", "isNotSitting"};
ACTION_CONDITION
statement = QUOTE([ARR_2(_target,1)] call FUNC(displayPatientInformation));
modifierFunction = QUOTE([ARR_3(_target,1,_this select 3)] call FUNC(modifyAction));
modifierFunction = QUOTE([ARR_3(_target,""body"",_this select 3)] call FUNC(modifyAction));
runOnHover = 1;
class TriageCard {
displayName = CSTRING(Actions_TriageCard);
Expand All @@ -32,7 +32,7 @@ class ACE_ArmLeft {
exceptions[] = {"isNotInside", "isNotSitting"};
ACTION_CONDITION
statement = QUOTE([ARR_2(_target,2)] call FUNC(displayPatientInformation));
modifierFunction = QUOTE([ARR_3(_target,2,_this select 3)] call FUNC(modifyAction));
modifierFunction = QUOTE([ARR_3(_target,""leftarm"",_this select 3)] call FUNC(modifyAction));
runOnHover = 1;
};
class ACE_ArmRight {
Expand All @@ -42,7 +42,7 @@ class ACE_ArmRight {
exceptions[] = {"isNotInside", "isNotSitting"};
ACTION_CONDITION
statement = QUOTE([ARR_2(_target,3)] call FUNC(displayPatientInformation));
modifierFunction = QUOTE([ARR_3(_target,3,_this select 3)] call FUNC(modifyAction));
modifierFunction = QUOTE([ARR_3(_target,""rightarm"",_this select 3)] call FUNC(modifyAction));
runOnHover = 1;
};
class ACE_LegLeft {
Expand All @@ -52,7 +52,7 @@ class ACE_LegLeft {
exceptions[] = {"isNotInside", "isNotSitting"};
ACTION_CONDITION
statement = QUOTE([ARR_2(_target,4)] call FUNC(displayPatientInformation));
modifierFunction = QUOTE([ARR_3(_target,4,_this select 3)] call FUNC(modifyAction));
modifierFunction = QUOTE([ARR_3(_target,""leftleg"",_this select 3)] call FUNC(modifyAction));
runOnHover = 1;
};
class ACE_LegRight {
Expand All @@ -62,6 +62,6 @@ class ACE_LegRight {
exceptions[] = {"isNotInside", "isNotSitting"};
ACTION_CONDITION
statement = QUOTE([ARR_2(_target,5)] call FUNC(displayPatientInformation));
modifierFunction = QUOTE([ARR_3(_target,5,_this select 3)] call FUNC(modifyAction));
modifierFunction = QUOTE([ARR_3(_target,""rightleg"",_this select 3)] call FUNC(modifyAction));
runOnHover = 1;
};
16 changes: 7 additions & 9 deletions addons/medical_gui/functions/fnc_modifyAction.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,30 @@
*
* Arguments:
* 0: Unit <OBJECT>
* 1: Body part index <NUMBER>
* 1: Body part <STRING>
* 2: Action data <ARRAY>
*
* Return Value:
* None
*
* Example:
* [_target, 0, _actionData] call ace_medical_gui_fnc_modifyAction
* [_target, "head", _actionData] call ace_medical_gui_fnc_modifyAction
*
* Public: No
*/

#define COLOR_SCALE ["#ffffff", "#fff1a1", "#ffe075", "#ffcb55", "#ffb73c", "#ffa127", "#ff8815", "#ff6d05", "#ff4b00", "#ff0000"]

params ["_target", "_partIndex", "_actionData"];
params ["_target", "_bodyPart", "_actionData"];
private _partIndex = ALL_BODY_PARTS find _bodyPart;

private _bloodLossOnBodyPart = 0;

// Add all bleeding from wounds on selection
{
_x params ["", "_bodyPartN", "_amountOf", "_bleeding"];

if (_bodyPartN == _partIndex) then {
_bloodLossOnBodyPart = _bloodLossOnBodyPart + (_amountOf * _bleeding);
};
} forEach GET_OPEN_WOUNDS(_target);
_x params ["", "_amountOf", "_bleeding"];
_bloodLossOnBodyPart = _bloodLossOnBodyPart + (_amountOf * _bleeding);
} forEach (GET_OPEN_WOUNDS(_target) getOrDefault [_bodyPart, []]);

private _frBL = 0 max (_bloodLossOnBodyPart / BLOOD_LOSS_RED_THRESHOLD) min 1;
private _colorInt = ceil (_frBL * (BLOOD_LOSS_TOTAL_COLORS - 1)); // ceil because any bleeding more than zero shouldn't be white
Expand Down
7 changes: 5 additions & 2 deletions addons/medical_gui/functions/fnc_updateBodyImage.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@ private _bodyPartDamage = _target getVariable [QEGVAR(medical,bodyPartDamage), [
private _bodyPartBloodLoss = [0, 0, 0, 0, 0, 0];

{
_x params ["", "_bodyPartN", "_amountOf", "_bleeding"];
_bodyPartBloodLoss set [_bodyPartN, (_bodyPartBloodLoss select _bodyPartN) + (_bleeding * _amountOf)];
private _partIndex = ALL_BODY_PARTS find _x;
{
_x params ["", "_amountOf", "_bleeding"];
_bodyPartBloodLoss set [_partIndex, (_bodyPartBloodLoss select _partIndex) + (_bleeding * _amountOf)];
} forEach _y;
} forEach GET_OPEN_WOUNDS(_target);

{
Expand Down
6 changes: 3 additions & 3 deletions addons/medical_gui/functions/fnc_updateInjuryList.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,9 @@ private _fnc_processWounds = {
params ["_wounds", "_format", "_color"];

{
_x params ["_woundClassID", "_bodyPartN", "_amountOf"];
_x params ["_woundClassID", "_amountOf"];

if (_selectionN == _bodyPartN && {_amountOf > 0}) then {
if (_amountOf > 0) then {
private _classIndex = _woundClassID / 10;
private _category = _woundClassID % 10;

Expand All @@ -128,7 +128,7 @@ private _fnc_processWounds = {

_woundEntries pushBack [format [_format, _woundDescription], _color];
};
} forEach _wounds;
} forEach (_wounds getOrDefault [ALL_BODY_PARTS select _selectionN, []]);
};

[GET_OPEN_WOUNDS(_target), "%1", [1, 1, 1, 1]] call _fnc_processWounds;
Expand Down
Loading