From ba4fcf615de2ea1bbfbf3453194b2af55871e53d Mon Sep 17 00:00:00 2001 From: Grim <69561145+LinkIsGrim@users.noreply.github.com> Date: Sat, 1 Jul 2023 01:37:08 +0300 Subject: [PATCH 01/16] Medical GUI - Add setting to show Damage (#8444) * use pain variable for severe pain and use threshold in damage color calculation show % of damage threshold in medical menu * use damage taken instead of damage left * Add setting and switch to separate tooltip * tooltip -> entry * Change display names and tooltip * switch to qualitative * remove newlines --------- Co-authored-by: Salluci <69561145+Salluci@users.noreply.github.com> Co-authored-by: BrettMayson --- .../functions/fnc_updateBodyImage.sqf | 16 ++++++++ .../functions/fnc_updateInjuryList.sqf | 41 ++++++++++++++++++- addons/medical_gui/initSettings.sqf | 9 ++++ addons/medical_gui/stringtable.xml | 24 +++++++++++ 4 files changed, 88 insertions(+), 2 deletions(-) diff --git a/addons/medical_gui/functions/fnc_updateBodyImage.sqf b/addons/medical_gui/functions/fnc_updateBodyImage.sqf index 51a15945d3..7d3b6f03c5 100644 --- a/addons/medical_gui/functions/fnc_updateBodyImage.sqf +++ b/addons/medical_gui/functions/fnc_updateBodyImage.sqf @@ -22,6 +22,7 @@ params ["_ctrlGroup", "_target"]; private _tourniquets = GET_TOURNIQUETS(_target); private _fractures = GET_FRACTURES(_target); private _bodyPartDamage = _target getVariable [QEGVAR(medical,bodyPartDamage), [0, 0, 0, 0, 0, 0]]; +private _damageThreshold = GET_DAMAGE_THRESHOLD(_target); private _bodyPartBloodLoss = [0, 0, 0, 0, 0, 0]; { @@ -70,6 +71,21 @@ private _bodyPartBloodLoss = [0, 0, 0, 0, 0, 0]; [_bloodLoss] call FUNC(bloodLossToRGBA); } else { private _damage = _bodyPartDamage select _forEachIndex; + switch (true) do { // torso damage threshold doesn't need scaling + case (_forEachIndex > 3): { // legs: index 4 & 5 + _damageThreshold = LIMPING_DAMAGE_THRESHOLD * 4; + }; + case (_forEachIndex > 1): { // arms: index 2 & 3 + _damageThreshold = FRACTURE_DAMAGE_THRESHOLD * 4; + }; + case (_forEachIndex == 0): { // head: index 0 + _damageThreshold = _damageThreshold * 1.25; + }; + default { // torso: index 1 + _damageThreshold = _damageThreshold * 1.5 + }; + }; + _damage = (_damage / _damageThreshold) min 1; [_damage] call FUNC(damageToRGBA); }; diff --git a/addons/medical_gui/functions/fnc_updateInjuryList.sqf b/addons/medical_gui/functions/fnc_updateInjuryList.sqf index b0bf76fe45..d6f650f8a8 100644 --- a/addons/medical_gui/functions/fnc_updateInjuryList.sqf +++ b/addons/medical_gui/functions/fnc_updateInjuryList.sqf @@ -33,6 +33,43 @@ private _bodyPartName = [ _entries pushBack [localize _bodyPartName, [1, 1, 1, 1]]; +// Damage taken tooltip +if (GVAR(showDamageEntry)) then { + private _bodyPartDamage = (_target getVariable [QEGVAR(medical,bodyPartDamage), [0, 0, 0, 0, 0, 0]]) select _selectionN; + if (_bodyPartDamage > 0) then { + private _damageThreshold = GET_DAMAGE_THRESHOLD(_target); + switch (true) do { + case (_selectionN > 3): { // legs: index 4 & 5 + _damageThreshold = LIMPING_DAMAGE_THRESHOLD * 4; + }; + case (_selectionN > 1): { // arms: index 2 & 3 + _damageThreshold = FRACTURE_DAMAGE_THRESHOLD * 4; + }; + case (_selectionN == 0): { // head: index 0 + _damageThreshold = _damageThreshold * 1.25; + }; + default { // torso: index 1 + _damageThreshold = _damageThreshold * 1.5; + }; + }; + _bodyPartDamage = (_bodyPartDamage / _damageThreshold) min 1; + switch (true) do { + case (_bodyPartDamage isEqualTo 1): { + _entries pushBack [localize LSTRING(traumaSustained4), [_bodyPartDamage] call FUNC(damageToRGBA)]; + }; + case (_bodyPartDamage >= 0.75): { + _entries pushBack [localize LSTRING(traumaSustained3), [_bodyPartDamage] call FUNC(damageToRGBA)]; + }; + case (_bodyPartDamage >= 0.5): { + _entries pushBack [localize LSTRING(traumaSustained2), [_bodyPartDamage] call FUNC(damageToRGBA)]; + }; + case (_bodyPartDamage >= 0.25): { + _entries pushBack [localize LSTRING(traumaSustained1), [_bodyPartDamage] call FUNC(damageToRGBA)]; + }; + }; + }; +}; + // Indicate if unit is bleeding at all if (IS_BLEEDING(_target)) then { _entries pushBack [localize LSTRING(Status_Bleeding), [1, 0, 0, 1]]; @@ -78,10 +115,10 @@ if (_target call EFUNC(common,isAwake)) then { private _pain = GET_PAIN_PERCEIVED(_target); if (_pain > 0) then { private _painText = switch (true) do { - case (_pain > 0.5): { + case (_pain > PAIN_UNCONSCIOUS): { ELSTRING(medical_treatment,Status_SeverePain); }; - case (_pain > 0.1): { + case (_pain > (PAIN_UNCONSCIOUS / 5)): { ELSTRING(medical_treatment,Status_Pain); }; default { diff --git a/addons/medical_gui/initSettings.sqf b/addons/medical_gui/initSettings.sqf index eb6a36bac6..c1d02d7131 100644 --- a/addons/medical_gui/initSettings.sqf +++ b/addons/medical_gui/initSettings.sqf @@ -109,6 +109,15 @@ private _categoryColors = [ELSTRING(medical,Category), format ["| %1 |", LELSTRI ] call CBA_fnc_addSetting; } forEach _damageColors; +[ + QGVAR(showDamageEntry), + "CHECKBOX", + [LSTRING(showDamageEntry_DisplayName), LSTRING(showDamageEntry_Description)], + [ELSTRING(medical,Category), LSTRING(SubCategory)], + false, + true +] call CBA_fnc_addSetting; + [ QGVAR(showBloodlossEntry), "CHECKBOX", diff --git a/addons/medical_gui/stringtable.xml b/addons/medical_gui/stringtable.xml index e7cda25af9..afcd58b6e4 100644 --- a/addons/medical_gui/stringtable.xml +++ b/addons/medical_gui/stringtable.xml @@ -1250,5 +1250,29 @@ Показывать тяжесть кровопотери в списке ранений. Mostrar la pérdida de sangre cualitativa en la lista de heridas. + + Show Trauma Sustained + Mostrar Traumatismo Sofrido + + + Show trauma sustained in the injury list. + Mostrar traumatismo sofrido na lista de feridas. + + + Minor Trauma + Traumatismo Leve + + + Major Trauma + Traumatismo Significante + + + Severe Trauma + Traumatismo Severo + + + Chronic Trauma + Traumatismo Crônico + From c7e13ca4c7106ffb567b84b8590a472df4cab2f1 Mon Sep 17 00:00:00 2001 From: Grim <69561145+LinkIsGrim@users.noreply.github.com> Date: Mon, 3 Jul 2023 16:00:46 +0300 Subject: [PATCH 02/16] Repair - Move to separate settings menu (#9236) * Repair - Move from logistics settings menu * Repair - Move from logistics settings menu --- addons/repair/initSettings.sqf | 40 ++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/addons/repair/initSettings.sqf b/addons/repair/initSettings.sqf index 82a411c91d..554a666130 100644 --- a/addons/repair/initSettings.sqf +++ b/addons/repair/initSettings.sqf @@ -1,7 +1,9 @@ +private _category = format ["ACE %1", LLSTRING(Repair)]; + [ QGVAR(displayTextOnRepair), "CHECKBOX", [LSTRING(SettingDisplayTextName), LSTRING(SettingDisplayTextDesc)], - [localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_repair"], + _category, true, // default value false, // isGlobal {[QGVAR(displayTextOnRepair), _this] call EFUNC(common,cbaSettings_settingChanged)} @@ -10,7 +12,7 @@ [ QGVAR(engineerSetting_repair), "LIST", [LSTRING(engineerSetting_Repair_name), LSTRING(engineerSetting_Repair_description)], - [localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_repair"], + _category, [[0,1,2],[LSTRING(engineerSetting_anyone), LSTRING(engineerSetting_EngineerOnly), LSTRING(engineerSetting_AdvancedOnly)],1], // [values, titles, defaultIndex] true, // isGlobal {[QGVAR(engineerSetting_repair), _this] call EFUNC(common,cbaSettings_settingChanged)} @@ -19,7 +21,7 @@ [ QGVAR(engineerSetting_wheel), "LIST", [LSTRING(engineerSetting_Wheel_name), LSTRING(engineerSetting_Wheel_description)], - [localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_repair"], + _category, [[0,1,2],[LSTRING(engineerSetting_anyone), LSTRING(engineerSetting_EngineerOnly), LSTRING(engineerSetting_AdvancedOnly)],0], // [values, titles, defaultIndex] true, // isGlobal {[QGVAR(engineerSetting_wheel), _this] call EFUNC(common,cbaSettings_settingChanged)} @@ -28,7 +30,7 @@ [ QGVAR(patchWheelEnabled), "LIST", [LSTRING(patchWheelEnabled_name), LSTRING(patchWheelEnabled_description)], - [localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_repair"], + _category, [[-1,0,1,2],["str_player_none", LSTRING(engineerSetting_anyone), LSTRING(engineerSetting_EngineerOnly), LSTRING(engineerSetting_AdvancedOnly)],1], // default value true // isGlobal ] call CBA_fnc_addSetting; @@ -37,7 +39,7 @@ QGVAR(patchWheelRequiredItems), "LIST", [LSTRING(patchWheelRequiredItems_DisplayName), LSTRING(patchWheelRequiredItems_Description)], - [localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_repair"], + _category, [[[], [ANY_TOOLKIT_FAKECLASS]], ["STR_A3_None", "STR_A3_CfgWeapons_Toolkit0"], 1], true ] call CBA_fnc_addSetting; @@ -46,7 +48,7 @@ QGVAR(patchWheelLocation), "LIST", [LSTRING(patchWheelLocation_DisplayName), LSTRING(patchWheelLocation_Description)], - [localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_repair"], + _category, [[["ground", "vehicle"], ["vehicle"], ["ground"]], ["str_difficulty_any", LSTRING(patchWheelOnVehicle), LSTRING(patchWheelOnGround)], 0], true ] call CBA_fnc_addSetting; @@ -54,7 +56,7 @@ [ QGVAR(repairDamageThreshold), "SLIDER", [LSTRING(repairDamageThreshold_name), LSTRING(repairDamageThreshold_description)], - [localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_repair"], + _category, [0,1,0.6,2], // [min, max, default value, trailing decimals (-1 for whole numbers only)] true, // isGlobal {[QGVAR(repairDamageThreshold), _this] call EFUNC(common,cbaSettings_settingChanged)} @@ -63,7 +65,7 @@ [ QGVAR(repairDamageThreshold_engineer), "SLIDER", [LSTRING(repairDamageThreshold_Engineer_name), LSTRING(repairDamageThreshold_Engineer_description)], - [localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_repair"], + _category, [0,1,0.4,2], // [min, max, default value, trailing decimals (-1 for whole numbers only)] true, // isGlobal {[QGVAR(repairDamageThreshold_engineer), _this] call EFUNC(common,cbaSettings_settingChanged)} @@ -72,7 +74,7 @@ [ QGVAR(consumeItem_toolKit), "LIST", // fnc_repair expects number [LSTRING(consumeItem_ToolKit_name), LSTRING(consumeItem_ToolKit_description)], - [localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_repair"], + _category, [[0,1],[ELSTRING(common,No), ELSTRING(common,Yes)],0], // [values, titles, defaultIndex] true, // isGlobal {[QGVAR(consumeItem_toolKit), _this] call EFUNC(common,cbaSettings_settingChanged)} @@ -82,7 +84,7 @@ QGVAR(locationsBoostTraining), "CHECKBOX", [ELSTRING(common,LocationsBoostTraining_DisplayName), LSTRING(LocationsBoostTraining_Description)], - [localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_repair"], + _category, false, true ] call CBA_fnc_addSetting; @@ -90,7 +92,7 @@ [ QGVAR(fullRepairLocation), "LIST", [LSTRING(fullRepairLocation), LSTRING(fullRepairLocation_description)], - [localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_repair"], + _category, [[0,1,2,3,4],[LSTRING(useAnywhere), LSTRING(repairVehicleOnly), LSTRING(repairFacilityOnly), LSTRING(vehicleAndFacility), ELSTRING(common,Disabled)],2], // [values, titles, defaultIndex] true, // isGlobal {[QGVAR(fullRepairLocation), _this] call EFUNC(common,cbaSettings_settingChanged)} @@ -99,7 +101,7 @@ [ QGVAR(engineerSetting_fullRepair), "LIST", [LSTRING(engineerSetting_fullRepair_name), LSTRING(engineerSetting_fullRepair_description)], - [localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_repair"], + _category, [[0,1,2],[LSTRING(engineerSetting_anyone), LSTRING(engineerSetting_EngineerOnly), LSTRING(engineerSetting_AdvancedOnly)],2], // [values, titles, defaultIndex] true, // isGlobal {[QGVAR(engineerSetting_fullRepair), _this] call EFUNC(common,cbaSettings_settingChanged)} @@ -108,7 +110,7 @@ [ QGVAR(addSpareParts), "CHECKBOX", [LSTRING(addSpareParts_name), LSTRING(addSpareParts_description)], - [localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_repair"], + _category, true, // default value true, // isGlobal {[QGVAR(addSpareParts), _this] call EFUNC(common,cbaSettings_settingChanged)}, @@ -119,7 +121,7 @@ QGVAR(wheelRepairRequiredItems), "LIST", [LSTRING(WheelRepairRequiredItems_DisplayName), LSTRING(WheelRepairRequiredItems_Description)], - [localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_repair"], + _category, [[[], [ANY_TOOLKIT_FAKECLASS]], ["STR_A3_None", "STR_A3_CfgWeapons_Toolkit0"], 0], true ] call CBA_fnc_addSetting; @@ -128,7 +130,7 @@ QGVAR(miscRepairRequiredItems), "LIST", [LSTRING(MiscRepairRequiredItems_DisplayName), LSTRING(MiscRepairRequiredItems_Description)], - [localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_repair"], + _category, [[[], [ANY_TOOLKIT_FAKECLASS]], ["STR_A3_None", "STR_A3_CfgWeapons_Toolkit0"], 1], true ] call CBA_fnc_addSetting; @@ -137,7 +139,7 @@ QGVAR(fullRepairRequiredItems), "LIST", [LSTRING(FullRepairRequiredItems_DisplayName), LSTRING(FullRepairRequiredItems_Description)], - [localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_repair"], + _category, [[[], [ANY_TOOLKIT_FAKECLASS]], ["STR_A3_None", "STR_A3_CfgWeapons_Toolkit0"], 1], true ] call CBA_fnc_addSetting; @@ -145,7 +147,7 @@ [ QGVAR(autoShutOffEngineWhenStartingRepair), "CHECKBOX", [LSTRING(autoShutOffEngineWhenStartingRepair_name), LSTRING(autoShutOffEngineWhenStartingRepair_description)], - [localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_repair"], + _category, false, // default value true, // isGlobal {[QGVAR(autoShutOffEngineWhenStartingRepair), _this] call EFUNC(common,cbaSettings_settingChanged)} @@ -156,7 +158,7 @@ QGVAR(patchWheelTime), "SLIDER", [LSTRING(patchWheelTime_DisplayName), LSTRING(patchWheelTime_Description)], - [localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_repair"], + _category, [0.1, 60, 5, 1], true ] call CBA_fnc_addSetting; @@ -165,7 +167,7 @@ QGVAR(patchWheelMaximumRepair), "SLIDER", [LSTRING(patchWheelMaximumRepair_DisplayName), LSTRING(patchWheelMaximumRepair_Description)], - [localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_repair"], + _category, [0, 1, 0.3, 1, true], true ] call CBA_fnc_addSetting; From cc1636c14f3cf58e777e30e4a7fbaac02e9ae1e4 Mon Sep 17 00:00:00 2001 From: Grim <69561145+LinkIsGrim@users.noreply.github.com> Date: Thu, 6 Jul 2023 06:51:00 +0300 Subject: [PATCH 03/16] Repair - Change Repair Threshold setting descriptions (#9242) * change stringtable * change setting to % slider * keep old translations --- addons/repair/initSettings.sqf | 4 ++-- addons/repair/stringtable.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/repair/initSettings.sqf b/addons/repair/initSettings.sqf index 554a666130..040e44c2eb 100644 --- a/addons/repair/initSettings.sqf +++ b/addons/repair/initSettings.sqf @@ -57,7 +57,7 @@ private _category = format ["ACE %1", LLSTRING(Repair)]; QGVAR(repairDamageThreshold), "SLIDER", [LSTRING(repairDamageThreshold_name), LSTRING(repairDamageThreshold_description)], _category, - [0,1,0.6,2], // [min, max, default value, trailing decimals (-1 for whole numbers only)] + [0, 1, 0.6, 1, true], true, // isGlobal {[QGVAR(repairDamageThreshold), _this] call EFUNC(common,cbaSettings_settingChanged)} ] call CBA_fnc_addSetting; @@ -66,7 +66,7 @@ private _category = format ["ACE %1", LLSTRING(Repair)]; QGVAR(repairDamageThreshold_engineer), "SLIDER", [LSTRING(repairDamageThreshold_Engineer_name), LSTRING(repairDamageThreshold_Engineer_description)], _category, - [0,1,0.4,2], // [min, max, default value, trailing decimals (-1 for whole numbers only)] + [0, 1, 0.4, 1, true], true, // isGlobal {[QGVAR(repairDamageThreshold_engineer), _this] call EFUNC(common,cbaSettings_settingChanged)} ] call CBA_fnc_addSetting; diff --git a/addons/repair/stringtable.xml b/addons/repair/stringtable.xml index 3b650f13d5..92bee905bb 100644 --- a/addons/repair/stringtable.xml +++ b/addons/repair/stringtable.xml @@ -1285,7 +1285,7 @@ 維修門檻 - What is the maximum damage that can be repaired with a toolkit? + Maximum damage to which a part can be repaired with a toolkit.\n0% means all damage can be repaired. Der maximale Schaden, der von einem Reperatursatz behoben werden kann? Jaki jest maksymalny poziom uszkodzeń jaki może zostać naprawiony przy pomocy narzędzi? Qual é o dano máximo que pode ser reparado com um kit de ferramentas? @@ -1315,7 +1315,7 @@ 維修門檻 (工兵) - What is the maximum damage that can be repaired by an engineer? + Maximum damage to which a part can be repaired by an engineer above the minimum level required for the repair.\n0% means all damage can be repaired. Der maximale Schaden, der von einem Pionier behoben werden kann? Jaki jest maksymalny poziom uszkodzeń jaki może zostać naprawiony przez mechanika? Qual é o dano máximo que pode ser reparado com um engenheiro? From 50430e47efab1ff4ecec6b9192f9290d383e4305 Mon Sep 17 00:00:00 2001 From: Grim <69561145+LinkIsGrim@users.noreply.github.com> Date: Thu, 6 Jul 2023 06:51:25 +0300 Subject: [PATCH 04/16] Medical - Change Epinephrine Wake Up Boost setting description (#9240) * change stringtable * keep old translations --- addons/medical/stringtable.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/medical/stringtable.xml b/addons/medical/stringtable.xml index c76c312f89..4be9a4029f 100644 --- a/addons/medical/stringtable.xml +++ b/addons/medical/stringtable.xml @@ -65,7 +65,7 @@ 에피네프린 사용 시 추가 회복 확률 - Increases how often spontaneous wake up checks happen when patient has Epinephrine in their system. + When an unconscious patient has Epinephrine in their system, the time between spontaneous wake up checks is divided by this value. 患者がアドレナリンを投与されると自発的に覚醒する確率を上昇させます。 增加因病患的循環系統裡面的腎上腺素自我甦醒的機率。 增加因病患的循环系统里面的肾上腺素自我苏醒的机率。 From 04e41a4d5ad6227b33ac4a7286f782b19204ef3b Mon Sep 17 00:00:00 2001 From: Grim <69561145+LinkIsGrim@users.noreply.github.com> Date: Thu, 6 Jul 2023 06:52:04 +0300 Subject: [PATCH 05/16] Repair - Make Full Repair Time dependent on vehicle damage (#8417) * add variable full repair time * enable compile cache * Fix stupid * whoops * incremental full repair * cleanup function header * ignore hitpoints inFullRepairProgress * fix getHitPointsToIgnore * final cleanup * don't show repair hint while doing full repair * make this all work * fix stupid put this back in place * Add setting for speedup when near repair facility/vehicle enable compile cache * refactor near repair facility/vehicle checks * remove skipping hint from do_repair better for feedback this way * git diff stuff * use functions directly in ACE_Repair.hpp * add check for vehicle proximity * add a new line * switch to multiply by setting instead * speed boost settings, remove exit addRepairActions * stringtable * remove speed boost settings * fix things, add forceDisplayName * name in function header * fix TRACE * add animation looping * remove systemChat Co-authored-by: Filip Maciejewski * add time coefficient setting * move to repair category * time coefficient max and default values --------- Co-authored-by: Salluci <69561145+Salluci@users.noreply.github.com> Co-authored-by: Filip Maciejewski --- addons/repair/ACE_Repair.hpp | 13 +- addons/repair/XEH_PREP.hpp | 3 + .../repair/functions/fnc_addRepairActions.sqf | 62 +++----- addons/repair/functions/fnc_doRepair.sqf | 8 +- .../functions/fnc_fullRepairProgress.sqf | 50 ++++++ .../functions/fnc_getFullRepairTime.sqf | 42 ++++++ .../functions/fnc_getHitPointsToIgnore.sqf | 142 ++++++++++++++++++ .../functions/fnc_getPostRepairDamage.sqf | 9 +- .../functions/fnc_isInRepairFacility.sqf | 25 +-- .../functions/fnc_isNearRepairVehicle.sqf | 14 +- addons/repair/functions/fnc_repair.sqf | 23 ++- .../repair/functions/fnc_repair_failure.sqf | 4 + .../repair/functions/fnc_repair_success.sqf | 4 + addons/repair/initSettings.sqf | 23 +++ addons/repair/script_component.hpp | 4 + addons/repair/stringtable.xml | 26 +++- 16 files changed, 366 insertions(+), 86 deletions(-) create mode 100644 addons/repair/functions/fnc_fullRepairProgress.sqf create mode 100644 addons/repair/functions/fnc_getFullRepairTime.sqf create mode 100644 addons/repair/functions/fnc_getHitPointsToIgnore.sqf diff --git a/addons/repair/ACE_Repair.hpp b/addons/repair/ACE_Repair.hpp index ae436791ad..344c509b2f 100644 --- a/addons/repair/ACE_Repair.hpp +++ b/addons/repair/ACE_Repair.hpp @@ -3,10 +3,11 @@ class ACE_Repair { class ReplaceWheel { displayName = CSTRING(ReplaceWheel); displayNameProgress = CSTRING(ReplacingWheel); + forceDisplayName = 0; repairLocations[] = {"All"}; requiredEngineer = QGVAR(engineerSetting_Wheel); - repairingTime = 10; + repairingTime = QGVAR(wheelChangeTime); repairingTimeSelfCoef = 1; items = QGVAR(wheelRepairRequiredItems); condition = QFUNC(canReplaceWheel); @@ -21,6 +22,7 @@ class ACE_Repair { animationCallerProne = "Acts_carFixingWheel"; animationCallerSelf = "Acts_carFixingWheel"; animationCallerSelfProne = "Acts_carFixingWheel"; + loopAnimation = 0; litter[] = {}; }; class RemoveWheel: ReplaceWheel { @@ -46,7 +48,7 @@ class ACE_Repair { displayNameProgress = CSTRING(RepairingHitPoint); condition = QFUNC(canMiscRepair); requiredEngineer = QGVAR(engineerSetting_Repair); - repairingTime = 15; + repairingTime = QGVAR(miscRepairTime); callbackSuccess = QFUNC(doRepair); items = QGVAR(miscRepairRequiredItems); itemConsumed = QGVAR(consumeItem_ToolKit); @@ -80,11 +82,14 @@ class ACE_Repair { class FullRepair: MiscRepair { displayName = CSTRING(fullRepair); displayNameProgress = CSTRING(fullyRepairing); + forceDisplayName = 1; + loopAnimation = 1; requiredEngineer = QGVAR(engineerSetting_fullRepair); repairLocations[] = {QGVAR(fullRepairLocation)}; - repairingTime = 30; - condition = "-1 != ((getAllHitPointsDamage _target param [2,[]]) findIf {_x > 0})"; + repairingTime = QFUNC(getFullRepairTime); + condition = "((getAllHitPointsDamage _target) select 2) findIf {_x > 0} != -1"; callbackSuccess = QFUNC(doFullRepair); + callbackProgress = QFUNC(fullRepairProgress); items = QGVAR(fullRepairRequiredItems); itemConsumed = QGVAR(consumeItem_ToolKit); }; diff --git a/addons/repair/XEH_PREP.hpp b/addons/repair/XEH_PREP.hpp index 7c82632f87..ea9e40a4e7 100644 --- a/addons/repair/XEH_PREP.hpp +++ b/addons/repair/XEH_PREP.hpp @@ -17,8 +17,11 @@ PREP(doRepair); PREP(doRepairTrack); PREP(doReplaceTrack); PREP(doReplaceWheel); +PREP(fullRepairProgress); PREP(getClaimObjects); +PREP(getFullRepairTime); PREP(getHitPointString); +PREP(getHitPointsToIgnore); PREP(getPatchWheelTime); PREP(getPostRepairDamage); PREP(getRepairItems); diff --git a/addons/repair/functions/fnc_addRepairActions.sqf b/addons/repair/functions/fnc_addRepairActions.sqf index f78863985d..20607ca940 100644 --- a/addons/repair/functions/fnc_addRepairActions.sqf +++ b/addons/repair/functions/fnc_addRepairActions.sqf @@ -25,6 +25,9 @@ TRACE_2("addRepairActions", _vehicle,_type); private _initializedClasses = GETMVAR(GVAR(initializedClasses),[]); if (_type in _initializedClasses) exitWith {}; +// get hitPoints to ignore +private _hitPointsToIgnore = [_vehicle] call FUNC(getHitPointsToIgnore); + // get all hitpoints and selections (getAllHitPointsDamage _vehicle) params [["_hitPoints", []], ["_hitSelections", []]]; // Since 1.82 these are all lower case @@ -40,8 +43,6 @@ private _icon = ["a3\ui_f\data\igui\cfg\actions\repair_ca.paa", "#FFFFFF"]; private _vehCfg = configOf _vehicle; // Custom position can be defined via config for associated hitpoint private _hitpointPositions = getArray (_vehCfg >> QGVAR(hitpointPositions)); -// Associated hitpoints can be grouped via config to produce a single repair action -private _hitpointGroups = getArray (_vehCfg >> QGVAR(hitpointGroups)); // Get turret paths private _turretPaths = ((fullCrew [_vehicle, "gunner", true]) + (fullCrew [_vehicle, "commander", true])) apply {_x # 3}; @@ -88,59 +89,32 @@ private _turretPaths = ((fullCrew [_vehicle, "gunner", true]) + (fullCrew [_vehi _processedSelections pushBack _selection; } else { - // Empty hitpoints don't contain enough information - if (_hitpoint isEqualTo "") exitWith { TRACE_3("Skipping Empty Hit",_hitpoint,_forEachIndex,_selection); }; - // Ignore glass hitpoints - if ((_hitpoint find "glass") != -1) exitWith { TRACE_3("Skipping Glass",_hitpoint,_forEachIndex,_selection); }; - // Ignore hitpoints starting with # (seems to be lights) - if ((_hitpoint select [0,1]) == "#") exitWith { TRACE_3("Skipping # hit",_hitpoint,_forEachIndex,_selection); }; - // Ignore ERA/Slat armor (vanilla uses hitera_/hitslat_, pre-1.82 RHS uses era_) - // ToDo: see how community utilizes new armor system, could also check getText (_hitpointConfig >> "simulation") - if (((_hitpoint select [0,7]) == "hitera_") || {(_hitpoint select [0,8]) == "hitslat_"} || {(_hitpoint select [0,4]) == "era_"}) exitWith { TRACE_3("Skipping ERA/SLAT",_hitpoint,_forEachIndex,_selection); }; + // Skip ignored hitpoints + if (_hitpoint in _hitPointsToIgnore) exitWith { + TRACE_3("Skipping ignored hitpoint",_hitpoint,_forEachIndex,_selection); + }; // Some hitpoints do not have a selection but do have an armorComponent value (seems to mainly be RHS) // Ref https://community.bistudio.com/wiki/Arma_3_Damage_Enhancement // this code won't support identically named hitpoints (e.g. commander turret: Duplicate HitPoint name 'HitTurret') private _armorComponent = ""; if (_selection == "") then { - { - private _turretHitpointCfg = ([_vehCfg, _x] call CBA_fnc_getTurret) >> "HitPoints"; - private _hitpointsCfg = "configName _x == _hitpoint" configClasses _turretHitpointCfg; - if (_hitpointsCfg isNotEqualTo []) exitWith { - TRACE_2("turret hitpoint configFound",_hitpoint,_x); - // only do turret hitpoints or stuff linked to visuals for now or we apparently get some weird stuff - if ((_hitpoint in ["hitturret", "hitgun"]) || {(getNumber (_hitpointsCfg # 0 >> "isGun")) == 1} || {(getNumber (_hitpointsCfg # 0 >> "isTurret")) == 1} || {(getText (_hitpointsCfg # 0 >> "visual")) != ""}) then { + private _hitpointsCfg = "configName _x == _hitpoint" configClasses (_vehCfg >> "HitPoints"); + if (_hitpointsCfg isNotEqualTo []) then { + _armorComponent = getText (_hitpointsCfg # 0 >> "armorComponent"); + }; + if (_armorComponent == "") then { + { + private _turretHitpointCfg = ([_vehCfg, _x] call CBA_fnc_getTurret) >> "HitPoints"; + private _hitpointsCfg = "configName _x == _hitpoint" configClasses _turretHitpointCfg; + if (_hitpointsCfg isNotEqualTo []) exitWith { + TRACE_2("turret hitpoint configFound",_hitpoint,_x); _armorComponent = getText (_hitpointsCfg # 0 >> "armorComponent"); }; - }; - } forEach _turretPaths; - if (_armorComponent == "") then { - private _hitpointsCfg = "configName _x == _hitpoint" configClasses (_vehCfg >> "HitPoints"); - if ((getText (_hitpointsCfg # 0 >> "visual")) != "") then { - _armorComponent = getText (_hitpointsCfg # 0 >> "armorComponent"); - }; + } forEach _turretPaths; }; if (_armorComponent != "") then { INFO_3("%1: %2 no selection: using armorComponent %3",_type,_hitpoint,_armorComponent); }; }; - if ((_selection == "") && {_armorComponent == ""}) exitWith { TRACE_3("Skipping no selection OR armor component",_hitpoint,_forEachIndex,_selection); }; - - - //Depends hitpoints shouldn't be modified directly (will be normalized) - // Biki: Clearing 'depends' in case of inheritance cannot be an empty string (rpt warnings), but rather a "0" value. - if (!((getText (_vehCfg >> "HitPoints" >> _hitpoint >> "depends")) in ["", "0"])) exitWith { - TRACE_3("Skip Depends",_hitpoint,_forEachIndex,_selection); - }; - - private _childHitPoint = false; - { - { - if (_hitpoint == _x) exitWith { - _childHitPoint = true; - }; - } forEach (_x select 1); - } forEach _hitpointGroups; - // If the current selection is associated with a child hitpoint, then skip - if (_childHitPoint) exitWith { TRACE_3("childHitpoint",_hitpoint,_forEachIndex,_selection); }; // Find the action position private _position = compile format ["_target selectionPosition ['%1', 'HitPoints'];", _selection]; diff --git a/addons/repair/functions/fnc_doRepair.sqf b/addons/repair/functions/fnc_doRepair.sqf index 1b6f497d8e..2874eaf2f8 100644 --- a/addons/repair/functions/fnc_doRepair.sqf +++ b/addons/repair/functions/fnc_doRepair.sqf @@ -7,6 +7,7 @@ * 0: Unit that does the repairing * 1: Vehicle to repair * 2: Selected hitpointIndex + * 3: Repair action classname * * Return Value: * None @@ -17,10 +18,11 @@ * Public: No */ -params ["_unit", "_vehicle", "_hitPointIndex"]; -TRACE_3("params",_unit,_vehicle,_hitPointIndex); +params ["_unit", "_vehicle", "_hitPointIndex", "_action"]; +TRACE_4("params",_unit,_vehicle,_hitPointIndex,_action); -private _postRepairDamageMin = [_unit] call FUNC(getPostRepairDamage); +// override minimum damage if doing full repair +private _postRepairDamageMin = [_unit, _action isEqualTo "fullRepair"] call FUNC(getPostRepairDamage); (getAllHitPointsDamage _vehicle) params ["_allHitPoints"]; private _hitPointClassname = _allHitPoints select _hitPointIndex; diff --git a/addons/repair/functions/fnc_fullRepairProgress.sqf b/addons/repair/functions/fnc_fullRepairProgress.sqf new file mode 100644 index 0000000000..444bb750b3 --- /dev/null +++ b/addons/repair/functions/fnc_fullRepairProgress.sqf @@ -0,0 +1,50 @@ +#include "script_component.hpp" +/* + * Author: LinkIsGrim + * Handles full repair by periodically repairing damaged hitpoints. + * + * Arguments: + * 0: Arguments + * 0: Engineer + * 1: Vehicle + * 2: Hitpoint (unused) + * 3: Repair action classname + * 1: Elapsed Time + * 2: Total Time + * + * Return Value: + * Continue Repair + * + * Example: + * [[objNull, player], 5, 10] call ace_repair_fnc_fullRepairProgress + * + * Public: No + */ + +params ["_args", "_elapsedTime", "_totalTime"]; +_args params ["_engineer", "_vehicle", "", "_action"]; + +if !((alive _vehicle) && {(abs speed _vehicle) < 1}) exitWith {false}; // make sure vehicle doesn't drive off + +// Not enough time has elapsed to repair a hitpoint +if (_totalTime - _elapsedTime > ([_engineer, _vehicle] call FUNC(getFullRepairTime)) - (GVAR(miscRepairTime) * GVAR(timeCoefficientFullRepair))) exitWith {true}; + +private _allHitPointsDamage = getAllHitPointsDamage _vehicle; +_allHitPointsDamage params ["_hitPoints", "", "_damageValues"]; + +private _hitPointsToIgnore = [_vehicle] call FUNC(getHitPointsToIgnore); + +private _firstDamagedIndex = { + private _hitPoint = _hitPoints select _forEachIndex; + if (_x > 0 && {!(_hitPoint in _hitPointsToIgnore)}) exitWith {_forEachIndex}; + -1 +} forEach _damageValues; + +// Stop repairing if there are no more damaged hitpoints +// callBackSuccess to FUNC(doFullRepair) for ignored hitpoints +if (_firstDamagedIndex == -1) exitWith {true}; + +// Repair the first damaged hitpoint +[_engineer, _vehicle, _firstDamagedIndex, _action] call FUNC(doRepair); + +true diff --git a/addons/repair/functions/fnc_getFullRepairTime.sqf b/addons/repair/functions/fnc_getFullRepairTime.sqf new file mode 100644 index 0000000000..78f46472a5 --- /dev/null +++ b/addons/repair/functions/fnc_getFullRepairTime.sqf @@ -0,0 +1,42 @@ +#include "script_component.hpp" +/* + * Author: LinkIsGrim + * Calculates the Full Repair time based on the amount of hitpoints to repair + * + * Arguments: + * 0: Engineer + * 1: Vehicle + * + * Return Value: + * Repair Time + * + * Example: + * [player, vehicle] call ace_repair_fnc_getFullRepairTime + * + * Public: No + */ + +params ["_engineer", "_vehicle"]; + +private _allHitPointsDamage = getAllHitPointsDamage _vehicle; +_allHitPointsDamage params ["_hitPoints", "", "_damageValues"]; + +private _hitPointsToIgnore = [_vehicle] call FUNC(getHitPointsToIgnore); + +private _repairsNeeded = 0; +private _doExtraRepair = false; +{ + if (_x <= 0) then {continue}; // skip hitpoints that don't need repairs + private _hitPoint = _hitPoints select _forEachIndex; + if (_hitPoint in _hitPointsToIgnore) then { // only add extra repair for ignore hitpoints if they're damaged + _doExtraRepair = true; + continue + }; + _repairsNeeded = _repairsNeeded + ceil (_x / 0.5); // repair is capped at 0.5 in FUNC(doRepair) +} forEach _damageValues; + +if (_doExtraRepair) then { + _repairsNeeded = _repairsNeeded + 1; +}; + +_repairsNeeded * GVAR(miscRepairTime) * GVAR(timeCoefficientFullRepair) // return diff --git a/addons/repair/functions/fnc_getHitPointsToIgnore.sqf b/addons/repair/functions/fnc_getHitPointsToIgnore.sqf new file mode 100644 index 0000000000..24f2d9a207 --- /dev/null +++ b/addons/repair/functions/fnc_getHitPointsToIgnore.sqf @@ -0,0 +1,142 @@ +#include "script_component.hpp" +/* + * Author: commy2, kymckay, LinkIsGrim + * Get list of vehicle hitpoints to ignore + * + * Arguments: + * 0: Vehicle + * + * Return Value: + * HitPoints to ignore + * + * Example: + * [vehicle] call ace_repair_fnc_getHitpointsToIgnore + * + * Public: No + */ + +params ["_vehicle"]; + +private _type = typeOf _vehicle; +TRACE_2("getHitPointsToIgnore", _vehicle,_type); +private _initializedClasses = missionNamespace getVariable [QGVAR(hitPointsToIgnoreInitializedClasses), createHashMap]; +if (_type in _initializedClasses) exitWith {_initializedClasses get _type}; + +private _vehCfg = configOf _vehicle; +private _hitpointGroups = getArray (_vehCfg >> QGVAR(hitpointGroups)); +private _turretPaths = ((fullCrew [_vehicle, "gunner", true]) + (fullCrew [_vehicle, "commander", true])) apply {_x # 3}; + +(getAllHitPointsDamage _vehicle) params [["_hitPoints", []], ["_hitSelections", []]]; +// get hitpoints of wheels with their selections +([_vehicle] call FUNC(getWheelHitPointsWithSelections)) params ["_wheelHitPoints", "_wheelHitSelections"]; + +private _hitPointsToIgnore = [""]; // always ignore empty hitpoints +private _processedSelections = []; + +{ + private _selection = _x; + private _hitpoint = toLower (_hitPoints select _forEachIndex); + private _isWheelOrTrack = _selection in _wheelHitSelections || {_hitpoint in _wheelHitPoints} || {_hitpoint in TRACK_HITPOINTS}; + + if (_hitpoint isEqualTo "") then { // skip empty hitpoint + continue + }; + + if (_isWheelOrTrack && {_selection in _processedSelections || {_selection isEqualTo ""}}) then { // skip duplicate or empty selection wheel/track + TRACE_3("Skipping duplicate Wheel/Track or empty selection",_hitpoint,_forEachIndex,_selection); + /*#ifdef DEBUG_MODE_FULL + systemChat format ["Skipping duplicate wheel, hitpoint %1, index %2, selection %3", _hitpoint, _forEachIndex, _selection]; + #endif*/ + _hitPointsToIgnore pushBackUnique _hitpoint; + _processedSelections pushBack _selection; + continue + }; + + if ("glass" in _hitpoint) then { // skip glass + TRACE_3("Skipping glass",_hitpoint,_forEachIndex,_selection); + /*#ifdef DEBUG_MODE_FULL + systemChat format ["Skipping glass, hitpoint %1, index %2, selection %3", _hitpoint, _forEachIndex, _selection]; + #endif*/ + _hitPointsToIgnore pushBackUnique _hitpoint; + _processedSelections pushBack _selection; + continue + }; + + if (_hitpoint select [0,1] isEqualTo "#" || {_hitpoint select [0,9] isEqualTo "hit_light"}) then { // skip lights + TRACE_3("Skipping light",_hitpoint,_forEachIndex,_selection); + /*#ifdef DEBUG_MODE_FULL + systemChat format ["Skipping light, hitpoint %1, index %2, selection %3", _hitpoint, _forEachIndex, _selection]; + #endif*/ + _hitPointsToIgnore pushBackUnique _hitpoint; + _processedSelections pushBack _selection; + continue + }; + + if (_hitpoint select [0,7] isEqualTo "hitera_" || {_hitpoint select [0,8] isEqualTo "hitslat_"} || {_hitpoint select [0,4] isEqualTo "era_"}) then { // skip era/slat + TRACE_3("Skipping ERA/Slat HitPoint",_hitpoint,_forEachIndex,_selection); + /*#ifdef DEBUG_MODE_FULL + systemChat format ["Skipping ERA/SLAT, hitpoint %1, index %2, selection %3", _hitpoint, _forEachIndex, _selection]; + #endif*/ + _hitPointsToIgnore pushBackUnique _hitpoint; + _processedSelections pushBack _selection; + continue + }; + + private _armorComponent = ""; + if (_selection == "") then { // some hitpoints have empty selection but defined armor component (mostly RHS) + { + private _turretHitpointCfg = ([_vehCfg, _x] call CBA_fnc_getTurret) >> "HitPoints"; + private _hitpointsCfg = "configName _x == _hitpoint" configClasses _turretHitpointCfg; + if (_hitpointsCfg isNotEqualTo []) exitWith { + TRACE_2("turret hitpoint configFound",_hitpoint,_x); + // only do turret hitpoints and stuff linked to visuals + if ((_hitpoint in ["hitturret", "hitgun"]) || {(getNumber (_hitpointsCfg # 0 >> "isGun")) == 1} || {(getNumber (_hitpointsCfg # 0 >> "isTurret")) == 1} || {(getText (_hitpointsCfg # 0 >> "visual")) != ""}) then { + _armorComponent = getText (_hitpointsCfg # 0 >> "armorComponent"); + }; + }; + } forEach _turretPaths; + if (_armorComponent == "") then { + private _hitpointsCfg = "configName _x == _hitpoint" configClasses (_vehCfg >> "HitPoints"); + if (_hitpointsCfg isNotEqualTo [] && {(getText (_hitpointsCfg # 0 >> "visual")) != ""}) then { + _armorComponent = getText (_hitpointsCfg # 0 >> "armorComponent"); + }; + }; + }; + + if ((_selection == "") && {_armorComponent == ""}) then { + TRACE_3("Skipping no selection OR armor component",_hitpoint,_forEachIndex,_selection); + /*#ifdef DEBUG_MODE_FULL + systemChat format ["Skipping no selection OR armor component, hitpoint %1, index %2, selection %3", _hitpoint, _forEachIndex, _selection]; + #endif*/ + _hitPointsToIgnore pushBackUnique _hitpoint; + _processedSelections pushBack _selection; + continue + }; + + if (!(getText (_vehCfg >> "HitPoints" >> _hitpoint >> "depends") in ["", "0"])) then { // skip depends hitpoints, should be normalized by engine + TRACE_3("Skipping depends hitpoint",_hitpoint,_forEachIndex,_selection); + /*#ifdef DEBUG_MODE_FULL + systemChat format ["Skipping depends hitpoint, hitpoint %1, index %2, selection %3", _hitpoint, _forEachIndex, _selection]; + #endif*/ + _hitPointsToIgnore pushBackUnique _hitpoint; + _processedSelections pushBack _selection; + continue + }; + + if ((_hitpointGroups findIf {(_x select 1) == _hitpoint}) != -1) then { // skip child hitpoints + TRACE_3("Skipping child hitpoint",_hitpoint,_forEachIndex,_selection); + /*#ifdef DEBUG_MODE_FULL + systemChat format ["Skipping child hitpoint, hitpoint %1, index %2, selection %3", _hitpoint, _forEachIndex, _selection]; + #endif*/ + _hitPointsToIgnore pushBackUnique _hitpoint; + _processedSelections pushBack _selection; + continue + }; + + _processedSelections pushBack _selection; +} forEach _hitSelections; + +_initializedClasses set [_type, _hitPointsToIgnore]; +missionNamespace setVariable [QGVAR(hitPointsToIgnoreInitializedClasses), _initializedClasses]; + +_hitPointsToIgnore diff --git a/addons/repair/functions/fnc_getPostRepairDamage.sqf b/addons/repair/functions/fnc_getPostRepairDamage.sqf index 0eac151e45..141df15369 100644 --- a/addons/repair/functions/fnc_getPostRepairDamage.sqf +++ b/addons/repair/functions/fnc_getPostRepairDamage.sqf @@ -5,6 +5,7 @@ * * Arguments: * 0: Unit that does the repairing + * 1: Override for full repair (default: false) * * Return Value: * 0: Repair Damage Threshold @@ -15,11 +16,11 @@ * Public: No */ -params ["_unit"]; -TRACE_1("params",_unit); +params ["_unit", ["_override", false]]; +TRACE_2("params",_unit,_override); -//If in facility or near vehicle then complete repair of hitpoint: -if (([_unit] call FUNC(isInRepairFacility) || {[_unit] call FUNC(isNearRepairVehicle)})) exitWith {0}; +//If in facility, near vehicle, or doing full repair then complete repair of hitpoint: +if ((_override || {[_unit] call FUNC(isInRepairFacility)} || {[_unit] call FUNC(isNearRepairVehicle)})) exitWith {0}; private _class = _unit getVariable ["ACE_IsEngineer", getNumber (configOf _unit >> "engineer")]; //If advanced or more qualified than min, then use engineer threshold: diff --git a/addons/repair/functions/fnc_isInRepairFacility.sqf b/addons/repair/functions/fnc_isInRepairFacility.sqf index 1693297494..a0a1615cd9 100644 --- a/addons/repair/functions/fnc_isInRepairFacility.sqf +++ b/addons/repair/functions/fnc_isInRepairFacility.sqf @@ -15,28 +15,15 @@ * Public: Yes */ +#define CHECK_OBJECTS(var) ((var) findIf {(_x getVariable ["ACE_isRepairFacility", getNumber (configOf _x >> QGVAR(canRepair))] > 0) && {!(_x isKindOf "AllVehicles")} && {alive _x}} != -1) + params [["_object", objNull, [objNull]]]; TRACE_1("params",_object); -private _position = getPosASL _object; -private _isInBuilding = false; -private _checkObject = { - if ( - _x getVariable ["ACE_isRepairFacility", getNumber (configOf _x >> QGVAR(canRepair))] > 0 - && {!(_x isKindOf "AllVehicles")} // check if it's not repair vehicle - && {alive _x} - ) exitWith { - _isInBuilding = true; - }; +private _fnc_check = { + private _position = _object modelToWorldVisual [0, 0, eyePos _object select 2]; + CHECK_OBJECTS(lineIntersectsWith [ARR_3(_position, _position vectorAdd [ARR_3(0, 0, 10)], _object)]) || {CHECK_OBJECTS(_object nearObjects 7.5)} }; -private _objects = (lineIntersectsWith [_object modelToWorldVisual [0, 0, (_position select 2)], _object modelToWorldVisual [0, 0, (_position select 2) +10], _object]); -_checkObject forEach _objects; - -if (_isInBuilding) exitWith {true}; - -_objects = _object nearObjects 7.5; -_checkObject forEach _objects; - -_isInBuilding +[[], _fnc_check, _object, QGVAR(inRepairFacilityCache), IN_REPAIR_FACILITY_CACHE_EXPIRY] call EFUNC(common,cachedCall); diff --git a/addons/repair/functions/fnc_isNearRepairVehicle.sqf b/addons/repair/functions/fnc_isNearRepairVehicle.sqf index 1243c0f95b..3a894162ee 100644 --- a/addons/repair/functions/fnc_isNearRepairVehicle.sqf +++ b/addons/repair/functions/fnc_isNearRepairVehicle.sqf @@ -15,14 +15,14 @@ * Public: Yes */ +#define CHECK_OBJECTS(var) ((var) findIf {alive _x && {[_x] call FUNC(isRepairVehicle)}} != -1) + params ["_unit"]; TRACE_1("params",_unit); -private _nearObjects = nearestObjects [_unit, ["Air", "LandVehicle", "Slingload_base_F"], 20]; +private _fnc_check = { + private _nearObjects = nearestObjects [_unit, ["Air", "LandVehicle", "Slingload_base_F"], 20]; + CHECK_OBJECTS(_nearObjects) +}; -private _return = false; -{ - if (alive _x && {[_x] call FUNC(isRepairVehicle)}) exitWith {_return = true;}; -} forEach _nearObjects; - -_return; +[[], _fnc_check, _unit, QGVAR(nearRepairVehicleCache), NEAR_REPAIR_VEHICLE_CACHE_EXPIRY] call EFUNC(common,cachedCall); diff --git a/addons/repair/functions/fnc_repair.sqf b/addons/repair/functions/fnc_repair.sqf index 51fdea90fe..a0654d2555 100644 --- a/addons/repair/functions/fnc_repair.sqf +++ b/addons/repair/functions/fnc_repair.sqf @@ -148,6 +148,7 @@ if (_callbackProgress == "") then { // Player Animation private _callerAnim = [getText (_config >> "animationCaller"), getText (_config >> "animationCallerProne")] select (stance _caller == "PRONE"); +private _loopAnim = (getNumber (_config >> "loopAnimation")) isEqualTo 1; _caller setVariable [QGVAR(selectedWeaponOnrepair), currentWeapon _caller]; // Cannot use secondairy weapon for animation @@ -171,10 +172,27 @@ if (vehicle _caller == _caller && {_callerAnim != ""}) then { } else { _caller setVariable [QGVAR(repairPrevAnimCaller), animationState _caller]; }; + _caller setVariable [QGVAR(repairCurrentAnimCaller), toLower _callerAnim]; [_caller, _callerAnim] call EFUNC(common,doAnimation); }; }; +if (_loopAnim) then { + private _animDoneEh = _caller addEventHandler ["AnimDone", { + params ["_caller", "_anim"]; + if (_anim isEqualTo (_caller getVariable [QGVAR(repairCurrentAnimCaller), ""])) then { + [{ + params ["_caller", "_anim"]; + if !(isNil {_caller getVariable QGVAR(repairCurrentAnimCaller)}) then { + TRACE_2("loop",_caller,_anim); + _this call EFUNC(common,doAnimation) + }; + }, [_caller, _anim], 2.5] call CBA_fnc_waitAndExecute; + }; + }]; + _caller setVariable [QGVAR(repairLoopAnimEh), _animDoneEh]; +}; + private _soundPosition = _caller modelToWorldVisualWorld (_caller selectionPosition "RightHand"); ["Acts_carFixingWheel", _soundPosition, nil, 50] call EFUNC(common,playConfigSound3D); @@ -213,7 +231,10 @@ private _hitPointClassname = if (_hitPoint isEqualType "") then { }; private _processText = getText (_config >> "displayNameProgress"); private _backupText = format [localize LSTRING(RepairingHitPoint), _hitPointClassname]; -([_hitPointClassname, _processText, _backupText] call FUNC(getHitPointString)) params ["_text"]; +private _text = _processText; +if (getNumber (_config >> "forceDisplayName") isNotEqualTo 1) then { + _text = ([_hitPointClassname, _processText, _backupText] call FUNC(getHitPointString)) select 0; +}; TRACE_4("display",_hitPoint,_hitPointClassname,_processText,_text); diff --git a/addons/repair/functions/fnc_repair_failure.sqf b/addons/repair/functions/fnc_repair_failure.sqf index 83cce85e0d..5acd9564e7 100644 --- a/addons/repair/functions/fnc_repair_failure.sqf +++ b/addons/repair/functions/fnc_repair_failure.sqf @@ -29,9 +29,13 @@ TRACE_5("params",_caller,_target,_selectionName,_className,_usersOfItems); if (primaryWeapon _caller == "ACE_FakePrimaryWeapon") then { _caller removeWeapon "ACE_FakePrimaryWeapon"; }; + +_caller removeEventHandler ["AnimDone", _caller getVariable [QGVAR(repairLoopAnimEh), -1]]; +_caller setVariable [QGVAR(repairLoopAnimEh), nil]; if (vehicle _caller == _caller && {!(_caller call EFUNC(common,isSwimming))}) then { [_caller, _caller getVariable [QGVAR(repairPrevAnimCaller), ""], 2] call EFUNC(common,doAnimation); }; +_caller setVariable [QGVAR(repairCurrentAnimCaller), nil]; _caller setVariable [QGVAR(repairPrevAnimCaller), nil]; private _weaponSelect = (_caller getVariable [QGVAR(selectedWeaponOnrepair), ""]); diff --git a/addons/repair/functions/fnc_repair_success.sqf b/addons/repair/functions/fnc_repair_success.sqf index a86be84244..99778c37dd 100644 --- a/addons/repair/functions/fnc_repair_success.sqf +++ b/addons/repair/functions/fnc_repair_success.sqf @@ -29,9 +29,13 @@ TRACE_4("params",_caller,_target,_selectionName,_className); if (primaryWeapon _caller == "ACE_FakePrimaryWeapon") then { _caller removeWeapon "ACE_FakePrimaryWeapon"; }; + +_caller removeEventHandler ["AnimDone", _caller getVariable [QGVAR(repairLoopAnimEh), -1]]; +_caller setVariable [QGVAR(repairLoopAnimEh), nil]; if (vehicle _caller == _caller && {!(_caller call EFUNC(common,isSwimming))}) then { [_caller, _caller getVariable [QGVAR(repairPrevAnimCaller), ""], 2] call EFUNC(common,doAnimation); }; +_caller setVariable [QGVAR(repairCurrentAnimCaller), nil]; _caller setVariable [QGVAR(repairPrevAnimCaller), nil]; private _weaponSelect = (_caller getVariable [QGVAR(selectedWeaponOnrepair), ""]); diff --git a/addons/repair/initSettings.sqf b/addons/repair/initSettings.sqf index 040e44c2eb..066e944a50 100644 --- a/addons/repair/initSettings.sqf +++ b/addons/repair/initSettings.sqf @@ -107,6 +107,14 @@ private _category = format ["ACE %1", LLSTRING(Repair)]; {[QGVAR(engineerSetting_fullRepair), _this] call EFUNC(common,cbaSettings_settingChanged)} ] call CBA_fnc_addSetting; +[ + QGVAR(timeCoefficientFullRepair), "SLIDER", + [LSTRING(timeCoefficientFullRepair_name), LSTRING(timeCoefficientFullRepair_description)], + _category, + [0,3,1.5,2], + true +] call CBA_fnc_addSetting; + [ QGVAR(addSpareParts), "CHECKBOX", [LSTRING(addSpareParts_name), LSTRING(addSpareParts_description)], @@ -153,6 +161,21 @@ private _category = format ["ACE %1", LLSTRING(Repair)]; {[QGVAR(autoShutOffEngineWhenStartingRepair), _this] call EFUNC(common,cbaSettings_settingChanged)} ] call CBA_fnc_addSetting; +[ + QGVAR(miscRepairTime), "SLIDER", + [LSTRING(miscRepairTime_name), LSTRING(miscRepairTime_description)], + _category, + [0,60,15,-1], // [min, max, default value, trailing decimals (-1 for whole numbers only)] + true +] call CBA_fnc_addSetting; + +[ + QGVAR(wheelChangeTime), "SLIDER", + [LSTRING(wheelChangeTime_name), LSTRING(wheelChangeTime_description)], + _category, + [0,60,10,-1], // [min, max, default value, trailing decimals (-1 for whole numbers only)] + true +] call CBA_fnc_addSetting; [ QGVAR(patchWheelTime), diff --git a/addons/repair/script_component.hpp b/addons/repair/script_component.hpp index 2a6196c6fc..9fab647079 100644 --- a/addons/repair/script_component.hpp +++ b/addons/repair/script_component.hpp @@ -20,6 +20,10 @@ #define DAMAGE_COLOR_SCALE ["#FFFFFF", "#FFFF7E", "#FFEC4D", "#FFD52C", "#FCB121", "#FF9916", "#FF7D16", "#FF4400", "#FF0000"] +#define IN_REPAIR_FACILITY_CACHE_EXPIRY 1 + +#define NEAR_REPAIR_VEHICLE_CACHE_EXPIRY 1 + #define ANY_TOOLKIT_FAKECLASS QGVAR(anyToolKit) #define PATCH_WHEEL_STEP_TIME 0.05 diff --git a/addons/repair/stringtable.xml b/addons/repair/stringtable.xml index 92bee905bb..4929e0f31a 100644 --- a/addons/repair/stringtable.xml +++ b/addons/repair/stringtable.xml @@ -266,6 +266,12 @@ 維修載具中... Tamir Ediliyor... + + Full Repair Time Coefficient + + + Modifies how long it takes to perform a Full Repair.\nThe repair time is based on based on the amount of repairs needed for each part, including those normally inaccessible. + Boost engineer training when in repair vehicles or facilities. Untrained becomes engineer, engineer becomes advanced engineer. Améliore les compétences en ingénierie des unités en fonction du lieu où elles se trouvent ; notamment dans les véhicules de réparation ou les ateliers.\nUn soldat non formé devient ingénieur, un ingénieur devient ingénieur avancé. @@ -1860,7 +1866,7 @@ 選擇的備件數量 - Wheel Repair Requirements + Wheel Change Requirements Bedingungen für die Reifenreperatur Wym. naprawy kół Requisitos de reparación de ruedas @@ -2062,6 +2068,18 @@ Apagar el motor automáticamente al efectuar una reparación 수리 시 엔진을 자동으로 끕니다. + + Part Repair Time + + + Time in seconds to complete a repair. + + + Wheel Change Time + + + Time in seconds to remove or change a wheel. + Patch Wheel Radflicken @@ -2071,16 +2089,16 @@ Radflicken... - Patch wheel time + Wheel Patch Time Time it takes to patch a wheel by 5%. - Patch wheel maximum repair + Patch Wheel Threshold - Maximum level a wheel can be patched. + Maximum level to which a wheel can be patched. Wheel Patch Location From 30a0e55843cf6126d1e77e0603bc7d6a87a34878 Mon Sep 17 00:00:00 2001 From: Grim <69561145+LinkIsGrim@users.noreply.github.com> Date: Fri, 7 Jul 2023 07:14:35 +0300 Subject: [PATCH 06/16] Field Rations - Add arsenal category (#9221) * add field rations category * improve macro * second verse same as the first * account for empty items * switch to configClasses * documentation * add API variable * Update docs/wiki/framework/field-rations-framework.md --- addons/field_rations/CfgWeapons.hpp | 7 +++- addons/field_rations/XEH_PREP.hpp | 1 + addons/field_rations/XEH_preInit.sqf | 7 ++++ addons/field_rations/XEH_preStart.sqf | 2 ++ .../functions/fnc_scanFieldRations.sqf | 34 +++++++++++++++++++ addons/field_rations/script_component.hpp | 2 ++ .../wiki/framework/field-rations-framework.md | 1 + 7 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 addons/field_rations/functions/fnc_scanFieldRations.sqf diff --git a/addons/field_rations/CfgWeapons.hpp b/addons/field_rations/CfgWeapons.hpp index 760d41290f..b100ba4e90 100644 --- a/addons/field_rations/CfgWeapons.hpp +++ b/addons/field_rations/CfgWeapons.hpp @@ -40,6 +40,7 @@ class CfgWeapons { XGVAR(replacementItem) = "ACE_WaterBottle_Half"; XGVAR(consumeAnims)[] = {QGVAR(drinkStand), QGVAR(drinkCrouch), QGVAR(drinkProne)}; XGVAR(consumeSounds)[] = {QGVAR(drink1), QGVAR(drink1), QGVAR(drink2)}; + ACE_isFieldRationItem = 1; }; class ACE_WaterBottle_Half: ACE_WaterBottle { @@ -87,6 +88,7 @@ class CfgWeapons { XGVAR(replacementItem) = "ACE_Canteen_Half"; XGVAR(consumeAnims)[] = {QGVAR(drinkStand), QGVAR(drinkCrouch), QGVAR(drinkProne)}; XGVAR(consumeSounds)[] = {QGVAR(drink1), QGVAR(drink1), QGVAR(drink2)}; + ACE_isFieldRationItem = 1; }; class ACE_Canteen_Half: ACE_Canteen { @@ -132,6 +134,7 @@ class CfgWeapons { XGVAR(consumeText) = CSTRING(DrinkingX); XGVAR(consumeAnims)[] = {QGVAR(drinkStandCan), QGVAR(drinkCrouchCan), QGVAR(drinkProneCan)}; XGVAR(consumeSounds)[] = {QGVAR(drinkCan1), QGVAR(drinkCan1), QGVAR(drinkCan2)}; + ACE_isFieldRationItem = 1; }; class ACE_Can_Franta: ACE_Can_Spirit { @@ -164,6 +167,7 @@ class CfgWeapons { XGVAR(consumeTime) = 10; XGVAR(hungerSatiated) = 20; XGVAR(consumeText) = CSTRING(EatingX); + ACE_isFieldRationItem = 1; }; class ACE_MRE_BeefStew: ACE_MRE_LambCurry { @@ -225,7 +229,7 @@ class CfgWeapons { model = QPATHTOF(data\mre_human.p3d); picture = QPATHTOF(ui\item_mre_human_co.paa); }; - + // - Misc Food ------------------------------------------------------------ class ACE_Sunflower_Seeds: ACE_ItemCore { author = ECSTRING(common,ACETeam); @@ -240,5 +244,6 @@ class CfgWeapons { XGVAR(consumeTime) = 10; XGVAR(hungerSatiated) = 10; XGVAR(consumeText) = CSTRING(EatingX); + ACE_isFieldRationItem = 1; }; }; diff --git a/addons/field_rations/XEH_PREP.hpp b/addons/field_rations/XEH_PREP.hpp index 68833a495b..2035345f47 100644 --- a/addons/field_rations/XEH_PREP.hpp +++ b/addons/field_rations/XEH_PREP.hpp @@ -14,5 +14,6 @@ ACEX_PREP(handleEffects); ACEX_PREP(handleHUD); ACEX_PREP(handleRespawn); ACEX_PREP(refillItem); +ACEX_PREP(scanFieldRations); ACEX_PREP(setRemainingWater); ACEX_PREP(update); diff --git a/addons/field_rations/XEH_preInit.sqf b/addons/field_rations/XEH_preInit.sqf index c4efb567ed..ede921483e 100644 --- a/addons/field_rations/XEH_preInit.sqf +++ b/addons/field_rations/XEH_preInit.sqf @@ -8,6 +8,8 @@ PREP_RECOMPILE_END; #include "initSettings.sqf" +#define ARSENAL_CATEGORY_ICON QPATHTOF(ui\icon_survival.paa) + // Init arrays of status modifiers GVAR(thirstModifiers) = []; GVAR(hungerModifiers) = []; @@ -18,4 +20,9 @@ GVAR(waterSourceP3Ds) = _cache select 0; // List of refill action offsets corresponding to the p3ds in the array above GVAR(waterSourceOffsets) = _cache select 1; +// Custom Arsenal Tab +if (["ace_arsenal"] call EFUNC(common,isModLoaded)) then { + [keys FIELD_RATIONS_ITEMS, LLSTRING(DisplayName), ARSENAL_CATEGORY_ICON] call EFUNC(arsenal,addRightPanelButton); +}; + ADDON = true; diff --git a/addons/field_rations/XEH_preStart.sqf b/addons/field_rations/XEH_preStart.sqf index eec59ff8f7..88109cf9ee 100644 --- a/addons/field_rations/XEH_preStart.sqf +++ b/addons/field_rations/XEH_preStart.sqf @@ -30,3 +30,5 @@ private _waterSourceOffsets = [ uiNamespace setVariable [QGVAR(cacheP3Ds), compileFinal str [_waterSourceP3Ds, _waterSourceOffsets]]; TRACE_1("compiled",count _waterSourceP3Ds); + +call FUNC(scanFieldRations); diff --git a/addons/field_rations/functions/fnc_scanFieldRations.sqf b/addons/field_rations/functions/fnc_scanFieldRations.sqf new file mode 100644 index 0000000000..395b3ba45b --- /dev/null +++ b/addons/field_rations/functions/fnc_scanFieldRations.sqf @@ -0,0 +1,34 @@ +#include "script_component.hpp" +/* + * Author: Salluci + * Caches all item classnames used as field rations, their thirst/hunger values, and whether they are treated as magazines + * + * Arguments: + * None + * + * Return Value: + * None + * + * Example: + * call acex_field_rations_fnc_scanFieldRations + * + * Public: No + */ + +private _list = createHashMap; +private _cfgWeapons = configFile >> "CfgWeapons"; +private _cfgMagazines = configFile >> "CfgMagazines"; + +private _fnc_isFieldRationItem = toString { + (getNumber (_x >> "ACE_isFieldRationItem") isEqualTo 1) || {(getNumber (_x >> QXGVAR(thirstQuenched))) > 0} || {(getNumber (_x >> QXGVAR(hungerSatiated))) > 0} || {(getText (_x >> QXGVAR(refillItem))) isNotEqualTo ""} +}; + +{ + _list set [configName _x, ""]; +} forEach (_fnc_isFieldRationItem configClasses _cfgWeapons); + +{ + _list set [configName _x, ""]; +} forEach (_fnc_isFieldRationItem configClasses _cfgMagazines); + +uiNamespace setVariable [QXGVAR(fieldRationItems), compileFinal str _list]; diff --git a/addons/field_rations/script_component.hpp b/addons/field_rations/script_component.hpp index 9811493029..bcde75fe9c 100644 --- a/addons/field_rations/script_component.hpp +++ b/addons/field_rations/script_component.hpp @@ -33,3 +33,5 @@ #define IDC_DRAINING_HUD_THIRST_ICON 7750 #define IDC_DRAINING_HUD_HUNGER_GROUP 7840 #define IDC_DRAINING_HUD_HUNGER_ICON 7850 + +#define FIELD_RATIONS_ITEMS (createHashMapFromArray (call (uiNamespace getVariable [QXGVAR(fieldRationItems), {createHashMap}]))) diff --git a/docs/wiki/framework/field-rations-framework.md b/docs/wiki/framework/field-rations-framework.md index 54d2b22e90..bc433e7d52 100644 --- a/docs/wiki/framework/field-rations-framework.md +++ b/docs/wiki/framework/field-rations-framework.md @@ -28,6 +28,7 @@ Config Name | Type | Description `acex_field_rations_refillItem` | String | Makes an item refillable, class name of item added when refilled (OPTIONAL) `acex_field_rations_refillAmount` | Number | Amount of water required to refill item (OPTIONAL) `acex_field_rations_refillTime` | Number | Time required to refill item (in seconds) (OPTIONAL) +`ACE_isFieldRationItem` | Number | Force adds the item to the ACE Field Rations category in ACE Arsenal (OPTIONAL) _* Value range is 0 to 100 and can be modified by the corresponding coefficient setting._ From 0e26755b88bb5141594320cf9292fe02a05eedc7 Mon Sep 17 00:00:00 2001 From: Grim <69561145+LinkIsGrim@users.noreply.github.com> Date: Fri, 7 Jul 2023 07:14:44 +0300 Subject: [PATCH 07/16] Medical - Add arsenal category (#9220) * add medical category to arsenal * function header Co-authored-by: PabstMirror * move to preinit, protect list * improve macro * documentation * add config property * add CfgMagazines * Revert "add CfgMagazines" Arsenal doesn't support magazines in custom categories --------- Co-authored-by: GhostIsSpooky <69561145+Salluci@users.noreply.github.com> Co-authored-by: PabstMirror --- addons/medical_treatment/CfgWeapons.hpp | 19 +++++++++++ addons/medical_treatment/XEH_PREP.hpp | 1 + addons/medical_treatment/XEH_preInit.sqf | 7 ++++ addons/medical_treatment/XEH_preStart.sqf | 2 ++ .../functions/fnc_scanMedicalItems.sqf | 34 +++++++++++++++++++ addons/medical_treatment/script_component.hpp | 2 ++ .../framework/medical-treatment-framework.md | 18 ++++++++++ 7 files changed, 83 insertions(+) create mode 100644 addons/medical_treatment/functions/fnc_scanMedicalItems.sqf diff --git a/addons/medical_treatment/CfgWeapons.hpp b/addons/medical_treatment/CfgWeapons.hpp index fed3184a59..e285697cc1 100644 --- a/addons/medical_treatment/CfgWeapons.hpp +++ b/addons/medical_treatment/CfgWeapons.hpp @@ -8,12 +8,14 @@ class CfgWeapons { class FirstAidKit: ItemCore { type = 0; + ACE_isMedicalItem = 1; class ItemInfo: InventoryFirstAidKitItem_Base_F { mass = 4; }; }; class Medikit: ItemCore { type = 0; + ACE_isMedicalItem = 1; class ItemInfo: MedikitItem { mass = 60; }; @@ -27,6 +29,7 @@ class CfgWeapons { displayName = CSTRING(Bandage_Basic_Display); descriptionShort = CSTRING(Bandage_Basic_Desc_Short); descriptionUse = CSTRING(Bandage_Basic_Desc_Use); + ACE_isMedicalItem = 1; class ItemInfo: CBA_MiscItem_ItemInfo { mass = 1; }; @@ -39,6 +42,7 @@ class CfgWeapons { model = QPATHTOF(data\packingbandage.p3d); descriptionShort = CSTRING(Packing_Bandage_Desc_Short); descriptionUse = CSTRING(Packing_Bandage_Desc_Use); + ACE_isMedicalItem = 1; class ItemInfo: CBA_MiscItem_ItemInfo { mass = 1; }; @@ -51,6 +55,7 @@ class CfgWeapons { model = "\A3\Structures_F_EPA\Items\Medical\Bandage_F.p3d"; descriptionShort = CSTRING(Bandage_Elastic_Desc_Short); descriptionUse = CSTRING(Bandage_Elastic_Desc_Use); + ACE_isMedicalItem = 1; class ItemInfo: CBA_MiscItem_ItemInfo { mass = 1; }; @@ -63,6 +68,7 @@ class CfgWeapons { model = QPATHTOF(data\tourniquet.p3d); descriptionShort = CSTRING(Tourniquet_Desc_Short); descriptionUse = CSTRING(Tourniquet_Desc_Use); + ACE_isMedicalItem = 1; class ItemInfo: CBA_MiscItem_ItemInfo { mass = 1; }; @@ -74,6 +80,7 @@ class CfgWeapons { picture = QPATHTOF(ui\splint_ca.paa); model = QPATHTOF(data\splint.p3d); descriptionShort = CSTRING(splint_Desc_Short); + ACE_isMedicalItem = 1; class ItemInfo: CBA_MiscItem_ItemInfo { mass = 2; }; @@ -86,6 +93,7 @@ class CfgWeapons { model = QPATHTOF(data\morphine.p3d); descriptionShort = CSTRING(Morphine_Desc_Short); descriptionUse = CSTRING(Morphine_Desc_Use); + ACE_isMedicalItem = 1; class ItemInfo: CBA_MiscItem_ItemInfo { mass = 1; }; @@ -98,6 +106,7 @@ class CfgWeapons { model = QPATHTOF(data\adenosine.p3d); descriptionShort = CSTRING(adenosine_Desc_Short); descriptionUse = CSTRING(adenosine_Desc_Use); + ACE_isMedicalItem = 1; class ItemInfo: CBA_MiscItem_ItemInfo { mass = 1; }; @@ -110,6 +119,7 @@ class CfgWeapons { model = QPATHTOF(data\atropine.p3d); descriptionShort = CSTRING(Atropine_Desc_Short); descriptionUse = CSTRING(Atropine_Desc_Use); + ACE_isMedicalItem = 1; class ItemInfo: CBA_MiscItem_ItemInfo { mass = 1; }; @@ -122,6 +132,7 @@ class CfgWeapons { model = QPATHTOF(data\epinephrine.p3d); descriptionShort = CSTRING(Epinephrine_Desc_Short); descriptionUse = CSTRING(Epinephrine_Desc_Use); + ACE_isMedicalItem = 1; class ItemInfo: CBA_MiscItem_ItemInfo { mass = 1; }; @@ -137,6 +148,7 @@ class CfgWeapons { picture = QPATHTOF(ui\plasmaIV_ca.paa); descriptionShort = CSTRING(Plasma_IV_Desc_Short); descriptionUse = CSTRING(Plasma_IV_Desc_Use); + ACE_isMedicalItem = 1; class ItemInfo: CBA_MiscItem_ItemInfo { mass = 10; }; @@ -167,6 +179,7 @@ class CfgWeapons { hiddenSelectionsTextures[] = {QPATHTOF(data\IVBag_blood_1000ml_ca.paa)}; descriptionShort = CSTRING(Blood_IV_Desc_Short); descriptionUse = CSTRING(Blood_IV_Desc_Use); + ACE_isMedicalItem = 1; class ItemInfo: CBA_MiscItem_ItemInfo { mass = 10; }; @@ -197,6 +210,7 @@ class CfgWeapons { picture = QPATHTOF(ui\salineIV_ca.paa); descriptionShort = CSTRING(Saline_IV_Desc_Short); descriptionUse = CSTRING(Saline_IV_Desc_Use); + ACE_isMedicalItem = 1; class ItemInfo: CBA_MiscItem_ItemInfo { mass = 10; }; @@ -225,6 +239,7 @@ class CfgWeapons { picture = QPATHTOF(ui\quickclot_ca.paa); descriptionShort = CSTRING(QuikClot_Desc_Short); descriptionUse = CSTRING(QuikClot_Desc_Use); + ACE_isMedicalItem = 1; class ItemInfo: CBA_MiscItem_ItemInfo { mass = 1; }; @@ -236,6 +251,7 @@ class CfgWeapons { picture = QPATHTOF(ui\personal_aid_kit_ca.paa); descriptionShort = CSTRING(Aid_Kit_Desc_Short); descriptionUse = CSTRING(Aid_Kit_Desc_Use); + ACE_isMedicalItem = 1; class ItemInfo: CBA_MiscItem_ItemInfo { mass = 10; }; @@ -248,6 +264,7 @@ class CfgWeapons { picture = QPATHTOF(ui\surgicalKit_ca.paa); descriptionShort = CSTRING(SurgicalKit_Desc_Short); descriptionUse = CSTRING(SurgicalKit_Desc_Use); + ACE_isMedicalItem = 1; class ItemInfo: CBA_MiscItem_ItemInfo { mass = 15; }; @@ -260,6 +277,7 @@ class CfgWeapons { picture = QPATHTOF(ui\suture_ca.paa); descriptionShort = CSTRING(Suture_Desc_Short); descriptionUse = CSTRING(Suture_Desc_Use); + ACE_isMedicalItem = 1; class ItemInfo: CBA_MiscItem_ItemInfo { mass = 1; }; @@ -272,6 +290,7 @@ class CfgWeapons { picture = QPATHTOF(ui\bodybag_ca.paa); descriptionShort = CSTRING(Bodybag_Desc_Short); descriptionUse = CSTRING(Bodybag_Desc_Use); + ACE_isMedicalItem = 1; class ItemInfo: CBA_MiscItem_ItemInfo { mass = 7; }; diff --git a/addons/medical_treatment/XEH_PREP.hpp b/addons/medical_treatment/XEH_PREP.hpp index be64563857..ab128aa49c 100644 --- a/addons/medical_treatment/XEH_PREP.hpp +++ b/addons/medical_treatment/XEH_PREP.hpp @@ -48,6 +48,7 @@ PREP(medicationLocal); PREP(onMedicationUsage); PREP(placeInBodyBag); PREP(removeBody); +PREP(scanMedicalItems); PREP(setTriageStatus); PREP(splint); PREP(splintLocal); diff --git a/addons/medical_treatment/XEH_preInit.sqf b/addons/medical_treatment/XEH_preInit.sqf index dfb6bf6518..30bf875291 100644 --- a/addons/medical_treatment/XEH_preInit.sqf +++ b/addons/medical_treatment/XEH_preInit.sqf @@ -8,6 +8,8 @@ PREP_RECOMPILE_END; #include "initSettings.sqf" +#define ARSENAL_CATEGORY_ICON (["\A3\ui_f\data\igui\cfg\actions\heal_ca.paa", QPATHTOEF(medical_gui,data\categories\bandage_fracture.paa)] select (["ace_medical_gui"] call EFUNC(common,isModLoaded))) + // config to determine animation acceleration coefficient // adjusting these is trail and error // if the animation is cut of ingame, increase these values @@ -44,4 +46,9 @@ GVAR(facilityClasses) = []; } forEach getArray _x; } forEach configProperties [configFile >> QEGVAR(medical,facilities), "isArray _x"]; +// Custom Arsenal tab +if (["ace_arsenal"] call EFUNC(common,isModLoaded)) then { + [MEDICAL_TREATMENT_ITEMS, LELSTRING(medical,Category), ARSENAL_CATEGORY_ICON] call EFUNC(arsenal,addRightPanelButton); +}; + ADDON = true; diff --git a/addons/medical_treatment/XEH_preStart.sqf b/addons/medical_treatment/XEH_preStart.sqf index 022888575e..27f8f2d9c2 100644 --- a/addons/medical_treatment/XEH_preStart.sqf +++ b/addons/medical_treatment/XEH_preStart.sqf @@ -1,3 +1,5 @@ #include "script_component.hpp" #include "XEH_PREP.hpp" + +call FUNC(scanMedicalItems) diff --git a/addons/medical_treatment/functions/fnc_scanMedicalItems.sqf b/addons/medical_treatment/functions/fnc_scanMedicalItems.sqf new file mode 100644 index 0000000000..17b2456c42 --- /dev/null +++ b/addons/medical_treatment/functions/fnc_scanMedicalItems.sqf @@ -0,0 +1,34 @@ +#include "script_component.hpp" +/* + * Author: Salluci + * Caches all item classnames used in ACE_Medical_Treatment_Actions + * + * Arguments: + * None + * + * Return Value: + * None + * + * Example: + * call ace_medical_treatment_fnc_scanMedicalItems + * + * Public: No + */ + +private _list = []; +private _cfgActions = configFile >> QGVAR(actions); + +private _fnc_isMedicalItem = toString { + getNumber (_x >> "ACE_isMedicalItem") isEqualTo 1 +}; + +// get items in ACE_Medical_Treament_Actions, fallback for items without API config property +{ + _list append (getArray (_x >> "items")); +} forEach ("true" configClasses _cfgActions); + +{ + _list pushBack (configName _x); +} forEach (_fnc_isMedicalItem configClasses (configFile >> "CfgWeapons")); + +uiNamespace setVariable [QGVAR(treatmentItems), compileFinal str (_list arrayIntersect _list)] diff --git a/addons/medical_treatment/script_component.hpp b/addons/medical_treatment/script_component.hpp index 682e8a471c..36173d4ac1 100644 --- a/addons/medical_treatment/script_component.hpp +++ b/addons/medical_treatment/script_component.hpp @@ -54,3 +54,5 @@ // Animations that would be played faster than this are instead skipped. (= Progress bar too quick for animation). #define ANIMATION_SPEED_MAX_COEFFICIENT 2.5 + +#define MEDICAL_TREATMENT_ITEMS (call (uiNamespace getVariable [QGVAR(treatmentItems), {[]}])) diff --git a/docs/wiki/framework/medical-treatment-framework.md b/docs/wiki/framework/medical-treatment-framework.md index a3f5d04de1..adb9cd485d 100644 --- a/docs/wiki/framework/medical-treatment-framework.md +++ b/docs/wiki/framework/medical-treatment-framework.md @@ -38,3 +38,21 @@ class CfgVehicles { }; }; ``` +### 1.3 Treatment Items + +Items in `CfgWeapons` with `ACE_isMedicalItem` property will be added to the ACE Medical category in the ACE Arsenal. +```cpp +class CfgWeapons { + class MyMedicalItem { + ACE_isMedicalItem = 1; + }; +}; +``` +Required items in `ACE_Medical_Treatment_Actions` will also be added as a fallback. +```cpp +class ACE_Medical_Treatment_Actions { + class MyCustomTreatment { + items[] = {"MyMedicalItem"}; + }; +}; +``` From 45af0cdca065c3dea2f474396a32812a6fb327a8 Mon Sep 17 00:00:00 2001 From: Grim <69561145+LinkIsGrim@users.noreply.github.com> Date: Fri, 7 Jul 2023 08:19:45 +0300 Subject: [PATCH 08/16] Medical Treatment - Remove early exit when stitching with sutures (#9243) --- .../medical_treatment/functions/fnc_surgicalKitProgress.sqf | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/addons/medical_treatment/functions/fnc_surgicalKitProgress.sqf b/addons/medical_treatment/functions/fnc_surgicalKitProgress.sqf index 8fc4832f8f..f7ed35e412 100644 --- a/addons/medical_treatment/functions/fnc_surgicalKitProgress.sqf +++ b/addons/medical_treatment/functions/fnc_surgicalKitProgress.sqf @@ -83,9 +83,7 @@ if ( }; // Consume a suture for the next wound if one exists, stop stitching if none are left -if (GVAR(consumeSurgicalKit) == 2) then { - // Don't consume a suture if there are no more wounds to stitch - if (_bandagedWoundsOnPart isEqualTo []) exitWith {false}; +if (GVAR(consumeSurgicalKit) == 2 && {_bandagedWoundsOnPart isNotEqualTo []}) then { ([_medic, _patient, ["ACE_suture"]] call FUNC(useItem)) params ["_user"]; !isNull _user } else { From 29b5eb97a95e187403cd4f8ae6ba8e33e7b20909 Mon Sep 17 00:00:00 2001 From: Tim Beswick Date: Sun, 9 Jul 2023 15:33:51 +0100 Subject: [PATCH 09/16] Medical - Handle wound hashmaps deserialized as CBA_namespaces (#9245) --- addons/medical/functions/fnc_deserializeState.sqf | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/addons/medical/functions/fnc_deserializeState.sqf b/addons/medical/functions/fnc_deserializeState.sqf index 2002abf59e..8f9d60b6e3 100644 --- a/addons/medical/functions/fnc_deserializeState.sqf +++ b/addons/medical/functions/fnc_deserializeState.sqf @@ -56,6 +56,13 @@ private _state = [_json] call CBA_fnc_parseJSON; _x params ["_var", "_default"]; private _value = _state getVariable _x; + // Handle wound hashmaps deserialized as CBA_namespaces + if (typeName _value == "LOCATION") then { + private _keys = allVariables _value; + private _values = _keys apply {_value getVariable _x}; + _value = _keys createHashMapFromArray _values; + }; + // Treat null as nil if (_value isEqualTo objNull) then { _value = _default; From 05c9e4247b15baa7912d0ab9be6c5c0701c85a89 Mon Sep 17 00:00:00 2001 From: Will <100206101+SpicyBagpipes@users.noreply.github.com> Date: Sun, 9 Jul 2023 17:37:30 +0100 Subject: [PATCH 10/16] Logistics Wirecutter - Add modded class support (#9235) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update script_component.hpp Change check for wire cutters for all child classes in addition to current class * Update script_component.hpp fix bracket * Change isKindOf for alt syntax Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> * Update addons/logistics_wirecutter/script_component.hpp Better performing searching for wirecutter Co-authored-by: BrettMayson * Update XEH_postInit.sqf Index all possible wirecutters * Update script_component.hpp arrayIntersect with possible wirecutters * Update XEH_postInit.sqf Incorrect quotes * Update CfgWeapons.hpp Add iswirecutter to wirecutter * Update XEH_postInit.sqf Remove pointless parentheses * Update addons/logistics_wirecutter/script_component.hpp fix for incorrect arrayintersect check Co-authored-by: PabstMirror * Update addons/logistics_wirecutter/XEH_postInit.sqf Incorrect quoting Co-authored-by: Jouni Järvinen * use configClasses and cache at preStart --------- Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> Co-authored-by: BrettMayson Co-authored-by: PabstMirror Co-authored-by: Jouni Järvinen --- addons/logistics_wirecutter/CfgWeapons.hpp | 1 + addons/logistics_wirecutter/XEH_postInit.sqf | 2 ++ addons/logistics_wirecutter/XEH_preStart.sqf | 4 ++++ addons/logistics_wirecutter/script_component.hpp | 2 +- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/addons/logistics_wirecutter/CfgWeapons.hpp b/addons/logistics_wirecutter/CfgWeapons.hpp index cfaa6c3259..5c66196f4a 100644 --- a/addons/logistics_wirecutter/CfgWeapons.hpp +++ b/addons/logistics_wirecutter/CfgWeapons.hpp @@ -8,6 +8,7 @@ class CfgWeapons { descriptionShort = CSTRING(wirecutterDescription); model = QPATHTOF(data\ace_wirecutter.p3d); picture = QPATHTOF(ui\item_wirecutter_ca.paa); + ACE_isWirecutter = 1; scope = 2; class ItemInfo: CBA_MiscItem_ItemInfo { mass = 25; diff --git a/addons/logistics_wirecutter/XEH_postInit.sqf b/addons/logistics_wirecutter/XEH_postInit.sqf index a22479e7e1..29dc506396 100644 --- a/addons/logistics_wirecutter/XEH_postInit.sqf +++ b/addons/logistics_wirecutter/XEH_postInit.sqf @@ -7,3 +7,5 @@ if (hasInterface) then { if (isServer) then { [QGVAR(destroyFence), {_this call FUNC(destroyFence)}] call CBA_fnc_addEventHandler; }; + +GVAR(possibleWirecutters) = call (uiNamespace getVariable [QGVAR(possibleWirecutters), {[]}]); diff --git a/addons/logistics_wirecutter/XEH_preStart.sqf b/addons/logistics_wirecutter/XEH_preStart.sqf index 022888575e..75567fe26e 100644 --- a/addons/logistics_wirecutter/XEH_preStart.sqf +++ b/addons/logistics_wirecutter/XEH_preStart.sqf @@ -1,3 +1,7 @@ #include "script_component.hpp" #include "XEH_PREP.hpp" + +// Cache wirecutter item classes, see XEH_postInit.sqf +private _possibleWirecutters = ("getNumber (_x >> 'ACE_isWirecutter') == 1" configClasses (configFile >> "CfgWeapons")) apply {configName _x}; +uiNamespace setVariable [QGVAR(possibleWirecutters), compileFinal str _possibleWirecutters]; diff --git a/addons/logistics_wirecutter/script_component.hpp b/addons/logistics_wirecutter/script_component.hpp index a499b6ae32..7335ef2e57 100644 --- a/addons/logistics_wirecutter/script_component.hpp +++ b/addons/logistics_wirecutter/script_component.hpp @@ -88,7 +88,7 @@ #define CUT_TIME_ENGINEER 7.5 #define HAS_WIRECUTTER(unit) (\ - "ACE_wirecutter" in (unit call EFUNC(common,uniqueItems)) \ + ((unit call EFUNC(common,uniqueItems)) arrayIntersect GVAR(possibleWirecutters)) isNotEqualTo []\ || {getNumber ((configOf (backpackContainer unit)) >> QGVAR(hasWirecutter)) == 1} \ || {getNumber (configFile >> "CfgWeapons" >> (vest unit) >> QGVAR(hasWirecutter)) == 1} \ ) From ab2207924f6311fcb15dd6372cccc27ca1db682d Mon Sep 17 00:00:00 2001 From: Will <100206101+SpicyBagpipes@users.noreply.github.com> Date: Sun, 9 Jul 2023 19:14:54 +0100 Subject: [PATCH 11/16] Logistics Wirecutter - Add documentation (#9248) * Create wirecutter-framework.md * Update docs/wiki/framework/wirecutter-framework.md --------- Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> --- docs/wiki/framework/wirecutter-framework.md | 41 +++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 docs/wiki/framework/wirecutter-framework.md diff --git a/docs/wiki/framework/wirecutter-framework.md b/docs/wiki/framework/wirecutter-framework.md new file mode 100644 index 0000000000..3f2a97c0b1 --- /dev/null +++ b/docs/wiki/framework/wirecutter-framework.md @@ -0,0 +1,41 @@ +--- +layout: wiki +title: Wirecutter Framework +description: Explains how to set-up items, backpacks and vests with ACE3 wirecutter system. +group: framework +order: 5 +parent: wiki +mod: ace +version: + major: 3 + minor: 16 + patch: 0 +--- + +## 1. Config Values + +The properties below control whether an item is considered a wirecutter. Worn items (vests and backpacks) can have "built-in" wirecutters with the `ace_logistics_wirecutter_hasWirecutter` property. +```cpp +class CfgWeapons { + class MyVest { + ace_logistics_wirecutter_hasWirecutter = 1; //1 for true, 0 for false. + }; + class MyItem { + ACE_isWirecutter = 1; //1 for true, 0 for false. + }; +}; +class CfgVehicles { + class MyBackpack { + ace_logistics_wirecutter_hasWirecutter = 1; //1 for true, 0 for false. + }; +}; +``` + + +## 2. Events + +### 2.1 Listenable + +Event Name | Description | Passed Parameter(s) | Locality +---------- | ----------- | ------------------- | -------- +`ace_wireCuttingStarted` | Wire cutting started | `[_unit, _fence]` | Global From 1aa7eb2a1a5d4a1085455ecdfc3a49875ee1a487 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sun, 9 Jul 2023 22:41:12 +0200 Subject: [PATCH 12/16] Update fnc_codeToString.sqf (#9249) --- addons/common/functions/fnc_codeToString.sqf | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/addons/common/functions/fnc_codeToString.sqf b/addons/common/functions/fnc_codeToString.sqf index b938148220..8d746e9024 100644 --- a/addons/common/functions/fnc_codeToString.sqf +++ b/addons/common/functions/fnc_codeToString.sqf @@ -16,10 +16,7 @@ */ params ["_code"]; + if (_code isEqualType "") exitWith {_code}; -_code = str(_code); -_code = _code select [1, count _code - 2]; - -_code - +toString _code From e181ba5aa1f659fe05b7833f256a2557b2d40d9d Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sun, 9 Jul 2023 23:13:43 +0200 Subject: [PATCH 13/16] Gunbag - Fix arsenal caching conflicting with CBA_fnc_setLoadout (#9250) * Update XEH_preInit.sqf * Update addons/gunbag/XEH_preInit.sqf --------- Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> --- addons/gunbag/XEH_preInit.sqf | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/addons/gunbag/XEH_preInit.sqf b/addons/gunbag/XEH_preInit.sqf index 78c6741dbb..7829c58074 100644 --- a/addons/gunbag/XEH_preInit.sqf +++ b/addons/gunbag/XEH_preInit.sqf @@ -49,6 +49,11 @@ PREP_RECOMPILE_END; private _gunbagWeapon = _extendedInfo getOrDefault [QGVAR(gunbagWeapon), []]; if (_gunbagWeapon isNotEqualTo []) then { (backpackContainer _unit) setVariable [QGVAR(gunbagWeapon), _gunbagWeapon, true]; + + // Prevent the arsenal closed event from overwriting new info + if (!isNil QGVAR(arsenalCache)) then { + GVAR(arsenalCache) = _gunbagWeapon; + }; }; }] call CBA_fnc_addEventHandler; From 1b8c56f0bed068a75d10978ea1187759272b7e9c Mon Sep 17 00:00:00 2001 From: Dystopian Date: Mon, 10 Jul 2023 05:49:37 +0300 Subject: [PATCH 14/16] Interaction - Add actions to access and allow carrying inventory holders (#6029) * Add interaction to inventory holders * Add Take Weapon action * Add Drag/Carry actions * Fix menu position * Add Inventory action also to unconscious * Underwater: Fix menu position, disable gear action * Add dead body weapons carrying with workaround * Disable man gear action in water * Optimize position code * Fix macro using * Use macro and power * Restrict max dragged items count * Remove superfluous condition, Add Take action to all holders * Cleanup XEH * Remove weapon carry-drop workaround * code style changes * code style changes * brackets, isEqualTo, vehicle check * code style changes * brackets, isEqualTo, vehicle check --------- Co-authored-by: Salluci --- addons/dragging/CfgEventHandlers.hpp | 5 +++ addons/dragging/CfgVehicles.hpp | 26 ++++++++++++++ addons/dragging/functions/fnc_canCarry.sqf | 25 ++++++++++--- addons/dragging/functions/fnc_canDrag.sqf | 25 ++++++++++--- addons/dragging/script_component.hpp | 2 ++ addons/interaction/CfgVehicles.hpp | 41 ++++++++++++++++++++++ addons/interaction/XEH_postInit.sqf | 18 ++++++++++ 7 files changed, 132 insertions(+), 10 deletions(-) diff --git a/addons/dragging/CfgEventHandlers.hpp b/addons/dragging/CfgEventHandlers.hpp index d1f8a87636..8903f2ded8 100644 --- a/addons/dragging/CfgEventHandlers.hpp +++ b/addons/dragging/CfgEventHandlers.hpp @@ -40,6 +40,11 @@ class Extended_Init_EventHandlers { init = QUOTE(_this call DFUNC(initObject)); }; }; + class WeaponHolder { + class ADDON { + init = QUOTE(_this call DFUNC(initObject)); + }; + }; class Land_Camping_Light_F { class ADDON { init = QUOTE(_this call DFUNC(initObject)); diff --git a/addons/dragging/CfgVehicles.hpp b/addons/dragging/CfgVehicles.hpp index cea1675565..c972a6514f 100644 --- a/addons/dragging/CfgVehicles.hpp +++ b/addons/dragging/CfgVehicles.hpp @@ -226,6 +226,32 @@ class CfgVehicles { GVAR(canCarry) = 1; }; + // weapons dropped from dead body + class WeaponHolderSimulated: ThingX { + GVAR(canCarry) = 1; + GVAR(carryPosition[]) = {0,0.5,1.3}; + GVAR(carryDirection) = 0; + + // z-position floats from -1.2 to >0 + // it's OK for carrying but odd for dragging + // needs workaround to drag correctly. Disabled ATM + GVAR(canDrag) = 0; + GVAR(dragPosition[]) = {0,1,0}; + GVAR(dragDirection) = 0; + }; + + class ReammoBox; + // dropped weapons/gear + class WeaponHolder: ReammoBox { + GVAR(canCarry) = 1; + GVAR(carryPosition[]) = {0,0.5,1}; + GVAR(carryDirection) = 0; + + GVAR(canDrag) = 1; + GVAR(dragPosition[]) = {0,1,0}; + GVAR(dragDirection) = 0; + }; + class Lamps_base_F; class Land_PortableLight_single_F: Lamps_base_F { GVAR(canCarry) = 1; diff --git a/addons/dragging/functions/fnc_canCarry.sqf b/addons/dragging/functions/fnc_canCarry.sqf index 2483903eef..41fc983ba7 100644 --- a/addons/dragging/functions/fnc_canCarry.sqf +++ b/addons/dragging/functions/fnc_canCarry.sqf @@ -1,6 +1,6 @@ #include "script_component.hpp" /* - * Author: commy2 + * Author: commy2, Dystopian * Check if unit can carry the object. Doesn't check weight. * * Arguments: @@ -11,20 +11,35 @@ * Can the unit carry the object? * * Example: - * [player, cursorTarget] call ace_dragging_fnc_canCarry; + * [player, cursorTarget] call ace_dragging_fnc_canCarry * * Public: No */ params ["_unit", "_target"]; +if !(alive _target && {_target getVariable [QGVAR(canCarry), false]} && {isNull objectParent _target}) exitWith {false}; + if !([_unit, _target, []] call EFUNC(common,canInteractWith)) exitWith {false}; //#2644 - Units with injured legs cannot bear the extra weight of carrying an object //The fireman carry animation does not slow down for injured legs, so you could carry and run if ((_unit getHitPointDamage "HitLegs") >= 0.5) exitWith {false}; -// a static weapon has to be empty for dragging (ignore UAV AI) -if (((typeOf _target) isKindOf "StaticWeapon") && {{(getText (configOf _x >> "simulation")) != "UAVPilot"} count crew _target > 0}) exitWith {false}; +// Static weapons need to be empty for carrying (ignore UAV AI) +if (_target isKindOf "StaticWeapon") exitWith { + crew _target findIf {getText (configOf _x >> "simulation") != "UAVPilot"} == -1 +}; -alive _target && {vehicle _target isEqualto _target} && {_target getVariable [QGVAR(canCarry), false]} && {animationState _target in ["", "unconscious"] || (_target getVariable ["ACE_isUnconscious", false]) || (_target isKindOf "CAManBase" && {(_target getHitPointDamage "HitLegs") > 0.4})} +// Units need to be unconscious or be limping +if (_target isKindOf "CAManBase") exitWith { + lifeState _target isEqualTo "INCAPACITATED" + || {_target getHitPointDamage "HitLegs" > 0.4} +}; + +// Check max items for WeaponHolders +if (["WeaponHolder", "WeaponHolderSimulated"] findIf {_target isKindOf _x} != -1) exitWith { + (count (weaponCargo _target + magazineCargo _target + itemCargo _target)) <= MAX_DRAGGED_ITEMS +}; + +true // return diff --git a/addons/dragging/functions/fnc_canDrag.sqf b/addons/dragging/functions/fnc_canDrag.sqf index afc679e375..82cb33068b 100644 --- a/addons/dragging/functions/fnc_canDrag.sqf +++ b/addons/dragging/functions/fnc_canDrag.sqf @@ -1,6 +1,6 @@ #include "script_component.hpp" /* - * Author: commy2 + * Author: commy2, Dystopian * Check if unit can drag the object. Doesn't check weight. * * Arguments: @@ -11,16 +11,31 @@ * Can the unit drag the object? * * Example: - * [player, cursorTarget] call ace_dragging_fnc_canDrag; + * [player, cursorTarget] call ace_dragging_fnc_canDrag * * Public: No */ params ["_unit", "_target"]; +if !(alive _target && {_target getVariable [QGVAR(canDrag), false]} && {isNull objectParent _target}) exitWith {false}; + if !([_unit, _target, ["isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; -// a static weapon has to be empty for dragging (ignore UAV AI) -if ((typeOf _target) isKindOf "StaticWeapon" && {{(getText (configOf _x >> "simulation")) != "UAVPilot"} count crew _target > 0}) exitWith {false}; +// Static weapons need to be empty for dragging (ignore UAV AI) +if (_target isKindOf "StaticWeapon") exitWith { + crew _target findIf {getText (configOf _x >> "simulation") != "UAVPilot"} == -1 +}; -alive _target && {vehicle _target isEqualto _target} && {_target getVariable [QGVAR(canDrag), false]} && {animationState _target in ["", "unconscious"] || (_target getVariable ["ACE_isUnconscious", false]) || (_target isKindOf "CAManBase" && {(_target getHitPointDamage "HitLegs") > 0.4})} +// Units need to be unconscious or be limping +if (_target isKindOf "CAManBase") exitWith { + lifeState _target isEqualTo "INCAPACITATED" + || {_target getHitPointDamage "HitLegs" > 0.4} +}; + +// Check max items for WeaponHolders +if (["WeaponHolder", "WeaponHolderSimulated"] findIf {_target isKindOf _x} != -1) exitWith { + (count (weaponCargo _target + magazineCargo _target + itemCargo _target)) <= MAX_DRAGGED_ITEMS +}; + +true // return diff --git a/addons/dragging/script_component.hpp b/addons/dragging/script_component.hpp index 5befaede9c..ed1ad0fb37 100644 --- a/addons/dragging/script_component.hpp +++ b/addons/dragging/script_component.hpp @@ -20,3 +20,5 @@ #define DRAG_ANIMATIONS ["amovpercmstpslowwrfldnon_acinpknlmwlkslowwrfldb_2", "amovpercmstpsraswpstdnon_acinpknlmwlksnonwpstdb_2", "amovpercmstpsnonwnondnon_acinpknlmwlksnonwnondb_2", "acinpknlmstpsraswrfldnon", "acinpknlmstpsnonwpstdnon", "acinpknlmstpsnonwnondnon", "acinpknlmwlksraswrfldb", "acinpknlmwlksnonwnondb", "ace_dragging", "ace_dragging_static", "ace_dragging_drop"] #define CARRY_ANIMATIONS ["acinpercmstpsnonwnondnon", "acinpknlmstpsnonwnondnon_acinpercmrunsnonwnondnon"] + +#define MAX_DRAGGED_ITEMS 3 diff --git a/addons/interaction/CfgVehicles.hpp b/addons/interaction/CfgVehicles.hpp index c88e93c095..57753dfaff 100644 --- a/addons/interaction/CfgVehicles.hpp +++ b/addons/interaction/CfgVehicles.hpp @@ -162,6 +162,12 @@ class CfgVehicles { exceptions[] = {"isNotSwimming"}; icon = "\a3\ui_f\data\IGUI\Cfg\simpleTasks\types\getout_ca.paa"; }; + class GVAR(Gear) { + displayName = "$STR_ACTION_GEAR"; + condition = QUOTE(!(lifeState _target in [ARR_2('HEALTHY','INJURED')]) && {isNull objectParent _target}); + statement = QUOTE(_player action [ARR_2(QUOTE(QUOTE(Gear)),_target)]); + icon = "\A3\ui_f\data\igui\cfg\actions\gear_ca.paa"; + }; }; class ACE_Torso { @@ -693,6 +699,41 @@ class CfgVehicles { class ACE_SelfActions {}; }; + // weapons dropped from dead body + class WeaponHolderSimulated: ThingX { + class ACE_Actions { + class ACE_MainActions { + displayName = CSTRING(MainAction); + distance = 3; + position = QUOTE(_target worldToModel ASLToAGL getPosASL _target); + + class GVAR(Gear) { + displayName = "$STR_ACTION_GEAR"; + statement = QUOTE(_player action [ARR_2(QUOTE(QUOTE(Gear)),_target)]); + icon = "\A3\ui_f\data\igui\cfg\actions\gear_ca.paa"; + }; + }; + }; + }; + + class ReammoBox; + // dropped weapons/gear + class WeaponHolder: ReammoBox { + class ACE_Actions { + class ACE_MainActions { + displayName = CSTRING(MainAction); + distance = 3; + position = QUOTE(_target worldToModel ASLToAGL getPosASL _target); + + class GVAR(Gear) { + displayName = "$STR_ACTION_GEAR"; + statement = QUOTE(_player action [ARR_2(QUOTE(QUOTE(Gear)),_target)]); + icon = "\A3\ui_f\data\igui\cfg\actions\gear_ca.paa"; + }; + }; + }; + }; + class Lamps_base_F; class Land_PortableLight_single_F: Lamps_base_F { class EventHandlers { diff --git a/addons/interaction/XEH_postInit.sqf b/addons/interaction/XEH_postInit.sqf index 6d7d96713c..75e92c02c9 100644 --- a/addons/interaction/XEH_postInit.sqf +++ b/addons/interaction/XEH_postInit.sqf @@ -161,3 +161,21 @@ GVAR(isOpeningDoor) = false; [QGVAR(clearWeaponAttachmentsActionsCache)] call CBA_fnc_localEvent; }] call CBA_fnc_addPlayerEventHandler; } forEach ["loadout", "weapon"]; + + +// add "Take _weapon_" action to dropped weapons +private _action = [ + // action display name will be overwritten in modifier function + QGVAR(takeWeapon), "take", "\A3\ui_f\data\igui\cfg\actions\take_ca.paa", + {_player action ["TakeWeapon", _target, weaponCargo _target select 0]}, + {count weaponCargo _target == 1}, + nil, nil, nil, nil, nil, + { + params ["_target", "", "", "_actionData"]; + _actionData set [1, format [localize "STR_ACTION_TAKE_BAG", getText (configfile >> "CfgWeapons" >> weaponCargo _target select 0 >> "displayName")]]; + } +] call EFUNC(interact_menu,createAction); + +{ + [_x, 0, ["ACE_MainActions"], _action, true] call EFUNC(interact_menu,addActionToClass); +} forEach ["WeaponHolder", "WeaponHolderSimulated"]; From 8032ccacfc827c7baabe79bfdf099484ceb6c1ed Mon Sep 17 00:00:00 2001 From: Grim <69561145+LinkIsGrim@users.noreply.github.com> Date: Mon, 10 Jul 2023 06:45:22 +0300 Subject: [PATCH 15/16] Common - Add `FUNC(hasZeusAccess)` (#9252) * add fnc_hasZeusAccess * header * Update addons/common/functions/fnc_hasZeusAccess.sqf --------- Co-authored-by: PabstMirror --- addons/common/XEH_PREP.hpp | 1 + addons/common/functions/fnc_hasZeusAccess.sqf | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 addons/common/functions/fnc_hasZeusAccess.sqf diff --git a/addons/common/XEH_PREP.hpp b/addons/common/XEH_PREP.hpp index 2706ca45e2..323f2c1d0d 100644 --- a/addons/common/XEH_PREP.hpp +++ b/addons/common/XEH_PREP.hpp @@ -105,6 +105,7 @@ PREP(handleModifierKey); PREP(handleModifierKeyUp); PREP(hasItem); PREP(hasMagazine); +PREP(hasZeusAccess); PREP(headBugFix); PREP(hideUnit); PREP(interpolateFromArray); diff --git a/addons/common/functions/fnc_hasZeusAccess.sqf b/addons/common/functions/fnc_hasZeusAccess.sqf new file mode 100644 index 0000000000..057e4b1f0f --- /dev/null +++ b/addons/common/functions/fnc_hasZeusAccess.sqf @@ -0,0 +1,19 @@ +#include "script_component.hpp" +/* + * Author: LinkIsGrim + * Check if current player has Zeus access + * + * Arguments: + * None + * + * Return Value: + * Has Zeus + * + * Example: + * call ace_common_fnc_hasZeusAccess + * + * Public: Yes + */ + +// Use of player is intentional +!isNull getAssignedCuratorLogic player // return From 535662b883e0a0013ee4ff19b67f5571e357088e Mon Sep 17 00:00:00 2001 From: Grim <69561145+LinkIsGrim@users.noreply.github.com> Date: Mon, 10 Jul 2023 06:45:53 +0300 Subject: [PATCH 16/16] Dragging - Add limping check to carrier and improve limping check for target unit (#9251) * fix limping damage threshold * add check for carrier not limping --- addons/dragging/functions/fnc_canCarry.sqf | 4 ++-- addons/dragging/functions/fnc_canDrag.sqf | 4 ++-- addons/dragging/functions/fnc_carryObjectPFH.sqf | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/addons/dragging/functions/fnc_canCarry.sqf b/addons/dragging/functions/fnc_canCarry.sqf index 41fc983ba7..dac874f6c0 100644 --- a/addons/dragging/functions/fnc_canCarry.sqf +++ b/addons/dragging/functions/fnc_canCarry.sqf @@ -31,10 +31,10 @@ if (_target isKindOf "StaticWeapon") exitWith { crew _target findIf {getText (configOf _x >> "simulation") != "UAVPilot"} == -1 }; -// Units need to be unconscious or be limping +// Units need to be unconscious or limping if (_target isKindOf "CAManBase") exitWith { lifeState _target isEqualTo "INCAPACITATED" - || {_target getHitPointDamage "HitLegs" > 0.4} + || {_target getHitPointDamage "HitLegs" >= 0.5} }; // Check max items for WeaponHolders diff --git a/addons/dragging/functions/fnc_canDrag.sqf b/addons/dragging/functions/fnc_canDrag.sqf index 82cb33068b..8336e20f2d 100644 --- a/addons/dragging/functions/fnc_canDrag.sqf +++ b/addons/dragging/functions/fnc_canDrag.sqf @@ -27,10 +27,10 @@ if (_target isKindOf "StaticWeapon") exitWith { crew _target findIf {getText (configOf _x >> "simulation") != "UAVPilot"} == -1 }; -// Units need to be unconscious or be limping +// Units need to be unconscious or limping if (_target isKindOf "CAManBase") exitWith { lifeState _target isEqualTo "INCAPACITATED" - || {_target getHitPointDamage "HitLegs" > 0.4} + || {_target getHitPointDamage "HitLegs" >= 0.5} }; // Check max items for WeaponHolders diff --git a/addons/dragging/functions/fnc_carryObjectPFH.sqf b/addons/dragging/functions/fnc_carryObjectPFH.sqf index 93e35547ad..072b688b9d 100644 --- a/addons/dragging/functions/fnc_carryObjectPFH.sqf +++ b/addons/dragging/functions/fnc_carryObjectPFH.sqf @@ -33,8 +33,8 @@ if !(_unit getVariable [QGVAR(isCarrying), false]) exitWith { [_idPFH] call CBA_fnc_removePerFrameHandler; }; -// drop if the crate is destroyed OR (target moved away from carrier (weapon disasembled)) -if (!alive _target || {_unit distance _target > 10}) exitWith { +// drop if the crate is destroyed OR target moved away from carrier (weapon disassembled) OR carrier starts limping +if !(alive _target && {_unit distance _target <= 10} && {_unit getHitPointDamage "HitLegs" < 0.5}) exitWith { TRACE_2("dead/distance",_unit,_target); if ((_unit distance _target > 10) && {(CBA_missionTime - _startTime) < 1}) exitWith { //attachTo seems to have some kind of network delay and target can return an odd position during the first few frames,