From de8940af9b53be04be30661633f894422c524638 Mon Sep 17 00:00:00 2001 From: Grim <69561145+LinkIsGrim@users.noreply.github.com> Date: Sun, 10 Sep 2023 02:06:15 -0400 Subject: [PATCH] Medical Treatment - Add setting to rollover bandage effectiveness (#8426) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * use leftover bandage effectiveness on other wounds in same limb variable naming * Comments Co-authored-by: Kyle Mckay <5459452+kymckay@users.noreply.github.com> * variable naming, fix part index check in findMostEffectiveWound trace 4 * fix function header * Account for multiple wounds in time calculation * fix trace, remove systemChat * update for hashmaps * compile cache * Update addons/medical_treatment/functions/fnc_findMostEffectiveWounds.sqf Co-authored-by: Jouni Järvinen * add bandage effectiveness setting * stupid * remove limit on bandageRemaining * Update addons/medical_treatment/functions/fnc_bandageLocal.sqf Co-authored-by: BrettMayson * Update fnc_getBandageTime.sqf * Update fnc_bandageLocal.sqf * fix header / debug --------- Co-authored-by: Salluci <69561145+Salluci@users.noreply.github.com> Co-authored-by: Kyle Mckay <5459452+kymckay@users.noreply.github.com> Co-authored-by: Jouni Järvinen Co-authored-by: BrettMayson Co-authored-by: PabstMirror --- addons/medical_treatment/XEH_PREP.hpp | 2 +- .../functions/fnc_bandageLocal.sqf | 54 +++++++++++-------- ...nd.sqf => fnc_findMostEffectiveWounds.sqf} | 39 +++++++++++--- .../functions/fnc_getBandageTime.sqf | 44 ++++++++++----- addons/medical_treatment/initSettings.sqf | 18 +++++++ addons/medical_treatment/stringtable.xml | 12 +++++ 6 files changed, 124 insertions(+), 45 deletions(-) rename addons/medical_treatment/functions/{fnc_findMostEffectiveWound.sqf => fnc_findMostEffectiveWounds.sqf} (52%) diff --git a/addons/medical_treatment/XEH_PREP.hpp b/addons/medical_treatment/XEH_PREP.hpp index ab128aa49c..a6266b1508 100644 --- a/addons/medical_treatment/XEH_PREP.hpp +++ b/addons/medical_treatment/XEH_PREP.hpp @@ -25,7 +25,7 @@ PREP(cprStart); PREP(createLitter); PREP(createLitterServer); PREP(diagnose); -PREP(findMostEffectiveWound); +PREP(findMostEffectiveWounds); PREP(fullHeal); PREP(fullHealLocal); PREP(getBandageTime); diff --git a/addons/medical_treatment/functions/fnc_bandageLocal.sqf b/addons/medical_treatment/functions/fnc_bandageLocal.sqf index 74d2641766..b03d59aea4 100644 --- a/addons/medical_treatment/functions/fnc_bandageLocal.sqf +++ b/addons/medical_treatment/functions/fnc_bandageLocal.sqf @@ -25,35 +25,46 @@ private _openWounds = GET_OPEN_WOUNDS(_patient); private _woundsOnPart = _openWounds getOrDefault [_bodyPart, []]; if (_woundsOnPart isEqualTo []) exitWith {}; -// Figure out which injury for this bodypart is the best choice to bandage -// TODO also use up the remainder on left over injuries -private _targetWound = [_patient, _bandage, _bodyPart] call FUNC(findMostEffectiveWound); -_targetWound params ["_wound", "_woundIndex", "_effectiveness"]; +// Figure out which injuries for this bodypart are the best choice to bandage +private _targetWounds = [_patient, _bandage, _bodyPart, GVAR(bandageEffectiveness)] call FUNC(findMostEffectiveWounds); // Everything is patched up on this body part already -if (_effectiveness == -1) exitWith {}; +if (count _targetWounds == 0) exitWith {}; -// Find the impact this bandage has and reduce the amount this injury is present -private _amountOf = _wound select 1; -private _impact = _effectiveness min _amountOf; -_amountOf = _amountOf - _impact; -_wound set [1, _amountOf]; -_woundsOnPart set [_woundIndex, _wound]; +private _treatedDamage = 0; +private _clearConditionCache = false; + +{ + private _wound = _x; + _wound params ["_classID", "_amountOf", "_bleeding", "_damage"]; + _y params ["_effectiveness", "_woundIndex", "_impact"]; + + // clear condition cache if we stopped all bleeding for this injury + if (!_clearConditionCache) then { + _clearConditionCache = (_effectiveness >= _amountOf); + }; + + // Reduce the amount this injury is present + (_woundsOnPart select _woundIndex) set [1, _amountOf - _impact]; + + // Store treated damage for clearing trauma + _treatedDamage = _treatedDamage + (_impact * _damage); + + // Handle reopening bandaged wounds + if (_impact > 0 && {GVAR(advancedBandages) == 2}) then { + [_patient, _impact, _bodyPart, _woundIndex, _wound, _bandage] call FUNC(handleBandageOpening); + }; +} forEach _targetWounds; _patient setVariable [VAR_OPEN_WOUNDS, _openWounds, true]; [_patient] call EFUNC(medical_status,updateWoundBloodLoss); -// Handle the reopening of bandaged wounds -if (_impact > 0 && {GVAR(advancedBandages) == 2}) then { - [_patient, _impact, _bodyPart, _woundIndex, _wound, _bandage] call FUNC(handleBandageOpening); -}; - // Check if we fixed limping from this treatment if ( EGVAR(medical,limping) == 1 - && {_bodyPart isEqualTo "leftleg" || _bodyPart isEqualTo "rightleg"} - && {_amountOf <= 0} + && {_clearConditionCache} + && {_bodyPart in ["leftleg", "rightleg"]} && {_patient getVariable [QEGVAR(medical,isLimping), false]} ) then { [_patient] call EFUNC(medical_engine,updateDamageEffects); @@ -62,9 +73,8 @@ if ( if (GVAR(clearTrauma) == 2) then { TRACE_2("clearTrauma - clearing trauma after bandage",_bodyPart,_openWounds); private _partIndex = ALL_BODY_PARTS find _bodyPart; - private _treatedDamageOf = (_wound select 3) * _impact; private _bodyPartDamage = _patient getVariable [QEGVAR(medical,bodyPartDamage), [0,0,0,0,0,0]]; - private _newDam = (_bodyPartDamage select _partIndex) - _treatedDamageOf; + private _newDam = (_bodyPartDamage select _partIndex) - _treatedDamage; // Prevent obscenely small damage from lack of floating precision if (_newDam < 0.05) then { @@ -73,7 +83,7 @@ if (GVAR(clearTrauma) == 2) then { _bodyPartDamage set [_partIndex, _newDam]; }; _patient setVariable [QEGVAR(medical,bodyPartDamage), _bodyPartDamage, true]; - TRACE_2("clearTrauma - healed damage",_partIndex,_treatedDamageOf); + TRACE_2("clearTrauma - healed damage",_partIndex,_treatedDamage); switch (_bodyPart) do { case "head": { [_patient, true, false, false, false] call EFUNC(medical_engine,updateBodyPartVisuals); }; @@ -85,7 +95,7 @@ if (GVAR(clearTrauma) == 2) then { }; // Reset treatment condition cache for nearby players if we stopped all bleeding -if (_amountOf <= 0) then { +if (_clearConditionCache) then { private _nearPlayers = (_patient nearEntities ["CAManBase", 6]) select {_x call EFUNC(common,isPlayer)}; TRACE_1("clearConditionCaches: bandage",_nearPlayers); [QEGVAR(interact_menu,clearConditionCaches), [], _nearPlayers] call CBA_fnc_targetEvent; diff --git a/addons/medical_treatment/functions/fnc_findMostEffectiveWound.sqf b/addons/medical_treatment/functions/fnc_findMostEffectiveWounds.sqf similarity index 52% rename from addons/medical_treatment/functions/fnc_findMostEffectiveWound.sqf rename to addons/medical_treatment/functions/fnc_findMostEffectiveWounds.sqf index 7f7e4a1848..56561a42a5 100644 --- a/addons/medical_treatment/functions/fnc_findMostEffectiveWound.sqf +++ b/addons/medical_treatment/functions/fnc_findMostEffectiveWounds.sqf @@ -1,20 +1,26 @@ #include "script_component.hpp" /* - * Author: kymckay - * Finds the wound most effective to bandage on the given bodypart of the patient for the given bandage type. + * Author: kymckay, LinkIsGrim + * Finds the most effective wounds to bandage on the given bodypart of the patient for the given bandage type and remaining overall bandage effectiveness. * * Arguments: * 0: Patient * 1: Treatment classname * 2: Body part + * 3: Amount of bandage remaining (default: 1) + * 4: Wounds found from prior runs of the function (default: Empty Hashmap) * * Return Value: - * [Wound, Index, Effectiveness] + * [Wound, [Effectiveness, Index, Impact]] of : + * + * Example: + * [cursorObject, "FieldDressing", "rightleg"] call ace_medical_treatment_fnc_findMostEffectiveWounds * * Public: No */ -params ["_patient", "_bandage", "_bodyPart"]; +params ["_patient", "_bandage", "_bodyPart", ["_bandageRemaining", 1], ["_foundWounds", createHashMap]]; +TRACE_1("findMostEffectiveWounds",count _foundWounds); // Get the default effectiveness for the used bandage private _config = configFile >> QUOTE(ADDON) >> "Bandaging"; @@ -30,13 +36,16 @@ if (isClass (_config >> _bandage)) then { // Iterate over open wounds to find the most effective target private _openWounds = GET_OPEN_WOUNDS(_patient) getOrDefault [_bodyPart, []]; -if (_openWounds isEqualTo []) exitWith { [EMPTY_WOUND, -1, -1] }; +if (_openWounds isEqualTo []) exitWith {_foundWounds}; private _wound = EMPTY_WOUND; private _woundIndex = -1; private _effectivenessFound = -1; +private _impactFound = -1; { + // Ignore iterated wounds + if (_x in _foundWounds) then {continue}; _x params ["_classID", "_amountOf", "_bleeding", "_damage"]; private _woundEffectiveness = _effectiveness; @@ -52,18 +61,32 @@ private _effectivenessFound = -1; _woundEffectiveness = getNumber (_woundTreatmentConfig >> "effectiveness"); }; } else { - // Basic medical bandage just has a base level config (same effectivenes for all wound types) + // Basic medical bandage just has a base level config (same effectiveness for all wound types) if (_bandage != "BasicBandage") then { WARNING_2("No config for wound type [%1] config base [%2]",_className,_config); }; }; + // Multiply by bandageRemaining in case this is a rollover + _woundEffectiveness = _woundEffectiveness * _bandageRemaining; + // Track most effective found so far - if (_woundEffectiveness * _amountOf * _bleeding > _effectivenessFound * (_wound select 1) * (_wound select 2)) then { + if ((_woundEffectiveness * _amountOf * _bleeding) > (_effectivenessFound * (_wound select 1) * (_wound select 2))) then { _effectivenessFound = _woundEffectiveness; + _impactFound = _amountOf min _effectivenessFound; _woundIndex = _forEachIndex; _wound = _x; }; } forEach _openWounds; -[_wound, _woundIndex, _effectivenessFound] +if (_woundIndex isEqualTo -1) exitWith {_foundWounds}; + +_bandageRemaining = _bandageRemaining - (_impactFound/_effectivenessFound); +_foundWounds set [_wound, [_effectivenessFound, _woundIndex, _impactFound]]; + +// recursion, run function again to find next most effective wound +if (GVAR(bandageRollover) && {_bandageRemaining > 0}) then { + [_patient, _bandage, _bodyPart, _bandageRemaining, _foundWounds] call FUNC(findMostEffectiveWounds); +}; + +_foundWounds // return diff --git a/addons/medical_treatment/functions/fnc_getBandageTime.sqf b/addons/medical_treatment/functions/fnc_getBandageTime.sqf index 44ad2a9744..17faf58167 100644 --- a/addons/medical_treatment/functions/fnc_getBandageTime.sqf +++ b/addons/medical_treatment/functions/fnc_getBandageTime.sqf @@ -13,7 +13,7 @@ * Treatment Time * * Example: - * [player, cursorTarget, "Head", "FieldDressing"] call ace_medical_treatment_fnc_getBandageTime + * [player, cursorTarget, "head", "FieldDressing"] call ace_medical_treatment_fnc_getBandageTime * * Public: No */ @@ -23,24 +23,35 @@ params ["_medic", "_patient", "_bodyPart", "_bandage"]; private _partIndex = ALL_BODY_PARTS find toLower _bodyPart; if (_partIndex < 0) exitWith { ERROR_1("invalid partIndex - %1",_this); 0 }; -private _targetWound = [_patient, _bandage, _bodyPart] call FUNC(findMostEffectiveWound); -_targetWound params ["_wound", "_woundIndex", "_effectiveness"]; -TRACE_3("findMostEffectiveWound",_wound,_woundIndex,_effectiveness); +private _targetWounds = [_patient, _bandage, _bodyPart] call FUNC(findMostEffectiveWounds); +TRACE_1("findMostEffectiveWounds",_targetWounds); + +private _woundCount = count _targetWounds; // Everything is patched up on this body part already -if (_wound isEqualTo EMPTY_WOUND) exitWith {0}; - -_wound params ["_classID", "_amountOf", "_bloodloss", "_damage"]; -private _category = (_classID % 10); +if (_woundCount == 0) exitWith {0}; // Base bandage time is based on wound size and remaining percentage -private _bandageTime = [BANDAGE_TIME_S, BANDAGE_TIME_M, BANDAGE_TIME_L] select _category; +private _bandageTimesArray = [BANDAGE_TIME_S, BANDAGE_TIME_M, BANDAGE_TIME_L]; +private _bandageTime = 0; -// Scale bandage time based on amount left and effectiveness (less time if only a little wound left) -// Basic bandage treatment will have a very high effectiveness and can be ignored -if (GVAR(advancedBandages) != 0) then { - _bandageTime = _bandageTime * linearConversion [0, _effectiveness, _amountOf, 0.666, 1, true]; -}; +{ + private _wound = _x; + _wound params ["_classID", "", "_amountOf"]; + _y params ["_effectiveness", "", "_impact"]; + private _category = (_classID % 10); + + // Base bandage time is based on wound size and remaining percentage + private _woundTime = _bandageTimesArray select _category; + + // Scale bandage time based on amount left and effectiveness (less time if only a little wound left) + // Basic bandage treatment will have a very high effectiveness and can be ignored + if (GVAR(advancedBandages != 0)) then { + _woundTime = _woundTime * linearConversion [0, _effectiveness, _impact, 0.666, 1, true]; + }; + + _bandageTime = _bandageTime + _woundTime; +} forEach _targetWounds; // Medics are more practised at applying bandages if ([_medic] call FUNC(isMedic)) then { @@ -52,6 +63,11 @@ if (_medic == _patient) then { _bandageTime = _bandageTime + BANDAGE_TIME_MOD_SELF; }; +// Bandaging multiple injuries doesn't require opening a new bandage each time +if (_woundCount > 1) then { + _bandageTime = _bandageTime - (2 * _woundCount); +}; + TRACE_1("",_bandageTime); // Nobody can bandage instantly _bandageTime max 2.25 diff --git a/addons/medical_treatment/initSettings.sqf b/addons/medical_treatment/initSettings.sqf index f66868aac9..fd83a9995f 100644 --- a/addons/medical_treatment/initSettings.sqf +++ b/addons/medical_treatment/initSettings.sqf @@ -25,6 +25,24 @@ true ] call CBA_fnc_addSetting; +[ + QGVAR(bandageRollover), + "CHECKBOX", + [LSTRING(bandageRollover_DisplayName), LSTRING(bandageRollover_Description)], + [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + true, + false // server can force if necessary, otherwise client decides +] call CBA_fnc_addSetting; + +[ + QGVAR(bandageEffectiveness), + "SLIDER", + [LSTRING(bandageEffectiveness_DisplayName), LSTRING(bandageEffectiveness_Description)], + [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + [0, 5, 1, 2], + true +] call CBA_fnc_addSetting; + [ QGVAR(woundReopenChance), "SLIDER", diff --git a/addons/medical_treatment/stringtable.xml b/addons/medical_treatment/stringtable.xml index 051b0e6d00..5d5dcd50a6 100644 --- a/addons/medical_treatment/stringtable.xml +++ b/addons/medical_treatment/stringtable.xml @@ -4686,5 +4686,17 @@ 身体抽搐了一下,可能还没死! 꿈틀대는걸 보니 죽은 것 같지는 않습니다! + + Bandage Rollover + + + If enabled, bandages can close different types of wounds on the same body part.\nBandaging multiple injuries will scale bandaging time accordingly. + + + Bandage Effectiveness Coefficient + + + Determines how effective bandages are at closing wounds. +