diff --git a/addons/arsenal/CfgWeapons.hpp b/addons/arsenal/CfgWeapons.hpp index c45bb7d5ece..0539a58bac1 100644 --- a/addons/arsenal/CfgWeapons.hpp +++ b/addons/arsenal/CfgWeapons.hpp @@ -3,6 +3,12 @@ class CfgWeapons { class ToolKit: ItemCore { ACE_isTool = 1; // sort in Tools Tab }; + + class ChemicalDetector_01_base_F: ItemCore { + ACE_asItem = 1; + ACE_isTool = 1; // sort in Tools Tab + }; + class DetectorCore; class MineDetector: DetectorCore { ACE_isTool = 1; // sort in Tools Tab diff --git a/addons/arsenal/XEH_PREP.hpp b/addons/arsenal/XEH_PREP.hpp index d0819056f25..b69ff0cb749 100644 --- a/addons/arsenal/XEH_PREP.hpp +++ b/addons/arsenal/XEH_PREP.hpp @@ -51,6 +51,7 @@ PREP(handleSearchInputChanged); PREP(handleSearchModeToggle); PREP(handleStats); PREP(initBox); +PREP(isMiscItem); PREP(itemInfo); PREP(loadoutsChangeTab); PREP(message); diff --git a/addons/arsenal/XEH_preStart.sqf b/addons/arsenal/XEH_preStart.sqf index 7e561340104..867d308874a 100644 --- a/addons/arsenal/XEH_preStart.sqf +++ b/addons/arsenal/XEH_preStart.sqf @@ -9,5 +9,6 @@ uiNamespace setVariable [QGVAR(baseWeaponNameCache), createHashMap]; uiNamespace setVariable [QGVAR(addListBoxItemCache), createHashMap]; uiNamespace setVariable [QGVAR(rightPanelCache), createHashMap]; uiNamespace setVariable [QGVAR(sortCache), createHashMap]; +uiNamespace setVariable [QGVAR(isMiscItemCache), createHashMap]; call FUNC(scanConfig); diff --git a/addons/arsenal/functions/fnc_addRightPanelButton.sqf b/addons/arsenal/functions/fnc_addRightPanelButton.sqf index a1bdb09d1d1..2137c2a4260 100644 --- a/addons/arsenal/functions/fnc_addRightPanelButton.sqf +++ b/addons/arsenal/functions/fnc_addRightPanelButton.sqf @@ -56,20 +56,9 @@ if (!isNil "_currentButtonInPosition") then { }; // If spot found, add items and return position -private _cfgWeapons = configFile >> "CfgWeapons"; -private _cfgMagazines = configFile >> "CfgMagazines"; -private _configItemInfo = ""; +// Sanitize to configCase and drop anything that's not a misc item +_items = _items apply {_x call EFUNC(common,getConfigName)} select {_x call FUNC(isMiscItem)}; -_items = _items select { - _configItemInfo = _cfgWeapons >> _x >> "ItemInfo"; - - _x isKindOf ["CBA_MiscItem", _cfgWeapons] && {getNumber (_configItemInfo >> "type") in [TYPE_MUZZLE, TYPE_OPTICS, TYPE_FLASHLIGHT, TYPE_BIPOD]} || - {getNumber (_configItemInfo >> "type") in [TYPE_FIRST_AID_KIT, TYPE_MEDIKIT, TYPE_TOOLKIT]} || - {getText (_cfgWeapons >> _x >> "simulation") == "ItemMineDetector"} || - {getNumber (_cfgMagazines >> _x >> "ACE_isUnique") == 1} || - {getNumber (_cfgMagazines >> _x >> "ACE_asItem") == 1} -}; - -GVAR(customRightPanelButtons) set [_position, [_items apply {_x call EFUNC(common,getConfigName)}, _picture, _tooltip, _moveOnOverwrite]]; +GVAR(customRightPanelButtons) set [_position, [_items, _picture, _tooltip, _moveOnOverwrite]]; _position diff --git a/addons/arsenal/functions/fnc_isMiscItem.sqf b/addons/arsenal/functions/fnc_isMiscItem.sqf new file mode 100644 index 00000000000..b132a5549bc --- /dev/null +++ b/addons/arsenal/functions/fnc_isMiscItem.sqf @@ -0,0 +1,54 @@ +#include "..\script_component.hpp" +/* + * Author: DartRuffian, LinkIsGrim + * Determines if a class is a miscellaneous item or not. + * + * Arguments: + * 0: Item or magazine + * 1: Item config (default: nil) + * 2: Whether item is a magazine (default: false) + * 3: Skip setting false keys in the cache, mostly used for building it during preStart (default: false) + * + * Return Value: + * True if class is a misc item, otherwise false + * + * Example: + * "ACE_CableTie" call ace_arsenal_fnc_isMiscItem + * + * Public: No +*/ + +params ["_item", "_config", ["_isMag", false], ["_skipFalseKeys", false]]; +TRACE_4("",_item,_config,_isMag,_skipFalseKeys); + +private _cache = uiNamespace getVariable QGVAR(isMiscItemCache); +private _return = _cache get _item; + +// Don't replace with getOrDefaultCall, we want the key to only be set if return is true or _skipFalseKeys is false +if (isNil "_return") then { + private _fnc_hasProperty = {getNumber (_config >> "ACE_asItem") == 1 || {getNumber (_config >> "ACE_isUnique") == 1}}; + + _return = switch (true) do { + case (_item isKindOf ["CBA_MiscItem", configFile >> "CfgWeapons"]): {true}; // CBA misc item, easy + + if (isNil "_config") then { + _config = _item call CBA_fnc_getItemConfig; + }; + + case (_isMag): _fnc_hasProperty; // Magazine misc item, also easy + + private _itemType = getNumber (_config >> "ItemInfo" >> "type"); + + case (_itemType in [TYPE_FIRST_AID_KIT, TYPE_MEDIKIT, TYPE_TOOLKIT]): {true}; // Special items: Med/Toolkits + case (_itemType in [TYPE_MUZZLE, TYPE_OPTICS, TYPE_FLASHLIGHT, TYPE_BIPOD]): _fnc_hasProperty; // "Forced" misc items + case ((getText (configFile >> "CfgWeapons" >> _item >> "simulation")) == "ItemMineDetector"): {true}; // Special items: mine detectors + + default {false} + }; + + if (_return || !_skipFalseKeys) then { + _cache set [_item, _return]; + }; +}; + +_return diff --git a/addons/arsenal/functions/fnc_scanConfig.sqf b/addons/arsenal/functions/fnc_scanConfig.sqf index b5c6627cc7a..4e8e381d2eb 100644 --- a/addons/arsenal/functions/fnc_scanConfig.sqf +++ b/addons/arsenal/functions/fnc_scanConfig.sqf @@ -50,7 +50,7 @@ private _isTool = false; _configItemInfo = _x >> "ItemInfo"; _hasItemInfo = isClass (_configItemInfo); _itemInfoType = if (_hasItemInfo) then {getNumber (_configItemInfo >> "type")} else {0}; - _isMiscItem = _className isKindOf ["CBA_MiscItem", _cfgWeapons]; + _isMiscItem = [_className, _x, false, true] call FUNC(isMiscItem); _isTool = getNumber (_x >> "ACE_isTool") isEqualTo 1; switch (true) do { @@ -127,13 +127,7 @@ private _isTool = false; }; }; // Misc. items - case ( - _hasItemInfo && - {_isMiscItem && - {_itemInfoType in [TYPE_OPTICS, TYPE_FLASHLIGHT, TYPE_MUZZLE, TYPE_BIPOD]}} || - {_itemInfoType in [TYPE_FIRST_AID_KIT, TYPE_MEDIKIT, TYPE_TOOLKIT]} || - {_simulationType == "ItemMineDetector"} - ): { + case (_hasItemInfo && _isMiscItem): { (_configItems get IDX_VIRT_MISC_ITEMS) set [_className, nil]; if (_isTool) then {_toolList set [_className, nil]}; }; @@ -160,7 +154,11 @@ private _magazineMiscItems = createHashMap; { _magazineMiscItems set [configName _x, nil]; -} forEach ((toString {getNumber (_x >> "ACE_isUnique") == 1 || getNumber (_x >> "ACE_asItem") == 1}) configClasses _cfgMagazines); +} forEach ((toString { + with uiNamespace do { // configClasses runs in missionNamespace even if we're in preStart apparently + [configName _x, _x, true, true] call FUNC(isMiscItem); + }; +}) configClasses _cfgMagazines); // Remove invalid/non-existent entries _grenadeList deleteAt ""; diff --git a/addons/arsenal/functions/fnc_updateUniqueItemsList.sqf b/addons/arsenal/functions/fnc_updateUniqueItemsList.sqf index 9b7eb6327a8..4cbdc4bcba0 100644 --- a/addons/arsenal/functions/fnc_updateUniqueItemsList.sqf +++ b/addons/arsenal/functions/fnc_updateUniqueItemsList.sqf @@ -211,7 +211,7 @@ private _attachments = GVAR(virtualItems) get IDX_VIRT_ATTACHMENTS; _configItemInfo = _config >> "ItemInfo"; _hasItemInfo = isClass (_configItemInfo); _itemInfoType = if (_hasItemInfo) then {getNumber (_configItemInfo >> "type")} else {0}; - _isMiscItem = _x isKindOf ["CBA_MiscItem", _cfgWeapons]; + _isMiscItem = _x call FUNC(isMiscItem); _baseWeapon = if (!_isMiscItem) then { _x call FUNC(baseWeapon) @@ -263,12 +263,7 @@ private _attachments = GVAR(virtualItems) get IDX_VIRT_ATTACHMENTS; // Misc. items case ( !(_x in (GVAR(virtualItems) get IDX_VIRT_MISC_ITEMS)) && // misc. items don't use 'baseWeapon' - {_x in (_configItems get IDX_VIRT_MISC_ITEMS) || - {_hasItemInfo && - {_isMiscItem && - {_itemInfoType in [TYPE_OPTICS, TYPE_FLASHLIGHT, TYPE_MUZZLE, TYPE_BIPOD]}} || - {_itemInfoType in [TYPE_FIRST_AID_KIT, TYPE_MEDIKIT, TYPE_TOOLKIT]} || - {_simulationType == "ItemMineDetector"}}} + {_x in (_configItems get IDX_VIRT_MISC_ITEMS) || {_hasItemInfo && _isMiscItem}} ): { (GVAR(virtualItems) get IDX_VIRT_UNIQUE_MISC_ITEMS) set [_x, nil]; }; diff --git a/addons/cargo/stringtable.xml b/addons/cargo/stringtable.xml index 1ee1d4d1cc3..7dcd121959b 100644 --- a/addons/cargo/stringtable.xml +++ b/addons/cargo/stringtable.xml @@ -348,6 +348,7 @@ 화물 크기 확인 貨物としての大きさを確認 Проверить размер груза + Vérifier la taille de la cargaison Cargo Size: %1 diff --git a/addons/common/functions/fnc_checkVersionNumber.sqf b/addons/common/functions/fnc_checkVersionNumber.sqf index 61ed7f62313..5fc5ea22fda 100644 --- a/addons/common/functions/fnc_checkVersionNumber.sqf +++ b/addons/common/functions/fnc_checkVersionNumber.sqf @@ -1,6 +1,6 @@ #include "..\script_component.hpp" /* - * Author: commy2, johnb43 + * Author: commy2, johnb43, Timi007 * Compares version numbers from loaded addons. * * Arguments: @@ -32,8 +32,37 @@ private _cfgPatches = configFile >> "CfgPatches"; private _versions = []; { - (getText (_cfgPatches >> _x >> "version") splitString ".") params [["_major", "0"], ["_minor", "0"]]; - private _version = parseNumber _major + parseNumber _minor / 100; + // Determine the version of the addon. Parse it into a floating point number for comparison. Only major and minor are used. + // If no version is found or a parsing error occurs, the version is zero. + private _addonCfgPatches = _cfgPatches >> _x; + private _versionCfg = _addonCfgPatches >> "version"; + private _version = switch (true) do { + // Normal case. Version is defined as a floating point number -> MAJOR.MINOR + case (isNumber _versionCfg): { + getNumber _versionCfg + }; + // Addon Builder converts the version into a string if it is an invalid float -> "MAJOR.MINOR.PATCH" + case (isText _versionCfg): { + (getText _versionCfg splitString ".") params [["_major", "0"], ["_minor", "0"]]; + + parseNumber _major + parseNumber _minor / 100 + }; + // Fallback 1 (maybe versionAr is defined) + case (isArray (_addonCfgPatches >> "versionAr")): { + (getArray (_addonCfgPatches >> "versionAr")) params [["_major", 0], ["_minor", 0]]; + + _major + _minor / 100 + }; + // Fallback 2 (maybe versionStr is defined) + case (isText (_addonCfgPatches >> "versionStr")): { + (getText (_addonCfgPatches >> "versionStr") splitString ".") params [["_major", "0"], ["_minor", "0"]]; + + parseNumber _major + parseNumber _minor / 100 + }; + // No version found + default { 0 }; + }; + _versions pushBack _version; } forEach _files; diff --git a/addons/dragging/functions/fnc_canCarry.sqf b/addons/dragging/functions/fnc_canCarry.sqf index a38f37a02ee..d2cccad4576 100644 --- a/addons/dragging/functions/fnc_canCarry.sqf +++ b/addons/dragging/functions/fnc_canCarry.sqf @@ -21,7 +21,11 @@ params ["_unit", "_target"]; private _alive = alive _target; private _isPerson = _target isKindOf "CAManBase"; -if !((_alive || _isPerson) && {_target getVariable [QGVAR(canCarry), false]} && {isNull objectParent _target}) exitWith {false}; +if !( + (_alive || _isPerson) + && {_target getVariable [QGVAR(canCarry), false]} + && {isNull objectParent _target || {!isNull getCorpse _target}} +) exitWith {false}; if !([_unit, _target, []] call EFUNC(common,canInteractWith)) exitWith {false}; diff --git a/addons/fastroping/CfgVehicles.hpp b/addons/fastroping/CfgVehicles.hpp index ef2483e05b9..da49ff93aef 100644 --- a/addons/fastroping/CfgVehicles.hpp +++ b/addons/fastroping/CfgVehicles.hpp @@ -1,3 +1,68 @@ +#define MACRO_FRIES_SELFACTIONS \ + class ACE_SelfActions { \ + class ACE_prepareFRIES { \ + displayName = CSTRING(Interaction_prepareFRIES); \ + condition = QUOTE([_target] call FUNC(canPrepareFRIES)); \ + statement = QUOTE([_target] call FUNC(prepareFRIES)); \ + }; \ + class ACE_stowFRIES { \ + displayName = CSTRING(Interaction_stowFRIES); \ + condition = QUOTE([_target] call FUNC(canStowFRIES)); \ + statement = QUOTE([_target] call FUNC(stowFRIES)); \ + }; \ + class ACE_deployRopes3 { \ + displayName = CSTRING(Interaction_deployRopes3); \ + condition = QUOTE([ARR_3(_target,_player,'ACE_rope3')] call FUNC(canDeployRopes)); \ + statement = QUOTE([ARR_2(QQGVAR(deployRopes),[ARR_3(_target,_player,'ACE_rope3')])] call CBA_fnc_serverEvent); \ + }; \ + class ACE_deployRopes6 { \ + displayName = CSTRING(Interaction_deployRopes6); \ + condition = QUOTE([ARR_3(_target,_player,'ACE_rope6')] call FUNC(canDeployRopes)); \ + statement = QUOTE([ARR_2(QQGVAR(deployRopes),[ARR_3(_target,_player,'ACE_rope6')])] call CBA_fnc_serverEvent); \ + }; \ + class ACE_deployRopes12 { \ + displayName = CSTRING(Interaction_deployRopes12); \ + condition = QUOTE([ARR_3(_target,_player,'ACE_rope12')] call FUNC(canDeployRopes)); \ + statement = QUOTE([ARR_2(QQGVAR(deployRopes),[ARR_3(_target,_player,'ACE_rope12')])] call CBA_fnc_serverEvent); \ + }; \ + class ACE_deployRopes15 { \ + displayName = CSTRING(Interaction_deployRopes15); \ + condition = QUOTE([ARR_3(_target,_player,'ACE_rope15')] call FUNC(canDeployRopes)); \ + statement = QUOTE([ARR_2(QQGVAR(deployRopes),[ARR_3(_target,_player,'ACE_rope15')])] call CBA_fnc_serverEvent); \ + }; \ + class ACE_deployRopes18 { \ + displayName = CSTRING(Interaction_deployRopes18); \ + condition = QUOTE([ARR_3(_target,_player,'ACE_rope18')] call FUNC(canDeployRopes)); \ + statement = QUOTE([ARR_2(QQGVAR(deployRopes),[ARR_3(_target,_player,'ACE_rope18')])] call CBA_fnc_serverEvent); \ + }; \ + class ACE_deployRopes27 { \ + displayName = CSTRING(Interaction_deployRopes27); \ + condition = QUOTE([ARR_3(_target,_player,'ACE_rope27')] call FUNC(canDeployRopes)); \ + statement = QUOTE([ARR_2(QQGVAR(deployRopes),[ARR_3(_target,_player,'ACE_rope27')])] call CBA_fnc_serverEvent); \ + }; \ + class ACE_deployRopes36 { \ + displayName = CSTRING(Interaction_deployRopes36); \ + condition = QUOTE([ARR_4(_target,_player,'ACE_rope36',true)] call FUNC(canDeployRopes)); \ + statement = QUOTE([ARR_2(QQGVAR(deployRopes),[ARR_3(_target,_player,'ACE_rope36')])] call CBA_fnc_serverEvent); \ + }; \ + class ACE_cutRopes { \ + displayName = CSTRING(Interaction_cutRopes); \ + condition = QUOTE([_target] call FUNC(canCutRopes)); \ + statement = QUOTE(true); \ + class confirmCutRopes { \ + displayName = ECSTRING(common,confirm); \ + condition = QUOTE([_target] call FUNC(canCutRopes)); \ + statement = QUOTE([_target] call FUNC(cutRopes)); \ + }; \ + }; \ + class ACE_fastRope { \ + displayName = CSTRING(Interaction_fastRope); \ + condition = QUOTE([ARR_2(_player,_target)] call FUNC(canFastRope)); \ + statement = QUOTE([ARR_2(_player,_target)] call FUNC(fastRope)); \ + }; \ + } + + class CfgVehicles { class Logic; class Module_F: Logic { @@ -24,69 +89,10 @@ class CfgVehicles { class Air; class Helicopter: Air { - class ACE_SelfActions { - class ACE_prepareFRIES { - displayName = CSTRING(Interaction_prepareFRIES); - condition = QUOTE([_target] call FUNC(canPrepareFRIES)); - statement = QUOTE([_target] call FUNC(prepareFRIES)); - }; - class ACE_stowFRIES { - displayName = CSTRING(Interaction_stowFRIES); - condition = QUOTE([_target] call FUNC(canStowFRIES)); - statement = QUOTE([_target] call FUNC(stowFRIES)); - }; - class ACE_deployRopes3 { - displayName = CSTRING(Interaction_deployRopes3); - condition = QUOTE([ARR_3(_target,_player,'ACE_rope3')] call FUNC(canDeployRopes)); - statement = QUOTE([ARR_2(QQGVAR(deployRopes),[ARR_3(_target,_player,'ACE_rope3')])] call CBA_fnc_serverEvent); - }; - class ACE_deployRopes6 { - displayName = CSTRING(Interaction_deployRopes6); - condition = QUOTE([ARR_3(_target,_player,'ACE_rope6')] call FUNC(canDeployRopes)); - statement = QUOTE([ARR_2(QQGVAR(deployRopes),[ARR_3(_target,_player,'ACE_rope6')])] call CBA_fnc_serverEvent); - }; - class ACE_deployRopes12 { - displayName = CSTRING(Interaction_deployRopes12); - condition = QUOTE([ARR_3(_target,_player,'ACE_rope12')] call FUNC(canDeployRopes)); - statement = QUOTE([ARR_2(QQGVAR(deployRopes),[ARR_3(_target,_player,'ACE_rope12')])] call CBA_fnc_serverEvent); - }; - class ACE_deployRopes15 { - displayName = CSTRING(Interaction_deployRopes15); - condition = QUOTE([ARR_3(_target,_player,'ACE_rope15')] call FUNC(canDeployRopes)); - statement = QUOTE([ARR_2(QQGVAR(deployRopes),[ARR_3(_target,_player,'ACE_rope15')])] call CBA_fnc_serverEvent); - }; - class ACE_deployRopes18 { - displayName = CSTRING(Interaction_deployRopes18); - condition = QUOTE([ARR_3(_target,_player,'ACE_rope18')] call FUNC(canDeployRopes)); - statement = QUOTE([ARR_2(QQGVAR(deployRopes),[ARR_3(_target,_player,'ACE_rope18')])] call CBA_fnc_serverEvent); - }; - class ACE_deployRopes27 { - displayName = CSTRING(Interaction_deployRopes27); - condition = QUOTE([ARR_3(_target,_player,'ACE_rope27')] call FUNC(canDeployRopes)); - statement = QUOTE([ARR_2(QQGVAR(deployRopes),[ARR_3(_target,_player,'ACE_rope27')])] call CBA_fnc_serverEvent); - }; - class ACE_deployRopes36 { - displayName = CSTRING(Interaction_deployRopes36); - condition = QUOTE([ARR_4(_target,_player,'ACE_rope36',true)] call FUNC(canDeployRopes)); - statement = QUOTE([ARR_2(QQGVAR(deployRopes),[ARR_3(_target,_player,'ACE_rope36')])] call CBA_fnc_serverEvent); - }; - class ACE_cutRopes { - displayName = CSTRING(Interaction_cutRopes); - condition = QUOTE([_target] call FUNC(canCutRopes)); - // should not be empty to work with EGVAR(interact_menu,consolidateSingleChild) setting - statement = QUOTE(true); - class confirmCutRopes { - displayName = ECSTRING(common,confirm); - condition = QUOTE([_target] call FUNC(canCutRopes)); - statement = QUOTE([_target] call FUNC(cutRopes)); - }; - }; - class ACE_fastRope { - displayName = CSTRING(Interaction_fastRope); - condition = QUOTE([ARR_2(_player,_target)] call FUNC(canFastRope)); - statement = QUOTE([ARR_2(_player,_target)] call FUNC(fastRope)); - }; - }; + MACRO_FRIES_SELFACTIONS; + }; + class Plane: Air { + MACRO_FRIES_SELFACTIONS; }; class Helicopter_Base_F; diff --git a/addons/fastroping/XEH_postInit.sqf b/addons/fastroping/XEH_postInit.sqf index c28fb065179..2e6da10a2ab 100644 --- a/addons/fastroping/XEH_postInit.sqf +++ b/addons/fastroping/XEH_postInit.sqf @@ -31,7 +31,7 @@ if (isServer) then { - ["Helicopter", "init", { + ["Air", "init", { if (!GVAR(autoAddFRIES)) exitWith {}; params ["_vehicle"]; if (isNumber (configOf _vehicle >> QGVAR(enabled)) && {isNil {_vehicle getVariable [QGVAR(FRIES), nil]}}) then { @@ -51,7 +51,7 @@ if (isServer) then { #ifdef DRAW_FASTROPE_INFO addMissionEventHandler ["Draw3D", { - if !(cursorObject isKindOf "Helicopter") exitWith {}; + if !(cursorObject isKindOf "Air") exitWith {}; private _config = configOf cursorObject; private _enabled = getNumber (_config >> QGVAR(enabled)); drawIcon3D ["", [.5,.5,1,1], (ASLToAGL getPosASL cursorObject), 0.5, 0.5, 0, format ["%1 = %2", typeOf cursorObject, _enabled], 0.5, 0.025, "TahomaB"]; diff --git a/addons/fastroping/XEH_preInit.sqf b/addons/fastroping/XEH_preInit.sqf index b7502751676..fc06833d192 100644 --- a/addons/fastroping/XEH_preInit.sqf +++ b/addons/fastroping/XEH_preInit.sqf @@ -9,9 +9,9 @@ PREP_RECOMPILE_END; #include "initSettings.inc.sqf" if (isServer) then { - ["Helicopter", "Deleted", LINKFUNC(unequipFRIES)] call CBA_fnc_addClassEventHandler; + ["Air", "Deleted", LINKFUNC(unequipFRIES)] call CBA_fnc_addClassEventHandler; }; -["Helicopter", "Killed", LINKFUNC(unequipFRIES)] call CBA_fnc_addClassEventHandler; +["Air", "Killed", LINKFUNC(unequipFRIES)] call CBA_fnc_addClassEventHandler; ADDON = true; diff --git a/addons/fastroping/functions/fnc_deployAI.sqf b/addons/fastroping/functions/fnc_deployAI.sqf index 01aa363afb5..fd566f9bfd2 100644 --- a/addons/fastroping/functions/fnc_deployAI.sqf +++ b/addons/fastroping/functions/fnc_deployAI.sqf @@ -18,7 +18,7 @@ */ params [["_vehicle", objNull, [objNull]], ["_deploySpecial", false, [true]], ["_createDeploymentGroup", true, [true]]]; -if (isNull _vehicle || {!(_vehicle isKindOf "Helicopter")}) exitWith { +if (isNull _vehicle || {!(_vehicle isKindOf "Air")}) exitWith { if (hasInterface) then { // Note: BIS_fnc_guiMessage causes a CTD with call, so spawn is used instead. ["deployAI was called with an invalid or non-existant vehicle.", QFUNC(deployAI)] spawn BIS_fnc_guiMessage; diff --git a/addons/field_rations/XEH_postInit.sqf b/addons/field_rations/XEH_postInit.sqf index 54feeef659f..ee921c5139a 100644 --- a/addons/field_rations/XEH_postInit.sqf +++ b/addons/field_rations/XEH_postInit.sqf @@ -74,26 +74,31 @@ if !(hasInterface) exitWith {}; } forEach _subActions; // Add inventory context menu option to consume items - ["ACE_ItemCore", ["CONTAINER"], LSTRING(EatDrink), [], QPATHTOF(ui\icon_survival.paa), - [ - {true}, - { - params ["", "", "_item"]; + private _eatOrDrinkCondition = [ + {true}, + { + params ["", "", "_item"]; - XGVAR(enabled) && { - private _config = configFile >> "CfgWeapons" >> _item; - getNumber (_config >> QXGVAR(thirstQuenched)) > 0 - || {getNumber (_config >> QXGVAR(hungerSatiated)) > 0} - } + XGVAR(enabled) && { + private _config = _item call CBA_fnc_getItemConfig; + getNumber (_config >> QXGVAR(thirstQuenched)) > 0 + || {getNumber (_config >> QXGVAR(hungerSatiated)) > 0} } - ], - { - params ["_unit", "", "_item"]; - private _itemConfig = configFile >> "CfgWeapons" >> _item; - [objNull, _unit, [_item, _itemConfig, false]] call FUNC(consumeItem); - false } - ] call CBA_fnc_addItemContextMenuOption; + ]; + private _eatOrDrinkStatement = { + params ["_unit", "", "_item"]; + private _itemConfig = _item call CBA_fnc_getItemConfig; + private _isMagazine = isClass (configFile >> "CfgMagazines" >> _item); + [objNull, _unit, [_item, _itemConfig, _isMagazine]] call FUNC(consumeItem); + false // Close context menu + }; + + { + [_x, ["CONTAINER"], LSTRING(EatDrink), [], QPATHTOF(ui\icon_survival.paa), + _eatOrDrinkCondition, _eatOrDrinkStatement + ] call CBA_fnc_addItemContextMenuOption; + } forEach ["ACE_ItemCore", "CA_Magazine"]; // Add water source helpers when interaction menu is opened ["ace_interactMenuOpened", LINKFUNC(addWaterSourceInteractions)] call CBA_fnc_addEventHandler; diff --git a/addons/frag/XEH_postInit.sqf b/addons/frag/XEH_postInit.sqf index 0ea9c57eeb7..c3998b6def4 100644 --- a/addons/frag/XEH_postInit.sqf +++ b/addons/frag/XEH_postInit.sqf @@ -4,7 +4,9 @@ [{ params ["_projectile", "_posASL"]; - if (_projectile getVariable [QGVAR(blacklisted), false]) exitWith {}; + // check if a projectile is blacklisted and that it will inflict damage when it explodes to avoid + // multiple events being sent from different clients for one explosion + if (_projectile getVariable [QGVAR(blacklisted), false] || !(_projectile getShotInfo 5)) exitWith {}; private _ammo = typeOf _projectile; if (GVAR(reflectionsEnabled)) then { diff --git a/addons/frag/functions/fnc_fired.sqf b/addons/frag/functions/fnc_fired.sqf index 1cc72af2af6..285d3f7fd89 100644 --- a/addons/frag/functions/fnc_fired.sqf +++ b/addons/frag/functions/fnc_fired.sqf @@ -40,9 +40,7 @@ private _hitPartEventHandler = _projectile addEventHandler ["HitPart", { private _ammo = typeOf _projectile; private _vectorUp = vectorUp _projectile; - /* - * Wait a frame to see what happens to the round - */ + // Wait a frame to see what happens to the round [LINKFUNC(doSpallHitPart), [_projectile, _objectHit, _posASL, _velocity, _surfNorm, _surfType, _ammo, _vectorUp]] call CBA_fnc_execNextFrame; }]; private _penetratedEventHandler = _projectile addEventHandler ["Penetrated",LINKFUNC(doSpallPenetrate)]; diff --git a/addons/frag/functions/fnc_frago.sqf b/addons/frag/functions/fnc_frago.sqf index b6d20883d2d..59bc0236821 100644 --- a/addons/frag/functions/fnc_frago.sqf +++ b/addons/frag/functions/fnc_frago.sqf @@ -39,120 +39,109 @@ _shellType call FUNC(getFragInfo) params ["_fragRange", "_fragVelocity", "_fragT private _fragPosAGL = ASLToAGL _fragPosASL; TRACE_5("fragValues",_fragPosASL,_fragPosAGL,_fragRange,_fragVelocity,_metalMassModifier); -// Post 2.18 change - uncomment line 43, modify lines 45, and remove lines 44, 51-57, 64-66 -// private _targets = [ASLToAGL _fragPosAGL, _fragRange, _fragRange, 0, false, _fragRange] nearEntities [["Car", "Motorcycle", "Tank", "StaticWeapon", "CAManBase", "Air", "Ship"], false, true, true]; -private _objects = _fragPosAGL nearEntities [["Car", "Motorcycle", "Tank", "StaticWeapon", "CAManBase", "Air", "Ship"], _fragRange]; -if (_objects isEqualTo []) exitWith { + +// Compile possible targets including units, vehicles, and crews +private _targets = [_fragPosAGL, _fragRange, _fragRange, 0, false, _fragRange] nearEntities [["Car", "Motorcycle", "Tank", "StaticWeapon", "CAManBase", "Air", "Ship"], false, true, true]; +if (_targets isEqualTo []) exitWith { TRACE_2("No nearby targets",_fragPosAGL,_fragRange); - 0 + 0 // return }; - -// grab crews and add them in so that targets stay approx. sorted by distance -TRACE_1("",_objects); -private _targets = []; -{ - private _crew = crew _x; - _crew pushBackUnique _x; - _targets append _crew; -} forEach _objects; -TRACE_2("",_fragRange,count _targets); +TRACE_3("",_fragRange,count _targets,_targets); private _fragCount = 0; - private _fragArcs = []; _fragArcs set [360, 0]; -if (_targets isNotEqualTo []) then { - if (GVAR(reflectionsEnabled)) then { - [_fragPosASL, _shellType] call FUNC(doReflections); - }; - { - private _target = _x; - if (alive _target && {getNumber ((configOf _target) >> "isPlayableLogic") == 0}) then { - (boundingBox _target) params ["_boundingBoxA", "_boundingBoxB"]; - - private _cubic = ((abs (_boundingBoxA select 0)) + (_boundingBoxB select 0)) * ((abs (_boundingBoxA select 1)) + (_boundingBoxB select 1)) * ((abs (_boundingBoxA select 2)) + (_boundingBoxB select 2)); - - if (_cubic <= 1) exitWith {}; - - private _targetVel = velocity _target; - private _targetPos = getPosASL _target; - private _distance = _target distance _fragPosAGL; - private _add = ((_boundingBoxB select 2) / 2) + ((((_distance - (_fragVelocity / 8)) max 0) / _fragVelocity) * 10); - - _targetPos = _targetPos vectorAdd [ - (_targetVel select 0) * (_distance / _fragVelocity), - (_targetVel select 1) * (_distance / _fragVelocity), - _add - ]; - - private _baseVec = _fragPosASL vectorFromTo _targetPos; - - private _dir = floor (_baseVec call CBA_fnc_vectDir); - private _currentCount = RETDEF(_fragArcs select _dir,0); - if (_currentCount < 10) then { - private _count = ceil (random _metalMassModifier); - private _vecVar = FRAG_VEC_VAR; - if !(_target isKindOf "CAManBase") then { - ADD(_vecVar,(sqrt _cubic) / 2000); - if ((crew _target) isEqualTo [] && {_count > 0}) then { - _count = 0 max (_count / 2); - }; +if (GVAR(reflectionsEnabled)) then { + [_fragPosASL, _shellType] call FUNC(doReflections); +}; +{ + private _target = _x; + if (getNumber ((configOf _target) >> "isPlayableLogic") == 0) then { + (boundingBox _target) params ["_boundingBoxA", "_boundingBoxB"]; + + private _cubic = ((abs (_boundingBoxA select 0)) + (_boundingBoxB select 0)) * ((abs (_boundingBoxA select 1)) + (_boundingBoxB select 1)) * ((abs (_boundingBoxA select 2)) + (_boundingBoxB select 2)); + + if (_cubic <= 1) exitWith {}; + + private _targetVel = velocity _target; + private _targetPos = getPosASL _target; + private _distance = _target distance _fragPosAGL; + private _add = ((_boundingBoxB select 2) / 2) + ((((_distance - (_fragVelocity / 8)) max 0) / _fragVelocity) * 10); + + _targetPos = _targetPos vectorAdd [ + (_targetVel select 0) * (_distance / _fragVelocity), + (_targetVel select 1) * (_distance / _fragVelocity), + _add + ]; + + private _baseVec = _fragPosASL vectorFromTo _targetPos; + + private _dir = floor (_baseVec call CBA_fnc_vectDir); + private _currentCount = RETDEF(_fragArcs select _dir,0); + if (_currentCount < 10) then { + private _count = ceil (random _metalMassModifier); + private _vecVar = FRAG_VEC_VAR; + if !(_target isKindOf "CAManBase") then { + ADD(_vecVar,(sqrt _cubic) / 2000); + if ((crew _target) isEqualTo [] && {_count > 0}) then { + _count = 0 max (_count / 2); }; - private _vecVarHalf = _vecVar / 2; - for "_i" from 1 to _count do { - private _vectorDir = _baseVec vectorDiff [ - _vecVarHalf - (random _vecVar), - _vecVarHalf - (random _vecVar), - _vecVarHalf - (random _vecVar) - ]; - - private _fragObjSpeed = _fragVelocity * (1 - random 0.5); - private _fragObjVelocity = _vectorDir vectorMultiply _fragObjSpeed; - - private _fragObj = createVehicleLocal [selectRandom _fragTypes, _fragPosAGL, [], 0, "CAN_COLLIDE"]; - _fragObj setVectorDir _vectorDir; - _fragObj setVelocity _fragObjVelocity; - #ifdef DEBUG_MODE_DRAW - [_fragObj, "green", true] call FUNC(dev_trackObj); - if (GVAR(dbgSphere)) then { - [_targetPos, "(0.88,0.36,0.92,0.8)"] call FUNC(dev_sphereDraw); - }; - #endif - INC(_fragCount); - INC(_currentCount); + }; + private _vecVarHalf = _vecVar / 2; + for "_i" from 1 to _count do { + private _vectorDir = _baseVec vectorDiff [ + _vecVarHalf - (random _vecVar), + _vecVarHalf - (random _vecVar), + _vecVarHalf - (random _vecVar) + ]; + + private _fragObjSpeed = _fragVelocity * (1 - random 0.5); + private _fragObjVelocity = _vectorDir vectorMultiply _fragObjSpeed; + + private _fragObj = createVehicleLocal [selectRandom _fragTypes, _fragPosAGL, [], 0, "CAN_COLLIDE"]; + _fragObj setVectorDir _vectorDir; + _fragObj setVelocity _fragObjVelocity; + #ifdef DEBUG_MODE_DRAW + [_fragObj, "green", true] call FUNC(dev_trackObj); + if (GVAR(dbgSphere)) then { + [_targetPos, "(0.88,0.36,0.92,0.8)"] call FUNC(dev_sphereDraw); }; - _fragArcs set [_dir, _currentCount]; + #endif + INC(_fragCount); + INC(_currentCount); }; + _fragArcs set [_dir, _currentCount]; }; - if (_fragCount > _maxFrags) exitWith {}; - } forEach _targets; - TRACE_1("targeted",_fragCount); - if (_fragCount > _maxFrags) exitWith {}; - private _randomCount = ceil ((_maxFrags - _fragCount) * 0.35); - TRACE_1("",_randomCount); - private _sectorSize = 360 / (_randomCount max 1); - - for "_i" from 1 to _randomCount do { - // Distribute evenly - private _sectorOffset = 360 * (_i - 1) / (_randomCount max 1); - private _randomDir = random (_sectorSize); - private _vectorDir = [cos (_sectorOffset + _randomDir), sin (_sectorOffset + _randomDir), sin (30 - (random 45))]; - - private _fragObjSpeed = _fragVelocity * (1 - random 0.5); - private _fragObjVelocity = _vectorDir vectorMultiply _fragObjSpeed; - - private _fragObj = createVehicleLocal [selectRandom _fragTypes, _fragPosAGL, [], 0, "CAN_COLLIDE"]; - _fragObj setVectorDir _vectorDir; - _fragObj setVelocity _fragObjVelocity; - - #ifdef DEBUG_MODE_DRAW - [_fragObj, "blue", true] call FUNC(dev_trackObj); - #endif - INC(_fragCount); }; + if (_fragCount > _maxFrags) exitWith {}; +} forEach _targets; +TRACE_1("targeted",_fragCount); +if (_fragCount > _maxFrags) exitWith {}; +private _randomCount = ceil ((_maxFrags - _fragCount) * 0.35); +TRACE_1("",_randomCount); +private _sectorSize = 360 / (_randomCount max 1); + +for "_i" from 1 to _randomCount do { + // Distribute evenly + private _sectorOffset = 360 * (_i - 1) / (_randomCount max 1); + private _randomDir = random (_sectorSize); + private _vectorDir = [cos (_sectorOffset + _randomDir), sin (_sectorOffset + _randomDir), sin (30 - (random 45))]; + + private _fragObjSpeed = _fragVelocity * (1 - random 0.5); + private _fragObjVelocity = _vectorDir vectorMultiply _fragObjSpeed; + + private _fragObj = createVehicleLocal [selectRandom _fragTypes, _fragPosAGL, [], 0, "CAN_COLLIDE"]; + _fragObj setVectorDir _vectorDir; + _fragObj setVelocity _fragObjVelocity; + + #ifdef DEBUG_MODE_DRAW + [_fragObj, "blue", true] call FUNC(dev_trackObj); + #endif + INC(_fragCount); }; TRACE_1("total created",_fragCount); END_COUNTER(frago); +_fragCount // return diff --git a/addons/frag/stringtable.xml b/addons/frag/stringtable.xml index 71bda49dfc4..dadd4029e4c 100644 --- a/addons/frag/stringtable.xml +++ b/addons/frag/stringtable.xml @@ -118,6 +118,7 @@ Отладка Debug Debug + Debug Spalling Intensity @@ -126,6 +127,7 @@ Интенсивность обрушения Intensità dello spalling Intensidad del astillamiento + Intensité de l'écaillage Modifier to increase or decrease the number and intensity of spalling events. Increasing this value may cause performance degradation. @@ -134,6 +136,7 @@ Модификатор для увеличения или уменьшения количества и интенсивности событий обрушения. Увеличение этого значения может привести к ухудшению производительности. Modificatore per il numero e intensità di spalling simulato, ovvero la frammentazione interna ad un veicolo colpito. Valori alti possono causare una degradazione della performance. Modificador para aumentar o disminuir el número y la intensidad de los eventos de astillamiento. Aumentar este valor puede producir una degradación en el rendimiento. + Modificateur permettant d'augmenter ou de diminuer le nombre et l'intensité des événements d'écaillage. L'augmentation de cette valeur peut entraîner une dégradation des performances. Frag/Spall Debug Tracing @@ -143,6 +146,7 @@ Отладка трассировки фрагментации/осколков Traccia Frag/Spall per Debug Trazado Debug de Fragmentación/Astillamiento + Suivi du débogage des éclats/explosions Enables visual tracing of fragmentation and spalling rounds. @@ -152,6 +156,7 @@ Включает визуальную трассировку фрагментации и осколочных снарядов. Abilita il tracciamento visivo di effetti di frammentazione e spalling. Habilitar trazado visual de los proyectiles generados por la fragmentación y el astillamiento. + Active le suivi des éclats/explosions. Draw Event Spheres @@ -160,6 +165,7 @@ Изобразить сферы событий Visualizza sfere eventi Dibujar Esferas de Eventos + Visualiser les sphères d'événements Draw color coded spheres at any event for tracked rounds. @@ -168,6 +174,7 @@ Изобразить цветные сферы на любом событии для отслеживаемых раундов. Visualizza sfere colorate su ogni evento di un frammento tracciato. Dibujar esferas codificadas por color en cualquier evento para proyectiles seguidos. + Affiche des sphères de couleur sur chaque événement d'un fragment tracé. Draw Hitboxes @@ -176,6 +183,7 @@ Изобразить хитбоксы Visualizza hitbox Dibujar hitboxes + Afficher les hitboxes Draw hitboxes on objects that were targeted. @@ -185,6 +193,7 @@ Изобразить хитбоксы на объектах, которые были нацелены. Visualizza hitbox su potenziali bersagli della frammentazione. Dibuja hitboxes en objetos que son seguidos. + Affiche les hitboxes sur les cibles potentielles de fragmentation. diff --git a/addons/medical_damage/functions/fnc_determineIfFatal.sqf b/addons/medical_damage/functions/fnc_determineIfFatal.sqf index 1e5c533e98b..c56763ef479 100644 --- a/addons/medical_damage/functions/fnc_determineIfFatal.sqf +++ b/addons/medical_damage/functions/fnc_determineIfFatal.sqf @@ -6,7 +6,7 @@ * Arguments: * 0: The Unit * 1: Part No - * 2: Damage Array - QGVAR(medical,bodyPartDamage) + * 2: Damage Array - QEGVAR(medical,bodyPartDamage) * 3: New Damage * * ReturnValue: @@ -20,7 +20,7 @@ params ["_unit", "_part", "_bodyPartDamage", "_woundDamage"]; -if (_part > 1) exitWith { false }; +if (_part > 1 && EGVAR(medical,useLimbDamage) == 0) exitWith { false }; scopeName "main"; @@ -46,6 +46,15 @@ if (EGVAR(medical,fatalDamageSource) in [1, 2]) then { _bodyPartDamage params ["_headDamage", "_bodyDamage"]; private _vitalDamage = ((_headDamage - _headThreshhold) max 0) + ((_bodyDamage - _bodyThreshhold) max 0); + + // Sum of trauma to the limbs can also be fatal (shock) but this should take much more damage at default (5x as much) + if ([false, !isPlayer _unit, true] select EGVAR(medical,useLimbDamage)) then { + private _limbThreshold = EGVAR(medical,limbDamageThreshold) * _damageThreshold; + { + _vitalDamage = _vitalDamage + ((_x - _limbThreshold) max 0); + } forEach _bodyPartDamage select [2]; + }; + private _chanceFatal = 1 - exp -((_vitalDamage/FATAL_SUM_DAMAGE_WEIBULL_L)^FATAL_SUM_DAMAGE_WEIBULL_K); TRACE_3("",_bodyPartDamage,_vitalDamage,_chanceFatal); @@ -56,4 +65,3 @@ if (EGVAR(medical,fatalDamageSource) in [1, 2]) then { }; false - diff --git a/addons/medical_damage/functions/fnc_handleIncapacitation.sqf b/addons/medical_damage/functions/fnc_handleIncapacitation.sqf index b352564b45d..391d69c08bf 100644 --- a/addons/medical_damage/functions/fnc_handleIncapacitation.sqf +++ b/addons/medical_damage/functions/fnc_handleIncapacitation.sqf @@ -20,7 +20,7 @@ params ["_unit"]; private _painLevel = GET_PAIN_PERCEIVED(_unit); private _bodyPartDamage = _unit getVariable [QEGVAR(medical,bodyPartDamage), [0,0,0,0,0,0]]; -_bodyPartDamage params ["_headDamage", "_bodyDamage", "_leftArmDamage", "_rightArmDamage", "_leftLegDamage", "_rightLegDamage"]; +_bodyPartDamage params ["_headDamage", "_bodyDamage"]; // Exclude non penetrating body damage { diff --git a/addons/medical_damage/initSettings.inc.sqf b/addons/medical_damage/initSettings.inc.sqf index 229b086505c..c6d7f49e343 100644 --- a/addons/medical_damage/initSettings.inc.sqf +++ b/addons/medical_damage/initSettings.inc.sqf @@ -2,7 +2,7 @@ QEGVAR(medical,fatalDamageSource), "LIST", [LSTRING(fatalDamageSource_DisplayName), LSTRING(fatalDamageSource_Description)], - [ELSTRING(medical,Category)], + ELSTRING(medical,Category), [[0, 1, 2], [LSTRING(fatalDamageSource_vitalShotsOnly), LSTRING(fatalDamageSource_trauma), LSTRING(fatalDamageSource_both)], 2], true ] call CBA_fnc_addSetting; @@ -25,6 +25,24 @@ true ] call CBA_fnc_addSetting; +[ + QEGVAR(medical,useLimbDamage), + "LIST", + [LSTRING(useLimbDamage_DisplayName), LSTRING(useLimbDamage_Description)], + ELSTRING(medical,Category), + [[0, 1, 2], [ELSTRING(common,Never), ELSTRING(common,aiOnly), ELSTRING(common,playersAndAI)], 0], + 1 +] call CBA_fnc_addSetting; + +[ + QEGVAR(medical,limbDamageThreshold), + "SLIDER", + [LSTRING(limbDamageThreshold_DisplayName), LSTRING(limbDamageThreshold_Description)], + ELSTRING(medical,Category), + [0, 25, 5, 2], + 1 +] call CBA_fnc_addSetting; + [ QEGVAR(medical,painUnconsciousChance), "SLIDER", diff --git a/addons/medical_damage/stringtable.xml b/addons/medical_damage/stringtable.xml index fa4e1c4ae48..f8f7e22e895 100644 --- a/addons/medical_damage/stringtable.xml +++ b/addons/medical_damage/stringtable.xml @@ -843,5 +843,21 @@ 치명상으로 인해 사망할 확률을 정합니다. A chance de morrer para um ferimento fatal. + + Use Limb Damage + Использовать урон конечностям + + + Controls whether limb damage is taken into account for sum of trauma calculations. + Определяет, учитывается ли повреждение конечностей при расчете совокупности травм. + + + Limb Damage Threshold + Порог повреждения конечностей + + + Sets the amount of damage limbs can receive before going critical, leading to death. Must be over 0 for any effect.\nRequires the "Use Limb Damage" setting to be enabled and "Fatal Damage Source" to be set to "Sum of Trauma" or "Either".\nStacks multiplicatively with the overall unit Damage Threshold. Doesn't interact with fractures/limping at all. + Устанавливает величину урона, который могут получить конечности, прежде чем урон станет критическим, что приведет к смерти. Для любого эффекта должно быть больше 0.\nТребуется, чтобы настройка "Использовать урон конечностям" была включена, а "Причина смертельного урона" была установлена на "Совокупность травмы" или "Оба".\nУмножается с общим порогом повреждения. Никак не взаимодействует с переломами или хроманием. + diff --git a/addons/medical_gui/functions/fnc_updateBodyImage.sqf b/addons/medical_gui/functions/fnc_updateBodyImage.sqf index b8ee8ee240e..71b86449280 100644 --- a/addons/medical_gui/functions/fnc_updateBodyImage.sqf +++ b/addons/medical_gui/functions/fnc_updateBodyImage.sqf @@ -77,12 +77,22 @@ private _bodyPartBloodLoss = [0, 0, 0, 0, 0, 0]; [_bloodLoss] call FUNC(bloodLossToRGBA); } else { private _damage = _bodyPartDamage select _forEachIndex; + // _damageThreshold here indicates how close unit is to guaranteed death via sum of trauma, so use the same multipliers used in medical_damage/functions/fnc_determineIfFatal.sqf + // TODO: make multipliers for head and torso a macro in medical_engine/script_macros_medical.hpp switch (true) do { // torso damage threshold doesn't need scaling case (_forEachIndex > 3): { // legs: index 4 & 5 - _damageThreshold = LIMPING_DAMAGE_THRESHOLD * 4; + if (!EGVAR(medical,useLimbDamage) || EGVAR(medical,limbDamageThreshold) == 0) then { // Just indicate how close to the limping threshold we are + _damageThreshold = LIMPING_DAMAGE_THRESHOLD * 4; + } else { + _damageThreshold = _damageThreshold * EGVAR(medical,limbDamageThreshold); + }; }; case (_forEachIndex > 1): { // arms: index 2 & 3 - _damageThreshold = FRACTURE_DAMAGE_THRESHOLD * 4; + if (!EGVAR(medical,useLimbDamage) || EGVAR(medical,limbDamageThreshold) == 0) then { // Just indicate how close to the fracture threshold we are + _damageThreshold = FRACTURE_DAMAGE_THRESHOLD * 4; + } else { + _damageThreshold = _damageThreshold * EGVAR(medical,limbDamageThreshold); + }; }; case (_forEachIndex == 0): { // head: index 0 _damageThreshold = _damageThreshold * 1.25; diff --git a/addons/medical_gui/functions/fnc_updateInjuryList.sqf b/addons/medical_gui/functions/fnc_updateInjuryList.sqf index 3219eb025f5..f7a9eec1122 100644 --- a/addons/medical_gui/functions/fnc_updateInjuryList.sqf +++ b/addons/medical_gui/functions/fnc_updateInjuryList.sqf @@ -168,10 +168,18 @@ if (GVAR(showDamageEntry)) then { private _damageThreshold = GET_DAMAGE_THRESHOLD(_target); switch (true) do { case (_selectionN > 3): { // legs: index 4 & 5 - _damageThreshold = LIMPING_DAMAGE_THRESHOLD * 4; + if (!EGVAR(medical,useLimbDamage) || EGVAR(medical,limbDamageThreshold) == 0) then { // Just indicate how close to the limping threshold we are + _damageThreshold = LIMPING_DAMAGE_THRESHOLD * 4; + } else { + _damageThreshold = _damageThreshold * EGVAR(medical,limbDamageThreshold); + }; }; case (_selectionN > 1): { // arms: index 2 & 3 - _damageThreshold = FRACTURE_DAMAGE_THRESHOLD * 4; + if (!EGVAR(medical,useLimbDamage) || EGVAR(medical,limbDamageThreshold) == 0) then { // Just indicate how close to the fracture threshold we are + _damageThreshold = FRACTURE_DAMAGE_THRESHOLD * 4; + } else { + _damageThreshold = _damageThreshold * EGVAR(medical,limbDamageThreshold); + }; }; case (_selectionN == 0): { // head: index 0 _damageThreshold = _damageThreshold * 1.25; @@ -180,6 +188,7 @@ if (GVAR(showDamageEntry)) then { _damageThreshold = _damageThreshold * 1.5; }; }; + // _bodyPartDamage here should indicate how close unit is to guaranteed death via sum of trauma, so use the same multipliers used in medical_damage/functions/fnc_determineIfFatal.sqf _bodyPartDamage = (_bodyPartDamage / _damageThreshold) min 1; switch (true) do { case (_bodyPartDamage isEqualTo 1): { diff --git a/addons/medical_treatment/ACE_Medical_Treatment_Actions.hpp b/addons/medical_treatment/ACE_Medical_Treatment_Actions.hpp index 4058132e3db..582e3b6db53 100644 --- a/addons/medical_treatment/ACE_Medical_Treatment_Actions.hpp +++ b/addons/medical_treatment/ACE_Medical_Treatment_Actions.hpp @@ -100,8 +100,10 @@ class GVAR(actions) { displayNameProgress = CSTRING(Applying_Splint); category = "bandage"; icon = QPATHTOEF(medical_gui,ui\splint.paa); + medicRequired = QGVAR(medicSplint); allowedSelections[] = {"LeftArm", "RightArm", "LeftLeg", "RightLeg"}; items[] = {"ACE_splint"}; + treatmentLocations = QGVAR(locationSplint); treatmentTime = QGVAR(treatmentTimeSplint); callbackSuccess = QFUNC(splint); condition = QFUNC(canSplint); @@ -115,9 +117,11 @@ class GVAR(actions) { displayName = CSTRING(Inject_Morphine); displayNameProgress = CSTRING(Injecting_Morphine); icon = QPATHTOEF(medical_gui,ui\auto_injector.paa); + medicRequired = QGVAR(medicMorphine); allowedSelections[] = {"LeftArm", "RightArm", "LeftLeg", "RightLeg"}; category = "medication"; items[] = {"ACE_morphine"}; + treatmentLocations = QGVAR(locationMorphine); condition = ""; treatmentTime = QGVAR(treatmentTimeAutoinjector); callbackSuccess = QFUNC(medication); @@ -128,8 +132,10 @@ class GVAR(actions) { class Adenosine: Morphine { displayName = CSTRING(Inject_Adenosine); displayNameProgress = CSTRING(Injecting_Adenosine); + medicRequired = QGVAR(medicAdenosine); condition = QGVAR(advancedMedication); items[] = {"ACE_adenosine"}; + treatmentLocations = QGVAR(locationAdenosine); litter[] = {{"ACE_MedicalLitter_adenosine"}}; }; class Epinephrine: Morphine { diff --git a/addons/medical_treatment/initSettings.inc.sqf b/addons/medical_treatment/initSettings.inc.sqf index 7f0fc06764c..0f02f37b892 100644 --- a/addons/medical_treatment/initSettings.inc.sqf +++ b/addons/medical_treatment/initSettings.inc.sqf @@ -2,7 +2,7 @@ QGVAR(advancedDiagnose), "LIST", [LSTRING(AdvancedDiagnose_DisplayName), LSTRING(AdvancedDiagnose_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [[0, 1, 2, 3], [ELSTRING(common,Disabled), ELSTRING(common,Enabled), LSTRING(AdvancedDiagnose_DiagnoseCardiacArrest), LSTRING(AdvancedDiagnose_DiagnoseCardiacArrestDirect)], 1], true ] call CBA_fnc_addSetting; @@ -11,7 +11,7 @@ QGVAR(advancedMedication), "CHECKBOX", [LSTRING(AdvancedMedication_DisplayName), LSTRING(AdvancedMedication_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), true, true ] call CBA_fnc_addSetting; @@ -20,7 +20,7 @@ QGVAR(advancedBandages), "LIST", [LSTRING(AdvancedBandages_DisplayName), LSTRING(AdvancedBandages_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [[0, 1, 2], [ELSTRING(common,Disabled), ELSTRING(common,Enabled), LSTRING(AdvancedBandages_EnabledCanReopen)], 1], true ] call CBA_fnc_addSetting; @@ -29,7 +29,7 @@ QGVAR(bandageRollover), "CHECKBOX", [LSTRING(bandageRollover_DisplayName), LSTRING(bandageRollover_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), true, false // server can force if necessary, otherwise client decides ] call CBA_fnc_addSetting; @@ -38,7 +38,7 @@ QGVAR(bandageEffectiveness), "SLIDER", [LSTRING(bandageEffectiveness_DisplayName), LSTRING(bandageEffectiveness_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [0, 5, 1, 2], true ] call CBA_fnc_addSetting; @@ -47,7 +47,7 @@ QGVAR(woundReopenChance), "SLIDER", [LSTRING(WoundReopenChance_DisplayName), LSTRING(WoundReopenChance_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [0, 5, 1, 2], true ] call CBA_fnc_addSetting; @@ -56,7 +56,7 @@ QGVAR(clearTrauma), "LIST", [LSTRING(ClearTrauma_DisplayName), LSTRING(ClearTrauma_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [[0, 1, 2], [ELSTRING(common,Never), LSTRING(ClearTrauma_AfterStitch), LSTRING(ClearTrauma_AfterBandage)], 1], true ] call CBA_fnc_addSetting; @@ -66,7 +66,7 @@ QGVAR(locationsBoostTraining), "CHECKBOX", [ELSTRING(common,LocationsBoostTraining_DisplayName), LSTRING(LocationsBoostTraining_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), false, true ] call CBA_fnc_addSetting; @@ -75,7 +75,7 @@ QGVAR(allowSharedEquipment), "LIST", [LSTRING(AllowSharedEquipment_DisplayName), LSTRING(AllowSharedEquipment_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [[0, 1, 2], [LSTRING(AllowSharedEquipment_PriorityPatient), LSTRING(AllowSharedEquipment_PriorityMedic), ELSTRING(common,No)], 0], true ] call CBA_fnc_addSetting; @@ -84,7 +84,7 @@ QGVAR(convertItems), "LIST", [LSTRING(ConvertItems_DisplayName), LSTRING(ConvertItems_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [[0, 1, 2], [ELSTRING(common,Enabled), LSTRING(ConvertItems_RemoveOnly), ELSTRING(common,Disabled)], 0], 1, {[QGVAR(convertItems), _this] call EFUNC(common,cbaSettings_settingChanged)}, @@ -95,7 +95,7 @@ QGVAR(treatmentTimeAutoinjector), "SLIDER", [LSTRING(TreatmentTimeAutoinjector_DisplayName), LSTRING(TreatmentTimeAutoinjector_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [0.1, 60, 5, 1], true ] call CBA_fnc_addSetting; @@ -104,7 +104,7 @@ QGVAR(treatmentTimeTourniquet), "SLIDER", [LSTRING(TreatmentTimeTourniquet_DisplayName), LSTRING(TreatmentTimeTourniquet_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [0.1, 60, 7, 1], true ] call CBA_fnc_addSetting; @@ -113,7 +113,7 @@ QGVAR(treatmentTimeSplint), "SLIDER", [LSTRING(TreatmentTimeSplint_DisplayName), LSTRING(TreatmentTimeSplint_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [0.1, 60, 7, 1], true ] call CBA_fnc_addSetting; @@ -122,7 +122,7 @@ QGVAR(treatmentTimeBodyBag), "SLIDER", [LSTRING(TreatmentTimeBodyBag_DisplayName), LSTRING(TreatmentTimeBodyBag_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [0.1, 60, 15, 1], true ] call CBA_fnc_addSetting; @@ -131,7 +131,7 @@ QGVAR(treatmentTimeGrave), "SLIDER", [LSTRING(TreatmentTimeGrave_DisplayName), LSTRING(TreatmentTimeGrave_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [0.1, 120, 30, 1], true ] call CBA_fnc_addSetting; @@ -140,7 +140,7 @@ QGVAR(medicEpinephrine), "LIST", [LSTRING(MedicEpinephrine_DisplayName), LSTRING(MedicEpinephrine_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [[0, 1, 2], [LSTRING(Anyone), LSTRING(Medics), LSTRING(Doctors)], 0], true ] call CBA_fnc_addSetting; @@ -149,7 +149,62 @@ QGVAR(locationEpinephrine), "LIST", [LSTRING(LocationEpinephrine_DisplayName), LSTRING(LocationEpinephrine_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), + [[0, 1, 2, 3, 4], [ELSTRING(common,Anywhere), ELSTRING(common,Vehicle), LSTRING(MedicalFacilities), LSTRING(VehiclesAndFacilities), ELSTRING(common,Disabled)], 0], + true +] call CBA_fnc_addSetting; + +[ + QGVAR(medicMorphine), + "LIST", + [LSTRING(MedicMorphine_DisplayName), LSTRING(MedicMorphine_Description)], + LSTRING(Category), + [[0, 1, 2], [LSTRING(Anyone), LSTRING(Medics), LSTRING(Doctors)], 0], + true +] call CBA_fnc_addSetting; + +[ + QGVAR(locationMorphine), + "LIST", + [LSTRING(LocationMorphine_DisplayName), LSTRING(LocationMorphine_Description)], + LSTRING(Category), + [[0, 1, 2, 3, 4], [ELSTRING(common,Anywhere), ELSTRING(common,Vehicle), LSTRING(MedicalFacilities), LSTRING(VehiclesAndFacilities), ELSTRING(common,Disabled)], 0], + true +] call CBA_fnc_addSetting; + +[ + QGVAR(medicSplint), + "LIST", + [LSTRING(MedicSplint_DisplayName), LSTRING(MedicSplint_Description)], + LSTRING(Category), + [[0, 1, 2], [LSTRING(Anyone), LSTRING(Medics), LSTRING(Doctors)], 0], + true +] call CBA_fnc_addSetting; + + +[ + QGVAR(locationSplint), + "LIST", + [LSTRING(LocationSplint_DisplayName), LSTRING(LocationSplint_Description)], + LSTRING(Category), + [[0, 1, 2, 3, 4], [ELSTRING(common,Anywhere), ELSTRING(common,Vehicle), LSTRING(MedicalFacilities), LSTRING(VehiclesAndFacilities), ELSTRING(common,Disabled)], 0], + true +] call CBA_fnc_addSetting; + +[ + QGVAR(medicAdenosine), + "LIST", + [LSTRING(MedicAdenosine_DisplayName), LSTRING(MedicAdenosine_Description)], + LSTRING(Category), + [[0, 1, 2], [LSTRING(Anyone), LSTRING(Medics), LSTRING(Doctors)], 0], + true +] call CBA_fnc_addSetting; + +[ + QGVAR(locationAdenosine), + "LIST", + [LSTRING(LocationAdenosine_DisplayName), LSTRING(LocationAdenosine_Description)], + LSTRING(Category), [[0, 1, 2, 3, 4], [ELSTRING(common,Anywhere), ELSTRING(common,Vehicle), LSTRING(MedicalFacilities), LSTRING(VehiclesAndFacilities), ELSTRING(common,Disabled)], 0], true ] call CBA_fnc_addSetting; @@ -158,7 +213,7 @@ QGVAR(medicPAK), "LIST", [LSTRING(MedicPAK_DisplayName), LSTRING(MedicPAK_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [[0, 1, 2], [LSTRING(Anyone), LSTRING(Medics), LSTRING(Doctors)], 1], true ] call CBA_fnc_addSetting; @@ -167,7 +222,7 @@ QGVAR(locationPAK), "LIST", [LSTRING(LocationPAK_DisplayName), LSTRING(LocationPAK_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [[0, 1, 2, 3, 4], [ELSTRING(common,Anywhere), ELSTRING(common,Vehicle), LSTRING(MedicalFacilities), LSTRING(VehiclesAndFacilities), ELSTRING(common,Disabled)], 3], true ] call CBA_fnc_addSetting; @@ -176,7 +231,7 @@ QGVAR(consumePAK), "LIST", [LSTRING(ConsumePAK_DisplayName), LSTRING(ConsumePAK_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [[0, 1], [ELSTRING(common,No), ELSTRING(common,Yes)], 0], true ] call CBA_fnc_addSetting; @@ -185,7 +240,7 @@ QGVAR(allowSelfPAK), "LIST", [LSTRING(AllowSelfPAK_DisplayName), LSTRING(AllowSelfPAK_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [[0, 1], [ELSTRING(common,No), ELSTRING(common,Yes)], 0], true ] call CBA_fnc_addSetting; @@ -194,7 +249,7 @@ QGVAR(timeCoefficientPAK), "SLIDER", [LSTRING(TimeCoefficientPAK_DisplayName), LSTRING(TimeCoefficientPAK_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [0, 5, 1, 1], true ] call CBA_fnc_addSetting; @@ -203,7 +258,7 @@ QGVAR(medicSurgicalKit), "LIST", [LSTRING(MedicSurgicalKit_DisplayName), LSTRING(MedicSurgicalKit_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [[0, 1, 2], [LSTRING(Anyone), LSTRING(Medics), LSTRING(Doctors)], 1], true ] call CBA_fnc_addSetting; @@ -212,7 +267,7 @@ QGVAR(locationSurgicalKit), "LIST", [LSTRING(LocationSurgicalKit_DisplayName), LSTRING(LocationSurgicalKit_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [[0, 1, 2, 3, 4], [ELSTRING(common,Anywhere), ELSTRING(common,Vehicle), LSTRING(MedicalFacilities), LSTRING(VehiclesAndFacilities), ELSTRING(common,Disabled)], 2], true ] call CBA_fnc_addSetting; @@ -221,7 +276,7 @@ QGVAR(consumeSurgicalKit), "LIST", [LSTRING(ConsumeSurgicalKit_DisplayName), LSTRING(ConsumeSurgicalKit_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [[0, 1, 2], ["str_eval_typenothing", LSTRING(SurgicalKit_Display), LSTRING(Suture_Display)], 0], true ] call CBA_fnc_addSetting; @@ -230,7 +285,7 @@ QGVAR(allowSelfStitch), "LIST", [LSTRING(AllowSelfStitch_DisplayName), LSTRING(AllowSelfStitch_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [[0, 1], [ELSTRING(common,No), ELSTRING(common,Yes)], 0], true ] call CBA_fnc_addSetting; @@ -239,7 +294,7 @@ QGVAR(woundStitchTime), "SLIDER", [LSTRING(WoundStitchTime_DisplayName), LSTRING(WoundStitchTime_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [0.1, 60, 5, 1], true ] call CBA_fnc_addSetting; @@ -248,7 +303,7 @@ QGVAR(medicIV), "LIST", [LSTRING(MedicIV_DisplayName), LSTRING(MedicIV_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [[0, 1, 2], [LSTRING(Anyone), LSTRING(Medics), LSTRING(Doctors)], 1], true ] call CBA_fnc_addSetting; @@ -257,7 +312,7 @@ QGVAR(locationIV), "LIST", [LSTRING(LocationIV_DisplayName), LSTRING(LocationIV_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [[0, 1, 2, 3, 4], [ELSTRING(common,Anywhere), ELSTRING(common,Vehicle), LSTRING(MedicalFacilities), LSTRING(VehiclesAndFacilities), ELSTRING(common,Disabled)], 0], 1 ] call CBA_fnc_addSetting; @@ -266,7 +321,7 @@ QGVAR(allowSelfIV), "LIST", [LSTRING(AllowSelfIV_DisplayName), LSTRING(AllowSelfIV_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [[0, 1], [ELSTRING(common,No), ELSTRING(common,Yes)], 1], true ] call CBA_fnc_addSetting; @@ -275,7 +330,7 @@ QGVAR(treatmentTimeIV), "SLIDER", [LSTRING(TreatmentTimeIV_DisplayName), LSTRING(TreatmentTimeIV_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [0.1, 60, 12, 1], true ] call CBA_fnc_addSetting; @@ -284,7 +339,7 @@ QGVAR(cprSuccessChanceMin), "SLIDER", [LSTRING(CPRSuccessChanceMin_DisplayName), LSTRING(CPRSuccessChanceMin_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [0, 1, 0.4, 2, true], true ] call CBA_fnc_addSetting; @@ -293,7 +348,7 @@ QGVAR(cprSuccessChanceMax), "SLIDER", [LSTRING(CPRSuccessChanceMax_DisplayName), LSTRING(CPRSuccessChanceMax_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [0, 1, 0.4, 2, true], true ] call CBA_fnc_addSetting; @@ -302,7 +357,7 @@ QGVAR(treatmentTimeCPR), "SLIDER", [LSTRING(TreatmentTimeCPR_DisplayName), LSTRING(TreatmentTimeCPR_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [0.1, 60, 15, 1], true ] call CBA_fnc_addSetting; @@ -311,7 +366,7 @@ QGVAR(treatmentTimeCoeffZeus), "SLIDER", [LSTRING(TreatmentTimeCoeffZeus_DisplayName), LSTRING(TreatmentTimeCoeffZeus_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [0, 10, 1, 2] ] call CBA_fnc_addSetting; @@ -319,7 +374,7 @@ QGVAR(allowBodyBagUnconscious), "CHECKBOX", [LSTRING(AllowBodyBagUnconscious_DisplayName), LSTRING(AllowBodyBagUnconscious_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), false, true ] call CBA_fnc_addSetting; @@ -328,7 +383,7 @@ QGVAR(allowGraveDigging), "LIST", [LSTRING(AllowGraveDigging_DisplayName), LSTRING(AllowGraveDigging_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [[0, 1, 2], [ELSTRING(common,Disabled), LSTRING(AllowGraveDigging_graveOnlyDead), ELSTRING(common,Yes)], 1], true ] call CBA_fnc_addSetting; @@ -337,7 +392,7 @@ QGVAR(graveDiggingMarker), "CHECKBOX", [LSTRING(GraveDiggingMarker_DisplayName), LSTRING(GraveDiggingMarker_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), true, true ] call CBA_fnc_addSetting; @@ -346,7 +401,7 @@ QGVAR(holsterRequired), "LIST", [LSTRING(HolsterRequired_DisplayName), LSTRING(HolsterRequired_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], + LSTRING(Category), [[0, 1, 2, 3, 4], [ELSTRING(common,Disabled), LSTRING(HolsterRequired_Lowered), LSTRING(HolsterRequired_LoweredExam), LSTRING(HolsterRequired_Holstered), LSTRING(HolsterRequired_HolsteredExam)], 0], true ] call CBA_fnc_addSetting; @@ -355,7 +410,7 @@ QGVAR(allowLitterCreation), "CHECKBOX", [LSTRING(AllowLitterCreation_DisplayName), LSTRING(AllowLitterCreation_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Litter)], + [LSTRING(Category), LSTRING(SubCategory_Litter)], true, true ] call CBA_fnc_addSetting; @@ -364,7 +419,7 @@ QGVAR(maxLitterObjects), "LIST", [LSTRING(MaxLitterObjects_DisplayName), LSTRING(MaxLitterObjects_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Litter)], + [LSTRING(Category), LSTRING(SubCategory_Litter)], [[50, 100, 200, 300, 400, 500, 1000, 2000, 3000, 4000, 5000], [/* settings function will auto create names */], 5], true ] call CBA_fnc_addSetting; @@ -373,7 +428,7 @@ QGVAR(litterCleanupDelay), "SLIDER", [LSTRING(LitterCleanupDelay_DisplayName), LSTRING(LitterCleanupDelay_Description)], - [ELSTRING(medical,Category), LSTRING(SubCategory_Litter)], + [LSTRING(Category), LSTRING(SubCategory_Litter)], [-1, 3600, 600, 0], true ] call CBA_fnc_addSetting; diff --git a/addons/medical_treatment/script_component.hpp b/addons/medical_treatment/script_component.hpp index 6a334ed72a3..e315dd94b3a 100644 --- a/addons/medical_treatment/script_component.hpp +++ b/addons/medical_treatment/script_component.hpp @@ -20,7 +20,7 @@ // Returns a text config entry as compiled code or variable from missionNamespace #define GET_FUNCTION(var,cfg) \ private var = getText (cfg); \ - if (isNil var) then { \ + if (missionNamespace isNil var) then { \ var = compile var; \ } else { \ var = missionNamespace getVariable var; \ diff --git a/addons/medical_treatment/stringtable.xml b/addons/medical_treatment/stringtable.xml index b0d140d8255..2332df22ad2 100644 --- a/addons/medical_treatment/stringtable.xml +++ b/addons/medical_treatment/stringtable.xml @@ -1,6 +1,23 @@ + + ACE Medical Treatment + ACE-Medicsystem Behandlung + ACE Медицина Лечение + ACE Opcje medyczne Leczenie + Médico ACE Tratamiento + ACE Zdravotnické Léčba + ACE Médico Tratamento + ACE Médical Traitement + ACE Orvosi Rendszer + ACE Medica Trattamento + ACE 의료 치료 + ACE 医疗 治疗 + ACE 醫療系統 治療 + ACE Medikal Tedavi + ACE 医療 治療 + Treatment Behandlung @@ -546,6 +563,42 @@ Controla donde puede sr usada la Epinefrina. 에피네프린을 사용할 수 있는 장소를 정합니다. + + Allow Splint + + + Training level required to use Splint. + + + Locations Splint + + + Controls where Splints can be used. + + + Allow Morphine + + + Training level required to use Morphine. + + + Locations Morphine + + + Controls where Morphine can be used. + + + Allow Adenosine + + + Training level required to use Adenosine. + + + Locations Adenosine + + + Controls where Adenosine can be used. + Allow PAK Доступ к Аптечке diff --git a/addons/microdagr/XEH_clientInit.sqf b/addons/microdagr/XEH_clientInit.sqf index c17914ad4b6..2b8bcd88b38 100644 --- a/addons/microdagr/XEH_clientInit.sqf +++ b/addons/microdagr/XEH_clientInit.sqf @@ -53,5 +53,6 @@ GVAR(settingShowAllWaypointsOnMap) = true; GVAR(newWaypointPosition) = []; GVAR(currentWaypoint) = -1; GVAR(rangeFinderPositionASL) = []; +GVAR(prevWaypointsCount) = 0; GVAR(mgrsGridZoneDesignator) = format ["%1 %2",EGVAR(common,MGRS_data) select 0, EGVAR(common,MGRS_data) select 1]; diff --git a/addons/microdagr/functions/fnc_saveCurrentAndSetNewMode.sqf b/addons/microdagr/functions/fnc_saveCurrentAndSetNewMode.sqf index c756b63141b..72822cff409 100644 --- a/addons/microdagr/functions/fnc_saveCurrentAndSetNewMode.sqf +++ b/addons/microdagr/functions/fnc_saveCurrentAndSetNewMode.sqf @@ -22,7 +22,7 @@ private _display = uiNamespace getVariable [[QGVAR(RscTitleDisplay), QGVAR(Dialo if (isNull _display) exitWith {LOG("No Display");}; -if (GVAR(currentApplicationPage) == 2) then { +if (GVAR(currentApplicationPage) == APP_MODE_MAP) then { private _theMap = [_display displayCtrl IDC_MAPDETAILS, _display displayCtrl IDC_MAPPLAIN] select (!GVAR(mapShowTexture)); private _mapCtrlPos = ctrlPosition _theMap; @@ -32,7 +32,7 @@ if (GVAR(currentApplicationPage) == 2) then { GVAR(mapZoom) = (ctrlMapScale _theMap) * _mapSize; //Hit button again, toggle map modes: - if (_newMode == 2) then { + if (_newMode == APP_MODE_MAP) then { if (GVAR(mapShowTexture)) then { GVAR(mapShowTexture) = false; } else { diff --git a/addons/microdagr/functions/fnc_updateDisplay.sqf b/addons/microdagr/functions/fnc_updateDisplay.sqf index e5de2b2fe49..5407635d0de 100644 --- a/addons/microdagr/functions/fnc_updateDisplay.sqf +++ b/addons/microdagr/functions/fnc_updateDisplay.sqf @@ -166,13 +166,20 @@ case (APP_MODE_WAYPOINTS): { _wpListBox lbSetTextRight [_forEachIndex, (format ["%1km", _2dDistanceKm toFixed GVAR(waypointPrecision)])]; } forEach _waypoints; - _currentIndex = (_currentIndex max 0) min (count _waypoints); + // Select last created waypoint + private _currWaypointsCount = count _waypoints; + if (_currWaypointsCount > (GVAR(prevWaypointsCount))) then { + _currentIndex = _currWaypointsCount - 1; + } else { + _currentIndex = (_currentIndex max 0) min (_currWaypointsCount - 1); + }; if ((lbCurSel _wpListBox) != _currentIndex) then { _wpListBox lbSetCurSel _currentIndex; }; //Reset focus to a dummy ctrl (top button), otherwise HOME/POS1 key goes to top of listBox and has keybind blocked ctrlSetFocus (_display displayCtrl IDC_TOPMENUBUTTON); + GVAR(prevWaypointsCount) = _currWaypointsCount; }; case (APP_MODE_SETUP): { diff --git a/addons/missile_gbu/stringtable.xml b/addons/missile_gbu/stringtable.xml index cee2b448c60..e4ebb0590a9 100644 --- a/addons/missile_gbu/stringtable.xml +++ b/addons/missile_gbu/stringtable.xml @@ -8,6 +8,7 @@ GBU-12 [ACE] GBU-12 [ACE] GBU-12 [ACE] + GBU-12 [ACE] FAB-250M-54 [ACE] @@ -16,6 +17,7 @@ FAB-250M-54 [ACE] FAB-250M-54 [ACE] ФАБ-250M-54 [ACE] + FAB-250M-54 [ACE] 1x GBU-12 [ACE] @@ -24,6 +26,7 @@ 1x GBU-12 [ACE] 1x GBU-12 [ACE] 1x GBU-12 [ACE] + 1x GBU-12 [ACE] 2x GBU-12 [ACE] @@ -32,6 +35,7 @@ 2x GBU-12 [ACE] 2x GBU-12 [ACE] 2x GBU-12 [ACE] + 2x GBU-12 [ACE] 4x GBU-12 [ACE] @@ -40,6 +44,7 @@ 4x GBU-12 [ACE] 4x GBU-12 [ACE] 4x GBU-12 [ACE] + 4x GBU-12 [ACE] 1x FAB-250M-54 [ACE] @@ -48,6 +53,7 @@ 1x FAB-250M-54 [ACE] 1x FAB-250M-54 [ACE] 1x ФАБ-250M-54 [ACE] + 1x FAB-250M-54 [ACE] 2x FAB-250M-54 [ACE] @@ -56,6 +62,7 @@ 2x FAB-250M-54 [ACE] 2x FAB-250M-54 [ACE] 2x ФАБ-250M-54 [ACE] + 2x FAB-250M-54 [ACE] diff --git a/addons/missile_vikhr/stringtable.xml b/addons/missile_vikhr/stringtable.xml index 622bb3af757..ad9e1a302c3 100644 --- a/addons/missile_vikhr/stringtable.xml +++ b/addons/missile_vikhr/stringtable.xml @@ -8,6 +8,7 @@ 9k121 ヴィーフリ [ACE] 9K121 비흐르 [ACE] 9k121 Вихрь [ACE] + 9k121 Vikhr [ACE] 1x 9k121 Vikhr [ACE] @@ -16,6 +17,7 @@ 1x 9k121 ヴィーフリ [ACE] 1x 9K121 비흐르 [ACE] 1x 9k121 Вихрь [ACE] + 1x 9k121 Vikhr [ACE] 2x 9k121 Vikhr [ACE] @@ -24,6 +26,7 @@ 2x 9k121 ヴィーフリ [ACE] 2x 9K121 비흐르 [ACE] 2x 9k121 Вихрь [ACE] + 2x 9k121 Vikhr [ACE] 3x 9k121 Vikhr [ACE] @@ -32,6 +35,7 @@ 3x 9k121 ヴィーフリ [ACE] 3x 9K121 비흐르 [ACE] 3x 9k121 Вихрь [ACE] + 3x 9k121 Vikhr [ACE] 4x 9k121 Vikhr [ACE] @@ -40,6 +44,7 @@ 4x 9k121 ヴィーフリ [ACE] 4x 9K121 비흐르 [ACE] 4x 9k121 Вихрь [ACE] + 4x 9k121 Vikhr [ACE] 6x 9k121 Vikhr [ACE] @@ -48,6 +53,7 @@ 6x 9k121 ヴィーフリ [ACE] 6x 9K121 비흐르 [ACE] 6x 9k121 Вихрь [ACE] + 6x 9k121 Vikhr [ACE] 8x 9k121 Vikhr [ACE] @@ -56,6 +62,7 @@ 8x 9k121 ヴィーフリ [ACE] 8x 9K121 비흐르 [ACE] 8x 9k121 Вихрь [ACE] + 8x 9k121 Vikhr [ACE] diff --git a/addons/scopes/stringtable.xml b/addons/scopes/stringtable.xml index 947447d379c..b7891da2001 100644 --- a/addons/scopes/stringtable.xml +++ b/addons/scopes/stringtable.xml @@ -355,6 +355,7 @@ 스코프에 조절 UI 보이기 Показать интерфейс настройки в области видимости. Mostrar IU de ajuste en el visor + Afficher l'IU de réglage du réticule dans la lunette de visée Minor adjustment up diff --git a/addons/spectator/functions/fnc_cam_setCameraMode.sqf b/addons/spectator/functions/fnc_cam_setCameraMode.sqf index 2b0af6a80bd..e8eddfbb808 100644 --- a/addons/spectator/functions/fnc_cam_setCameraMode.sqf +++ b/addons/spectator/functions/fnc_cam_setCameraMode.sqf @@ -61,7 +61,12 @@ if (!isNull _focus || _newMode == MODE_FREE) then { if (_newMode == MODE_FREE) then { _camera cameraEffect ["Internal", "BACK"]; - switchCamera GVAR(camAgentFree); // Fix draw3D while in free camera for case where player is perma-dead + + // Waiting for correct client state avoids "Side" being spammed every frame in RPT + if (getClientStateNumber >= 10) then { + switchCamera GVAR(camAgentFree); // Fix draw3D while in free camera for case where player is perma-dead + }; + _camera setDir getDirVisual _camera; if (!isNull _focus) then { diff --git a/addons/spectator/functions/fnc_ui_toggleUI.sqf b/addons/spectator/functions/fnc_ui_toggleUI.sqf index ff34798c690..91decbfa933 100644 --- a/addons/spectator/functions/fnc_ui_toggleUI.sqf +++ b/addons/spectator/functions/fnc_ui_toggleUI.sqf @@ -1,7 +1,8 @@ #include "..\script_component.hpp" /* * Author: Nelson Duarte, AACO, kymckay - * Function used to toggle the whole user interface + * Function used to toggle the whole user interface. + * When toggled on it restores the UI to the state it was in when it was toggled off. * * Arguments: * None @@ -15,19 +16,83 @@ * Public: No */ -private _visible = !GVAR(uiVisible); +private _visible = GVAR(uiVisible); { - private _fade = 1; - if (_visible) then { - _fade = getNumber (configFile >> QGVAR(display) >> "Controls" >> ctrlClassName _x >> "fade"); + private _fade = if (_visible) then { + 1 + } else { + getNumber (configFile >> QGVAR(display) >> "Controls" >> ctrlClassName _x >> "fade") }; _x ctrlSetFade _fade; _x ctrlCommit 0.25; -} forEach [CTRL_LIST, CTRL_TABS, CTRL_CAM_TYPES, CTRL_WIDGET]; +} forEach [CTRL_LIST, CTRL_TABS, CTRL_CAM_TYPES, CTRL_WIDGET, CTRL_COMPASS]; -showChat !_visible; -playSound (["HintExpand","HintCollapse"] select _visible); +if (_visible) then { + // If UI is to be toggled off, save what is currently visible + GVAR(toggleUiOpenDisplays) = [GVAR(uiHelpVisible), GVAR(uiMapVisible), GVAR(drawUnits), GVAR(drawProjectiles)]; -GVAR(uiVisible) = _visible; + // Turn help off + if (GVAR(uiHelpVisible)) then { + { + _x ctrlSetFade 1; + _x ctrlCommit 0.25; + } forEach [CTRL_HELP_BACK, CTRL_HELP]; + + GVAR(uiHelpVisible) = !GVAR(uiHelpVisible); + }; + + // Turn off map + if (GVAR(uiMapVisible)) then { + [] call FUNC(ui_toggleMap); + }; + + // Turn unit markers off + if (GVAR(drawUnits)) then { + GVAR(drawUnits) = !GVAR(drawUnits); + }; + + // Turn projectile markers off + if (GVAR(drawProjectiles)) then { + GVAR(drawProjectiles) = !GVAR(drawProjectiles); + }; +} else { + // If UI is to be toggled on + (missionNamespace getVariable [QGVAR(toggleUiOpenDisplays), []]) params [ + ["_helpWasVisible", false], + ["_mapWasVisible", false], + ["_unitsWereVisible", false], + ["_projectilesWereVisible", false] + ]; + + // Turn help on if previously enabled and help is now disabled + if (_helpWasVisible && !GVAR(uiHelpVisible)) then { + { + _x ctrlSetFade (getNumber (configFile >> QGVAR(display) >> "Controls" >> ctrlClassName _x >> "fade")); + _x ctrlCommit 0.25; + } forEach [CTRL_HELP_BACK, CTRL_HELP]; + + GVAR(uiHelpVisible) = !GVAR(uiHelpVisible); + }; + + // Turn map on if previously enabled and map is now disabled + if (_mapWasVisible && !GVAR(uiMapVisible)) then { + [] call FUNC(ui_toggleMap); + }; + + // Turn unit markers on if previously enabled and unit markers are now disabled + if (_unitsWereVisible && !GVAR(drawUnits)) then { + GVAR(drawUnits) = !GVAR(drawUnits); + }; + + // Turn projectile markers on if previously enabled and projectile markers are now disabled + if (_projectilesWereVisible && !GVAR(drawProjectiles)) then { + GVAR(drawProjectiles) = !GVAR(drawProjectiles); + }; +}; + +showChat _visible; +playSound (["HintExpand", "HintCollapse"] select !_visible); + +GVAR(uiVisible) = !_visible; diff --git a/addons/spectator/script_component.hpp b/addons/spectator/script_component.hpp index c29c60bdefc..357b75690b5 100644 --- a/addons/spectator/script_component.hpp +++ b/addons/spectator/script_component.hpp @@ -138,3 +138,5 @@ #define CTRL_WIDGET_WEAPON (SPEC_DISPLAY displayCtrl IDC_WIDGET_WEAPON) #define IDC_WIDGET_THROWABLE 60042 #define CTRL_WIDGET_THROWABLE (SPEC_DISPLAY displayCtrl IDC_WIDGET_THROWABLE) +#define IDC_COMPASS 60043 +#define CTRL_COMPASS (SPEC_DISPLAY displayCtrl IDC_COMPASS) diff --git a/addons/spectator/ui.hpp b/addons/spectator/ui.hpp index d81887db760..a1d8a745501 100644 --- a/addons/spectator/ui.hpp +++ b/addons/spectator/ui.hpp @@ -456,6 +456,8 @@ class GVAR(display) { }; }; }; - class compass: EGVAR(common,CompassControl) {}; + class compass: EGVAR(common,CompassControl) { + idc = IDC_COMPASS; + }; }; }; diff --git a/docs/wiki/development/arma-3-scheduler-and-our-practices.md b/docs/wiki/development/arma-3-scheduler-and-our-practices.md index d2ffda2a07f..88c06f92576 100644 --- a/docs/wiki/development/arma-3-scheduler-and-our-practices.md +++ b/docs/wiki/development/arma-3-scheduler-and-our-practices.md @@ -36,7 +36,7 @@ Code running in the unscheduled environment uses linear execution, that means it ## 2. What is the scheduler and why do I care? -The Arma 3 script scheduler basically gives a fair-share execution to all running scripts, FSMs, and SQS files running on any given client or server at any given time. See the [Biki article](https://community.bistudio.com/wiki/Biki2.0:Performance_Considerations){:target="_blank"} for an in-depth explanation of this. What this basically means though, is that all scripts get a fair share; this also means scheduled execution is drastically affected by other mods that use scheduled execution. For example, if 2 different spawn's are running in a tight loop of `while {true} do {...};`, they will both get exactly 50% of the scheduling time. +The Arma 3 script scheduler basically gives a fair-share execution to all running scripts, FSMs, and SQS files running on any given client or server at any given time. What this basically means though, is that all scripts get a fair share; this also means scheduled execution is drastically affected by other mods that use scheduled execution. For example, if 2 different spawn's are running in a tight loop of `while {true} do {...};`, they will both get exactly 50% of the scheduling time. With the way mission makers and mod makers generally use `spawn`/`execVM`, this means you're actually getting drastically less execution time in the scheduled environment than you might think. This leads to visible delay issues all the way up to massive delay on execution. You can easily test and prove this by looping spawns and watching the execution times extend. @@ -109,3 +109,8 @@ See: [https://github.com/CBATeam/CBA_A3/blob/master/addons/common/fnc_waitUntilA ```sqf [{condition}, {code}, [params]] call CBA_fnc_waitUntilAndExecute; ``` + +## 4 Additional Information +Biki: +- https://community.bistudio.com/wiki/Code_Best_Practices +- https://community.bistudio.com/wiki/Code_Optimisation diff --git a/docs/wiki/framework/arsenal-framework.md b/docs/wiki/framework/arsenal-framework.md index 330e7fa99b1..2f37e552e1e 100644 --- a/docs/wiki/framework/arsenal-framework.md +++ b/docs/wiki/framework/arsenal-framework.md @@ -137,8 +137,8 @@ Examples: ACE Arsenal uses 2 existing config entries to sort and display items. - `baseWeapon`: Class name that is used to display an item in the arsenal, used for weapon/attachment variants that are not normally shown to the player (AI variants, PIP optics, and so on). This property can be applied to any weapon or weapon attachment in `CfgWeapons`. Items using CBA or RHS' Scripted Optics systems, or CBA Switchable Attachments do not need this property explictly set, and will automatically use their player-accessible class. -- `ACE_isUnique`: Classes in `CfgMagazines` with this property set to `1` will be treated and shown by the Arsenal as Misc. Items. Used for items with attached data that needs to be kept track of, such as Notepads or Spare Barrels. -- `ACE_asItem`: Classes in `CfgMagazines` with this property set to `1` will be treated and shown by the Arsenal as Items. Used for magazines that are not meant to be used in a weapon, such as Painkillers. +- `ACE_isUnique`: Classes in `CfgWeapons` or `CfgMagazines` with this property set to `1` will be treated and shown by the Arsenal as Misc. Items. Used for items with attached data that needs to be kept track of, such as Notepads or Spare Barrels. +- `ACE_asItem`: Classes in `CfgWeapons` or `CfgMagazines` with this property set to `1` will be treated and shown by the Arsenal as Items. Used for magazines that are not meant to be used in a weapon, such as Painkillers. ### 3.2 New config entries