From 0c529446ec4944c3f42e7ccf59d3bb9a313c47d3 Mon Sep 17 00:00:00 2001 From: Kex Date: Sun, 7 Apr 2024 17:57:14 +0200 Subject: [PATCH 001/290] Fix bug template (#9936) --- .github/ISSUE_TEMPLATE/bug_report.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index c71190ce39..08c14747e5 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -23,14 +23,14 @@ All good? Then proceed and fill out the items below. **Mods (complete and add to the following information):** - **Arma 3:** `x.xx` [e.g. 1.00 stable, rc, dev] - **CBA:** `3.x.x` [e.g. 3.0.0 stable, commit hash] -- **ACE3:** `3.x.x` [eg. 3.0.0 stable, commit hash] +- **ACE3:** `3.x.x` [e.g. 3.0.0 stable, commit hash] **Description:** A clear and concise description of what the bug is. **Steps to reproduce:** -_Follow [https://ace3.acemod.org/img/wiki/user/issue_flowchart.webp](this flowchart)!_ +_Follow [this flowchart](https://ace3.acemod.org/img/wiki/user/issue_flowchart.webp)!_ 1. _Go to ..._ 2. _Click ..._ From 095ce882792f3be4b4c2ab6daea7239be36fbe75 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sun, 7 Apr 2024 17:59:14 +0200 Subject: [PATCH 002/290] Hearing - Notify restart req. for combat deafness setting (#9934) --- addons/hearing/initSettings.inc.sqf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/hearing/initSettings.inc.sqf b/addons/hearing/initSettings.inc.sqf index f22a7b4eda..8856ad1202 100644 --- a/addons/hearing/initSettings.inc.sqf +++ b/addons/hearing/initSettings.inc.sqf @@ -5,7 +5,9 @@ private _category = format ["ACE %1", localize LSTRING(Module_DisplayName)]; [LSTRING(EnableCombatDeafness_DisplayName), LSTRING(EnableCombatDeafness_Description)], _category, true, - 1 + 1, + {[QGVAR(enableCombatDeafness), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart ] call CBA_fnc_addSetting; [ From 5130a220087e8bc3a0a77a2cc3fd46137df30fc7 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 10 Apr 2024 13:23:50 +0200 Subject: [PATCH 003/290] Hearing - Add setting to add earplugs to all units (#9935) Add option to add earplugs to all units --- addons/hearing/functions/fnc_addEarPlugs.sqf | 6 +++--- addons/hearing/initSettings.inc.sqf | 4 ++-- addons/hearing/stringtable.xml | 3 +++ 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/addons/hearing/functions/fnc_addEarPlugs.sqf b/addons/hearing/functions/fnc_addEarPlugs.sqf index c541d78618..035d82956f 100644 --- a/addons/hearing/functions/fnc_addEarPlugs.sqf +++ b/addons/hearing/functions/fnc_addEarPlugs.sqf @@ -24,10 +24,10 @@ params ["_unit"]; TRACE_2("params",_unit,typeOf _unit); // Exit if hearing is disabled OR autoAdd is disabled OR soldier has earplugs already in (persistence scenarios) -if (!GVAR(enableCombatDeafness) || {!GVAR(autoAddEarplugsToUnits)} || {[_unit] call FUNC(hasEarPlugsIn)}) exitWith {}; +if (!GVAR(enableCombatDeafness) || {GVAR(autoAddEarplugsToUnits) == 0} || {[_unit] call FUNC(hasEarPlugsIn)}) exitWith {}; -// add earplugs if the soldier has a rocket launcher -if ((secondaryWeapon _unit) != "") exitWith { +// Add earplugs if enabled for everyone or if the soldier has a rocket launcher +if (GVAR(autoAddEarplugsToUnits) == 2 || {(secondaryWeapon _unit) != ""}) exitWith { TRACE_1("has launcher - adding",_unit); _unit addItem "ACE_EarPlugs"; }; diff --git a/addons/hearing/initSettings.inc.sqf b/addons/hearing/initSettings.inc.sqf index 8856ad1202..61b6d239c5 100644 --- a/addons/hearing/initSettings.inc.sqf +++ b/addons/hearing/initSettings.inc.sqf @@ -43,9 +43,9 @@ private _category = format ["ACE %1", localize LSTRING(Module_DisplayName)]; ] call CBA_fnc_addSetting; [ - QGVAR(autoAddEarplugsToUnits), "CHECKBOX", + QGVAR(autoAddEarplugsToUnits), "LIST", [LSTRING(autoAddEarplugsToUnits_DisplayName), LSTRING(autoAddEarplugsToUnits_Description)], _category, - true, + [[0, 1, 2], [ELSTRING(common,Disabled), LSTRING(heavyWeaponUnits), ELSTRING(common,Enabled)], 1], 1 ] call CBA_fnc_addSetting; diff --git a/addons/hearing/stringtable.xml b/addons/hearing/stringtable.xml index 58d0bfa05d..de741e55c1 100644 --- a/addons/hearing/stringtable.xml +++ b/addons/hearing/stringtable.xml @@ -371,5 +371,8 @@ 귀마개 토글 Mettre/enlever les bouchons + + Only units with heavy weapons + From 3255dbef362560b363d7b4c1833560bb1fca9c2b Mon Sep 17 00:00:00 2001 From: lambdatiger Date: Wed, 10 Apr 2024 06:25:46 -0500 Subject: [PATCH 004/290] Compats - Add/Fix Adv, Vehicle Damage ERA and SLAT arrays (#9925) * added missing hitpoints and new classes * added CUP compats * Fixed missing base class and missing comma --- addons/compat_cup_vehicles/CfgVehicles.hpp | 136 +++++++++++++++++++++ addons/compat_rhs_afrf3/CfgVehicles.hpp | 67 +++++++++- 2 files changed, 198 insertions(+), 5 deletions(-) diff --git a/addons/compat_cup_vehicles/CfgVehicles.hpp b/addons/compat_cup_vehicles/CfgVehicles.hpp index 47c7f901f5..5334987fff 100644 --- a/addons/compat_cup_vehicles/CfgVehicles.hpp +++ b/addons/compat_cup_vehicles/CfgVehicles.hpp @@ -148,5 +148,141 @@ class CfgVehicles { roles[]={"cargo"}; }; }; + EGVAR(vehicle_damage,eraHitpoints)[] = { + "hitera_l1", "hitera_l2", "hitera_l3", "hitera_l4", "hitera_l5", + "hitera_l6", "hitera_l7", "hitera_l8", "hitera_r1", "hitera_r2", + "hitera_r3", "hitera_r4", "hitera_r5", "hitera_r6", "hitera_r7", + "hitera_r8", "hitera_t1", "hitera_t2", "hitera_t3", "hitera_t4", + "hitera_t5", "hitera_t6", "hitera_t7", "hitera_t8", "hitera_fr1", + "hitera_fr2", "hitera_fr3", "hitera_fr4", "hitera_fr5", "hitera_fr6", + "hitera_fr7", "hitera_fr8", "hitera_fr9", "hitera_fl1", "hitera_fl2", + "hitera_fl3", "hitera_fl4", "hitera_fl5" + }; + EGVAR(vehicle_damage,slatHitpoints)[] = {}; + }; + class CUP_T90_Base: Tank_F { + EGVAR(vehicle_damage,eraHitpoints)[] = { + "hitera_l1", "hitera_l2", "hitera_l3", "hitera_r1", "hitera_r2", + "hitera_r3", "hitera_1_t_l", "hitera_1_t_r", "hitera_2_t_l", + "hitera_2_t_r" + }; + EGVAR(vehicle_damage,slatHitpoints)[] = {}; + }; + class CUP_T90M_Base: Tank_F { + EGVAR(vehicle_damage,eraHitpoints)[] = { + "hitera_t1", "hitera_t2", "hitera_t3", "hitera_t4", "hitera_t5", + "hitera_t6", "hitera_t7", "hitera_t8", "hitera_t9", "hitera_t10", + "hitera_t11", "hitera_t12", "hitera_t13", "hitera_t14", "hitera_t15", + "hitera_t16", "hitera_t17", "hitera_t18", "hitera_t19", "hitera_t20", + "hitera_t21", "hitera_f1", "hitera_f2", "hitera_f3", "hitera_f4", + "hitera_f5", "hitera_f6", "hitera_f7", "hitera_s1", "hitera_s2", + "hitera_s3", "hitera_s4", "hitera_s5", "hitera_s6", "hitera_s7", + "hitera_s8", "hitera_s9", "hitera_s10", "hitera_s11", "hitera_s12", + "hitera_t22", "hitera_t23", "hitera_t24", "hitera_t25", "hitera_t26", + "hitera_t27", "hitera_t28", "hitera_t29", "hitera_t30", "hitera_t31", + "hitera_t32", "hitera_t33" + }; + EGVAR(vehicle_damage,slatHitpoints)[] = { + "hitslat_left", "hitslat_right", "hitslat_turret_rear", + "hitslat_turret_left", "hitslat_rear" + }; + }; + + class CUP_T72_ACR_Base; + class CUP_B_T72_CZ: CUP_T72_ACR_Base { + EGVAR(vehicle_damage,eraHitpoints)[] = { + "hitera_top_l1", "hitera_top_l2", "hitera_top_l3", "hitera_top_l4", + "hitera_top_r1", "hitera_top_r2", "hitera_top_r3", "hitera_top_r4", + "hitera_front_r1", "hitera_front_r2", "hitera_front_l1", + "hitera_front_l2", "hitera_top_rear" + }; + EGVAR(vehicle_damage,slatHitpoints)[] = {}; + }; + + class CUP_Leopard2_Base; + class CUP_Leopard2_ERA_Base: CUP_Leopard2_Base { + EGVAR(vehicle_damage,eraHitpoints)[] = { + "hitera_1", "hitera_2", "hitera_3", "hitera_4", "hitera_5", "hitera_6", + "hitera_7", "hitera_8", "hitera_9", "hitera_10", "hitera_11", "hitera_12", + "hitera_13", "hitera_14", "hitera_15", "hitera_16", "hitera_17", "hitera_18", + "hitera_19", "hitera_20", "hitera_21", "hitera_22", "hitera_23", "hitera_24", + "hitera_25", "hitera_26", "hitera_27", "hitera_28", "hitera_29", "hitera_30", + "hitera_31", "hitera_32", "hitera_33", "hitera_34", "hitera_35", "hitera_36", + "hitera_37", "hitera_38", "hitera_39", "hitera_40", "hitera_41", "hitera_42", + "hitera_43", "hitera_44", "hitera_45", "hitera_46", "hitera_47" + }; + EGVAR(vehicle_damage,slatHitpoints)[] = {}; + }; + + class CUP_M1_Abrams_base; + class CUP_M1A2_TUSK_base: CUP_M1_Abrams_base { + EGVAR(vehicle_damage,eraHitpoints)[] = { + "hitera_l1", "hitera_l2", "hitera_l3", "hitera_l4", "hitera_r1", + "hitera_r2", "hitera_r3", "hitera_r4" + }; + EGVAR(vehicle_damage,slatHitpoints)[] = { + "hitslat_rear" + }; + }; + + class CUP_M1Abrams_Base; + class CUP_M1Abrams_TUSK_Base: CUP_M1Abrams_Base { + EGVAR(vehicle_damage,eraHitpoints)[] = { + "hitera_l01", "hitera_l02", "hitera_l03", "hitera_l04", "hitera_l05", + "hitera_l06", "hitera_l07", "hitera_l08", "hitera_l09", "hitera_l10", + "hitera_l11", "hitera_l12", "hitera_l13", "hitera_l14", "hitera_l15", + "hitera_l16", "hitera_r01", "hitera_r02", "hitera_r03", "hitera_r04", + "hitera_r05", "hitera_r06", "hitera_r07", "hitera_r08", "hitera_r09", + "hitera_r10", "hitera_r11", "hitera_r12", "hitera_r13", "hitera_r14", + "hitera_r15", "hitera_r16" + }; + EGVAR(vehicle_damage,slatHitpoints)[] = { + "hitslat_rear" + }; + }; + + class CUP_M1Abrams_A2_Base; + class CUP_M1Abrams_A2_TUSK_Base: CUP_M1Abrams_A2_Base { + EGVAR(vehicle_damage,eraHitpoints)[] = { + "hitera_l01", "hitera_l02", "hitera_l03", "hitera_l04", "hitera_l05", + "hitera_l06", "hitera_l07", "hitera_l08", "hitera_l09", "hitera_l10", + "hitera_l11", "hitera_l12", "hitera_l13", "hitera_l14", "hitera_l15", + "hitera_l16", "hitera_l17", "hitera_l18", "hitera_l19", "hitera_l20", + "hitera_r01", "hitera_r02", "hitera_r03", "hitera_r04", "hitera_r05", + "hitera_r06", "hitera_r07", "hitera_r08", "hitera_r09", "hitera_r10", + "hitera_r11", "hitera_r12", "hitera_r13", "hitera_r14", "hitera_r15", + "hitera_r16", "hitera_r17", "hitera_r18", "hitera_r19", "hitera_r20" + }; + EGVAR(vehicle_damage,slatHitpoints)[] = { + "hitslat_rear" + }; + }; + + class CUP_M1A2Abrams_Base; + class CUP_M1A2Abrams_TUSK_Base: CUP_M1A2Abrams_Base { + EGVAR(vehicle_damage,eraHitpoints)[] = { + "hitera_l01", "hitera_l02", "hitera_l03", "hitera_l04", "hitera_l05", + "hitera_l06", "hitera_l07", "hitera_l08", "hitera_l09", "hitera_l10", + "hitera_l11", "hitera_l12", "hitera_l13", "hitera_l14", "hitera_l15", + "hitera_l16", "hitera_r01", "hitera_r02", "hitera_r03", "hitera_r04", + "hitera_r05", "hitera_r06", "hitera_r07", "hitera_r08", "hitera_r09", + "hitera_r10", "hitera_r11", "hitera_r12", "hitera_r13", "hitera_r14", + "hitera_r15", "hitera_r16" + }; + EGVAR(vehicle_damage,slatHitpoints)[] = { + "hitslat_rear" + }; + }; + class CUP_M1A2Abrams_TUSK_II_Base: CUP_M1A2Abrams_TUSK_Base { + EGVAR(vehicle_damage,eraHitpoints)[] = { + "hitera_l01", "hitera_l02", "hitera_l03", "hitera_l04", "hitera_l05", + "hitera_l06", "hitera_l07", "hitera_l08", "hitera_l09", "hitera_l10", + "hitera_l11", "hitera_l12", "hitera_l13", "hitera_l14", "hitera_l15", + "hitera_l16", "hitera_l17", "hitera_l18", "hitera_l19", "hitera_l20", + "hitera_r01", "hitera_r02", "hitera_r03", "hitera_r04", "hitera_r05", + "hitera_r06", "hitera_r07", "hitera_r08", "hitera_r09", "hitera_r10", + "hitera_r11", "hitera_r12", "hitera_r13", "hitera_r14", "hitera_r15", + "hitera_r16", "hitera_r17", "hitera_r18", "hitera_r19", "hitera_r20" + }; }; }; diff --git a/addons/compat_rhs_afrf3/CfgVehicles.hpp b/addons/compat_rhs_afrf3/CfgVehicles.hpp index 622d764ad2..1cf5029bc3 100644 --- a/addons/compat_rhs_afrf3/CfgVehicles.hpp +++ b/addons/compat_rhs_afrf3/CfgVehicles.hpp @@ -434,7 +434,11 @@ class CfgVehicles { "era_13_hitpoint", "era_14_hitpoint", "era_15_hitpoint", "era_16_hitpoint", "era_17_hitpoint", "era_18_hitpoint", "era_19_hitpoint", "era_20_hitpoint", "era_21_hitpoint", "era_22_hitpoint", "era_23_hitpoint", "era_24_hitpoint", "era_25_hitpoint", "era_26_hitpoint", "era_27_hitpoint", "era_28_hitpoint", "era_29_hitpoint", "era_30_hitpoint", - "era_31_hitpoint", "era_32_hitpoint" + "era_31_hitpoint", "era_32_hitpoint", "era_33_hitpoint", "era_34_hitpoint", "era_35_hitpoint", "era_36_hitpoint", + "era_37_hitpoint", "era_38_hitpoint", "era_39_hitpoint", "era_40_hitpoint", "era_41_hitpoint", "era_42_hitpoint", + "era_43_hitpoint", "era_44_hitpoint", "era_45_hitpoint", "era_46_hitpoint", "era_47_hitpoint", "era_48_hitpoint", + "era_49_hitpoint", "era_50_hitpoint", "era_58_hitpoint", "era_59_hitpoint", "era_60_hitpoint", "era_61_hitpoint", + "era_62_hitpoint", "era_63_hitpoint", "era_64_hitpoint", "era_65_hitpoint", "era_66_hitpoint", "era_67_hitpoint" }; EGVAR(vehicle_damage,slatHitpoints)[] = { "SLAT_51_hitpoint", "SLAT_52_hitpoint", "SLAT_53_hitpoint", @@ -470,6 +474,9 @@ class CfgVehicles { "era_43_hitpoint", "era_44_hitpoint", "era_45_hitpoint", "era_46_hitpoint", "era_47_hitpoint", "era_48_hitpoint", "era_49_hitpoint", "era_50_hitpoint" }; + EGVAR(vehicle_damage,slatHitpoints)[] = { + "slat_51_hitpoint", "slat_52_hitpoint", "slat_53_hitpoint", "slat_54_hitpoint" + }; }; class rhs_t90am_tv: rhs_t90_tv { EGVAR(vehicle_damage,eraHitpoints)[] = { @@ -483,7 +490,7 @@ class CfgVehicles { "era_43_hitpoint", "era_44_hitpoint", "era_45_hitpoint", "era_46_hitpoint", "era_47_hitpoint", "era_48_hitpoint", "era_49_hitpoint", "era_50_hitpoint", "era_51_hitpoint", "era_52_hitpoint", "era_53_hitpoint", "era_54_hitpoint", "era_55_hitpoint", "era_56_hitpoint", "era_57_hitpoint", "era_58_hitpoint", "era_59_hitpoint", "era_60_hitpoint", - "era_51_hitpoint", "era_62_hitpoint", "era_63_hitpoint", "era_64_hitpoint", "era_65_hitpoint", "era_66_hitpoint" + "era_61_hitpoint", "era_62_hitpoint", "era_63_hitpoint", "era_64_hitpoint", "era_65_hitpoint", "era_66_hitpoint" }; EGVAR(vehicle_damage,slatHitpoints)[] = { "SLAT_18_hitpoint", "SLAT_19_hitpoint", "SLAT_20_hitpoint", "SLAT_21_hitpoint", @@ -492,10 +499,31 @@ class CfgVehicles { }; }; class rhs_t90sm_tv: rhs_t90am_tv { + EGVAR(vehicle_damage,eraHitpoints)[] = { + "era_1_hitpoint", "era_2_hitpoint", "era_3_hitpoint", "era_4_hitpoint", + "era_5_hitpoint", "era_6_hitpoint", "era_7_hitpoint", "era_8_hitpoint", + "era_9_hitpoint", "era_10_hitpoint", "era_11_hitpoint", "era_12_hitpoint", + "era_13_hitpoint", "era_14_hitpoint", "era_15_hitpoint", "era_16_hitpoint", + "era_17_hitpoint", "era_18_hitpoint", "era_19_hitpoint", "era_20_hitpoint", + "era_21_hitpoint", "era_22_hitpoint", "era_24_hitpoint", "era_25_hitpoint", + "era_27_hitpoint", "era_28_hitpoint", "era_29_hitpoint", "era_30_hitpoint", + "era_31_hitpoint", "era_32_hitpoint", "era_33_hitpoint", "era_34_hitpoint", + "era_35_hitpoint", "era_36_hitpoint", "era_37_hitpoint", "era_38_hitpoint", + "era_39_hitpoint", "era_40_hitpoint", "era_41_hitpoint", "era_42_hitpoint", + "era_43_hitpoint", "era_44_hitpoint", "era_45_hitpoint", "era_46_hitpoint", + "era_47_hitpoint", "era_48_hitpoint", "era_49_hitpoint", "era_50_hitpoint", + "era_26_hitpoint", "era_55_hitpoint", "era_56_hitpoint", "era_57_hitpoint", + "era_58_hitpoint", "era_59_hitpoint", "era_60_hitpoint", "era_61_hitpoint", + "era_62_hitpoint", "era_63_hitpoint", "era_64_hitpoint", "era_65_hitpoint", + "era_66_hitpoint", "era_23_hitpoint" + }; EGVAR(vehicle_damage,slatHitpoints)[] = { - "SLAT_23_hitpoint", "SLAT_26_hitpoint", "SLAT_51_hitpoint", "SLAT_52_hitpoint", - "SLAT_53_hitpoint", "SLAT_54_hitpoint", "SLAT_55_hitpoint", "SLAT_56_hitpoint", - "SLAT_57_hitpoint" + "slat_23_hitpoint", "slat_26_hitpoint", "slat_51_hitpoint", + "slat_52_hitpoint", "slat_53_hitpoint", "slat_54_hitpoint", + "slat_55_hitpoint", "slat_56_hitpoint", "slat_57_hitpoint", + "slat_18_hitpoint", "slat_19_hitpoint", "slat_20_hitpoint", + "slat_21_hitpoint", "slat_22_hitpoint", "slat_24_hitpoint", + "slat_25_hitpoint" }; }; @@ -539,6 +567,35 @@ class CfgVehicles { "era_31_hitpoint", "era_32_hitpoint", "era_33_hitpoint", "era_34_hitpoint", "era_35_hitpoint", "era_36_hitpoint" }; }; + class rhs_t80um: rhs_t80u { + EGVAR(vehicle_damage,eraHitpoints)[] = { + "era_1_hitpoint", "era_2_hitpoint", "era_3_hitpoint", "era_4_hitpoint", "era_5_hitpoint", "era_6_hitpoint", + "era_7_hitpoint", "era_8_hitpoint", "era_9_hitpoint", "era_10_hitpoint", "era_11_hitpoint", "era_12_hitpoint", + "era_13_hitpoint", "era_14_hitpoint", "era_15_hitpoint", "era_16_hitpoint", "era_17_hitpoint", "era_18_hitpoint", + "era_19_hitpoint", "era_20_hitpoint", "era_21_hitpoint", "era_22_hitpoint", "era_23_hitpoint", "era_24_hitpoint", + "era_25_hitpoint", "era_26_hitpoint", "era_27_hitpoint", "era_28_hitpoint", "era_29_hitpoint", "era_30_hitpoint", + "era_31_hitpoint", "era_32_hitpoint", "era_33_hitpoint", "era_34_hitpoint", "era_35_hitpoint", "era_36_hitpoint" + }; + }; + + class rhs_t15_base; + class rhs_t15_tv: rhs_t15_base { + EGVAR(vehicle_damage,eraHitpoints)[] = { + "era_1_hitpoint", "era_2_hitpoint", "era_3_hitpoint", "era_4_hitpoint", + "era_5_hitpoint", "era_6_hitpoint", "era_7_hitpoint", "era_8_hitpoint", + "era_9_hitpoint", "era_10_hitpoint", "era_11_hitpoint", "era_12_hitpoint", + "era_13_hitpoint", "era_14_hitpoint", "era_15_hitpoint", "era_16_hitpoint", + "era_17_hitpoint", "era_18_hitpoint", "era_19_hitpoint", "era_20_hitpoint", + "era_21_hitpoint", "era_22_hitpoint", "era_23_hitpoint", "era_24_hitpoint", + "era_25_hitpoint", "era_26_hitpoint", "era_27_hitpoint", "era_28_hitpoint", + "era_29_hitpoint", "era_30_hitpoint", "era_31_hitpoint", "era_32_hitpoint", + "era_33_hitpoint", "era_34_hitpoint", "era_35_hitpoint", "era_36_hitpoint", + "era_37_hitpoint" + }; + EGVAR(vehicle_damage,slatHitpoints)[] = { + "slat_38_hitpoint", "slat_39_hitpoint", "slat_40_hitpoint", "slat_41_hitpoint" + }; + }; // Wirecutter Backpacks class rhs_assault_umbts; From 2b5ea1628f6c2e463d7367b2210ab2e3bdc9a19a Mon Sep 17 00:00:00 2001 From: OverlordZorn <56258612+OverlordZorn@users.noreply.github.com> Date: Wed, 10 Apr 2024 13:26:30 +0200 Subject: [PATCH 005/290] Weather - Winter Terrain Temperatures (#9943) * a -> an * Added last resort catch for winter maps to define suitable temps * removed debug line * purge :soap: * added check for "snow" in raintexture * cleaned up conditions * Update arma-3-scheduler-and-our-practices.md * isNull && {} * Update fnc_getMapData.sqf * Update fnc_getMapData.sqf * Update fnc_getMapData.sqf * changed order in condition checks and indentation * not so lazy * deep config lookup -> _cfg * comment * removed accidental empty line * :roller_coaster: * Update fnc_getMapData.sqf * Revert "Update fnc_getMapData.sqf" This reverts commit a57d114182ee094a873274dda8874f12780e4795. * Update addons/weather/functions/fnc_getMapData.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * Update addons/weather/functions/fnc_getMapData.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * Update addons/weather/functions/fnc_getMapData.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * then -> exitWith --------- Co-authored-by: Mr. Zorn <56258612+PulsarNeutronStar@users.noreply.github.com> Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- addons/weather/functions/fnc_getMapData.sqf | 49 ++++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/addons/weather/functions/fnc_getMapData.sqf b/addons/weather/functions/fnc_getMapData.sqf index c1cae6e2f8..555704fc87 100644 --- a/addons/weather/functions/fnc_getMapData.sqf +++ b/addons/weather/functions/fnc_getMapData.sqf @@ -48,34 +48,35 @@ GVAR(currentHumidity) = 0; GVAR(currentOvercast) = 0; // Get all non inherited arrays to filter maps that inherit from Stratis/Altis/Tanoa -private _nonInheritedArrays = configProperties [configFile >> "CfgWorlds" >> _worldName, "isArray _x", false]; +private _cfgPath = configFile >> "CfgWorlds" >> _worldName; +private _nonInheritedArrays = configProperties [_cfgPath, "isArray _x", false]; // And check if any custom non-inherited weather is defined through config and use that if so -if ((configFile >> "CfgWorlds" >> _worldName >> "ACE_TempDay") in _nonInheritedArrays) exitWith { - if (isArray (configFile >> "CfgWorlds" >> _worldName >> "ACE_TempDay")) then { - GVAR(TempDay) = getArray (configFile >> "CfgWorlds" >> _worldName >> "ACE_TempDay"); +if ((_cfgPath >> "ACE_TempDay") in _nonInheritedArrays) exitWith { + if (isArray (_cfgPath >> "ACE_TempDay")) then { + GVAR(TempDay) = getArray (_cfgPath >> "ACE_TempDay"); }; - if (isArray (configFile >> "CfgWorlds" >> _worldName >> "ACE_TempNight")) then { - GVAR(TempNight) = getArray (configFile >> "CfgWorlds" >> _worldName >> "ACE_TempNight"); + if (isArray (_cfgPath >> "ACE_TempNight")) then { + GVAR(TempNight) = getArray (_cfgPath >> "ACE_TempNight"); }; - if (isArray (configFile >> "CfgWorlds" >> _worldName >> "ACE_Humidity")) then { - GVAR(Humidity) = getArray (configFile >> "CfgWorlds" >> _worldName >> "ACE_Humidity"); + if (isArray (_cfgPath >> "ACE_Humidity")) then { + GVAR(Humidity) = getArray (_cfgPath >> "ACE_Humidity"); }; - if (isArray (configFile >> "CfgWorlds" >> _worldName >> "ACE_WindSpeedMin")) then { - GVAR(WindSpeedMin) = getArray (configFile >> "CfgWorlds" >> _worldName >> "ACE_WindSpeedMin"); + if (isArray (_cfgPath >> "ACE_WindSpeedMin")) then { + GVAR(WindSpeedMin) = getArray (_cfgPath >> "ACE_WindSpeedMin"); }; - if (isArray (configFile >> "CfgWorlds" >> _worldName >> "ACE_WindSpeedMean")) then { - GVAR(WindSpeedMean) = getArray (configFile >> "CfgWorlds" >> _worldName >> "ACE_WindSpeedMean"); + if (isArray (_cfgPath >> "ACE_WindSpeedMean")) then { + GVAR(WindSpeedMean) = getArray (_cfgPath >> "ACE_WindSpeedMean"); }; - if (isArray (configFile >> "CfgWorlds" >> _worldName >> "ACE_WindSpeedMax")) then { - GVAR(WindSpeedMax) = getArray (configFile >> "CfgWorlds" >> _worldName >> "ACE_WindSpeedMax"); + if (isArray (_cfgPath >> "ACE_WindSpeedMax")) then { + GVAR(WindSpeedMax) = getArray (_cfgPath >> "ACE_WindSpeedMax"); }; - if (isArray (configFile >> "CfgWorlds" >> _worldName >> "ACE_WindDirectionProbabilities")) then { - GVAR(WindDirectionProbabilities) = getArray (configFile >> "CfgWorlds" >> _worldName >> "ACE_WindDirectionProbabilities"); + if (isArray (_cfgPath >> "ACE_WindDirectionProbabilities")) then { + GVAR(WindDirectionProbabilities) = getArray (_cfgPath >> "ACE_WindDirectionProbabilities"); }; }; // Check if the map is among the most popular -if (_worldName in ["chernarus", "bootcamp_acr", "woodland_acr", "utes"]) then { +if (_worldName in ["chernarus", "bootcamp_acr", "woodland_acr", "utes"]) exitWith { // Source: http://www.iten-online.ch/klima/europa/tschechien/prag.htm GVAR(TempDay) = [1, 3, 9, 14, 19, 23, 25, 24, 21, 13, 7, 2]; GVAR(TempNight) = [-4, -3, 0, 4, 9, 12, 14, 14, 10, 6, 2, -2]; @@ -239,3 +240,17 @@ if (_worldName in ["kunduz"]) exitWith { [0.04, 0.02, 0.05, 0.14, 0.19, 0.07, 0.10, 0.07] // December ]; }; + + +// Catches any "Winter" Map that hasnt been defined otherwise - this should stay at the end of the file +// Values are not based on any RL reference since the snow terrain textures persists regardless the date +_cfgPath = _cfgPath >> "RainParticles"; +if ( + "winter" in _worldName || + {"snow" in getText (_cfgPath >> "rainDropTexture")} || + {getNumber (_cfgPath >> "snow") != 0} +) exitWith { + GVAR(TempDay) = [-10,-9,-8,-7,-6,-5,-6,-7,-8,-9,-10,-11]; + GVAR(TempNight) = [-15,-14,-13,-12,-11,-10,-9,-10,-11,-12,-13,-17]; + GVAR(Humidity) = [82, 80, 81, 82, 83, 82, 81, 82, 83, 82, 83, 82]; +}; From bcf1133477bd2dbd2ff3756f85163bd45ec74689 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 11 Apr 2024 17:43:19 +0200 Subject: [PATCH 006/290] Scopes - Notify restart req. for enable & pressure settings (#9944) * Moved keybinds, made settings require restart * Move keybinds --- addons/scopes/XEH_postInit.sqf | 101 +------------------- addons/scopes/functions/fnc_adjustScope.sqf | 3 +- addons/scopes/initKeybinds.inc.sqf | 95 ++++++++++++++++++ addons/scopes/initSettings.inc.sqf | 8 +- 4 files changed, 106 insertions(+), 101 deletions(-) create mode 100644 addons/scopes/initKeybinds.inc.sqf diff --git a/addons/scopes/XEH_postInit.sqf b/addons/scopes/XEH_postInit.sqf index 9c96281246..4ce8d6d11c 100644 --- a/addons/scopes/XEH_postInit.sqf +++ b/addons/scopes/XEH_postInit.sqf @@ -9,6 +9,9 @@ if (!hasInterface) exitWith {}; +// Add keybinds +#include "initKeybinds.inc.sqf" + GVAR(Optics) = ["", "", ""]; GVAR(Guns) = ["", "", ""]; GVAR(canAdjustElevation) = [false, false, false]; @@ -41,104 +44,6 @@ GVAR(scopeAdjust) = [[[0,0],0,[0,0],0], [[0,0],0,[0,0],0], [[0,0],0,[0,0],0]]; }; }] call CBA_fnc_addPlayerEventHandler; - // Add keybinds - ["ACE3 Scope Adjustment", QGVAR(AdjustUpMinor), localize LSTRING(AdjustUpMinor), { - // Conditions: canInteract - if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; - // Conditions: specific - if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; - - [ACE_player] call FUNC(inventoryCheck); - - // Statement - [ACE_player, ELEVATION_UP, MINOR_INCREMENT] call FUNC(adjustScope); - }, {false}, [201, [false, false, false]], true] call CBA_fnc_addKeybind; - - ["ACE3 Scope Adjustment", QGVAR(AdjustDownMinor), localize LSTRING(AdjustDownMinor), { - // Conditions: canInteract - if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; - // Conditions: specific - if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; - - [ACE_player] call FUNC(inventoryCheck); - - // Statement - [ACE_player, ELEVATION_DOWN, MINOR_INCREMENT] call FUNC(adjustScope); - }, {false}, [209, [false, false, false]], true] call CBA_fnc_addKeybind; - - ["ACE3 Scope Adjustment", QGVAR(AdjustLeftMinor), localize LSTRING(AdjustLeftMinor), { - // Conditions: canInteract - if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; - // Conditions: specific - if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; - - [ACE_player] call FUNC(inventoryCheck); - - // Statement - [ACE_player, WINDAGE_LEFT, MINOR_INCREMENT] call FUNC(adjustScope); - }, {false}, [209, [false, true, false]], true] call CBA_fnc_addKeybind; - - ["ACE3 Scope Adjustment", QGVAR(AdjustRightMinor), localize LSTRING(AdjustRightMinor), { - // Conditions: canInteract - if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; - // Conditions: specific - if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; - - [ACE_player] call FUNC(inventoryCheck); - - // Statement - [ACE_player, WINDAGE_RIGHT, MINOR_INCREMENT] call FUNC(adjustScope); - }, {false}, [201, [false, true, false]], true] call CBA_fnc_addKeybind; - - ["ACE3 Scope Adjustment", QGVAR(AdjustUpMajor), localize LSTRING(AdjustUpMajor), { - // Conditions: canInteract - if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; - // Conditions: specific - if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; - - [ACE_player] call FUNC(inventoryCheck); - - // Statement - [ACE_player, ELEVATION_UP, MAJOR_INCREMENT] call FUNC(adjustScope); - }, {false}, [201, [true, false, false]], true] call CBA_fnc_addKeybind; - - ["ACE3 Scope Adjustment", QGVAR(AdjustDownMajor), localize LSTRING(AdjustDownMajor), { - // Conditions: canInteract - if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; - // Conditions: specific - if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; - - [ACE_player] call FUNC(inventoryCheck); - - // Statement - [ACE_player, ELEVATION_DOWN, MAJOR_INCREMENT] call FUNC(adjustScope); - }, {false}, [209, [true, false, false]], true] call CBA_fnc_addKeybind; - - ["ACE3 Scope Adjustment", QGVAR(AdjustLeftMajor), localize LSTRING(AdjustLeftMajor), { - // Conditions: canInteract - if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; - // Conditions: specific - if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; - - [ACE_player] call FUNC(inventoryCheck); - - // Statement - [ACE_player, WINDAGE_LEFT, MAJOR_INCREMENT] call FUNC(adjustScope); - }, {false}, [209, [true, true, false]], true] call CBA_fnc_addKeybind; - - ["ACE3 Scope Adjustment", QGVAR(AdjustRightMajor), localize LSTRING(AdjustRightMajor), { - // Conditions: canInteract - if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; - // Conditions: specific - if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; - - [ACE_player] call FUNC(inventoryCheck); - - // Statement - [ACE_player, WINDAGE_RIGHT, MAJOR_INCREMENT] call FUNC(adjustScope); - }, {false}, [201, [true, true, false]], true] call CBA_fnc_addKeybind; - - // Register fire event handler ["ace_firedPlayer", LINKFUNC(firedEH)] call CBA_fnc_addEventHandler; ["ace_firedPlayerNonLocal", LINKFUNC(firedEH)] call CBA_fnc_addEventHandler; diff --git a/addons/scopes/functions/fnc_adjustScope.sqf b/addons/scopes/functions/fnc_adjustScope.sqf index bd2d2d1da6..0a9d7bd089 100644 --- a/addons/scopes/functions/fnc_adjustScope.sqf +++ b/addons/scopes/functions/fnc_adjustScope.sqf @@ -17,12 +17,13 @@ * Public: No */ +if (!GVAR(enabled)) exitWith {false}; + params ["_unit", "_turretAndDirection", "_majorStep"]; TRACE_3("adjustScope",_unit,_turretAndDirection,_majorStep); if (!(_unit isKindOf "Man")) exitWith {false}; if (currentMuzzle _unit != currentWeapon _unit) exitWith {false}; -if (!GVAR(enabled)) exitWith {false}; private _weaponIndex = [_unit, currentWeapon _unit] call EFUNC(common,getWeaponIndex); if (_weaponIndex < 0) exitWith {false}; diff --git a/addons/scopes/initKeybinds.inc.sqf b/addons/scopes/initKeybinds.inc.sqf new file mode 100644 index 0000000000..a147b1b215 --- /dev/null +++ b/addons/scopes/initKeybinds.inc.sqf @@ -0,0 +1,95 @@ +["ACE3 Scope Adjustment", QGVAR(AdjustUpMinor), LLSTRING(AdjustUpMinor), { + // Conditions: canInteract + if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; + // Conditions: specific + if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; + + [ACE_player] call FUNC(inventoryCheck); + + // Statement + [ACE_player, ELEVATION_UP, MINOR_INCREMENT] call FUNC(adjustScope); +}, {false}, [201, [false, false, false]], true] call CBA_fnc_addKeybind; + +["ACE3 Scope Adjustment", QGVAR(AdjustDownMinor), LLSTRING(AdjustDownMinor), { + // Conditions: canInteract + if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; + // Conditions: specific + if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; + + [ACE_player] call FUNC(inventoryCheck); + + // Statement + [ACE_player, ELEVATION_DOWN, MINOR_INCREMENT] call FUNC(adjustScope); +}, {false}, [209, [false, false, false]], true] call CBA_fnc_addKeybind; + +["ACE3 Scope Adjustment", QGVAR(AdjustLeftMinor), LLSTRING(AdjustLeftMinor), { + // Conditions: canInteract + if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; + // Conditions: specific + if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; + + [ACE_player] call FUNC(inventoryCheck); + + // Statement + [ACE_player, WINDAGE_LEFT, MINOR_INCREMENT] call FUNC(adjustScope); +}, {false}, [209, [false, true, false]], true] call CBA_fnc_addKeybind; + +["ACE3 Scope Adjustment", QGVAR(AdjustRightMinor), LLSTRING(AdjustRightMinor), { + // Conditions: canInteract + if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; + // Conditions: specific + if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; + + [ACE_player] call FUNC(inventoryCheck); + + // Statement + [ACE_player, WINDAGE_RIGHT, MINOR_INCREMENT] call FUNC(adjustScope); +}, {false}, [201, [false, true, false]], true] call CBA_fnc_addKeybind; + +["ACE3 Scope Adjustment", QGVAR(AdjustUpMajor), LLSTRING(AdjustUpMajor), { + // Conditions: canInteract + if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; + // Conditions: specific + if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; + + [ACE_player] call FUNC(inventoryCheck); + + // Statement + [ACE_player, ELEVATION_UP, MAJOR_INCREMENT] call FUNC(adjustScope); +}, {false}, [201, [true, false, false]], true] call CBA_fnc_addKeybind; + +["ACE3 Scope Adjustment", QGVAR(AdjustDownMajor), LLSTRING(AdjustDownMajor), { + // Conditions: canInteract + if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; + // Conditions: specific + if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; + + [ACE_player] call FUNC(inventoryCheck); + + // Statement + [ACE_player, ELEVATION_DOWN, MAJOR_INCREMENT] call FUNC(adjustScope); +}, {false}, [209, [true, false, false]], true] call CBA_fnc_addKeybind; + +["ACE3 Scope Adjustment", QGVAR(AdjustLeftMajor), LLSTRING(AdjustLeftMajor), { + // Conditions: canInteract + if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; + // Conditions: specific + if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; + + [ACE_player] call FUNC(inventoryCheck); + + // Statement + [ACE_player, WINDAGE_LEFT, MAJOR_INCREMENT] call FUNC(adjustScope); +}, {false}, [209, [true, true, false]], true] call CBA_fnc_addKeybind; + +["ACE3 Scope Adjustment", QGVAR(AdjustRightMajor), LLSTRING(AdjustRightMajor), { + // Conditions: canInteract + if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; + // Conditions: specific + if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; + + [ACE_player] call FUNC(inventoryCheck); + + // Statement + [ACE_player, WINDAGE_RIGHT, MAJOR_INCREMENT] call FUNC(adjustScope); +}, {false}, [201, [true, true, false]], true] call CBA_fnc_addKeybind; diff --git a/addons/scopes/initSettings.inc.sqf b/addons/scopes/initSettings.inc.sqf index 917587be8e..40ed62cbcc 100644 --- a/addons/scopes/initSettings.inc.sqf +++ b/addons/scopes/initSettings.inc.sqf @@ -5,7 +5,9 @@ private _category = format ["ACE %1", localize LSTRING(DisplayName)]; [LSTRING(enabled_displayName), LSTRING(enabled_description)], _category, true, - 1 + 1, + {[QGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart ] call CBA_fnc_addSetting; [ @@ -69,7 +71,9 @@ private _category = format ["ACE %1", localize LSTRING(DisplayName)]; [LSTRING(deduceBarometricPressureFromTerrainAltitude_displayName), LSTRING(deduceBarometricPressureFromTerrainAltitude_description)], _category, false, - 1 + 1, + {[QGVAR(deduceBarometricPressureFromTerrainAltitude), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart ] call CBA_fnc_addSetting; [ From 6165b46ab6ec8657ba5f30060f310bb72d1a0679 Mon Sep 17 00:00:00 2001 From: PlayerBotPro Date: Thu, 11 Apr 2024 23:58:50 +0800 Subject: [PATCH 007/290] Medical Treatment - Fix Painkiller has no effect when Advanced Medication is off (#9942) * fix: Painkiller has no effect when Advanced Medication is off * Change PainKillers_PAIN_SUPPRESSION to uppercase * Update addons/medical_treatment/functions/fnc_medicationLocal.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --------- Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- addons/medical_treatment/functions/fnc_medicationLocal.sqf | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/addons/medical_treatment/functions/fnc_medicationLocal.sqf b/addons/medical_treatment/functions/fnc_medicationLocal.sqf index 31884dac20..0b23b365e8 100644 --- a/addons/medical_treatment/functions/fnc_medicationLocal.sqf +++ b/addons/medical_treatment/functions/fnc_medicationLocal.sqf @@ -19,6 +19,9 @@ // todo: move this macro to script_macros_medical.hpp? #define MORPHINE_PAIN_SUPPRESSION 0.6 +// 0.2625 = 0.6/0.8 * 0.35 +// 0.6 = basic medication morph. pain suppr., 0.8 = adv. medication morph. pain suppr., 0.35 = adv. medication painkillers. pain suppr. +#define PAINKILLERS_PAIN_SUPPRESSION 0.2625 params ["_patient", "_bodyPart", "_classname"]; TRACE_3("medicationLocal",_patient,_bodyPart,_classname); @@ -36,6 +39,10 @@ if (!GVAR(advancedMedication)) exitWith { case "Epinephrine": { [QEGVAR(medical,WakeUp), _patient] call CBA_fnc_localEvent; }; + case "Painkillers": { + private _painSuppress = GET_PAIN_SUPPRESS(_patient); + _patient setVariable [VAR_PAIN_SUPP, (_painSuppress + PAINKILLERS_PAIN_SUPPRESSION) min 1, true]; + }; }; }; TRACE_1("Running treatmentMedicationLocal with Advanced configuration for",_patient); From 32707dd860119b47ef8921500e7221e20caad4bf Mon Sep 17 00:00:00 2001 From: V1nsyara Date: Sat, 13 Apr 2024 22:53:50 +0300 Subject: [PATCH 008/290] Language Russian - Update translation (#9947) Russian --- addons/advanced_throwing/stringtable.xml | 2 ++ addons/common/stringtable.xml | 3 +++ addons/fieldmanual/stringtable.xml | 1 + addons/hearing/stringtable.xml | 1 + addons/medical_gui/stringtable.xml | 3 +++ addons/medical_treatment/stringtable.xml | 6 +++--- 6 files changed, 13 insertions(+), 3 deletions(-) diff --git a/addons/advanced_throwing/stringtable.xml b/addons/advanced_throwing/stringtable.xml index 7676464474..1e0b5ae23f 100644 --- a/addons/advanced_throwing/stringtable.xml +++ b/addons/advanced_throwing/stringtable.xml @@ -192,6 +192,7 @@ 一時的に風の情報を表示 바람 정보 임시로 표시 Afficher temporairement les informations sur le vent + Временно показать информацию о ветре Temporarily display Wind Info while throwing, to aid in placing smoke grenades effectively. @@ -200,6 +201,7 @@ 投擲行動中に風向きの情報を一時的に表示し、発煙手榴弾の煙幕を効果的に展開しやすくします。 연막탄을 효과적으로 배치하는 데 도움이 되도록 투척하는 동안 일시적으로 바람 정보를 표시합니다. Affiche les informations sur le vent pendant le lancement pour placer les grenades fumigènes plus efficacement. + Временно отображайте информацию о ветре во время броска, чтобы помочь эффективно разместить дымовые шашки. Prepare/Change Throwable diff --git a/addons/common/stringtable.xml b/addons/common/stringtable.xml index 7138c8da95..4afdf2ad89 100644 --- a/addons/common/stringtable.xml +++ b/addons/common/stringtable.xml @@ -1833,18 +1833,21 @@ 手ぶれ 무기 흔들림 Oscillation de l'arme + Колебание оружия Enable Weapon Sway 手ぶれを有効化 무기 흔들림 추가 Activer l'oscillation de l'arme + Включить колебание оружия Enables weapon sway influenced by sway factors, such as stance, fatigue and medical condition.\nDisabling this setting will defer sway to vanilla or other mods. 姿勢、疲労、負傷状態などの手ぶれ要因に影響を受ける武器照準の揺れを有効にします。\nこの設定を無効にすると、手ぶれの揺れはバニラまたは他のMODの処理に任されます。 흔들림 계수, 자세, 피로도, 건강 상태 등의 요인에 영향을 받는 무기 흔들림을 활성화합니다.\n이 설정을 비활성화하면 바닐라 또는 다른 모드의 흔들림으로 대체됩니다. Active l'oscillation de l'arme influencé par les facteurs d'oscillation, tels que la position, la fatigue et l'état de santé.\nLa désactivation de ce paramètre reportera l'oscillation à vanilla ou à d'autres mods. + Активируйте колебание оружия в зависимости от таких факторов, как стойка, усталость и состояние здоровья.\nОтключение этого параметра приведет к переносу раскачивания на vanilla или другие моды. Sway factor diff --git a/addons/fieldmanual/stringtable.xml b/addons/fieldmanual/stringtable.xml index 18f45a1e7e..05c7414f17 100644 --- a/addons/fieldmanual/stringtable.xml +++ b/addons/fieldmanual/stringtable.xml @@ -155,6 +155,7 @@ %3IV-Flüssigkeiten%4 stellen das verlorene Blutvolumen wieder her. Blut, Plasma und Kochsalzlösung sind funktionell gleich.<br/><br/>%3Verwende:%4<br/>%2Verwende [%3%13%4] oder [%3%14%4] und wählen ein Körperteil aus..<br/>%2Stelle das Blutvolumen wieder her, indem der gewünschte %3IV Flüssigkeitstyp%4 ausgewählt wird. %3Fluidi EV%4 ristorano volume di sangue perso. Sangue, Plasma, e Salina sono funzionalmente identiche.<br/><br/>%3Utilizzo:%4<br/>%2Usa [%3%13%4] o [%3%14%4] e seleziona un arto.<br/>%2Ristora il volume di sangue selezionando il tipo di %3Fluido EV%4 desiderato. %3IV 輸液%4は失われた血液を回復します。血液、血漿、生理食塩水は機能的には同じです。<br/><br/>%3使用方法:%4<br/>%2[%3%13%4] または [%3%14%4] を使って四肢を選択します。<br/>%2希望の%3IV 輸液%4の種類を選択して、血液量を復元します。 + %%3Внутривенные жидкости%4восстанавливают потерянный объем крови. Кровь, плазма и физраствор функционально идентичны.<br/><br/>%3 Использование:%4<br/>%2 Используйте [%3%13%4] или [%3%14%4] и выберите добавку.<br/>%2 Восстановите объем крови выбрав желаемый %4тип %3жидкости Increase Heart Rate | Wake Up Faster diff --git a/addons/hearing/stringtable.xml b/addons/hearing/stringtable.xml index de741e55c1..0cb4cffb99 100644 --- a/addons/hearing/stringtable.xml +++ b/addons/hearing/stringtable.xml @@ -373,6 +373,7 @@ Only units with heavy weapons + Только юниты с тяжелым вооружением diff --git a/addons/medical_gui/stringtable.xml b/addons/medical_gui/stringtable.xml index 6d7e819b29..5a41bba671 100644 --- a/addons/medical_gui/stringtable.xml +++ b/addons/medical_gui/stringtable.xml @@ -1366,6 +1366,7 @@ 出血状態の表示 출혈 상태 표시 Afficher l'état des saignements + Показать состояние кровотечения Display if the patient is bleeding, optionally with rate @@ -1376,6 +1377,7 @@ 患者が出血しているかどうかを表示します。オプションで出血速度も表示します 환자가 출혈 중인지 여부를 표시합니다(선택적으로 출혈 속도 포함) Indique si le patient saigne, éventuellement avec le taux de saignement + Показывает, есть ли у пациента кровотечение, опционально с указанием частоты Show Bleeding Rate @@ -1386,6 +1388,7 @@ 出血速度の表示 출혈 속도 표시 Afficher le taux de saignement + Показать частоту кровотечения Peek Medical Info on Hit diff --git a/addons/medical_treatment/stringtable.xml b/addons/medical_treatment/stringtable.xml index 4e186edc85..be421eff36 100644 --- a/addons/medical_treatment/stringtable.xml +++ b/addons/medical_treatment/stringtable.xml @@ -3574,7 +3574,7 @@ Receiving Saline IV [%1ml] Erhalte Saline IV [%1ml] Recibiendo Salina IV [%1ml] - Принимается солевой раствор IV [%1 мл] + Принимается физраствор [%1 мл] Otrzymywanie soli IV [%1ml] Transfusion de sérum salé : [%1 ml] Přijímání soli IV [%1ml] @@ -3590,7 +3590,7 @@ Receiving Blood IV [%1ml] Erhalte Blut IV [%1ml] Recibiendo Sangre IV [%1ml] - Принимается кровь IV [%1 мл] + Принимается кровь [%1 мл] Otrzymywanie krwi IV [%1ml] Transfusion de sang : [%1 ml] Přijímání krve IV [%1ml] @@ -3606,7 +3606,7 @@ Receiving Plasma IV [%1ml] Erhalte Plasma IV [%1ml] Recibiendo Plasma IV [%1ml] - Принимается плазма IV [%1 мл] + Принимается плазма [%1 мл] Otrzymywanie plazmy IV [%1ml] Transfusion de plasma : [%1 ml] Přijímání plazmy IV [%1ml] From b637a0ea0930df9312818e35a659f487c8d560b7 Mon Sep 17 00:00:00 2001 From: Hexo <130893962+Alfred-Neuman@users.noreply.github.com> Date: Sat, 13 Apr 2024 22:09:48 +0200 Subject: [PATCH 009/290] Update translate Hearing french (#9949) Co-authored-by: PabstMirror --- addons/hearing/stringtable.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/hearing/stringtable.xml b/addons/hearing/stringtable.xml index 0cb4cffb99..1cbeacf259 100644 --- a/addons/hearing/stringtable.xml +++ b/addons/hearing/stringtable.xml @@ -373,6 +373,7 @@ Only units with heavy weapons + Uniquement les unités dotées d'armes lourdes Только юниты с тяжелым вооружением From dda6b9d2dc2d896a53b6e81001e595b17bee1596 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Tue, 16 Apr 2024 22:33:40 +0200 Subject: [PATCH 010/290] Medical Treatment - Enforce bandage effectiveness variable type (#9950) Enforce bandage effectiveness variable type --- addons/medical_treatment/functions/fnc_bandageLocal.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/medical_treatment/functions/fnc_bandageLocal.sqf b/addons/medical_treatment/functions/fnc_bandageLocal.sqf index 4cecbb2f17..2c59540fd1 100644 --- a/addons/medical_treatment/functions/fnc_bandageLocal.sqf +++ b/addons/medical_treatment/functions/fnc_bandageLocal.sqf @@ -18,7 +18,7 @@ * Public: No */ -params ["_patient", "_bodyPart", "_bandage", ["_bandageEffectiveness", 1]]; +params ["_patient", "_bodyPart", "_bandage", ["_bandageEffectiveness", 1, [0]]]; TRACE_4("bandageLocal",_patient,_bodyPart,_bandage,_bandageEffectiveness); _bodyPart = toLowerANSI _bodyPart; From 7480ae377dc19e0ce74c76479fe6c41e3eee7a8c Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Fri, 19 Apr 2024 19:27:04 +0200 Subject: [PATCH 011/290] Scopes - Stop changing CBA setting value directly (#9954) Update XEH_postInit.sqf --- addons/scopes/XEH_postInit.sqf | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/addons/scopes/XEH_postInit.sqf b/addons/scopes/XEH_postInit.sqf index 4ce8d6d11c..997fe8d6dd 100644 --- a/addons/scopes/XEH_postInit.sqf +++ b/addons/scopes/XEH_postInit.sqf @@ -19,11 +19,13 @@ GVAR(canAdjustWindage) = [false, false, false]; GVAR(scopeAdjust) = [[[0,0],0,[0,0],0], [[0,0],0,[0,0],0], [[0,0],0,[0,0],0]]; ["CBA_settingsInitialized", { - if (!GVAR(enabled)) exitWith {}; - if (GVAR(deduceBarometricPressureFromTerrainAltitude)) then { - GVAR(zeroReferenceBarometricPressure) = 1013.25 * (1 - (0.0065 * EGVAR(common,mapAltitude)) / 288.15) ^ 5.255754495; + // Overwrite setting if automatic pressure deduction is wanted + if (isServer && GVAR(deduceBarometricPressureFromTerrainAltitude)) then { + private _referencePressure = 1013.25 * (1 - (0.0065 * EGVAR(common,mapAltitude)) / 288.15) ^ 5.255754495; + + [QGVAR(zeroReferenceBarometricPressure), _referencePressure, 2, "server"] call CBA_settings_fnc_set; }; // Check inventory when it changes @@ -47,5 +49,4 @@ GVAR(scopeAdjust) = [[[0,0],0,[0,0],0], [[0,0],0,[0,0],0], [[0,0],0,[0,0],0]]; // Register fire event handler ["ace_firedPlayer", LINKFUNC(firedEH)] call CBA_fnc_addEventHandler; ["ace_firedPlayerNonLocal", LINKFUNC(firedEH)] call CBA_fnc_addEventHandler; - }] call CBA_fnc_addEventHandler; From 23842aab39c32dbbefa2f7b894b773bff2da1620 Mon Sep 17 00:00:00 2001 From: Tim Beswick Date: Fri, 19 Apr 2024 20:57:41 +0100 Subject: [PATCH 012/290] Medical - Fix script error when bandaging (#9956) Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- addons/medical_treatment/functions/fnc_bandage.sqf | 7 ++++--- docs/wiki/framework/events-framework.md | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/addons/medical_treatment/functions/fnc_bandage.sqf b/addons/medical_treatment/functions/fnc_bandage.sqf index 2152e81a3b..8657936a66 100644 --- a/addons/medical_treatment/functions/fnc_bandage.sqf +++ b/addons/medical_treatment/functions/fnc_bandage.sqf @@ -10,7 +10,8 @@ * 3: Treatment * 4: Item User * 5: Used Item - * 6: Bandage effectiveness coefficient (default: 1) + * 6: Create litter + * 7: Bandage effectiveness coefficient (default: 1) * * Return Value: * None @@ -21,10 +22,10 @@ * Public: No */ -_this set [6, _this param [6, 1]]; // set default Bandage effectiveness coefficient +_this set [7, _this param [7, 1]]; // set bandage effectiveness coefficient [QGVAR(bandaged), _this] call CBA_fnc_localEvent; // Raise event with reference so mods can modify this -params ["_medic", "_patient", "_bodyPart", "_classname", "", "", "_bandageEffectiveness"]; +params ["_medic", "_patient", "_bodyPart", "_classname", "", "", "", "_bandageEffectiveness"]; [_patient, "activity", LSTRING(Activity_bandagedPatient), [[_medic, false, true] call EFUNC(common,getName)]] call FUNC(addToLog); diff --git a/docs/wiki/framework/events-framework.md b/docs/wiki/framework/events-framework.md index 8a50912e02..f8183b598f 100644 --- a/docs/wiki/framework/events-framework.md +++ b/docs/wiki/framework/events-framework.md @@ -42,7 +42,7 @@ The vehicle events will also have the following local variables available `_gunn |`ace_treatmentSucceded` | [_caller, _target, _selectionName, _className, _itemUser, _usedItem] | Local | Listen | Treatment action is completed (local on the _caller) |`ace_treatmentFailed` | [_caller, _target, _selectionName, _className, _itemUser, _usedItem] | Local | Listen | Treatment action has been interrupted (local on the _caller) |`ace_medical_handleUnitVitals` | [_unit, _deltaT] | Local | Listen | Vitals update ran for unit, _deltaT is the time elapsed since the previous vitals update (local to _unit) -|`ace_medical_treatment_bandaged` | [_medic, _patient, _bodyPart, _className, _bandageEffectiveness] | Local | Listen | _medic has bandaged _patient, the array can be modified to change treatment parameters (local to _medic) +|`ace_medical_treatment_bandaged` | [_medic, _patient, _bodyPart, _className, _itemUser, _usedItem, _createLitter, _bandageEffectiveness] | Local | Listen | _medic has bandaged _patient, the array can be modified to change treatment parameters (local to _medic) ### 2.3 Interaction Menu (`ace_interact_menu`) MenuType: 0 = Interaction, 1 = Self Interaction From ac9ffb5276d8a62169551bc01b12009b5f6b276b Mon Sep 17 00:00:00 2001 From: Dart <59131299+DartRuffian@users.noreply.github.com> Date: Fri, 19 Apr 2024 15:53:33 -0500 Subject: [PATCH 013/290] Docs - Fix tables and inconsistencies (#9952) Co-authored-by: LinkIsGrim <69561145+LinkIsGrim@users.noreply.github.com> --- docs/wiki/framework/arsenal-framework.md | 202 +++++++++--------- docs/wiki/framework/attach-framework.md | 14 +- docs/wiki/framework/dragging-framework.md | 68 +++--- docs/wiki/framework/events-framework.md | 196 ++++++++--------- docs/wiki/framework/explosives-framework.md | 62 +++--- docs/wiki/framework/fastroping-framework.md | 22 +- .../wiki/framework/field-rations-framework.md | 42 ++-- docs/wiki/framework/fire-framework.md | 22 +- docs/wiki/framework/fortify-framework.md | 16 +- docs/wiki/framework/frag-framework.md | 66 +++--- docs/wiki/framework/goggles-framework.md | 8 +- docs/wiki/framework/grenades-framework.md | 10 +- .../framework/interactionMenu-framework.md | 37 ++-- docs/wiki/framework/laser-framework.md | 18 +- docs/wiki/framework/medical-framework.md | 22 +- .../framework/medical-treatment-framework.md | 2 + .../framework/missile-guidance-framework.md | 6 +- docs/wiki/framework/overpressure-framework.md | 6 +- docs/wiki/framework/rearm-framework.md | 158 +++++++------- docs/wiki/framework/refuel-framework.md | 78 +++---- .../framework/reloadlaunchers-framework.md | 6 +- docs/wiki/framework/slideshow-framework.md | 44 ++-- docs/wiki/framework/spectator-framework.md | 10 +- docs/wiki/framework/tagging-framework.md | 34 +-- docs/wiki/framework/trenches-framework.md | 2 +- docs/wiki/framework/ui-framework.md | 26 +-- docs/wiki/framework/vehiclelock-framework.md | 22 +- docs/wiki/framework/vehicles-framework.md | 18 +- docs/wiki/framework/wirecutter-framework.md | 6 +- docs/wiki/framework/xm157-framework.md | 1 - 30 files changed, 616 insertions(+), 608 deletions(-) diff --git a/docs/wiki/framework/arsenal-framework.md b/docs/wiki/framework/arsenal-framework.md index 273a70836f..954bbc0a7e 100644 --- a/docs/wiki/framework/arsenal-framework.md +++ b/docs/wiki/framework/arsenal-framework.md @@ -31,11 +31,11 @@ To quickly add a full ACE Arsenal to a box for all clients use the following cod `ace_arsenal_fnc_initBox` -| | Argument | Type | Optional (default value) ----| -------- | ---- | ------------------------ -0 | Box | Object | Required -1 | Items | Array of strings or boolean | Required -2 | Initialize globally | Boolean | Optional (default: `false`) +| | Argument | Type | Optional (default value) | +|----| -------- | ---- | ------------------------ | +| 0 | Box | Object | Required | +| 1 | Items | Array of strings or boolean | Required | +| 2 | Initialize globally | Boolean | Optional (default: `false`) | This will add the virtual items passed as arguments and add an ACE interaction to open ACE Arsenal. @@ -51,11 +51,11 @@ Please note that at least one virtual item needs to be added otherwise ACE Arsen `ace_arsenal_fnc_openBox` -| | Argument | Type | Optional (default value) ----| -------- | ---- | ------------------------ -0 | Box | Object | Required -1 | Unit to open ACE Arsenal on | Object | Required -2 | Ignore virtual items and fill ACE Arsenal | Boolean | Optional (default: `false`) +| | Argument | Type | Optional (default value) | +|----| -------- | ---- | ------------------------ | +| 0 | Box | Object | Required | +| 1 | Unit to open ACE Arsenal on | Object | Required | +| 2 | Ignore virtual items and fill ACE Arsenal | Boolean | Optional (default: `false`) | Examples: - `[_box, player] call ace_arsenal_fnc_openBox` @@ -67,10 +67,10 @@ In the second example a full ACE Arsenal will be opened on the player. `ace_arsenal_fnc_removeBox` -| | Argument | Type | Optional (default value) ----| -------- | ---- | ------------------------ -0 | Box | Object | Required -2 | Remove globally | Boolean | Optional (default: `false`) +| | Argument | Type | Optional (default value) | +|----| -------- | ---- | ------------------------ | +| 0 | Box | Object | Required | +| 2 | Remove globally | Boolean | Optional (default: `false`) | Example: `[_box, true] call ace_arsenal_fnc_removeBox` @@ -81,11 +81,11 @@ Example: `ace_arsenal_fnc_addVirtualItems` -| | Argument | Type | Optional (default value) ----| -------- | ---- | ------------------------ -0 | Box | Object | Required -1 | Items | Array of strings or boolean | Required -2 | Add globally | Boolean | Optional (default: `false`) +| | Argument | Type | Optional (default value) | +|----| -------- | ---- | ------------------------ | +| 0 | Box | Object | Required | +| 1 | Items | Array of strings or boolean | Required | +| 2 | Add globally | Boolean | Optional (default: `false`) | Passing an array of strings (class names) will add each one of those items to the specified box, passing true will add ALL items that are compatible with ACE Arsenal (the sorting is done on game startup). Faces, voices and insignia can't be added via this function. @@ -97,11 +97,11 @@ Examples: `ace_arsenal_fnc_removeVirtualItems` -| | Argument | Type | Optional (default value) ----| -------- | ---- | ------------------------ -0 | Box | Object | Required -1 | Items | Array of strings or boolean | Required -2 | Remove globally | Boolean | Optional (default: `false`) +| | Argument | Type | Optional (default value) | +|----| -------- | ---- | ------------------------ | +| 0 | Box | Object | Required | +| 1 | Items | Array of strings or boolean | Required | +| 2 | Remove globally | Boolean | Optional (default: `false`) | Like adding virtual items, passing an array of string (class names) will remove each ones of those items, however passing true will remove all virtual items and also remove the interaction to access ACE Arsenal. Faces, voices and insignia can't be removed via this function. @@ -185,11 +185,11 @@ Players with Zeus access can save default loadouts ingame, doing so will make th `ace_arsenal_fnc_addDefaultLoadout` -| | Argument | Type | Optional (default value) ----| -------- | ---- | ------------------------ -0 | Name of loadout | String | Required -1 | getUnitLoadout array or CBA extended loadout array | Array | Required -2 | Add loadout globally | Boolean | Optional (default: `false`) +| | Argument | Type | Optional (default value) | +|----| -------- | ---- | ------------------------ | +| 0 | Name of loadout | String | Required | +| 1 | getUnitLoadout array or CBA extended loadout array | Array | Required | +| 2 | Add loadout globally | Boolean | Optional (default: `false`) | Example: `["Squad Leader", getUnitLoadout sql1, true] call ace_arsenal_fnc_addDefaultLoadout` @@ -229,22 +229,22 @@ The arguments passed to the bar, text and condition statements are: `ace_arsenal_fnc_addStat` -| | Argument | Type | Optional (default value) ---- | -------- | ---- | ------------------------ -0 | Tabs to add the stat to | Array of arrays | Required -0.1 | Left tab indexes | Array of numbers | Required -0.2 | Right tab indexes | Array of numbers | Required -1 | Stat class ID | String | Required -2 | Config entries to pass | Array of strings | Required -3 | Title | String | Required -4 | Show bar / show text bools | Array of booleans | Required -4.1 | Show bar | Boolean | Required -4.2 | Show text | Boolean | Required -5 | Array of statements | Array of code | Required -5.1 | Bar code | Code | Required -5.2 | Text code | Code | Required -5.3 | Condition | Code | Required -6 | Priority | Number | Optional (default: `0`) +| | Argument | Type | Optional (default value) | +| --- | -------- | ---- | ------------------------ | +| 0 | Tabs to add the stat to | Array of arrays | Required | +| 0.1 | Left tab indexes | Array of numbers | Required | +| 0.2 | Right tab indexes | Array of numbers | Required | +| 1 | Stat class ID | String | Required | +| 2 | Config entries to pass | Array of strings | Required | +| 3 | Title | String | Required | +| 4 | Show bar / show text bools | Array of booleans | Required | +| 4.1 | Show bar | Boolean | Required | +| 4.2 | Show text | Boolean | Required | +| 5 | Array of statements | Array of code | Required | +| 5.1 | Bar code | Code | Required | +| 5.2 | Text code | Code | Required | +| 5.3 | Condition | Code | Required | +| 6 | Priority | Number | Optional (default: `0`) | Return Value: - Array of stat IDs @@ -263,9 +263,9 @@ If a stat already exists (so same class ID and tab), it will ignore the new addi `ace_arsenal_fnc_removeStat` -| | Argument | Type | Optional (default value) ----| -------- | ---- | ------------------------ -0 | Array of IDs | Array | Required +| | Argument | Type | Optional (default value) | +|----| -------- | ---- | ------------------------ | +| 0 | Array of IDs | Array | Required | Stats IDs are unique, IDs are generated as follows: @@ -345,15 +345,15 @@ The argument passed to the condition is: `ace_arsenal_fnc_addSort` -| | Argument | Type | Optional (default value) ---- | -------- | ---- | ------------------------ -0 | Tabs to add the sort to | Array of arrays | Required -0.1 | Left tab indexes | Array of numbers | Required -0.2 | Right tab indexes | Array of numbers | Required -1 | Stat class ID | String | Required -2 | Title | String | Required -3 | Algorithm | Code | Required -4 | Condition | Code | Optional (default: `{true}`) +| | Argument | Type | Optional (default value) | +| --- | -------- | ---- | ------------------------ | +| 0 | Tabs to add the sort to | Array of arrays | Required | +| 0.1 | Left tab indexes | Array of numbers | Required | +| 0.2 | Right tab indexes | Array of numbers | Required | +| 1 | Stat class ID | String | Required | +| 2 | Title | String | Required | +| 3 | Algorithm | Code | Required | +| 4 | Condition | Code | Optional (default: `{true}`) | Return Value: - Array of sort IDs @@ -382,9 +382,9 @@ If a sorting method already exists (so same class ID and tab), it will ignore th `ace_arsenal_fnc_removeSort` -| | Argument | Type | Optional (default value) ----| -------- | ---- | ------------------------ -0 | Array of IDs | Array | Required +| | Argument | Type | Optional (default value) | +|----| -------- | ---- | ------------------------ | +| 0 | Array of IDs | Array | Required | Sorting method IDs are unique and are generated in the same fashion as the stat IDs (see `5.3 Removing stats via a function`). @@ -438,15 +438,15 @@ The focused unit object is passed to the condition and statement functions. `ace_arsenal_fnc_addAction` -| | Argument | Type | Optional (default value) ---- | -------- | ---- | ------------------------ -0 | Tabs to add the sort to | Array of numbers | Required -1 | Action class ID | String | Required -2 | Title | String | Required -3 | Actions | Array of arrays | Required -4 | Condition | Code | Optional (default: `{true}`) -5 | Scope editor | Number | Optional (default: `2`) -6 | Update on cargo change | Boolean | Optional (default: `false`) +| | Argument | Type | Optional (default value) | +| --- | -------- | ---- | ------------------------ | +| 0 | Tabs to add the sort to | Array of numbers | Required | +| 1 | Action class ID | String | Required | +| 2 | Title | String | Required | +| 3 | Actions | Array of arrays | Required | +| 4 | Condition | Code | Optional (default: `{true}`) | +| 5 | Scope editor | Number | Optional (default: `2`) | +| 6 | Update on cargo change | Boolean | Optional (default: `false`) | Return Value: - Array of action IDs @@ -474,9 +474,9 @@ If an action already exists (so same class ID and tab within an action), it will `ace_arsenal_fnc_removeAction` -| | Argument | Type | Optional (default value) ----| -------- | ---- | ------------------------ -0 | Array of IDs | Array | Required +| | Argument | Type | Optional (default value) | +|----| -------- | ---- | ------------------------ | +| 0 | Array of IDs | Array | Required | Action IDs are unique and their generation is explained in `7.2 Adding sorting methods via a function`. @@ -492,28 +492,28 @@ All are local. | Name | Arguments | Added in | | ------------- | ------------- | ------------- | -| ace_arsenal_boxInitialized | Arsenal box (OBJECT), items (BOOL or ARRAY) | -| ace_arsenal_boxRemoved | Arsenal box (OBJECT) | -| ace_arsenal_displayOpened | Arsenal display (DISPLAY) | -| ace_arsenal_displayClosed | None | -| ace_arsenal_leftPanelFilled | Arsenal display (DISPLAY), current left panel IDC (SCALAR), current right panel IDC (SCALAR) | -| ace_arsenal_rightPanelFilled | Arsenal display (DISPLAY), current left panel IDC (SCALAR), current right panel IDC (SCALAR) | -| ace_arsenal_onLoadoutSave | Loadout index (SCALAR), [loadout name (STRING), loadout data (ARRAY)] | -| ace_arsenal_onLoadoutSaveExtended | Loadout index (SCALAR), [loadout name (STRING), CBA extended loadout data (ARRAY)] | 3.15.1 -| ace_arsenal_onLoadoutLoad | loadout data (ARRAY), loadout name (STRING) | -| ace_arsenal_onLoadoutLoadExtended | CBA extended loadout data (ARRAY), loadout name (STRING) | 3.15.1 -| ace_arsenal_onLoadoutDelete | loadout name (STRING) | -| ace_arsenal_loadoutShared | Loadouts list listnBox control (CONTROL), loadout author (STRING), loadout name (STRING), loadout data (ARRAY) | -| ace_arsenal_loadoutUnshared | Loadouts list listnBox control (CONTROL), loadout author (STRING), loadout name (STRING) | -| ace_arsenal_cargoChanged | Arsenal display (DISPLAY), item (STRING), add or remove (NUMBER), shiftState (BOOL) | -| ace_arsenal_loadoutImported | Arsenal display (DISPLAY), import list (BOOL) | -| ace_arsenal_loadoutExported | Arsenal display (DISPLAY), export list (BOOL) | -| ace_arsenal_loadoutsDisplayOpened | loadouts screen display (DISPLAY) | 3.12.3 | -| ace_arsenal_loadoutsDisplayClosed | None | 3.12.3 | -| ace_arsenal_loadoutsTabChanged | loadouts screen display (DISPLAY), tab control (CONTROL) | 3.12.3 | -| ace_arsenal_loadoutsListFilled | loadouts screen display (DISPLAY), tab control (CONTROL) | 3.12.3 | -| ace_arsenal_loadoutVerified | loadout data (ARRAY), loadout CBA extended data (HASHMAP), null items (ARRAY), unavailable items (ARRAY), unavailable extended data (ARRAY) | 3.17.0 | -| ace_arsenal_weaponItemChanged | weapon classname (STRING), item classname (STRING), item index (NUMBER, 0-5: muzzle, side, optic, bipod, magazine, underbarrel) | 3.16.0 | +| `ace_arsenal_boxInitialized` | Arsenal box (OBJECT), items (BOOL or ARRAY) | +| `ace_arsenal_boxRemoved` | Arsenal box (OBJECT) | +| `ace_arsenal_displayOpened` | Arsenal display (DISPLAY) | +| `ace_arsenal_displayClosed` | None | +| `ace_arsenal_leftPanelFilled` | Arsenal display (DISPLAY), current left panel IDC (SCALAR), current right panel IDC (SCALAR) | +| `ace_arsenal_rightPanelFilled` | Arsenal display (DISPLAY), current left panel IDC (SCALAR), current right panel IDC (SCALAR) | +| `ace_arsenal_onLoadoutSave` | Loadout index (SCALAR), [loadout name (STRING), loadout data (ARRAY)] | +| `ace_arsenal_onLoadoutSaveExtended` | Loadout index (SCALAR), [loadout name (STRING), CBA extended loadout data (ARRAY)] | 3.15.1 +| `ace_arsenal_onLoadoutLoad` | loadout data (ARRAY), loadout name (STRING) | +| `ace_arsenal_onLoadoutLoadExtended` | CBA extended loadout data (ARRAY), loadout name (STRING) | 3.15.1 +| `ace_arsenal_onLoadoutDelete` | loadout name (STRING) | +| `ace_arsenal_loadoutShared` | Loadouts list listnBox control (CONTROL), loadout author (STRING), loadout name (STRING), loadout data (ARRAY) | +| `ace_arsenal_loadoutUnshared` | Loadouts list listnBox control (CONTROL), loadout author (STRING), loadout name (STRING) | +| `ace_arsenal_cargoChanged` | Arsenal display (DISPLAY), item (STRING), add or remove (NUMBER), shiftState (BOOL) | +| `ace_arsenal_loadoutImported` | Arsenal display (DISPLAY), import list (BOOL) | +| `ace_arsenal_loadoutExported` | Arsenal display (DISPLAY), export list (BOOL) | +| `ace_arsenal_loadoutsDisplayOpened` | loadouts screen display (DISPLAY) | 3.12.3 | +| `ace_arsenal_loadoutsDisplayClosed` | None | 3.12.3 | +| `ace_arsenal_loadoutsTabChanged` | loadouts screen display (DISPLAY), tab control (CONTROL) | 3.12.3 | +| `ace_arsenal_loadoutsListFilled` | loadouts screen display (DISPLAY), tab control (CONTROL) | 3.12.3 | +| `ace_arsenal_loadoutVerified` | loadout data (ARRAY), loadout CBA extended data (HASHMAP), null items (ARRAY), unavailable items (ARRAY), unavailable extended data (ARRAY) | 3.17.0 | +| `ace_arsenal_weaponItemChanged` | weapon classname (STRING), item classname (STRING), item index (NUMBER, 0-5: muzzle, side, optic, bipod, magazine, underbarrel) | 3.16.0 | ## 9. Custom sub item categories @@ -521,13 +521,13 @@ All are local. `ace_arsenal_fnc_addRightPanelButton` -| | Argument | Type | Optional (default value) ----| -------- | ---- | ------------------------ -0 | Misc. items | Array of strings | Required -1 | Tooltip | String | Optional (default: `""`) -2 | Picture path | String | Optional (default: `"\z\ace\addons\arsenal\data\iconCustom.paa"`) -3 | Override a specific button | Number | Optional (default: `-1`) -4 | Move button on overwrite | Bool | Optional (default: `false`) +| | Argument | Type | Optional (default value) | +|----| -------- | ---- | ------------------------ | +| 0 | Misc. items | Array of strings | Required | +| 1 | Tooltip | String | Optional (default: `""`) | +| 2 | Picture path | String | Optional (default: `"\z\ace\addons\arsenal\data\iconCustom.paa"`) | +| 3 | Override a specific button | Number | Optional (default: `-1`) | +| 4 | Move button on overwrite | Bool | Optional (default: `false`) | Return Value: - Successful: Number of the slot (0-9) diff --git a/docs/wiki/framework/attach-framework.md b/docs/wiki/framework/attach-framework.md index 2ed5f74561..f1f35bc6a8 100644 --- a/docs/wiki/framework/attach-framework.md +++ b/docs/wiki/framework/attach-framework.md @@ -35,10 +35,10 @@ class CfgVehicles { ``` ### 1.2 Define attach orientation for non-symmetric items -In the case the item needs to have a particular orientation when attached, add the config value: ``ace_attach_orientation`` which is an array describing the ``roll`` and ``yaw`` orientation of the object. -The default value is: ``[0,0]``. +In the case the item needs to have a particular orientation when attached, add the config value: ``ace_attach_orientation`` which is an array describing the ``roll`` and ``yaw`` orientation of the object. +The default value is: ``[0,0]``. -Example: +Example: ```cpp class CfgWeapons { class attach_item: CBA_MiscItem { @@ -49,11 +49,11 @@ class CfgWeapons { ``` ## 2. Event Handlers -### 2.1 Listenable Events +### 2.1 Listenable Events | Event Key | Parameters | Locality | Description | -|----------|---------|---------|---------|---------|---------| -|`ace_attach_attached` | [_attachedObject, _itemClassname, _temporary] | Local | Called after an item is attached to an object. `_temporary` flag means the item is being re-attached (after a unit is exiting a vehicle, for example) -|`ace_attach_detaching` | [_attachedObject, _itemClassname, _temporary] | Local | Called just before an item is detached/removed from an object. `_temporary` flag means the item will be reattached later, see above. +|----------|---------|---------|---------| +|`ace_attach_attached` | [_attachedObject, _itemClassname, _temporary] | Local | Called after an item is attached to an object. `_temporary` flag means the item is being re-attached (after a unit is exiting a vehicle, for example) | +|`ace_attach_detaching` | [_attachedObject, _itemClassname, _temporary] | Local | Called just before an item is detached/removed from an object. `_temporary` flag means the item will be reattached later, see above. | ### 2.2 Other events for attached objects Use [CBA Extended Event Handlers](https://github.com/CBATeam/CBA_A3/wiki/Extended-Event-Handlers-(new)). Note that objects attached to units will be deleted/created upon entering/exiting vehicles and should be handled accordingly. diff --git a/docs/wiki/framework/dragging-framework.md b/docs/wiki/framework/dragging-framework.md index f4400aed44..43a7c98ba4 100644 --- a/docs/wiki/framework/dragging-framework.md +++ b/docs/wiki/framework/dragging-framework.md @@ -46,58 +46,58 @@ You will **not** be able to carry / drag objects that are too heavy, the mass is `ace_dragging_fnc_setDraggable` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Any object | Object | Required -1 | Enable dragging, true to enable, false to disable | Boolean | Required -2 | Position to offset the object from player | Array | Optional (default: `[0, 1.5, 0]`) -3 | Direction in degree to rotate the object | Number | Optional (default: `0`) -4 | Ignore weight limitation for dragging | Boolean | Optional (default: `false`) -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Any object | Object | Required | +| 1 | Enable dragging, true to enable, false to disable | Boolean | Required | +| 2 | Position to offset the object from player | Array | Optional (default: `[0, 1.5, 0]`) | +| 3 | Direction in degree to rotate the object | Number | Optional (default: `0`) | +| 4 | Ignore weight limitation for dragging | Boolean | Optional (default: `false`) | +| **R** | None | None | Return value | #### 2.1.1 Example 1 `[foo, true, [0, 2, 0], 45] call ace_dragging_fnc_setDraggable;` - | Arguments | Explanation ----| --------- | ----------- -0 | `foo` | My object -1 | `true` | Dragging is enabled -2 | `[0,2,0]` | 0 meters sideways, 2 meters forward, 0 meters upwards -3 | `45` | Rotated by 45° +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `foo` | My object | +| 1 | `true` | Dragging is enabled | +| 2 | `[0,2,0]` | 0 meters sideways, 2 meters forward, 0 |meters upwards +| 3 | `45` | Rotated by 45° | #### 2.1.2 Example 2 `[bar, false, [3, -2, 2], 20] call ace_dragging_fnc_setDraggable;` - | Arguments | Explanation ----| --------- | ----------- -0 | `bar` | My object -1 | `false` | Dragging is disabled -2 | `[3, -2, 2]` | 3 meters sideways, 2 meters backwards, 2 meters upwards -3 | `20` | Rotated by 20° +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `bar` | My object | +| 1 | `false` | Dragging is disabled | +| 2 | `[3, -2, 2]` | 3 meters sideways, 2 meters backwards, 2 meters upwards | +| 3 | `20` | Rotated by 20° | ### 2.2 Enabling / disabling carrying `ace_dragging_fnc_setCarryable` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Any object | Object | Required -1 | Enable carrying, true to enable, false to disable | Boolean | Required -2 | Position to offset the object from player | Array | Optional (default: `[0, 1, 1]`) -3 | Direction in degree to rotate the object | Number | Optional (default: `0`) -4 | Ignore weight limitation for carrying | Boolean | Optional (default: `false`) -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Any object | Object | Required | +| 1 | Enable carrying, true to enable, false to disable | Boolean | Required | +| 2 | Position to offset the object from player | Array | Optional (default: `[0, 1, 1]`) | +| 3 | Direction in degree to rotate the object | Number | Optional (default: `0`) | +| 4 | Ignore weight limitation for carrying | Boolean | Optional (default: `false`) | +| **R** | None | None | Return value | #### 2.2.1 Example `[foo, true, [0, 3, 1], 10] call ace_dragging_fnc_setCarryable;` - | Arguments | Explanation ----| --------- | ----------- -0 | `foo` | My object -1 | `true`| Carrying is enabled -2 | `[0,2,0]` | 0 meters sideways, 3 meters forward, 1 meter upwards -3 | `10` | Rotated by 10° +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `foo` | My object | +| 1 | `true`| Carrying is enabled | +| 2 | `[0,2,0]` | 0 meters sideways, 3 meters forward, 1 meter upwards | +| 3 | `10` | Rotated by 10° | diff --git a/docs/wiki/framework/events-framework.md b/docs/wiki/framework/events-framework.md index f8183b598f..d6d4caa849 100644 --- a/docs/wiki/framework/events-framework.md +++ b/docs/wiki/framework/events-framework.md @@ -23,32 +23,32 @@ E.G.: If you only need to do action when player's weapon fires, this will be fas The vehicle events will also have the following local variables available `_gunner (OBJECT), _turret (ARRAY)`. | Event Key | Parameters | Locality | Type | Description | -|----------|---------|---------|---------|---------|---------| -|`ace_firedPlayer` | [_unit, _weapon, _muzzle, _mode, _ammo, _magazine, _projectile] | Local | Listen | ACE_player fires -|`ace_firedPlayerNonLocal` | [_unit, _weapon, _muzzle, _mode, _ammo, _magazine, _projectile] | Local | Listen | Any other player fires -|`ace_firedNonPlayer` | [_unit, _weapon, _muzzle, _mode, _ammo, _magazine, _projectile] | Local | Listen | AI fires -|`ace_firedPlayerVehicle` | [_vehicle, _weapon, _muzzle, _mode, _ammo, _magazine, _projectile] | Local | Listen | ACE_player turret fires -|`ace_firedPlayerVehicleNonLocal` | [_vehicle, _weapon, _muzzle, _mode, _ammo, _magazine, _projectile] | Local | Listen | Any other player turret fires -|`ace_firedNonPlayerVehicle` | [_vehicle, _weapon, _muzzle, _mode, _ammo, _magazine, _projectile] | Local | Listen | AI turret fires +|----------|---------|---------|---------|---------| +|`ace_firedPlayer` | [_unit, _weapon, _muzzle, _mode, _ammo, _magazine, _projectile] | Local | Listen | ACE_player fires | +|`ace_firedPlayerNonLocal` | [_unit, _weapon, _muzzle, _mode, _ammo, _magazine, _projectile] | Local | Listen | Any other player fires | +|`ace_firedNonPlayer` | [_unit, _weapon, _muzzle, _mode, _ammo, _magazine, _projectile] | Local | Listen | AI fires | +|`ace_firedPlayerVehicle` | [_vehicle, _weapon, _muzzle, _mode, _ammo, _magazine, _projectile] | Local | Listen | ACE_player turret fires | +|`ace_firedPlayerVehicleNonLocal` | [_vehicle, _weapon, _muzzle, _mode, _ammo, _magazine, _projectile] | Local | Listen | Any other player turret fires | +|`ace_firedNonPlayerVehicle` | [_vehicle, _weapon, _muzzle, _mode, _ammo, _magazine, _projectile] | Local | Listen | AI turret fires | ### 2.2 Medical (`ace_medical`) | Event Key | Parameters | Locality | Type | Description | -|----------|---------|---------|---------|---------|---------| -|`ace_unconscious` | [_unit, _state(BOOL)] | Global | Listen | Unit's unconscious state changed -|`ace_placedInBodyBag` | [_target, _bodyBag, _isGrave] | Global | Listen | Target placed into a bodybag Note: (Target will soon be deleted, target could be a bodybag) -|`ace_placedInGrave` | [_target, _grave] | Global | Listen | Target placed into a grave, _grave will be objNull if `Create Grave Markers` is disabled Note: (Target will soon be deleted) -|`ace_treatmentStarted` | [_caller, _target, _selectionName, _className, _itemUser, _usedItem] | Local | Listen | Treatment action has started (local on the _caller) -|`ace_treatmentSucceded` | [_caller, _target, _selectionName, _className, _itemUser, _usedItem] | Local | Listen | Treatment action is completed (local on the _caller) -|`ace_treatmentFailed` | [_caller, _target, _selectionName, _className, _itemUser, _usedItem] | Local | Listen | Treatment action has been interrupted (local on the _caller) -|`ace_medical_handleUnitVitals` | [_unit, _deltaT] | Local | Listen | Vitals update ran for unit, _deltaT is the time elapsed since the previous vitals update (local to _unit) -|`ace_medical_treatment_bandaged` | [_medic, _patient, _bodyPart, _className, _itemUser, _usedItem, _createLitter, _bandageEffectiveness] | Local | Listen | _medic has bandaged _patient, the array can be modified to change treatment parameters (local to _medic) +|----------|---------|---------|---------|---------| +|`ace_unconscious` | [_unit, _state(BOOL)] | Global | Listen | Unit's unconscious state changed | +|`ace_placedInBodyBag` | [_target, _bodyBag, _isGrave] | Global | Listen | Target placed into a bodybag Note: (Target will soon be deleted, target could be a bodybag) | +|`ace_placedInGrave` | [_target, _grave] | Global | Listen | Target placed into a grave, _grave will be objNull if `Create Grave Markers` is disabled Note: (Target will soon be deleted) | +|`ace_treatmentStarted` | [_caller, _target, _selectionName, _className, _itemUser, _usedItem] | Local | Listen | Treatment action has started (local on the _caller) | +|`ace_treatmentSucceded` | [_caller, _target, _selectionName, _className, _itemUser, _usedItem] | Local | Listen | Treatment action is completed (local on the _caller) | +|`ace_treatmentFailed` | [_caller, _target, _selectionName, _className, _itemUser, _usedItem] | Local | Listen | Treatment action has been interrupted (local on the _caller) | +|`ace_medical_handleUnitVitals` | [_unit, _deltaT] | Local | Listen | Vitals update ran for unit, _deltaT is the time elapsed since the previous vitals update (local to _unit) | +|`ace_medical_treatment_bandaged` | [_medic, _patient, _bodyPart, _className, _itemUser, _usedItem, _createLitter, _bandageEffectiveness] | Local | Listen | _medic has bandaged _patient, the array can be modified to change treatment parameters (local to _medic) | ### 2.3 Interaction Menu (`ace_interact_menu`) MenuType: 0 = Interaction, 1 = Self Interaction | Event Key | Parameters | Locality | Type | Description | -|----------|---------|---------|---------|---------|---------| +|----------|---------|---------|---------|---------| |`ace_interactMenuOpened` | [_menuType] | Local | Listen | Interaction Menu Opened |`ace_interactMenuClosed` | [_menuType] | Local | Listen | Interaction Menu Closed |`ace_interact_menu_newControllableObject` | [_typeOf] | Local | Listen | New controlable object, only fires once per type (add self interactions) @@ -56,79 +56,79 @@ MenuType: 0 = Interaction, 1 = Self Interaction ### 2.4 Cargo (`ace_cargo`) | Event Key | Parameters | Locality | Type | Description | -|----------|---------|---------|---------|---------|---------| -|`ace_addCargo` | [_item (CLASSNAME or OBJECT), _vehicle, _cargoCount] | Target | Callable | Scripted way to add cargo to vehicle -|`ace_cargoLoaded` | [_item, _vehicle] | Global | Listen | Cargo has been Loaded into vehicle -|`ace_cargoUnloaded` | [_item, _vehicle, _unloadType] | Global | Listen | Cargo has been Unloaded from vehicle +|----------|---------|---------|---------|---------| +|`ace_addCargo` | [_item (CLASSNAME or OBJECT), _vehicle, _cargoCount] | Target | Callable | Scripted way to add cargo to vehicle | +|`ace_cargoLoaded` | [_item, _vehicle] | Global | Listen | Cargo has been Loaded into vehicle | +|`ace_cargoUnloaded` | [_item, _vehicle, _unloadType] | Global | Listen | Cargo has been Unloaded from vehicle | ### 2.5 Captives (`ace_captives`) | Event Key | Parameters | Locality | Type | Description | -|----------|---------|---------|---------|---------|---------| -|`ace_captiveStatusChanged` | [_unit, _state(BOOL), _reason ("SetHandcuffed" or "SetSurrendered"), _caller] | Global | Listen | Unit's captivity state changed -|`ace_captives_setSurrendered` | [_unit, _state(BOOL)] | Target | Callable | Sets a unit to either start or stop surrendering -|`ace_captives_setHandcuffed` | [_unit, _state(BOOL)] | Target | Callable | Sets a unit to either start or stop being handcuffed -|`ace_captives_escortingCaptive` | [_unit, _state(BOOL), _caller] | Local | Listen | Caller starting or stopping escort of unit +|----------|---------|---------|---------|---------| +|`ace_captiveStatusChanged` | [_unit, _state(BOOL), _reason ("SetHandcuffed" or "SetSurrendered"), _caller] | Global | Listen | Unit's captivity state changed | +|`ace_captives_setSurrendered` | [_unit, _state(BOOL)] | Target | Callable | Sets a unit to either start or stop surrendering | +|`ace_captives_setHandcuffed` | [_unit, _state(BOOL)] | Target | Callable | Sets a unit to either start or stop being handcuffed | +|`ace_captives_escortingCaptive` | [_unit, _state(BOOL), _caller] | Local | Listen | Caller starting or stopping escort of unit | ### 2.6 Settings (`ace_common`) | Event Key | Parameters | Locality | Type | Description | -|----------|---------|---------|---------|---------|---------| -|`ace_settingsInitialized` | [] | Local | Listen | All modules are read and settings are ready -|`ace_settingChanged` | [_name,_value] | Local | Listen | A setting has been changed +|----------|---------|---------|---------|---------| +|`ace_settingsInitialized` | [] | Local | Listen | All modules are read and settings are ready | +|`ace_settingChanged` | [_name,_value] | Local | Listen | A setting has been changed | ### 2.7 Tagging (`ace_tagging`) | Event Key | Parameters | Locality | Type | Description | -|----------|---------|---------|---------|---------|---------| -|`ace_tagCreated` | [_tagObject, _texture, _tagAttachedTo (can be null), _unitThatCreated] | Global | Listen | Tag is created +|----------|---------|---------|---------|---------| +|`ace_tagCreated` | [_tagObject, _texture, _tagAttachedTo (can be null), _unitThatCreated] | Global | Listen | Tag is created | ### 2.8 Explosives (`ace_explosives`) | Event Key | Parameters | Locality | Type | Description | -|----------|---------|---------|---------|---------|---------| -|`ace_allowDefuse` | [_mine, _allow] | Global or Target | Callable | Set allowance of the dynamic defusal action on a mine -|`ace_tripflareTriggered` | [_flareObject, [_posX, _posY, _posZ]] | Global | Listen | Tripflare triggered -|`ace_explosives_clackerAdded` | [_unit, _explosive, _id] | Local | Listen | Clacker added to explosive -|`ace_explosives_place` | [_explosive, _dir, _pitch, _unit] | Global | Listen | Explosive is armed -|`ace_explosives_setup` | [_explosiveVehicle, _magClassname, _unit] | Global | Listen | Explosive is placed in the world +|----------|---------|---------|---------|---------| +|`ace_allowDefuse` | [_mine, _allow] | Global or Target | Callable | Set allowance of the dynamic defusal action on a mine | +|`ace_tripflareTriggered` | [_flareObject, [_posX, _posY, _posZ]] | Global | Listen | Tripflare triggered | +|`ace_explosives_clackerAdded` | [_unit, _explosive, _id] | Local | Listen | Clacker added to explosive | +|`ace_explosives_place` | [_explosive, _dir, _pitch, _unit] | Global | Listen | Explosive is armed | +|`ace_explosives_setup` | [_explosiveVehicle, _magClassname, _unit] | Global | Listen | Explosive is placed in the world | ### 2.9 Logistics Wirecutter (`ace_logistics`) | Event Key | Parameters | Locality | Type | Description | -|----------|---------|---------|---------|---------|---------| -|`ace_wireCuttingStarted` | [_unit, _fence] | Global | Listen | Fence cutting started +|----------|---------|---------|---------|---------| +|`ace_wireCuttingStarted` | [_unit, _fence] | Global | Listen | Fence cutting started | ### 2.9 Refuel (`ace_refuel`) | Event Key | Parameters | Locality | Type | Description | -|----------|---------|---------|---------|---------|---------| -|`ace_refuel_started` | [_source, _target] | Local | Listen | Refueling has started -|`ace_refuel_tick` | [_source, _target, _amount] | Local | Listen | Amount of fuel transferred in a tick -|`ace_refuel_stopped` | [_source, _target] | Local | Listen | Refueling has stopped +|----------|---------|---------|---------|---------| +|`ace_refuel_started` | [_source, _target] | Local | Listen | Refueling has started | +|`ace_refuel_tick` | [_source, _target, _amount] | Local | Listen | Amount of fuel transferred in a tick | +|`ace_refuel_stopped` | [_source, _target] | Local | Listen | Refueling has stopped | ### 2.10 Cook Off (`ace_cookoff`) | Event Key | Parameters | Locality | Type | Description | -|----------|---------|---------|---------|---------|---------| +|----------|---------|---------|---------|---------| |`ace_cookoff_cookOff` | _vehicle | Global | Listen | Vehicle cook off has started -|`ace_cookoff_cookOffBox` | _box | Global | Listen | Ammo box cook off has started -|`ace_cookoff_engineFire` | _vehicle | Global | Listen | Engine fire has started +|`ace_cookoff_cookOffBox` | _box | Global | Listen | Ammo box cook off has started | +|`ace_cookoff_engineFire` | _vehicle | Global | Listen | Engine fire has started | ### 2.11 Attach (`ace_attach`) | Event Key | Parameters | Locality | Type | Description | -|----------|---------|---------|---------|---------|---------| -|`ace_attach_attached` | [_attachedObject, _itemClassname, _temporary] | Local | Listen | After an item was attached to a unit/vehicle. _temporary flag means a item is being re-attached after the player exits a vehicle -|`ace_attach_detaching` | [_attachedObject, _itemName, _temporary] | Local | Listen | Just before an item gets detached/removed from a unit/vehicle. _temporary flag means its detached because the player unit entered a vehicle. +|----------|---------|---------|---------|---------| +|`ace_attach_attached` | [_attachedObject, _itemClassname, _temporary] | Local | Listen | After an item was attached to a unit/vehicle. _temporary flag means a item is being re-attached after the player exits a vehicle | +|`ace_attach_detaching` | [_attachedObject, _itemName, _temporary] | Local | Listen | Just before an item gets detached/removed from a unit/vehicle. _temporary flag means its detached because the player unit entered a vehicle. | ### 2.12 Trenches (`ace_trenches`) | Event Key | Parameters | Locality | Type | Description | |---------- |------------|----------|------|-------------| -| `ace_trenches_placed` | [_unit, _trench] | Global | Listen | After trench object is placed by unit. -| `ace_trenches_finished` | [_unit, _trench] | Global | Listen | After trench object is fully dug up by unit (100% progress). +| `ace_trenches_placed` | [_unit, _trench] | Global | Listen | After trench object is placed by unit. | +| `ace_trenches_finished` | [_unit, _trench] | Global | Listen | After trench object is fully dug up by unit (100% progress). | ### 2.13 Medical GUI (`ace_medical_gui`) @@ -169,21 +169,21 @@ Also Reference [CBA Events System](https://github.com/CBATeam/CBA_A3/wiki/Custom `CBA_fnc_addEventHandler` - Adds an event handler with the event name and returns the event handler ID. - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Event name | String | Required -1 | Code block | Code | Required -**R** | Event ID | Number | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Event name | String | Required | +| 1 | Code block | Code | Required | +| **R** | Event ID | Number | Return value | #### 3.1.2 Remove Event `CBA_fnc_removeEventHandler` - Removes a specific event handler of the given event name, using the ID returned from `CBA_fnc_addEventHandler`. - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Event name | String | Required -1 | Event ID | Number | Required -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Event name | String | Required | +| 1 | Event ID | Number | Required | +| **R** | None | None | Return value | ### 3.2 Calling Events @@ -191,42 +191,42 @@ Also Reference [CBA Events System](https://github.com/CBATeam/CBA_A3/wiki/Custom `CBA_fnc_localEvent` - Calls an event only on the local machine, useful for inter-module events. - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Event name | String | Required -1 | Arguments | Any | Required -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Event name | String | Required | +| 1 | Arguments | Any | Required | +| **R** | None | None | Return value | #### 3.2.2 Target Event `CBA_fnc_targetEvent` - Calls an event only on the target machine or list of target machines. - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Event name | String | Required -1 | Arguments | Any | Required -2 | Target(s) | Object OR Number OR Array | Required -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Event name | String | Required | +| 1 | Arguments | Any | Required | +| 2 | Target(s) | Object OR Number OR Array | Required | +| **R** | None | None | Return value | #### 3.2.3 Server Event `CBA_fnc_serverEvent` - Calls an event only on the server machine (dedicated or self-hosted). - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Event name | String | Required -1 | Arguments | Any | Required -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Event name | String | Required | +| 1 | Arguments | Any | Required | +| **R** | None | None | Return value | #### 3.2.4 Global Event `CBA_fnc_globalEvent` - Calls an event on all machines - the local machine, and the server machine. - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Event name | String | Required -1 | Arguments | Any | Required -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Event name | String | Required | +| 1 | Arguments | Any | Required | +| **R** | None | None | Return value | ### 3.3 Synchronized Events @@ -237,12 +237,12 @@ Adds a globally synchronized event handler which will expire events after the pr `ace_common_fnc_addSyncedEventHandler` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Event name | String | Required -1 | Code block | Code | Required -2 | Time to live | Number OR Code | Optional (default: `0`) -**R** | Event ID | Number | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Event name | String | Required | +| 1 | Code block | Code | Required | +| 2 | Time to live | Number OR Code | Optional (default: `0`) | +| **R** | Event ID | Number | Return value | #### 3.3.2 Remove Synchronized Event @@ -250,10 +250,10 @@ Removes a specific event handler of the given event name, using the ID returned `ace_common_fnc_removeSyncedEventHandler` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Event name | String | Required -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Event name | String | Required | +| **R** | None | None | Return value | #### 3.3.3 Call Synchronized Event @@ -261,12 +261,12 @@ Calls a globally synchronized event, which will also be run on JIP players unles `ace_common_fnc_syncedEvent` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Event name | String | Required -1 | Arguments | Any | Required -2 | Time to live for this call | Number OR Code | Optional (default: `0`) -**R** | Event ID | Number | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Event name | String | Required | +| 1 | Arguments | Any | Required | +| 2 | Time to live for this call | Number OR Code | Optional (default: `0`) | +| **R** | Event ID | Number | Return value | ### 3.4 Example diff --git a/docs/wiki/framework/explosives-framework.md b/docs/wiki/framework/explosives-framework.md index 9d943e3eee..8abffa9448 100644 --- a/docs/wiki/framework/explosives-framework.md +++ b/docs/wiki/framework/explosives-framework.md @@ -120,16 +120,16 @@ class CfgWeapons { ## 4. Trigger list -Name | Use ----- | ----- -`Command` | Explode when activated via clacker. -`MK16_Transmitter` | Explode when activated via M26 clacker. -`DeadManSwitch` | Explode after activated via the switch or the person dies. -`Cellphone` | Explode when the number is called. -`PressurePlate` | Explode upon being stepped upon. -`IRSensor` | Explode after movement is detected in front of the mine. -`Timer` | Explode after timer drop to 0. -`Tripwire` | Explode when something touch the tripwire. +| Name | Use | +| ---- | ----- | +| `Command` | Explode when activated via clacker. | +| `MK16_Transmitter` | Explode when activated via M26 clacker. | +| `DeadManSwitch` | Explode after activated via the switch or the person dies. | +| `Cellphone` | Explode when the number is called. | +| `PressurePlate` | Explode upon being stepped upon. | +| `IRSensor` | Explode after movement is detected in front of the mine. | +| `Timer` | Explode after timer drop to 0. | +| `Tripwire` | Explode when something touch the tripwire. | ## 5. Scripting @@ -138,41 +138,41 @@ Name | Use `ace_explosives_fnc_scriptedExplosive` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Explosive objects | Array | Required -1 | Delay before detonation | Number | Optional (default: `0`, randomized up to given number if negative) -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Explosive objects | Array | Required | +| 1 | Delay before detonation | Number | Optional (default: `0`, randomized up to given number if negative) | +| **R** | None | None | Return value | #### 5.1.1 Example `[[charge1, charge2], -3] call ace_explosives_fnc_scriptedExplosive;` - | Arguments | Explanation ----| --------- | ----------- -0 | `[charge1, charge2]` | Explosive objects to detonate -1 | `-3` | Randomized delay, up to 3 seconds +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `[charge1, charge2]` | Explosive objects to detonate | +| 1 | `-3` | Randomized delay, up to 3 seconds | ### 5.2 Connect Explosive `ace_explosives_fnc_connectExplosive` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Unit to connect to | Object | Required -1 | Explosive object to connect to | Object | Required -2 | Detonator type class name (must be present on unit) | String | Required -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Unit to connect to | Object | Required | +| 1 | Explosive object to connect to | Object | Required | +| 2 | Detonator type class name (must be present on unit) | String | Required | +| **R** | None | None | Return value | #### 5.2.1 Example `[player, claymore1, "ACE_Clacker"] call ace_explosives_fnc_connectExplosive;` - | Arguments | Explanation ----| --------- | ----------- -0 | `player` | Unit explosive will connect to -1 | `claymore1` | Explosive object that will be connected -2 | `"ACE_Clacker"` | Detonator type class name +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `player` | Unit explosive will connect to | +| 1 | `claymore1` | Explosive object that will be connected | +| 2 | `"ACE_Clacker"` | Detonator type class name | #### 5.3 Detonation Handler. @@ -207,7 +207,7 @@ Jammer that blocks RF triggers: #### 5.4 Disabling `setShotParents`. -ACE will set the owner/instigator of the explosive to the unit placeing/detonating it. +ACE will set the owner/instigator of the explosive to the unit placing/detonating it. This can be disabled by executing ```sqf diff --git a/docs/wiki/framework/fastroping-framework.md b/docs/wiki/framework/fastroping-framework.md index fad016a8bf..57c6b9055d 100644 --- a/docs/wiki/framework/fastroping-framework.md +++ b/docs/wiki/framework/fastroping-framework.md @@ -18,7 +18,7 @@ If you want to prepare a helicopter from your addon for fastroping, there's a fe By using simple rope origin points you will only need two config entries: -``` +```cpp ace_fastroping_enabled = 1; ace_fastroping_ropeOrigins[] = { {x, y, z}, @@ -28,7 +28,7 @@ ace_fastroping_ropeOrigins[] = { This will create the ropes at the two given points. If you have defined memory points for the rope origins, you can use them too: -``` +```cpp ace_fastroping_enabled = 1; ace_fastroping_ropeOrigins[] = {"ropeOriginLeft", "ropeOriginRight"}; ``` @@ -41,7 +41,7 @@ If your helicopter is not fastroping capable by default, you can make it take a To make your helicopter FRIES capable, you need to add the following config entries: -``` +```cpp ace_fastroping_enabled = 2; ace_fastroping_friesType = "yourFRIESType"; ace_fastroping_friesAttachmentPoint[] = {x, y, z}; @@ -87,16 +87,16 @@ ACE3 provides two functions that are compatible with most helicopters and all AC `ace_fastroping_fnc_equipFRIES` -| | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Helicopter | Object | Required -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Helicopter | Object | Required | +| **R** | None | None | Return value | ### 4.2. Remove FRIES from helicopter `ace_fastroping_fnc_unequipFRIES` -| | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Helicopter | Object | Required -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Helicopter | Object | Required | +| **R** | None | None | Return value | diff --git a/docs/wiki/framework/field-rations-framework.md b/docs/wiki/framework/field-rations-framework.md index bc433e7d52..34b8b8fbcd 100644 --- a/docs/wiki/framework/field-rations-framework.md +++ b/docs/wiki/framework/field-rations-framework.md @@ -16,19 +16,19 @@ redirect_from: "/wiki/frameworkx/field-rations-framework.html" ### 1.1 Consumable Items -Config Name | Type | Description ------------ | ---- | ----------- -`acex_field_rations_thirstQuenched` | Number | Amount of thirst quenched when item is consumed* -`acex_field_rations_hungerSatiated` | Number | Amount of hunger satiated when item is consumed* -`acex_field_rations_consumeTime` | Number | Time required to consume the item (in seconds) -`acex_field_rations_consumeText` | String | Progress bar text (OPTIONAL) -`acex_field_rations_consumeAnims` | Array | Animations to play when consuming item** (OPTIONAL) -`acex_field_rations_consumeSounds` | Array | Sounds to play when consuming item** (OPTIONAL) -`acex_field_rations_replacementItem` | String | Class name of replacement item to add on consumption (OPTIONAL) -`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) +| Config Name | Type | Description | +| ----------- | ---- | ----------- | +| `acex_field_rations_thirstQuenched` | Number | Amount of thirst quenched when item is consumed* | +| `acex_field_rations_hungerSatiated` | Number | Amount of hunger satiated when item is consumed* | +| `acex_field_rations_consumeTime` | Number | Time required to consume the item (in seconds) | +| `acex_field_rations_consumeText` | String | Progress bar text (OPTIONAL) | +| `acex_field_rations_consumeAnims` | Array | Animations to play when consuming item** (OPTIONAL) | +| `acex_field_rations_consumeSounds` | Array | Sounds to play when consuming item** (OPTIONAL) | +| `acex_field_rations_replacementItem` | String | Class name of replacement item to add on consumption (OPTIONAL) | +| `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._ @@ -37,17 +37,17 @@ _** Array is in format: STAND, CROUCH, PRONE. If player is in vehicle, the first ### 1.2 Water Sources -Config Name | Type | Description ------------ | ---- | ----------- -`acex_field_rations_waterSupply` | Number | Amount of water inside the object (-1 - disabled, -10 - infinite) (OPTIONAL) -`acex_field_rations_offset` | Array | Refill action offset relative to model (OPTIONAL) +| Config Name | Type | Description | +| ----------- | ---- | ----------- | +| `acex_field_rations_waterSupply` | Number | Amount of water inside the object (-1 - disabled, -10 - infinite) (OPTIONAL) | +| `acex_field_rations_offset` | Array | Refill action offset relative to model (OPTIONAL) | ## 2. Events -Event Name | Passed Parameter(s) | Locality | Description ----------- | ------------------- | -------- | ----------- -`acex_rationConsumed` | [_player, _consumeItem, _replacementItem, _thirstQuenched, _hungerSatiated, _isMagazine] | Local | Item consumed -`acex_rationRefilled` | [_source, _player, _item, _refillItem, _refillAmount, _isMagazine] | Local | Item refilled +| Event Name | Passed Parameter(s) | Locality | Description | +| ---------- | ------------------- | -------- | ----------- | +| `acex_rationConsumed` | [_player, _consumeItem, _replacementItem, _thirstQuenched, _hungerSatiated, _isMagazine] | Local | Item consumed | +| `acex_rationRefilled` | [_source, _player, _item, _refillItem, _refillAmount, _isMagazine] | Local | Item refilled | ## 3. Scripting diff --git a/docs/wiki/framework/fire-framework.md b/docs/wiki/framework/fire-framework.md index 4f9ecdfdd3..7994036ece 100644 --- a/docs/wiki/framework/fire-framework.md +++ b/docs/wiki/framework/fire-framework.md @@ -21,22 +21,22 @@ Use `CBA_fnc_serverEvent` to use the following features. Events are defined only `ace_fire_addFireSource` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Source of flame | Object/Position ASL | Required -1 | Radius of fire | Number | Required -2 | Intensity of fire (1, 10] | Number | Required -3 | Fire source ID | Any | Required -4 | Condition to stop fire | Code | Optional (default: `{ true }`) -5 | Arguments to pass to condition | Any | Optional (default: `[]`) +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Source of flame | Object/Position ASL | Required | +| 1 | Radius of fire | Number | Required | +| 2 | Intensity of fire (1, 10] | Number | Required | +| 3 | Fire source ID | Any | Required | +| 4 | Condition to stop fire | Code | Optional (default: `{ true }`) | +| 5 | Arguments to pass to condition | Any | Optional (default: `[]`) | ### 1.2 Removing fire source `ace_fire_removeFireSource` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Fire source ID | Any | Required +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Fire source ID | Any | Required | ## 2. Variables diff --git a/docs/wiki/framework/fortify-framework.md b/docs/wiki/framework/fortify-framework.md index 27bfe7d613..9de0fab35b 100644 --- a/docs/wiki/framework/fortify-framework.md +++ b/docs/wiki/framework/fortify-framework.md @@ -114,11 +114,11 @@ The Fortify budget can be updated for any side using the function. ### 2.1 Listenable -Event Name | Passed Parameter(s) | Locality | Description ----------- | ----------- | ------------------- | -------- -`acex_fortify_objectPlaced` | [player, side, objectPlaced] | Global | Fortify object placed -`acex_fortify_objectDeleted` | [player, side, objectDeleted] | Global | Fortify object deleted -`acex_fortify_onDeployStart` | [player, object, cost] | Local | Player starts placing object -`ace_fortify_onDeployStop` | [player, object, cost] | Local | Player stops placing object. Raised only if stopped before trying to place (= before progress bar appears). If it's during progress bar, only `ace_fortify_deployCanceled` is raised. -`ace_fortify_deployFinished` | [[player, side, configName, posASL, vectorDir, vectorUp, cost], elapsedTime, totalTime, errorCode] | Local | Player successfully finishes building object -`ace_fortify_deployCanceled` | [[player, side, configName, posASL, vectorDir, vectorUp, cost], elapsedTime, totalTime, errorCode] | Local | Player cancels building object +| Event Name | Passed Parameter(s) | Locality | Description | +| ---------- | ----------- | ------------------- | -------- | +| `acex_fortify_objectPlaced` | [player, side, objectPlaced] | Global | Fortify object placed | +| `acex_fortify_objectDeleted` | [player, side, objectDeleted] | Global | Fortify object deleted | +| `acex_fortify_onDeployStart` | [player, object, cost] | Local | Player starts placing object | +| `ace_fortify_onDeployStop` | [player, object, cost] | Local | Player stops placing object. Raised only if stopped before trying to place (= before progress bar appears). If it's during progress bar, only `ace_fortify_deployCanceled` is raised. | +| `ace_fortify_deployFinished` | [[player, side, configName, posASL, vectorDir, vectorUp, cost], elapsedTime, totalTime, errorCode] | Local | Player successfully finishes building object | +| `ace_fortify_deployCanceled` | [[player, side, configName, posASL, vectorDir, vectorUp, cost], elapsedTime, totalTime, errorCode] | Local | Player cancels building object | diff --git a/docs/wiki/framework/frag-framework.md b/docs/wiki/framework/frag-framework.md index 07c59764f5..d05f5068f6 100644 --- a/docs/wiki/framework/frag-framework.md +++ b/docs/wiki/framework/frag-framework.md @@ -60,22 +60,22 @@ Dimensionless value, as long as same unit as `ace_frag_metal` (for example `kg/k Gurney constant for explosive force. You can find a list of common explosive types below. If you can not find it here, or want more accurate numbers, just google the type of explosive and Gurney constant and you can find substantial information. This is **not** the detonation velocity of the explosive, do not confuse them! -Type | Speed ---------------- | -------- -Composition B | 2700 m/s -Composition C-3 | 2680 m/s -Cyclotol 75/25 | 2790 m/s -HMX | 2800 m/s -LX-14 | 2970 m/s -Octol 75/25 | 2800 m/s -PBX 9404 | 2900 m/s -PBX 9502 | 2377 m/s -Pentolite | 2750 m/s -PETN | 2930 m/s -RDX | 2830 m/s -Tetryl | 2500 m/s -TNT | 2440 m/s -Tritonal | 2320 m/s +| Type | Speed | +| --------------- | -------- | +| Composition B | 2700 m/s | +| Composition C-3 | 2680 m/s | +| Cyclotol 75/25 | 2790 m/s | +| HMX | 2800 m/s | +| LX-14 | 2970 m/s | +| Octol 75/25 | 2800 m/s | +| PBX 9404 | 2900 m/s | +| PBX 9502 | 2377 m/s | +| Pentolite | 2750 m/s | +| PETN | 2930 m/s | +| RDX | 2830 m/s | +| Tetryl | 2500 m/s | +| TNT | 2440 m/s | +| Tritonal | 2320 m/s | ### 1.4 Gurney shape factor @@ -83,11 +83,11 @@ Tritonal | 2320 m/s Shape factor for the explosive configuration. You should choose it based on the general configuration of explosives/metal in the warhead. Most grenades for example are a sphere. Artillery and aircraft bombs are a cylinder. Mines generally a flat plate. Below is a list of the three common shapes and their factors. -Shape | Factor --------- | ------ -Sphere | 3/5 -Cylinder | 1/2 -Plate | 3/5 +| Shape | Factor | +| -------- | ------ | +| Sphere | 3/5 | +| Cylinder | 1/2 | +| Plate | 3/5 | There are other configurations but these are the most common. If you are interested in others check out the wikipedia link given above. Most of these will not correctly function in ACE3 though due to additional variables for the equation. @@ -97,18 +97,18 @@ There are other configurations but these are the most common. If you are interes There are different types of fragmentation fragments to choose from, and they can be defined in this config value. -| Type -| ---- -| ACE_frag_tiny -| ACE_frag_tiny_HD -| ACE_frag_small -| ACE_frag_small_HD -| ACE_frag_medium -| ACE_frag_medium_HD -| ACE_frag_large -| ACE_frag_large_HD -| ACE_frag_huge -| ACE_frag_huge_HD +| Type | +| ------------------ | +| ACE_frag_tiny | +| ACE_frag_tiny_HD | +| ACE_frag_small | +| ACE_frag_small_HD | +| ACE_frag_medium | +| ACE_frag_medium_HD | +| ACE_frag_large | +| ACE_frag_large_HD | +| ACE_frag_huge | +| ACE_frag_huge_HD | The tinier the piece of fragmentation the shorter the distance of travel. The `_HD` variants are all even higher drag versions. Grenades generally should use the `_HD` variants. Experimentation here is important. diff --git a/docs/wiki/framework/goggles-framework.md b/docs/wiki/framework/goggles-framework.md index 1b9b27588b..07840ebf95 100644 --- a/docs/wiki/framework/goggles-framework.md +++ b/docs/wiki/framework/goggles-framework.md @@ -34,7 +34,7 @@ class CfgGlasses { ### 2.1 Listenable -Event Name | Description | Passed Parameter(s) | Locality ----------- | ----------- | ------------------- | -------- -`ace_glassesChanged` | Glasses Changed | `[_unit, _glassesClass]` | Local -`ace_glassesCracked` | Glasses Cracked | `[_unit]` | Local +| Event Name | Description | Passed Parameter(s) | Locality | +| ---------- | ----------- | ------------------- | -------- | +| `ace_glassesChanged` | Glasses Changed | `[_unit, _glassesClass]` | Local | +| `ace_glassesCracked` | Glasses Cracked | `[_unit]` | Local | diff --git a/docs/wiki/framework/grenades-framework.md b/docs/wiki/framework/grenades-framework.md index b8f61872ff..3fed8fd50a 100644 --- a/docs/wiki/framework/grenades-framework.md +++ b/docs/wiki/framework/grenades-framework.md @@ -73,8 +73,8 @@ The amount of randomness in the fuse time. ### 3.1 Listenable -Event Name | Description | Passed Parameter(s) | Locality ----------- | ----------- | ------------------- | -------- -`ace_flashbangExploded` | A flashbang exploded | `[_grenadePosASL]` | Global -`ace_grenades_flashbangedAI` | A local AI was affected by a flashbang | `[_unit, _strength, _grenadePosASL]` | Local -`ace_grenades_flashbangedPlayer` | The local player was affected by a flashbang | `[_strength, _grenadePosASL]` | Local +| Event Name | Description | Passed Parameter(s) | Locality | +| ---------- | ----------- | ------------------- | -------- | +| `ace_flashbangExploded` | A flashbang exploded | `[_grenadePosASL]` | Global | +| `ace_grenades_flashbangedAI` | A local AI was affected by a flashbang | `[_unit, _strength, _grenadePosASL]` | Local | +| `ace_grenades_flashbangedPlayer` | The local player was affected by a flashbang | `[_strength, _grenadePosASL]` | Local | diff --git a/docs/wiki/framework/interactionMenu-framework.md b/docs/wiki/framework/interactionMenu-framework.md index 68e49414e2..fb66fb3918 100644 --- a/docs/wiki/framework/interactionMenu-framework.md +++ b/docs/wiki/framework/interactionMenu-framework.md @@ -40,21 +40,25 @@ class CfgVehicles { exceptions[] = {}; statement = "_player switchMove 'TestDance'"; icon = "\z\dance.paa"; + }; + }; + }; +}; ``` -Config Name | Type | Description ----------- | ----------- | ------------------- -`displayName` | String | Text shown to user -`condition` | String (of code) | Condition to show the action -`statement` | String (of code) | Statement run when selected -`icon` | String (file path) | Icon shown (OPTIONAL) -`exceptions` | Array (of strings) | Exceptions to `canInteractWith` conditions (e.g. `"notOnMap"`) (OPTIONAL) -`insertChildren` | String (of code) | Code to return sub actions (OPTIONAL) -`modifierFunction` | String (of code) | Code to modify this action (OPTIONAL) -`runOnHover` | Number or String | (1=true) OR Condition code - Will run the statement on hover (OPTIONAL) -`distance` | Number | External Base Actions Only, Max distance player can be from action point -`position` | String (of code) | External Base Actions Only, Code to return a position in model cords (priority over `selection`) -`selection` | String | External Base Actions Only, A memory point for `selectionPosition` +| Config Name | Type | Description | +| ---------- | ----------- | ------------------- | +| `displayName` | String | Text shown to user | +| `condition` | String (of code) | Condition to show the action | +| `statement` | String (of code) | Statement run when selected | +| `icon` | String (file path) | Icon shown (OPTIONAL) | +| `exceptions` | Array (of strings) | Exceptions to `canInteractWith` conditions (e.g. `"notOnMap"`) (OPTIONAL) | +| `insertChildren` | String (of code) | Code to return sub actions (OPTIONAL) | +| `modifierFunction` | String (of code) | Code to modify this action (OPTIONAL) | +| `runOnHover` | Number or String | (1=true) OR Condition code - Will run the statement on hover (OPTIONAL) | +| `distance` | Number | External Base Actions Only, Max distance player can be from action point | +| `position` | String (of code) | External Base Actions Only, Code to return a position in model cords (priority over `selection`) | +| `selection` | String | External Base Actions Only, A memory point for `selectionPosition` | Actions can be inserted anywhere on the config tree, e.g. hearing's earplugs is a sub action of `ACE_Equipment`: @@ -62,7 +66,10 @@ Actions can be inserted anywhere on the config tree, e.g. hearing's earplugs is class CAManBase: Man { class ACE_SelfActions { class ACE_Equipment { - class ACE_PutInEarplugs { + class ACE_PutInEarplugs {}; + }; + }; +}; ``` ## 3. Adding actions via scripts @@ -233,7 +240,7 @@ This is the ideal way to add self interaction actions, as adding them via `addAc params ["_type"]; // string of the object's classname if (!(_type isKindOf "Car")) exitWith {}; if ((getNumber (configFile >> "CfgVehicles" >> _type >> "side")) != 3) exitWith {}; - + private _action = ["playRadio","Play Radio","",{playMusic "NeverGonnaGiveYouUp"},{true}] call ace_interact_menu_fnc_createAction; [_type, 1, ["ACE_SelfActions"], _action, true] call ace_interact_menu_fnc_addActionToClass; }] call CBA_fnc_addEventHandler; diff --git a/docs/wiki/framework/laser-framework.md b/docs/wiki/framework/laser-framework.md index 1a7bbf7d6b..fef12a4760 100644 --- a/docs/wiki/framework/laser-framework.md +++ b/docs/wiki/framework/laser-framework.md @@ -18,17 +18,17 @@ version: `ace_laser_fnc_getLaserCode` -| | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Unit/Vehicle | Object | Required -**R** | Laser code | Number | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Unit/Vehicle | Object | Required | +| **R** | Laser code | Number | Return value | ### 1.2. Set object's laser code `ace_laser_fnc_setLaserCode` -| | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Unit/Vehicle | Object | Required -1 | Laser code | Number | Required -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Unit/Vehicle | Object | Required | +| 1 | Laser code | Number | Required | +| **R** | None | None | Return value | diff --git a/docs/wiki/framework/medical-framework.md b/docs/wiki/framework/medical-framework.md index 834eeced80..00d9133b00 100644 --- a/docs/wiki/framework/medical-framework.md +++ b/docs/wiki/framework/medical-framework.md @@ -219,23 +219,23 @@ Custom wound handlers should follow the same spec as the built-in handler: `ace_medical_damage_fnc_woundsHandlerBase` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Unit that was hit | Object | Required -1 | Array of damage dealt to each body part | Array | Required -2 | Type of damage | String | Required -**R** | Parameters to be passed to the next handler in the list, e.g. `_this` or a modified copy of it. Return `[]` to prevent further handling. | Array | Required +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Unit that was hit | Object | Required | +| 1 | Array of damage dealt to each body part | Array | Required | +| 2 | Type of damage | String | Required | +| **R** | Parameters to be passed to the next handler in the list, e.g. `_this` or a modified copy of it. Return `[]` to prevent further handling. | Array | Required | The damage elements are sorted in descending order according to how much damage was dealt to each body part _before armor was taken into account_, but the actual damage values are _after armor_. ### Example `[player, [[0.5, "Body", 1], [0.3, "Head", 0.6]], "grenade"] ace_medical_damage_fnc_woundsHandlerBase` - | Arguments | Explanation ----| --------- | ----------- -0 | `player` | Unit that was hit -1 | `[[0.5, "Body", 1], [0.3, "Head", 0.6]]` | 0.5 damage to body (was 1 before armor), 0.3 damage to head (was 0.6 before armor) -2 | `"grenade"` | type grenade (non-selection-specific) +| | Arguments | Explanation | +| ---| --------- | ----------- | +| 0 | `player` | Unit that was hit | +| 1 | `[[0.5, "Body", 1], [0.3, "Head", 0.6]]` | 0.5 damage to body (was 1 before armor), 0.3 damage to head (was 0.6 before armor) | +| 2 | `"grenade"` | type grenade (non-selection-specific) | ## 5. Tweaking internal variables Some of ACE Medical's underlying behavior, primarily related to damage handling and the vitals loop, can be fine-tuned by editing `ace_medical_const_` variables, found in [script_macros_medical.hpp](https://github.com/acemod/ACE3/blob/master/addons/medical_engine/script_macros_medical.hpp). diff --git a/docs/wiki/framework/medical-treatment-framework.md b/docs/wiki/framework/medical-treatment-framework.md index c84d4382ea..736295804a 100644 --- a/docs/wiki/framework/medical-treatment-framework.md +++ b/docs/wiki/framework/medical-treatment-framework.md @@ -125,4 +125,6 @@ ace_medical_treatment_graveRotation = 0; // rotation angle (will depend on model ### 3.2 Zeus Medical Menu Module If a mission maker wishes to disable Zeus access to the medical menu, they can set the variable below: +```sqf ace_medical_gui_enableZeusModule = false; // default is true +``` diff --git a/docs/wiki/framework/missile-guidance-framework.md b/docs/wiki/framework/missile-guidance-framework.md index 3b31975da3..ff6859d735 100644 --- a/docs/wiki/framework/missile-guidance-framework.md +++ b/docs/wiki/framework/missile-guidance-framework.md @@ -117,6 +117,6 @@ class ace_missileguidance_attackProfiles { ### 5.1 Listenable -Event Name | Description | Passed Parameter(s) | Locality ----------- | ----------- | ------------------- | -------- -`ace_missileguidance_handoff` | Missile handed off | `[_target, _args]` | Global +| Event Name | Description | Passed Parameter(s) | Locality | +| ---------- | ----------- | ------------------- | -------- | +| `ace_missileguidance_handoff` | Missile handed off | `[_target, _args]` | Global | diff --git a/docs/wiki/framework/overpressure-framework.md b/docs/wiki/framework/overpressure-framework.md index 7e7969f62a..243157c186 100644 --- a/docs/wiki/framework/overpressure-framework.md +++ b/docs/wiki/framework/overpressure-framework.md @@ -46,6 +46,6 @@ class CfgWeapons { ### 2.1 Listenable -Event Name | Description | Passed Parameter(s) | Locality ----------- | ----------- | ------------------- | -------- -`ace_overpressure` | Overpressure damage inflicted | `[_firer, _posASL, _direction, _weapon, _magazine, _ammo]` | Target +| Event Name | Description | Passed Parameter(s) | Locality | +| ---------- | ----------- | ------------------- | -------- | +| `ace_overpressure` | Overpressure damage inflicted | `[_firer, _posASL, _direction, _weapon, _magazine, _ammo]` | Target | diff --git a/docs/wiki/framework/rearm-framework.md b/docs/wiki/framework/rearm-framework.md index 7f899f54c9..a4061cb2bc 100644 --- a/docs/wiki/framework/rearm-framework.md +++ b/docs/wiki/framework/rearm-framework.md @@ -71,31 +71,31 @@ Meant to run on server only. `ace_rearm_fnc_makeSource` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Ammo Truck | Object | Required -1 | Supply Count | Number | Optional (default: `0`) -1 | Add (`true`) or set (`false`) supply | Bool | Optional (default: `false`) -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Ammo Truck | Object | Required | +| 1 | Supply Count | Number | Optional (default: `0`) | +| 1 | Add (`true`) or set (`false`) supply | Bool | Optional (default: `false`) | +| **R** | None | None | Return value | #### 3.1.1 Example `[cursorObject, 1200] call ace_rearm_fnc_makeSource` - | Arguments | Explanation ----| --------- | ----------- -0 | `cursorObject` | Rearm source object -1 | `1200` | Ammo supply +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `cursorObject` | Rearm source object | +| 1 | `1200` | Ammo supply | ### 3.2 Enabling / disabling rearming `ace_rearm_fnc_disable` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Ammo Truck | Object | Required -1 | Disable rearming, true to disable, false to enable | Boolean | Optional (default: `true`) -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Ammo Truck | Object | Required | +| 1 | Disable rearming, true to disable, false to enable | Boolean | Optional (default: `true`) | +| **R** | None | None | Return value | This function disables rearming for all supported turrets of a vehicle. @@ -103,9 +103,9 @@ This function disables rearming for all supported turrets of a vehicle. `[tank] call ace_rearm_fnc_disable;` - | Arguments | Explanation ----| --------- | ----------- -0 | `tank` | My object +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `tank` | My object | Disables rearming on the object `tank`. @@ -113,10 +113,10 @@ Disables rearming on the object `tank`. `[tank, false] call ace_rearm_fnc_disable;` - | Arguments | Explanation ----| --------- | ----------- -0 | `tank` | My object -1 | `false`| Rearming is enabled +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `tank` | My object | +| 1 | `false` | Rearming is enabled | Enables rearming on the object `tank`. @@ -124,10 +124,10 @@ Enables rearming on the object `tank`. `ace_rearm_fnc_getSupplyCount` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Ammo Truck | Object | Required -**R** | Supply count | Number | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Ammo Truck | Object | Required | +| **R** | Supply count | Number | Return value | This function returns the current supply count of the ammo truck. @@ -135,9 +135,9 @@ This function returns the current supply count of the ammo truck. `[ammo_truck] call ace_rearm_fnc_getSupplyCount;` - | Arguments | Explanation ----| --------- | ----------- -0 | `ammo_truck` | My object +| | Arguments | Explanation | +| ---| ------------- | ----------- | +| 0 | `ammo_truck` | My object | The remaining supply count of `ammo_truck` will be returned. @@ -145,11 +145,11 @@ The remaining supply count of `ammo_truck` will be returned. `ace_rearm_fnc_setSupplyCount` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Ammo Truck | Object | Required -1 | Supply Count | Boolean | Required -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Ammo Truck | Object | Required | +| 1 | Supply Count | Boolean | Required | +| **R** | None | None | Return value | This function sets the current supply count of the ammo truck. It can be used to replenish the ammo truck on `Limited ammo supply based on caliber` setting. @@ -157,21 +157,21 @@ This function sets the current supply count of the ammo truck. It can be used to `[ammo_truck, 1000] call ace_rearm_fnc_setSupplyCount;` - | Arguments | Explanation ----| --------- | ----------- -0 | `ammo_truck` | My ammo truck object -1 | `1000`| Supply Count +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `ammo_truck` | My ammo truck object | +| 1 | `1000`| Supply Count | ### 3.5 Adding specific magazines `ace_rearm_fnc_addMagazineToSupply` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Ammo Truck | Object | Required -1 | Magazine Classname | String | Required -2 | Only add content of one ammo box | Boolean | Optional (default: `false`) -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Ammo Truck | Object | Required | +| 1 | Magazine Classname | String | Required | +| 2 | Only add content of one ammo box | Boolean | Optional (default: `false`) | +| **R** | None | None | Return value | This function is most useful with the module setting `Only specific Magazines`. Note that this function only adds one magazine of a specific class. Other magazines of the same size are not available on this module setting. It has to be used to replenish the ammo truck on `Only specific Magazines` setting. @@ -181,10 +181,10 @@ This function can also be used to increase the supply count on setting `Limited `[ammo_truck, "32Rnd_155mm_Mo_shells"] call ace_rearm_fnc_addMagazineToSupply;` - | Arguments | Explanation ----| --------- | ----------- -0 | `ammo_truck` | My ammo truck object -1 | `"32Rnd_155mm_Mo_shells"` | Some magazine class +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `ammo_truck` | My ammo truck object | +| 1 | `"32Rnd_155mm_Mo_shells"` | Some magazine class | The 32 artillery shells are added to the supply count or the magazine storage of the specified ammo truck. @@ -192,11 +192,11 @@ The 32 artillery shells are added to the supply count or the magazine storage of `ace_rearm_fnc_addVehicleMagazinesToSupply` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Ammo Truck | Object | Required -1 | Any vehicle object or class name | Object or String | Required -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Ammo Truck | Object | Required | +| 1 | Any vehicle object or class name | Object or String | Required | +| **R** | None | None | Return value | This function wraps `ace_rearm_fnc_addMagazineToSupply` and uses it to add all default magazines of all supported turrets of the vehicle to the ammo truck. @@ -204,10 +204,10 @@ This function wraps `ace_rearm_fnc_addMagazineToSupply` and uses it to add all d `[ammo_truck, tank] call ace_rearm_fnc_addVehicleMagazinesToSupply;` - | Arguments | Explanation ----| --------- | ----------- -0 | `ammo_truck` | My ammo truck object -1 | `tank`| A vehicle object +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `ammo_truck` | My ammo truck object | +| 1 | `tank`| A vehicle object | All magazines found in the class config of the object `tank` are made available. @@ -215,10 +215,10 @@ All magazines found in the class config of the object `tank` are made available. `[ammo_truck, "B_MBT_01_arty_F"] call ace_rearm_fnc_addVehicleMagazinesToSupply;` - | Arguments | Explanation ----| --------- | ----------- -0 | `ammo_truck` | My ammo truck object -1 | `"B_MBT_01_arty_F"`| Vehicle class name +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `ammo_truck` | My ammo truck object | +| 1 | `"B_MBT_01_arty_F"`| Vehicle class name | All magazines found in the config of the vehicle class `B_MBT_01_arty_F` are made available. @@ -227,21 +227,21 @@ All magazines found in the config of the vehicle class `B_MBT_01_arty_F` are mad `ace_rearm_fnc_removeMagazineFromSupply` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Ammo Truck | Object | Required -1 | Magazine Classname | String | Required -2 | Number of Rounds to withdraw | Number | Optional (default: `-1`) -**R** | Magazine could be removed successfully | Boolean | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Ammo Truck | Object | Required | +| 1 | Magazine Classname | String | Required | +| 2 | Number of Rounds to withdraw | Number | Optional (default: `-1`) | +| **R** | Magazine could be removed successfully | Boolean | Return value | #### 3.7.1 Example 1 `[ammo_truck, "500Rnd_127x99_mag_Tracer_Red"] call ace_rearm_fnc_removeMagazineFromSupply;` - | Arguments | Explanation ----| --------- | ----------- -0 | `ammo_truck` | My ammo truck object -1 | `"500Rnd_127x99_mag_Tracer_Red"`| Carrying is enabled +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `ammo_truck` | My ammo truck object | +| 1 | `"500Rnd_127x99_mag_Tracer_Red"`| Carrying is enabled | Removes one ammo box worth of "500Rnd_127x99_mag_Tracer_Red" from the supply. Depending on the module setting the ammo box does hold an entire magazine or only the caliber based amount of rounds. @@ -249,16 +249,16 @@ Removes one ammo box worth of "500Rnd_127x99_mag_Tracer_Red" from the supply. De `[ammo_truck, "500Rnd_127x99_mag_Tracer_Red", 50] call ace_rearm_fnc_removeMagazineFromSupply;` - | Arguments | Explanation ----| --------- | ----------- -0 | `ammo_truck` | My ammo truck object -1 | `"500Rnd_127x99_mag_Tracer_Red"`| Carrying is enabled -2 | `50` | Number of rounds +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `ammo_truck` | My ammo truck object | +| 1 | `"500Rnd_127x99_mag_Tracer_Red"`| Carrying is enabled | +| 2 | `50` | Number of rounds | Removes one ammo box with 50 rounds of 500Rnd_127x99_mag_Tracer_Red from the supply. This is 10% of the supply of an entire magazine. ## 4. Events -| Name | Arguments | Global? | Added in | -| ------------- | ------------- | ------------- | -| ace_rearm_sourceInitalized | Yes | Ammo truck (OBJECT) | 3.16.0 | +| Name | Arguments | Global? | Added in | +| ------------- | --------- | ------- | -------- | +| `ace_rearm_sourceInitalized` | Ammo truck (OBJECT) | Yes | 3.16.0 | diff --git a/docs/wiki/framework/refuel-framework.md b/docs/wiki/framework/refuel-framework.md index c91c8cb6e3..325606a970 100644 --- a/docs/wiki/framework/refuel-framework.md +++ b/docs/wiki/framework/refuel-framework.md @@ -45,57 +45,57 @@ Meant to be called on server only. `ace_refuel_fnc_makeSource` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Fuel Source | Object | Required -1 | Amount (in liters) | Number | Optional (default: `0`) -2 | Hooks positions | Array | Optional (default: `[[0,0,0]]`) -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Fuel Source | Object | Required | +| 1 | Amount (in liters) | Number | Optional (default: `0`) | +| 2 | Hooks positions | Array | Optional (default: `[[0,0,0]]`) | +| **R** | None | None | Return value | #### 2.1.1 Example `[cursorObject, 100] call ace_refuel_fnc_makeSource` - | Arguments | Explanation ----| --------- | ----------- -0 | `cursorObject` | Fuel source object -1 | `100` | Fuel amount (in liters) +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `cursorObject` | Fuel source object | +| 1 | `100` | Fuel amount (in liters) | ### 2.2 Getting the fuel supply `ace_refuel_fnc_getFuel` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Fuel Truck | Object | Required -**R** | Fuel amount left (in liters) | Number | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Fuel Truck | Object | Required | +| **R** | Fuel amount left (in liters) | Number | Return value | #### 2.2.1 Example `[fuelTruck] call ace_refuel_fnc_getFuel;` - | Arguments | Explanation ----| --------- | ----------- -0 | `fuelTruck` | My fuel truck object +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `fuelTruck` | My fuel truck object | ### 2.3 Setting the fuel supply `ace_refuel_fnc_setFuel` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Fuel Truck | Object | Required -1 | Amount (in liters) | Number | Required -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +| ---| --------- | ---- | ------------------------ | +| 0 | Fuel Truck | Object | Required | +| 1 | Amount (in liters) | Number | Required | +| **R** | None | None | Return value | #### 2.3.1 Example `[fuelTruck, 428] call ace_refuel_fnc_setFuel;` - | Arguments | Explanation ----| --------- | ----------- -0 | `fuelTruck` | Fuel truck object -1 | `428` | New fuel amount (in liters) +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `fuelTruck` | Fuel truck object | +| 1 | `428` | New fuel amount (in liters) | ### 2.4 Make a jerry can @@ -103,19 +103,19 @@ Meant to be run on all clients and server. `ace_refuel_fnc_makeJerryCan` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Jerry Can | Object | Required -1 | Amount (in liters) | Number | Optional (default: `20`) -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Jerry Can | Object | Required | +| 1 | Amount (in liters) | Number | Optional (default: `20`) | +| **R** | None | None | Return value | #### 2.4.1 Example 1 `[can] call ace_refuel_fnc_makeJerryCan;` - | Arguments | Explanation ----| --------- | ----------- -0 | `can` | Jerry can object +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `can` | Jerry can object | The jerry can will have the default 20 liters volume. @@ -123,16 +123,16 @@ The jerry can will have the default 20 liters volume. `[can, 200] call ace_refuel_fnc_makeJerryCan;` - | Arguments | Explanation ----| --------- | ----------- -0 | `can` | Jerry can object -1 | `200` | Amount (in liters) +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `can` | Jerry can object | +| 1 | `200` | Amount (in liters) | The jerry can will now have a volume of 200 liters. ## 3. Events | Name | Arguments | Global? | Added in | -| ------------- | ------------- | ------------- | +| ------------- | ------------- | ----- | ------------- | | ace_refuel_sourceInitialized | Fuel source (OBJECT), items (BOOL or ARRAY) | Yes | 3.16.0 | | ace_refuel_jerryCanInitalized | Jerry can (OBJECT) | Yes | 3.16.0 | diff --git a/docs/wiki/framework/reloadlaunchers-framework.md b/docs/wiki/framework/reloadlaunchers-framework.md index d055cc533c..074dc09ff0 100644 --- a/docs/wiki/framework/reloadlaunchers-framework.md +++ b/docs/wiki/framework/reloadlaunchers-framework.md @@ -26,6 +26,6 @@ class CfgWeapons { ### 2.1 Listenable -Event Name | Description | Passed Parameter(s) | Locality ----------- | ----------- | ------------------- | -------- -`ace_reloadlaunchers_reloadLauncher` | Launcher reloaded | `[_unit, _target, _weapon, _magazine]` | Target +| Event Name | Description | Passed Parameter(s) | Locality | +| ---------- | ----------- | ------------------- | -------- | +| `ace_reloadlaunchers_reloadLauncher` | Launcher reloaded | `[_unit, _target, _weapon, _magazine]` | Target | diff --git a/docs/wiki/framework/slideshow-framework.md b/docs/wiki/framework/slideshow-framework.md index 0697116039..575a81420c 100644 --- a/docs/wiki/framework/slideshow-framework.md +++ b/docs/wiki/framework/slideshow-framework.md @@ -32,16 +32,16 @@ Important notes: `ace_slideshow_fnc_createSlideshow` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Screen Objects | Array | Required -1 | Controller Objects | Array | Required (screen objects are used if empty `[]`, none are available with automatic transitions) -2 | Image Paths | Array | Required (paths must use backslash `\`) -3 | Action Names | Array | Required -4 | Slide Duration | Number | Optional (default: `0`, `0` disables automatic transitions) -5 | Set Name | String | Optional (default: localized `"Slides"`) -6 | Texture Selection | Number | Optional (default: `0`) -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Screen Objects | Array | Required | +| 1 | Controller Objects | Array | Required (screen objects are used if empty `[]`, none are available with automatic transitions) | +| 2 | Image Paths | Array | Required (paths must use backslash `\`) | +| 3 | Action Names | Array | Required | +| 4 | Slide Duration | Number | Optional (default: `0`, `0` disables automatic transitions) | +| 5 | Set Name | String | Optional (default: localized `"Slides"`) | +| 6 | Texture Selection | Number | Optional (default: `0`) | +| **R** | None | None | Return value | _Note: Set Name argument added in 3.9.1._ @@ -49,15 +49,15 @@ _Note: Set Name argument added in 3.9.1._ `[[object1, object2], [controller1], ["images\image1.paa", "images\image2.paa"], ["Action1", "Action2"], 5, "My Slides", 1] call ace_slideshow_fnc_createSlideshow;` - | Arguments | Explanation ----| --------- | ----------- -0 | `[object1, object2]` | Objects on which images will be projected on -1 | `[controller1]` | Objects with which slideshow can be controlled -2 | `["images\image1.paa", "images\image2.paa"]` | Paths to images projected on screen objects -3 | `["Action1", "Action2"]` | Action names for interaction menu if automatic transitions are not enabled -4 | `5` | 5s slide duration before change to next image -5 | `"My Slides"` | Main interaction point name, for easier distinguishing of multiple slideshow sets -6 | `1` | Uses texture selection 1 for objects with multiple options +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `[object1, object2]` | Objects on which images will be projected on | +| 1 | `[controller1]` | Objects with which slideshow can be controlled | +| 2 | `["images\image1.paa", "images\image2.paa"]` | Paths to images projected on screen objects | +| 3 | `["Action1", "Action2"]` | Action names for interaction menu if automatic transitions are not enabled | +| 4 | `5` | 5s slide duration before change to next image | +| 5 | `"My Slides"` | Main interaction point name, for easier distinguishing of multiple slideshow sets | +| 6 | `1` | Uses texture selection 1 for objects with multiple options | ### 2.2 Create Map Images @@ -86,7 +86,7 @@ _Note: Set Name argument added in 3.9.1._ tex1 = [] call ace_slideshow_fnc_mapImage; tex2 = [(getPos aWhiteboard), 0.5, [[getpos aWhiteboard, "you", "mil_start"]], 0] call ace_slideshow_fnc_mapImage; tex3 = [[4000, 4000], 0.5, [[[5000, 5000], "target", "mil_objective"]], 2] call ace_slideshow_fnc_mapImage; -[[aWhiteboard], [], [tex1, tex2, tex3], ["Full", "Sat Start", "Sat Objective"]] call ace_slideshow_fnc_createSlideshow; +[[aWhiteboard], [], [tex1, tex2, tex3], ["Full", "Sat Start", "Sat Objective"]] call ace_slideshow_fnc_createSlideshow; ``` ### 2.2.2 Map Slideshow Advanced Example @@ -105,12 +105,12 @@ private _initCode = { [{ params ["_displayID","_idPFH"]; private _display = findDisplay _displayID; - if (isNull _display) exitWith { + if (isNull _display) exitWith { systemChat format ["%1 - removing pfeh", _this]; [_idPFH] call CBA_fnc_removePerFrameHandler; }; displayUpdate _display; - + private _map = _display displayCtrl 1; _map ctrlMapAnimAdd [0, 0.3, getpos theUAV]; ctrlMapAnimCommit _map; diff --git a/docs/wiki/framework/spectator-framework.md b/docs/wiki/framework/spectator-framework.md index 22bc0c0021..c78285b98b 100644 --- a/docs/wiki/framework/spectator-framework.md +++ b/docs/wiki/framework/spectator-framework.md @@ -48,11 +48,11 @@ Note that these settings govern the default spectator behaviour. Through the use ### 3.1 Listenable -Event Name | Passed Parameter(s) | Locality | Description ----------- | ----------- | ------------------- | -------- -`ace_spectatorSet` | [_isSpectator, _player] | Global | Player's spectator status was changed -`ace_spectator_displayLoaded` | _display | Local | Spectator display was loaded -`ace_spectator_displayUnloaded` | _display | Local | Spectator display was unloaded +| Event Name | Passed Parameter(s) | Locality | Description | +| ---------- | ----------- | ------------------- | -------- | +| `ace_spectatorSet` | [_isSpectator, _player] | Global | Player's spectator status was changed | +| `ace_spectator_displayLoaded` | _display | Local | Spectator display was loaded | +| `ace_spectator_displayUnloaded` | _display | Local | Spectator display was unloaded | ## 4. Scripting diff --git a/docs/wiki/framework/tagging-framework.md b/docs/wiki/framework/tagging-framework.md index e263a2afaa..126971abf5 100644 --- a/docs/wiki/framework/tagging-framework.md +++ b/docs/wiki/framework/tagging-framework.md @@ -41,28 +41,28 @@ class ACE_Tags { `ace_tagging_fnc_addCustomTag` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Unique Identifier | String | Required -1 | Display Name | String | Required -2 | Required Item | String | Required -3 | Textures | Array | Required -4 | Icon | String | Optional (default: `""` - Default white point) -5 | Material Paths | Array | Optional (default: `[]] - No custom material) -6 | Tag Model | String | Optional (default: `"UserTexture1m_F"` - 1x1m texture surface) -**R** | Successfully Added Tag | Boolean | Return value +| | Arguments | Type | Optional (default value) | +| ---| --------- | ---- | ------------------------ | +| 0 | Unique Identifier | String | Required | +| 1 | Display Name | String | Required | +| 2 | Required Item | String | Required | +| 3 | Textures | Array | Required | +| 4 | Icon | String | Optional (default: `""` - Default white point) | +| 5 | Material Paths | Array | Optional (default: `[]` - No custom material) | +| 6 | Tag Model | String | Optional (default: `"UserTexture1m_F"` - 1x1m texture surface) | +| **R** | Successfully Added Tag | Boolean | Return value | #### 2.1.1 Example `["ace_victoryRed", "Victory Red", "ACE_SpraypaintRed", ["tagTexture1.paa", "tagTexture2.paa"], "icon.paa"] call ace_tagging_fnc_addCustomTag;` - | Arguments | Explanation ----| --------- | ----------- -0 | `"ace_victoryRed"` | Unique identifier (similar to class name) -1 | `"Victory Red"` | Name of your tag being displayed in the interaction menu -2 | `"ACE_SpraypaintRed"` | Required item to have in the inventory to be able to spray your tag -3 | `["tagTexture1.paa", "tagTexture2.paa"]` | List of texture variants (one is randomly selected when tagging) -4 | `"icon.paa"` | Icon being displayed in the interaction menu +| | Arguments | Explanation | +| ---| --------- | ----------- | +| 0 | `"ace_victoryRed"` | Unique identifier (similar to class name) | +| 1 | `"Victory Red"` | Name of your tag being displayed in the interaction menu | +| 2 | `"ACE_SpraypaintRed"` | Required item to have in the inventory to be able to spray your tag | +| 3 | `["tagTexture1.paa", "tagTexture2.paa"]` | List of texture variants (one is randomly selected when tagging) | +| 4 | `"icon.paa"` | Icon being displayed in the interaction menu | ### 2.2 Tags in description.ext diff --git a/docs/wiki/framework/trenches-framework.md b/docs/wiki/framework/trenches-framework.md index 5fc2dc636e..40e83689ba 100644 --- a/docs/wiki/framework/trenches-framework.md +++ b/docs/wiki/framework/trenches-framework.md @@ -30,7 +30,7 @@ class CfgSurfaces { ```cpp class CfgWeapons { // same config also works on backpacks (CfgVehicles) class yourBaseClass; - class yourEntrenchingToolClass: yourBaseClass + class yourEntrenchingToolClass: yourBaseClass { ace_trenches_entrenchingTool = 1; }; }; diff --git a/docs/wiki/framework/ui-framework.md b/docs/wiki/framework/ui-framework.md index af391f36d5..3b6ec08951 100644 --- a/docs/wiki/framework/ui-framework.md +++ b/docs/wiki/framework/ui-framework.md @@ -53,21 +53,21 @@ Adding new elements through scripting is currently not possible. `ace_ui_fnc_setElementVisibility` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Source | String | Required -1 | Set/Unset | Boolean | Required -2 | Element Name | String | Required -3 | Show/Hide | Boolean | Optional (default: `false`) -**R** | Successfully Modified | Boolean | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Source | String | Required | +| 1 | Set/Unset | Boolean | Required | +| 2 | Element Name | String | Required | +| 3 | Show/Hide | Boolean | Optional (default: `false`) | +| **R** | Successfully Modified | Boolean | Return value | #### 2.1.1 Example `["ace_reload", true, "ammoCount", false] call ace_ui_fnc_setElementVisibility;` - | Arguments | Explanation ----| --------- | ----------- -0 | `"ace_reload"` | Source displayed in hint when trying to edit this element from in-game settings or in RPT when some other source tries to edit it -1 | `true` | Set element, preventing others to change it (except config, which always has priority) -2 | `"ammoCount"` | Element name to modify -3 | `false` | Hide the element +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `"ace_reload"` | Source displayed in hint when trying to edit this element from in-game settings or in RPT when some other source tries to edit it | +| 1 | `true` | Set element, preventing others to change it (except config, which always has priority) | +| 2 | `"ammoCount"` | Element name to modify | +| 3 | `false` | Hide the element | diff --git a/docs/wiki/framework/vehiclelock-framework.md b/docs/wiki/framework/vehiclelock-framework.md index 8dc1aea2cf..d882cab971 100644 --- a/docs/wiki/framework/vehiclelock-framework.md +++ b/docs/wiki/framework/vehiclelock-framework.md @@ -31,22 +31,22 @@ Sync the module with vehicles and players. Custom keys will be handed to players `ace_vehiclelock_fnc_addKeyForVehicle` - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Unit | Object | Required -1 | Vehicle | Object | Required -2 | Use Custom Key | Boolean | Optional (default: `false`, `false` for side key, `true` for custom key) -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Unit | Object | Required | +| 1 | Vehicle | Object | Required | +| 2 | Use Custom Key | Boolean | Optional (default: `false`, `false` for side key, `true` for custom key) | +| **R** | None | None | Return value | #### 3.1.1 Example `[bob, car1, true] call ace_vehiclelock_fnc_addKeyForVehicle;` - | Arguments | Explanation ----| --------- | ----------- -0 | `bob` | Unit the key will be added to -1 | `car1` | Vehicle the key will work on -2 | `true` | Set custom key +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `bob` | Unit the key will be added to | +| 1 | `car1` | Vehicle the key will work on | +| 2 | `true` | Set custom key | ### 3.2 Override Side diff --git a/docs/wiki/framework/vehicles-framework.md b/docs/wiki/framework/vehicles-framework.md index a1f66e807a..dac52d0cfa 100644 --- a/docs/wiki/framework/vehicles-framework.md +++ b/docs/wiki/framework/vehicles-framework.md @@ -38,18 +38,18 @@ class CfgVehicles { `ace_vehicles_fnc_setVehicleStartDelay` Has global effects. - | Arguments | Type | Optional (default value) ----| --------- | ---- | ------------------------ -0 | Vehicle | Object | Required -1 | Delay (in seconds) | Number | Required -**R** | None | None | Return value +| | Arguments | Type | Optional (default value) | +|----| --------- | ---- | ------------------------ | +| 0 | Vehicle | Object | Required | +| 1 | Delay (in seconds) | Number | Required | +| **R** | None | None | Return value | #### 1.2.1 Example `[myCar, 2.2] call ace_vehicles_fnc_setVehicleStartDelay;` - | Arguments | Explanation ----| --------- | ----------- -0 | `myCar` | My car object -1 | `2.2` | New startup delay +| | Arguments | Explanation | +|----| --------- | ----------- | +| 0 | `myCar` | My car object | +| 1 | `2.2` | New startup delay | diff --git a/docs/wiki/framework/wirecutter-framework.md b/docs/wiki/framework/wirecutter-framework.md index 3f2a97c0b1..65a4ed1f98 100644 --- a/docs/wiki/framework/wirecutter-framework.md +++ b/docs/wiki/framework/wirecutter-framework.md @@ -36,6 +36,6 @@ class CfgVehicles { ### 2.1 Listenable -Event Name | Description | Passed Parameter(s) | Locality ----------- | ----------- | ------------------- | -------- -`ace_wireCuttingStarted` | Wire cutting started | `[_unit, _fence]` | Global +| Event Name | Description | Passed Parameter(s) | Locality | +| ---------- | ----------- | ------------------- | -------- | +| `ace_wireCuttingStarted` | Wire cutting started | `[_unit, _fence]` | Global | diff --git a/docs/wiki/framework/xm157-framework.md b/docs/wiki/framework/xm157-framework.md index 45a2a19c21..d92d4b37e9 100644 --- a/docs/wiki/framework/xm157-framework.md +++ b/docs/wiki/framework/xm157-framework.md @@ -52,5 +52,4 @@ class CfgWeapons { }; }; }; - ``` From 97257ca77a0eb02d4ca25cb615154b1a6594a88b Mon Sep 17 00:00:00 2001 From: OverlordZorn <56258612+OverlordZorn@users.noreply.github.com> Date: Sun, 21 Apr 2024 16:15:07 +0200 Subject: [PATCH 014/290] Documentation - minor fix (#9967) a -> an --- docs/wiki/development/arma-3-scheduler-and-our-practices.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 440f0f9557..d2ffda2a07 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 a 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. 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. 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. From 5a6d6a73df5577b9fc147e15f7f7dd1edb72032a Mon Sep 17 00:00:00 2001 From: Crowdedlight Date: Mon, 22 Apr 2024 19:08:49 +0200 Subject: [PATCH 015/290] Wiki - Fix search being broken by the attach-framework page (#9969) --- docs/wiki/framework/attach-framework.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/wiki/framework/attach-framework.md b/docs/wiki/framework/attach-framework.md index f1f35bc6a8..f118b3b934 100644 --- a/docs/wiki/framework/attach-framework.md +++ b/docs/wiki/framework/attach-framework.md @@ -15,7 +15,7 @@ version: ## 1. Config Values ### 1.1 Make item attachable -An item can be added to the ACE Attach framework by adding the ``ACE_attachable`` property to a class in ``CfgWeapons`` or ``CfgMagazines``. The value must be the classname of a valid class in ``CfgVehicles``: +An item can be added to the ACE Attach framework by adding the `ACE_attachable` property to a class in `CfgWeapons` or `CfgMagazines`. The value must be the classname of a valid class in `CfgVehicles`: ```cpp class CfgWeapons { class attach_item: CBA_MiscItem { @@ -29,14 +29,14 @@ class CfgVehicles { scope = 1; // Should be 1 (private) or 2 (public), scope 0 will cause errors on object creation displayName = "New ACE attachable item"; model = "\path\to\my\model.p3d"; - vehicleClass = ""; + vehicleClass = ""; }; }; ``` ### 1.2 Define attach orientation for non-symmetric items -In the case the item needs to have a particular orientation when attached, add the config value: ``ace_attach_orientation`` which is an array describing the ``roll`` and ``yaw`` orientation of the object. -The default value is: ``[0,0]``. +In the case the item needs to have a particular orientation when attached, add the config value: `ace_attach_orientation` which is an array describing the `roll` and `yaw` orientation of the object. +The default value is: `[0,0]`. Example: ```cpp From a0e4f095551bd324a16d5cd656286c3aea5c208a Mon Sep 17 00:00:00 2001 From: Hexo <130893962+Alfred-Neuman@users.noreply.github.com> Date: Tue, 23 Apr 2024 00:15:05 +0200 Subject: [PATCH 016/290] Translations - French (Map tools) (#9953) * Update translate Hearing french * update map tools --------- Co-authored-by: PabstMirror --- addons/maptools/stringtable.xml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/addons/maptools/stringtable.xml b/addons/maptools/stringtable.xml index cca7aa98a8..bb0782f22b 100644 --- a/addons/maptools/stringtable.xml +++ b/addons/maptools/stringtable.xml @@ -41,7 +41,7 @@ 標定盤 Tavola di calcolo Графическая доска - Tableau de calcul + Planche traçante The Plotting Board is a map tool designed for use in the directing of short range indirect fires. @@ -49,7 +49,7 @@ 標定盤(プロッティング・ボード)は、短距離の間接射撃の指示に使用するために設計されたマップツールです。 La tavola di calcolo è uno strumento utilizzato per dirigere fuoco di artiglieria a corto raggio. Графическая доска - это картографический инструмент, предназначенный для использования при ведении непрямого огня с малой дистанции. - La table de calcul est un instrument utilisé pour diriger les tirs d'artillerie à courte portée. + Une planche traçante est un outil cartographique conçu pour diriger des tirs indirects à courte distance. Map Tools @@ -274,7 +274,7 @@ 플로팅 보드 그리기 채널 허용 Canali ammessi su tavola di calcolo Разрешить создание каналов на миллиметровой доске. - Canaux autorisés sur la table de calcul + Canaux autorisés sur la planche traçante Channels in which plotting board drawing is enabled. @@ -282,7 +282,7 @@ 플로팅 보드 그리기가 활성화된 채널입니다. Canali in cui si può disegnare sulla tavola di calcolo. Каналы, в которых включено рисование на миллиметровой доске. - Canaux dans lesquels vous pouvez dessiner sur le tableau. + Canaux dans lesquels vous pouvez dessiner sur le planche traçante Allow Direct Comms Only (Polylines Only) @@ -306,7 +306,7 @@ 플로팅 보드 Tavola di calcolo Миллиметровая доска - Table de calcul + Planche traçante Plotting Board Acrylic @@ -314,7 +314,7 @@ 플로팅 보드 (아크릴) Acrilico tavola di calcolo Миллиметровая доска акрилловая - Table de calcul Acrylique + Planche traçante Acrylique Plotting Board Ruler @@ -322,7 +322,7 @@ 플로팅 보드 (자) Righello tavola di calcolo Линейка для миллиметровой доски - Règle de la table de calcul + Règle de la planche traçante To Plotting Board @@ -330,7 +330,7 @@ 플로팅 보드에 Su tavola di calcolo К миллиметровой доске. - Sur la table de calcul + Sur la planche traçante To Plotting Board Acrylic @@ -338,7 +338,7 @@ 플로팅 보드 (아크릴)에 Su acrilico tavola di calcolo К миллиметровой доске акрилловой - Sur la table de calcul Acrylique + Sur la planche traçante Acrylique To Plotting Board Ruler @@ -346,7 +346,7 @@ 플로팅 보드 (자)에 Su righello tavola di calcolo К линейке миллиметровой доски. - Sur la règle de la table à calcul + Sur la règle de la planche traçante Wipe all markers off Plotting Board @@ -354,7 +354,7 @@ 플로팅 보드에 있는 모든 마커 지우기 Cancella tutti i disegni dalla tavola Сотрите все маркеры с миллиметровой доски. - Effacer tous les dessins de la planche + Effacer tous les dessins de la planche traçante Show Plotting Board @@ -362,7 +362,7 @@ 플로팅 보드 보이기 Mostra tavola di calcolo Показать миллиметровую доску. - Afficher la table de calcul + Afficher la planche traçante Hide Plotting Board @@ -370,7 +370,7 @@ 플로팅 보드 숨기기 Nascondi tavola di calcolo Скрыть миллиметровую доску. - Masquer la table de calcul + Masquer la planche traçante Toggle Plotting Board Ruler From 9e6f624a68b5788585ffe5ddd115a7fad84bc316 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Tue, 23 Apr 2024 23:07:16 +0200 Subject: [PATCH 017/290] Cargo - Fix undefined variable and config entries (#9965) Cargo fixes --- addons/cargo/CfgVehicles.hpp | 4 ++-- addons/cargo/XEH_postInit.sqf | 2 +- addons/cargo/functions/fnc_initVehicle.sqf | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/cargo/CfgVehicles.hpp b/addons/cargo/CfgVehicles.hpp index 485a53d8f5..6f6a93e820 100644 --- a/addons/cargo/CfgVehicles.hpp +++ b/addons/cargo/CfgVehicles.hpp @@ -510,7 +510,7 @@ class CfgVehicles { }; GVAR(space) = 2; - GVAR(hasCargo) = 2; + GVAR(hasCargo) = 1; GVAR(size) = 3; GVAR(canLoad) = 1; @@ -524,7 +524,7 @@ class CfgVehicles { class CBA_Extended_EventHandlers: CBA_Extended_EventHandlers {}; }; GVAR(space) = 3; - GVAR(hasCargo) = 3; + GVAR(hasCargo) = 1; GVAR(size) = 3; GVAR(canLoad) = 1; diff --git a/addons/cargo/XEH_postInit.sqf b/addons/cargo/XEH_postInit.sqf index 94cb2afc87..f48849b50b 100644 --- a/addons/cargo/XEH_postInit.sqf +++ b/addons/cargo/XEH_postInit.sqf @@ -86,7 +86,7 @@ GVAR(vehicleAction) = [ GVAR(enable) && {alive _target} && {locked _target < 2} && - {(_target getVariable [QGVAR(hasCargo), getNumber (configOf _target >> QGVAR(hasCargo)) == 1])} && + {_target getVariable [QGVAR(hasCargo), getNumber (configOf _target >> QGVAR(hasCargo)) == 1]} && {[_player, _target, ["isNotSwimming"]] call EFUNC(common,canInteractWith)} && {[_player, _target] call EFUNC(interaction,canInteractWithVehicleCrew)} && {([_player, _target] call EFUNC(interaction,getInteractionDistance)) < MAX_LOAD_DISTANCE} diff --git a/addons/cargo/functions/fnc_initVehicle.sqf b/addons/cargo/functions/fnc_initVehicle.sqf index 4ca004b94e..af80761fe0 100644 --- a/addons/cargo/functions/fnc_initVehicle.sqf +++ b/addons/cargo/functions/fnc_initVehicle.sqf @@ -23,7 +23,7 @@ private _config = configOf _vehicle; // If vehicle had space given to it via eden/public, then override config hasCargo setting private _hasCargoPublic = _vehicle getVariable QGVAR(hasCargo); -private _hasCargoPublicDefined = !isNil "_canLoadPublic"; +private _hasCargoPublicDefined = !isNil "_hasCargoPublic"; if (_hasCargoPublicDefined && {!(_hasCargoPublic isEqualType false)}) then { WARNING_4("%1[%2] - Variable %3 is %4 - Should be bool",_vehicle,_type,QGVAR(hasCargo),_hasCargoPublic); From c17873dcad517005f73832339ce1ed6b0dd6345d Mon Sep 17 00:00:00 2001 From: jonpas Date: Wed, 24 Apr 2024 02:29:25 +0200 Subject: [PATCH 018/290] Prepare 3.17.1 Build 84 --- addons/main/script_version.hpp | 4 ++-- docs/_config.yml | 4 ++-- docs/_config_dev.yml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/addons/main/script_version.hpp b/addons/main/script_version.hpp index 501b3095dc..62b6d52e2e 100644 --- a/addons/main/script_version.hpp +++ b/addons/main/script_version.hpp @@ -1,4 +1,4 @@ #define MAJOR 3 #define MINOR 17 -#define PATCHLVL 0 -#define BUILD 83 +#define PATCHLVL 1 +#define BUILD 84 diff --git a/docs/_config.yml b/docs/_config.yml index 66cd1141f7..e29663ce3b 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -9,8 +9,8 @@ ace: version: major: 3 minor: 17 - patch: 0 - build: 82 + patch: 1 + build: 84 markdown: kramdown diff --git a/docs/_config_dev.yml b/docs/_config_dev.yml index e3c042e9c7..b6f160c7d3 100644 --- a/docs/_config_dev.yml +++ b/docs/_config_dev.yml @@ -9,8 +9,8 @@ ace: version: major: 3 minor: 17 - patch: 0 - build: 82 + patch: 1 + build: 84 markdown: kramdown From 1eca83db9fb1cd4ca101f73d4f9949a17059e38f Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 25 Apr 2024 06:41:27 +0200 Subject: [PATCH 019/290] Common - Fix animations not playing (#9973) Update CfgMoves.hpp --- addons/common/CfgMoves.hpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/addons/common/CfgMoves.hpp b/addons/common/CfgMoves.hpp index 3c51140fed..da83153b15 100644 --- a/addons/common/CfgMoves.hpp +++ b/addons/common/CfgMoves.hpp @@ -1,8 +1,5 @@ class CfgMovesBasic { - // Idle affects legs when weapon switching - fixes units sliding when holstering weapons - class Default { - idle = ""; - }; + class Default; // From ACRE class ManActions { @@ -86,5 +83,14 @@ class CfgMovesMaleSdr: CfgMovesBasic { class AinvPknlMstpSnonWnonDnon_medic0: HealBase { variantsPlayer[] = {}; }; + + // Idle affects legs when weapon switching - fixes units sliding when holstering weapons + class AmovPercMstpSnonWnonDnon: StandBase { + idle = ""; + }; + // Need to reset idle, as it breaks animations otherwise + class CutSceneAnimationBase: AmovPercMstpSnonWnonDnon { + idle = "idleDefault"; + }; }; }; From a12ad9ec59dcb69aa1fec7b0ae9b03549dc982e4 Mon Sep 17 00:00:00 2001 From: Dystopian Date: Thu, 25 Apr 2024 09:23:10 +0400 Subject: [PATCH 020/290] Interact menu - Fix condition in consolidated menu (#9946) Fix condition in consolidated menu --- .../interact_menu/functions/fnc_collectActiveActionTree.sqf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/interact_menu/functions/fnc_collectActiveActionTree.sqf b/addons/interact_menu/functions/fnc_collectActiveActionTree.sqf index ebb02caa11..9a3eb31598 100644 --- a/addons/interact_menu/functions/fnc_collectActiveActionTree.sqf +++ b/addons/interact_menu/functions/fnc_collectActiveActionTree.sqf @@ -109,14 +109,14 @@ if ((_activeChildren isEqualTo []) && {_statementCode isEqualTo {}}) exitWith { if (GVAR(consolidateSingleChild) && {count _activeChildren == 1} && {_statementCode isEqualTo {}}) then { _activeChildren select 0 params ["_childActionData", "_childChildren", "_childObject"]; - _childActionData params ["", "_displayNameChild", "_iconChild", "_statementChild", "", "", "_customParamsChild", "", "", "_paramsChild"]; + _childActionData params ["", "_displayNameChild", "_iconChild", "_statementChild", "_conditionChild", "_insertChildrenChild", "_customParamsChild", "", "", "_paramsChild"]; _origActionData = [ _actionName, format ["%1 > %2", _displayName, _displayNameChild], _iconChild, _statementChild, - _conditionCode, - _insertChildrenCode, + _conditionChild, + _insertChildrenChild, _customParamsChild, _position, _distance, From b513a110f5564d42243770c52f338642d5b594cf Mon Sep 17 00:00:00 2001 From: Apricot <50947830+Apricot-ale@users.noreply.github.com> Date: Sat, 27 Apr 2024 07:34:11 +0900 Subject: [PATCH 021/290] Translations - Improve Japanese localization (3.17.1) (#9977) Tweaks --- addons/cargo/stringtable.xml | 2 +- addons/common/stringtable.xml | 4 +-- addons/dragging/stringtable.xml | 2 +- addons/explosives/stringtable.xml | 6 ++-- addons/field_rations/stringtable.xml | 2 +- addons/finger/stringtable.xml | 2 +- addons/fortify/stringtable.xml | 8 ++--- addons/frag/stringtable.xml | 6 ++-- addons/headless/stringtable.xml | 2 +- addons/hearing/stringtable.xml | 23 ++++++------ addons/map/stringtable.xml | 2 +- addons/map_gestures/stringtable.xml | 6 ++-- addons/medical/stringtable.xml | 4 +-- addons/medical_ai/stringtable.xml | 2 +- addons/medical_blood/stringtable.xml | 2 +- addons/medical_damage/stringtable.xml | 14 ++++---- addons/medical_engine/stringtable.xml | 2 +- addons/medical_gui/stringtable.xml | 2 +- addons/medical_statemachine/stringtable.xml | 8 ++--- addons/medical_treatment/stringtable.xml | 40 ++++++++++----------- addons/microdagr/stringtable.xml | 6 ++-- addons/pylons/stringtable.xml | 2 +- addons/rearm/stringtable.xml | 2 +- addons/refuel/stringtable.xml | 2 +- addons/repair/stringtable.xml | 4 +-- addons/spectator/stringtable.xml | 2 +- addons/trenches/stringtable.xml | 8 ++--- addons/vehiclelock/stringtable.xml | 2 +- addons/viewdistance/stringtable.xml | 2 +- addons/volume/stringtable.xml | 2 +- addons/weather/stringtable.xml | 2 +- 31 files changed, 87 insertions(+), 86 deletions(-) diff --git a/addons/cargo/stringtable.xml b/addons/cargo/stringtable.xml index 79ee3f96b5..0a766ab221 100644 --- a/addons/cargo/stringtable.xml +++ b/addons/cargo/stringtable.xml @@ -513,7 +513,7 @@ Modifies how long it takes to load/unload items.\nTime, in seconds, is the size of the item multiplied by this value. Gibt an, wie lange das Laden / Entladen von Gegenständen dauern soll.\nZeit in Sekunden, die mit der Größe des Gegenstandes multipliziert wird. - 貨物の積み込み/積み下ろしに掛かる時間を変更します。\n時間 (秒) は、貨物のサイズにこの値を掛けたものです。 + 貨物の積み込み/積み下ろしに掛かる時間を変更します。\n時間 (秒単位) は、貨物のサイズにこの値を掛けたものです。 Modyfikuje, jak długo zajmuje załadowywanie/wyładowywanie przedmiotów. \nCzasem, w sekundach, jest wielkość przedmiotu razy jego wartość. Modifica il tempo impiegato per caricare o scaricare gli oggetti.\nIl tempo, in secondi, equivale alla dimensione dell'oggetto moltiplicata per questo valore Изменяет время для загрузки/выгрузки предметов. \nВремя (сек) - это размер предмета, умноженный на это значение. diff --git a/addons/common/stringtable.xml b/addons/common/stringtable.xml index 4afdf2ad89..1c960e9173 100644 --- a/addons/common/stringtable.xml +++ b/addons/common/stringtable.xml @@ -498,7 +498,7 @@ 设定当玩家有错误的 PBO 时要如何处理。 Nastavuje jakou akci provést pokud hráč nemá správné PBO. Określa akcję, która ma być podjęta, jeśli gracz nie ma właściwych PBO. - プレイヤーが不正規のPBOを所持している場合の動作を決定します。 + プレイヤーが不正規のPBOを所持している場合の動作を定義します。 Define la accion a tomar si un jugador no tiene el PBO correcto Definisce l'azione che verrà presa se il giocatore non ha gli stessi PBO. Определяет, какое действие будет предпринято, если игрок не имеет корректные PBO. @@ -1582,7 +1582,7 @@ Controls extra information shown in progress bar. - プログレス バーへ表示される情報量を決定します。 + プログレス バーへ表示される情報量を制御します。 Définit quelles informations supplémentaires sont affichées dans la barre de progression. Устанавливает дополнительную информацию в индикаторе процесса. Kontrolliert zusätzliche Informationen beim Fortschrittsbalkens. diff --git a/addons/dragging/stringtable.xml b/addons/dragging/stringtable.xml index 7cf53ba55c..9552f50273 100644 --- a/addons/dragging/stringtable.xml +++ b/addons/dragging/stringtable.xml @@ -192,7 +192,7 @@ Determines whether object's weight is added onto weight calculations. - 重量計算にオブジェクトの重量を追加するかどうかを決定します。 + 重量計算にオブジェクトの重量を追加するかどうかを定義します。 Determina se la massa del contenitore è sommata alla massa del contenuto per i calcoli di peso. Określa, czy waga obiektu jest dodawana do obliczeń ciężaru. Legt fest, ob das Gewicht des Objekts zu den Gewichtsberechnungen hinzugefügt wird. diff --git a/addons/explosives/stringtable.xml b/addons/explosives/stringtable.xml index b21238e98e..fccc685c4f 100644 --- a/addons/explosives/stringtable.xml +++ b/addons/explosives/stringtable.xml @@ -1170,7 +1170,7 @@ Minimum time value (in seconds) for the explosive timer. Минимальное время до взрыва в секундах Définit la durée minimale paramétrable sur le minuteur. - 起爆タイマーの最低時間 (秒) を設定します。 + 起爆タイマーの最短時間 (秒単位) を設定します。 Tiempo mínimo (en segundos) para el temporizador del explosivo. Minimalna wartość czasomierza dla ładunku (w sekundach). Minimale Zeit (in Sekunden) für den Zeitzünder. @@ -1183,7 +1183,7 @@ Maximum time value (in seconds) for the explosive timer. Макисмальное время до взрыва в секундах Définit la durée maximale paramétrable sur le minuteur. - 起爆タイマーの最長時間 (秒) を設定します。 + 起爆タイマーの最長時間 (秒単位) を設定します。 Tiempo máximo (en segundos) para el temporizador del explosivo. Maksymalna wartość czasomierza dla ładunku (w sekundach). Maximale Zeit (in Sekunden) für den Zeitzünder. @@ -1196,7 +1196,7 @@ Default time value (in seconds) for the explosive timer. Стандартное время до взрыва в секундах Définit la durée paramétrée par défaut sur le minuteur. - 起爆タイマーの標準時間 (秒) を設定します。 + 起爆タイマーの標準時間 (秒単位) を設定します。 Tiempo por defecto (en segundos) para el temporizador del explosivo. Domyślna wartość czasomierza dla ładunku (w sekundach). Standardmäßige Zeit (in Sekunden) für den Zeitzünder. diff --git a/addons/field_rations/stringtable.xml b/addons/field_rations/stringtable.xml index 482f347598..2b443ccc3c 100644 --- a/addons/field_rations/stringtable.xml +++ b/addons/field_rations/stringtable.xml @@ -455,7 +455,7 @@ 控制顏色化圖示的透明度。設定為動態使其界面透明度與飲食需求一樣,越透明越需要。 控制彩色图标 HUD 的透明度。动态设置使 HUD 的透明度随着口渴或饥饿的增加而减弱。 Kontroluje transparentność kolorowych ikon HUD. Dynamiczne ustawienie zmniejsza przejrzystość wraz z zwiększeniem głodu czy pragnienia. - 色付きアイコンの透明度を決定できます。動的に設定されると、空腹度や喉の渇きが増すにつれて、アイコンの透明度を下げます。 + 色付きアイコンの透明度を制御できます。動的に設定されると、空腹度や喉の渇きが増すにつれて、アイコンの透明度を下げます。 Настраивает прозрачность цветных иконок. «Динамическая» делает иконки менее прозрачными при увеличении жажды и голода. Renkli Simgeler Gösterge Paneli'nin şeffaflığını kontrol eder. Dinamik ayar, susuzluk veya açlık arttıkça HUD'yi daha az şeffaf hale getirir. 색깔 아이콘의 투명도를 조절합니다. 동적 설정의 경우 배고픔이나 목마름이 해결되면 덜 투명하게 바뀝니다. diff --git a/addons/finger/stringtable.xml b/addons/finger/stringtable.xml index 9f61aa0f7c..bdb0c835b6 100644 --- a/addons/finger/stringtable.xml +++ b/addons/finger/stringtable.xml @@ -79,7 +79,7 @@ Distancia máxima entre los jugadores para mostrar el indicador que señala [por defecto: 4 metros] Maximální vzdálenost mezi hráči pro ukázání směru [výchozí: 4 metry] Distanza massima tra giocatori per mostrare l'indicatore di puntamento [Predefinito: 4 metri] - 指差しのマーカー表示が他のプレイヤーに表示される最大範囲を決定できます。 [デフォルト: 4メートル] + 指差しのマーカー表示が他のプレイヤーに表示される最大範囲 [デフォルト: 4メートル] 플레이어 사이에서 가리키기 표시를 보이게 하는 최대거리를 설정합니다[기본설정: 4 미터] 设定指向标记最大显示距离。[预设:4米] 設定指向指示器最大顯示距離。[預設: 4公尺] diff --git a/addons/fortify/stringtable.xml b/addons/fortify/stringtable.xml index c3fda20caf..15150d6685 100644 --- a/addons/fortify/stringtable.xml +++ b/addons/fortify/stringtable.xml @@ -145,7 +145,7 @@ Mostra aggiornamenti di budget 顯示預算更新 显示预算更新 - 予算の更新を表示 + 予算更新を表示 Pokaż aktualizacje budżetu Показывать обновления бюджета Bütçe güncellenmelerini göster @@ -160,7 +160,7 @@ 決定預算變更時是否會顯示提示 决定预算变更时是否会显示提示 Controlla se vengono mostrati avvisi di aggiornamento del budget - 予算が更新されヒント表示時の操作を決定します + 予算更新のヒントが表示される場面を制御します Kontroluje kiedy aktualizacje budżetu są wyświetlane Настраивает сообщения об обновлении бюджета Bütçe güncellenince bilgi verilip verilmeyeceğini kontrol eder. @@ -190,7 +190,7 @@ Ha l'attrezzo di fortificazione 有要塞工具 有设防工具 - 要塞ツール所持の時 + 要塞ツール所持時 Posiada narzędzie do fortyfikowania Если имеется инструмент Insa Etme Aleti Olanlara Göster @@ -233,7 +233,7 @@ 건축물을 지을 때 걸리는 시간을 계수를 적용하여 계산합니다. Koeffizient zur Bestimmung der Bauzeit \nA in Ax + b, wobei x die Kosten des Objekts sind. Il coefficiente 'C' che determina il tempo di costruzione.\nTempo Totale = Costo * C + Tempo Minimo - 建造する時間を決定するために使用される係数。\n計算式はAx + bです。この係数はAであり、xは建造物のコストです。 + 建造する時間を定義するために使用される係数。\n計算式はAx + bです。この係数はAであり、xは建造物のコストです。 Współczynnik używany do określenia czasu budowy konstrukcji.\nA w Ax + b gdzie x jest kosztem obiektu Коэффициент используемый для указания времени необходимого для возведения постройки.\nA в формуле Ax + b, где x - это цена объекта Coeficiente usado para determinar el tiempo de construcción de una estructura.\nA en Ax + b donde x es el coste del objeto diff --git a/addons/frag/stringtable.xml b/addons/frag/stringtable.xml index 2bd76c2928..f88877448d 100644 --- a/addons/frag/stringtable.xml +++ b/addons/frag/stringtable.xml @@ -105,7 +105,7 @@ Active la simulation de la réflexion des explosions ACE. Ativa a simulação de reflexo de explosão do ACE Включить симуляцию отражения взрывов ACE - ACE爆発反射シミュレーションを有効化 + ACE 爆発反射シミュレーションを有効化 ACE 폭발 반사 시뮬레이션을 적용합니다. 启用 ACE 模拟爆炸反射 啟用ACE模擬爆炸反射 @@ -138,7 +138,7 @@ Ez a beállítás szabályozza a repeszeződés és pattogzás által kilőtt objektumok követett számát. Ha több ez a szám, ezek az objektumok nem lesznek követve. Csökkentsd ezt a beállítást, ha nem akarsz lassulásokat magas-törmelékmennyiségű helyzetekben (200+ repesz a levegőben egyszerre) Эта настройка контролирует максимальное количество снарядов, которок отслеживает система осколков и обломков в каждый момент времени. /nСнаряды, выстреленные сверх этого числа, отслеживаться не будут. Уменьшите это значение, если вы не хотите падения FPS при большом количестве снарядов в одной перестрелке (> 200 одновременно летящих снарядов) Questo parametro controlla il numero massimo di proiettili che la frammentazione e il sistema di spalling tracciano in ogni momento. Se vengono sparati ulteriori proiettili, non verranno tracciati. Abbassa questo parametro se non vuoi cali di FPS in scenari con molti proiettili (>200 proiettili in aria contemporaneamente) - この設定では、断片化および剥離システムが常に追跡する飛翔体の最大量を制御します。 さらに多くの飛翔体が発射された場合、それらは追跡されません。 弾数が多いシナリオでFPSを低下させたくない場合は、この設定を下げてください。 (一度に200発以上が空中に発射されます) + この設定では、断片化および剥離システムが常に追跡する飛翔体の最大量を制御します。 この値より多くの飛翔体が発射された場合、それらは追跡されません。 弾数が多いシナリオでFPSを低下させたくない場合は、この設定を下げてください。 (一度に200発以上が空中に発射されます) 이 설정은 탄환파편 및 파편 시스템으로 인해 생긴 발사체의 수를 결정합니다. 만약 더 많은 발사체가 나올 경우 정해진 수 이외에는 추적하지 않습니다. 이 설정을 낮춤으로써 파편이 많은 시나리오를 실행할때 더욱 원활히 진행할 수 있습니다 (한 번에 200개 이하) 设定在指定时间内,系统最大可追踪的破片粒子数量。如有更多的碎片在这之后产生,这些粒子将不会被追踪。如果你想要维持好的帧数,此设定勿调的过高。( >一次200颗粒子) 設定在指定時間內,系統最大可追蹤的碎片/剝落粒子數量。如有更多的碎片在這之後產生,這些粒子將不會被追蹤。如果你想要維持好的幀數,此設定勿調的過高。( >一次200顆粒子) @@ -170,7 +170,7 @@ A lepattogzási útvonalak számításának darabjai képkockánként. Ez eloszlatja az FPS-megszakadást több képkockára, ezzel csökkentve a súlyosságát. Число обрабатываемых осколков за кадр. Это позволяет распределить нагрузку по отслеживанию осколков между несколькими кадрами, чтобы предотвратить падение FPS. Il numero di calcoli per tracciamento di spalling ad ogni frame. Questo aiuta a distribuire l'impatto del tracciamento dello spalling su più frame, riducendolo ulteriormente. - 与えられたフレームごとに追跡する剥離飛翔体の数を決定します。FPS に影響をあたえないよう、剥離飛翔体を複数のフレームで追跡し、分散させています。 + 任意のフレームごとに追跡される剥離飛翔体の数。剥離による飛翔体を追跡することによるFPSへの影響を複数フレームに分散させ抑えることが出来ます。 가능한 프레임마다 파편을 추적 및 계산합니다. 여러 프레임에 걸쳐 파편난 발사체를 추적하여 FPS에 도움을 줍니다. 이를 제한함으로써 더욱 큰 효과를 볼 수 있습니다. 设定在每一帧数内,系统最大可追踪的破片粒子数量。此设定可有效帮助系统减低计算压力。 設定在每一幀數內,系統最大可追蹤的碎片/剝落粒子數量。此設定可有效幫助系統減低計算壓力 diff --git a/addons/headless/stringtable.xml b/addons/headless/stringtable.xml index 584c12f954..35dcb11862 100644 --- a/addons/headless/stringtable.xml +++ b/addons/headless/stringtable.xml @@ -62,7 +62,7 @@ Minimale Verzögerung zwischen Transfers in Sekunden. (Standard: 15) Minimalny odstęp pomiędzy transferami w sekundach. (Domyślnie: 15) 전송 간 최소 지연 시간, 초당. (기본값: 15) - 移行する際の最低遅延を秒数で設定します。 (デフォルト: 15) + 移行する際の最低遅延を秒単位で設定します。 (デフォルト: 15) Délai minimum entres les transferts, en secondes. (Défaut: 15) 设定每次转换间隔多少秒。(预设:15秒) 設定每次轉換間隔多少秒。(預設:15秒) diff --git a/addons/hearing/stringtable.xml b/addons/hearing/stringtable.xml index 1cbeacf259..1265478639 100644 --- a/addons/hearing/stringtable.xml +++ b/addons/hearing/stringtable.xml @@ -45,7 +45,7 @@ Füldugó berakva Protetores colocados Indossa i tappi auricolari - 耳栓を着ける + 耳栓を装着 귀마개 착용 塞入耳塞 塞入耳塞 @@ -79,7 +79,7 @@ Füldugó berakva Protetores colocados Tappi auricolari indossati - 耳栓を着けました + 耳栓を装着しました 귀마개 착용 耳塞已塞入 耳塞已塞入 @@ -144,7 +144,7 @@ Quando il giocatore riceve danni all'udito, non far sentire il fischio nelle orecchie Remove o efeito de zunido quando o jogador recebe dano na audição Убирает эффект звона в ушах, когда игрок получает повреждение слуха - プレイヤーの聴覚が損傷したときの耳鳴り効果を削除します + プレイヤーが聴覚にダメージを受けた際の耳鳴り効果音を無効化します 플레이어가 청력손실을 입을 때 생기는 이명현상을 제거합니다. 关闭耳鸣效果时,就算玩家受到相当程度的听力伤害,也不会造成耳鸣效果 關閉耳鳴效果時,就算玩家受到相當程度的聽力傷害, 也不會造成耳鳴效果 @@ -192,7 +192,7 @@ Уменьшает возможность игрока слышать звуки при повреждении органов слуха Assorda il giocatore quando riceve danni all'udito Réduit la capacité auditive du joueur lorsqu'il subit des dommages auditifs. - プレイヤーが聴覚ダメージを受けると聴力が低下します + プレイヤーが聴覚にダメージを受けると聴力が低下します 청력에 손상을 입으면 듣는 소리가 감소합니다. 当玩家听力受损时降低听力能力? 當玩家聽力受損時降低聽力能力? @@ -268,7 +268,7 @@ Aggiungi l'oggetto 'ACE_EarPlugs' a tutte le unità che hanno armi/lanciatori rumorosi. Può essere disabilitato se vengono usati loadout personalizzati. Agregar el item `ACE_EarPlugs` a todas las unidades equipadas con armas muy ruidosas. Desactivar si quieren utilizarse equipamientos personalizados. Ajoute l'objet `Ace_EarPlugs` à toutes les unités ayant des armes bruyantes. Peut être désactivé si de l'équipement personnalisé est utilisé. - 全ユニットへ`ACE_EarPlugs`アイテムを持たせます。これはロードアウトの編集で無効化できます。 + 全てのユニットに`ACE_EarPlugs`アイテムを所持させます。これはロードアウトの編集で無効化できます。 무기를 가지고 있는 모든 인원에게 'ACE_EarPlugs'를 지급합니다. 임의의 장비를 사용시 비활성화할 수 있습니다. 增加`ACE_EarPlugs`物品给拥有巨大噪音武器的单位。当你想自定装备时,此功能可被关闭。 增加`ACE_EarPlugs`物品給擁有巨大噪音武器的單位。當你想自定裝備時,此功能可被關閉。 @@ -292,7 +292,7 @@ Volume muffling Lautstärkedämpfung Atténuation du volume - 音量低下 + 音量の抑制 降低音量 進低音量 Attenuazione del volume @@ -306,7 +306,7 @@ Earplugs Volume Lautstärke Ohrenstöpsel - 耳栓時の音量 + 耳栓装着時音量 耳塞时音量 耳塞時音量 Volume con i Tappi @@ -321,7 +321,7 @@ Volume when using earplugs. Lautstärke wenn man Ohrenstöpsel benutzt - 耳栓使用時の音量を決定します。 + 耳栓を使用した時の音量。 决定带上耳塞时的音量 使用耳塞時音量 Volume audio quandi si indossano i tappi per le orecchie. @@ -336,7 +336,7 @@ Unconscious Volume Lautstärke Bewusstlosigkeit - 気絶時の音量 + 無意識状態時音量 无意识时音量 昏迷時音量 Volume quando incoscente @@ -351,7 +351,7 @@ Volume when unconscious. Lautstärke während man Bewusstlos ist - 無意識状態時の音量を決定します。 + 無意識状態になった時の音量。 决定处于无意识时的音量 昏迷時使用耳塞的音量 Volume quando incoscente. @@ -365,7 +365,7 @@ Put/take out earplugs - 耳栓を着け外す + 耳栓の着脱 Вставить/вынуть беруши Metti/Togli tappi 귀마개 토글 @@ -375,6 +375,7 @@ Only units with heavy weapons Uniquement les unités dotées d'armes lourdes Только юниты с тяжелым вооружением + 重火器を装備したユニットのみ diff --git a/addons/map/stringtable.xml b/addons/map/stringtable.xml index ed5d427424..5d91167639 100644 --- a/addons/map/stringtable.xml +++ b/addons/map/stringtable.xml @@ -268,7 +268,7 @@ Milyen gyakran frissüljenek a jelölők (másodpercben) Как часто должны обновляться маркеры (в секундах) Quanto spesso vengono aggiornati i marker (in secondi) - マーカが再描画される間隔を設定できます (秒) + マーカが再描画される間隔 (秒単位) 몇 초마다 마커를 새로 갱신합니까? 设定每多少时间重新标示出单位位置(秒) 設定每多少時間重新標示出單位位置 (秒) diff --git a/addons/map_gestures/stringtable.xml b/addons/map_gestures/stringtable.xml index 3b7d7e77dd..91f07c7cdf 100644 --- a/addons/map_gestures/stringtable.xml +++ b/addons/map_gestures/stringtable.xml @@ -228,7 +228,7 @@ Farbwert für Gruppenführer, die mit diesem Modul synchronisiert werden. Color para los líderes de los grupos sincronizados al módulo. Couleur pour les chefs des groupes synchronisés avec ce module. - モジュールで同期されたグループの隊長に設定される色の値を決定します。 + モジュールで同期されたグループの隊長に設定される色の値。 그룹이 이 모듈에 동기화 됐을 때의 리더 색상입니다. 改变与此同步小队队长的指示颜色。 改變與此同步小隊隊長的指示器顏色 @@ -259,7 +259,7 @@ Farbwert für Gruppenmitglieder, die mit diesem Modul synchronisiert werden. Color para los miembros de los grupos sincronizados al módulo. Couleur pour les membres des groupes synchronisés avec ce module. - モジュールで同期されたグループの隊員に設定される色の値を決定します。 + モジュールで同期されたグループの隊員に設定される色の値。 그룹이 이 모듈에 동기화 됐을 때의 멤버 색상입니다. 改变与此同步小队队员的指示颜色 改變與此同步小隊隊員的指示器顏色 @@ -386,7 +386,7 @@ What player can see what Определяет, какая группа игроков может видеть жесты на карте во время брифинга Définit quels pointages les joueurs peuvent voir lors du briefing. - プレイヤーが見ることができる対象を決定します。 + プレイヤーが見ることができる対象 Qué puede ver cada jugador Quali giocatori possono vedere gesti sulla mappa in fase di briefing. Co mogą widzieć gracze diff --git a/addons/medical/stringtable.xml b/addons/medical/stringtable.xml index cfc05e4d75..6a081fa648 100644 --- a/addons/medical/stringtable.xml +++ b/addons/medical/stringtable.xml @@ -37,7 +37,7 @@ Unconscious Wake Up Chance Wahrscheinlichkeit um aufzuwachen - 気絶時の覚醒確率 + 無意識状態時の覚醒確率 Шанс очнуться при потере сознания Chance de reprendre connaissance Chance de recuperar consciência @@ -84,7 +84,7 @@ When an unconscious patient has Epinephrine in their system, the time between spontaneous wake up checks is divided by this value. - 気絶した患者の体内に投与されたアドレナリンがある場合、 覚醒確率計算の実施間隔が値で除算されます。 + 無意識状態の患者の体内に投与されたアドレナリンがある場合、 覚醒確率計算の実施間隔が値で除算されます。 增加因病患的循環系統裡面的腎上腺素自我甦醒的機率。 增加因病患的循环系统里面的肾上腺素自我苏醒的机率。 Augmente la fréquence des tests de réveil lorsque le patient a de l'épinéphrine dans son système sanguin.\n(L'épinéphrine n'accélère pas la reprise de conscience si la valeur est définie sur 1.) diff --git a/addons/medical_ai/stringtable.xml b/addons/medical_ai/stringtable.xml index 7f5680dc3f..5081a09d96 100644 --- a/addons/medical_ai/stringtable.xml +++ b/addons/medical_ai/stringtable.xml @@ -20,7 +20,7 @@ AI will respond to injury and unconsciousness KI reagiert auf Verletzungen und Bewusstlosigkeit - AIが負傷者と気絶している人に対して行動するようになります。 + AIが負傷者と無意識状態の人に対して行動するようになります。 ИИ будет реагировать на травмы и потерю сознания Les unités IA seront sensibles aux blessures, ainsi qu'à la perte de connaissance. A IA irá responder a ferimentos e perdas de consciência diff --git a/addons/medical_blood/stringtable.xml b/addons/medical_blood/stringtable.xml index 6c3be0c557..a63de99ea0 100644 --- a/addons/medical_blood/stringtable.xml +++ b/addons/medical_blood/stringtable.xml @@ -99,7 +99,7 @@ Controls the lifetime of blood drop objects. - 血痕オブジェクトの寿命を決定します。 + 血痕オブジェクトの寿命を制御します。 Définit la durée d'affichage des traces de sang. Управляет временем жизни объектов капель крови. Controla o tempo de vida que um objeto de gota de sangue tem. diff --git a/addons/medical_damage/stringtable.xml b/addons/medical_damage/stringtable.xml index f21cb1901f..626826117d 100644 --- a/addons/medical_damage/stringtable.xml +++ b/addons/medical_damage/stringtable.xml @@ -18,7 +18,7 @@ Sets the amount of damage a player can receive before going unconscious (and dying if "Sum of Trauma" is enabled). - プレイヤーが気絶するまでに受けられるダメージ量を設定します。\n("外傷の合計"が有効な場合は死亡するまでに受けられるダメージ量) + プレイヤーが無意識状態に陥るまでに受けられるダメージ量を設定します。\n("外傷の合計"が有効な場合は死亡するまでに受けられるダメージ量) Définit la quantité de dégâts qu'un joueur peut subir avant de perdre connaissance (ou mourir, si l'option "Somme des traumatismes" est sélectionnée). Устанавливает количество урона, которое может получить игрок, прежде чем потеряет сознание (и умирает, если включена функция "Сумма травм"). Define a quantidade de dano que um jogador pode receber antes de ficar inconsciente. @@ -49,7 +49,7 @@ Sets the amount of damage an AI unit can receive before going unconscious (or dying when "Sum of Trauma" is enabled). - AIが気絶するまでに受けられるダメージ量を設定します。\n("外傷の合計"が有効な場合は死亡するまでに受けられるダメージ量) + AIが無意識状態に陥るまでに受けられるダメージ量を設定します。\n("外傷の合計"が有効な場合は死亡するまでに受けられるダメージ量) Définit la quantité de dégâts qu'une unité IA peut subir avant de perdre connaissance (ou mourir, si l'option "Somme des traumatismes" est sélectionnée). Устанавливает количество урона, которое может получить ИИ, прежде чем потеряет сознание (или умирает, когда включена функция "Сумма травм").. Define a quantidade de dano que uma IA pode receber antes de ficar inconsciente. @@ -625,7 +625,7 @@ Determines what damage can be fatal Определяет какой урон будет смертельным - 致命となるダメージの種類を決定します。 + 致命となるダメージの種類を定義します。 決定何種傷害為致命 确定哪些伤害可能是致命的 Determina quali danni possono essere letali @@ -757,7 +757,7 @@ Legt die Höhe des Schadens fest, den eine Einheit erhalten kann, bevor diese ohnmächtig wird. (0 für Misionsnormalwert) Determina il livello di danni sopportabili da un'unità senza svenire. (0 per il valore predefinito dalla missione) Définit la quantité de dégâts que l'unité peut subir avant de perdre connaissance (ou mourir, si l'option "Somme des traumatismes" est sélectionnée).\n(0 utilise la valeur définie dans la mission.) - このユニットが気絶するまでに受けられるダメージ量を設定します。 (ミッション標準は0) + このユニットが無意識状態に陥るまでに受けられるダメージ量を設定します。 (ミッション標準は0) Určuje kolik poškození může jednotka utrpět než upadne do bezvědomí. (pro použití standardní hodnoty mise zadejte 0) Устанавливает количество урона, которое может получить юнит перед тем, как потерять сознание. (0 для значения миссии) Ustawia próg obrażeń jakie może otrzymać jednostka przed utratą przytomności. (0 jako ustawienie domyślne misji) @@ -772,7 +772,7 @@ Шанс потерять сознание от боли Szansa na nieprzytomność przez ból Probabilità Svenimento da Dolore - 痛みによる気絶確率 + 痛みによる無意識化確率 Probabilidad de inconsciencia por dolor Douleur - Chance d'évanouissement Chance für Bewusslosigkeit durch Schmerz @@ -785,7 +785,7 @@ Шанс, что человек потеряет сознание, когда его боль выше допустимого порога при получении травмы. La probabilità che un'unità perda i sensi quando il suo dolore è sopra la soglia critica ricevendo danni. Szansa że osoba straci przytomność gdy jej ból jest powyżej tolerowalnego progu podczas otrzymywania obrażeń. - ユニットがダメージを受けた時の痛みが許容しきい値を超えていた場合に気絶する確率を設定します。 + ユニットがダメージを受けた時の痛みが許容しきい値を超えていた場合に無意識状態に陥る確率を設定します。 La probabilidad de que una persona caiga inconsciente cuando su dolor está por encima del umbral al haber recibido daño. La probabilité pour qu'une personne perde connaissance lorsque la douleur ressentie est supérieure à son seuil de tolérance. Die Wahrscheinlichkeit, dass eine Person bewusstlos wird, wenn ihre Schmerzen bei einer Verwundung über der Toleranzschwelle liegen. @@ -798,7 +798,7 @@ Порог боли для потери сознания Soglia Critica di Dolore Seuil d'inconscience par la douleur. - 気絶する痛みのしきい値 + 無意識状態に陥る痛みのしきい値 Próg Nieprzytomności od Bólu Schmerz-Bewusstlosigkeit-Grenze 고통 기절 한계점 diff --git a/addons/medical_engine/stringtable.xml b/addons/medical_engine/stringtable.xml index 3aa0831a28..1765df0d39 100644 --- a/addons/medical_engine/stringtable.xml +++ b/addons/medical_engine/stringtable.xml @@ -20,7 +20,7 @@ Controla si la tripulación recibe daño debido a colisiones en vehículo. Définit si les passagers à bord des véhicules peuvent être blessés en cas d'accident. Kontroluje czy załoga pojazdu otrzyma obrażenia podczas kolizji pojazdu. - 車両が衝突をすると乗員がダメージを受けるかどうかを決定します。 + 車両が衝突をすると乗員がダメージを受けるかどうかを制御します。 Kontrolliert, ob Besatzung eines Fahrzeugs Schaden durch Unfälle erleiden soll Determina se i passeggeri di un veicolo subiranno danni da schianti o incidenti. 控制乘员是否受到车辆碰撞的伤害。 diff --git a/addons/medical_gui/stringtable.xml b/addons/medical_gui/stringtable.xml index 5a41bba671..71388bfb41 100644 --- a/addons/medical_gui/stringtable.xml +++ b/addons/medical_gui/stringtable.xml @@ -198,7 +198,7 @@ Maximum distance from which the Medical Menu can be opened. Maximale Entfernung, um das Sanitätsmenü zu öffnen. - 医療メニューを開いたままにできる最大距離を決定します。 + 医療メニューを開いたままにできる最大距離。 Максимальное расстояние, с которого можно открыть Медицинское меню. Définit la distance (en mètres) à partir de laquelle il n'est plus possible d'activer le menu médical pour traiter un patient. A Distância máxima do paciente para que o Menu Médico possa ser aberto. diff --git a/addons/medical_statemachine/stringtable.xml b/addons/medical_statemachine/stringtable.xml index 1b29b1c553..2b828d506e 100644 --- a/addons/medical_statemachine/stringtable.xml +++ b/addons/medical_statemachine/stringtable.xml @@ -68,7 +68,7 @@ Controls when AI can receive fatal injuries. A fatal injury is caused by significant damage to the head or troso.\nWhen set to "Always", this effectively produces "AI Instant Death" behaviour as AI will immediately die from any fatal injury.\nNOTE: Any mode other than "Always" requires AI Unconsciousness to be enabled. Controla quando a IA pode receber lesões fatais. Uma lesão fatal é causada por um dano significante na cabeça ou tronco.\nQuando definido para "Sempre", isso efetivamente causa a "Morte Instantânea da IA", pois a IA irá imediatamente morrer para qualquer lesão fatal.\nNOTA: Qualquer opção além de "Sempre" requer que Inconsciência de IA esteja ativada. - AIが致命傷を受けた時の挙動を管理できます。頭部や胸部に受ける大きなダメージは致命傷になります。\n"常に"に設定されていると、いかなる致命傷でも"AIの即死"効果が生まれます。\n注: "常に"以外のモードでは"AIの気絶"を有効化させる必要があります。 + AIが致命傷を受けた時の挙動を管理できます。頭部や胸部に受ける大きなダメージは致命傷になります。\n"常に"に設定されていると、いかなる致命傷でも"AIの即死"効果が生まれます。\n注: "常に"以外のモードでは"AIの無意識状態化"を有効化させる必要があります。 控制當AI受致命傷時是否能救起。致命傷是指對頭部或身體造成可觀傷害所造成的。\n當設置為"總是"時,這會使其與"AI 瞬間死亡"同一個效果,在AI受到致命傷時瞬間死亡。\n備註:選了"總是"以外的選項的話必須開啟「AI無意識」的選項。 控制当 AI 受致命伤时是否能救起。致命伤是指对头部或躯干遭受重大伤害。\n当设置为"总是"时,这将有效地产生"AI 即时死亡"行为,因为 AI 将立即死于任何致命伤。\n注意:"总是"以外的任何模式都需要启用 AI 无意识。 Détermine si les unités IA décèdent en cas de blessure mortelle. Une blessure mortelle est définie par des dommages importants à la tête ou au cœur.\nSi réglé sur "Toujours", cela produit effectivement un comportement de "Mort instantanée" car les unités IA mourront immédiatement de toute blessure mortelle.\nNOTE : Tout mode autre que "Toujours" nécessite l'activation de l'option "Inconscience IA". @@ -92,7 +92,7 @@ Inconscience IA AI eszméletlenség Incoscienza IA - AIの気絶 + AIの無意識状態化 인공지능 기절 AI 无意识 AI無意識 @@ -101,7 +101,7 @@ Controls whether AI can go unconscious instead of immediately dying.\nThis setting works together with the "AI Fatal Injuries" setting since, going into cardiac arrest requires that the unit is able to go unconscious.\nHowever, these settings are separated because units can go unconscious from critical vitals resulting from non-fatal injuries.\nIn essence, this means that in order to enable cardiac arrest for AI units, this setting must be enabled. Controla se a IA pode ficar inconsciente ao invés de morrer imediatamente.\nEssa configuração funciona com "Lesões Fatais de IA", pois para uma unidade ter uma parada cardíaca é necessário que a IA possa fica inconsciente.\nContudo, essas configurações são separadas pois unidades podem ficar inconscientes por vitais críticos causados por ferimentos não-fatais.\nEssencialmente, isso significa que para ativar uma parada cardíaca em IA, essa configuração precisa estar ativa. - AIが即死する代わりに気絶するかどうかを決定できます。\nこれは "AIの致命傷" 設定と連動します。これは心停止を起こすにはユニットが気絶する必要がある為です。\nしかしながら、これらの設定はユニットが非致死性の負傷により重体となって気絶できるよう分離されています。\n本質的にはこの設定はAIユニットの心停止を可能にするものであり、有効化されておくべきです。 + AIが即死する代わりに無意識状態化するかどうかを制御します。\nこれは "AIの致命傷" 設定と連動します。何故ならば、ユニットを心停止させるためには無意識状態に陥る必要がある為です。\nしかし、これらの設定は、致命的ではない負傷の経過による重症状態化でユニットが無意識状態に陥ることが出来るようにするため、分割されています。\n要するに、AIユニットの心停止を有効にするには、この設定を有効にする必要があるということです。 控制AI是否能進入無意識狀態而非立刻原地死亡。\n這個選項會與「AI致命傷」的選項聯動,使單位心搏停止的話必須先讓其無意識。\n然而,兩個設定分開之原因是使單位能因從非致命傷的攻擊情況下進入生命危險的狀態。\n簡單來說,你想要讓AI單位有心搏停止可能的話,該選項必須啟用。 控制 AI 是否可以进入昏迷状态而不是立即死亡。\n这个设置与"AI 致命伤"设置一起工作,因为进入心脏骤停需要单位能够昏迷。\n然而,这些设置是分开的,因为单位可能会因非致命伤害导致的关键生命体征而昏迷过去。\n从本质上讲,这意味着为了使 AI 单位的心脏骤停,必须启用此设置。 Définit si les unités IA peuvent perdre connaissance au lieu de mourir immédiatement.\nCe paramètre fonctionne conjointement avec l'option "Décès si blessure mortelle (IA)" car, pour qu'une unité IA subisse un arrêt cardiaque, elle doit également pouvoir perdre connaissance.\nCependant, ces paramètres sont séparés car les unités peuvent s'évanouir suite à des signes vitaux critiques résultant de blessures non mortelles.\nEn résumé, cela signifie que ce paramètre doit absolument être activé pour qu'une unité IA puisse entrer en état d'arrêt cardiaque. @@ -132,7 +132,7 @@ Controls how long it takes to die from cardiac arrest. - どのくらいの時間、心停止すると死亡するかを決定します。 + どのくらいの時間、心停止すると死亡するかを制御します。 Définit le temps qu'il faut pour mourir d'un arrêt cardiaque. Контролирует, сколько времени требуется, чтобы умереть от остановки сердца. Controla o tempo necessário para morrer para uma parada cardíaca. diff --git a/addons/medical_treatment/stringtable.xml b/addons/medical_treatment/stringtable.xml index be421eff36..29774efb3c 100644 --- a/addons/medical_treatment/stringtable.xml +++ b/addons/medical_treatment/stringtable.xml @@ -196,7 +196,7 @@ Controls when hitpoint damage from wounds is healed. - 治療後に負傷箇所にある外傷の状態を決定できます。 + 治療後に負傷箇所にある外傷の状態を制御できます。 Définit à quel moment les blessures sont entièrement soignées. Определяет, когда исцеляется урон от ран. Steuert, wann Trefferpunktschaden von Wunden geheilt wird. @@ -264,7 +264,7 @@ Controls whether medical equipment can be shared between the patient and the medic. - 患者と救護者との間で医療品の共有をするかどうかを決定します。 + 患者と救護者との間で医療品の共有をするかどうかを制御します。 Définit si l'équipement médical du médecin et du patient sont mis en commun, et quel matériel est à utiliser en priorité, le cas échéant. Контролирует, можно ли разделить медикаменты между пациентом и врачом. Controla se um item médico pode ser compartilhado entre médico e paciente. @@ -325,7 +325,7 @@ Time, in seconds, required to administer medication using an autoinjector. Définit le temps nécessaire à l'administration d'une substance auto-injectable (en secondes). - 自動注射器の使用に掛かる時間 (秒) を決定します。 + 自動注射器の使用に掛かる時間。 (秒単位) Tiempo, en segundos, requerido para administrar medicación utilizando un autoinyectador. Время, необходимое для введения медикаментов автоинъектором (в секундах). Czas w sekundach potrzebny do aplikacji medykamentów za pomocą autostrzykawki. @@ -351,7 +351,7 @@ Définit le temps nécessaire à l'application ou au retrait d'un garrot (en secondes). Zeit in Sekunden, die benötigt wird, um ein Tourniquet anzuwenden. Tempo in secondi richiesto per mettere/rimuovere un laccio emostatico. - 止血帯の使用/取り外しに掛かる時間 (秒) を決定します。 + 止血帯の使用/取り外しに掛かる時間。 (秒単位) Tiempo, en segundos, requerido para aplicar/quitar un torniquete. Время, необходимое для наложения/снятия жгута (в секундах). Czas w sekundach potrzebny do założenia/zdjęcia stazy. @@ -375,7 +375,7 @@ Définit le temps nécessaire à la pose d'une perfusion IV (en secondes). Zeit in Sekunden, die benötigt wird, um einen Infusionsbeutel aufzutragen. Tempo in secondi richiesto per applicare una Flebo Endovenosa. - 点滴の投与に掛かる時間 (秒) を決定します。 + 点滴の投与に掛かる時間。 (秒単位) Tiempo, en segundos, requerido para administrar una bolsa de IV. Время, необходимое для применения пакета внутривенного переливания (в секундах). Czas w sekundach potrzebny na aplikację transfuzji IV. @@ -399,7 +399,7 @@ Définit le temps nécessaire à l'application d'une attelle (en secondes). Zeit in Sekunden, die zum Anbringen einer Schiene benötigt wird. Tempo in secondi richiesto per applicare una gessatura. - 添え木の使用に掛かる時間 (秒) を決定します。 + 添え木の使用に掛かる時間。 (秒単位) TIempo, en segundos, requerido para aplicar una férula. Время, необходимое для наложения шины (в секундах). Czas w sekundach potrzebny na aplikację szyny. @@ -423,7 +423,7 @@ Définit le temps nécessaire à la mise en housse d'un corps (en secondes). Zeit in Sekunden, die benötigt wird, um einen Leichensack aufzutragen. Tempo in secondi richiesto per mettere un deceduto in una sacca per corpi. - 遺体袋の使用に掛かる時間 (秒) を決定します。 + 遺体袋の使用に掛かる時間。 (秒単位) Tiempo, en segundos, requerido para poner a un paciente en una bolsa para cuerpos. Время, необходимое для того чтобы упаковать труп в мешок (в секундах). Czas w sekundach potrzebny na spakowanie ciała do worka na ciało. @@ -447,7 +447,7 @@ Durée, en secondes, requise pour creuser une tombe pour un corps. Zeit (in Sekunden), die benötigt wird, um ein Grab für einen Leichnam auszuheben. Tempo in secondi richiesto per seppellire un morto. - 遺体の墓を掘るのに掛かる時間 (秒) を決定します。 + 遺体の墓を掘るのに掛かる時間。 (秒単位) Время в секундах, необходимое для того, чтобы выкопать могилу для тела. @@ -500,7 +500,7 @@ Controls where epinephrine can be used. - アドレナリンが使える場所を決定します。 + アドレナリンが使える場所を制御します。 Définit les lieux où l'usage d'épinéphrine est autorisé. Контролирует, где можно использовать Адреналин. Controla onde Epinefrina pode ser utilizada. @@ -566,7 +566,7 @@ Controls where a PAK can be used. - PAKが使える場所を決定します。 + PAKが使える場所を制御します。 Définit les lieux où l'usage de la trousse sanitaire est autorisé. Контролирует, где можно использовать Аптечку. Controla onde o KPS pode ser utilizado. @@ -598,7 +598,7 @@ Controls whether a PAK should be consumed after use. - PAKの使用後に消費するかどうかを決定します。 + PAKの使用後に消費するかどうかを制御します。 Définit si la trousse sanitaire doit être à usage unique. Контролирует, следует ли израсходовать Аптечку после использования. Controla se o KPS deve ser descartado/consumido após o uso. @@ -724,7 +724,7 @@ Controls where a surgical kit can be used. - 手術キットが使える場所を決定します。 + 手術キットが使える場所を制御します。 Définit les lieux où l'usage de la trousse chirurgicale est autorisé. Контролирует, где можно использовать Хирургический набор Controle onde o Kit Cirúrgico pode ser utilizado. @@ -809,7 +809,7 @@ Time, in seconds, required to stitch a single wound. Définit le temps nécessaire à la suture d'une plaie (en secondes). - 縫合に掛かる時間 (秒) を決定します。 + 縫合に掛かる時間。 (秒単位) Tiempo, en segundos, requerido para suturar una única herida. Время, необходимое для зашивания одной раны (в секундах). Czas w sekundach potrzebny na zaszycie pojedyńczej rany. @@ -851,7 +851,7 @@ Allow Unconscious Body Bag Housse mortuaire - Autoriser patients inconscients - 気絶者を遺体袋に + 無意識者の遺体袋への収容許可 Permitir bolsa para cuerpos inconsciente Разрешить упаковывать пациентов без сознания в мешки для трупов Nieprzytomni w worku na ciało @@ -863,7 +863,7 @@ Enables placing an unconscious patient in a body bag. Active la possibilité de placer des patients inconscients dans les housses mortuaires.\nAttention : le cas échéant cela provoquera la mort du patient. - 無意識状態のプレイヤーを遺体袋へ入れられるかどうかを決定します。 + 無意識状態のプレイヤーを遺体袋へ入れることが出来る様にします。 Permitir colocar a un paciente inconsciente en una bolsa para cuerpos. Разрешает упаковывать пациентов без сознания в мешки для трупов. Zezwalaj na pakowanie nieprzytomnych osób do worka na ciało. @@ -969,7 +969,7 @@ Controls where IV transfusions can be performed. - IV 輸液を行える場所を決定できます。 + IV 輸液を行える場所を制御します。 Controla dónde pueden ser realizadas las transfusiones IV. Définit les lieux où la pose de perfusions est autorisée. Определяет к каким частям тела разрешено применять пакеты внутренного переливания. @@ -997,7 +997,7 @@ Controls whether vanilla medical items are converted to ACE Medical items, removed only, or ignored. Legt fest, ob Standard Medic-Equipment in ACE-Equipment umgewandelt oder entfernt wird - ゲーム標準の医療アイテムをACE医療アイテムへ変換するか、削除するか、そのままにするかを決定します。 + ゲーム標準の医療アイテムをACE医療アイテムへ変換するか、削除するか、そのままにするかを制御します。 Détermine si les objets médicaux vanilla sont convertis en objets médicaux ACE, s'ils sont simplement retirés, ou s'ils sont ignorés. Определяет, что делать с ванильными медикаментами: преобразовать в медикаменты ACE, удалить или проигнорировать. Controla se itens médicos vanilla serão convertidos para itens do ACE, removidos ou ignorados. @@ -1105,7 +1105,7 @@ Controls the lifetime of litter objects, in seconds. -1 is forever. - 廃棄物の寿命を秒で決定できます。-1 にすると恒久的になります。 + 廃棄物の寿命を秒単位で制御します。-1 にすると恒久的になります。 Définit la durée d'affichage des détritus, en secondes. Durée illimitée : -1. Управляет временем жизни объектов мусора в секундах. -1 означает Навсегда. Controla o tempo de vida de objetos de lixo criados em segundos. -1 é para sempre. @@ -1263,7 +1263,7 @@ Time, in seconds, required to perform CPR on a patient. Définit le temps nécessaire à la mise en œuvre d'une RCP (en secondes). Tempo in secondi richiesto per effettuare RCP su un paziente. - 心肺蘇生(CPR)に掛かる時間 (秒) を決定します。 + 心肺蘇生(CPR)に掛かる時間。 (秒単位) Tiempo, en segundos, requerido para realizar RCP en un paciente. Время, необходимое для проведения сердечно-лёгочной реанимации (СЛР) (в секундах). Czas w sekundach jaki jest potrzebny do wykonania CPR na pacjencie. @@ -4957,7 +4957,7 @@ 붕대가 상처를 치료하는 데 얼마나 효과적으로 지속되는지 결정합니다. Défini l'efficacité des bandages à refermer des plaies. Determina quanto i bendaggi sono efficaci nel chiudere le ferite. - 包帯が傷をふさぐのにどれだけ効果的かを決定します。 + 包帯が傷をふさぐのにどれだけ効果的かを定義します。 Определяет, насколько эффективны бинты при закрытии ран. diff --git a/addons/microdagr/stringtable.xml b/addons/microdagr/stringtable.xml index c8e0b16d34..786cb15b95 100644 --- a/addons/microdagr/stringtable.xml +++ b/addons/microdagr/stringtable.xml @@ -447,7 +447,7 @@ Mennyi térképadatot tartalmaz a MicroDAGR Сколько данных должно отображаться на карте MicroDAGR Quanti dati cartografici sono mostrati sulla mappa del MicroDAGR - MicroDAGR で表示する地図情報を決定します + MicroDAGR で表示される地図の情報量 얼마나 많은 데이터를 마이크로DAGR가 보여주는지를 결정합니다 有多少地图数据会显示在微型军用 GPS 接收器 有多少地圖數據會顯示在微型軍用GPS接收器 @@ -519,7 +519,7 @@ Controls how precise the waypointdistance can be displayed Legt die Genauigkeit der Entfernung von Wegpunkten fest Controlla quanto è precisa la distanza indicata dal waypoint - 表示されるウェイポイントの精度を設定します + ウェイポイント距離の表示精度を制御します。 Kontroluje jak precyzyjnie może być wyświetlany dystans PT Управляет точностью отображения расстояний маршрутных точек Controla o quão preciso pode exibir o waypoint de distância @@ -589,7 +589,7 @@ Meghatárroza a MicroDAGR objektumok térképének tartalmát. A kevesebb adat korlátozza a térképnézeti módot az eszközön. Контролирует, сколько данных должно отображаться на карте устройств MicroDAGR. Ограничивает объем отображаемых данных на миникарте. Controlla quanti dati cartografici vengono caricati sui MicroDAGR. Meno dati permetteranno la visualizzazione di meno informazioni sulla minimappa. - アイテム上で表示されるデータ量を決定します。設定を減らすと地図上での情報が少なくなります。 + microDAGRの項目に入力されるデータの量を制御します。データを少なくすると、マップビューが制限され、ミニマップの表示量が少なくなります。 마이크로DAGR에 얼마나 많은 데이터가 들어있는지 정합니다. 적을 수록 지도상에도 비춰지는게 적어집니다. 设定有多少数据会显示在微型军用 GPS 接收器上。这些资料的多寡会反映在迷你地图的显示上。 設定有多少數據會顯示在微型軍用GPS接收器上。這些資料的多寡會反映在迷你地圖的顯示上。 diff --git a/addons/pylons/stringtable.xml b/addons/pylons/stringtable.xml index d431910d34..1021a2fc15 100644 --- a/addons/pylons/stringtable.xml +++ b/addons/pylons/stringtable.xml @@ -289,7 +289,7 @@ The time it takes to replace each pylon (in seconds). - 各パイロンの置き換えに掛かる時間を設定します。(秒) + 各パイロンの置き換えに掛かる時間。 (秒単位) Il tempo che impiega ogni pilone ad essere sostituito (in secondi). 每個派龍架需花多久時間進行整補(單位為秒) 每个挂架需花多久时间进行整装(单位为秒)。 diff --git a/addons/rearm/stringtable.xml b/addons/rearm/stringtable.xml index 157be6eec2..b8dfd37f77 100644 --- a/addons/rearm/stringtable.xml +++ b/addons/rearm/stringtable.xml @@ -698,7 +698,7 @@ Distance maximale à laquelle un véhicule peut être réarmé. Die maximale Distanz, über die ein Fahrzeug Aufmunitioniert werden kann A distância máxima que um veículo pode ser rearmado/municiado. - 車両から再武装できる範囲を決定します。 + 車両から再武装できる最大距離 與載具之最大可整裝距離 车辆可重新整装的最大距离 La distanza massima da cui un veicolo può essere riarmato diff --git a/addons/refuel/stringtable.xml b/addons/refuel/stringtable.xml index 41a8c5254e..909a3f4587 100644 --- a/addons/refuel/stringtable.xml +++ b/addons/refuel/stringtable.xml @@ -578,7 +578,7 @@ Время в секундах, которое занимает взаимодействие со шлангом. Cuanto tiempo en segundos tardan las interacciones de repostado. Durata delle interazioni in secondi. - 燃料補給に掛かる時間 (秒) + 燃料補給に掛かる時間。 (秒単位) Jak długo powinna trwać interakcja tankowania w sekundach. Wie lange Auftank-Interaktionen in Sekunden dauern. Durée des interactions de ravitaillement en secondes. diff --git a/addons/repair/stringtable.xml b/addons/repair/stringtable.xml index 4d2f84eea5..775202ed3a 100644 --- a/addons/repair/stringtable.xml +++ b/addons/repair/stringtable.xml @@ -2145,7 +2145,7 @@ Time in seconds to complete a repair. - 修理完了までの所要時間 + 修理完了までの所要時間 (秒単位) Czas w sekundach do przeprowadzenia naprawy Tempo in secondi richiesto per completare una riparazione. Zeit in Sekunden, um eine Reparatur abzuschließen. @@ -2165,7 +2165,7 @@ Time in seconds to remove or change a wheel. - タイヤの取り外しまたは交換に掛かる時間。 + タイヤの取り外しまたは交換に掛かる時間。 (秒単位) Czas w sekundach do zdjęcia lub zmienienia koła. Tempo in secondi richiesto per rimuovere o sostituire una ruota. Zeit in Sekunden, um ein Rad zu entfernen oder zu wechseln. diff --git a/addons/spectator/stringtable.xml b/addons/spectator/stringtable.xml index 4bd6817591..7f55998d9f 100644 --- a/addons/spectator/stringtable.xml +++ b/addons/spectator/stringtable.xml @@ -224,7 +224,7 @@ Maximum distance the follow camera can be from the target Maximale Distanz in welcher die Kamera dem Ziel folgen kann. Максимальная дистанция от камеры слежения до цели - カメラが目標へ追随できる最大距離を決定できます。 + カメラが目標へ追随できる最大距離 A distância máxima que a câmera de acompanhamento pode estar do alvo. 攝影機能追隨目標的最大距離 摄影机能追随目标的最大距离 diff --git a/addons/trenches/stringtable.xml b/addons/trenches/stringtable.xml index 6e029cb4c0..4b47ee6a14 100644 --- a/addons/trenches/stringtable.xml +++ b/addons/trenches/stringtable.xml @@ -282,7 +282,7 @@ Time, in seconds, required to dig a small trench. Время в секундах, необходимое для рытья малого окопа Définit le temps nécessaire au déploiement des petites tranchées (en secondes). - 小型塹壕の造成が完了するまで掛かる時間 (秒) を設定できます。 + 小型塹壕の造成が完了するまで掛かる時間。 (秒単位) Tiempo, en segundos, requerido para cavar una trinchera pequeña. Czas, w sekundach wymagany do wykopania małego okopu Zeit in Sekunden, um einen kleinen Graben auszuheben. @@ -306,7 +306,7 @@ Time, in seconds, required to remove a small trench. Время в секундах, необходимое для удаления малого окопа Définit le temps nécessaire pour le retrait des petites tranchées (en secondes). - 小型塹壕の撤去が完了するまで掛かる時間 (秒) を設定できます。 + 小型塹壕の撤去が完了するまで掛かる時間。 (秒単位) Tiempo, en segundos, requerido para eliminar una trinchera pequeña. Czas, w sekundach wymagany do usunięcia małego okopu Zeit in Sekunden, um einen kleinen Graben aufzuschütten. @@ -330,7 +330,7 @@ Time, in seconds, required to dig a big trench. Время в секундах, необходимое для рытья большого окопа Définit le temps nécessaire au déploiement des grandes tranchées (en secondes). - 大型塹壕の造成が完了するまで掛かる時間 (秒) を設定できます。 + 大型塹壕の造成が完了するまで掛かる時間。 (秒単位) Tiempo, en segundos, requerido para cavar una trinchera grande Czas, w sekundach wymagany do wykopania dużego okopu Zeit in Sekunden, um einen großen Graben auszuheben. @@ -354,7 +354,7 @@ Time, in seconds, required to remove a big trench. Время в секундах, необходимое для удаления большого окопа Définit le temps nécessaire pour le retrait des grandes tranchées (en secondes). - 大型塹壕の撤去が完了するまで掛かる時間 (秒) を設定できます。 + 大型塹壕の撤去が完了するまで掛かる時間。 (秒単位) Tiempo, en segundos, requerido para eliminar una trinchera grande Czas, w sekundach wymagany do usunięcia dużego okopu Zeit in Sekunden, um einen großen Graben aufzuschütten. diff --git a/addons/vehiclelock/stringtable.xml b/addons/vehiclelock/stringtable.xml index 55600489e8..7cfa58d07a 100644 --- a/addons/vehiclelock/stringtable.xml +++ b/addons/vehiclelock/stringtable.xml @@ -365,7 +365,7 @@ Alapértelmezett idő a zárfeltöréshez (másodpercben). Alapértelmezett: 10 Время для взлома замка отмычкой (в секундах). По умолчанию: 10 Tempo Default richiesto per forzare serrature (in secondi). Predefinito: 10 - Lockpickを使った作業の所要時間の標準設定。(秒) デフォルト: 10 + Lockpickを使った作業の所要時間の標準設定。 (秒単位) デフォルト: 10 해정을 위해 들이는 기본시간입니다(초 단위). 기본설정: 10 开锁时间(秒)。预设:10 開鎖時間(秒)。預設:10 diff --git a/addons/viewdistance/stringtable.xml b/addons/viewdistance/stringtable.xml index 4404d0efe8..eb7ed94838 100644 --- a/addons/viewdistance/stringtable.xml +++ b/addons/viewdistance/stringtable.xml @@ -96,7 +96,7 @@ Korlátozza, mekkora látótávolságot állíthatnak be a kliensek (maximum 10000-ig) Устанавливает предел дальности, насколько клиенты могут увеличить свою дальность видимости (до 10000) Imposta il limite massimo a cui i client possono alzare la propria distanza visiva (massimo 10000) - 各クライアントが設定できる視界距離の上限を設定します。(最大 10000) + 各クライアントが設定できる視界距離の上限 (最大 10000) 클라이언트가 최대 얼마나 멀리 볼 수 있는지 제한을 둡니다 (10000 까지 가능) 设定客户端最高可显示的视距(最高至10000) 設定客戶端最高可顯示的視野距離 (最高至10000) diff --git a/addons/volume/stringtable.xml b/addons/volume/stringtable.xml index ea0eabf4eb..feecb28b10 100644 --- a/addons/volume/stringtable.xml +++ b/addons/volume/stringtable.xml @@ -168,7 +168,7 @@ Time it takes (in seconds) for the sound to fade in/out. Zeit, die es benötigt (in Sekunden), für das Geräusch, ein- bzw. auszublenden. - 音がフェードイン/アウトするまでの時間 (秒) を決定します。 + 音がフェードイン/アウトするまでの時間。 (秒単位) Temps nécessaire (en secondes) aux sons pour être réduits/rétablis. 페이드 인/아웃 되는데 걸리는 시간(초) 设定音量淡出/入时所需的秒数。 diff --git a/addons/weather/stringtable.xml b/addons/weather/stringtable.xml index 55306f4a01..bb815b8d06 100644 --- a/addons/weather/stringtable.xml +++ b/addons/weather/stringtable.xml @@ -130,7 +130,7 @@ Megadja az intervallumot (másodpercben) az időjárás-frissítések között Определяет интервал (в секундах) между обновлениями погоды Definisce l'intervallo (in secondi) tra aggiornamenti del meteo - 天候を更新する間隔を定義します。(秒) + 天候を更新する間隔 (秒) を定義します 기후를 갱신하는 간격을 초 단위로 정합니다. 设定天气更新的时间间隔(秒) 設定天氣更新的時間間隔(秒) From 872d460e6d8053d565eb0767e6df50ea4c9f1595 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Fri, 26 Apr 2024 17:35:30 -0500 Subject: [PATCH 022/290] Tools - Add missing includes for p3ds (#9974) * Tools - Add missing includes for p3ds * Cleanup vn? * Update project.toml * Update tools\.vscode --- .hemtt/project.toml | 2 +- .../a3/data_f/penetration/hard_ground.rvmat | 9 ++ include/a3/ui_f/hpp/defineResincl.inc | 1 + include/a3/weapons_f/acc/data/optics.rvmat | 82 ++++++++++++++++++ .../a3/weapons_f/acc/data/scope_view3_ca.paa | Bin 0 -> 245175 bytes .../a3/weapons_f/acc/data/scope_view_ca.paa | Bin 0 -> 89946 bytes include/a3/weapons_f/data/nightvisiontl.paa | Bin 0 -> 119195 bytes .../reticle/data/optics_bg_dirt_ca.paa | Bin 0 -> 316874 bytes .../OPFOR/vests/items/vn_mine_satchel_02.p3d | 0 .../supply/a2_ammo/macv/vn_us_30cal.p3d | 0 .../supply/a2_ammo/macv/vn_us_can_30.p3d | 0 .../supply/a2_ammo/pavn/vn_pavn_50_can.p3d | 0 .../furniture/vn_us_fort_common_crate_01.p3d | 0 .../mortar_m2/vn_prop_60mm_crate_01.p3d | 0 .../mortar_m29/vn_prop_81mm_crate_02.p3d | 0 .../mortar_m2/vn_shell_60mm_m302_wp_ammo.p3d | 0 .../mortar_m2/vn_shell_60mm_m49a2_he_ammo.p3d | 0 .../mortar_m2/vn_shell_60mm_m83_lume_ammo.p3d | 0 .../mortar_m29/vn_shell_81mm_m374_he_ammo.p3d | 0 .../vn_shell_82mm_d832_wp_ammo.p3d | 0 .../vn_shell_82mm_o832d_he_ammo.p3d | 0 .../vn_shell_82mm_s832s_lume_ammo.p3d | 0 .../tow/vn_static_tow_mag.p3d | 0 .../mines/m112/vn_mine_m112_mag.p3d | 0 .../mines/m14/vn_mine_m14_mag.p3d | 0 .../mines/m15/vn_mine_m15_mag.p3d | 0 .../mines/m16/vn_mine_m16_mag.p3d | 0 .../mines/m16/vn_mine_tripwire_m16_02.p3d | 0 .../mines/m16/vn_mine_tripwire_m16_04.p3d | 0 .../mines/m18/vn_mine_m18.p3d | 0 .../mines/m18/vn_mine_m18_x3.p3d | 0 .../mines/punji/vn_mine_punji_01_mag.p3d | 0 .../mines/punji/vn_mine_punji_02_mag.p3d | 0 .../mines/punji/vn_mine_punji_03_mag.p3d | 0 .../mines/tm57/vn_mine_tm57_mag.p3d | 0 .../tripwire_arty/vn_mine_tripwire_arty.p3d | 0 .../tripwire_f1/vn_mine_tripwire_f1_02.p3d | 0 .../tripwire_f1/vn_mine_tripwire_f1_04.p3d | 0 tools/.vscode/settings.json | 3 +- tools/.vscode/tasks.json | 21 ++++- 40 files changed, 112 insertions(+), 6 deletions(-) create mode 100644 include/a3/data_f/penetration/hard_ground.rvmat create mode 100644 include/a3/weapons_f/acc/data/optics.rvmat create mode 100644 include/a3/weapons_f/acc/data/scope_view3_ca.paa create mode 100644 include/a3/weapons_f/acc/data/scope_view_ca.paa create mode 100644 include/a3/weapons_f/data/nightvisiontl.paa create mode 100644 include/a3/weapons_f/reticle/data/optics_bg_dirt_ca.paa delete mode 100644 include/vn/characters_f_vietnam/OPFOR/vests/items/vn_mine_satchel_02.p3d delete mode 100644 include/vn/objects_f_vietnam/supply/a2_ammo/macv/vn_us_30cal.p3d delete mode 100644 include/vn/objects_f_vietnam/supply/a2_ammo/macv/vn_us_can_30.p3d delete mode 100644 include/vn/objects_f_vietnam/supply/a2_ammo/pavn/vn_pavn_50_can.p3d delete mode 100644 include/vn/objects_f_vietnam/usarmy/furniture/vn_us_fort_common_crate_01.p3d delete mode 100644 include/vn/objects_f_vietnam/usarmy/supply/mortar_m2/vn_prop_60mm_crate_01.p3d delete mode 100644 include/vn/objects_f_vietnam/usarmy/supply/mortar_m29/vn_prop_81mm_crate_02.p3d delete mode 100644 include/vn/static_f_vietnam/mortar_m2/vn_shell_60mm_m302_wp_ammo.p3d delete mode 100644 include/vn/static_f_vietnam/mortar_m2/vn_shell_60mm_m49a2_he_ammo.p3d delete mode 100644 include/vn/static_f_vietnam/mortar_m2/vn_shell_60mm_m83_lume_ammo.p3d delete mode 100644 include/vn/static_f_vietnam/mortar_m29/vn_shell_81mm_m374_he_ammo.p3d delete mode 100644 include/vn/static_f_vietnam/mortar_type53/vn_shell_82mm_d832_wp_ammo.p3d delete mode 100644 include/vn/static_f_vietnam/mortar_type53/vn_shell_82mm_o832d_he_ammo.p3d delete mode 100644 include/vn/static_f_vietnam/mortar_type53/vn_shell_82mm_s832s_lume_ammo.p3d delete mode 100644 include/vn/static_f_vietnam/tow/vn_static_tow_mag.p3d delete mode 100644 include/vn/weapons_f_vietnam/mines/m112/vn_mine_m112_mag.p3d delete mode 100644 include/vn/weapons_f_vietnam/mines/m14/vn_mine_m14_mag.p3d delete mode 100644 include/vn/weapons_f_vietnam/mines/m15/vn_mine_m15_mag.p3d delete mode 100644 include/vn/weapons_f_vietnam/mines/m16/vn_mine_m16_mag.p3d delete mode 100644 include/vn/weapons_f_vietnam/mines/m16/vn_mine_tripwire_m16_02.p3d delete mode 100644 include/vn/weapons_f_vietnam/mines/m16/vn_mine_tripwire_m16_04.p3d delete mode 100644 include/vn/weapons_f_vietnam/mines/m18/vn_mine_m18.p3d delete mode 100644 include/vn/weapons_f_vietnam/mines/m18/vn_mine_m18_x3.p3d delete mode 100644 include/vn/weapons_f_vietnam/mines/punji/vn_mine_punji_01_mag.p3d delete mode 100644 include/vn/weapons_f_vietnam/mines/punji/vn_mine_punji_02_mag.p3d delete mode 100644 include/vn/weapons_f_vietnam/mines/punji/vn_mine_punji_03_mag.p3d delete mode 100644 include/vn/weapons_f_vietnam/mines/tm57/vn_mine_tm57_mag.p3d delete mode 100644 include/vn/weapons_f_vietnam/mines/tripwire_arty/vn_mine_tripwire_arty.p3d delete mode 100644 include/vn/weapons_f_vietnam/mines/tripwire_f1/vn_mine_tripwire_f1_02.p3d delete mode 100644 include/vn/weapons_f_vietnam/mines/tripwire_f1/vn_mine_tripwire_f1_04.p3d diff --git a/.hemtt/project.toml b/.hemtt/project.toml index 206bf9573c..f5ed361e3e 100644 --- a/.hemtt/project.toml +++ b/.hemtt/project.toml @@ -28,7 +28,7 @@ exclude = [ "zeus/functions/fnc_zeusAttributes.sqf", ] -[hemtt.launch] +[hemtt.launch.default] workshop = [ "450814997", # CBA_A3 ] diff --git a/include/a3/data_f/penetration/hard_ground.rvmat b/include/a3/data_f/penetration/hard_ground.rvmat new file mode 100644 index 0000000000..1c4d7f82b0 --- /dev/null +++ b/include/a3/data_f/penetration/hard_ground.rvmat @@ -0,0 +1,9 @@ +surfaceInfo="A3\data_f\Penetration\hard_ground.bisurf"; +ambient[]={0.48699999,0.32800001,0.249,1}; +diffuse[]={0.48699999,0.32800001,0.249,1}; +forcedDiffuse[]={0,0,0,0}; +emmisive[]={0,0,0,1}; +specular[]={0,0,0,1}; +specularPower=1; +PixelShaderID="Normal"; +VertexShaderID="Basic"; diff --git a/include/a3/ui_f/hpp/defineResincl.inc b/include/a3/ui_f/hpp/defineResincl.inc index 2f513642bc..df589bde2d 100644 --- a/include/a3/ui_f/hpp/defineResincl.inc +++ b/include/a3/ui_f/hpp/defineResincl.inc @@ -1380,6 +1380,7 @@ enum #define IDC_OPTIONS_PP_DOF_SLIDER 1317 #define IDC_OPTIONS_PP_DOF_VALUE 1318 #define IDC_OPTIONS_PP_CAUSTICS 1319 +#define IDC_OPTIONS_PP_HAZE 1329 #define IDC_OPTIONS_PP_SHARPEN_SLIDER 1320 #define IDC_OPTIONS_PP_SHARPEN_VALUE 1321 #define IDC_OPTIONS_PP_COLOR_CORRECTIONS 1322 diff --git a/include/a3/weapons_f/acc/data/optics.rvmat b/include/a3/weapons_f/acc/data/optics.rvmat new file mode 100644 index 0000000000..1183f3e16d --- /dev/null +++ b/include/a3/weapons_f/acc/data/optics.rvmat @@ -0,0 +1,82 @@ +class StageTI +{ + texture="a3\data_f\default_ti_ca.paa"; +}; +ambient[]={0,0,0,1}; +diffuse[]={0,0,0,1}; +forcedDiffuse[]={0,0,0,1}; +emmisive[]={0,0,0,1}; +specular[]={1,1,1,1}; +specularPower=500; +PixelShaderID="Super"; +VertexShaderID="Super"; +class Stage1 +{ + texture="a3\weapons_f\acc\data\optics_nohq.paa"; + uvSource="tex1"; + class uvTransform + { + aside[]={1,0,0}; + up[]={0,1,0}; + dir[]={0,0,0}; + pos[]={0,0,0}; + }; +}; +class Stage2 +{ + texture="#(argb,8,8,3)color(0.5,0.5,0.5,0.5,DT)"; + uvSource="tex"; + class uvTransform + { + aside[]={1,0,0}; + up[]={0,1,0}; + dir[]={0,0,0}; + pos[]={0,0,0}; + }; +}; +class Stage3 +{ + texture="#(argb,8,8,3)color(0,0,0,0.0,MC)"; + uvSource="tex"; + class uvTransform + { + aside[]={1,0,0}; + up[]={0,1,0}; + dir[]={0,0,0}; + pos[]={0,0,0}; + }; +}; +class Stage4 +{ + texture="a3\weapons_f\acc\data\optics_as.paa"; + uvSource="tex1"; + class uvTransform + { + aside[]={1,0,0}; + up[]={0,1,0}; + dir[]={0,0,0}; + pos[]={0,0,0}; + }; +}; +class Stage5 +{ + texture="#(argb,8,8,3)color(1,1,1,0.0,SMDI)"; + uvSource="tex1"; + class uvTransform + { + aside[]={1,0,0}; + up[]={0,1,0}; + dir[]={0,0,0}; + pos[]={0,0,0}; + }; +}; +class Stage6 +{ + texture="#(ai,64,64,1)fresnel(0.915,0.38)"; + uvSource="none"; +}; +class Stage7 +{ + texture="a3\data_f\env_land_optic_co.paa"; + uvSource="none"; +}; diff --git a/include/a3/weapons_f/acc/data/scope_view3_ca.paa b/include/a3/weapons_f/acc/data/scope_view3_ca.paa new file mode 100644 index 0000000000000000000000000000000000000000..d7ef93da4991a77c54bb8240794e0069e1fb1fad GIT binary patch literal 245175 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%0AOg`{TqPo*Wjq9p(1I6i9f!?&u)!gapb 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

{H=OuD0> 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 literal 0 HcmV?d00001 diff --git a/include/a3/weapons_f/acc/data/scope_view_ca.paa b/include/a3/weapons_f/acc/data/scope_view_ca.paa new file mode 100644 index 0000000000000000000000000000000000000000..a8dc6b370aaf028749a504622059b1f1306bbb18 GIT binary patch literal 89946 zcmeFZX?zq_7CwA$Rd@EKIt%F#mUI%*YXSk;tE;LLM~w<*kkKdvQJfhU!XWNrbyszw zjvEp-5eY7!xFE6`5qha4?#dWtP-Ib%eGNM#bgJK{f;#j6e|SH?AKw1`D5{grt#i*k z%X6N4ZkyxRUhA7!b?q%a6Cs3B`b6*hTHiS1eH<_2{k6Uuuj&0gerCMC`I>8Pl5nr$ z-~Nq+^gU0=j$}&qR#S5LHcC3{D7i3&67L-ppZI@$JxNS;8%a()PTYhP{`S#>{QrMz zsN(;-dPwvV{SnesGFBkf^G5N6?ICLY&K8%KtVw5ID*VPv($m?y3zI@7A!PpVvX)-C z?c#;8F)u@=?`#?5I%0gkL zD6FZ!-yx5-g+|em>XH*KUhw#Ziy4XaB@TUb>_U3ty-q>6eC`f<_hq{s@}1SLnK!-1 z9w6PPY%#$p6H{l`y*JEQVzP%=_Tn+}di~uFfjNJqj!uVs2dCuLU&dt49q`lM$wUS& z+3!?LYsS?(_=G#`YsQsf(&o;t`t@_aPauvSbC#ctIphSkK$ONv^PuNoPwvAs?-;UsN(8mOMP<_pr4_hhquC3G$cFlQhc2AkKbblM;+efN>k!GQ zU8+nS0lJ;I1#FjK$Kn{1Lr_OaonEl^OVOK4MV)lII(Zydr^#u5zKPgdN%mNhsrz(R$GDG{IAh6%!eZyMG*^fg`x`}%;!7@FSSB>) zE^+zOh$|xXu%7r0I^o934S(p7FYmq0=K~&Z#dV|P?qdJY?T%2WSRYzc4Yl6qjtO+b z?CB@$F~KH0GGd*R_tLJ@q{Suh7mwNk!n9*9|6^~aXCAW)-ZOh_;Q(xeoZMMwzS|Ly zj{jIB`<-54t4$W1y7%C}J%YIR^SZ?84qe>S=8*~A5h80`0dZT) zTP#;XfuAq)1f;fRTtY85r`jWQ(?YC*VETB0C&U-N#*^j(rz|!PbVhjNQzAaE;E%J4 z{8G#?H+P6k8MbDelNXyu!bR~wUYac0LZTy}9{hKD;y7o79Np@P(-YencR=jiJvq^- zi)Vi=3;PZh_XKy@<;js0&n_cnr z9VK^+&YEm?#QD1g#vKwTyWP5i#{>jCFd+3l8bauXH~~X2oxJf7q+Jn!@rY}l z#`}+(AhNc^CX29(uiwI&{pSPtV?^8)!k_H@q}O|n{u`rp?#M_TkFXXzx3`YYaE60N z>JrO)lRK0X51l)C&`R4c5hAA3Ka-N#ch_U3j{SgDIq; zCi9zptMIVKT(3Bs>`26yj0Q554HUh-;DM6U0#>txYfC8y3CgGd-omL?B#%fjT5 z?znPGMV8-iu0#gO0Rjp1-YUeZYRoP0XH4dq+i{tHH!iRJ1DBODE*qXL_N(xUGzNk7 zt2gnJZR?@=zcr_;Fc`7Kg&_Sd39io-L`j$3_(k;Nd4yEnIu;*ecHmAWIEM_sBjrt)Tk)S@StcR8yZ6^7`Bl z=K~4lCM6fHb4JEyC3?IHH-)w!N>et0t6o<>&mqvv1W$}FRFKN>Kn-FgaCLbVA--58SVA_0{+5^IC4?qd4 zRH$Q9lSh|6e+>@&{RhU%{~Uq?ANmsSPj1Ubh&uaow#3+DQh7*XJG-Y>&fCsW?dstn zsf=%f3a;i-$WuiPGr{NaA1=?6v(RN-@VVl z_t@gG5$mQKGw$rJo-}LM2pXg2gBPlI%-cUA8Sv}$Znb3gG>0M_{~l>g*!N|H9EN{( zyod1h$r2cH%X3)rxBrQmy?h^5?Ab|1C>4qS&rNPooN=|9HWJF1IvP{F*<*`|&Zzg= zlBTpo{E#1rF)H#r5z(1l%=;0Yi!)VsNGKPCzNxm5->C=kQi@_;2QM%=N#yEzPFb)i zV>W!KJLEBpIivdedCu4v#*}{V4HKLqNnwc_2#QtHvYmm?k{DZ$G!FKezyQygX*qJ9 z84op4&P=?8uZhG==Z%fA#uAhl;TM%v^hM(W)#6=w7@rpwMpj_EV&_F0fnN8QU zICauD1!D$CpF|H&SxbUCqU8~Xl3+@&=6S)Ud)Ku%_*N#7A^&M{g-6rOf>o>P?cPt# zX>3`KS4&Q=Yb@nr$Kn`l-?{UZfC9f2gK z!xczMW^AI=vJ?R)+0&z@ro6hQ+K7FLT>ZMaszXT0O-jpj1$+f5u=t{kVp&Aab7oC3 zKe7bahYs&Mzrz&~eKt>A9PgSBm!CWw_A%WDCCN8=BGR*ya9Mo6N0Hu@nX-_CUn1rL zk*z{(Xd!2w|jV!75pq2=GonuaqajAINJVX?EEe{5AgUBQ)BTx z`H@rZ!>pmZUwXt5@58Q1havR74$44WyLd7*)H6mFQ68JBv#L2WBNu#YWyvVyg-(|c zS+U9)>$U_pnOuT+?0W>Nz3srMq5%-e=gW&?A_6bnJf{hT2U+Q_qpKVN{-wXe6rQ>j zm&a~|f7~M=qtp(?46E%PUS#=tKHojFL=`sPs=&-8`jvNln+dLc}I+{JMTV zVzDiL)rM^?aKL0nPIN_urX4NLP@qVWzi(Mun86FB@lm;iHudxHg1u+7d8jbvx_Ld6 zIwvPH%dK}Ny(f`EqKX9Nrd>#s$W<|)T}Y}SgXN^9*Zx!*_Dw7f`(~ssdh?eXBoobK zTdH3fsrV9^h3ScFU0z>yQB1MFl$B<(5XI>i5^TCOyU7ugA?ExVm(tiT9mSw%=Zr9r z2PYQ#&v!?W7?uFWPpU{yoWU`z>iyo3loe#hqexwRAJEIYWr5(PdA1%A(IC2IMQ>c$ zxe;pJ_bEn`j&H+yGUxZs*T!K*yN=bdWw2p`3mCj8WRLYJG|Liak(fW$FgB`?%#VtN z(mbn0d#rEeV@2cap+}1X;_PBaKtc3d9lHuqoTi(#>s%2;Y8wz>+!-6js5@FdTskTy*izc+>(l-|$U8iDXh)e%CNS@(^!l+S*@r~tPA6w-Aq-FOV6K(!arh4L1ZU;hzijW;u)6Gng+-466 zmP&I+HOjDlsUBS|&1|NQu#}5BbId^KvGN9oC*VW)2}t)#9-TaPg9iZP`8yGxb@8=_ zq3(6hWw`;!wO8Oqy7J=&d~$EAN0d(dVEE*jJ@})p6LsnLI$~;m`!!nqNG_p@IrLJq zJz%}e_VsVEuLs#PpHWqAYZ@Z(E}gPhjv#sAgsQG{6N%OaJm0#Ty7m=@EYRv zc8^yWTOtSSI$MrpDmmp?9X$^R$xkT?1+Yjt06xT&VeZ(mL!V#f4aDs+S{@1wmP5ro z{+*>gep(UR44DHlq3{mFGf>V+6G>^Ty)-OI6+OX%G}bA%n-b}gnX|fHbA}{(U{6cb zAxliUxnIpZC_ERXqSP;S2~t}z=MjSN;<)G?fcL&}MyS7i1OnfTYjM|T;NHas? zI72T1fA_|XUq6ASk9TCdBkI|oVet9dzvSe+hQ{u*lT%%B^!93PNKkWF z6UkUES@kjr(I6=v6PY#Y6~q6`|org_h-j~zNu{sM^?-VYI103k@x z#d!OTQI*3&1JV(YHNicd7GGswj#gD(IEHdk>f8SLjFF4DK9p&4%B|UIC6_=N|ELAj z_QD+?9SBcqX*xU3E|VNhhJZ)Efpd#HKjzGB zUOZd(emoEIy!8YwFB+B1V>jV)Cy&bn575Jhu)Q(;WR|0>Sf14Zx~UUsZ$KK{s83>g zW{We{IwTS<-02DhD!k$jV{KpL#X=DtFQSMsbJNz(?noG@`k36L>^5+I4J}{=QI6k?N6)_(mv@!&m;tT7dK=2w9r6I89shPdvLq{*%|JKdNUSIv+2rJP3yC=e zJ$4?^bc+z9wEKiw>Iz5B+j@FX=L;vk!&83_0ndQndCTTirb7vv=6eF(S0C~S$_sZv z%!kL}GgHRka+3=o*v&_Z;JqLYvhhnpJpp)ZKuk5I4R!@c5(91rbZI2~VZGZcK3xd0 ze!ik6lzO@3X*=J>n(2b6^Vf1L`P?R}&X~lenfvXT_pwU|Hg|ArC2}dux;zIs5Oo9< z2R84)uOZ1c$Dwr|y!}|tZs7K~`!phra{>bbyJ@C+tkjN+&$+Zq# zMi(I2IJ0oqFWEqpI?Xmic%%SoVfSD$IHPN^Juak~b|H%!s~`>j~4b*#rv9xDq-bB#FiUIQ+z3!&!!tj1;kXLx&hJ9KvO5HfsMRy)1; zQnN$umsMH0pvf8Q*DDBQF?3YVlWf)R5|!;Ot2kEmvzMAmXBXULj|Ivjk&8#B(7s#p zB-BRwkuNdy_VoZqU%k?S+8eg@t^#{ma32ip@jv51cR+2|4KfHhLtT2nVS$DUl0AIX zWHD=_)~(uS=S`+m)6|{afq71Eq{Hovur^+#tLk@_4)TlUER_fQ(JP%T6fnwVE>Zf- z60B;<3sy}unan1#VCsaH{GGd&nO@qW6#ltBGtb=N0JB5$OT-hXV3zI|`P)@TC(S(7>L} z7@B^)OigeJ;)gGCxecKpsuD6?0?$2K@8R=pe83qJ*{ng;x6Np_Z)7XL#F?F;uqlPL z?)>4xS(jhjl$MGrdV9-<;IPa22-H)-8)<$mI96FQv812_+aGz_C*}k?zhnF(OSU`w zefqftHGwOZrMyZewJ#ROouyTR1QrUgJ`wd6umloli;E!p%q0!K)SHc&*r)K)-1IWIi=^KEgIarpxG%8CJvq?PVRK*1i7^dxTWliedprfGLAZ zN&`|b3qF!xHRiVQ^BuaF%y@V;UwW*FkCe+|p1S#pR5`G%D|!3cB3ZHoKiRNrJzJAN zmvqb+0&T>-+2-ba!dhuVLt!ecV+acB);|^F0d-g5^4RsjJP~n0onc__JO=0%kUm>b z$Ifslr=6toAE}nPblYy1p7k(|0BMw11 z+EE-5?TWN#Bh)5tSql8|CNkw}RRw-~1^lEKKmjM*WdyP6BADYakRE}ej4AZ|Ss+0+ zNqu_T`LoV=Kz-*sCr^jSk-1NzxrhGj&=!(SlhZT|pTXlsIIu-hcQ^8hUA z`ANNHM4*0buLY3_cB2##lrdmVM0XJhu66Xu)qd8#84{hvR!J;nf2Sg@wiP zvPdMgugxD>;E*FlUi}AzTW>N`98;X32<57Gv^Zpv#rW$d^$CW|y(_j$^%jysgPvy^ z(|;P^Gfm8HXuo-_l}fElGSjbPJVF}OFx<*8rhzHNvSwF+M6%tAcx}m2x6nFm7&cJ? zBzObV@Vb%dLeIdGwytOfJOK6-q!T~-=|Y4N^RY|Qi`R7|frBb!vujcYFM1jHO7B|O zas3Ri6ITqHkiW$=E}aDIp@^*~lHlrzoVLXyvzmw4-y3^=PjA5@9{$FoM|Q1;?R@@H zQAotT?+1?}>oyq+G}8;c*aXGVf^F?lMWG0^Q<7$^ZFZ9O&bEhsg(4qH5$nB zZUjnlZ6Vxja29k`&MT<>)c3ZX-)A+ojU6$)u=iOfLlGmn7c$<~CYRWn%)EsxUdd)8 z^qZOSI1oECFy$?GL>rpp(X|_ju*~<2#Dx9@peU^{Qg|!23jg8I#qIB-06+Z20+|j> z`RVNLY|?;8MK9f0Sqjr^>$zZI8&39FegbbIL z#Eo@@;w8M|h>;u`o`$l;7K&I}nRNqvPf)8d>m}M)JfHHU$lGfA`NtZmD5P3~^xo32 zI?emyLkF14?m(OQI1@?fdU$(IH#7hr3 z%p>W&#c{#x``&EoZuKWkS}%9 zO(W{RcgnieO!zATTooH#NM`b6SV$e9K53I$O=h}c>ilPy=BboTVGqoF^kXZnWOK|# zeszgm7MP-pw`M+w;xbEWa0RqKmwJ$eX7bHbv5<3bE9=qzSw~00NVYViw*NI`e3%T;Hm1)vLn%ayE`+I1=i}YX*Nb^IkBL5gQ%2%zgQGQ>(yDJAzof*zN9bF%S(neCf2K&*Aw~GNMX8i^qkjQ3 z1NINv+mh%3cuE@*OYWZW2=77KFZIAF6j{E(xpn4`(XMbEx_Tsr|NFG%Yn>6{_U8~T zA6z~?OKQzyTEBP+aGF9*rla3wcO;)&z%i9=Hx30fYXmyUnVM0-m8!nqo;;VAxD;Pt z6$)~hy`-Any>B;2E_$k~dWkC%Ill+9I{FpX`lnU6w7!6u-}j0Kw(@7yc`HO?q^s%- zPZ0|Y&k$)*hV~5bQlBIQ8E5=g^_jI!8C!h*vK<>x(fi9L4T?o9yzray`)mHfI8TOz zR4z?wu$t5=j;(6QOG2Dz_c=4)a>vEWeh3lj$UETxjW=QlTE7(GVNM9r>|BGpV_S+t z5;6nx>xJpVTAUGb`m#qS`X!6n1`PK5ET7^fAtZ9im4W;T=sVea3eoH^+HoS=-oZdm zgM|~P&4&&jzq-R6=(*M930%Pm#lQ&)n`lYC_4;fpTP0h^?r?<^ESyjfyDyaQ*$8etHu&0M*r)S>0@md(DIRF`Nf$G(4Ac1G)_~xKqvq zu&Xdh)C!#7;N!*d$o)G<00l_)p2+WwZCQFQl;0`x2s-X&M8rL3JON?92Dkb4H5k=D!DxxM7^I|tTuR}^f>M^_iHZ5X z&@&v{pr)B@auhCOi|S6ejHxZ$QePU@|MI*1j*#A4FXu@#$Je&Ru6R>T{Vl$>MRu@y zDb{JrT!J_x3lDLQ!!!T%0G>2uHr_U_#oe~I;gxv}!NZ?%=1O|*X8;FN*GX1Gxq@Pb z>A95KkpeyV`UNY|17yGQ%uZQFIEh>p)9rGkoR5~vN;z7xUiIkuK> zyUu*-SW|4 z@deD(U~RAN?~xVi%(8l2dZ14dW=B)l+AwFTiqP84h$}t61uzm&1tV}5W+EErCgtqO z03wN(gAh>-Ktsmd4fWjqEbbH|e!lq)FGwHg7UoVk1Tv`#1FXRFy?UM+U-`B|&rZ(cf+3U`RCFbeJGLyLe!0 zWvY#rELspL+=^Z0DqmU70e3{Iw!wrY^cksl&BMIP1!?PBQ0?K*K>{Qa>I`YwmATnmR@Al{Ti1yC6cp{i8UA(ZDOQ7^@zSiapXnGeQ&#DEtIAV?~qOa82 ztjSDI(p)P;dg$eI)>N?Go6qholH(2`iUH7R_%_(UAeT@Xx$Rl-CnA^7CKUh4P)$I| zO)T<8x4Ocj*T`)w(VqKV@b|6=-j6mm^(T$iWQj2+F*!9U&V>tfnrJlll=D(K8h~aX z!Z2K}8l*q21ZD}S$G%1!*>?vm&t2q@9W0=*bI}3_T+rHfvqN@bkGG)dx2@88ghib& zg;GO_Gb);%iR$JWwl|uqLh==-xg38HuumnL!CDom#b0t2d6ec$N%~e z+WzSS+#Ub-Qu-(u>GMbW)wsZw$1WV4nZ4G^w6|SmJBprZboMy8tQS7LVv#pRL{i8x z4H5lvQAF7^T&IBQm6w-SIlR$BmR7-v5(e~HK-ppV@iQMnay$-&s8PP#Z-9N5S*&hZ zF(+jw=VdfY)EO4Tc&e>OU+;)-WJskHcdcP8ISGms6TSW zj&9Xxj-+!IHNsrzaICr=m37xiOJ(d>yIuC0b{wx>G~q4HUh3TqO+{ba1o;h^B3}D2 z9yPwi1}Xy!g;FUZ<|lh(#Znb{ZrgH>YVqIgN!J7*A&Hu43ulC2F0ZY%!f5oEP>LaL zK(m8%?_#{2hdm~;2Q!d%oXA#NQGb{^FWp}>!phW+zYe-v&K(N6EOh2YZa zsjgzbv^GY$bSZd6S#|=%PDHk=DdofaFdxOz9!S~pGPH??vq%`&rOoILz+|>8?RXFI zLtptI+<vQ5o)@8Zt2X7iiP+g>CWNItPkyMSLT}0CP2Kb<+pl! zojrEGhIg!Ygn(E5>jtR)Kc)e z3B)HAVEMGaqVkvKpfOebC_%bUv6ZNgJP+x|#$IbOl z>##u>|!JAUfS@k_1!NSuN?rE5qzj;mpq(iWPB>hEczI1#1QFCL+q$VEhSo z#0@$m*IMQR^2$x-QZF3cYBj52j%|pLLYojDH};Crqj6M1M1PK#Y%_ZX$)y%PXrX^Q z!lkIKj=0`8X+;sQ+9M(u2SG)7CP?54; zR4jDxQbC)Ko8aj2Tp?%PRcTous>dvqq6V%`VPY4ov%A1m=aGehnz_jHR9Vr9bf&|=+53EB#J9f!J8lC>O%Y7T^&)j(6vUHUe;t3=mYu-Tg(g|DGdk>h_0Nc5(jvdA zV(x#Z0X#&GGCqqr|6%a~3}j2sOw1U$5K95BBcRrgg~++&(LIA=?6bqUnj>IU~_87D3Z*pd=y>`)~nv z4k>g{CilE6K(GOeF_LJl7hHw;F>{K%;bq{V67|u0iXV+8EivCE6QdaJ9^F3<=1AqWsSL9 z(2;%w{b+5Vt9xa?DJ&9RiIUkr6{ZBD-=p81tbQC($;wiFJak&?Hu!Ua49l^}ic=Bu zlWObe%}#%`mgb>cjbjII`=$@?-wf*akMcn$h`4)TCJC+BT2QnR`Ahl`A84=@r?MV! zgq4DPU)#-yL#U}0t#0rNtlzUYL(mO@E2i?@d;O+ztcs&V8guDz^VAH3ZDE5`$9MKB z=MfUTN{(XtL|~3-Nvl9_X@V^f1u3J8yVh5r()7pYmtj5rJ_0VP2ZREcNnvU&%p3-L zBxn56A$cSSg6{RQF%R8kWhw=!!S0RIUVRW_W7z;OS*^sBtC4=1&&o(JD$@t2G9FlH zk11?%X6MYCKL#WVR`!QkOdsR*YcJyFmyMW1=TDrO`c4+K1{ zBx}6`k5YYr{dz%A*gQ}Q0QPpgV?@03hx4lL()3}0=!R+kBRpH-gwAo&A|hL~=aYl=T2grk?VgzCL=rLmu2~>nWO) zBZ*}p1^b8*WESfxyRIBMm){sTQj=n6{7XoV4D|+Z((=dQuMdrb;MIdHZGmM`6v=K5 z;h{Iy6bGXF+Fkx=!~ZEfP6!S0YkRpICfJMQCptZ%`p*d~(ozA;ly?-2_VwHO?NTRq zvrf@rCy+~rkzOsD#MGo5TrdlQ(w!aYyL+Wg&?HljmN0$$(>Ni44XhgXhxeg67TM0O z-<;@Ip?pq+cX;(eb*-JMXVd>i8VD+BFKjazg*lLGno^(+Z(PRZWouWNp@Yl&WRcH_B*}#&oZwHijExm z+KBS9$X+y|8QqVA&sng9jpHF;DucKALgwqDLS) z1rl4)R|CFEN7C{eQycnqq8( zA9Hxck}L@)B9wGfO-Aa`VIXUBd}39v{b6Wb5+VI(s;^J0RD+mcrERSVnHH*O4pFsd zo&@ADeOqgqgICX^-VhI27Vfvx55Y~ zw;BDQ&tNl;eE1^r{H_f~o>x!p^6+3iJ4>cAHj6zZ^{ezP1Yb0yz~}2_U7in%de%AJ z1^l5UyuaNQQMgsEh+y>k#P_yg#I{!<_{%fO{PAn?uF8f@grYR?N!ZU+(oEL$%;k<4 zvL~%=9De^gOvB<68}cO4vC$B@_jNFK6%_wPYim>g)>g?je&q@d1t-!h*SB$1M^av! zUX%g1zs}&F;XRQne$BI4Fnkl3iHlv|;ZTZfee;@P!mC&^AsPaU3?YFET0rWR+@>~du;jShle z8>1PoE6U#HRhvK(TNrHPB2MHdowS-NjUHU=FO0Iy5+7e=*QKW?dje$r^LW6I>#YgY z_oD}F1Gcu8S6H7PNZ7%Gs`nlgdqySJ1TDZNNeX-3n*M{qXo>XvuP|m=q`$UzJm(H8 zXxtJP)nlx`8<3FipDihNo!C-AfTr34@vbvgRQxuq)A|wje_z-u>hHqFz-EuI+`M)% zhBg0&M;?pQlFUx4iShXgv+#UcDb-&CeJlmTPuiC9ylOsw{uSLC~poQHps%2s2ma>R4I2XNF0WmkB zs7Gvvg$i`FcVD|PjPXL9W89AN`H}%q6f~i%o|*Z$6=LOL!nX|b7^JMa;RVBFHyIT| z=MHo^nY+&%Y|5xu^pHcY=u3KwnWua~9Ip!PTsO!d);xUNbnY-oJzZ057li{~bhyFB zBr@^dzWUx?Zo!6$+R{9sxGkz=jyVdK6wztNmF-wIZtNe@X@YS(qSBX9jYIKlx_PiA z`*CbI+R{0kOscYhOcT_Z*KxV+>c8JU=oZPLZ^ryOhz=~-A1?*{u54d7s5Gqnx57udhqyy3ed%A8@TzT;YH1*YA8_f>+@$=*;OPao z#war)A1D;y)i>E-5@t_>8a6M$Wlt+m)7ia#HW!;G=F8^}aT!Ojj}xn43p(iTCSd8I zMy#w=rEDpRP)2($N#KtwqnD0)5POe&i)e;S_1y|?)i#c)jKBMY@hu4v@xdG5q<<_>pBkJ_DBxEwndegJ=f33z149=>}pN3=4lc3 ze69Dw@^(i!y0@<;I3nV14UsJJGHh+G(XKUhYz>Nv;rX7JV#-UYnKSz6a*c#KQX;o(o@C7Fl!X~jRno=ro$fJMCNw=f3jkam1QUze0eEX(;R#+SiYY4vV&p+XAX+WsMbcSxvF&qcY`C=YagRkbaXd}+)6{(iwBHl7ZIle@z35c3c^U> zm6?XP^_37;k4pWGy$4Ylm^PK<0Wllr0ZG29GtYkrVl1aY%>5t0Kh&7P)w)>SRO&q; zO=jS(E2iE&B6ohST5q11YWiqq<^yx{R5T3?tYtwNv`YBq3vmXjN$s_M1c#1-UoG

!YB~Ub>a5G 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≀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 OHK`(fY~{)bHU9(VabVQ| literal 0 HcmV?d00001 diff --git a/include/a3/weapons_f/data/nightvisiontl.paa b/include/a3/weapons_f/data/nightvisiontl.paa new file mode 100644 index 0000000000000000000000000000000000000000..04bddf87955e74b4dc6b4e498612c7a0e3fa512c GIT binary patch literal 119195 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 Om98xY!mg?9tXPs1Pa=L#pV?6tH9meID-qa`u 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%0DTb~;Z4lM{WkiP(N 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%0DQf< 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 Date: Sat, 27 Apr 2024 00:35:57 +0200 Subject: [PATCH 023/290] Medical - Add `_createLitter` to medical events (#9959) Added `_createLitter` to medical events --- addons/medical_treatment/functions/fnc_treatment.sqf | 4 ++-- addons/medical_treatment/functions/fnc_treatmentFailure.sqf | 5 +++-- addons/medical_treatment/functions/fnc_treatmentSuccess.sqf | 2 +- docs/wiki/framework/events-framework.md | 6 +++--- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/addons/medical_treatment/functions/fnc_treatment.sqf b/addons/medical_treatment/functions/fnc_treatment.sqf index 4222d69a4b..c524fd7ebb 100644 --- a/addons/medical_treatment/functions/fnc_treatment.sqf +++ b/addons/medical_treatment/functions/fnc_treatment.sqf @@ -155,9 +155,9 @@ if (_callbackProgress isEqualTo {}) then { _callbackProgress = {true}; }; -[_medic, _patient, _bodyPart, _classname, _itemUser, _usedItem] call _callbackStart; +[_medic, _patient, _bodyPart, _classname, _itemUser, _usedItem, _createLitter] call _callbackStart; -["ace_treatmentStarted", [_medic, _patient, _bodyPart, _classname, _itemUser, _usedItem]] call CBA_fnc_localEvent; +["ace_treatmentStarted", [_medic, _patient, _bodyPart, _classname, _itemUser, _usedItem, _createLitter]] call CBA_fnc_localEvent; [ _treatmentTime, diff --git a/addons/medical_treatment/functions/fnc_treatmentFailure.sqf b/addons/medical_treatment/functions/fnc_treatmentFailure.sqf index 42323922a3..7b3278b2a5 100644 --- a/addons/medical_treatment/functions/fnc_treatmentFailure.sqf +++ b/addons/medical_treatment/functions/fnc_treatmentFailure.sqf @@ -11,6 +11,7 @@ * 3: Treatment * 4: Item User * 5: Used Item + * 6: Create Litter * * Return Value: * None @@ -19,7 +20,7 @@ */ params ["_args"]; -_args params ["_medic", "_patient", "_bodyPart", "_classname", "_itemUser", "_usedItem"]; +_args params ["_medic", "_patient", "_bodyPart", "_classname", "_itemUser", "_usedItem", "_createLitter"]; // Return used item to user (if used) if (!isNull _itemUser) then { @@ -53,4 +54,4 @@ GET_FUNCTION(_callbackFailure,configFile >> QGVAR(actions) >> _classname >> "cal _args call _callbackFailure; -["ace_treatmentFailed", [_medic, _patient, _bodyPart, _classname, _itemUser, _usedItem]] call CBA_fnc_localEvent; +["ace_treatmentFailed", [_medic, _patient, _bodyPart, _classname, _itemUser, _usedItem, _createLitter]] call CBA_fnc_localEvent; diff --git a/addons/medical_treatment/functions/fnc_treatmentSuccess.sqf b/addons/medical_treatment/functions/fnc_treatmentSuccess.sqf index a400fa98dc..0c39f7646e 100644 --- a/addons/medical_treatment/functions/fnc_treatmentSuccess.sqf +++ b/addons/medical_treatment/functions/fnc_treatmentSuccess.sqf @@ -50,4 +50,4 @@ _args call _callbackSuccess; if (_createLitter) then { _args call FUNC(createLitter); }; // Emit local event for medical API -["ace_treatmentSucceded", [_medic, _patient, _bodyPart, _classname, _itemUser, _usedItem]] call CBA_fnc_localEvent; +["ace_treatmentSucceded", [_medic, _patient, _bodyPart, _classname, _itemUser, _usedItem, _createLitter]] call CBA_fnc_localEvent; diff --git a/docs/wiki/framework/events-framework.md b/docs/wiki/framework/events-framework.md index d6d4caa849..bec6492c96 100644 --- a/docs/wiki/framework/events-framework.md +++ b/docs/wiki/framework/events-framework.md @@ -38,9 +38,9 @@ The vehicle events will also have the following local variables available `_gunn |`ace_unconscious` | [_unit, _state(BOOL)] | Global | Listen | Unit's unconscious state changed | |`ace_placedInBodyBag` | [_target, _bodyBag, _isGrave] | Global | Listen | Target placed into a bodybag Note: (Target will soon be deleted, target could be a bodybag) | |`ace_placedInGrave` | [_target, _grave] | Global | Listen | Target placed into a grave, _grave will be objNull if `Create Grave Markers` is disabled Note: (Target will soon be deleted) | -|`ace_treatmentStarted` | [_caller, _target, _selectionName, _className, _itemUser, _usedItem] | Local | Listen | Treatment action has started (local on the _caller) | -|`ace_treatmentSucceded` | [_caller, _target, _selectionName, _className, _itemUser, _usedItem] | Local | Listen | Treatment action is completed (local on the _caller) | -|`ace_treatmentFailed` | [_caller, _target, _selectionName, _className, _itemUser, _usedItem] | Local | Listen | Treatment action has been interrupted (local on the _caller) | +|`ace_treatmentStarted` | [_caller, _target, _selectionName, _className, _itemUser, _usedItem, _createLitter] | Local | Listen | Treatment action has started (local on the _caller) | +|`ace_treatmentSucceded` | [_caller, _target, _selectionName, _className, _itemUser, _usedItem, _createLitter] | Local | Listen | Treatment action is completed (local on the _caller) | +|`ace_treatmentFailed` | [_caller, _target, _selectionName, _className, _itemUser, _usedItem, _createLitter] | Local | Listen | Treatment action has been interrupted (local on the _caller) | |`ace_medical_handleUnitVitals` | [_unit, _deltaT] | Local | Listen | Vitals update ran for unit, _deltaT is the time elapsed since the previous vitals update (local to _unit) | |`ace_medical_treatment_bandaged` | [_medic, _patient, _bodyPart, _className, _itemUser, _usedItem, _createLitter, _bandageEffectiveness] | Local | Listen | _medic has bandaged _patient, the array can be modified to change treatment parameters (local to _medic) | From 3b806295f75e1a1cc97c82b6728d797e3878d863 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sun, 28 Apr 2024 18:02:50 +0200 Subject: [PATCH 024/290] Hearing - Use class EH instead of extended EH (#9986) Use class EH instead of extended EH --- addons/hearing/CfgEventHandlers.hpp | 10 +--------- addons/hearing/XEH_postInit.sqf | 10 ++++++++++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/addons/hearing/CfgEventHandlers.hpp b/addons/hearing/CfgEventHandlers.hpp index 310be3675b..8143e2ce0d 100644 --- a/addons/hearing/CfgEventHandlers.hpp +++ b/addons/hearing/CfgEventHandlers.hpp @@ -13,15 +13,7 @@ class Extended_PreInit_EventHandlers { class Extended_PostInit_EventHandlers { class ADDON { - clientinit = QUOTE(call COMPILE_SCRIPT(XEH_postInit)); - }; -}; - -class Extended_Init_EventHandlers { - class CAManBase { - class GVAR(AddEarPlugs) { - serverInit = QUOTE(_this call FUNC(addEarPlugs)); - }; + init = QUOTE(call COMPILE_SCRIPT(XEH_postInit)); }; }; diff --git a/addons/hearing/XEH_postInit.sqf b/addons/hearing/XEH_postInit.sqf index f8f5c2938f..e6f328ad78 100644 --- a/addons/hearing/XEH_postInit.sqf +++ b/addons/hearing/XEH_postInit.sqf @@ -1,5 +1,15 @@ #include "script_component.hpp" +if (isServer) then { + ["CBA_settingsInitialized", { + TRACE_1("settingInit - server",GVAR(EnableCombatDeafness)); + // Only install event handler if combat deafness is enabled + if (!GVAR(EnableCombatDeafness)) exitWith {}; + + ["CAManBase", "Init", LINKFUNC(addEarPlugs), true, [], true] call CBA_fnc_addClassEventHandler; + }] call CBA_fnc_addEventHandler; +}; + if (!hasInterface) exitWith {}; #include "initKeybinds.inc.sqf" From 6e32fc1144ddfcdd51857cc09e88946031c64059 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sun, 28 Apr 2024 18:04:56 +0200 Subject: [PATCH 025/290] Hearing - Add earplugs only if not present (#9987) Only add earplugs if not present --- addons/hearing/functions/fnc_addEarPlugs.sqf | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/addons/hearing/functions/fnc_addEarPlugs.sqf b/addons/hearing/functions/fnc_addEarPlugs.sqf index 035d82956f..fdbcfbc621 100644 --- a/addons/hearing/functions/fnc_addEarPlugs.sqf +++ b/addons/hearing/functions/fnc_addEarPlugs.sqf @@ -20,11 +20,14 @@ if !(EGVAR(common,settingsInitFinished)) exitWith { EGVAR(common,runAtSettingsInitialized) pushBack [FUNC(addEarPlugs), _this]; }; +// Exit if hearing is disabled or if autoAdd is disabled +if (!GVAR(enableCombatDeafness) || {GVAR(autoAddEarplugsToUnits) == 0}) exitWith {}; + params ["_unit"]; TRACE_2("params",_unit,typeOf _unit); -// Exit if hearing is disabled OR autoAdd is disabled OR soldier has earplugs already in (persistence scenarios) -if (!GVAR(enableCombatDeafness) || {GVAR(autoAddEarplugsToUnits) == 0} || {[_unit] call FUNC(hasEarPlugsIn)}) exitWith {}; +// Exit if the unit already has earplugs (in ears (persistence scenarios) or inventory) +if (_unit call FUNC(hasEarPlugsIn) || {[_unit, "ACE_EarPlugs"] call EFUNC(common,hasItem)}) exitWith {}; // Add earplugs if enabled for everyone or if the soldier has a rocket launcher if (GVAR(autoAddEarplugsToUnits) == 2 || {(secondaryWeapon _unit) != ""}) exitWith { From 7c4f4cf8f856db7802410e6eb049b877dd059789 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sun, 28 Apr 2024 18:07:15 +0200 Subject: [PATCH 026/290] Grenades - Fix flashbangs causing pain for invulnerable units (#9981) Disable flashbang pain for invulnerable units --- addons/grenades/functions/fnc_flashbangExplosionEH.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/grenades/functions/fnc_flashbangExplosionEH.sqf b/addons/grenades/functions/fnc_flashbangExplosionEH.sqf index 6a7b683e6b..d54f600179 100644 --- a/addons/grenades/functions/fnc_flashbangExplosionEH.sqf +++ b/addons/grenades/functions/fnc_flashbangExplosionEH.sqf @@ -118,7 +118,7 @@ if (hasInterface && {!isNull ACE_player} && {alive ACE_player}) then { }; // add ace_medical pain effect: - if (["ace_medical"] call EFUNC(common,isModLoaded) && {_strength > 0.1}) then { + if (["ace_medical"] call EFUNC(common,isModLoaded) && {_strength > 0.1} && {isDamageAllowed _unit} && {_unit getVariable [QEGVAR(medical,allowDamage), true]}) then { [ACE_player, _strength / 2] call EFUNC(medical,adjustPainLevel); }; From 0f5b7c8762fdef5feaf4f34b7558f71073589116 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 29 Apr 2024 04:49:36 +0200 Subject: [PATCH 027/290] Grenades - Fix unconscious AI being affected by flashbangs (#9978) * Stop players being affected by AI flashbang code * Stop affecting unconscious AI * Update fnc_flashbangExplosionEH.sqf --- addons/grenades/functions/fnc_flashbangExplosionEH.sqf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/grenades/functions/fnc_flashbangExplosionEH.sqf b/addons/grenades/functions/fnc_flashbangExplosionEH.sqf index d54f600179..5e8d17e50c 100644 --- a/addons/grenades/functions/fnc_flashbangExplosionEH.sqf +++ b/addons/grenades/functions/fnc_flashbangExplosionEH.sqf @@ -41,12 +41,12 @@ if (hasInterface) then { }, [_light], 0.1] call CBA_fnc_waitAndExecute; }; -// Affect local AI +// Affect local AI (players are not local, except for ACE_player) // @todo: Affect units in static weapons, turned out, etc private _affected = (ASLtoAGL _grenadePosASL) nearEntities ["CAManBase", 20]; _affected = _affected - [ACE_player]; { - if (local _x && {alive _x}) then { + if (local _x && {_x call EFUNC(common,isAwake)}) then { private _unit = _x; private _strength = 1 - (((eyePos _unit) vectorDistance _grenadePosASL) min 20) / 20; From 3987c62accad2f54afb294dc79162757e421da74 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 29 Apr 2024 09:34:35 +0200 Subject: [PATCH 028/290] Grenades - Add missing documentation on flares and incendiaries (#9984) Update grenades-framework.md --- docs/wiki/framework/grenades-framework.md | 46 ++++++++++++++++++++--- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/docs/wiki/framework/grenades-framework.md b/docs/wiki/framework/grenades-framework.md index 3fed8fd50a..fce3b480c2 100644 --- a/docs/wiki/framework/grenades-framework.md +++ b/docs/wiki/framework/grenades-framework.md @@ -1,7 +1,7 @@ --- layout: wiki title: Grenades Framework -description: Explains how to set-up flashbangs, particularly multi-bangs. +description: Explains how to set-up incendiary, flares and flashbangs, particularly multi-bangs. group: framework parent: wiki order: 7 @@ -14,11 +14,12 @@ version: ## 1. Overview -ACE provides a simple interface for creating flashbang grenades and specifying their properties. It is important that one sets `timeToLive` to be greater than the total possible time until the last explosion, i.e, `ace_grenades_flashbangBangs * ace_grenades_flashbangInterval + ace_grenades_flashbangIntervalMaxDeviation`. Any explosions that occur after the `timeToLive` has expired will occur at `(0,0)`. +ACE provides a simple interface for creating incendiary, flare and flashbang grenades, as well as specifying their properties. For flashbangs, it is important that one sets `timeToLive` to be greater than the total possible time until the last explosion, i.e, `ace_grenades_flashbangBangs * ace_grenades_flashbangInterval + ace_grenades_flashbangIntervalMaxDeviation`. Any explosions that occur after the `timeToLive` has expired will occur at `(0,0)`. ## 2. Config Values +### 2.1 Flashbang Config Values There are several config entries specific to ACE flashbangs. All successive values can be left undefined and they will be given the defaults shown in the first example below, with the exception of `ace_grenades_flashbang`, which is equal to `0` if left undefined. ```cpp @@ -53,22 +54,55 @@ class CfgAmmo { }; ``` -### 2.1 ace_grenades_flashbang +#### 2.1.1 ace_grenades_flashbang If set to zero or left undefined, the grenade is not treated as a flashbang. If it is set to 1, the grenade will be treated as a flashbang with the associated effects. -### 2.2 ace_grenades_flashbangBangs +#### 2.1.2 ace_grenades_flashbangBangs The flashbang will explode as many times as is specified. The default is 1. -### 2.3 ace_grenades_flashbangInterval +#### 2.1.3 ace_grenades_flashbangInterval The average amount of time in seconds, after `explosionTime` has passed, between each subsequent bang. -### 2.4 ace_grenades_flashbangIntervalMaxDeviation +#### 2.1.4 ace_grenades_flashbangIntervalMaxDeviation The amount of randomness in the fuse time. +### 2.2 Incendiary Config Values + +```cpp +class CfgAmmo { + class ACE_G_M14 { + ace_grenades_incendiary = 1; + }; +}; +``` + +#### 2.2.1 ace_grenades_incendiary + +If set to zero or left undefined, the grenade is not treated as an incendiary. If it is set to 1, the grenade will be treated as an incendiary with the associated effects. + +### 2.3 Flare Config Values + +```cpp +class CfgAmmo { + class ACE_G_Handflare_White { + ace_grenades_flare = 1; + ace_grenades_color[] = {0.5,0.5,0.5,0.5}; // R, G, B, light intensity + }; +}; +``` + +#### 2.3.1 ace_grenades_flare + +If set to zero or left undefined, the grenade is not treated as a flare. If it is set to 1, the grenade will be treated as a flare with the associated effects. + +#### 2.3.1 ace_grenades_color + +Sets the color of the emitted light. The first 3 values of the array of the color, the last is the light intensity. + ## 3. Events ### 3.1 Listenable From 4f1c2fa8d7a98c2a8d2d8612edb8152a3b973c5f Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 29 Apr 2024 19:13:47 +0200 Subject: [PATCH 029/290] Common - Fix adding unusable throwables (#9980) * Prevent adding unusable grenades * Update fnc_addToInventory.sqf * Update addons/common/functions/fnc_addToInventory.sqf Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> * Update fnc_addToInventory.sqf --------- Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> --- .../common/functions/fnc_addToInventory.sqf | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/addons/common/functions/fnc_addToInventory.sqf b/addons/common/functions/fnc_addToInventory.sqf index 9902abe82b..38476ad5fc 100644 --- a/addons/common/functions/fnc_addToInventory.sqf +++ b/addons/common/functions/fnc_addToInventory.sqf @@ -59,6 +59,21 @@ switch (_container) do { }; }; +if (_type select 0 == "magazine") then { + private _configAmmoCount = getNumber (configFile >> "CfgMagazines" >> _classname >> "count"); + + // https://feedback.bistudio.com/T74244 + // When adding throwables with the addXXXCargo(Global) commands, they don't show up in the throwables list + // If a throwable has more than 1 ammo count, adding it with addItem(XXX) commands also renders the throwable unusable + if (_configAmmoCount == 1 && {_ammoCount in [-1, 1]} && {_classname call BIS_fnc_isThrowable}) then { // TODO: replace with https://community.bistudio.com/wiki/isThrowable in 2.18 + _type set [0, "item"]; + }; + + if (_ammoCount == -1) then { + _ammoCount = _configAmmoCount; + }; +}; + switch (_type select 0) do { case "weapon": { if (_canAdd || {_canFitWeaponSlot}) then { @@ -106,10 +121,6 @@ switch (_type select 0) do { }; case "magazine": { - if (_ammoCount == -1) then { - _ammoCount = getNumber (configFile >> "CfgMagazines" >> _classname >> "count"); - }; - if (_canAdd) then { _addedToUnit = true; From 9d168756df555cdc71db40343bc9d4c9bfd196b2 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Tue, 30 Apr 2024 00:55:59 -0500 Subject: [PATCH 030/290] CUP Compat - Fix NVG Black/Green translations (#9976) * cup compat - fix nvg black/green * Capitalize some colors --- addons/chemlights/stringtable.xml | 6 +- .../stringtable.xml | 58 +++++++++---------- addons/gunbag/stringtable.xml | 6 +- addons/irlight/stringtable.xml | 8 +-- addons/laserpointer/stringtable.xml | 12 ++-- addons/realisticnames/stringtable.xml | 10 ++-- addons/smallarms/stringtable.xml | 8 +-- optionals/tracers/stringtable.xml | 28 ++++----- 8 files changed, 68 insertions(+), 68 deletions(-) diff --git a/addons/chemlights/stringtable.xml b/addons/chemlights/stringtable.xml index 2c4066e9b7..76f937df61 100644 --- a/addons/chemlights/stringtable.xml +++ b/addons/chemlights/stringtable.xml @@ -355,7 +355,7 @@ Chemlight (Hi Green) - Cyalume HL (vert) + Cyalume HL (Vert) Knicklicht (Grün, Hell) ケミカルライト(高輝度 緑) Świetlik (jaskrawy zielony) @@ -533,9 +533,9 @@ Chemlight Shield (Green) ケミカルライト シールド(緑) Osłona na świetlik (zielona) - Knicklicht-Abschirmung (grün) + Knicklicht-Abschirmung (Grün) 화학조명 가림막 (초록) - Etui avec cyalume (vert) + Etui avec cyalume (Vert) Scudo Luce Chimica (Verde) 螢光棒保護殼 (綠色) 荧光棒保护壳(绿色) diff --git a/addons/compat_cup_weapons/compat_cup_weapons_nightvision/stringtable.xml b/addons/compat_cup_weapons/compat_cup_weapons_nightvision/stringtable.xml index a52bea0e31..47d35eba8c 100644 --- a/addons/compat_cup_weapons/compat_cup_weapons_nightvision/stringtable.xml +++ b/addons/compat_cup_weapons/compat_cup_weapons_nightvision/stringtable.xml @@ -13,32 +13,32 @@ AN/PVS-15 (Black, WP) - AN/PVS-15 (グリーン, 白色蛍光) - AN/PVS-15 (Verde, FB) - AN/PVS-15 (Zielone, WP) - AN/PVS-15 (grün, WP) - AN/PVS-15 (녹색, 백색광) - AN/PVS-15 (vertes, WP) - AN/PVS-15 (Чёрный, БФ) - - - AN/PVS-15 (Green, WP) AN/PVS-15 (ブラック、白色蛍光) AN/PVS-15 (Nero, FB) AN/PVS-15 (Czarne, WP) AN/PVS-15 (Schwarz, WP) AN/PVS-15 (검정, 백색광) - AN/PVS-15 (noires, WP) + AN/PVS-15 (Noires, WP) + AN/PVS-15 (Чёрный, БФ) + + + AN/PVS-15 (Green, WP) + AN/PVS-15 (グリーン, 白色蛍光) + AN/PVS-15 (Verde, FB) + AN/PVS-15 (Zielone, WP) + AN/PVS-15 (Grün, WP) + AN/PVS-15 (녹색, 백색광) + AN/PVS-15 (Vertes, WP) AN/PVS-15 (Зелёный, БФ) AN/PVS-15 (Tan, WP) AN/PVS-15 (タン, 白色蛍光) AN/PVS-15 (Marroncina, FB) - AN/PVS-15 (jasnobrązowa, WP) - AN/PVS-15 (hellbraun, WP) + AN/PVS-15 (Jasnobrązowa, WP) + AN/PVS-15 (Hellbraun, WP) AN/PVS-15 (황갈색, 백색광) - AN/PVS-15 (marron clair, WP) + AN/PVS-15 (Marron clair, WP) AN/PVS-15 (Желтовато-коричневый, БФ) @@ -50,32 +50,32 @@ GPNVG (Black, WP) - GPNVG (グリーン, 白色蛍光) - GPNVG (Verde, FB) - GPNVG (Zielone, WP) - GPNVG (grün, WP) - GPNVG (녹색, 백색광) - GPNVG (vertes, WP) + GPNVG (ブラック、白色蛍光) + GPNVG (Nero, FB) + GPNVG (Czarne, WP) + GPNVG (Schwarz, WP) + GPNVG (검정, 백색광) + GPNVG (Noires, WP) GPNVG (Чёрный, БФ) GPNVG (Tan, WP) GPNVG (タン, 白色蛍光) GPNVG (Marroncina, FB) - GPNVG (jasnobrązowa, WP) - GPNVG (hellbraun, WP) + GPNVG (Jasnobrązowa, WP) + GPNVG (Hellbraun, WP) GPNVG (황갈색, 백색광) - GPNVG (marron clair, WP) + GPNVG (Marron clair, WP) GPNVG (Желтовато-коричневый, БФ) GPNVG (Green, WP) - GPNVG (ブラック、白色蛍光) - GPNVG (Nero, FB) - GPNVG (Czarne, WP) - GPNVG (Schwarz, WP) - GPNVG (검정, 백색광) - GPNVG (noires, WP) + GPNVG (グリーン, 白色蛍光) + GPNVG (Verde, FB) + GPNVG (Zielone, WP) + GPNVG (Grün, WP) + GPNVG (녹색, 백색광) + GPNVG (Vertes, WP) GPNVG (Зелёный, БФ) diff --git a/addons/gunbag/stringtable.xml b/addons/gunbag/stringtable.xml index cf7198f41e..6389a667c8 100644 --- a/addons/gunbag/stringtable.xml +++ b/addons/gunbag/stringtable.xml @@ -19,12 +19,12 @@ Gunbag (Tan) - Waffentasche (hellbraun) - Housse d'arme (marron clair) + Waffentasche (Hellbraun) + Housse d'arme (Marron clair) Чехол (желтовато-коричневый) Pouzdro na zbraň (Žlutohnědá) ガンバッグ (タン) - Torba na broń (jasnobrązowa) + Torba na broń (Jasnobrązowa) 총가방 (황갈색) Borsa per Armi (Marroncina) 枪袋(黄褐色) diff --git a/addons/irlight/stringtable.xml b/addons/irlight/stringtable.xml index ab70abdebd..5423a8a8a0 100644 --- a/addons/irlight/stringtable.xml +++ b/addons/irlight/stringtable.xml @@ -14,12 +14,12 @@ DBAL-A3 (green) - DBAL-A3 (grün) + DBAL-A3 (Grün) DBAL-A3 (Verde) - DBAL-A3 (zielony) + DBAL-A3 (Zielony) DBAL-A3 (녹색) - DBAL-A3 (vert) - DBAL-A3 (verde) + DBAL-A3 (Vert) + DBAL-A3 (Verde) DBAL-A3 (緑) DBAL-A3 (зеленый) diff --git a/addons/laserpointer/stringtable.xml b/addons/laserpointer/stringtable.xml index 8eead72eca..b8d0a657d8 100644 --- a/addons/laserpointer/stringtable.xml +++ b/addons/laserpointer/stringtable.xml @@ -37,15 +37,15 @@ Laser Pointer (green) - Pointeur laser (vert) - Laserpointer (grün) + Pointeur laser (Vert) + Laserpointer (Grün) Лазерный прицел (зелёный) Laserové ukazovátko (Zelené) - Wskaźnik laserowy (zielony) + Wskaźnik laserowy (Zielony) Lézer-pointer (zöld) - Puntero láser (verde) - Puntatore laser (verde) - Laser (verde) + Puntero láser (Verde) + Puntatore laser (Verde) + Laser (Verde) レーザー ポインター (緑) 레이저 지시기 (초록) 激光指示器(绿色) diff --git a/addons/realisticnames/stringtable.xml b/addons/realisticnames/stringtable.xml index c67d3f70ad..6130f6aaf4 100644 --- a/addons/realisticnames/stringtable.xml +++ b/addons/realisticnames/stringtable.xml @@ -3077,7 +3077,7 @@ QBZ-95-1 (Green Hex) QBZ-95-1 (Hex Grün) QBZ-95-1 (Hex Verde) - QBZ-95-1 (zielony hex) + QBZ-95-1 (Zielony hex) QBZ-95-1 (Zelený Hex) QBZ-95-1 (Hex Vert) QBZ-95-1 (зелёный гекс) @@ -3128,7 +3128,7 @@ QBZ-95-1 GL (Green Hex) QBZ-95-1 GL (Hex Grün) QBZ-95-1 GL (Hex Verde) - QBZ-95-1 GL (zielony hex) + QBZ-95-1 GL (Zielony hex) QBZ-95-1 GL (Zelený Hex) QBZ-95-1 GL (Hex Vert) QBZ-95-1 GL (зелёный гекс) @@ -3179,7 +3179,7 @@ QBZ-95-1 LSW (Green Hex) QBZ-95-1 LSW (Hex Grün) QBZ-95-1 LSW (Hex Verde) - QBZ-95-1 LSW (zielony hex) + QBZ-95-1 LSW (Zielony hex) QBZ-95-1 LSW (Zelený Hex) QBZ-95-1 LSW (Hex Vert) QBZ-95-1 LSW (зелёный гекс) @@ -3230,7 +3230,7 @@ QBU-88 (Green Hex) QBU-88 (Hex Grün) QBU-88 (Hex Verde) - QBU-88 (zielony hex) + QBU-88 (Zielony hex) QBU-88 (Zelený Hex) QBU-88 (Hex Vert) QBU-88 (зелёный гекс) @@ -3536,7 +3536,7 @@ RPG-32 (Green Hex) RPG-32 (Hex Grün) RPG-32 (Hex Verde) - RPG-32 (zielony hex) + RPG-32 (Zielony hex) RPG-32 (Zelený Hex) RPG-32 (Hex Vert) RPG-32 (зелёный гекс) diff --git a/addons/smallarms/stringtable.xml b/addons/smallarms/stringtable.xml index c10248ca16..0b89a38b0d 100644 --- a/addons/smallarms/stringtable.xml +++ b/addons/smallarms/stringtable.xml @@ -33,13 +33,13 @@ .45 ACP 25Rnd Tracers (Green) Mag - 25-nab. mag. .45 ACP (zielony smugacz) + 25-nab. mag. .45 ACP (Zielony smugacz) Магазин, 25 патр. .45 ACP (зелёные трассеры) - Mag. 25 traçantes (vertes) .45 ACP - Cargador de 25 balas trazadoras (verde) de .45 ACP + Mag. 25 traçantes (Vertes) .45 ACP + Cargador de 25 balas trazadoras (Verde) de .45 ACP Caricatore 25cp .45 ACP Traccianti (Verdi) 25-Schuss-.45-ACP-Vermin-Magazin (Leuchtspur Grün) - .45 ACP, 25ks zásobník stopovky (zelené) + .45 ACP, 25ks zásobník stopovky (Zelené) .45 ACP 25 Merm. İzli (Yeşil) Şarjör .45 ACP 25Rnd トレーサー (緑) マガジン .45 ACP 25发 弹匣(曳光,绿) diff --git a/optionals/tracers/stringtable.xml b/optionals/tracers/stringtable.xml index 30b6b04d88..f4b1d5a750 100644 --- a/optionals/tracers/stringtable.xml +++ b/optionals/tracers/stringtable.xml @@ -8,7 +8,7 @@ Магазин 150 патр. 5.56 мм с послед. трас. (зелёные) 5.56 mm 150 colpi ricarica traccianti (verdi) caricatore 5.56 mm 150 ranný zásobník, stopovka pro přebití (Zelená) - Recarregar magazine de 150 balas tracejantes (verde) + Recarregar magazine de 150 balas tracejantes (Verde) 5.56 mm 150発入り 残通知 曳光弾 (緑) マガジン Cargador de 150 Cartuchos 5.56 mm Trazadora de recarga (Verde) 5.56mm 150발들이 재장전 알림 예광탄 (초록) 탄창 @@ -32,7 +32,7 @@ Магазин 150 патр. 5.56 мм трассирующих (зелёные) 5.56 mm 150 colpi traccianti (verdi) caricatore 5.56 mm 150 ranný zásobník, stopovka (Zelená) - Magazine 5.56mm Tracejante (verde) + Magazine 5.56mm Tracejante (Verde) 5.56 mm 150発入り 曳光弾 (緑) マガジン Cargador de 150 Cartuchos 5.56 mm Trazadora (Verde) 5.56mm 150발들이 예광탄 (초록) 탄창 @@ -80,7 +80,7 @@ Короб 200 патр. 5.56 мм с послед. трас. (зелёные) 5.56 mm 200colpi Ricarica traccianti (verdi) scatola 5.56 mm 200 ranný box, stopovka pro přebití (Zelená) - Recarregar Caixa 5.56mm 200 Balas tracejantes (verdes) + Recarregar Caixa 5.56mm 200 Balas tracejantes (Verdes) 5.56 mm 200発入り 残通知 曳光弾 (緑) ボックス Caja de 200 Cartuchos 5.56 mm Trazadora de recarga (Verde) 5.56mm 150발들이 예광탄 (노랑) 탄창 @@ -92,7 +92,7 @@ Короб 200 патр. 5.56 мм трассирующих (зелёные) 5.56 mm 200colpi Traccianti (verdi) Scatola 5.56 mm 200 ranný box, stopovka (Zelená) - Caixa 5.56mm 200 balas tracejantes (verdes) + Caixa 5.56mm 200 balas tracejantes (Verdes) 5.56 mm 200発入り 曳光弾 (緑) ボックス Caja de 200 Cartuchos 5.56 mm Trazadora (Verde) 5.56mm 200발들이 예광탄 (초록) 탄상자 @@ -260,7 +260,7 @@ Магазин 30 патр. 6.5 мм с послед. трас. (зелёные) 6.5mm 30Colpi Ricarica Traccianti(verdi) Caricatore 6.5 mm 30 ranný zásobník, stopovka pro přebití (Zelená) - Recarregar magazine 6.5mm 30 balas tracejantes (verde) + Recarregar magazine 6.5mm 30 balas tracejantes (Verde) 6.5 mm 30発入り 残通知 曳光弾 (緑) マガジン Cargador de 30 Cartuchos 6.5 mm Trazadora de recarga (Verde) 6.5mm 30발들이 재장전 알림 예광탄 (초록) 탄창 @@ -308,7 +308,7 @@ Магазин 30 патр. 6.5 мм трассирующих (зелёные) 6.5mm 30Colpi Traccianti (Verdi) Caricatore 6.5 mm 30 ranný zásobník, stopovka (Zelená) - Magazine 6.5mm 30 balas tracejantes (verde) + Magazine 6.5mm 30 balas tracejantes (Verde) 6.5 mm 30発入り 曳光弾 (緑) マガジン Cargador de 30 Cartuchos 6.5 mm Trazadora (Verde) 6.5mm 30발들이 예광탄 (초록) 탄창 @@ -352,11 +352,11 @@ 6.5mm 100Rnd Mixed Mag (Green) - 100 Schuss 6.5mm Magazin gemischt (grün) + 100 Schuss 6.5mm Magazin gemischt (Grün) Магазин 100 патр. 6.5 мм TE4 (зелёные) 6.5mm 100Colpi Misti Caricatore (verdi) 6.5 mm 100 ranný zásobník, částečná stopovka (Zelená) - Magazine 6.5mm 100 balas misturadas (verde) + Magazine 6.5mm 100 balas misturadas (Verde) 6.5 mm 100発入り 混合 (緑) マガジン Cargador de 100 cartuchos 6.5 mm Mezcla (Verde) 6.5mm 100발들이 혼합탄 (초록) 탄창 @@ -378,7 +378,7 @@ 6.5mm 100Rnd Mag Tracer (Green) 100 Schuss 6.5mm Magazin Leuchtspur (Grün) Магазин 100 патр. 6.5 мм трассирующих (зелёные) - 6.5mm 100Colpi Caricatore Tracciante (verde) + 6.5mm 100Colpi Caricatore Tracciante (Verde) 6.5 mm 100 ranný zásobník, stopovka (Zelená) Magazine 6.5mm 100 balas tracejantes 6.5 mm 100発入り (緑) マガジン @@ -496,7 +496,7 @@ 6.5 mm 200Rnd Belt Case Mixed (Green) - 6,5 mm 200-Schuss-Gurtkiste Gemischt (grün) + 6,5 mm 200-Schuss-Gurtkiste Gemischt (Grün) Короб 200 патр. 6.5 мм TE4 (зелёные) 6.5mm 200Colpi Caricatore esteso Misti (Verdi) 6.5 mm 200 ranný pás, částečná stopovka (Zelená) @@ -520,7 +520,7 @@ 6.5 mm 200Rnd Belt Case Mixed (Red) - 6,5 mm 200-Schuss-Gurtkiste Gemischt (grün) + 6,5 mm 200-Schuss-Gurtkiste Gemischt (Grün) Короб 200 патр. 6.5 мм TE4 (красные) 6.5 mm 200Colpi Caritore maggiorato Misti (rossi) 6.5 mm 200 ranný pás, částečná stopovka (Červená) @@ -544,7 +544,7 @@ 6.5 mm 200Rnd Belt Case Tracer (Green) - 6,5 mm 200-Schuss-Gurtkiste Leuchtspur (grün) + 6,5 mm 200-Schuss-Gurtkiste Leuchtspur (Grün) Короб 200 патр. 6.5 мм трассирующих (зелёные) 6.5 mm 200Colpi Caricatore maggiorato Traccianti (verdi) 6.5 mm 200 ranný pás, částečná stopovka (Zelená) @@ -600,7 +600,7 @@ 7.62 mm 20Colpi Traccianti (verdi) Caricatore 7.62 mm 20 ranný zásobník, stopovka (Zelená) 7.62 mm Magazynek 20szt. Smugowa (Zielona) - Magazine 7.62 mm 20 Balas Tracejantes (verdes) + Magazine 7.62 mm 20 Balas Tracejantes (Verdes) 7.62 mm 20発入り 曳光弾 (緑) マガジン Cargador de 20 cartuchos 7.62 mm Trazadora (Verde) 7.62mm 20발들이 예광탄 (초록) 탄창 @@ -764,7 +764,7 @@ .338 NM 130Rnd Belt Mixed (Green) - .338 NM 130 Schuss Gurt gemischt (grün) + .338 NM 130 Schuss Gurt gemischt (Grün) Лента 130 патр. .338 NM TE4 (зелёные) .338 NM 130Colpi Caricatore a nastro Misto (Verde) .338 NM 130 ranný pás, částečná stopovka (Zelená) From 8e367ee80eb378ae6d91d09ae68b0591e68f66b7 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Sun, 5 May 2024 15:24:45 -0500 Subject: [PATCH 031/290] Prepare 3.17.1 Build 85 --- addons/main/script_version.hpp | 2 +- docs/_config.yml | 2 +- docs/_config_dev.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/main/script_version.hpp b/addons/main/script_version.hpp index 62b6d52e2e..9223f27ea7 100644 --- a/addons/main/script_version.hpp +++ b/addons/main/script_version.hpp @@ -1,4 +1,4 @@ #define MAJOR 3 #define MINOR 17 #define PATCHLVL 1 -#define BUILD 84 +#define BUILD 85 diff --git a/docs/_config.yml b/docs/_config.yml index e29663ce3b..c23538d799 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -10,7 +10,7 @@ ace: major: 3 minor: 17 patch: 1 - build: 84 + build: 85 markdown: kramdown diff --git a/docs/_config_dev.yml b/docs/_config_dev.yml index b6f160c7d3..e83f8e441f 100644 --- a/docs/_config_dev.yml +++ b/docs/_config_dev.yml @@ -10,7 +10,7 @@ ace: major: 3 minor: 17 patch: 1 - build: 84 + build: 85 markdown: kramdown From 62353a91752fc052c1ddd21f3e537fb2c1dfd2f0 Mon Sep 17 00:00:00 2001 From: Fabio Schick <58027418+mrschick@users.noreply.github.com> Date: Sat, 11 May 2024 03:34:34 +0200 Subject: [PATCH 032/290] Translations - Updated Italian with recent additions (#10004) * hearing italian translations * common italian translations --- addons/common/stringtable.xml | 3 +++ addons/hearing/stringtable.xml | 1 + 2 files changed, 4 insertions(+) diff --git a/addons/common/stringtable.xml b/addons/common/stringtable.xml index 1c960e9173..3bf4205292 100644 --- a/addons/common/stringtable.xml +++ b/addons/common/stringtable.xml @@ -1834,6 +1834,7 @@ 무기 흔들림 Oscillation de l'arme Колебание оружия + Oscillazione arma Enable Weapon Sway @@ -1841,6 +1842,7 @@ 무기 흔들림 추가 Activer l'oscillation de l'arme Включить колебание оружия + Abilita oscillazione arma Enables weapon sway influenced by sway factors, such as stance, fatigue and medical condition.\nDisabling this setting will defer sway to vanilla or other mods. @@ -1848,6 +1850,7 @@ 흔들림 계수, 자세, 피로도, 건강 상태 등의 요인에 영향을 받는 무기 흔들림을 활성화합니다.\n이 설정을 비활성화하면 바닐라 또는 다른 모드의 흔들림으로 대체됩니다. Active l'oscillation de l'arme influencé par les facteurs d'oscillation, tels que la position, la fatigue et l'état de santé.\nLa désactivation de ce paramètre reportera l'oscillation à vanilla ou à d'autres mods. Активируйте колебание оружия в зависимости от таких факторов, как стойка, усталость и состояние здоровья.\nОтключение этого параметра приведет к переносу раскачивания на vanilla или другие моды. + Abilita l'oscillazione ACE, influenzata da fattori come postura, fatica e condizione medica.\nDisabilitare questa impostazione farà controllare l'oscillazione al gioco vanilla o altre mod. Sway factor diff --git a/addons/hearing/stringtable.xml b/addons/hearing/stringtable.xml index 1265478639..fcdbecb2ff 100644 --- a/addons/hearing/stringtable.xml +++ b/addons/hearing/stringtable.xml @@ -376,6 +376,7 @@ Uniquement les unités dotées d'armes lourdes Только юниты с тяжелым вооружением 重火器を装備したユニットのみ + Solo a unità con armi pesanti From 2a3ff8e185855a11e3777e92af6e4d7a3a8bbb71 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 11 May 2024 03:39:41 +0200 Subject: [PATCH 033/290] Medical Treatment - Fix low SpO2 making units go into cardiac arrest again (#10003) * Set SpO2 after successful CPR * Update fnc_cprLocal.sqf * Add API * Update fnc_cprLocal.sqf --- addons/medical_treatment/functions/fnc_cprLocal.sqf | 7 ++++++- docs/wiki/framework/medical-treatment-framework.md | 7 +++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/addons/medical_treatment/functions/fnc_cprLocal.sqf b/addons/medical_treatment/functions/fnc_cprLocal.sqf index 228774b2f6..e6b1299027 100644 --- a/addons/medical_treatment/functions/fnc_cprLocal.sqf +++ b/addons/medical_treatment/functions/fnc_cprLocal.sqf @@ -24,9 +24,14 @@ TRACE_2("cprLocal",_medic,_patient); private _bloodVolume = GET_BLOOD_VOLUME(_patient); private _successChance = linearConversion [BLOOD_VOLUME_CLASS_4_HEMORRHAGE, BLOOD_VOLUME_CLASS_2_HEMORRHAGE, _bloodVolume, GVAR(cprSuccessChanceMin), GVAR(cprSuccessChanceMax), true]; if ((random 1) < _successChance) then { + // If SpO2 is too low, it will make HR skyrocket to the point where patient goes back into CA + // Allow 3rd party mods to disable this mechanic + if (missionNamespace getVariable [QGVAR(setSpO2UponCPRSuccess), true] && {GET_SPO2(_patient) < DEFAULT_SPO2 / 2}) then { + _patient setVariable [VAR_SPO2, DEFAULT_SPO2 / 2, true]; + }; + TRACE_2("CPR random success",_bloodVolume,_successChance); [QEGVAR(medical,CPRSucceeded), _patient] call CBA_fnc_localEvent; } else { TRACE_2("CPR random fail",_bloodVolume,_successChance); }; - diff --git a/docs/wiki/framework/medical-treatment-framework.md b/docs/wiki/framework/medical-treatment-framework.md index 736295804a..52e661a516 100644 --- a/docs/wiki/framework/medical-treatment-framework.md +++ b/docs/wiki/framework/medical-treatment-framework.md @@ -128,3 +128,10 @@ If a mission maker wishes to disable Zeus access to the medical menu, they can s ```sqf ace_medical_gui_enableZeusModule = false; // default is true ``` + +### 3.3 SpO2 Configuration + +If 3rd party mods want to disable SpO2 being set to a minimum upon successful CPR, they can set the variable below: +```sqf +ace_medical_treatment_setSpO2UponCPRSuccess = false; // default is true +``` From 6972f02bc4da32799d3e6056a4d0d81b1f7e38d3 Mon Sep 17 00:00:00 2001 From: Abogado <16608353+regiregi22@users.noreply.github.com> Date: Sat, 11 May 2024 03:42:55 +0200 Subject: [PATCH 034/290] Translation - Add Missing Spanish (#10001) Translation to Spanish Translation to Spanish --- addons/advanced_throwing/stringtable.xml | 2 + addons/ai/stringtable.xml | 2 + addons/arsenal/stringtable.xml | 12 +++ addons/ballistics/stringtable.xml | 7 ++ addons/captives/stringtable.xml | 2 + addons/cargo/stringtable.xml | 5 ++ addons/common/stringtable.xml | 7 ++ .../compat_cup_weapons_csw/stringtable.xml | 17 ++++ .../stringtable.xml | 9 ++ .../compat_ws_realisticnames/stringtable.xml | 31 +++++++ addons/cookoff/stringtable.xml | 1 + addons/dragging/stringtable.xml | 6 ++ addons/explosives/stringtable.xml | 4 + addons/fastroping/stringtable.xml | 2 + addons/fieldmanual/stringtable.xml | 86 +++++++++++++++++++ addons/hearing/stringtable.xml | 2 + addons/irlight/stringtable.xml | 14 +++ addons/killtracker/stringtable.xml | 3 + addons/laser/stringtable.xml | 2 + addons/maptools/stringtable.xml | 18 ++++ addons/markers/stringtable.xml | 2 + addons/medical_ai/stringtable.xml | 3 + addons/medical_damage/stringtable.xml | 2 + addons/medical_engine/stringtable.xml | 2 + addons/medical_gui/stringtable.xml | 31 +++++++ addons/medical_status/stringtable.xml | 2 + addons/medical_treatment/stringtable.xml | 17 ++++ addons/medical_vitals/stringtable.xml | 3 + addons/nightvision/stringtable.xml | 12 +++ addons/overheating/stringtable.xml | 6 ++ addons/refuel/stringtable.xml | 5 ++ addons/reload/stringtable.xml | 2 + addons/reloadlaunchers/stringtable.xml | 6 ++ addons/repair/stringtable.xml | 21 +++++ addons/tagging/stringtable.xml | 2 + addons/zeus/stringtable.xml | 4 + 36 files changed, 352 insertions(+) diff --git a/addons/advanced_throwing/stringtable.xml b/addons/advanced_throwing/stringtable.xml index 1e0b5ae23f..e0e526e12e 100644 --- a/addons/advanced_throwing/stringtable.xml +++ b/addons/advanced_throwing/stringtable.xml @@ -193,6 +193,7 @@ 바람 정보 임시로 표시 Afficher temporairement les informations sur le vent Временно показать информацию о ветре + Mostrar información del viento temporalmente Temporarily display Wind Info while throwing, to aid in placing smoke grenades effectively. @@ -202,6 +203,7 @@ 연막탄을 효과적으로 배치하는 데 도움이 되도록 투척하는 동안 일시적으로 바람 정보를 표시합니다. Affiche les informations sur le vent pendant le lancement pour placer les grenades fumigènes plus efficacement. Временно отображайте информацию о ветре во время броска, чтобы помочь эффективно разместить дымовые шашки. + Mostrar información del viento temporalmente mientras se lanza, para ayudar a lanzar las granadas de humo de forma efectiva. Prepare/Change Throwable diff --git a/addons/ai/stringtable.xml b/addons/ai/stringtable.xml index 11a686f6b2..b9df8bb35a 100644 --- a/addons/ai/stringtable.xml +++ b/addons/ai/stringtable.xml @@ -91,6 +91,7 @@ Equipar NVGs automaticamente 暗視装置の自動装備 Автоматическое оснащение ПНВ + Auto equipar gafas de visión nocturna Equips NVG in inventory during night time and unequips it during day time.\nDoes not add NVGs to inventory! @@ -102,6 +103,7 @@ Equipa o NVG do inventário durante a noite e desequipa durante o dia.\nNão adiciona NVGs ao inventário! インベントリ内の暗視装置を夜間に装備し、日中は解除し収納します。\nこれはNVGをインベントリに追加しません。 Экипирует ПНВ в ночное время и отключает его в дневное время.\nНе добавляет ПНВ в инвентарь! + Equipa las gafas de visión nocturna en el inventario cuando es de noche, y las desequipa cuando es de día.\nNo añade las gafas al inventario! diff --git a/addons/arsenal/stringtable.xml b/addons/arsenal/stringtable.xml index 02c35266db..25ce1f75ae 100644 --- a/addons/arsenal/stringtable.xml +++ b/addons/arsenal/stringtable.xml @@ -1245,6 +1245,7 @@ Интегрирован тепловизор. 열화상 내장 Thermique intégrée + Térmica integrada Thermal & Primary integrated @@ -1253,6 +1254,7 @@ Интегрирован тепловизор и осн.прицел. 열화상과 주무기 내장 Thermique et primaire intégrés + Térmica y Primaria integrada Not Supported @@ -1609,6 +1611,7 @@ Décroissant Decrescente Нисходящий + Descendiente Ascending @@ -1620,6 +1623,7 @@ Croissant Crescente Восходящий + Ascendiente Tools @@ -1647,6 +1651,7 @@ Nombre de munitions Quantidade de munição Количество боеприпасов + Cantidad de munición Illuminators @@ -1657,6 +1662,7 @@ Iluminadores イルミネーター Осветители + Iluminadores Default to Favorites @@ -1668,6 +1674,7 @@ Favoris par défaut Favoritos por padrão По умолчанию - Избранное + Favoritos por defecto Controls whether the ACE Arsenal defaults to showing all items or favorites. @@ -1679,6 +1686,7 @@ Contrôle si l'arsenal ACE affiche par défaut tous les éléments ou les favoris. Controla se o Arsenal ACE exibe por padrão todos os itens ou favoritos. Определяет, будет ли в арсенале ACE по умолчанию отображаться все предметы или избранное. + Controla si el Arsenal de ACE muestra por defecto todos los objetos o sólo los favoritos Favorites Color @@ -1690,6 +1698,7 @@ Couleurs favorites Cor dos favoritos Избранный цвет + Color de Favoritos Highlight color for favorited items. @@ -1701,6 +1710,7 @@ Met en surbrillance les éléments favoris. Cor de destaque para itens favoritados. Выделите цветом любимые предметы. + Color de marcado para los objetos favoritos Switch between displaying all items or your favorites.\nDouble click while holding Shift to add or remove an item. @@ -1712,6 +1722,7 @@ Change entre l'affichage de tous les éléments ou de vos favoris.\nDouble-cliquez en maintenant la touche Maj enfoncée pour ajouter ou supprimer un élément. Alterna entre a exibição de todos os itens ou seus favoritos.\nClique duas vezes enquanto mantém pressionada a tecla Shift para adicionar ou remover um item. Переключайтесь между отображением всех элементов или ваших избранных.\nДважды щелкните, удерживая Shift, чтобы добавить или удалить элемент. + Alterna entre mostrar todos los objetos o sólo los favoritos.\nDoble click mientras se pulsa Shift para añadir o quitar un objeto. Search\nCTRL + Click to enable live results @@ -1721,6 +1732,7 @@ 검색\nCtrl + 클릭으로 실시간 검색 결과를 활성화 Поиск\nCtrl + Click для включения результатов в реальном времени Recherche\nCTRL + clic pour modifier les résultats tout en écrivant + Buscar\nCTRL + Click habilita los objetos en directo diff --git a/addons/ballistics/stringtable.xml b/addons/ballistics/stringtable.xml index aa746e543f..a4c67c68d5 100644 --- a/addons/ballistics/stringtable.xml +++ b/addons/ballistics/stringtable.xml @@ -3540,6 +3540,7 @@ Utilisation de l'IA Utilização por IA Использование ИИ + Uso de la IA Illum @@ -3551,6 +3552,7 @@ Fusées éclairantes Sinalizadoras Осветители + Iluminación Smoke @@ -3562,6 +3564,7 @@ Fumigènes Fumígenas Дым + Humo Inf @@ -3573,6 +3576,7 @@ Infanterie Infantaria Пехота + Infantería Veh @@ -3584,6 +3588,7 @@ Véhicule Veículo Техника + Vehículo Armor @@ -3595,6 +3600,7 @@ Blindage Blindagem Бронетехника + Blindados Air @@ -3606,6 +3612,7 @@ Aviation Aeronaves Авиация + Aeronaves diff --git a/addons/captives/stringtable.xml b/addons/captives/stringtable.xml index 174022ea11..4fc86ec58f 100644 --- a/addons/captives/stringtable.xml +++ b/addons/captives/stringtable.xml @@ -146,6 +146,7 @@ 포로 눈 가리기 目隠しをする Завязать глаза пленному + Vendar ojos al prisionero Remove blindfold @@ -156,6 +157,7 @@ 눈가리개 풀기 目隠しを外す Снять повязку с глаз + Quitar vendas de los ojos Cable Tie diff --git a/addons/cargo/stringtable.xml b/addons/cargo/stringtable.xml index 0a766ab221..e74fd742c2 100644 --- a/addons/cargo/stringtable.xml +++ b/addons/cargo/stringtable.xml @@ -40,6 +40,7 @@ 配置する 배치하기 Déployer + Desplegar Raise/Lower | (Ctrl + Scroll) Rotate @@ -337,6 +338,7 @@ 荷降ろし不可能です 하역할 수가 없습니다 Не может быть выгружен + No puede ser descargado Cargo Size: %1 @@ -346,6 +348,7 @@ 貨物のサイズ: %1 화물 크기: %1 Размер груза: %1 + Tamaño de carga: %1 Custom Name @@ -584,6 +587,7 @@ 配置機能を有効化 배치 활성화 Permettre le placement + Habilitar despliegue Controls whether cargo items can be unloaded via the deploy method. @@ -592,6 +596,7 @@ 配置機能を介して貨物アイテムを降ろすことが出来るかどうかを制御します。 배치 방법을 통해 화물 아이템을 내릴 수 있는지 여부를 제어합니다. Contrôler si les éléments de cargaison peuvent être déchargés via la méthode de déploiement. + Controla si los objetos de la carga pueden ser descargados mediante el método de despliegue. diff --git a/addons/common/stringtable.xml b/addons/common/stringtable.xml index 3bf4205292..f49e2cedde 100644 --- a/addons/common/stringtable.xml +++ b/addons/common/stringtable.xml @@ -1834,6 +1834,7 @@ 무기 흔들림 Oscillation de l'arme Колебание оружия + Oscilación del arma Oscillazione arma @@ -1842,6 +1843,7 @@ 무기 흔들림 추가 Activer l'oscillation de l'arme Включить колебание оружия + Habilitar oscilación del arma Abilita oscillazione arma @@ -1850,6 +1852,7 @@ 흔들림 계수, 자세, 피로도, 건강 상태 등의 요인에 영향을 받는 무기 흔들림을 활성화합니다.\n이 설정을 비활성화하면 바닐라 또는 다른 모드의 흔들림으로 대체됩니다. Active l'oscillation de l'arme influencé par les facteurs d'oscillation, tels que la position, la fatigue et l'état de santé.\nLa désactivation de ce paramètre reportera l'oscillation à vanilla ou à d'autres mods. Активируйте колебание оружия в зависимости от таких факторов, как стойка, усталость и состояние здоровья.\nОтключение этого параметра приведет к переносу раскачивания на vanilla или другие моды. + Habilita la oscilación del arma afectado por factores como la postura, la fatiga y la condición médica.\nDeshabilitar esta opción hará que el comportamiento de la oscilación venga definido por Vanilla o por otros mods. Abilita l'oscillazione ACE, influenzata da fattori come postura, fatica e condizione medica.\nDisabilitare questa impostazione farà controllare l'oscillazione al gioco vanilla o altre mod. @@ -1891,6 +1894,7 @@ Fattore di Oscillazione Appoggiato 静止依託時の手ぶれ係数 Коэффициент колебания прицела в состоянии покоя + Factor de oscilación apoyado Influences the amount of weapon sway while weapon is rested. @@ -1901,6 +1905,7 @@ Determina la quantità di oscillazione dell'arma quando questa è appoggiata. 静止し壁などに依託している時の武器の手ぶれの大きさに影響します。 Влияет на величину колебания прицела оружия в состоянии покоя. + Afecta la cantidad de oscilación del arma cuando se está apoyado. Deployed sway factor @@ -1911,6 +1916,7 @@ Fattore di Oscillazione su Bipode 接地展開時の手ぶれ係数 Коэффициент колебания прицела при развертывании + Factor de oscilación desplegado Influences the amount of weapon sway while weapon is deployed. @@ -1921,6 +1927,7 @@ Determina la quantità di oscillazione dell'arma quando questa è stabilizzata usando il bipode. 武器の接地展開時の武器の手ぶれの大きさに影響します。 Влияет на величину колебания прицела оружия при его развертывании. + Afecta la cantidad de oscilación del arma cuando se está desplegado. diff --git a/addons/compat_cup_weapons/compat_cup_weapons_csw/stringtable.xml b/addons/compat_cup_weapons/compat_cup_weapons_csw/stringtable.xml index a23cf87af0..4ce86a2606 100644 --- a/addons/compat_cup_weapons/compat_cup_weapons_csw/stringtable.xml +++ b/addons/compat_cup_weapons/compat_cup_weapons_csw/stringtable.xml @@ -6,36 +6,42 @@ [CSW] AGS30 ベルト [CSW] Лента AGS 30 [CSW] AGS-30 벨트 + [CSW] Cinta de AGS30 [CSW] MK19 Belt [CSW] Mk19 ベルト [CSW] Лента Mk19 [CSW] Mk.19 벨트 + [CSW] Cinta de MK19 [CSW] TOW Tube [CSW] TOW チューブ [CSW] Туба TOW [CSW] TOW 튜브 + [CSW] Tubo de TOW [CSW] TOW2 Tube [CSW] TOW2 チューブ [CSW] Туба TOW-2 [CSW] TOW2 튜브 + [CSW] Tubo de TOW2 [CSW] PG-9 Round [CSW] PG-9 砲弾 [CSW] Снаряд ПГ-9 [CSW] PG-9 대전차고폭탄 + [CSW] Carga de PG-9 [CSW] OG-9 Round [CSW] OG-9 砲弾 [CSW] Снаряд OГ-9 [CSW] OG-9 고폭파편탄 + [CSW] Carga de OG-9 [CSW] M1 HE @@ -43,6 +49,7 @@ [CSW] M1 HE [CSW] M1 고폭탄 [CSW] M1 HE + [CSW] HE de M1 [CSW] M84 Smoke @@ -50,6 +57,7 @@ [CSW] M84 Дымовая [CSW] M84 연막탄 [CSW] M84 Fumigène + [CSW] Humo M84 [CSW] M60A2 WP @@ -57,6 +65,7 @@ [CSW] M60A2 WP [CSW] M60A2 백린연막탄 [CSW] M60A2 WP + [CSW] M60A2 WP [CSW] M67 AT Laser Guided @@ -64,6 +73,7 @@ [CSW] M67 AT Laser Guided [CSW] M67 레이저유도 대전차탄 [CSW] M67 AT Guidé laser + [CSW] AT Guiado por Láser M67 [CSW] M314 Illumination @@ -71,6 +81,7 @@ [CSW] M314 Осветительная [CSW] M314 조명탄 [CSW] M314 Illumination + [CSW] Iluminación M314 [CSW] 3OF56 HE @@ -78,6 +89,7 @@ [CSW] 3OF56 HE [CSW] 3OF56 고폭탄 [CSW] 3OF56 HE + [CSW] HE de 3OF56 [CSW] 3OF69M Laser Guided @@ -85,6 +97,7 @@ [CSW] 3OF69M Laser Guided [CSW] 3OF69M 레이저유도탄 [CSW] 3OF69M Guidé laser + [CSW] 3OF69M Guiado por Láser [CSW] 122mm WP @@ -92,6 +105,7 @@ [CSW] 122mm WP [CSW] 122mm 백린탄 [CSW] 122mm WP + [CSW] WP de 122mm [CSW] D-462 Smoke @@ -99,6 +113,7 @@ [CSW] D-462 Дымовая [CSW] D-462 연막탄 [CSW] D-462 Fumigène + [CSW] Humo D-462 [CSW] S-463 Illumination @@ -106,6 +121,7 @@ [CSW] S-463 Осветительная [CSW] S-463 조명탄 [CSW] S-463 Eclairante + [CSW] Iluminación S-463 [CSW] BK-6M HEAT @@ -113,6 +129,7 @@ [CSW] BK-6M HEAT [CSW] BK-6M 대전차고폭탄 [CSW] BK-6M HEAT + [CSW] BK-6M HEAT diff --git a/addons/compat_cup_weapons/compat_cup_weapons_nightvision/stringtable.xml b/addons/compat_cup_weapons/compat_cup_weapons_nightvision/stringtable.xml index 47d35eba8c..e3166d6f42 100644 --- a/addons/compat_cup_weapons/compat_cup_weapons_nightvision/stringtable.xml +++ b/addons/compat_cup_weapons/compat_cup_weapons_nightvision/stringtable.xml @@ -10,6 +10,7 @@ AN/PVS-14 (백색광) AN/PVS-14 (WP) AN/PVS-14 (БФ) + AN/PVS-14 (WP) AN/PVS-15 (Black, WP) @@ -20,6 +21,7 @@ AN/PVS-15 (검정, 백색광) AN/PVS-15 (Noires, WP) AN/PVS-15 (Чёрный, БФ) + AN/PVS-15 (Negras, WP) AN/PVS-15 (Green, WP) @@ -30,6 +32,7 @@ AN/PVS-15 (녹색, 백색광) AN/PVS-15 (Vertes, WP) AN/PVS-15 (Зелёный, БФ) + AN/PVS-15 (Verdes, WP) AN/PVS-15 (Tan, WP) @@ -40,6 +43,7 @@ AN/PVS-15 (황갈색, 백색광) AN/PVS-15 (Marron clair, WP) AN/PVS-15 (Желтовато-коричневый, БФ) + AN/PVS-15 (Marrones, WP) AN/PVS-15 (Winter, WP) @@ -47,6 +51,7 @@ AN/PVS-15 (설상, 백색광) AN/PVS-15 (Белый, БФ) AN/PVS-15 (Blanc, WP) + AN/PVS-15 (Blancas, WP) GPNVG (Black, WP) @@ -57,6 +62,7 @@ GPNVG (검정, 백색광) GPNVG (Noires, WP) GPNVG (Чёрный, БФ) + GPNVG (Negras, WP) GPNVG (Tan, WP) @@ -67,6 +73,7 @@ GPNVG (황갈색, 백색광) GPNVG (Marron clair, WP) GPNVG (Желтовато-коричневый, БФ) + GPNVG (Marrones, WP) GPNVG (Green, WP) @@ -77,6 +84,7 @@ GPNVG (녹색, 백색광) GPNVG (Vertes, WP) GPNVG (Зелёный, БФ) + GPNVG (Verdes, WP) GPNVG (Winter, WP) @@ -84,6 +92,7 @@ GPNVG (설상, 백색광) AN/PVS-15 (Белый, БФ) GPNVG (Blanc, WP) + GPNVG (Blancas, WP) diff --git a/addons/compat_ws/compat_ws_realisticnames/stringtable.xml b/addons/compat_ws/compat_ws_realisticnames/stringtable.xml index 092fd2a9ea..714f869d8d 100644 --- a/addons/compat_ws/compat_ws_realisticnames/stringtable.xml +++ b/addons/compat_ws/compat_ws_realisticnames/stringtable.xml @@ -9,6 +9,7 @@ AA12 AA12 AA12 + AA12 AA12 (Sand) @@ -18,6 +19,7 @@ AA12 (サンド) AA12 (Песочный) AA12 (Sable) + AA12 (Arena) AA12 (Snake) @@ -26,6 +28,7 @@ AA12 (Serpe) AA12 (ヘビ柄) AA12 (Змея) + AA12 (Serpiente) Galil ARM @@ -35,6 +38,7 @@ ガリル ARM Galil ARM Galil ARM + Galil ARM Galil ARM (Old) @@ -44,6 +48,7 @@ ガリル ARM (使い古し) Galil ARM (Старый) Galil ARM (Ancien) + Galil ARM (Vieja) GLX 160 @@ -53,6 +58,7 @@ GLX 160 GLX 160 GLX 160 + GLX 160 GLX 160 (Snake) @@ -61,6 +67,7 @@ GLX-160 (Serpe) GLX 160 (ヘビ柄) GLX 160 (Змея) + GLX 160 (Serpiente) GLX 160 (Hex) @@ -70,6 +77,7 @@ GLX 160 (六角形迷彩) GLX 160 (Гекс) GLX 160 (Hex) + GLX 160 (Hex) GLX 160 (Green Hex) @@ -79,6 +87,7 @@ GLX 160 (緑六角形迷彩) GLX 160 (Зеленый Гекс) GLX 160 (Vert Hex) + GLX 160 (Hex Verde) GLX 160 (Camo) @@ -88,6 +97,7 @@ GLX 160 (迷彩) GLX 160 (Камуфляж) GLX 160 (Camo) + GLX 160 (Camo) GLX 160 (Sand) @@ -97,6 +107,7 @@ GLX 160 (サンド) GLX 160 (Песочный) GLX 160 (Sable) + GLX 160 (Arena) Mk14 Mod 1 EBR (Black) @@ -106,6 +117,7 @@ Mk14 Mod 1 EBR (ブラック) Mk14 Mod 1 EBR (Черный) Mk14 Mod 1 EBR (Noir) + Mk14 Mod 1 EBR (Negra) Mk14 Mod 1 EBR (Snake) @@ -114,6 +126,7 @@ Mk14 Mod 1 EBR (Serpe) Mk14 Mod 1 EBR (ヘビ柄) Mk14 Mod 1 EBR (Змея) + Mk14 Mod 1 EBR (Serpiente) Vektor SS-77 @@ -122,6 +135,7 @@ ヴェクター SS-77 Vektor SS-77 Vektor SS-77 + Vektor SS-77 Vektor SS-77 (Camo) @@ -131,6 +145,7 @@ ヴェクター SS-77 (迷彩) Vektor SS-77 (Камуфляж) Vektor SS-77 (Camo) + Vektor SS-77 (Camo) Vektor SS-77 (Hex) @@ -140,6 +155,7 @@ ヴェクター SS-77 (六角形迷彩) Vektor SS-77 (гекс) Vektor SS-77 (Hex) + Vektor SS-77 (Hex) Vektor SS-77 (Green Hex) @@ -149,6 +165,7 @@ ヴェクター SS-77 (緑六角形迷彩) Vektor SS-77 (зеленый гекс) Vektor SS-77 (VertHex) + Vektor SS-77 (Hex Verde) Vektor SS-77 (Desert) @@ -158,6 +175,7 @@ ヴェクター SS-77 (砂漠迷彩) Vektor SS-77 (песочныйt) Vektor SS-77 (Désert) + Vektor SS-77 (Desierto) Vektor SS-77 Compact @@ -167,6 +185,7 @@ ヴェクター SS-77 コンパクト Vektor SS-77 Compact Vektor SS-77 Compacte + Vektor SS-77 Compacta Vektor SS-77 Compact (Snake) @@ -175,6 +194,7 @@ Vektor SS-77 Compatto (Serpe) ヴェクター SS-77 コンパクト (ヘビ柄) Vektor SS-77 Compact (змея) + Vektor SS-77 Compacta (Serpiente) FN FAL 50.00 (Wood) @@ -184,6 +204,7 @@ FN FAL 50.00 (森林迷彩) FN FAL 50.00 (лесной) FN FAL 50.00 (Bois) + FN FAL 50.00 (Madera) FN FAL 50.00 GL (Wood) @@ -193,6 +214,7 @@ FN FAL 50.00 GL (森林迷彩) FN FAL 50.00 GL (лесной) FN FAL 50.00 GL (Bois) + FN FAL 50.00 GL (Madera) FN FAL 50.00 @@ -202,6 +224,7 @@ FN FAL 50.00 FN FAL 50.00 FN FAL 50.00 + FN FAL 50.00 FN FAL 50.00 GL @@ -211,6 +234,7 @@ FN FAL 50.00 GL FN FAL 50.00 GL FN FAL 50.00 GL + FN FAL 50.00 GL FN FAL 50.00 (Desert) @@ -220,6 +244,7 @@ FN FAL 50.00 (砂漠迷彩) FN FAL 50.00 (песочный) FN FAL 50.00 (Désert) + FN FAL 50.00 (Desierto) FN FAL 50.00 (Jungle) @@ -229,6 +254,7 @@ FN FAL 50.00 (熱帯迷彩) FN FAL 50.00 (джунгли) FN FAL 50.00 (Jungle) + FN FAL 50.00 (Jungla) Vektor R4 @@ -238,6 +264,7 @@ ヴェクター R5 Vektor R4 Vektor R4 + Vektor R4 Vektor R5 Carbine @@ -247,6 +274,7 @@ ヴェクター R5 カービン Vektor R5 Carbine Vektor R5 Carbine + Vektor R5 Carabina Vektor R5 Carbine GL @@ -256,6 +284,7 @@ ヴェクター R5 カービン GL Vektor R5 Carbine GL Vektor R5 Carbine GL + Vektor R5 Carabina GL Vektor R5 Carbine (Snake) @@ -264,6 +293,7 @@ Vektor R5 Carabina (Serpe) ヴェクター R5 カービン (ヘビ柄) Vektor R5 Carbine (Змея) + Vektor R5 Carabina (Serpiente) Vektor R5 Carbine GL (Snake) @@ -272,6 +302,7 @@ Vektor R5 Carabina GL (Serpe) ヴェクター R5 カービン GL (ヘビ柄) Vektor R5 Carbine GL (Змея) + Vektor R5 Carabina GL (Serpiente) XMS diff --git a/addons/cookoff/stringtable.xml b/addons/cookoff/stringtable.xml index 5f764a24b7..49654d8435 100644 --- a/addons/cookoff/stringtable.xml +++ b/addons/cookoff/stringtable.xml @@ -189,6 +189,7 @@ Contrôle si les véhicules seront toujours détruits après l'auto-inflammation. Define se os veículos serão sempre destruídos após cozinhamento. Определяет, всегда ли транспортные средства будут уничтожаться после детонации. + Controla si los vehículos siempre será destruidos despues de la detonación inducida por calor. Enable Cook-Off Vehicle Fire diff --git a/addons/dragging/stringtable.xml b/addons/dragging/stringtable.xml index 9552f50273..c2f96ce55a 100644 --- a/addons/dragging/stringtable.xml +++ b/addons/dragging/stringtable.xml @@ -167,6 +167,7 @@ Autoriser la course avec des objets légers Permitir corrida com objetos leves Позволяет работать с легкими объектами + Permitir correr con objetos ligeros Allow the player to run when carrying lightweight objects. @@ -178,6 +179,7 @@ Autorise le joueur à courir lorsqu'il porte un objet léger. Permite ao jogador correr enquanto carrega objetos leves. Разрешите игроку бегать при переноске легких предметов. + Permite al jugador correr cuando porta objetos ligeros. Skip Object Weight @@ -189,6 +191,7 @@ Ignorer le poids de l'objet Ignorar Peso do Objeto Игнорировать вес объекта + Ignora peso del objeto Determines whether object's weight is added onto weight calculations. @@ -200,6 +203,7 @@ Défini si le poids d'un objet est ajouté aux calculs du poids. Determina se o peso do objeto é adicionado aos cálculos de peso. Определяет, добавляется ли вес объекта при расчете веса. + Determina si el peso del objeto es añadido en los cálculos de peso. Max Weight Coefficient @@ -210,6 +214,7 @@ Maximaler Gewichtskoeffizient 最大重量係数 Максимальный коэффициент веса + Máximo Coeficiente de Peso Modifies weight limit calculations. Set to 0 to ignore. @@ -220,6 +225,7 @@ Ändert die Berechnung der Gewichtsbegrenzung. Zum Ignorieren auf 0 setzen. 重量制限の計算を変更します。 無視するには 0 に設定します。 Изменяет расчеты предельного веса. Установите значение 0 для игнорирования. + Modifica el límite de peso de los cálculos. Poner a 0 para que lo ignore. diff --git a/addons/explosives/stringtable.xml b/addons/explosives/stringtable.xml index fccc685c4f..168a830254 100644 --- a/addons/explosives/stringtable.xml +++ b/addons/explosives/stringtable.xml @@ -76,6 +76,7 @@ 選択した点火装置を全て起爆 활성화된 격발기의 모든 것을 폭파 Détoner tout sur le détonateur actif + Detonar Todos al Activar el detonador Set Active Clacker @@ -85,6 +86,7 @@ この点火装置を選択 격발기 활성 설정 Définir le détonateur actif + Establecer el Detonador Activo Cycle Active Clacker @@ -94,6 +96,7 @@ 点火装置を切り替え 격발기 활성 전환 Modifier le détonateur actif + Ciclar el Detonador Activo Active Clacker @@ -103,6 +106,7 @@ 選択中の点火装置 격발기 활성 Détonateur actif + Activar Detonador Explosive code: %1 diff --git a/addons/fastroping/stringtable.xml b/addons/fastroping/stringtable.xml index b68da23d28..10ea50a7c5 100644 --- a/addons/fastroping/stringtable.xml +++ b/addons/fastroping/stringtable.xml @@ -325,6 +325,7 @@ Equipement automatique FRIES Auto-equipar FRIES Авто-подготовка канатов + Auto-Equipar FRIES Automatically add FRIES to helicopters that support them. @@ -336,6 +337,7 @@ Ajoute automatiquement des FRIES aux hélicoptères qui les supportent. Adiciona automaticamente FRIES a helicópteros que os suportam. Автоматически добавляйте канаты в вертолеты, которые их поддерживают. + Añadir automáticamente el FRIES a los helicópteros que lo soporten. diff --git a/addons/fieldmanual/stringtable.xml b/addons/fieldmanual/stringtable.xml index 05c7414f17..98756c4910 100644 --- a/addons/fieldmanual/stringtable.xml +++ b/addons/fieldmanual/stringtable.xml @@ -28,6 +28,7 @@ 空腹 Голод Faim + Hambre %3Hunger%4 increases linearly with soldier's movement speed. Restore by eating food.<br/><br/>%3Usage:%4<br/>%2Pick up food.<br/>%2Use [%3%12%4] and select %3Survival%4.<br/>%2Choose an item to consume. @@ -39,6 +40,7 @@ %3空腹度%4は兵士の移動速度に比例して増加します。食べ物を食べることで回復します。<br/><br/>%3使用方法:%4<br/>%2食べ物を持つ。<br/>%2[%3%12%4] を使って%3サバイバル%4を選択。<br/>%2食べたいものを選ぶ。 %3Голод%4 линейно увеличивается со скоростью передвижения солдата. Восстанавливайтесь, употребляя пищу.<br/><br/>%3 Использование:%4<br/>%2Возьмите еду.<br/>%2Используйте [%3%12%4] и выберите %3Выживание% 4.<br/>%2Выберите продукт для потребления. %3La faim%4 augmente linéairement avec la vitesse de déplacement du soldat. Il se régénère en consommant de la nourriture.<br/><br/>%3Utilisation:%4<br/>%2Ramasser la nourriture.<br/>%2Utilisez [%3%12%4] et sélectionnez %3Survie%4.<br/>%2Choisissez un article à consommer. + El %3Hambre%4 aumenta linealmente con los movimientos del soldado. Se reestablece comiendo comida.<br/><br/>%3Uso:%4<br/>%2Coger comida.<br/>%2Usar [%3%12%4] y seleccionar %3Sobrevivir%4.<br/>%2Elegir un objeto para consumir. Thirst @@ -50,6 +52,7 @@ 渇き Жажда Soif + Sed %3Thirst%4 increases linearly with soldier's movement speed. Restore by drinking liquids.<br/><br/>%3Usage:%4<br/>%2Pick up a drink.<br/>%2Use [%3%12%4] and select %3Survival%4.<br/>%2Choose an item to consume. @@ -61,6 +64,7 @@ %3喉の渇き%4は兵士の移動速度に比例して増加します。飲み物を飲むことで回復します。<br/><br/>%3使用方法:%4<br/>%2飲み物を持つ。<br/>%2[%3%12%4] を使って%3サバイバル%4を選択。<br/>%2飲みたいものを選ぶ。 %3Жажда%4 линейно увеличивается со скоростью передвижения солдата. Восстанавливайтесь, употребляя напитки.<br/><br/>%3 Использование:%4<br/>%2Возьмите напиток.<br/>%2Используйте [%3%12%4] и выберите %3Выживание% 4.<br/>%2Выберите напиток для потребления. %3La soif%4 augmente linéairement avec la vitesse de déplacement du soldat. Elle se régénère en buvant des liquides.<br/><br/>%3Utilisez [%3%12%4] et choisissez %3survival%4.<br />%2Choisissez un article à boire. + La %3Sed%4 aumenta linealmente con la velocidad de movimiento del soldado. Se restaura bebiendo líquidos.<br/><br/>%3Uso:%4<br/>%2Selecciona una bebida.<br/>%2Usar [%3%12%4] y seleccionar %3Sobrevivir%4.<br/>%2Elegir un objeto para consumir. Medical Treatment @@ -72,6 +76,7 @@ 治療 Медицинское лечение Traitement médical + Tratamiento Médico Decrease Heart Rate @@ -83,6 +88,7 @@ 心拍数を下げる Уменьшить частоту сердечных сокращений Diminution de la fréquence cardiaque + Disminuir Ritmo Cardíaco %3Adenosine%4 is used to decrease heart rate.<br/><br/>%3Usage:%4<br/>%2Use [%3%13%4] or [%3%14%4] and select an appendage.<br/>%2Inject %3Adenosine%4. @@ -94,6 +100,7 @@ %3アデノシン%4は心拍数を下げるのに使われます。<br/><br/>%3使用方法:%4<br/>%2[%3%13%4] または [%3%14%4] を使って四肢を選択します。<br/>%2そして%3アデノシン%4を注射します。 %3Аденозин%4 используется для снижения частоты сердечных сокращений.<br/><br/>%3Применение:%4<br/>%2Используйте [%3%13%4] или [%3%14%4] и выберите конечность.<br/>%2Введите %3Аденозин%4. L'%3adénosine%4 est utilisée pour réduire la fréquence cardiaque.<br/><br/>%3Utilisation:%4<br/>%2Utilisez [%3%13%4] ou [%3%14%4] et sélectionnez un membre.<br/>%2Injectez l'%3Adénosine%4. + La %3Adenosina%4 se usa para disminuir el ritmo cardíaco.<br/><br/>%3Uso:%4<br/>%2Uso [%3%13%4] o [%3%14%4] y selecciona una extremidad.<br/>%2Inyectar %3Adenosina%4. Bandages @@ -105,6 +112,7 @@ 包帯 Бинты Pansements + Vendas Close Wounds @@ -116,6 +124,7 @@ 傷口をふさぐ Закрыть раны Fermer les plaies + Cerrar Heridas %3Bandages%4 stop bleeding and close wounds. Depending on your settings, bandages may reopen if surgery is not performed.<br/><br/>%2%3Field Dressing:%4<br/>%11<t color='#D9D900'>Average</t> In All Categories<br/>%2%3Packing Bandage:%4<br/>%11<t color='#D9D900'>Average</t> Treatment<br/>%11<t color='#E60000'>Higher</t> Reopen Chance<br/>%11<t color='#00CC00'>Longer</t> Reopen Delay<br/>%2%3Elastic Bandage:%4<br/>%11<t color='#00CC00'>Higher</t> Treatment<br/>%11<t color='#E60000'>Higher</t> Reopen Chance<br/>%11<t color='#E60000'>Shorter</t> Reopen Delay<br/>%2%3Quickclot:%4<br/>%11<t color='#E60000'>Lower</t> Treatment<br/>%11<t color='#00CC00'>Lower</t> Reopen Chance<br/>%11<t color='#00CC00'>Longer</t> Reopening Delay<br/><br/>%3Usage:%4<br/>%2Use [%3%13%4] or [%3%14%4] and select a injured body part.<br/>%2Bandage body part by selecting desired %3Bandage%4 type. @@ -125,6 +134,7 @@ %3Verbände%4 stoppen Blutungen und schließen Wunden. Abhängig von Ihren Einstellungen können sich Verbände wieder öffnen, wenn keine Operation durchgeführt wird.<br/><br/>%2%3Einfache Bandage:%4<br/>%11<t color='#D9D900'>Durchschnittlich</t> In allen Kategorien<br/>%2%3Mullbinde:%4<br/>%11<t color='#D9D900'>Durchschnittliche</t> Behandlung<br/>%11<t color='#E60000' >Höhere</t> Wiedereröffnungswahrscheinlichkeit<br/>%11<t color='#00CC00'>Längere</t> Wiedereröffnungsverzögerung<br/>%2%3Elastischer Verband:%4<br/>%11<t color='#00CC00'>Längere</t> Behandlung<br/>%11<t color='#E60000'>Höhere</t> Chance auf Wiedereröffnung<br/>%11<t color='#E60000'> Kürzere</t> Wiedereröffnungsverzögerung<br/>%2%3Quickclot:%4<br/>%11<t color='#E60000'>Kürzere</t> Behandlung<br/>%11<t color=' #00CC00'>Geringere</t> Wiedereröffnungswahrscheinlichkeit<br/>%11<t color='#00CC00'>Längere</t> Wiedereröffnungsverzögerung<br/><br/>%3Verwende:%4<br/> %2Verwenden Sie [%3%13%4] oder [%3%14%4] und wähle ein verletztes Körperteil aus.<br/>%2Verbinde ein Körperteil, indem der gewünschte %3Bandagen%4-Typ ausgewählt wurde. %3Bende%4 fermano emorragie e chiudono ferite. A seconda delle tue impostazioni, ferite bendate potrebbero riaprirsi se non suturate.<br/><br/>%2%3Bendaggio Basico:%4<br/>%11<t color='#D9D900'>Media</t> In tutte le categorie<br/>%2%3Bendaggio Compressivo:%4<br/>%11<t color='#D9D900'>Media</t> Trattamenti<br/>%11<t color='#E60000'>Alta</t> Probabilità di riapertura<br/>%11<t color='#00CC00'>Lungo</t> Tempo di riapertura<br/>%2%3Bendaggio Elastico:%4<br/>%11<t color='#00CC00'>Alto</t> Trattamento<br/>%11<t color='#E60000'>Alto</t> Probabilità di riapertura<br/>%11<t color='#E60000'>Breve</t> Tempo di riapertura<br/>%2%3Quickclot:%4<br/>%11<t color='#E60000'>Basso</t> Trattamento<br/>%11<t color='#00CC00'>Basso</t> Probabilità di riapertura<br/>%11<t color='#00CC00'>Lungo</t> Tempo di riapertura<br/><br/>%3Utilizzo:%4<br/>%2Usa [%3%13%4] o [%3%14%4] seleziona una parte del corpo ferita.<br/>%2Benda la parte del corpo ferita selezionando la %3Benda%4 desiderato. %3包帯%4は傷口をとじて出血を止めます。設定によっては、手術を行わないと包帯が解けて傷が再開放し出血が再開する場合があります。<br/><br/>%2%3緊急圧迫包帯:%4<br/>%11<t color='#D9D900'>平均的な</t> 全体性能を持っています<br/>%2%3弾性包帯:%4<br/>%11<t color='#D9D900'>平均的な</t> 治療効果<br/>%11<t color='#E60000'>高い</t> 再解放の可能性<br/>%11<t color='#00CC00'>長い</t> 再解放の再計算間隔<br/>%2%3伸縮包帯:%4<br/>%11<t color='#00CC00'>高い</t> 治療効果<br/>%11<t color='#E60000'>高い</t> 再解放の可能性<br/>%11<t color='#E60000'>短い</t> 再解放の再計算間隔<br/>%2%クイッククロット:%4<br/>%11<t color='#E60000'>低い</t> 治療効果<br/>%11<t color='#00CC00'>低い</t> 再解放の可能性<br/>%11<t color='#00CC00'>長い</t> 再解放の再計算間隔<br/><br/>%3使用方法:%4<br/>%2[%3%13%4] または [%3%14%4] を使って身体の負傷個所を選択します。<br/>%2希望の%3包帯%4の種類を選択して部位に包帯を巻きます。 + Las %3Vendas%4 paran el sangrado y cierran las heridas. Dependiendo de las opciones configuradas, las heridas pueden reabrirse si no se realiza cirugía.<br/><br/>%2%3Vendaje de campaña:%4<br/>%11<t color='#D9D900'>Medio</t> en todas las categorias<br/>%2%3Vendaje compresivo:%4<br/>%11<t color='#D9D900'>Medio</t> Tratamiento<br/>%11<t color='#E60000'>Alto</t> Probabilidad de Reapertura<br/>%11<t color='#00CC00'>Larga</t> Retardo en reapertura<br/>%2%3Vendaje elástico:%4<br/>%11<t color='#00CC00'>Alto</t> Tratamiento<br/>%11<t color='#E60000'>Alto</t> Probabilidad de reapertura<br/>%11<t color='#E60000'>Corto</t> Retardo en reapertura<br/>%2%3Quickclot:%4<br/>%11<t color='#E60000'>Bajo</t> Tratamiento<br/>%11<t color='#00CC00'>Bajo</t> Probabilidad de Reapertura<br/>%11<t color='#00CC00'>Larga</t> Retardo en reapertura<br/><br/>%3Uso:%4<br/>%2Uso [%3%13%4] o [%3%14%4] y selecciona una parte del cuerpo herida.<br/>%2Venda la parte del cuerpo seleccionada eligiendo el tipo de %3Venda%4. IV Fluids @@ -135,6 +145,7 @@ Fluidi EV IV 輸液 IV Fluides + Fluidos IV Restore Blood Volume @@ -146,6 +157,7 @@ 血液量を回復する Внутривенные жидкости Restaurer le volume sanguin + Reestablece el volumen de sangre %3IV fluids%4 restore lost blood volume. Blood, Plasma, and Saline are functionally the same.<br/><br/>%3Usage:%4<br/>%2Use [%3%13%4] or [%3%14%4] and select an appendage.<br/>%2Restore blood volume by selecting desired %3IV Fluid%4 type. @@ -156,6 +168,7 @@ %3Fluidi EV%4 ristorano volume di sangue perso. Sangue, Plasma, e Salina sono funzionalmente identiche.<br/><br/>%3Utilizzo:%4<br/>%2Usa [%3%13%4] o [%3%14%4] e seleziona un arto.<br/>%2Ristora il volume di sangue selezionando il tipo di %3Fluido EV%4 desiderato. %3IV 輸液%4は失われた血液を回復します。血液、血漿、生理食塩水は機能的には同じです。<br/><br/>%3使用方法:%4<br/>%2[%3%13%4] または [%3%14%4] を使って四肢を選択します。<br/>%2希望の%3IV 輸液%4の種類を選択して、血液量を復元します。 %%3Внутривенные жидкости%4восстанавливают потерянный объем крови. Кровь, плазма и физраствор функционально идентичны.<br/><br/>%3 Использование:%4<br/>%2 Используйте [%3%13%4] или [%3%14%4] и выберите добавку.<br/>%2 Восстановите объем крови выбрав желаемый %4тип %3жидкости + Los %3Fluidos IV%4 restauran el volumen de sangre. Sangre, Plasma, y Salino funcionan de manera similar.<br/><br/>%3Uso:%4<br/>%2Uso [%3%13%4] o [%3%14%4] y seleccionar una extremidad.<br/>%2Restaura el volumen de sangre seleccionando el tipo de %3Fluido IV%4 elegido. Increase Heart Rate | Wake Up Faster @@ -167,6 +180,7 @@ 心拍数を上げる | はやく起こす Увеличьте частоту сердечных сокращений | просыпайтесь быстрее Augmentation de la fréquence cardiaque - Réveil plus rapide + Incrementa el ritmo cardíaco | Despierta más rápido %3Epinephrine%4 increases a patient's pulse as well as potentially decreasing the time between consciousnesss checks (effectively reducing the time needed for the patient to wake up).<br/><br/>%3Usage%4<br/>%2Use [%3%13%4] or [%3%14%4] and select an appendage.<br/>%2Inject %3Epinephrine%4. @@ -176,6 +190,7 @@ %3Epinephrine%4 erhöht den Puls eines Patienten und verkürzt möglicherweise die Zeit zwischen Bewusstseinskontrollen (wodurch die Zeit, die der Patient zum Aufwachen benötigt, effektiv verkürzt wird).<br/><br/>%3Verwendung%4<br/>%2Verwende [%3%13%4] oder [%3%14%4] und wählen ein Körperteil aus.<br/>%2Injiziere %3Epinephrine%4. %3Epinefrina%4 aumenta il ritmo cardiaco di un paziente e riduce potenzialmente gli intervalli tra verifiche di coscienza (effettivamente riducendo il tempo necessario che questo paziente si svegli).<br/><br/>%3Utilizzo%4<br/>%2Usa [%3%13%4] o [%3%14%4] e seleziona un arto.<br/>%2Inietta %3Epinefrina%4. %3アドレナリン%4は、患者の脈拍を増加させるだけでなく、意識チェックの間隔を短縮する可能性があります。 (患者が目覚めるまでに必要な時間を効果的に短縮します)<br/><br/>%3使用方法%4<br/>%2[%3%13%4] または [%3%14%4] を使って四肢を選択します。<br/>%2%3アドレナリン%4を注射します。 + La %3Epinefrina%4 aumenta el pulso del paciente así como potencialmente disminuye el tiempo entre las comprobaciones sobre consciencia (reduciendo de manera efectiva el tiempo de despertar del paciente).<br/><br/>%3Uso%4<br/>%2Usa [%3%13%4] o [%3%14%4] y selecciona una extremidad.<br/>%2Inyecta %3Epinefrina%4. Restore Like New @@ -187,6 +202,7 @@ 生まれたてのように回復する Лечение тела Remettre comme neuf + Restaurar como nuevo The %3Personal Aid Kit%4 is an item that allows a soldier to be fully healed. Independent of %3ACE Settings%4, it requires that the patient is in %3Stable Condition%4 before use.<br/><br/>%3Stable Condition%4 qualifies as:<br/>%2Unit is %3Alive%4.<br/>%2Unit is %3Conscious%4.<br/>%2Unit has no active %3Bleeding%4.<br/>%2Heart Rate >= 40.<br/>%2Systolic BP >= 60.<br/>%2Diastolic BP >= 50.<br/><br/>%3Usage:%4<br/>%2Move to appropriate location depending on %3ACE Settings%4.<br/>%2Use [%3%13%4] or [%3%14%4] and select %3Advanced Treatments%4<br/>%2Select %3Use Personal Aid Kit%4. @@ -196,6 +212,7 @@ Das %3Persönliche Erste Hilfe Kit%4 ist ein Gegenstand, der es einem Soldaten ermöglicht, vollständig geheilt zu werden. Unabhängig von den %3ACE-Einstellungen%4 ist es erforderlich, dass sich der Patient vor der Verwendung in einem %3stabilen Zustand%4 befindet.<br/><br/>%3Stabiler Zustand%4 gilt wenn:<br/>%2Einheit ist %3am Leben%4 .<br/>%2Einheit ist %3Bei Bewusstsein%4.<br/>%2Einheit hat keine aktive %3Blutung%4.<br/>%2Herzfrequenz >= 40.<br/>%2Systolischer Blutdruck >= 60.< br/>%2Diastolischer Blutdruck >= 50.<br/><br/>%3Verwende:%4<br/>%2Bewege den Patienten je nach %3ACE-Einstellungen%4 an den entsprechenden Ort.<br/>%2Verwende [%3% 13%4] oder [%3%14%4] und wähle %3Erweiterte Behandlungen%4<br/>%2Wähle %3Persönliche Erste Hilfe Kit verwenden%4. Il %3Kit di Pronto Soccorso%4 è un oggetto che permette di curare completamente un soldato, indipendentemente da %3impostazioni ACE%4, richiede che il paziente sia in %3condizione stabile%4 prima dell'utilizzo.<br/><br/>%3Condizione stabile%4 significa:<br/>%2Paziente è %3Vivo%4.<br/>%2Paziente è %3Conscio%4.<br/>%2Paziente non sta %3Sanguinando%4.<br/>%2Ritmo cardiaco >= 40.<br/>%2Sistolico BC >= 60.<br/>%2Diastolico BC >= 50.<br/><br/>%3Utilizzo:%4<br/>%2Sposta in luogo specifico a seconda delle %3impostazioni ACE%4.<br/>%2Usa [%3%13%4] o [%3%14%4] e seleziona %3Trattamenti avanzati%4<br/>%2Seleziona %3Usa Kit di Pronto Soccorso%4. %3個人用治療キット%4は、兵士を完全に回復できるアイテムです。使用時には%3ACE 設定%4と関係なく、対象の患者が%3安定状態%4である必要があります。<br/><br/>%3安定状態%4とは次の状態です:<br/>%2ユニットが %3生存%4している。<br/>%2ユニットが %3覚醒状態%4である。<br/>%2ユニットが %3出血状態%4ではない。<br/>%2心拍数が40以上。<br/>%2収縮期血圧が60以上。<br/>%2拡張期血圧が50以上。<br/><br/>%3使用方法:%4<br/>%2%3ACE 設定%4で使用が許可された場所へ移動する。<br/>%2[%3%13%4] または [%3%14%4] を使って%3高度な治療%4を選択する。<br/>%2%3個人用治療キットを使う%4を選択して使用します。 + El %3Kit de Primeros Auxilios%4 es un objeto que permite al soldado ser curado totalmente. Independientemente de las %3Opciones de ACE%4, requiere que el paciente esté en %3Condición Estable%4 antes de usarse.<br/><br/>%3Condición Estable%4 significa que:<br/>%2La unidad está %3Viva%4.<br/>%2La unidad está %3Consciente%4.<br/>%2La unidad no está %3Sangrando%4.<br/>%2Ritmo Cardíaco >= 40.<br/>%2Presión Sistólica >= 60.<br/>%2Presión Diastólica >= 50.<br/><br/>%3Uso:%4<br/>%2Mover al lugar adecuado dependiendo de las%3Opciones de ACE%4.<br/>%2Uso [%3%13%4] o [%3%14%4] y seleccionar %3Tratamientos Avanzados%4<br/>%2Seleccionar %3Usar Kit de Primeros Auxilios%4. Fix Fractures @@ -207,6 +224,7 @@ 骨折を治す Исправлять переломы Réparation des fractures + Curar Fracturas A %3Splint%4 is used to fix fractures. The %3Splint%4 is consumed when used.<br/><br/>%3Usage:%4<br/>%2Use [%3%13%4] or [%3%14%4] and select an affected appendage.<br/>%2Select %3Apply Splint%4. @@ -216,6 +234,7 @@ Ein %3Splint%4 wird zur Fixierung von Frakturen verwendet. Der %3Splint%4 wird bei Verwendung verbraucht.<br/><br/>%3Verwendung:%4<br/>%2Verwende [%3%13%4] oder [%3%14%4] und wählen ein Körperteil aus.<br/>%2Wähle %3Schiene verwenden%4. Una %3Gessatura%4 è usata per risolvere fratture. La %3Gessatura%4 è consumata quando usata.<br/><br/>%3Utilizzo:%4<br/>%2Usa [%3%13%4] o [%3%14%4] e seleziona un arto afflitto.<br/>%2Seleziona %3Applica Gessatura%4. %3添え木%4は骨折の治療に使います。%3添え木%4は使用時に消費します。<br/><br/>%3使用方法:%4<br/>%2[%3%13%4] または [%3%14%4] を使って使用したい四肢を選択します。<br/>%2%3添え木を当てる%4を選択して使用します。 + La %3Férula%4 se utiliza para curar fracturas. La %3Férula%4 se consume cuando es usada.<br/><br/>%3Uso:%4<br/>%2Usar [%3%13%4] o [%3%14%4] y seleccionar la extremidad adecuada.<br/>%2Seleccionar %3Aaplicar Férula%4. Prevent Wounds From Reopening @@ -226,6 +245,7 @@ 傷口が開くのを防ぐ Предотвратить повторное открытие ран Empêcher la réouverture des plaies + Prevenir la reapertura de heridas A %3Surgical Kit%4 is used to prevent wounds from reopening after being bandaged. Depending on settings, it can also clear trauma and may require additional %3Sutures%4 to close wounds. Sutures are consumable, much like bandages, and are not a replacement for the Surgical Kit.<br/><br/>%3Usage:%4<br/>%2Use [%3%13%4] or [%3%14%4] and select %3Advanced Treatment%4.<br/>%2Select %3Use Surgical Kit%4. @@ -234,6 +254,7 @@ O %3Kit Cirúrgico%4 é utilizado para prevenir a reabertura de feridas após a aplicação de bandagens. A depender das configurações, ele também pode remover traumas e pode requerir %3Suturas%4 adicionais para fechar feridas. Suturas são consumíveis, tal como as bandagens, e não são substituem o Kit Cirúrgico.<br/><br/>%3Uso:%4<br/>%2Utilize [%3%13%4] ou [%3%14%4] e selecione %3Tratamento Avançado%4.<br/>%2Selecione %3Usar Kit Cirúrgico%4. Un %3Kit Chirurgico%4 è usato per impedire che ferite bendate si riaprano. A seconda delle impostazioni, può anche azzerare danni o potrebbe richiedere %3Suture%4 aggiuntive per chiudere ferite. Suture sono consumabili proprio come bende, non sono un sostituto per un Kit Chirurgico.<br/><br/>%3Utilizzo:%4<br/>%2Usa [%3%13%4] o [%3%14%4] e seleziona %3Trattamenti Avanzati%4.<br/>%2Seleziona %3Usa Kit Chirurgico%4. %3手術キット%4は包帯を巻いた傷口が再度開いて出血するのを防ぎます。設定によっては、負傷を取り除いたり、傷口を閉じるのに%3糸付縫合針%4を必要としたりします。糸付縫合針は消耗品で包帯のように使用され、手術キットを代替するものではありません。<br/><br/>%3使用方法:%4<br/>%2[%3%13%4] または [%3%14%4] を使って%3高度な治療%4を選択する。<br/>%2%3手術キット%4を選択して使用します。 + El %3Kit Quirúrgico%4 se usa para prevenir la reapertura de heridas despues de ser vendadas. Dependiendo de las opciones, tambien puede curar traumatismos y puede requerir %3Sutura%4 adicional para cerrar las heridas. Las Suturas son consumibles, al igual que las vendas, y no son un reemplazo para el Kit Quirúgico.<br/><br/>%3Uso:%4<br/>%2Usar [%3%13%4] o [%3%14%4] y seleccionar %3Tratamientos Avanzados%4.<br/>%2Seleccionar %3Usar Kit Quirúgico%4. Stop Bleeding @@ -244,6 +265,7 @@ 出血を止める Остановить кровотечение Arrêter les saignements + Parar Sangrado A %3Tourniquet%4 stops bleeding temporarily so that a wound(s) can be bandaged. Can only be used on limbs.<br/><br/>%3Usage:%4<br/>%2Use [%3%13%4] or [%3%14%4] and select an affected appendage.<br/>%2Select %3Apply Tourniquet%4. @@ -252,6 +274,7 @@ O %3Torniquete%4 interrompe o sangramento temporariamente, para que feridas possam ser enfaixadas. Seu uso é restrito aos membros.<br/><br/>%3Uso:%4<br/>%2Utilize [%3%13%4] ou [%3%14%4] e selecione um membro afetado.<br/>%2Selecione %3Aplicar Torniquete%4. Un %3Laccio Emostatico%4 ferma emorragie temporaneamente in modo da poter bendare ferite con calma. Utilizzabile su arti.<br/><br/>%3Utilizzo:%4<br/>%2Usa [%3%13%4] o [%3%14%4] e seleziona un arto afflitto.<br/>%2Seleziona %3Applica Laccio Emostatico%4. %3止血帯%4は一時的に出血を止め、その間に傷に包帯を巻くことができます。四肢にのみ使用できます。<br/><br/>%3使用方法:%4<br/>%2[%3%13%4] または [%3%14%4] を使って使用したい四肢を選択します。<br/>%2%3止血帯を巻く%4を選択して使用します。 + El %3Torniquete%4 para temporalmente el sangrado hasta que la herida sea vendada. Sólo puede ser usado en extremidades.<br/><br/>%3Uso:%4<br/>%2Usar [%3%13%4] o [%3%14%4] y seleccionar la extremidad afectada.<br/>%2Seleccionar %3Aplicar Torniquete%4. Medical Menu @@ -277,6 +300,7 @@ Tratamento, Simplificado 治療を簡略化する Traitement, simplifié + Tratamiento, Simplificado The %3Medical Menu%4 is a dedicated %3interface%4 to facilitate %3medical treatment%4. The %3R%4 and %3L%4 letters indicate the side of the patient's body being treated.<br/><br/>%3Usage:%4<br/>%2Use [%3%14%4] while looking at a patient to open the Medical Menu. Opening the menu without a patient allows for self-treatment.<br/>%2Alternatively, use [%3%12%4] or [%3%13%4] and select %3Medical Menu%4.<br/><br/>%3Keybinds:%4<br/>%2Use [%3W, A, S, D, X, and Z%4] to select body parts.<br/>%2Use your %3number keys%4 to select treatment categories. @@ -285,6 +309,7 @@ O %3Menu Médico%4 é uma %3interface%4 dedicada a facilitar o %3tratamento médico%4. As letras %3R%4 e %3L%4 indicam o lado do corpo do paciente que está recebendo o tratamento.<br/><br/>%3Uso:%4<br/>%2Utilize [%3%14%4] enquanto olha o paciente para abrir o Menu Médico. Se não houver paciente, o menu será de auto-tratamento.<br/>%2Alternativamente, utilize [%3%12%4] ou [%3%13%4] e selecione %3Menu Médico%4.<br/><br/>%3Atalhos de teclado:%4<br/>%2Utilize [%3W, A, S, D, X, e Z%4] para selecionar partes do corpo.<br/>%2Utilize as %3teclas numéricas%4 para selecionar as categorias de tratamento. Il %3Menù Medico%4 è un'%3interfaccia%4 dedicata a facilitare %3trattamenti medici%4. Le lettere %3Dx%4 e %3Sx%4 contrassegnano i lati del corpo del paziente che si stanno medicando.<br/><br/>%3Utilizzo:%4<br/>%2Usa [%3%14%4] guardando il paziente per aprire il Menù Medico. Aprire il menù senza paziente di fronte permette l'automedicazione.<br/>%2In alternativa, usa [%3%12%4] o [%3%13%4] e seleziona %3Menù Medico%4.<br/><br/>%3Comandi:%4<br/>%2Usa [%3W, A, S, D, X, and Z%4] per selezionare parti del corpo.<br/>%2Usa %3tasti numerici%4 per selezionare categorie di cure. %3医療メニュー%4は%3治療%4をしやすくするための専用%3インターフェース%4です。%3右%4と%3左%4の文字は治療を受ける患者の向きを表しています。<br/><br/>%3使用方法:%4<br/>%2[%3%14%4] を患者に視点を合わせながら押すことで患者の医療メニューを開けます。視点を合わせないで押すと、自分の医療メニューを開くことが出来ます。<br/>%2もしくは [%3%12%4] または [%3%13%4] を使って%3医療メニュー%4を選択します。<br/><br/>%3キーバインド:%4<br/>%2[%3W, A, S, D, X, と Zキー%4] を使って身体の部位を選択できます。<br/>%2%3数字キー%4を使って治療項目を選択できます。 + El %3Menú Médico%4 es una %3interfaz%4 dedicada para facilitar el %3tratamiento médico%4. Las letras %3R%4 and %3L%4 indican el lado del paciente siendo tratado.<br/><br/>%3Uso:%4<br/>%2Usar [%3%14%4] mientras se mira al paciente para abrir el Menú Médico. Abrir el menú sin mirar a un paciente permite el tratamiento a uno mismo. <br/>%2Alternativamente, usar [%3%12%4] o [%3%13%4] y seleccionar %3Menú Médico%4.<br/><br/>%3Teclas asociadas:%4<br/>%2Usar [%3W, A, S, D, X, and Z%4] para seleccionar las partes del cuerpo.<br/>%2Usar las %3teclas numéricas%4 para seleccionar las categorías de tratamiento. Portable, Precise, Rugged @@ -294,6 +319,7 @@ Leggero, Preciso, Robusto 高機動、高精度、高耐久 Portable, précis, robuste + Portable, Preciso, Robusto The %3Horus ATragMX%4 considers atmospheric conditions, gun data, ammunition, range, speed, and muzzle velocity to calculate precise aiming solutions with %3Come-Up%4 results - and even accounts for %3Coriolis%4 and %3Spin Drift%4 effects. %3ATragMX%4, loaded on a handheld computer made by %3TDS Recon%4, is easy to use and lightning fast. The %3Recon%4 meets the rigorous %3MIL-STD-810F%4 military standard for drops, vibration, humidity, altitude and extreme temperatures.<br/><br/>%3Usage:%4<br/>Please visit the wiki page for more information. @@ -302,6 +328,7 @@ O %3Horus ATragMX%4 considera condições atmosféricas, dados de armas, munição, alcance, e velocidade do projétil - e até os efeitos Coriolis e Spin - para calcular as configurações necessárias da mira. O %3ATragMX%4, carregado em um computador portátil feito pela %3TDS Recon%4, é rápido e fácil de usar. O %3Recon%4 satisfaz os rigorosos padrões militares %3MIL-STD-810F%4 para quedas, vibrações, umidade, altitude e temperaturas extremas.<br/><br/>%3Uso:%4<br/>Por favor, visite a wiki para mais informações. L'%3Horus ATragMX%4 tiene conto di condizioni atmosferiche, caratteristiche del fucile, munizioni, portata e velocità alla volata per calcolare precise impostazioni di mira con risultati %3Come-Up%4 - considerando anche effetti %3Coriolis%4 e %3Magnus%4. L'%3ATragMX%4, caricato su un computer portabile %3TDS Recon%4, è facile da usare e molto rapido nei calcoli. Il %3Recon%4 soddisfa i rigorosi standard militari %3MIL-STD-810F%4 per cadute, vibrazioni, umidità, altitudine e temperature estreme.<br/><br/>%3Utilizzo:%4<br/>Visitate la pagina wiki per ulteriori informazioni. %3ホルス ATragMX%4は、大気条件、銃のデータ、弾薬、射程、速度、および初速を考慮した%3最適な結果が得られる%4正確な照準のための計算とその解法を提供します。さらに、%3コリオリ効果%4および%3スピン ドリフト効果%4も考慮します。%3ATragMX%4は%3TDS Recon製%4の携帯コンピュータに読み込まれており、使いやすく、超高速です。%3Recon%4はは、落下、振動、湿度、高度、極端な温度に関する厳格な%3MIL-STD-810F%4軍事規格を満たしています。<br/><br/>%3使用方法:%4<br/>詳細については、Wiki ページを参照してください。 + El %3Horus ATragMX%4 tiene en cuenta las condiciones atmosféricas, datos del arma, munición, distancia, velocidad y velocidad en boca para calcular con precisión soluciones de tiro precisas con %3Resultados%4 - e incluso tiene en cuenta los efectos %3Coriolis%4 y %3Movimiento Giroscópico%4. %3ATragMX%4, cargado en un ordenador portátil fabricado por %3TDS Recon%4, es facil de usar y muy rápido. El %3Recon%4 cumple con los rigurosos estándares militares %3MIL-STD-810F%4 en cuanto a caidas, vibraciones, humedad, altitud y temperaturas extremas.<br/><br/>%3Uso:%4<br/>Por favor, visita la página de la Wiki para más información. Bring Out Your Dead @@ -311,6 +338,7 @@ Recupera i tuoi morti 死者を連れ出す Récupérez vos morts + Trae de vuelta a los muertos %3Body Bags%4 are used to transport dead bodies. They can be dragged and loaded into vehicles.<br/><br/>%3Usage:%4<br/>%2Approach a dead body.<br/>%2Use [%3%13%4] or [%3%15%4] and select %3Place Body In Bodybag%4. @@ -319,6 +347,7 @@ OS %3Sacos de Cadáver%4 são utilizados para transportar cadáveres. Eles podem ser arrastados e embarcados em veículos.<br/><br/>%3Uso:%4<br/>%2Aproxime-se de um cadáver.<br/>%2Utilize [%3%13%4] ou [%3%15%4] e selecione %3Colocar cadáver dentro do saco%4. %3Sacche per cadaveri%4 sono usate per trasportare i morti. Possono essere trascinate e caricate su veicoli.<br/><br/>%3Utilizzo:%4<br/>%2Avvicinati ad un morto.<br/>%2Usa [%3%13%4] o [%3%15%4] e seleziona %3Metti il corpo nella sacca per cadaveri%4. %3遺体袋%4は、遺体の輸送に使用されます。引きずって車両に積み込むことができます。<br/><br/>%3使用方法:%4<br/>%2遺体に近寄る。<br/>%2[%3%13%4] または [%3%15%4] を使って%3遺体袋に入れる%4を選択して使用します。 + Las %3Bolsas para Cadáveres%4 se usan para transportar cadáveres. Pueden ser arrastradas y cargadas en vehículos. <br/><br/>%3Uso:%4<br/>%2Acercarse a un cadáver.<br/>%2Usar [%3%13%4] o [%3%15%4] y seleccionar %3Colocar cuerpo en la Bolsa para Cadáveres%4. Take Prisoners @@ -328,6 +357,7 @@ Prendi prigionieri 捕虜の捕り方 Faire des prisonniers + Tomar prisioneros %3Cable Ties%4 enable a soldier to capture and detain another soldier. Once apprehended, the captor gains the ability to inspect the prisoner's belongings, set them free, or accompany them to an alternate area. Transporting escorted prisoners is also possible, including loading them into vehicles if needed. Depending on your settings, units may need to surrender before being taken captive.<br/><br/>%3Usage:%4<br/>%2Approach the unit and use the [%3%13%4].<br/>%2The interaction is located around the hands in the form of a handcuffs icon.<br/>%2Repeat to release. @@ -336,6 +366,7 @@ As %3Algema Plásticas%4 permitem a captura e detenção de soldados. Quando apreendidos, o captor se torna capaz de inspecionar os pertences do prisioneiro, liberá-los, ou acompanhá-los a outro local. Transportes mais longos também são possíveis, podendo colocá-los em veículos, se necessário. A depender das configurações, pode ser necessário que as unidades estejam rendidas antes de serem detidas.<br/><br/>%3Uso:%4<br/>%2Aproxime-se da unidade e use [%3%13%4].<br/>%2A interação encontra-se próxima às mãos simbolizada por uma algema.<br/>%2Faça o mesmo para liberar. %3Fascette%4 permettono a soldati di catturare e ammanettare altri soldati. Una volta catturati è possibile ispezionare il loro inventario, liberarli o scortarli altrove. È inoltre possibile caricarli su veicoli se necessario. A seconda delle impostazioni, potrebbe essere necessaria la resa di unità prima di poterle ammanettare.<br/><br/>%3Uso:%4<br/>%2Avvicinati all'unità e usa [%3%13%4].<br/>%2L'interazione è localizzata intorno alle mani con l'icona di manette.<br/>%2Ripeti per liberare. %3ケーブル タイ%4は兵士が他の兵士を拘束できるようにします。一度拘束すれば、拘束者は捕虜の所持品を検査したり、釈放したり、別の場所に移送することができるようになります。必要に応じて車両に積み込むなどして捕虜の輸送や護送も可能です。設定によっては、ユニットは捕虜になる前に降伏する必要がある場合があります。<br/><br/>%3使用方法:%4<br/>%2対象に近づいて [%3%13%4] を使います。<br/>%2インタラクションは、手錠アイコンの形で手のあたりに表示されます。<br/>%2同様の方法で解放できます。 + Las %3Bridas%4 permiten a un soldado capturar y detener a otro soldado. Una vez atado, el capturador tiene la habilidad de inspeccionar las pertenencias del prisionero, liberarles de nuevo o transportarles a otro área diferente. Transportar prisioneros escoltados tambien es posible, incluído montarles en vehículos si es necesario. Dependiendo de las opciones, puede requerirse que las unidades se rindan antes de ser capturados.<br/><br/>%3Uso:%4<br/>%2Acercarse a la unidad y usar el [%3%13%4].<br/>%2El punto de interacción se situa sobre las manos en forma de un icono de unas esposas.<br/>%2Repetir el paso para liberar. Phone In An Explosion @@ -345,6 +376,7 @@ Cellulare per esplosivi 電話でドカン Explosifs téléphone portable + Teléfono explosivo The %3Cellphone%4 is functionally a %3Clacker%4. Use it to connect and detonate an explosive device. Multiple devices can be linked to the cellphone and called within the phonebook.<br/><br/>%3Usage:%4<br/>%2Place an explosive.<br/>%2Use [%3%13%4], select %3Explosives%4, and select %3Cellphone%4.<br/>%2Open the cellphone interface with [%3%12%4].<br/>%2Navigate the phone book with the arrows and select your calling number.<br/>%2Call the number to detonate. @@ -353,6 +385,7 @@ O %3Celular%4 serve como dispositivo de detonação ao explosivo. Utilize-o para conectar e detonar dispositivos explosivos. Múltiplos dispositivos podem estar conectados ao celular e aparecerão na lista telefônica.<br/><br/>%3Uso:%4<br/>%2Plante o explosivo.<br/>%2Utilize [%3%13%4], selecione %3Explosivos%4, e selecione %3Celular%4.<br/>%2Abra a interface do celular com [%3%12%4].<br/>%2Navegue pela lista telefônica utilizando as setas e selecione o número desejado.<br/>%2Ligue para o número para detonar. Il %3Cellulare%4 è essenzialmente una %3spoletta%4. Usalo per collegare e detonare esplosivi. Molteplici esplosivi possono essere collegati ad un cellulare e detonati chiamando numeri nella rubrica.<br/><br/>%3Utilizzo:%4<br/>%2Piazza un esplosivo.<br/>%2Usa [%3%13%4], seleziona %3Esplosivi%4, seleziona %3Cellulare%4.<br/>%2Apri l'interfaccia del telefono con [%3%12%4].<br/>%2Naviga la rubrica con le freccette e seleziona il numero da chiamare.<br/>%2Chiama il numero del dispositivo da detonare. %3携帯電話%4は%3点火装置%4として機能します。爆破装置を接続して起爆するために使用します。複数のデバイスを携帯電話に繋ぎ、電話帳から呼び出すことができます。<br/><br/>%3使用方法:%4<br/>%2爆発物を設置。<br/>%2[%3%13%4] を使い、%3爆発物%4を選択して、%3携帯電話%4を選択します。<br/>%2[%3%12%4] を使って携帯電話インターフェースを開きます。<br/>%2矢印ボタンで電話帳に移動し、発信番号を選択します。<br/>%2電話を掛けることで起爆します。 + El %3Teléfono%4 es funcionalmente un %3Detonador%4. Úsalo para conectarlo y detonar un dispositivo explosivo. Múltiples dispositivos pueden ser conectados al teléfono y llamados desde la agenda de contactos.<br/><br/>%3Uso:%4<br/>%2Colocar un explosivo.<br/>%2Usar [%3%13%4], seleccionar %3Explosivos%4, y seleccionar %3Teléfono%4.<br/>%2Abrir la interfaz del teléfono con [%3%12%4].<br/>%2Navegar por la agenda de contactos con las flechas y selecciona el número a llamar.<br/>%2Llamar al número para detonarlo. Portable Reading Lights @@ -362,6 +395,7 @@ Luci da Lettura Portabili 携帯読書灯 Lampes de lecture portables + Luces de Lectura Portátiles %3Chemlight Shields%4 give you the ability to read your map, even in dark environments. However, when using %3Chemlight Shields%4, you will have a slight glow around you.<br/><br/>%3Usage:%4<br/>%2Use [%3%12%4] and select %3Equipment%4.<br/>%2elect %3Chemlights%4 and %3Prepare Chemlight Shield (Color)%4.<br/>%2Open %3Map%4.<br/>%2Use [%3%12%4] and select %3Flashlights%4 where you will find your chemlight shield. @@ -370,6 +404,7 @@ Os %3Protetores de Bastão de Luz%4 possibilitam a leitura de mapas em ambientes escuros. Todavia, quando utilizados, eles iluminam parcialmente os seus arredores.<br/><br/>%3Uso:%4<br/>%2Utilize [%3%12%4] e selecione %3Equipamento%4.<br/>%2Selecione %3Bastões de Luz%4 e %Preparar Protetor de Bastão de Luz (Cor)%4.<br/>%2Abrir %3Mapa%4.<br/>%2Utilize [%3%12%4] e selecione %3Lanternas%4 onde você encontrará o seu bastão de luz. %3Scudi per Luci Chimiche%4 permettono di leggere la mappa anche in ambienti bui. Il loro utilizzo comporta però un leggero effetto di luminosità intorno alla testa del giocatore.<br/><br/>%3Utilizzo:%4<br/>%2Usa [%3%12%4] e seleziona %3Eqipaggiamenti%4.<br/>%2Seleziona %3Luce Chimica%4 e %3Prepara Scudo Luce Chimica (Colore)%4.<br/>%2Apri %3Mappa%4.<br/>%2Usa [%3%12%4] e seleziona %3Torcia%4 dove troverai il tuo scudo per luce chimica. %3ケミライト シールド%4を使用すると、暗い環境でも地図を読み取ることができます。ただし、%3ケミライト シールド%4を使用すると、周囲がわずかに光ります。<br/><br/>%3使用方法:%4<br/>%2[%3%12%4] を使って%3装備%4を選択します。<br/>%2%3ケミライト%4を選択し%3ケミライト シールドを使う (色)%4を選択します。<br/>%2%3マップ%4を開きます。<br/>%2[%3%12%4] を使って%3フラッシュライト%4を選択し、ケミライト シールドを選択します。 + Los %3Protectores de Luz Química%4 proveen la habilidad de poder leer mapas en entornos oscuros. No obstante, cuando se usan los, %3Protectores de Luz Química%4, tendrás un ligero brillo alrededor tuyo.<br/><br/>%3Uso:%4<br/>%2Usar [%3%12%4] y seleccionar %3Equipamiento%4.<br/>%2Seleccionar %3Luces químicas%4 y %3Preparar Protector de Luz Química (Color)%4.<br/>%2Abrir %3Mapa%4.<br/>%2Usar [%3%12%4] y seleccionar %3Linternas%4 donde encontrarás el protector de luz química. Remote Detonation @@ -379,6 +414,7 @@ Detonazione da remoto リモコン爆弾 Détonation à distance + Detonación Remota Use %3Clackers%4 to connect and detonate an explosive device. Multiple devices can be linked to a clacker and detonated on different channels.<br/><br/>%3Usage:%4<br/>%2Place an explosive.<br/>%2Use [%3%13%4], select %3Explosives%4, and select the %3Clacker%4 you wish to link to.<br/>%2Open the ACE interface with [%3%12%4].<br/>%2Select %3Explosives%4 and select a %3Clacker%4.<br/>%2Select the %3Explosive%4 you wish to detonate. @@ -386,6 +422,7 @@ %3격발기%4를 사용하여 폭발물을 연결하고 폭발시킬 수 있습니다. 여러 폭발물을 다른 채널에 연결하여 폭발시킬 수도 있습니다.<br/><br/>%3사용 방법:%4<br/>%2폭발물을 설치합니다.<br/>%2[%3%13%4]를 사용하여 %3폭발물%4을 선택하고 연결할 %3격발기%4를 선택하십시오.<br/>%2[%3%12%4] 키로 ACE 인터페이스를 여십시오.<br/>%2%3폭발물%4을 선택하고 %3격발기%4를 선택하십시오.<br/>%2%3폭발물%4을 선택하면 폭발합니다. Usa %3Spolette%4 per collegare e detonare dispositivi esplosivi. Molteplici dispositivi possono essere collagati a una spoletta e detonati individualmente come vari canali.<br/><br/>%3Utilizzo:%4<br/>%2Piazza esplosivo.<br/>%2Usa [%3%13%4], seleziona %3Esplosivo%4, seleziona la %3Spoletta%4 a cui intendi collegarlo.<br/>%2Apri l'interfaccia ACE con [%3%12%4].<br/>%2Seleziona %3Esplosivi%4 e scegli una %3Spoletta%4.<br/>%2Seleziona un %3Explosivo%4 da detonare. %3点火装置%4を爆破装置に接続し使用することで起爆することが出来ます。複数の爆破装置を接続しそれぞれ違うチャンネルから起爆することもできます。<br/><br/>%3使用方法:%4<br/>%2爆発物を設置。<br/>%2[%3%13%4] を使い、%3爆発物%4を選択して、接続したい%3点火装置%4を選択します。<br/>%2ACEインターフェースを [%3%12%4] で開きます。<br/>%2%3爆発物%4を選択し、%3点火装置%4を選びます。<br/>%2起爆したい%3爆破装置%4を選択します。 + Utiliza los %3Detonadores%4 para conectar y detonar un explosivo. Múltiple dispositivos pueden ser conectados a un detonador y detonados en diferentes canales.<br/><br/>%3Uso:%4<br/>%2 Coloca un explosivo.<br/>%2Usar [%3%13%4], seleccionar %3Explosivos%4, y selecciona el %3Detonador%4 al que quieres conectarlo.<br/>%2Abre la interfaz de ACE con [%3%12%4].<br/>%2Selecciona %3Explosivos%4 y selecciona un %3Detonador%4.<br/>%2Selecciona el %3Explosivo%4 que quieres detonar. Navigate @@ -395,6 +432,7 @@ 測位 Навигация Naviguer + Navegar The %3DAGR%4 is a simpler version of the %3MicroDAGR GPS%4. It has similar features but lacks the topographic and satellite imaging functions of the %3MicroDAGR GPS%4.<br/><br/>%3Usage:%4<br/>%2Equip a %3DAGR%4.<br/>%2Use [%3%12%4] and select %3Configure%4 or %3Toggle%4.<br/><br/>The following menus are available when configuring your %3DAGR:%4<br/>%11%2Data View: WIP<br/>%11%2GoTo WP: Select a waypoint to track.<br/>%11%2WP List: Add/Edit/Remove waypoints.<br/>%11%2Connect To: Connect %3DAGR%4 to the %3Vector 21 Rangefinder%4.<br/>%11%2Options @@ -402,6 +440,7 @@ %3DAGR%4은 %3마이크로DAGR GPS%4의 단순화 버전입니다. 유사한 기능을 가지고 있지만 %3마이크로DAGR GPS%4의 지형 및 위성 이미지 기능이 없습니다.<br/><br/>%3사용 방법:%4<br/>%2%3DAGR%4를 장착하십시오.<br/>%2[%3%12%4를 사용하고 %3DAGR 설정%4 또는 %3DAGR 토글%4을 선택하십시오.<br/><br/>%3DAGR%4을 구성할 때 다음 메뉴를 사용할 수 있습니다:<br/>%11%2Data View: 제작 중<br/>%11%2GoTo WP: 추적할 웨이포인트를 선택합니다.<br/>%11%2WP List: 경유지를 추가/편집/제거합니다.<br/>%11%2Connect To: %3DAGR%4을 %3벡터 21%4 거리계에 연동시킵니다.<br/>%11%2옵션입니다 Il %3DAGR%4 è una versione più semplice del %3GPS MicroDAGR%4. Ha funzioni simili, gli manca però la capacità di visualizzare informazioni topografiche e satellitari come il %3GPS MicroDAGR%4.<br/><br/>%3Utilizzo:%4<br/>%2Equipaggia il %3DAGR%4.<br/>%2Usa [%3%12%4] e seleziona %3Configura%4 o %3Apri%4.<br/><br/>I seguenti Menù sono disponibili durante la configurazione del tuo %3DAGR:%4<br/>%11%2Pagina Dati: WIP<br/>%11%2VaiA WP: Seleziona un waypoint da tracciare.<br/>%11%2Lista WP: Aggiungi/Modifica/Rimuovi waypoint.<br/>%11%2Collega A: Collega il %3DAGR%4 al %3Telemetro Vector 21%4.<br/>%11%2Opzioni %3DAGR%4はシンプルなバージョンの%3MicroDAGR GPS%4です。同様の機能を備えていますが、%3MicroDAGR GPS%4のような地形および衛星画像機能はありません。<br/><br/>%3使用方法:%4<br/>%2%3DAGR%4を装備する。<br/>%2[%3%12%4] を使って%3設定%4 もしくは %3表示切替%4を選択します。<br/><br/>%3DAGR%4の設定には次のメニューを使用できます:<br/>%11%2Data View: WIP<br/>%11%2GoTo WP: 追跡するウェイポイントを選択します。<br/>%11%2WP List: ウェイポイントを追加/編集/削除します。<br/>%11%2Connect To: %3DAGR%4を%3ベクター 21 レンジファインダー%4に接続できます。<br/>%11%2Options + El %3DAGR%4 es una versión simplificada del %3MicroDAGR GPS%4. Tiene unas funcionalidades similares pero le faltan las funciones de los mapas topográficos e imágenes satelitales del %3MicroDAGR GPS%4.<br/><br/>%3Usage:%4<br/>%2Equip a %3DAGR%4.<br/>%2Usar [%3%12%4] y seleccionar %3Configurar%4 o %3Activar%4.<br/><br/>Los siguientes menús están disponibles cuando configuras el %3DAGR:%4<br/>%11%2Vista de Datos: WIP<br/>%11%2Ir a WP: Selecciona un Punto de Ruta para seguir.<br/>%11%2Lista de WP: Añadir/Editar/Suprimir puntos de ruta.<br/>%11%2Conectar A: Conectar %3DAGR%4 a %3Telémetro Vector 21%4.<br/>%11%2Opciones Explosive Revenge @@ -411,6 +450,7 @@ 爆発的な復讐 Взрывная месть Homme mort + Venganza Explosiva The %3Dead Man's Switch%4 is a device that allows a soldier to detonate an %3Explosive%4 when the soldier dies.<br/><br/>%3Usage:%4<br/>%2Use [%3%12%4] and select %3Explosives%4.<br/>%2Select %3Dead Man's Switch%4 and connect the desired %3Explosive%4.<br/>%2Repeat the process and disconnect to reverse. @@ -418,6 +458,7 @@ %3자폭 장치%4는 병사가 사망했을 때 병사가 %3폭발물%4을 폭발시킬 수 있는 장치입니다.<br/><br/>%3사용 방법:%4<br/>%2[%3%12%4]를 사용하고 %3폭발물%4을 선택하십시오.<br/>%2%3자폭 장치%4를 선택하고 원하는 %3폭발물%4에 연결하십시오.<br/>%2반대로 해제하고 싶다면 같은 행동을 반복하십시오. Il %3Detonatore a rilascio%4 è un dispositivo che permette a soldati di detonare un %3Esplosivo%4 quando perdono i sensi.<br/><br/>%3Utilizzo:%4<br/>%2Usa [%3%12%4] e seleziona %3Esplosivi%4.<br/>%2Seleziona %3Detonatore a rilascio%4 e collega l'%3Esplosivo%4 desiderato.<br/>%2Ripeti il processo e scollega per disarmare il detonatore. %3自爆装置%4は、兵士の死亡時に%3爆発物%4を起爆させることができる装置です。<br/><br/>%3使用方法:%4<br/>%2[%3%12%4] を使って%3爆発物%4を選択します。<br/>%2%3自爆装置%4を選択し、接続したい%3爆発物%4を選びます。<br/>%2同様の手順を逆に行うことで接続を解除できます。 + El %3Detonador de Hombre Muerto%4 es un dispositivo que permite a un soldado detonar un %3Explosivo%4 cuando el soldado muere.<br/><br/>%3Uso:%4<br/>%2Usar [%3%12%4] y seleccionar %3Explosivos%4.<br/>%2Seleccionar %3Detonador de Hombre Muerto%4 y conectar el %3Explosivo%4.<br/> deseado%2Repetir el proceso y desconectar para revertirlo. The %3Defusal Kit%4 allows defusal of explosives.<br/><br/>%3Usage:%4<br/>%2Equip a %3Defusal Kit%4.<br/>%2Safely approach an %3Explosive%4.<br/>%2Use [%3%13%4] and select %3Defuse%4. @@ -425,6 +466,7 @@ %3해체 장비%4를 사용하면 폭발물을 제거할 수 있습니다.<br/><br/>%3사용 방법:%4<br/>%2%3해체 장비%4를 장착하십시오.<br/>%2%3폭발물%4에 안전하게 접근하십시오.<br/>%2[%3%13%4]를 사용하고 %3해체%4를 선택하십시오. The %3Kit E.O.D.%4 permette il disinnesco di esplosivi.<br/><br/>%3Utilizzo:%4<br/>%2Equipaggia un %3Kit E.O.D.%4.<br/>%2Avvicinati in modo sicuro ad un %3Esplosivo%4.<br/>%2Usa [%3%13%4] e seleziona %3Disinnesca%4. %3解除キット%4は爆発物の無力化を行うことができます。<br/><br/>%3使用方法:%4<br/>%2%3解除キット%4を装備。<br/>%2慎重に%3爆発物%4に接近します。<br/>%2[%3%13%4] を使って%3無力化%4を選択します。 + El %3Kit de Desactivación%4 permite la desactivación de explosivos.<br/><br/>%3Uso:%4<br/>%2Equipa un %3Kit de Desactivación%4.<br/>%2Aproxímate al %3Explosivo%4<br/> de forma segura.%2Usa [%3%13%4] y selecciona %3Desactivar%4. Defuse Explosives @@ -434,6 +476,7 @@ 爆発物の解除 Обезвреживание взрывчатки Désamorcer les explosifs + Desactivar Explosivos Protect Your Hearing @@ -443,6 +486,7 @@ 聴覚の保護 Защитите свой слух Protéger votre audition + Protege tus oídos %3Ear Plugs%4 help prevent hearing damage from repeat loud noises near a soldier. Insert %3Ear Plugs%4 to lower volume of a soldier's environment and prevent %3Combat Deafness%4.<br/><br/>%3Usage:%4<br/>%2Use [%3%12%4] and select %3Equipment%4.<br/>%2Insert %3Ear Plugs%4. @@ -450,6 +494,7 @@ %3Tappi auricolari%4 aiutano a prevenire danni all'udito da ripetuti rumori forti in prossimità del soldato. Inserisci %3Tappi auricolari%4 per ridurre il volume dell'ambiente per il soldato e impedire %3Assordamento%4.<br/><br/>%3Utilizzo:%4<br/>%2Usa [%3%12%4] e seleziona %3Equipaggiamento%4.<br/>%2Indossa %3Tappi Auricolari%4. %3귀마개%4는 병사 주변에서 반복되는 시끄러운 소리로 인한 청력 손상을 방지하는 데 도움이 됩니다. %3귀마개%4를 끼워서 병사가 있는 환경의 소리 크기를 낮추고 %3전투로 인한 청력손상%4을 방지하십시오.<br/><br/>%3사용 방법:%4<br/>%2[%3%12%4]를 사용하여 %3장비%4를 선택하십시오.<br/>%2%3귀마개%4를 삽입하십시오. %3耳栓%4は、兵士の近くで繰り返される大きな騒音による聴覚障害を防ぐのに役立ちます。%3耳栓%4を耳に挿入することで兵士の環境の音量を下げ、%3戦闘難聴%4を防ぎます。<br/><br/>%3使用方法:%4<br/>%2[%3%12%4] を使って%3装備%4を選択します。<br/>%2%3耳栓を着ける%4ことで使用できます。 + Los %3Tapones de oídos%4 ayudan a prevenir el daño auditivo de ruidos altos repetidos cerca de un soldado. Inserta los %3Tapones de oídos%4 para reducir el volumen del entorno del soldado y prevenir la %3Sordera de Combate%4.<br/><br/>%3Uso:%4<br/>%2Usar [%3%12%4] y seleccionar %3Equipamiento%4.<br/>%2Insertar %3Tapones de oídos%4. Get To Cover @@ -459,6 +504,7 @@ 遮蔽を造り出す Добраться до укрытия Se mettre à couvert + Ponerse A Cubierto The %3Entrenching Tool%4 allows soldiers to dig trenches to help defend their position. The soldier must be on soil in order to dig a trench.<br/><br/>%3Usage:%4<br/>%2Equip an %3Entrenching Tool%4.<br/>%2Use [%3%12%4] and select %3Equipment%4.<br/>%2Select the type of trench you wish to build. @@ -466,6 +512,7 @@ La %3Pala da Trincea%4 permette a soldati di scavare trincee per difendere meglio la loro posizione. Il soldato deve trovarsi su suolo scavabile per poter creare trincee.<br/><br/>%3Utilizzo:%4<br/>%2Equipaggia una %3Pala da Trincea%4.<br/>%2Usa [%3%12%4] e seleziona %3Equipaggiamento%4.<br/>%2Seleziona il tipo di trincea che vuoi costruire. %3야전삽%4을 사용하면 병사들의 진지 방어를 위한 참호를 팔 수 있습니다. 병사가 참호를 파려면 흙 위에 있어야 합니다.<br/><br/>%3사용 방법:%4<br/>%2%3야전삽%4을 장비하십시오.<br/>%2[%3%12%4]를 사용하여 %3장비%4를 선택하십시오.<br/>%2짓고 싶은 종류의 참호를 선택하십시오. %3塹壕ツール%4を使用すると、兵士は自分の陣地を守るために塹壕を掘ることができます。塹壕を掘るには、兵士は土の上にいる必要があります。<br/><br/>%3使用方法:%4<br/>%2%3塹壕ツール%4を装備します。<br/>%2[%3%12%4] を使って%3装備%4を選択します。<br/>%2構築する塹壕の種類を選択します。 + La %3Pala de Trincheras%4 permite a los soldados excavar trincheras para ayudarles a defender su posición. El soldado debe estar sobre tierra para poder excavar una trinchera.<br/><br/>%3Uso:%4<br/>%2Equipar la %3Pala de Trincheras%4.<br/>%2Usar [%3%12%4] y seleccionar %3Equipamiento%4.<br/>%2Seleccionar el tipo de trinchera que quieres construir. Flashlights @@ -475,6 +522,7 @@ フラッシュライト Фонари Lampes de poche + Linternas Illuminate Your Map @@ -484,6 +532,7 @@ 地図に光あれ Осветите свою карту Éclairer votre carte + Ilumina Tu Mapa %3Flashlights%4 give you the ability to read your map, even in dark environments. However, when using %3Flashlights%4, you will have a slight glow around you.<br/><br/>%3Usage:%4<br/>%2On the map screen, use [%3%12%4] and select %3Flashlights%4.<br/>%2Select the %3Flashlight%4 you want to use and select %3On%4.<br/><br/>%3Available Flashlight Items%4:<br/>%2 Fulton MX-991<br/>%2 KSF-1<br/>%2 Maglite XL50<br/><br/>%3NOTE:%4<br/>Flashlight states are persistent. @@ -491,6 +540,7 @@ %3Torce%4 permettono di leggere la tua mappa anche in ambienti bui. Però quando le utilizzi avrai un leggero effetto luminoso intorno a te.<br/><br/>%3Utilizzo:%4<br/>%2Sulla mappa usa [%3%12%4] e seleziona %3Torcia%4.<br/>%2Seleziona la %3Torcia%4 che vuoi usare e seleziona %3Accendi%4.<br/><br/>%3Oggetti Torcia Disponibili%4:<br/>%2 Fulton MX-991<br/>%2 KSF-1<br/>%2 Maglite XL50<br/><br/>%3NOTE:%4<br/>Lo stato di una torcia è persistente. %3손전등%4은 어두운 환경에서도 지도를 읽을 수 있는 기능을 제공합니다. 단, %3손전등%4을 사용할 때 주변에 약간 빛이 납니다.<br/><br/>%3사용 방법:%4<br/>%2지도 화면에서 [%3%12%4]를 사용하고 %3손전등%4을 선택하십시오.<br/>%2사용할 %3손전등%4을 선택하고 %3켜기%4를 선택하십시오.<br/><br/>%3사용 가능한 손전등 아이템%4:<br/>%2풀턴 MX-991<br/>%2 KSF-1<br/>%2 매그라이트 XL50<br/><br/>%3참고:%4<br/>손전등 상태는 영구적입니다. %3フラッシュライト%4を使用すると、暗い環境でも地図を読むことができます。ただし、%3フラッシュライト%4を使用すると、周囲がわずかに光ります。<br/><br/>%3使用方法:%4<br/>%2マップ画面で [%3%12%4] を使用し、%3フラッシュライト%4を選択します。<br/>%2%3フラッシュライト%4を選択し、使用したいライトを%3点ける%4。<br/><br/>%3使用可能なフラッシュライトのアイテム%4:<br/>%2 フルトン MX-991<br/>%2 KSF-1<br/>%2 マグライト XL50<br/><br/>%3備考:%4<br/>フラッシュライトの状態は継続します。 + Las %3Linternas%4 proveen la habilidad para leer tu mapa, incluso en entornos oscuros. No obstante, cuando se usen las %3Linternas%4, aparecerá un ligero brillo alrededor tuya.<br/><br/>%3Uso:%4<br/>%2En la pantalla del mapa, utilizar [%3%12%4] y seleccionar %3Linternas%4.<br/>%2Seleccionar la %3Linterna%4 Que quieres utilizar y selecciona %3On%4.<br/><br/>%3Objetos de Linternas disponibles%4:<br/>%2 Fulton MX-991<br/>%2 KSF-1<br/>%2 Maglite XL50<br/><br/>%3NOTA:%4<br/>Los estados de las Linternas son persistentes. Observe From The Skies @@ -500,6 +550,7 @@ 空から戦場を見てみよう Наблюдайте с Небес Observer depuis le ciel + Observar Desde El Cielo The %3High-Altitude Unit Navigated Tactical Imaging Round (HuntIR)%4 is designed to be fired from a grenade launcher. After being fired in the air, the built-in parachute will be deployed and the IR CMOS camera will activate, providing a video stream until it touches the ground or is shot down.<br/><br/>%3Usage:%4<br/>%2Equip a %3HuntIR Monitor%4 and compatible ammunition.<br/>%2Fire the %3HuntIR Round%4 as high as possible over the area you want to observe.<br/>%2Open the %3HuntIR Monitor%4.<br/>%2Use [%3%12%4], select %3Equipment%4.<br/>%2Select %3Activate HuntIR Monitor%4. @@ -507,6 +558,7 @@ Il %3High-Altitude Unit Navigated Tactical Imaging Round (HuntIR)%4 è progettato per essere sparato da un lanciagranate. Dopo essere stato sparato verso l'alto, verrà aperto un paracadute incorporato e attivata una videocamera IR CMOS, inviando una diretta video finché toccherà terra o verrà abbattuto.<br/><br/>%3Utilizzo:%4<br/>%2Equipaggia un %3Monitor HuntIR%4 e munizioni compatibili.<br/>%2Spara un %3Colpo HuntIR%4 il più alto possibile sopra l'area che vuoi osservare.<br/>%2Apri il %3Monitor HuntIR%4.<br/>%2Usa [%3%12%4], seleziona %3Equipaggiamento%4.<br/>%2Seleziona %3Attiva Monitor HuntIR%4. %3고고도 유닛 탐색용 전술 영상화 탄약 (HuntIR)%4은 유탄발사기에서 발사될 수 있도록 설계되었습니다.공주에서 발사된 후 내장된 낙하산이 전개되고 적외선 CMOS 카메라가 작동하여 지상에 닿거나 격추될 때까지 비디오 스트림이 제공됩니다.<br/><br/>%3사용 방법:%4<br/>%2%3헌트IR 모니터%4와 호환 탄약을 장착하십시오.<br/>%2%3헌트IR 유탄%4을 발사하려는 구역에서 가능한 한 높게 발사하십시오.<br/>%2%3헌트IR 모니터%4를 여십시오.<br/>%2[%3%12%4]를 사용하여 %3장비%4를 선택하십시오.<br/>%2%3헌트IR 모니터 활성화%4를 선택하십시오. %3High-Altitude Unit Navigated Tactical Imaging Round (HuntIR)%4はグレネードランチャーから発射されるように設計されています。空中で発射された後、内蔵のパラシュートが展開され、IR CMOS カメラが起動し、地面に着くか撃墜されるまでビデオ ストリームを提供します。<br/><br/>%3使用方法:%4<br/>%2%3HuntIR モニター%4と互換性のある弾薬を装備します。<br/>%2観測したいエリアに向けてできるだけ高く%3HuntIR 弾頭%4を発射します。<br/>%2%3HuntIR モニター%4を開きます。<br/>%2[%3%12%4] を使って%3装備%4を選択します。<br/>%2%3HuntIRを起動する%4からモニターを起動します。 + El %3High-Altitude Unit Navigated Tactical Imaging Round (HuntIR)%4 está diseñado para ser disparado desde un lanzagranadas. Despues de ser disparada al aire, desplegará su paracaídas integrado y activará su cámara IR CMOS integrada, proveyendo de un flujo de video hasta que toque el suelo o sea derribado.<br/><br/>%3Uso:%4<br/>%2Equipa un %3Monitor HuntIR%4 y la munición compatible.<br/>%2Dispara la %3Munición HuntIR%4 tan alto como sea posible sobre el área que quieres observar.<br/>%2Abre el %3Monitor HuntIR%4.<br/>%2Usar [%3%12%4], seleccionar %3Equipamiento%4.<br/>%2Seleccionar %3Activar Monitor HuntIR%4. Track Your Team With Stealth @@ -516,6 +568,7 @@ 自分の部隊を追う Следите за своей командой незаметно Suivez votre équipe en toute discrétion + Sigue A Tu Equipo Con Sigilo The %3IR Strobe%4 is a throwable that emits an IR light pulse intermittently. The %3IR Strobe%4 can also be attached to a soldier, making it useful for tracking teammates under night vision devices.<br/><br/>%3Usage:%4<br/>%2Use [%3%12%4] and select %3Equipment%4.<br/>%2Select %3Attach%4 and select the %3IR Strobe%4. @@ -523,6 +576,7 @@ La %3Strobo IR%4 è un lanciabile che emette un impulso intermittente di luce IR. La %3Strobo IR%4 può anche essere attaccata ad un soldato, facilitando l'identificazione di alleati con visori notturni.<br/><br/>%3Utilizzo:%4<br/>%2Usa [%3%12%4] e seleziona %3Equipaggiamento%4.<br/>%2Seleziona %3Attacca%4 e scegli la %3Strobo IR%4. %3적외선 스트로브%4는 던질 수 있는 적외선 광펄스를 간헐적으로 방출하는 투척형 아이템입니다. %3적외선 스트로브%4는 병사에게도 부착 가능하기 때문에 야간투시장치로 팀원을 추적할 때 유용합니다.<br/><br/>%3사용 방법:%4<br/>%2[%3%12%4]를 사용하여 %3장비%4를 선택하십시오.<br/>%2%3아이템 부착%4을 선택하고 %3적외선 스트로브%4를 선택하십시오. %3赤外線ストロボ%4は、赤外線光パルスを断続的に放射します。投擲可能です。%3赤外線ストロボ%4は兵士に取り付けることもできるため、暗視装置の下でチームメイトを追跡するのに役立ちます。<br/><br/>%3使用方法:%4<br/>%2[%3%12%4] を使って%3装備%4を選択します。<br/>%2%3アイテムを取り付ける%4を選択して%3赤外線ストロボ%4を選び使用します。 + El %3Estroboscópico IR%4 es un objeto lanzable que emite un pulso intermitente de luz IR. El %3Estroboscópico IR%4 tambien puede ser sujeto a un soldado, haciéndolo útil para el seguimiento de los compañeros utilizando gafas de visión nocturna.<br/><br/>%3Uso:%4<br/>%2Usar [%3%12%4] y seleccionar %3Equipamiento%4.<br/>%2Seleccionar %3Sujetar%4 y seleccionar el %3Estroboscópico IR%4. Pocket Weatherstation @@ -532,6 +586,7 @@ 携帯気象予報所 Карманная метеостанция Station météo de poche + Estación Climática de Bolsillo The %3Kestrel 4500 Pocket Weather Tracker%4 is a mini weather station useful for collecting the the following weather data:<br/>%2Heading and wind direction<br/>%2Crosswind and headwind<br/>%2Altitude and barometric pressure<br/>%2Wet bulb temperature<br/>%2Humidity and dewpoint<br/>%2Density altitude<br/>%2Wind chill and temperature<br/>%2Time and date<br/>%2Minimum, maximum, and average values<br/><br/>%3Usage:%4<br/>%2Equip a %3Kestrel%4.<br/>%2Use [%3%12%4] and select %3Equipment%4.<br/>%2Select %3Open%4. @@ -539,6 +594,7 @@ Il %3Kestrel 4500 Indicatore Meteorologico Tascabile%4 è una mini-stazione meteo utile per ricavare le seguenti informazioni meteorologiche:<br/>%2Prua e direzione del vento<br/>%2Vento di traverso e frontale<br/>%2Altitudine and pressione barometrica<br/>%2Temperatura di bulbo umido<br/>%2Umidità e punto di rugiada<br/>%2Density altitude<br/>%2Temperatura e gelo del vento<br/>%2Data e Ora<br/>%2Valori minimi, massimi, e medi<br/><br/>%3Utilizzo:%4<br/>%2Equipaggia %3Kestrel%4.<br/>%2Usa [%3%12%4] e seleziona %3Equipaggiamento%4.<br/>%2Seleziona %3Apri%4. %3케스트렐 4500 휴대용 기상 추적 장비%4는 다음 날씨 데이터들을 수집하는 데 유용한 소형 기상 관측 장비입니다:<br/>%2바람이 오는 방향과 가는 방향<br/>%2옆바람과 맞바람<br/>%2고도 및 기압<br/>%2습구온도<br/>%2습도 및 이슬점<br/>%2밀도고도<br/>%2체감온도<br/>%2시간 및 날짜<br/>%2최소, 최대, 평균값<br/><br/>%3사용 방법:%4<br/>%2%3케스트렐 4500NV%4를 장착하십시오.<br/>%2[%3%12%4]를 사용하고 %3장비%4를 선택하십시오.<br/>%2%3열기%4를 선택하십시오. %3ケストレル 4500 携帯気象計%4は、次の気象データの収集に役立つミニ気象ステーションです:<br/>%2方位と風向<br/>%2横風と向かい風<br/>%2高度と気圧<br/>%2湿球温度<br/>%2湿度と露点<br/>%2密度高度<br/>%2ウィンドチルと温度<br/>%2日付と時刻<br/>%2最小値、最大値、平均値<br/><br/>%3使用方法:%4<br/>%2%3ケストレル%4を装備します。<br/>%2[%3%12%4] を使って%3装備%4を選択します。<br/>%2%3ケストレルを開く%4で使用できます。 + La %3Estación Climática de Bolsillo Kestrel 4500%4 es una pequeña estación climática portátil para recolectar la siguiente información del tiempo:<br/>%2Dirección y Sentido del Viento<br/>%2VIento cruzado y Viento en cola<br/>%2Altitud y presión barométrica<br/>%2Temperatura húmeda<br/>%2Humedad y punto de condensación<br/>%2Densidad de altitud<br/>%2Sensación térmica y temperatura<br/>%2Hora y fecha<br/>%2Valores mínimos, máximos y medios<br/><br/>%3Uso:%4<br/>%2Equipa un %3Kestrel%4.<br/>%2Usar [%3%12%4] y seleccionar %3Equipamiento%4.<br/>%2Seleccionar %3Abrir%4. Triangulate Your Position @@ -548,6 +604,7 @@ 三角測量で位置を特定 Передавайте свое местоположение Trianguler votre position + Triangular Tu Posición The %3Map Tools%4 are a set of tools that allows a soldier to measure distances and angles. Useful for land, and calculating firing solutions for artillery.<br/><br/>%3Usage:%4<br/>%2Open %3Map%4.<br/>%2Use [%3%12%4] and select %3Map Tools%4.<br/>%2 The Tool can be moved by dragging with [%3Left-Click%4] while holding [%3ALT%4]. @@ -556,6 +613,7 @@ %3독도용 도구%4는 병사가 거리와 각도를 측정할 수 있는 도구 세트입니다. 지상에서 유용하며 포병 사격 솔루션 계산에 유용합니다,<br/><br/>%3사용 방법:%4<br/>%2%3지도%4를 여십시오.<br/>%2[%3%12%4]를 사용하여 %3독도용 도구%4를 선택하십시오.<br/>%2도구는 [%3Alt 키%4]를 누른 상태에서 [%3마우스 왼쪽 클릭%4]으로 드래그하여 이동할 수 있습니다. %3マップ ツール%4は、兵士が距離と角度を測定できるようにするツールのセットです。陸上や大砲の射撃工程の計算を解くのに役立ちます。<br/><br/>%3使用方法:%4<br/>%2%3マップ%4を開きます。<br/>%2[%3%12%4] を使って%3マップ ツール%4を選択します。<br/>%2 [%3ALT%4] を押しながら [%3左クリック%4] でドラッグするとツールを移動できます。 Les %3Outils cartographiques%4 sont un ensemble d'outils permettant au soldat de mesurer des distances et des angles. Utile pour la terre et le calcul des solutions de tir pour l'artillerie.<br/><br/>%3Utilisation:%4<br/>%2Ouvrir la%3Carte%4.<br/>%2Utiliser [%3%12%4] et sélectionner %3Outils cartographiques%4.<br/>%2 L'outil peut être déplacé en le faisant glisser avec [%3Clic gauche%4] tout en maintenant [%3ALT%4]. + Las %3Herramientas de mapa%4 son un conjunto de herramientas que permiten a un soldado medir distancias y ángulos. Util para terrenos, y para calcular soluciones de tiro para artillería.<br/><br/>%3Uso:%4<br/>%2Abrir %3Mapa%4.<br/>%2Usar [%3%12%4] y seleccionar %3Herramientas de Mapa%4.<br/>%2 La herramienta puede ser movida siendo arrastrada con [%3CLick-Izquierdo%4] mientras se pulsa [%3ALT%4]. Advanced DAGR @@ -565,6 +623,7 @@ より高度なDAGR Продвинутый DAGR DAGR avancé + DAGR Avanzado The %3MicroDAGR GPS%4 is an advanced version of the %3DAGR%4. It provides position, navigation, and timing (PNT) data to include:<br/>%2Compass and heading<br/>%2Date and hour synced to the mission<br/>%2Elevation (relative to sea level)<br/>%2Current speed<br/>%2GPS with topographic and satellite view<br/>%2Creating, naming, and deleting waypoints<br/>%2Friendly identification (Requires ACE BLUFOR Tracker Setting)<br/>Connection to the Vector-21 Rangefinder for data import (waypoint creation and grid reference of ranged targets)<br/><br/>%3Usage:%4<br/>%2For usage instructions, please visit the dedicated %3MicroDAGR%4 wiki. @@ -572,6 +631,7 @@ Il %3GPS MicroDAGR%4 è una versione avanzata del %3DAGR%4. Esso mostra dati su posizione, navigazione e tempismo (PNT), includendo:<br/>%2Bussola e azimut<br/>%2Data e ora sincronizzate con la missione<br/>%2Elevazione (dal livello del mare)<br/>%2Velocità attuale<br/>%2GPS con visuale topografica e satellitare<br/>%2Creazione, rinomina e rimozione di waypoint<br/>%2Identificazione di alleati (Richiede Impostazioni ACE BLUFOR Tracker)<br/>Connessione al Telemetro Vector-21 per importazione di dati (creazione waypoint e indicazione di griglia su bersagli puntati)<br/><br/>%3Utilizzo:%4<br/>%2Per informazioni sull'utilizzo sei pregato di visitare la pagina wiki dedicata al %3MicroDAGR%4. %3마이크로DAGR GPS%4는 %3DAGR%4의 고급 버전입니다. 다음과 같이 위치, 내비게이션 및 타이밍(PNT) 데이터를 제공합니다:<br/>%2나침반 및 방향<br/>%2임무와 동기화된 날짜 및 시간<br/>%2고도 (해수면 기준)<br/>%2현재 속도<br/>%2지형 및 위성 시점 기능이 있는 GPS<br/>%2웨이포인트 생성, 작명 및 삭제<br/>%2아군 식별 (ACE의 GPS 피아식별기 켜기 체크 필요)<br/>%2데이터를 가져오기 위한 벡터-21 거리계에 연결(원거리 대상의 웨이포인트 생성 및 좌표 참조)<br/><br/>%3사용 방법:%4<br/>%2사용 방법을 보려면 전용 %3마이크로DAGR%4의 위키를 방문하십시오. %3MicroDAGR GPS%4は%3DAGR%4のより高度なバージョンです。測位、航法、計時(PNT)データが提供されます。これには以下の情報を含みます:<br/>%2コンパスと方位<br/>%2ミッションに同期された日付と時間<br/>%2標高 (海面に対する相対値)<br/>%2現在の速度<br/>%2地形図と衛星ビューを備えたGPS<br/>%2ウェイポイントの作成、名前付け、および削除<br/>%2友軍の識別 (ACE ブルーフォーストラッキング設定が必要)<br/>ベクター21レンジファインダーへの接続とデータのインポート (ウェイポイントの作成と遠距離ターゲットのグリッド参照)<br/><br/>%3使用方法:%4<br/>%2使用手順については、専用の %3MicroDAGR%4 wiki を参照してください。 + El %3GPS MicroDAGR%4 es una versión avanzada del %3DAGR%4. Provee de posicionamiento, navegación y datos de temporización (PNT) que incluye:<br/>%2Brújula y dirección<br/>%2Fecha y hora sincronizada con la misión<br/>%2Elevación (relativa al nivel del mar)<br/>%2Velocidad actual<br/>%2GPS con vista topográfica y satelital<br/>%2Creación, nombrado y borrado de puntos de ruta<br/>%2Identificación de aliados (Requiere la opción de ACE BLUFOR Tracker)<br/>Conexión con el telémetro Vector-21 para importación de datos (creación de puntos de ruta y referenciado en eje de coordenada para objetivos a distancia)<br/><br/>%3Uso:%4<br/>%2Para instrucciones de uso, por favor visita la Wiki dedicada de %3MicroDAGR%4. Range Tables @@ -581,6 +641,7 @@ 射表 Таблицы диапазонов Tables de tir + Tablas de Distancia Get A Firing Solution @@ -590,6 +651,7 @@ 撃ち方の解を得る Получите расчёт Obtenir une solution de tir + Obtener Una Solución de Tiro %3Range Tables%4 allow for a soldier to estimate accurate shot placement on direct or indirect targets (depending on asset). The %3Range Table%4 will automatically fill depending on the soldiers selected weapon/vehicle.<br/><br/>%3Usage:%4<br/>%2Use [%3%12%4] and select %3Equipment%4.<br/>%2Select the desired %3Range Table%4. @@ -597,6 +659,7 @@ %3Tavole di tiro%4 permettono al soldato di stimare piazzamenti accurati di colpi mediante fuoco diretto o indiretto (a seconda dell'arma). La %3Tavola di tiro%4 si modificherà in automatico a seconda dell'arma/veicolo del soldato.<br/><br/>%3Utilizzo:%4<br/>%2Usa [%3%12%4] and seleziona %3Equipaggiamento%4.<br/>%2Seleziona la portata desiderata sulla %3Tavola di tiro%4. %3사거리표%4를 사용하면 병사가 직접 또는 간접 표적(자산에 따라 다름)에 대한 정확한 사격 배치를 추정할 수 있습니다. %3사거리표%4는 선택한 병사의 무기/차량에 따라 자동으로 작성됩니다.<br/><br/>%3사용 방법:%4<br/>%2[%3%12%4]를 사용하고 %3장비%4를 선택하십시오.<br/>%2원하는 %3사거리표%4를 선택하십시오. %3射表%4 を使用すると、兵士は (手段に応じて) 直接的または間接的なターゲットへの正確な射撃位置を推定できます。%3射表%4は、兵士が選択した武器/車両に応じて自動的に入力されます。<br/><br/>%3使用方法:%4<br/>%2[%3%12%4] を使って%3装備%4を選択します。<br/>%2目的の%3射表%4を選択します。 + La %3Tabla de distancias%4 permite a un soldado estimar con precisión el posicionamiento de un disparo sobre un objetivo de manera directa o indirecta (dependiendo del dispositivo). La %3Tabla de distancias%4 se autorellena dependiendo del arma o vehículo seleccionado por el soldado.<br/><br/>%3Uso:%4<br/>%2Usar [%3%12%4] y seleccionar %3Equipamiento%4.<br/>%2Selecciona la %3Tabla de distancias%4 deseada. Ropes @@ -606,6 +669,7 @@ ロープ Канаты Corde + Cuerdas Tow With Ease @@ -615,6 +679,7 @@ 楽々けん引 Буксируйте с легкостью Remorquer avec facilité + Remolcar Con Facilidad %3Ropes%4 have multiple uses including %3Towing%4 vehicles and %3Fast Roping%4 from helicopters.<br/><br/>%3Towing:%4<br/>%2Approach a vehicle.<br/>%2Use [%3%13%4] and select %3Towing%4.<br/>%2Select rope length.<br/>%2Select attachment point on towing vehicle.<br/>%2Select attachment on towed vehicle.<br/><br/>%3Available Rope Lengths:%4<br/>%2 3.2 meters<br/>%2 6.2 meters<br/>%2 12.2 meters<br/>%2 15.2 meters<br/>%2 18.3 meters<br/>%2 27.4 meters<br/>%2 36.6 meters @@ -622,6 +687,7 @@ %3Corde%4 hanno molteplici utilizzi, come %3Trainare%4 veicoli e %3Fast Roping%4 da elicotteri.<br/><br/>%3Traino:%4<br/>%2Avvicinati a un veicolo.<br/>%2Usa [%3%13%4] e seleziona %3Traina%4.<br/>%2Seleziona lunghezza corda.<br/>%2Seleziona punto di attacco su veicolo trainante.<br/>%2Seleziona attacco su veicolo trainato.<br/><br/>%3Lunghezze corde a disposizione:%4<br/>%2 3.2 metri<br/>%2 6.2 metri<br/>%2 12.2 metri<br/>%2 15.2 metri<br/>%2 18.3 metri<br/>%2 27.4 metri<br/>%2 36.6 metri %3로프%4는 차량 %3견인%4 및 헬기의 %3패스트로프%4 등 여러 용도로 사용됩니다.<br/><br/>%3견인 방법:%4<br/>%2차량에 접근하십시오.<br/>%2[%3%13%4]를 사용하고 %3견인%4을 선택하십시오.<br/>%2로프 길이를 선택하십시오.<br/>%2견인할 차량의 부착 지점을 선택하십시오.<br/>%2견인될 차량의 부착 지점을 선택하십시오.<br/><br/>%3사용 가능한 로프 길이:%4<br/>%2 3.2m<br/>%2 6.2m<br/>%2 12.2m<br/>%2 15.2m<br/>%2 18.3m<br/>%2 27.4m<br/>%2 36.6m %3ロープ%4には、車両の%3けん引%4やヘリコプターからの%3ファストロープ%4など、複数の用途があります。<br/><br/>%3けん引方法:%4<br/>%2車両に近づきます。<br/>%2[%3%13%4] を使って%3けん引%4を選択します。<br/>%2ロープの長さを選択します。<br/>%2けん引する車両のロープ取付位置を選択します。<br/>%2けん引される車両のロープ取付位置を選択します。<br/><br/>%3利用可能なロープの長さ:%4<br/>%2 3.2 メートル<br/>%2 6.2 メートル<br/>%2 12.2 メートル<br/>%2 15.2 メートル<br/>%2 18.3 メートル<br/>%2 27.4 メートル<br/>%2 36.6 メートル + Las %3Cuerdas%4 tienen múltiples usos incluyendo el %3Remolcado%4 de vehículos y el %3Descenso con Cuerda%4 desde helicópteros.<br/><br/>%3Remolcado:%4<br/>%2Acércate a un vehículo.<br/>%2Usar [%3%13%4] y seleccionar %3Remolcado%4.<br/>%2Selecciona la longitud de la cuerda.<br/>%2Selecciona un punto de anclaje en el vehículo de remolcado.<br/>%2Selecciona una sujección en el vehículo remolcado.<br/><br/>%3Longitudes de Cuerda Disponibles:%4<br/>%2 3.2 metros<br/>%2 6.2 metros<br/>%2 12.2 metros<br/>%2 15.2 metros<br/>%2 18.3 metros<br/>%2 27.4 metros<br/>%2 36.6 metros Expand Your Fortifications @@ -631,6 +697,7 @@ 要塞を拡張する Расширить свои укрепления Élargissez vos fortifications + Expande Tus Fortificaciones %3Sandbags%4 are sacks made of sturdy material, filled with sand, used for a variety of purposes such as creating barriers or providing stability in construction projects. Useful in expanding larger placed fortifications.<br/><br/>%3Usage:%4<br/>%2Equip a %3Sandbag (Empty)%4.<br/>%2Use [%3%12%4] and select %3Deploy Sandbag%4.<br/>%2Follow on-screen instructions for placement. @@ -638,6 +705,7 @@ %3Sacchi di Sabbia%4 sono sacchi di un materiale robusto, riempiti di sabbia, usati per una varietà di utilizzi come creare barriere o aumentare la stabilità di fortificazioni.<br/><br/>%3Utilizzo:%4<br/>%2Equipaggia una %3Sacco di Sabbia (Vuoto)%4.<br/>%2Usa [%3%12%4] e seleziona %3Posiziona Sacco di Sabbia%4.<br/>%2Segui le istruzioni sullo schermo per il piazzamento. %3모래주머니%4는 튼튼한 재료로 만든 주머니로 모래를 채워 장벽을 만들거나 건설 작업에서 안정성을 제공하는 등 다양한 용도로 사용되며, 더 큰 요새를 확장하는 데 유용합니다.<br/><br/>%3사용 방법:%4<br/>%2%3모래주머니(비어있음)%4을 장착하십시오.<br/>%2[%3%12%4]를 사용하고 %3모래주머니 배치%4를 선택하십시오.<br/>%2화면의 지시에 따라 배치하십시오. %3土のう%4は、砂が詰められた頑丈な素材で作られた袋で、建設プロジェクトでの障壁の作成や安定性の提供など、さまざまな目的に使用されます。より大きな配置の要塞を拡張するのに役立ちます。<br/><br/>%3使用方法:%4<br/>%2%3土のう (空)%4を装備します。<br/>%2[%3%12%4] を使って%3土のうを作る%4を選択します。<br/>%2画面上の指示に従って配置します。 + Los %3Sacos de tierra%4 son sacos hechos de un material resistente, rellenados de tierra, usados para una diversa variedad de propósitos como la construcción de barreras o proveer estabilidad en los proyectos de construcción. Son útiles en la expansión de proyectos de construcción más grandes.<br/><br/>%3Uso:%4<br/>%2Equipa un %3Saco de tierra (Vacío)%4.<br/>%2Usar [%3%12%4] y seleccionar %3Desplegar Saco de tierra%4.<br/>%2Seguir las instrucciones en pantalla para su colocación. Lower Firearm Temperature @@ -647,6 +715,7 @@ 銃の熱を冷ます Понизьте температуру оружия Refroidir l'arme + Bajar la Temperatura del Arma %3Spare Barrels%4 allow a soldier to reduce their weapon's heat significantly. After a short delay, the weapon's barrel will be swapped and its heat reduced. A soldier may also check the temperature of any barrels within their inventory. Not all weapons support swapping barrels.<br/><br/>%3Usage:%4<br/>%2Use [%3%12%4] and select %3Equipment%4.<br/>%2Select %3Swap Barrel%4.<br/>%2Resume operation after barrel swap is complete. @@ -654,6 +723,7 @@ %3Canne di Ricambio%4 permettono ai soldati di raffreddare la loro arma notevolmente. Dopo una breve attesa, la canna dell'arma verrà sostituita e la temperatura ridotta. Un soldato può anche controllare la temperatura di canne di ricambio presenti nel proprio inventario. Non tutte le armi consentono lo scambio canna.<br/><br/>%3Utilizzo:%4<br/>%2Usa [%3%12%4] e seleziona %3Equipaggiamento%4.<br/>%2Seleziona %3Sostituisci Canna%4.<br/>%2Continua l'ingaggio dopo sostituzione avvenuta. %3예비 총열%4을 사용하면 병사의 무기의 발열을 크게 줄일 수 있습니다. 잠시 뒤에 무기의 총신이 교체되고 발열이 감소합니다. 군인은 소지품에 있는 총열의 온도도 확인할 수 있습니다. 모든 무기가 총열 교환을 지원하는 것은 아닙니다.<br/><br/>%3사용 방법:%4<br/>%2[%3%12%4]를 사용하고 %3장비%4를 선택하십시오.<br/>%2%3총열 교체%4를 선택하십시오.<br/>%2총열 교체가 완료된 후 작전을 계속하십시오. %3予備銃身%4を使用すると、兵士は武器の熱を大幅に下げることができます。少し経つと、武器の銃身が交換され熱が下がります。兵士はインベントリ内の銃身の温度を確認することもできます。すべての武器が銃身の交換をサポートしているわけではありません。<br/><br/>%3使用方法:%4<br/>%2[%3%12%4] を使って%3装備%4を選択します。<br/>%2%3銃身を交換%4を選択します。<br/>%2銃身交換が完了すると、再度射撃することが出来ます。 + El %3Cañón de Repuesto%4 permite a un soldado reducir el calor del arma significativamente. Tras un pequeño periodo, el cañón del arma habrá sido sustituido y el calor reducido. Un soldado puede tambien comprobar la temperatura de cualquier cañón en su inventario. No todas las armas soportan el cambio de cañón.<br/><br/>%3Uso:%4<br/>%2Usar [%3%12%4] y seleccionar %3Equipamiento%4.<br/>%2Seleccionar %3Cambiar Cañón%4.<br/>%2Continuar con la operación una vez se haya cambiado el cañón. Spray Paint @@ -663,6 +733,7 @@ ペイントスプレー Аэрозольная краска Bombe de peinture + Pintura En Spray Tag Your Territory @@ -672,6 +743,7 @@ 自分のテリトリーをマーキング Пометьте свою территорию Marquez votre territoire + Marca Tu Territorio %3Spray Paint%4 is used to tag surfaces with various symbols.<br/><br/>%3Usage:%4<br/>%2Move close to a surface (wall, vehicle, ground, etc).<br/>%2Use [%3%12%4] and select %3Tag%4.<br/>%2Choose a symbol.<br/><br/>%3Available Colors:%4<br/>%2Black<br/>%2Blue<br/>%2Green<br/>%2Red @@ -679,6 +751,7 @@ %3Bombolette Spray%4 vengono usate per marcare superfici con vari simboli.<br/><br/>%3Utilizzo:%4<br/>%2Muoviti vicino a una superfice (muro, veicolo, suolo, etc).<br/>%2Usa [%3%12%4] e seleziona %3Marca%4.<br/>%2Seleziona un simbolo.<br/><br/>%3Colori disponibili:%4<br/>%2Nero<br/>%2Blu<br/>%2Verde<br/>%2Rosso %3스프레이 페인트%4다양한 기호로 표면에 태그를 지정하는 데 사용됩니다.<br/><br/>%3사용 방법:%4<br/>%2표면(벽, 차량, 지면 등)에 가까이 가십시오.<br/>%2[%3%12%4]를 사용하고 %3태그%4를 선택하십시오.<br/>%2모양을 고르십시오.<br/><br/>%3사용 가능 색상:%4<br/>%2검정<br/>%2파랑<br/>%2초록<br/>%2빨강 %3ペイントスプレー%4は、地面や壁、車両の表面などに様々な図形のタグを付けるために使えます。<br/><br/>%3使用方法:%4<br/>%2塗りたい面に近づきます。(壁、車両、地面など)<br/>%2[%3%12%4] を使って%3タグ (スプレーペイント)%4を選択します。<br/>%2図形を選びます。<br/><br/>%3利用可能な色:%4<br/>%2黒<br/>%2白<br/>%2赤<br/>%2青<br/>%2緑<br/>%2黄 + La %3Pintura en Spray%4 se usa para marcar superficies con varios símbolos.<br/><br/>%3Uso:%4<br/>%2Acércate a una superficie (pared, vehículo, suelo, etc).<br/>%2Usar [%3%12%4] y seleccionar %3Tag%4.<br/>%2Elige un símbolo.<br/><br/>%3Colores disponibles:%4<br/>%2Negro<br/>%2Azul<br/>%2Verde<br/>%2Rojo Brace From Anywhere @@ -688,6 +761,7 @@ どこでも支持器 Опора может быть установлена в любом месте Stabilisé partout + Apoyarte En Cualquier Lugar The %3SSWT Kit%4 is a deployable tripod that allows a soldier to brace their aim when deployed. Use it when you need an elevated shooting position and there are no other objects around.<br/><br/>%3Usage:%4<br/>%2Use [%3%12%4] and select %3Equipment%4.<br/>%2Select %3SSWT Kit%4 and follow the on screen prompts to place. @@ -695,6 +769,7 @@ Il %3Kit SSWT%4 è un treppiede piazzabile che permette al soldato di appoggiare la sua arma. Usalo quando ti serve una posizione di tiro rialzata e non ci sono altri oggetti utili nelle vicinanze.<br/><br/>%3Utilizzo:%4<br/>%2Usa [%3%12%4] e seleziona %3Equipaggiamento%4.<br/>%2Seleziona %3Kit SSWT%4 e segui le indicazioni di piazzamento. %3SSWT 키트%4는 병사가 배치 시 조준력을 상승시킬 수 있는 배치 가능한 삼각대입니다. 높이 조절이 된 사격 위치가 필요하고 주위에 다른 물체가 없을 때 사용하십시오.<br/><br/>%3사용 방법:%4<br/>%2[%3%12%4] 를 사용하고 %3장비%4를 선택하십시오.<br/>%2%3SSWT 키트%4를 선택하고 화면의 지시에 따라 배치하십시오. %3SSWT キット%4は展開可能な三脚で、展開時に兵士が狙いを定めることができます。高い射撃位置が必要で、周囲に他の物体がない場合に使用してください。<br/><br/>%3使用方法:%4<br/>%2[%3%12%4] を使って%3装備%4を選択します。<br/>%2%3SSWT キット%4を選択し、画面上の指示に従って配置します。 + El %3Kit SSWT%4 es un trípode desplegable que permite a un soldado apoyarse para apuntar cuando está desplegado. Úsalo cuando necesites una posición de tiro elevada y no hay ningún otro objeto alrededor.<br/><br/>%3Uso:%4<br/>%2Usar [%3%12%4] y seleccionar %3Equipamiento%4.<br/>%2Seleccionar %3Kit SSWT%4 y sigue las indicaciones en pantalla para colocarlo. Keep Eyes In The Sky @@ -705,6 +780,7 @@ Не Отрывай Глаз От Неба Gardez les yeux au ciel Gardez les yeux au ciel + Manten Tus Ojos En El Cielo %3UAV Batteries%4 are used to recharge a UAV's energy storage. Especially useful for small UAVs.<br/><br/>%3Usage:%4<br/>%2Equip a %3UAV Battery%4<br/>%2Approach a %3UAV%4 with its %3Engine Off%4.<br/>%2Use [%3%13%4] and select %3Recharge%4. @@ -712,6 +788,7 @@ %3Batteria UAV%4 vengono usate per ricaricare gli UAV. Molto utile per piccoli UAV.<br/><br/>%3Utilizzo:%4<br/>%2Equipaggia una %3Batteria UAV%4<br/>%2Avvicinati al %3UAV%4 con il %3Motore Spento%4.<br/>%2Usa [%3%13%4] e seleziona %3Ricarica%4. %3무인기 배터리%4는 무인기의 에너지 저장소를 재충전하는 데 사용됩니다. 소형 무인기에 특히 유용합니다.<br/><br/>%3사용 방법:%4<br/>%2%3무인기 배터리%4를 장착하십시오.<br/>%2%3엔진을 끄고%4 %3무인기%4에 접근하십시오.<br/>%2[%3%13%4]를 사용하고 %3재충전%4을 선택하십시오. %3UAVバッテリー%4は、UAVの電源容量を充電するために使用されます。<br/><br/>%3使用方法:%4<br/>%2%3UAV バッテリー%4を装備します。<br/>%2%3エンジンをオフ%4にした%3UAV%4に近づきます。<br/>%2[%3%13%4] を使って%3充電%4を選択します。 + La %3Batería de VANT%4 se utilizan para recargar el almacenamiento de energía de un VANT. Especialmente útiles para pequeños VANTs.<br/><br/>%3Uso:%4<br/>%2Equipa una %3Batería de VANT%4<br/>%2Acércate a un %3VANT%4 con su %3Motor Apagado%4.<br/>%2Usa [%3%13%4] y selecciona %3Recargar%4. Making An Entrance @@ -721,6 +798,7 @@ 堂々入場する Создание собственного входа Faire son entrée + Abriendo Una Entrada %3Wirecutters%4 are a tool that allows a soldier to bypass wired fencing. Useful for creating backdoor entrances into secure areas.<br/><br/>%3Usage:%4<br/>%2Move close to a fence.<br/>%2Use [%3%12%4] and select %3Cut Fence%4. @@ -728,6 +806,7 @@ La %3Trancia%4 è un utensile che permette ai soldati di sorpassare filo spinato e recinzioni. Utile per creare punti di accesso nel retro di zone protette.<br/><br/>%3Utilizzo:%4<br/>%2Avvicinati a una barriera.<br/>%2Usa [%3%12%4] e seleziona %3Taglia%4. %3절단기%4는 병사가 철조망을 통과할 수 있게 해주는 도구입니다. 보안 구역에 뒷입구를 만드는 데 유용합니다.<br/><br/>%3사용 방법:%4<br/>%2철조망에 가까이 가십시오.<br/>%2[%3%13%4]를 사용하고 %3철조망 자르기%4를 선택하십시오. %3ワイヤーカッター%4は、兵士が有線フェンスを回避できるようにするツールです。安全にエリアへの裏口を作成するのに役立ちます。<br/><br/>%3使用方法:%4<br/>%2フェンスの近くに移動します。<br/>%2[%3%12%4] を使って%3フェンスを切断する%4を選択します。 + La %3Cizalla%4 es una herramienta que permite a un soldado atravesar una valla de alambre. Es útil para crear entradas traseras en áreas seguras.<br/><br/>%3Uso:%4<br/>%2Acércate a una valla.<br/>%2Usar [%3%12%4] y seleccionar %3Cortar Valla%4. Items @@ -770,6 +849,7 @@ 要塞を構築する Стройте укрепления Construire des fortifications + Construir Fortificaciones The %3Fortify Tool%4 allows soldiers to build fortifications provided by their mission creator.<br/><br/>%3Usage:%4<br/>%2Pick up a %3Fortify Tool%4.<br/>%2Use [%3%12%4] and select %3Fortify%4.<br/>%2Select an available fortification and follow the on screen prompts for placement. @@ -777,6 +857,7 @@ L'%3Attrezzo di Fortificazione%4 permette ai soldati di costruire fortificazioni permesse dal creatore della missione.<br/><br/>%3Utilizzo:%4<br/>%2Raccogli un %3Attrezzo di Fortificazione%4.<br/>%2Usa [%3%12%4] e seleziona %3Fortifica%4.<br/>%2Seleziona una fortificazione disponibile e segui le indicazioni di piazzamento sullo schermo. %3요새화 도구%4를 사용하면 병사들이 임무 생성자가 제공한 요새를 구축할 수 있습니다.<br/><br/>%3사용 방법:%4<br/>%2%3요새화 도구%4를 가지십시오.<br/>%2[%3%12%4]를 사용하고 %3요새화%4를 선택하십시오.<br/>%2사용 가능한 요새를 선택하고 화면의 지시에 따라 배치하십시오. %3要塞ツール%4を使用すると、兵士はミッション作成者が提供した要塞を構築できます。<br/><br/>%3使用方法:%4<br/>%2%3要塞ツール%4を持つ。<br/>%2[%3%12%4] を使って%3要塞%4を選択します。<br/>%2利用可能な構造物を選択し、画面上の指示に従って配置します。 + La %3Herramienta de Fortificación%4 permite a los soldados construir fortificaciones provistas por su creador de mision.<br/><br/>%3Uso:%4<br/>%2Coge una %3Herramienta de Fortificación%4.<br/>%2Usar [%3%12%4] y seleccionar %3Fortificar%4.<br/>%2Selecciona una fortificación disponible y sigue las instrucciones en pantalla para su colocación. Breaking and Entering @@ -786,6 +867,7 @@ 破壊して乗り込む Взлом и проникновение Entrée par effraction + Romper y Entrar %3Lockpicks%4 are used to gain access to locked vehicles.<br/><br/>%3Usage:%4<br/>%2Equip a %3Lockpick%4.<br/>%2Approach a %3Locked%4 vehicle.<br/>Use [%3%13%4] and select %3Lockpick Vehicle%4.<br/><br/><t underline='1'>%3Note:%4</t> Lockpicks and keys are only available via scripting or ACE Vehicle Key modules. @@ -793,6 +875,7 @@ I %3Grimaldelli%4 sono usati per forzare l'accesso a veicoli bloccati.<br/><br/>%3Utilizzo:%4<br/>%2Equipaggia un %3Grimaldello%4.<br/>%2Avvicinati a un veicolo %3Bloccato%4 vehicle.<br/>Usa [%3%13%4] e seleziona %3Scassina Veicolo%4.<br/><br/><t underline='1'>%3Note:%4</t> Grimaldelli e chiavi sono solo reperibili mediante scripting o moduli ACE di assegnazione Chiavi Veicoli. %3해정도구%4는 잠긴 차량에 들어가는 데 사용됩니다.<br/><br/>%3사용 방법:%4<br/>%2%3해정도구%4를 장착하십시오.<br/>%2%3잠긴%4 차량에 접근하십시오.<br/>[%3%13%4]를 사용하고 %3차량 잠금해제%4를 선택하십시오.<br/><br/><t underline='1'>%3참고:%4</t> 해정도구와 열쇠는 스크립팅 또는 ACE 차량 열쇠 모듈에서만 사용할 수 있습니다. %3Lockpick%4は、ロックされた車両にアクセスするために使用されます。<br/><br/>%3使用方法:%4<br/>%2%3Lockpick%4を装備します。<br/>%2%3鍵の掛かった%4車両に近づきます。<br/>[%3%13%4] を使って%3鍵をこじ開ける%4を選択します。<br/><br/><t underline='1'>%3備考:%4</t> ロックピックとキーは、スクリプトまたは ACE Vehicle Key モジュールを介してのみ使用できます。 + La %3Ganzúa%4 es usada para lograr acceso a vehículos bloqueados.<br/><br/>%3Uso:%4<br/>%2Equipar %3Ganzúa%4.<br/>%2Acércate a un vehículo %3Bloqueado%4.<br/>Usar [%3%13%4] y seleccionar %3Ganzuar Vehículo%4.<br/><br/><t underline='1'>%3Nota:%4</t>Ganzúas y Llaves sólo están disponibles mediante scripting o módulos de Llaves de Vehículos ACE. Vehicle Keys @@ -802,6 +885,7 @@ 車両キー Взлом и проникновение Clés de véhicule + Llaves de Vehículos Lock/Unlock Vehicles @@ -811,6 +895,7 @@ 車両のロック/ロック解除 Взлом и проникновение Verrouiller/déverrouiller un véhicule + Bloquear/Desbloquear vehículos %3Vehicle Keys%4 are used to lock/unlock your vehicles. Vehicle keys can exist for the whole side, or keys can be created for a particular vehicle itself.<br/><br/>%3Usage:%4<br/>%2Equip a %3Vehicle Key%4.<br/>%2Approach the vehicle that the key belongs to.<br/>Use [%3%13%4] and select %3Lock/Unlock Vehicle%4.<br/><br/><t underline='1'>%3Note:%4</t> Lockpicks and keys are only available via scripting or ACE Vehicle Key modules. @@ -818,6 +903,7 @@ Le %3Chiavi di Veicoli%4 vengono usate per bloccare/sbloccare i propri veicoli. Chiavi di veicoli possono esistere per un'intera fazione, oppure per un veicolo particolare.<br/><br/>%3Utilizzo:%4<br/>%2Equipaggia una %3Chiave di Veicolo%4.<br/>%2Avvicinati al veicolo a cui appartiene la chiave.<br/>Usa [%3%13%4] e seleziona %3Blocca/Sblocca Veicolo%4.<br/><br/><t underline='1'>%3Note:%4</t> Grimaldelli e chiavi sono solo disponibili mediante scripting o moduli ACE Chiavi Veicoli. %3차량 열쇠%4는 차량을 잠그거나 잠금해제하는 데 사용됩니다. 차량 열쇠는 모든 세력에게 존재할 수도 있고, 특정 차량 자체에 대해 열쇠를 생성할 수도 있습니다.<br/><br/>%3사용 방법:%4<br/>%2%3차량 열쇠%4를 장착하십시오.<br/>%2해당 열쇠에 속한 차량에 접근하십시오.<br/>[%3%13%4]를 사용하고 %3차량 잠금/잠금해제%4를 선택하십시오.<br/><br/><t underline='1'>%3참고:%4</t> 해정도구와 열쇠는 스크립팅 또는 ACE 차량 열쇠 모듈에서만 사용할 수 있습니다. %3Vehicle Key%4は、車両のロック/ロック解除に使用されます。車両キーは陣営全体に存在することも、特定の車両だけに対してキーを作成することもできます。<br/><br/>%3使用方法:%4<br/>%2%3Vehicle Key%4を装備します。<br/>%2鍵の対応している車両に近づきます。<br/>[%3%13%4] を使って%3鍵を解錠/施錠%4します。<br/><br/><t underline='1'>%3備考:%4</t> ロックピックとキーは、スクリプトまたは ACE Vehicle Key モジュールを介してのみ使用できます。 + Las %3Llaves de Vehículos%4 son usadas para bloquear/desbloquear tus vehículos. Las Llaves de Vehículos existen para un bando entero o para un vehículo concreto.<br/><br/>%3Uso:%4<br/>%2Equipa una %3Llave de Vehículo%4.<br/>%2Acércate a un vehículo cuya llave corresponda.<br/>Usar [%3%13%4] y selecciona %3Bloquear/Desbloquear Vehículo%4.<br/><br/><t underline='1'>%3Nota:%4</t> Ganzúas y Llaves sólo están disponibles mediante scripting o módulos de Llaves de Vehículos ACE diff --git a/addons/hearing/stringtable.xml b/addons/hearing/stringtable.xml index fcdbecb2ff..ff912a75d1 100644 --- a/addons/hearing/stringtable.xml +++ b/addons/hearing/stringtable.xml @@ -370,12 +370,14 @@ Metti/Togli tappi 귀마개 토글 Mettre/enlever les bouchons + Poner/quitar tapones Only units with heavy weapons Uniquement les unités dotées d'armes lourdes Только юниты с тяжелым вооружением 重火器を装備したユニットのみ + Sólo unidades con armas pesadas Solo a unità con armi pesanti diff --git a/addons/irlight/stringtable.xml b/addons/irlight/stringtable.xml index 5423a8a8a0..506e9deb9d 100644 --- a/addons/irlight/stringtable.xml +++ b/addons/irlight/stringtable.xml @@ -11,6 +11,7 @@ DBAL-A3 (vermelho) DBAL-A3 (赤) DBAL-A3 (красный) + DBAL-A3 (rojo) DBAL-A3 (green) @@ -22,6 +23,7 @@ DBAL-A3 (Verde) DBAL-A3 (緑) DBAL-A3 (зеленый) + DBAL-A3 (verde) <t color='#9cf953'>Use: </t>Turn Laser ON/OFF<br>Double click to switch mode @@ -33,6 +35,7 @@ <t color='#9cf953'>Uso: </t>Ligar/Desligar Laser<br>Duplo clique para mudar o modo <t color='#9cf953'>使用方法: </t>レーザーのオン/オフ切り替え<br>ダブルクリックでモード切り替え <t color='#9cf953'>Использование: </t>Включение / выключение лазера <br>Двойной щелчок для переключения режима + <t color='#9cf953'>Uso: </t>Alternar Láser ON/OFF<br>Doble click para cambiar estado Dual Beam Aiming Laser @@ -44,6 +47,7 @@ Laser de Pontaria de Duplo Feixe 複合ビーム照準レーザー Двухлучевой прицельный лазер + Láser de Apuntado de Doble Haz Visible Laser @@ -55,6 +59,7 @@ Laser Visível 可視光レーザー Видимый лазер + Láser Visible IR Laser @@ -66,6 +71,7 @@ Laser IR IRレーザー ИК-лазер + Láser IR IR Illuminator @@ -77,6 +83,7 @@ Iluminador IR IRイルミネーター ИК-осветитель + Iluminador IR IR Laser and Illuminator @@ -88,6 +95,7 @@ Laser e Iluminador IR IRレーザーとイルミネーター ИК-лазер и осветитель + Láser e Iluminador IR Wide Beam @@ -99,6 +107,7 @@ Feixe Largo 広角ビーム Широкий луч + Haz Ancho Medium Beam @@ -110,6 +119,7 @@ Feixe Médio 標準ビーム Средний луч + Haz Medio Narrow Beam @@ -121,6 +131,7 @@ Feixe Estreito 狭角ビーム Узкий луч + Haz Estrecho <t color='#9cf953'>Use: </t>Turn Light ON/OFF<br>Double click to switch mode @@ -132,6 +143,7 @@ <t color='#9cf953'>Uso: </t>Ligar/Desligar Iluminador<br>Duplo clique para mudar o modo <t color='#9cf953'>使用方法: </t>ライトのオン/オフ<br>ダブルクリックでモード切り替え <t color='#9cf953'>Использование: </t>Включение / выключение освещения <br>Двойной щелчок для переключения режима + <t color='#9cf953'>Uso: </t>Alternar Luz ON/OFF<br>Doble click para cambiar estado Special Purpose IR LED Illuminator @@ -143,6 +155,7 @@ Iluminador LED IR de Uso Especial 特殊用途のIR LEDイルミネーター ИК-светодиодный осветитель специального назначения + Iluminador LED IR de Propósito Especial Illuminator / Laser Momentary Switch @@ -154,6 +167,7 @@ Interruptor Momentâneo Iluminador/Laser イルミネーター/レーザーモーメンタリースイッチ Мгновенный переключатель осветителя/лазера + Conmutador Momentáneo Iluminador / Láser diff --git a/addons/killtracker/stringtable.xml b/addons/killtracker/stringtable.xml index 24c7bcdd56..63196a442e 100644 --- a/addons/killtracker/stringtable.xml +++ b/addons/killtracker/stringtable.xml @@ -9,6 +9,7 @@ ACE キルトラッカー ACE 킬트래커 ACE Suivi des morts + ACE Contador de Muertes ACE Killed Events @@ -103,6 +104,7 @@ プレイヤーに殺害されたAIユニットを追跡 플레이어가 죽인 AI 트래킹 Suivi de l'IA tuée par les joueurs + Cuenta las unidades de IA matadas por el jugador Defines if killed AIs will be shown in the kill tracker during mission debriefing. @@ -112,6 +114,7 @@ ミッションデブリーフィングのキルトラッカーに殺害されたAIが表示されるかどうかを定義します。 사후강평 중 살해된 AI가 킬트래킹에 표시되는지 여부를 정의합니다. Définit si les IA tuées seront affichées dans le tracker pendant le débriefing de la mission. + Define si las IAs matadas se mostrarán en el contador de muertes en el debiefring de la misión. diff --git a/addons/laser/stringtable.xml b/addons/laser/stringtable.xml index f0977c84f7..c6bf7cfc25 100644 --- a/addons/laser/stringtable.xml +++ b/addons/laser/stringtable.xml @@ -129,6 +129,7 @@ Traqueur laser : activé Rastreador a Laser: Ligado Лазерный точечный трекер: Включен + Rastreador del Puntero Láser: On Laser Spot Tracker: Off @@ -140,6 +141,7 @@ Traqueur laser : désactivé Rastreador a Laser: Desligado Лазерный точечный трекер: выключен + Rastreador del Puntero Láser: Off Draw Laser on Map diff --git a/addons/maptools/stringtable.xml b/addons/maptools/stringtable.xml index bb0782f22b..f71cc8489f 100644 --- a/addons/maptools/stringtable.xml +++ b/addons/maptools/stringtable.xml @@ -42,6 +42,7 @@ Tavola di calcolo Графическая доска Planche traçante + Tablero de Trazado The Plotting Board is a map tool designed for use in the directing of short range indirect fires. @@ -50,6 +51,7 @@ La tavola di calcolo è uno strumento utilizzato per dirigere fuoco di artiglieria a corto raggio. Графическая доска - это картографический инструмент, предназначенный для использования при ведении непрямого огня с малой дистанции. Une planche traçante est un outil cartographique conçu pour diriger des tirs indirects à courte distance. + El Tablero de Trazado es una herramienta de mapa utilizada para dirigir fuego indirecto de corto alcance. Map Tools @@ -275,6 +277,7 @@ Canali ammessi su tavola di calcolo Разрешить создание каналов на миллиметровой доске. Canaux autorisés sur la planche traçante + Permitir Canales de Dibujado de Tablero de Trazado Channels in which plotting board drawing is enabled. @@ -283,6 +286,7 @@ Canali in cui si può disegnare sulla tavola di calcolo. Каналы, в которых включено рисование на миллиметровой доске. Canaux dans lesquels vous pouvez dessiner sur le planche traçante + Canales en los que el tablero de trazado está habilitado. Allow Direct Comms Only (Polylines Only) @@ -291,6 +295,7 @@ Comunicazioni Dirette (solo linee) Разрешать только прямую связь (только полилинии) Communications directes uniquement (lignes uniquement) + Permitir Sólo Comunicaciones Directas (Sólo Polylineas) Allow Direct/Group Comms (Polylines and Group Markers) @@ -299,6 +304,7 @@ Comunicazioni dirette/gruppo (linee e marker) Разрешить прямую/групповую связь (полилинии и групповые маркеры) Autoriser les communications directes/de groupe (polylignes et marqueurs de groupe) + Permitir Comunicaciones Directas/Grupales (Polylineas y Marcadores de Grupo) Plotting Board @@ -307,6 +313,7 @@ Tavola di calcolo Миллиметровая доска Planche traçante + Tablero de Trazado Plotting Board Acrylic @@ -315,6 +322,7 @@ Acrilico tavola di calcolo Миллиметровая доска акрилловая Planche traçante Acrylique + Tablero de Trazado Acrílico Plotting Board Ruler @@ -323,6 +331,7 @@ Righello tavola di calcolo Линейка для миллиметровой доски Règle de la planche traçante + Regla de Tablero de Trazado To Plotting Board @@ -331,6 +340,7 @@ Su tavola di calcolo К миллиметровой доске. Sur la planche traçante + A Tablero de Trazado To Plotting Board Acrylic @@ -339,6 +349,7 @@ Su acrilico tavola di calcolo К миллиметровой доске акрилловой Sur la planche traçante Acrylique + A Tablero de Trazado Acrílico To Plotting Board Ruler @@ -347,6 +358,7 @@ Su righello tavola di calcolo К линейке миллиметровой доски. Sur la règle de la planche traçante + A Regla de Tablero de Trazado Wipe all markers off Plotting Board @@ -355,6 +367,7 @@ Cancella tutti i disegni dalla tavola Сотрите все маркеры с миллиметровой доски. Effacer tous les dessins de la planche traçante + Borrar todas las marcas del Tablero de Trazado Show Plotting Board @@ -363,6 +376,7 @@ Mostra tavola di calcolo Показать миллиметровую доску. Afficher la planche traçante + Mostrar Tablero de Trazado Hide Plotting Board @@ -371,6 +385,7 @@ Nascondi tavola di calcolo Скрыть миллиметровую доску. Masquer la planche traçante + Ocultar Tablero de Trazado Toggle Plotting Board Ruler @@ -379,6 +394,7 @@ Mostra/Nascondi Righello Переключить линейку миллиметровой доски. Afficher/masquer la règle + Alternar Regla de Tablero de Trazado Align @@ -429,6 +445,7 @@ Su Вверх Monter + Arriba To Maptool @@ -437,6 +454,7 @@ Su strumento cartografico К инструментам карты Outil cartographique + A Herramienta de Mapa diff --git a/addons/markers/stringtable.xml b/addons/markers/stringtable.xml index a0c0be17f7..2c9dc1531b 100644 --- a/addons/markers/stringtable.xml +++ b/addons/markers/stringtable.xml @@ -421,6 +421,7 @@ "MS" - 밀리초 (0부터 59까지) "MM" - ミリ秒 (0から59) "ММ" - миллисекунды (от 0 до 59) + "MM" - Milisegundos (de 0 a 59) "mmm" - Milliseconds (from 0 to 999) @@ -431,6 +432,7 @@ "mmm" - 밀리초 (0부터 999까지) "mmm" - ミリ秒 (0から599) "ммм" - миллисекунды (от 0 до 999) + "mmm" - Milisegundos (de 0 a 999) Timestamp Hour Format diff --git a/addons/medical_ai/stringtable.xml b/addons/medical_ai/stringtable.xml index 5081a09d96..54f0c2714c 100644 --- a/addons/medical_ai/stringtable.xml +++ b/addons/medical_ai/stringtable.xml @@ -58,6 +58,7 @@ Exigir Itens アイテムを要求 Требуемые предметы + Requerir Objetos AI will only perform medical treatment if they have the necessary items in their inventory. @@ -69,6 +70,7 @@ A IA só irá realizar tratamento médico se tiver os itens necessários em seu inventário. AIのインベントリに必要なアイテムがある場合にのみ治療を実行します。 Искусственный интеллект будет оказывать медицинскую помощь только в том случае, если в его инвентаре есть необходимые предметы. + La IA sólo realizará el tratamiento médico en caso de que dispongan de los objetos necesarios en su inventario. Auto Convert Items for AI @@ -80,6 +82,7 @@ Conversão automática de itens para IA AIのアイテムを自動変換 Автоматическое преобразование элементов для ИИ + Auto Convertir Objetos para la IA diff --git a/addons/medical_damage/stringtable.xml b/addons/medical_damage/stringtable.xml index 626826117d..3f274dd37a 100644 --- a/addons/medical_damage/stringtable.xml +++ b/addons/medical_damage/stringtable.xml @@ -803,6 +803,7 @@ Schmerz-Bewusstlosigkeit-Grenze 고통 기절 한계점 Limite de Dor Antes da Inconsciência + Umbral de Dolor de Inconsciencia Sets the threshold for severe pain, above which a person can fall unconscious upon receiving damage. @@ -814,6 +815,7 @@ Legt die Grenze für starke Schmerzen fest, oberhalb derer eine Person bei erlittenem Schaden bewusstlos werden kann. 사람이 데미지를 입었을 때 의식불명 상태가 될 수 있는 심각한 고통의 한계점을 설정합니다. Define o limite para dor severa, acima do qual uma pessoa pode ficar inconsciente ao receber dano. + Establece el umbral para dolor severo, sobre el cual una persona puede caer inconsciente una vez reciba daño. Fatal Injury Death Chance diff --git a/addons/medical_engine/stringtable.xml b/addons/medical_engine/stringtable.xml index 1765df0d39..cf19713202 100644 --- a/addons/medical_engine/stringtable.xml +++ b/addons/medical_engine/stringtable.xml @@ -37,6 +37,7 @@ Efeito de Penetração de Blindagem 装甲貫通効果 Эффект сквозного прохождения брони + Efecto de Atravesar Armadura Controls effect of armor 'passThrough' on final damage. Makes high armor values, like ones used in GL rigs, less effective.\nUse 0% for pre 3.16.0 armor behavior.\nOnly touch this if you know what you're doing! @@ -48,6 +49,7 @@ Controla o efeito de penetração (passThrough) da blindagem no dano final. Torna valores de blindagem altos, como os usados em coletes GL, menos eficazes.\nUse 0% para o comportamento de blindagem anterior à versão 3.16.0.\nSó mexa nisso se souber o que está fazendo! ボディアーマーの'passThrough'値が最終的な身体ダメージに与える影響を調整します。擲弾兵リグで使用されるような高い装甲値では効果が低くなります。\n3.16.0以前の挙動にするには0%にしてください。\nこれが何かわからない場合は変更しないことをお勧めします。 Контролирует эффект `passThrough` при нанесении конечного урона. Делает высокие значения брони, подобные тем, которые используются в GL rigs, менее эффективными.\nИспользуйте 0% для поведения брони до версии 3.16.0.n\Прикасайтесь к этому, только если знаете, что делаете! + Controla el efecto de 'passThrough' de armadura en el daño final. Hace que los valores altos de armadura, como los usados en los chalecos GL, sean menos efectivos.\nUsar 0% para comportamiento de armadura en versiones anteriores a 3.16.0.\nSólo modifica esto si sabes lo que estás haciendo! diff --git a/addons/medical_gui/stringtable.xml b/addons/medical_gui/stringtable.xml index 71388bfb41..b88d9cbbf1 100644 --- a/addons/medical_gui/stringtable.xml +++ b/addons/medical_gui/stringtable.xml @@ -293,6 +293,7 @@ Medizinische Info anzeigen 医療情報一時表示 Просмотр медицинской информации + Ojear Información Médica Medical Peek Duration @@ -303,6 +304,7 @@ Dauer zum Anzeigen der medizinischen Info 医療情報一時表示の表示時間 Продолжительность медицинского осмотра + Duración del Ojear Información Médica How long the medical info peek remains open after releasing the key. @@ -313,6 +315,7 @@ Durata di visualizzazione delle Info Mediche dopo aver rilasciato il tasto. 医療情報一時表示キーを放してからどれだけ長く情報表示するか。 Как долго окно просмотра медицинской информации остается открытым после отпускания клавиши. + Durante cuánto tiempo la información médica ojeada permanece abierta una ves se deje de apretar la tecla. Load Patient @@ -566,6 +569,7 @@ Passa a te stesso 自分に切り替え Переключиться на себя + Cambiar a uno mismo Switch to target @@ -576,6 +580,7 @@ Passa al paziente 相手に切り替え Переключиться на цель + Cambiar al objetivo Head @@ -1002,6 +1007,7 @@ Nessuna emorragia 出血はしていない Кровотечения нет + Sin sangrado Slow bleeding @@ -1012,6 +1018,7 @@ Debole emorragia 出血は穏やか Медленное кровотечение + Sangrado lento Moderate bleeding @@ -1022,6 +1029,7 @@ Emorraggia moderata 出血はそこそこ速い Умеренное кровотечение + Sangrado moderado Severe bleeding @@ -1032,6 +1040,7 @@ Forte emorragia 出血は激しい Сильное кровотечение + Sangrado severo Massive bleeding @@ -1042,6 +1051,7 @@ Gravissima emorragia 出血は酷く多い Огромное кровотечение + Sangrado masivo in Pain @@ -1116,6 +1126,7 @@ Nessuna perdita di sangue 失血なし Потери крови нет + Sin pérdida de sangre @@ -1400,6 +1411,7 @@ Zeige medizinische Info beim Treffer an 被弾時の医療情報一時表示 Показать медицинскую информацию о попадании + Ojear Información Médica en Impacto Temporarily show medical info when injured. @@ -1411,6 +1423,7 @@ Bei Verletzungen vorübergehend medizinische Info anzeigen. 被弾時に医療情報を一時的に表示します。 Временно показывать медицинскую информацию при травме. + Temporalmente muestra la información médica cuando es herido. Medical Peek Duration on Hit @@ -1422,6 +1435,7 @@ Dauer der Anzeige bei einem Treffer. 被弾時の医療情報一時表示の表示時間 Продолжительность медицинского осмотра при попадании + Duración de Ojear la Información Médica cuando hay Impacto How long the medical info peek remains open after being injured. @@ -1433,6 +1447,7 @@ Wie lange die medizinische Info nach einer Verletzung angezeigt wird. 被弾時の医療情報の一時表示をどれだけ長く表示するか。 Как долго окно просмотра медицинской информации остается открытым после получения травмы. + Durante cuánto tiempo la información médica ojeada permanece abierta una tras haber sido herido. Show Trauma Sustained @@ -1445,6 +1460,7 @@ 显示遭受的创伤 Afficher les traumatismes subis Показать полученную травму + Mostrar Trauma Sostenido Show trauma sustained in the injury list. @@ -1457,6 +1473,7 @@ 在伤情表上显示创伤 Afficher les traumatismes subis dans la liste des blessures. Показать полученную травму в списке травм. + Mostrar trauma sostenido en la lista de heridas Body Part Outline Color @@ -1468,6 +1485,7 @@ Umrissfarbe des Körperteils 身体部位の輪郭表示の色 Цвет контура части тела + Color de Contorno de las Partes del Cuerpo Color of outline around selected body part. @@ -1479,6 +1497,7 @@ Farbe des Umrisses um das ausgewählten Körperteil. 選択した身体部位の輪郭表示の色。 Цвет контура вокруг выбранной части тела. + Color del contorno alrededor de la parte del cuerpo seleccionada. Minor Trauma @@ -1491,6 +1510,7 @@ 轻微创伤 Traumatisme mineur Незначительная травма + Trauma Menor Major Trauma @@ -1503,6 +1523,7 @@ 中度创伤 Traumatisme majeur Серьезная травма + Trauma mayor Severe Trauma @@ -1515,6 +1536,7 @@ 重度创伤 Traumatisme grave Тяжелая травма + Trauma Severo Chronic Trauma @@ -1527,6 +1549,7 @@ 慢性创伤 Traumatisme chronique Хроническая травма + Trauma Crónico L @@ -1538,6 +1561,7 @@ L Лево + I R @@ -1549,6 +1573,7 @@ R Право + D in your inventory @@ -1560,6 +1585,7 @@ im Inventar 個あなたが保有 в вашем инвентаре + en tu inventario in patient's inventory @@ -1571,6 +1597,7 @@ im Inventar des Patienten 個患者が保有 в инвентаре пациента + en el inventario del paciente in vehicle's inventory @@ -1582,6 +1609,7 @@ Nell'inventario del veicolo 個車両内に保有 в инвентаре транспорта + en el inventario del vehículo No effect until tourniquet removed @@ -1592,6 +1620,7 @@ Nessun effetto fino alla rimozione del laccio emostatico 止血帯を外すまで効果を発揮しません Никакого эффекта до тех пор, пока жгут не будет снят + Sin efecto hasta que se quita el torniquete Show Tourniquet Warning @@ -1602,6 +1631,7 @@ Mostra avviso di laccio emostatico 止血帯の警告を表示 Показать предупреждение о наложении жгута + Mostrar Advertencia de Torniquete Show a warning tooltip when a tourniquet will interfere with a medical action. @@ -1612,6 +1642,7 @@ Mostra un avviso se un laccio emostatico impedisce un trattamento medico. 止血帯が医療行為を妨げる場合には、警告ツールチップを表示します。 Показать всплывающую подсказку с предупреждением, когда жгут помешает медицинскому вмешательству. + Muestra un mensaje de advertencia cuando un torniquete interfiera con una acción médica. diff --git a/addons/medical_status/stringtable.xml b/addons/medical_status/stringtable.xml index f6f51b5533..ea3f77429b 100644 --- a/addons/medical_status/stringtable.xml +++ b/addons/medical_status/stringtable.xml @@ -126,6 +126,7 @@ Risque de perte d'arme 武器を落とす確率 Шанс выпадения оружия + Probabilidad de Soltar Arma Chance for a player to drop their weapon when going unconscious.\nHas no effect on AI. @@ -136,6 +137,7 @@ Pourcentage de chances pour un joueur de lâcher son arme lorsqu'il perd connaissance.\nAucun effet sur les IA. プレーヤーが意識を失ったときに武器を落とす可能性。\nAI には影響しません。 Шанс для игрока выронить свое оружие, когда он теряет сознание.\nНе влияет на ИИ + Probabilidad del jugador de soltar su arma cuando quedan inconscientes.\nNo tiene efecto sobre la IA. diff --git a/addons/medical_treatment/stringtable.xml b/addons/medical_treatment/stringtable.xml index 29774efb3c..ea38c6fbe8 100644 --- a/addons/medical_treatment/stringtable.xml +++ b/addons/medical_treatment/stringtable.xml @@ -439,6 +439,7 @@ Tempo di scavo tomba 墓掘りの所要時間 Время рытья могилы + Tiempo de Cavado de Tumba Time, in seconds, required to dig a grave for a body. @@ -449,6 +450,7 @@ Tempo in secondi richiesto per seppellire un morto. 遺体の墓を掘るのに掛かる時間。 (秒単位) Время в секундах, необходимое для того, чтобы выкопать могилу для тела. + Tiempo, en segundos, requerido para cavar una tumba para un cuerpo. Allow Epinephrine @@ -3506,6 +3508,7 @@ Kein Schmerz 痛みはない Нет боли + Sin dolor In mild pain @@ -3627,6 +3630,7 @@ Kein IV IV なし Нет капельницы + Sin IV Blood Pressure @@ -4657,6 +4661,7 @@ Scava tomba per cadavere 墓を掘る Выкопать могилу для тела + Cavar tumba para cuerpo Digging grave for body... @@ -4667,6 +4672,7 @@ Scavando tomba per cadavere... 墓を掘っています Рытьё могилы для тела... + Cavando tumba para cuerpo... %1 has bandaged patient @@ -4919,6 +4925,7 @@ Controlla nome sulla lapide 墓石の名前を確認 Проверьте имя на надгробии + Comprobar nombre en la lápida Bandage Rollover @@ -4929,6 +4936,7 @@ Srotolamento Bendaggi 包帯の繰り越し Перевязка множественных ран + Vendaje múltiple If enabled, bandages can close different types of wounds on the same body part.\nBandaging multiple injuries will scale bandaging time accordingly. @@ -4939,6 +4947,7 @@ Se attivo, un singolo bendaggio potrà chiudere più ferite sulla stessa parte del corpo.\nBendare più ferite di conseguenza richiederà più tempo. 有効にすると、体の同じ部分にある別の種類の傷を一つの包帯で閉じることができます。\n複数の傷に包帯を巻くと、それに応じて包帯時間が変動します。 Если эта функция включена, бинты могут закрывать различные типы ран на одной и той же части тела.\nПри перевязке нескольких повреждений время перевязки будет увеличено соответствующим образом. + Si se habilita, las vendas pueden cerrar diferentes tipos de heridas en la misma parte del cuerpo.n\Vendar múltiples heridas escala el tiempo de vendado acorde. Bandage Effectiveness Coefficient @@ -4949,6 +4958,7 @@ Coefficiente di efficacia bendaggi 包帯有効性係数 Коэффициент эффективности повязки + Coeficiente de Efectividad de Vendado Determines how effective bandages are at closing wounds. @@ -4959,6 +4969,7 @@ Determina quanto i bendaggi sono efficaci nel chiudere le ferite. 包帯が傷をふさぐのにどれだけ効果的かを定義します。 Определяет, насколько эффективны бинты при закрытии ран. + Determina como de efectivos son los vendajes cerrando heridas. Medical Items @@ -4982,6 +4993,7 @@ 제우스 치료 시간 계수 Коэффициент времени обработки Zeus Coeff. de temps + Coeficiente de Tiempo del Tratamiento de Zeus Multiply all treatment times with this coefficient when in Zeus. @@ -4991,6 +5003,7 @@ 제우스일 때 모든 치료 시간에 이 계수를 곱합니다. Умножьте все время лечения на этот коэффициент, когда вы находитесь в Zeus. Coefficient de temps de traitement Zeus + Multiplica los tiempos de tratamientos por este coeficiente cuando se está en Zeus Painkillers @@ -5015,6 +5028,7 @@ 鎮痛剤を投与 진통제 투여 Administrer des analgésiques + Administrar Analgésicos Administering Painkillers... @@ -5023,6 +5037,7 @@ 鎮痛剤を投与しています・・・ 진통제 투여 중... Administration d'analgésiques... + Administrando Analgésicos... Over-the-counter analgesic used to combat light to moderate pain experiences. @@ -5031,6 +5046,7 @@ 軽度から中程度の痛みに対処するために使用される市販の鎮痛薬。 가벼운 통증부터 중간 정도의 통증을 퇴치하는 데 사용되는 일반의약품 진통제입니다. Analgésique sans ordonnance utilisé pour lutter contre les douleurs légères à modérées. + Analgésico sin receta médica usado para aplacar dolores de ligeros a moderados. Over-the-counter analgesic used to combat light to moderate pain experiences. @@ -5039,6 +5055,7 @@ 軽度から中程度の痛みに対処するために使用される市販の鎮痛薬。 가벼운 통증부터 중간 정도의 통증을 퇴치하는 데 사용되는 일반의약품 진통제입니다. Analgésique sans ordonnance utilisé pour lutter contre les douleurs légères à modérées. + Analgésico sin receta médica usado para aplacar dolores de ligeros a moderados. diff --git a/addons/medical_vitals/stringtable.xml b/addons/medical_vitals/stringtable.xml index eb0080bd07..54c19f53fa 100644 --- a/addons/medical_vitals/stringtable.xml +++ b/addons/medical_vitals/stringtable.xml @@ -9,6 +9,7 @@ バイタル 생명 Paramètres vitaux + Vitales Enable SpO2 Simulation @@ -17,6 +18,7 @@ SpO2シミュレーションを有効化 산소포화도 시뮬레이션 활성화 Activer la simulation de la SpO2 + Habilitar Simulación SpO2 Enables oxygen saturation simulation, providing variable heart rate and oxygen demand based on physical activity and altitude. Required for Airway Management. @@ -25,6 +27,7 @@ 酸素飽和度シミュレーションを有効にし、身体活動や標高に基づいて変動する心拍数と酸素要求量の機能を提供します。 気道管理に必要です。 산소포화도 시뮬레이션을 활성화하여 신체 활동과 고도에 따라 다양한 심박수와 산소 요구량을 제공합니다. 기도 관리에 필요합니다. Permet de simuler la saturation en oxygène, de modifier la fréquence cardiaque et la consommation d'oxygène en fonction de l'activité physique et de l'altitude. Nécessaire pour la gestion des voies respiratoires. + Habilita la saturación de oxígeno, utilizando la demanda de oxígeno y ritmo cardíaco basado en la actividad física y la altitud. Requerido para el Manejo de las Vías Aéreas. diff --git a/addons/nightvision/stringtable.xml b/addons/nightvision/stringtable.xml index e1345ec44e..1c1cd61ba7 100644 --- a/addons/nightvision/stringtable.xml +++ b/addons/nightvision/stringtable.xml @@ -132,6 +132,7 @@ 야투경 (3세대, 갈색, 백색광) JVN (Gen3, marron, WP) ПНВ (Gen3, Коричневый, БФ) + Gafas de visión nocturna (Gen3, Marrón, FB) Night Vision Goggles, White Phosphor @@ -142,6 +143,7 @@ 백색광 야투경 Jumelles Vision Nocturne, Phosphore blanc Очки ночного видения, белый фосфор + Gafas de Visión Nocturna, Fósforo Blanco NV Goggles (Gen3, Green) @@ -169,6 +171,7 @@ 야투경 (3세대, 녹색, 백색광) JVN (Gen3, vertes, WP) ПНВ (Gen3, Зелёный, БФ) + Gafas de visión nocturna (Gen3, Verde, FB) NV Goggles (Gen3, Black) @@ -196,6 +199,7 @@ 야투경 (3세대, 검정, 백색광) JVN (Gen3, noires, WP) ПНВ (Gen3, Чёрный, БФ) + Gafas de visión nocturna (Gen3, Negro, FB) NV Goggles (Gen4, Brown) @@ -218,6 +222,7 @@ 야투경 (4세대, 갈색, 백색광) JVN (Gen4, marron, WP) ПНВ (Gen4, Коричневый, БФ) + Gafas de visión nocturna (Gen4, Marrón, FB) NV Goggles (Gen4, Black) @@ -240,6 +245,7 @@ 야투경 (4세대, 검정, 백색광) JVN (Gen4, noires, WP) ПНВ (Gen4, Чёрный, БФ) + Gafas de visión nocturna (Gen4, Negro, FB) NV Goggles (Gen4, Green) @@ -262,6 +268,7 @@ 야투경 (4세대, 녹색, 백색광) JVN (Gen4, vertes, WP) ПНВ (Gen4, Зелёный, БФ) + Gafas de visión nocturna (Gen4, Verde, FB) NV Goggles (Wide, Brown) @@ -284,6 +291,7 @@ 야투경 (넓음, 갈색, 백색광) JVN (Large, marron, WP) ПНВ (Широкий, Коричневый, БФ) + Gafas de visión nocturna (Panorámicas, Marrón, FB) NV Goggles (Wide, Black) @@ -306,6 +314,7 @@ 야투경 (넓음, 검정, 백색광) JVN (Large, noires, WP) ПНВ (Широкий, Чёрный, БФ) + Gafas de visión nocturna (Panorámicas, Negro, FB) NV Goggles (Wide, Green) @@ -328,6 +337,7 @@ 야투경 (넓음, 녹색, 백색광) JVN (Large, vertes, WP) ПНВ (Широкий, Зелёный, БФ) + Gafas de visión nocturna (Panorámicas, Verde, FB) Brightness: %1 @@ -587,6 +597,7 @@ 야투경 세대 Génération de jumelles de vision nocturne Генерация ночного видения + Generación de Visión Nocturna Gen %1 @@ -597,6 +608,7 @@ %1세대 Gen %1 Генерация %1 + Gen %1 diff --git a/addons/overheating/stringtable.xml b/addons/overheating/stringtable.xml index 48399b443c..8676ff67bb 100644 --- a/addons/overheating/stringtable.xml +++ b/addons/overheating/stringtable.xml @@ -882,6 +882,7 @@ 노리쇠 방식 Тип болта Type d'obturateur + Tipo de Cerrojo Open Bolt @@ -890,6 +891,7 @@ 오픈 볼트 Открыть болт Obturateur ouvert + Cerrojo Abierto Closed Bolt @@ -898,6 +900,7 @@ 클로즈드 볼트 Закрыть болт Obturateur fermé + Cerrojo Cerrado Barrel Type @@ -906,6 +909,7 @@ 총열 방식 Тип ствола Type de canon + Tipo de Cañón Non-Removeable @@ -914,6 +918,7 @@ 제거 불가 Несъемный Inamovible + No-Desmontable Quick Change @@ -922,6 +927,7 @@ 신속 교체 Быстросъемный Changement rapide + Cambiado Rápido diff --git a/addons/refuel/stringtable.xml b/addons/refuel/stringtable.xml index 909a3f4587..648ee38c6d 100644 --- a/addons/refuel/stringtable.xml +++ b/addons/refuel/stringtable.xml @@ -506,6 +506,7 @@ 연료통 집어들기 Взять канистру с топливом Ramasser le réservoir de carburant + Coger garrafa de combustible Picking fuel canister up... @@ -515,6 +516,7 @@ 연료통 집어드는 중... Поднимаю канистру с топливом... Ramasser les bidons de carburant... + Cogiendo garrafa de combustible... Connect fuel canister @@ -524,6 +526,7 @@ 연료통 꽂기 Подсоединить канистру с топливом Raccorder le réservoir de carburant + Conectar garrafa de combustible Connecting fuel canister... @@ -533,6 +536,7 @@ 연료통 꽂는 중... Подсоединение топливной канистры... Raccorder le réservoir de carburant... + Conectando garrafa de combustible... Disconnect fuel canister @@ -542,6 +546,7 @@ 연료통 빼기 Отсоединить канистру с топливом Débrancher le réservoir de carburant + Desconectar garrafa de combustible Refuel hose length diff --git a/addons/reload/stringtable.xml b/addons/reload/stringtable.xml index e081834e29..2c4bbcab76 100644 --- a/addons/reload/stringtable.xml +++ b/addons/reload/stringtable.xml @@ -138,6 +138,7 @@ Taśma została połączona 탄띠가 연결되었습니다 Ремень был пристегнут + Cinta enganchada Belt could not be linked @@ -148,6 +149,7 @@ Taśma nie mogła być połączona 탄띠를 연결할 수 없습니다 Ремень не удалось пристегнуть + La cinta no ha podido ser enganchada diff --git a/addons/reloadlaunchers/stringtable.xml b/addons/reloadlaunchers/stringtable.xml index ac42ef4d99..b55ccde170 100644 --- a/addons/reloadlaunchers/stringtable.xml +++ b/addons/reloadlaunchers/stringtable.xml @@ -10,6 +10,7 @@ 동료의 장전에 대한 알림 표시 Affichage de notifications lors d'une rechargement par un ami Отображает уведомления о загрузке помощника + Mostrar notificaciones para recarga de compañero Displays notifications when an assistant loads a gunner's launcher. @@ -20,6 +21,7 @@ 부사수가 사수의 발사기를 장전할 때 알림을 표시합니다. Affiche une notofication lorsqu'un assistant recharge l'arme du tireur. Отображает уведомления, когда помощник загружает пусковую установку стрелка. + Mostrar notificaciones cuando un asistente recarga el lanzador del tirador. Load launcher @@ -47,6 +49,7 @@ %1 ładuje twoją wyrzutnię %1이(가) 당신의 발사기를 장전했습니다. %1 загружает Вашу установку + %1 está cargando tu lanzador %1 stopped loading your launcher @@ -57,6 +60,7 @@ %1 przestał ładować twoją wyrzutnię %1이(가) 당신의 발사기 장전을 멈췄습니다. %1 прекратил загружать Вашу установку + %1 paró de cargar tu lanzador Loading launcher... @@ -118,6 +122,7 @@ Wyrzutnia nie mogła być załadowana 발사기를 장전할 수 없습니다. Не удалось загрузить пусковую установку + El lanzador no ha podido ser cargado Buddy Loading @@ -128,6 +133,7 @@ Nachladen durch Kamerad バディローディング Перезарядка помощником + Cargado de Compañero diff --git a/addons/repair/stringtable.xml b/addons/repair/stringtable.xml index 775202ed3a..850f9dee7f 100644 --- a/addons/repair/stringtable.xml +++ b/addons/repair/stringtable.xml @@ -281,6 +281,7 @@ 전체 수리 시간 계수 Coefficient du temps de réparation complète Коэффициент времени полного ремонта + Coeficiente de Tiempo de Reparación Completa Modifies how long it takes to perform a Full Repair.\nThe repair time is based on the amount of repairs needed for each part, including those normally inaccessible. @@ -291,6 +292,7 @@ 전체적인 수리를 수행하는 데 걸리는 시간을 수정합니다.\n수리 시간은 일반적으로 접근할 수 없는 부품을 포함하여 각 부품에 필요한 수리 시간을 기준으로 합니다. Modifie la durée que prend une réparation complète.\nLe temps de réparation est basé sur la quantité de réparations requises pour chaque partie, incluant celles qui sont normalement inaccessibles. Изменяет время, необходимое для выполнения полного ремонта.\nВремя ремонта зависит от объема ремонтных работ, необходимых для каждой детали, включая те, которые обычно недоступны. + Modifica cuánto tiempo lleva realizar una Reparación Completa.\nEl tiempo de reparación está basado en la cantidad de reparaciones necesarias para cada parte, incluyendo aquellas que normalmente no son accesibles. Boost engineer training when in repair vehicles or facilities. Untrained becomes engineer, engineer becomes advanced engineer. @@ -1262,6 +1264,7 @@ タイヤ交換の許可 바퀴 교체 허용 Autoriser le remplacement des roues + Permitir Recambio de Rueda Who can remove and replace wheels? @@ -1287,6 +1290,7 @@ 바퀴 수리 허용 Autoriser le rafistolage des roues Разрешить починить колесо + Permitir Parcheo de Rueda Who can patch wheels? @@ -1297,6 +1301,7 @@ 누가 바퀴를 수리할 수 있습니까? Qui peut rafistoler les roues ? Кто может починить колеса? + Quién puede parchear ruedas? Allow Repair @@ -1957,6 +1962,7 @@ 바퀴 수리 아이템 필요 Exigences pour rafistoler une roue Требования для починки колеса + Requerimientos de Parcheo de Ruedas Items required to patch a wheel. @@ -1967,6 +1973,7 @@ 바퀴를 수리하기 위해 아이템이 필요합니다. Equipements requis pour rafistoler une roue. Предметы, необходимые для починки колеса. + Objetos requeridos para parchear una rueda. Misc Repair Requirements @@ -2142,6 +2149,7 @@ 부품 수리 시간 Temps de réparation des pièces Время ремонта детали + Tiempo de Reparación de Pieza Time in seconds to complete a repair. @@ -2152,6 +2160,7 @@ 수리를 완료하는 시간(초 단위) Durée en secondes pour terminer une réparation. Время завершения ремонта в секундах. + Tiempo en segundos para completar una reparación. Wheel Change Time @@ -2162,6 +2171,7 @@ 바퀴 교체 시간 Temps de changement d'une roue Время замены колеса + Tiempo de Cambio de Rueda Time in seconds to remove or change a wheel. @@ -2172,6 +2182,7 @@ 바퀴를 제거하거나 교체하는 데 걸리는 시간(초 단위) Durée en seconde pour enlever ou changer une roue. Время в секундах на снятие или замену колеса. + Tiempo en segundos para quitar o cambiar una rueda. Patch Wheel @@ -2182,6 +2193,7 @@ 바퀴 수리 Rafistoler la roue Чинить колесо + Parchear Rueda Patching Wheel... @@ -2192,6 +2204,7 @@ 바퀴 수리 중... Rafistolage de la roue... Починка колеса... + Parcheando Rueda... Wheel Patch Time @@ -2202,6 +2215,7 @@ 바퀴 수리 시간 Temps de rafistolage d'une roue Время починки полеса + Tiempo de Parcheo de Rueda Time it takes to patch a wheel by 5%. @@ -2212,6 +2226,7 @@ 바퀴를 5% 수리하는 데 걸리는 시간(초 단위) Durée pour rafistoler une roue de 5%. Время, необходимое для починки колеса, сокращается на 5%. + Tiempo que lleva parchear una rueda por cada 5%. Patch Wheel Threshold @@ -2222,6 +2237,7 @@ 바퀴 수리 한계점 Seuil de rafistolage d'une roue Порог починки колеса + Umbral de Parcheo de Rueda Maximum damage to which a wheel can be patched.\n0% means all damage can be repaired. @@ -2232,6 +2248,7 @@ 바퀴를 수리할 수 있는 최대 레벨입니다. Niveau maximum de dégâts jusqu'à laquelle une roue peut être réparée.\n0% signifie que la roue peut être reparée entièrement. Максимальный уровень, до которого колесо может быть починено. + Máximo daño que permite a una rueda ser parcheada.\n0% significa que todo el daño puede ser reparado. Wheel Patch Location @@ -2242,6 +2259,7 @@ 바퀴 수리 장소 Lieu de rafistolage des roues Место починки колеса + Localización para el Parcheo de Rueda Where the wheel can be patched. @@ -2252,6 +2270,7 @@ 바퀴를 수리할 수 있는 곳입니다. Lieu où les roues peuvent être rafistolées. Где колесо можно починить. + Dónde puede ser parcheada la rueda. On the ground @@ -2262,6 +2281,7 @@ 지면 위 Sur le terrain На земле + En el suelo On a vehicle @@ -2272,6 +2292,7 @@ 차량 Sur un véhicule На транспорте + En un vehículo diff --git a/addons/tagging/stringtable.xml b/addons/tagging/stringtable.xml index 4d32fac6d6..fa54b56b54 100644 --- a/addons/tagging/stringtable.xml +++ b/addons/tagging/stringtable.xml @@ -384,6 +384,7 @@ 차량 ID 마킹 Marquage ID des véhicules Идентификационная маркировка транспортного средства + Marcado Identificativo de Vehículo Replaces clan tag with stenciled text @@ -394,6 +395,7 @@ 클랜 태그를 스텐실 텍스트로 바꿉니다. Remplace le tag du clan par un texte au pochoir Заменяет тег клана трафаретным текстом + Reemplaza marca del clan con un texto serigrafiado diff --git a/addons/zeus/stringtable.xml b/addons/zeus/stringtable.xml index 8b3aaed92c..329a0a3bd7 100644 --- a/addons/zeus/stringtable.xml +++ b/addons/zeus/stringtable.xml @@ -1322,6 +1322,7 @@ 화물 내리기 Выгрузить из отсека Décharger de la cargaison + Descargar de la carga Toggle NVGs @@ -1968,6 +1969,7 @@ 의료 메뉴가 비활성화되었습니다 Медицинское меню отключено Le Menu médical est désactivé + El menú médico está deshabilitado Lay Trenchline @@ -1978,6 +1980,7 @@ Piazza Trincea 塹壕溝線を敷設 Проложить траншею + Poner una Trinchera +SHIFT to force (Can only lay N/S or E/W) @@ -1988,6 +1991,7 @@ +SHIFT per forzare (Può piazzare solo N/S o E/O +SHIFTキー で強制的に敷設 (北/南または東/西方向にのみ配置可能) +SHIFT на принудительное (может укладываться только на Север/Юг или Восток/Запад) + +SHIFT para forzar (Puede solo colocar en N/S or E/O) From b26d6543a6320000fe585913dd6237c9caca39e4 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Sat, 11 May 2024 22:15:02 -0500 Subject: [PATCH 035/290] Prepare 3.17.1 Build 86 --- addons/main/script_version.hpp | 2 +- docs/_config.yml | 2 +- docs/_config_dev.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/main/script_version.hpp b/addons/main/script_version.hpp index 9223f27ea7..75b323ede3 100644 --- a/addons/main/script_version.hpp +++ b/addons/main/script_version.hpp @@ -1,4 +1,4 @@ #define MAJOR 3 #define MINOR 17 #define PATCHLVL 1 -#define BUILD 85 +#define BUILD 86 diff --git a/docs/_config.yml b/docs/_config.yml index c23538d799..ee7822969d 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -10,7 +10,7 @@ ace: major: 3 minor: 17 patch: 1 - build: 85 + build: 86 markdown: kramdown diff --git a/docs/_config_dev.yml b/docs/_config_dev.yml index e83f8e441f..348e1aee44 100644 --- a/docs/_config_dev.yml +++ b/docs/_config_dev.yml @@ -10,7 +10,7 @@ ace: major: 3 minor: 17 patch: 1 - build: 85 + build: 86 markdown: kramdown From a31608073edb40d7d1ad6e16bbc4a92ad5749279 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Tue, 21 May 2024 18:25:59 -0500 Subject: [PATCH 036/290] Maptools - Fix gps detection (#10007) * Maptools - Fix gps detection * Use `infoPanelComponents` Co-Authored-By: johnb432 <58661205+johnb432@users.noreply.github.com> --------- Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- addons/maptools/functions/fnc_canUseMapGPS.sqf | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/addons/maptools/functions/fnc_canUseMapGPS.sqf b/addons/maptools/functions/fnc_canUseMapGPS.sqf index 0bdd0d0ea6..e9ca813288 100644 --- a/addons/maptools/functions/fnc_canUseMapGPS.sqf +++ b/addons/maptools/functions/fnc_canUseMapGPS.sqf @@ -17,8 +17,7 @@ if (!visibleMap || {!alive ACE_player}) exitWith {false}; -private _gpsOpened = visibleGPS; -private _gpsAvailable = openGPS true; -if (!_gpsOpened) then {openGPS false}; +private _panels = flatten (ACE_player infoPanelComponents "left"); +private _index = _panels find "MinimapDisplayComponent"; -_gpsAvailable // return +_index != -1 && {_panels select (_index + 1)} From db2bf60c2871e7808b7eb3c5533b67b7da7bb8ec Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 22 May 2024 03:16:05 +0200 Subject: [PATCH 037/290] Cargo - Add documentation on adding cargo via config (#9994) * Fix bag of holdings in cargo * Update CfgVehicles.hpp * Update CfgVehicles.hpp * Revert space changes --- addons/cargo/CfgVehicles.hpp | 13 +++---------- docs/wiki/framework/cargo-framework.md | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/addons/cargo/CfgVehicles.hpp b/addons/cargo/CfgVehicles.hpp index 6f6a93e820..66fa98159e 100644 --- a/addons/cargo/CfgVehicles.hpp +++ b/addons/cargo/CfgVehicles.hpp @@ -48,15 +48,7 @@ class CfgVehicles { class Car: LandVehicle { GVAR(space) = 4; GVAR(hasCargo) = 1; - class ACE_Cargo { - /* - class Cargo { - class ACE_medicalSupplyCrate { - type = "ACE_medicalSupplyCrate"; - amount = 1; - }; - };*/ - }; + class ADDON {}; }; class Tank: LandVehicle { @@ -75,7 +67,7 @@ class CfgVehicles { GVAR(hasCargo) = 1; }; - // HEMTTs - Default at 10, some variants are altered based on model size and/or expected level of free space inside. + // HEMTTs - Default at 30, some variants are altered based on model size and/or expected level of free space inside. class Truck_01_base_F: Truck_F { GVAR(space) = 30; }; @@ -523,6 +515,7 @@ class CfgVehicles { class EventHandlers { class CBA_Extended_EventHandlers: CBA_Extended_EventHandlers {}; }; + GVAR(space) = 3; GVAR(hasCargo) = 1; GVAR(size) = 3; diff --git a/docs/wiki/framework/cargo-framework.md b/docs/wiki/framework/cargo-framework.md index 68b28f7fa7..a1d810ce9c 100644 --- a/docs/wiki/framework/cargo-framework.md +++ b/docs/wiki/framework/cargo-framework.md @@ -47,6 +47,24 @@ class CfgVehicles {

ace_cargo_hasCargo and ace_cargo_canLoad are only needed if you aren't inheriting from any of BI base classes or if you are trying to disable loading for a specific vehicle / object.

+### 1.3 Adding predefined cargo via config + +```cpp +class CfgVehicles { + class yourVehicleClass { + ace_cargo_space = 4; // Add if necessary + ace_cargo_hasCargo = 1; // Add if necessary + class ace_cargo { + class cargo { + class ACE_medicalSupplyCrate { // Doesn't have to have the same name as the item you're adding + type = "ACE_medicalSupplyCrate"; + amount = 1; + }; + }; + }; + }; +}; +``` ## 2. Events From 4cf61a026b0e266ecf8a5de5ae2a5d0c52b17391 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 22 May 2024 03:18:32 +0200 Subject: [PATCH 038/290] Interact Menu - Use hashmaps for interactions (#9920) * Use hashmaps for interactions * Update addons/interact_menu/functions/fnc_splitPath.sqf Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> * Account for case sensitivity * Update addons/interact_menu/functions/fnc_compileMenu.sqf Co-authored-by: PabstMirror * Update addons/interact_menu/functions/fnc_compileMenuSelfAction.sqf Co-authored-by: PabstMirror --------- Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> Co-authored-by: PabstMirror --- addons/interact_menu/XEH_clientInit.sqf | 9 ++++----- addons/interact_menu/XEH_preInit.sqf | 6 +++--- .../functions/fnc_addActionToClass.sqf | 10 ++++------ .../functions/fnc_addMainAction.sqf | 8 ++------ .../interact_menu/functions/fnc_compileMenu.sqf | 16 ++++++++-------- .../functions/fnc_compileMenuSelfAction.sqf | 13 ++++++------- .../functions/fnc_initMenuReorder.sqf | 2 +- .../functions/fnc_removeActionFromClass.sqf | 9 ++++----- .../functions/fnc_renderActionPoints.sqf | 5 ++--- addons/interact_menu/functions/fnc_splitPath.sqf | 12 +++++++----- .../fnc_userActions_getHouseActions.sqf | 9 ++++----- .../functions/fnc_addPassengerActions.sqf | 6 +----- 12 files changed, 46 insertions(+), 59 deletions(-) diff --git a/addons/interact_menu/XEH_clientInit.sqf b/addons/interact_menu/XEH_clientInit.sqf index 5c9a2ecae0..d0c6d93940 100644 --- a/addons/interact_menu/XEH_clientInit.sqf +++ b/addons/interact_menu/XEH_clientInit.sqf @@ -3,16 +3,16 @@ if (!hasInterface) exitWith {}; // Wait until player controls (man,vehicle or uav) a thing before compiling the menu -GVAR(controllableSelfActionsAdded) = [] call CBA_fnc_createNamespace; +GVAR(controllableSelfActionsAdded) = createHashMap; DFUNC(newControllableObject) = { params ["_object"]; private _type = typeOf _object; TRACE_2("newControllableObject",_object,_type); if (_type == "") exitWith {}; - if (!(GVAR(controllableSelfActionsAdded) getVariable [_type, false])) then { + if !(_type in GVAR(controllableSelfActionsAdded)) then { [_type] call FUNC(compileMenuSelfAction); - GVAR(controllableSelfActionsAdded) setVariable [_type, true]; + GVAR(controllableSelfActionsAdded) set [_type, nil]; [{ TRACE_1("sending newControllableObject event",_this); // event for other systems to add self actions, running addActionToClass before this will cause compiling @@ -27,8 +27,7 @@ DFUNC(newControllableObject) = { GVAR(blockDefaultActions) = []; -GVAR(cachedBuildingTypes) = []; -GVAR(cachedBuildingActionPairs) = []; +GVAR(cachedBuildingTypes) = createHashMap; GVAR(ParsedTextCached) = []; diff --git a/addons/interact_menu/XEH_preInit.sqf b/addons/interact_menu/XEH_preInit.sqf index bf3278f0a3..88269bcc04 100644 --- a/addons/interact_menu/XEH_preInit.sqf +++ b/addons/interact_menu/XEH_preInit.sqf @@ -12,12 +12,12 @@ if (!hasInterface) exitWith { ADDON = true; }; ["All", "init", LINKFUNC(compileMenu)] call CBA_fnc_addClassEventHandler; -GVAR(ActNamespace) = [] call CBA_fnc_createNamespace; -GVAR(ActSelfNamespace) = [] call CBA_fnc_createNamespace; +GVAR(ActNamespace) = createHashMap; +GVAR(ActSelfNamespace) = createHashMap; // Compile actions for CAManBase now and use for all mans types ["CAManBase"] call FUNC(compileMenu); -GVAR(cacheManActions) = +(GVAR(ActNamespace) getVariable ["CAManBase", []]); // copy +GVAR(cacheManActions) = +(GVAR(ActNamespace) getOrDefault ["CAManBase" call EFUNC(common,getConfigName), []]); // copy // Event handlers for all interact menu controls DFUNC(handleMouseMovement) = { diff --git a/addons/interact_menu/functions/fnc_addActionToClass.sqf b/addons/interact_menu/functions/fnc_addActionToClass.sqf index 93d54c991c..ccea8c4654 100644 --- a/addons/interact_menu/functions/fnc_addActionToClass.sqf +++ b/addons/interact_menu/functions/fnc_addActionToClass.sqf @@ -48,6 +48,8 @@ if (param [4, false, [false]]) exitwith { (_parentPath + [_action select 0]) }; +_objectType = _objectType call EFUNC(common,getConfigName); + // Ensure the config menu was compiled first if (_typeNum == 0) then { [_objectType] call FUNC(compileMenu); @@ -56,18 +58,14 @@ if (_typeNum == 0) then { }; private _namespace = [GVAR(ActNamespace), GVAR(ActSelfNamespace)] select _typeNum; -private _actionTrees = _namespace getVariable _objectType; -if (isNil "_actionTrees") then { - _actionTrees = []; - _namespace setVariable [_objectType, _actionTrees]; -}; +private _actionTrees = _namespace getOrDefault [_objectType, [], true]; if (_parentPath isEqualTo ["ACE_MainActions"]) then { [_objectType, _typeNum] call FUNC(addMainAction); }; private _parentNode = [_actionTrees, _parentPath] call FUNC(findActionNode); -if (isNil {_parentNode}) exitWith { +if (isNil "_parentNode") exitWith { ERROR_4("Failed to add action - action (%1) to parent %2 on object %3 [%4]",(_action select 0),_parentPath,_objectType,_typeNum); [] }; diff --git a/addons/interact_menu/functions/fnc_addMainAction.sqf b/addons/interact_menu/functions/fnc_addMainAction.sqf index 83349c21b3..beb02997b9 100644 --- a/addons/interact_menu/functions/fnc_addMainAction.sqf +++ b/addons/interact_menu/functions/fnc_addMainAction.sqf @@ -19,14 +19,10 @@ params ["_objectType", "_typeNum"]; private _namespace = [GVAR(ActNamespace), GVAR(ActSelfNamespace)] select _typeNum; -private _actionTrees = _namespace getVariable _objectType; -if (isNil "_actionTrees") then { - _actionTrees = []; -}; - +private _actionTrees = _namespace getOrDefault [_objectType, []]; private _parentNode = [_actionTrees, ["ACE_MainActions"]] call FUNC(findActionNode); -if (isNil {_parentNode}) then { +if (isNil "_parentNode") then { TRACE_2("No Main Action on object",_objectType,_typeNum); private _mainAction = ["ACE_MainActions", localize ELSTRING(interaction,MainAction), "", {}, {true}] call FUNC(createAction); [_objectType, _typeNum, [], _mainAction] call EFUNC(interact_menu,addActionToClass); diff --git a/addons/interact_menu/functions/fnc_compileMenu.sqf b/addons/interact_menu/functions/fnc_compileMenu.sqf index 75d759465c..8c5d3c5fa1 100644 --- a/addons/interact_menu/functions/fnc_compileMenu.sqf +++ b/addons/interact_menu/functions/fnc_compileMenu.sqf @@ -17,22 +17,22 @@ params ["_target"]; -private _objectType = _target; -if (_target isEqualType objNull) then { - _objectType = typeOf _target; +private _objectType = if (_target isEqualType objNull) then { + typeOf _target +} else { + _target call EFUNC(common,getConfigName) }; -private _namespace = GVAR(ActNamespace); // Exit if the action menu is already compiled for this class -if (!isNil {_namespace getVariable _objectType}) exitWith {}; +if (_objectType in GVAR(ActNamespace)) exitWith {}; if (_objectType isKindOf "VirtualMan_F") exitWith { // these have config: isPlayableLogic = 1 TRACE_1("skipping playable logic",_objectType); - _namespace setVariable [_objectType, []]; + GVAR(ActNamespace) set [_objectType, []]; }; if ((_objectType isKindOf "CAManBase") && {!isNil QGVAR(cacheManActions)}) exitWith { - _namespace setVariable [_objectType, +GVAR(cacheManActions)]; // copy + GVAR(ActNamespace) set [_objectType, +GVAR(cacheManActions)]; // copy }; private _recurseFnc = { @@ -139,7 +139,7 @@ if (_objectType isKindOf "CAManBase") then { }; }; -_namespace setVariable [_objectType, _actions]; +GVAR(ActNamespace) set [_objectType, _actions]; /* [ diff --git a/addons/interact_menu/functions/fnc_compileMenuSelfAction.sqf b/addons/interact_menu/functions/fnc_compileMenuSelfAction.sqf index ed3a02dd14..8f19dfabbe 100644 --- a/addons/interact_menu/functions/fnc_compileMenuSelfAction.sqf +++ b/addons/interact_menu/functions/fnc_compileMenuSelfAction.sqf @@ -17,15 +17,14 @@ params ["_target"]; -private _objectType = _target; -if (_target isEqualType objNull) then { - _objectType = typeOf _target; +private _objectType = if (_target isEqualType objNull) then { + typeOf _target +} else { + _target call EFUNC(common,getConfigName) }; -private _namespace = GVAR(ActSelfNamespace); // Exit if the action menu is already compiled for this class -if (!isNil {_namespace getVariable _objectType}) exitWith {}; - +if (_objectType in GVAR(actSelfNamespace)) exitWith {}; private _recurseFnc = { params ["_actionsCfg"]; @@ -131,4 +130,4 @@ private _actions = [ ] ]; -_namespace setVariable [_objectType, _actions]; +GVAR(ActSelfNamespace) set [_objectType, _actions]; diff --git a/addons/interact_menu/functions/fnc_initMenuReorder.sqf b/addons/interact_menu/functions/fnc_initMenuReorder.sqf index 48445b3fa0..d55f2f06ea 100644 --- a/addons/interact_menu/functions/fnc_initMenuReorder.sqf +++ b/addons/interact_menu/functions/fnc_initMenuReorder.sqf @@ -17,7 +17,7 @@ params ["_class"]; -private _actionTrees = GVAR(ActSelfNamespace) getVariable _class; +private _actionTrees = GVAR(ActSelfNamespace) get _class; private _rootNode = [_actionTrees, ["ACE_SelfActions"]] call FUNC(findActionNode); private _rootActions = _rootNode select 1; private _settingCategoryPrefix = format ["ACE %1 - ", LELSTRING(Interaction,InteractionMenuSelf)]; diff --git a/addons/interact_menu/functions/fnc_removeActionFromClass.sqf b/addons/interact_menu/functions/fnc_removeActionFromClass.sqf index 6772b61c54..7585616ef6 100644 --- a/addons/interact_menu/functions/fnc_removeActionFromClass.sqf +++ b/addons/interact_menu/functions/fnc_removeActionFromClass.sqf @@ -19,17 +19,16 @@ params ["_objectType", "_typeNum", "_fullPath"]; +_objectType = _objectType call EFUNC(common,getConfigName); + private _res = _fullPath call FUNC(splitPath); _res params ["_parentPath", "_actionName"]; private _namespace = [GVAR(ActNamespace), GVAR(ActSelfNamespace)] select _typeNum; -private _actionTrees = _namespace getVariable _objectType; -if (isNil "_actionTrees") then { - _actionTrees = []; -}; +private _actionTrees = _namespace getOrDefault [_objectType, []]; private _parentNode = [_actionTrees, _parentPath] call FUNC(findActionNode); -if (isNil {_parentNode}) exitWith {}; +if (isNil "_parentNode") exitWith {}; // Iterate through children of the father private _found = false; diff --git a/addons/interact_menu/functions/fnc_renderActionPoints.sqf b/addons/interact_menu/functions/fnc_renderActionPoints.sqf index 058b5ed846..4ce37aa66b 100644 --- a/addons/interact_menu/functions/fnc_renderActionPoints.sqf +++ b/addons/interact_menu/functions/fnc_renderActionPoints.sqf @@ -61,7 +61,7 @@ private _fnc_renderNearbyActions = { } forEach GVAR(objectActionList); // Iterate through base level class actions and render them if appropiate - private _classActions = GVAR(ActNamespace) getVariable [typeOf _target, []]; + private _classActions = GVAR(ActNamespace) getOrDefault [typeOf _target, []]; { private _action = _x; // Try to render the menu @@ -95,8 +95,7 @@ private _fnc_renderSelfActions = { GVAR(objectActionList) = _target getVariable [QGVAR(selfActions), []]; // Iterate through base level class actions and render them if appropiate - private _namespace = GVAR(ActSelfNamespace); - private _classActions = _namespace getVariable typeOf _target; + private _classActions = GVAR(ActSelfNamespace) get typeOf _target; private _pos = if !(GVAR(useCursorMenu)) then { //Convert to ASL, add offset and then convert back to AGL (handles waves when over water) diff --git a/addons/interact_menu/functions/fnc_splitPath.sqf b/addons/interact_menu/functions/fnc_splitPath.sqf index 8c0856d118..8fabaca5a5 100644 --- a/addons/interact_menu/functions/fnc_splitPath.sqf +++ b/addons/interact_menu/functions/fnc_splitPath.sqf @@ -17,11 +17,13 @@ */ private _parentPath = []; -for [{private _i = 0},{_i < (count _this) - 1},{_i = _i + 1}] do { - _parentPath pushBack (_this select _i); -}; -private _actionName = if (count _this > 0) then { - _this select ((count _this) - 1); + +_parentPath append _this; + +private _count = count _this; + +private _actionName = if (_count > 0) then { + _parentPath deleteAt (_count - 1) // TODO: replace with _parentPath deleteAt [-1] and drop _count in 2.18 } else { "" }; diff --git a/addons/interact_menu/functions/fnc_userActions_getHouseActions.sqf b/addons/interact_menu/functions/fnc_userActions_getHouseActions.sqf index c11da0c271..8f28950840 100644 --- a/addons/interact_menu/functions/fnc_userActions_getHouseActions.sqf +++ b/addons/interact_menu/functions/fnc_userActions_getHouseActions.sqf @@ -17,8 +17,9 @@ params ["_typeOfBuilding"]; -private _searchIndex = GVAR(cachedBuildingTypes) find _typeOfBuilding; -if (_searchIndex != -1) exitWith {GVAR(cachedBuildingActionPairs) select _searchIndex}; +private _cachedMemPoints = GVAR(cachedBuildingTypes) get _typeOfBuilding; + +if (!isNil "_cachedMemPoints") exitWith {_cachedMemPoints}; private _memPoints = []; private _memPointsActions = []; @@ -148,8 +149,6 @@ private _ladders = getArray (configFile >> "CfgVehicles" >> _typeOfBuilding >> " } forEach _ladders; -GVAR(cachedBuildingTypes) pushBack _typeOfBuilding; -GVAR(cachedBuildingActionPairs) pushBack [_memPoints, _memPointsActions]; - +GVAR(cachedBuildingTypes) set [_typeOfBuilding, [_memPoints, _memPointsActions]]; [_memPoints, _memPointsActions] diff --git a/addons/interaction/functions/fnc_addPassengerActions.sqf b/addons/interaction/functions/fnc_addPassengerActions.sqf index a3d8c2eff0..9b8981bfd0 100644 --- a/addons/interaction/functions/fnc_addPassengerActions.sqf +++ b/addons/interaction/functions/fnc_addPassengerActions.sqf @@ -20,11 +20,7 @@ params ["", "", "_parameters"]; _parameters params ["_unit"]; -private _namespace = EGVAR(interact_menu,ActNamespace); -private _actionTrees = _namespace getVariable typeOf _unit; -if (isNil "_actionTrees") then { - _actionTrees = []; -}; +private _actionTrees = EGVAR(interact_menu,ActNamespace) getOrDefault [typeOf _unit, []]; private _actions = []; From 52762c1e62c24d9abcb04b672af661725ed07f17 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Tue, 21 May 2024 20:23:46 -0500 Subject: [PATCH 039/290] Arsenal - Changes for CBA Disposable hashs (#9998) * Arsenal - Changes for CBA Disposable hashs * Update addons/arsenal/functions/fnc_onSelChangedRight.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * Update addons/arsenal/functions/fnc_onSelChangedRight.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --------- Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- addons/arsenal/functions/fnc_onSelChangedRight.sqf | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/addons/arsenal/functions/fnc_onSelChangedRight.sqf b/addons/arsenal/functions/fnc_onSelChangedRight.sqf index ccb2988765..abec68ceee 100644 --- a/addons/arsenal/functions/fnc_onSelChangedRight.sqf +++ b/addons/arsenal/functions/fnc_onSelChangedRight.sqf @@ -69,7 +69,14 @@ switch (_currentItemsIndex) do { // Secondary weapon case IDX_CURR_SECONDARY_WEAPON_ITEMS: { private _currentItemInSlot = (GVAR(currentItems) select IDX_CURR_SECONDARY_WEAPON_ITEMS) select _itemIndex; - private _isDisposable = CBA_disposable_replaceDisposableLauncher && {!isNil {CBA_disposable_loadedLaunchers getVariable (secondaryWeapon GVAR(center))}}; + private _isDisposable = CBA_disposable_replaceDisposableLauncher && {!isNil "CBA_disposable_loadedLaunchers"} && + { + if (CBA_disposable_loadedLaunchers isEqualType createHashMap) then { // after CBA 3.18 + (secondaryWeapon GVAR(center)) in CBA_disposable_loadedLaunchers + } else { + !isNil {CBA_disposable_loadedLaunchers getVariable (secondaryWeapon player)} + } + }; // If removal if (_item == "") then { From 99d7e4d57b94296414565cedc0622dada66dc4a3 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 22 May 2024 03:24:50 +0200 Subject: [PATCH 040/290] Grenades - Add 3 more sounds to flashbang detonations (#9982) * Add 3 more sounds to flashbang detonations * Update addons/grenades/functions/fnc_flashbangThrownFuze.sqf Co-authored-by: PabstMirror --------- Co-authored-by: PabstMirror --- addons/grenades/functions/fnc_flashbangThrownFuze.sqf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/grenades/functions/fnc_flashbangThrownFuze.sqf b/addons/grenades/functions/fnc_flashbangThrownFuze.sqf index 7f1a52417c..f966283f96 100644 --- a/addons/grenades/functions/fnc_flashbangThrownFuze.sqf +++ b/addons/grenades/functions/fnc_flashbangThrownFuze.sqf @@ -19,7 +19,8 @@ params ["_projectile"]; TRACE_1("params",_projectile); if (alive _projectile) then { - playSound3D ["A3\Sounds_F\arsenal\explosives\grenades\Explosion_HE_grenade_01.wss", _projectile, false, getPosASL _projectile, 5, 1.2, 400]; + private _soundFile = format ["A3\Sounds_F\arsenal\explosives\grenades\Explosion_HE_grenade_0%1.wss", floor (random 4) + 1]; + playSound3D [_soundFile, _projectile, false, getPosASL _projectile, 5, 1.2, 400]; ["ace_flashbangExploded", [getPosASL _projectile]] call CBA_fnc_globalEvent; }; From 052f1c95a33cb5030e735877c1611e60beacaab8 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 22 May 2024 08:32:46 +0200 Subject: [PATCH 041/290] Cargo - Add checks for adding cargo via config (#9999) * Add checks for cargo via config * Update fnc_initVehicle.sqf * Use loaded number instead of intended number --- addons/cargo/functions/fnc_addCargoItem.sqf | 21 +++++++++++++++------ addons/cargo/functions/fnc_initVehicle.sqf | 11 +++++++++-- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/addons/cargo/functions/fnc_addCargoItem.sqf b/addons/cargo/functions/fnc_addCargoItem.sqf index 38ccdc0dd9..de262bdcfb 100644 --- a/addons/cargo/functions/fnc_addCargoItem.sqf +++ b/addons/cargo/functions/fnc_addCargoItem.sqf @@ -7,9 +7,10 @@ * 0: Item to be loaded or * 1: Holder object (vehicle) * 2: Amount (default: 1) + * 3: Ignore interaction distance and stability checks (default: false) * * Return Value: - * None + * Objects loaded * * Example: * ["ACE_Wheel", cursorObject] call ace_cargo_fnc_addCargoItem @@ -17,21 +18,29 @@ * Public: No */ -params ["_item", "_vehicle", ["_amount", 1]]; -TRACE_3("params",_item,_vehicle,_amount); +params ["_item", "_vehicle", ["_amount", 1], ["_ignoreInteraction", false]]; +TRACE_4("params",_item,_vehicle,_amount,_ignoreInteraction); + +private _loaded = 0; // Get config sensitive case name if (_item isEqualType "") then { _item = _item call EFUNC(common,getConfigName); for "_i" from 1 to _amount do { - [_item, _vehicle] call FUNC(loadItem); + if !([_item, _vehicle, _ignoreInteraction] call FUNC(loadItem)) exitWith {}; + + _loaded = _loaded + 1; }; } else { - [_item, _vehicle] call FUNC(loadItem); + _loaded = parseNumber ([_item, _vehicle, _ignoreInteraction] call FUNC(loadItem)); _item = typeOf _item; }; +TRACE_1("loaded",_loaded); + // Invoke listenable event -["ace_cargoAdded", [_item, _vehicle, _amount]] call CBA_fnc_globalEvent; +["ace_cargoAdded", [_item, _vehicle, _loaded]] call CBA_fnc_globalEvent; + +_loaded // return diff --git a/addons/cargo/functions/fnc_initVehicle.sqf b/addons/cargo/functions/fnc_initVehicle.sqf index af80761fe0..25cebe5b13 100644 --- a/addons/cargo/functions/fnc_initVehicle.sqf +++ b/addons/cargo/functions/fnc_initVehicle.sqf @@ -52,14 +52,21 @@ if (isServer) then { private _cargoClassname = ""; private _cargoCount = 0; + private _loaded = 0; { _cargoClassname = getText (_x >> "type"); _cargoCount = getNumber (_x >> "amount"); - TRACE_3("adding ACE_Cargo",configName _x,_cargoClassname,_cargoCount); + TRACE_3("adding ace_cargo",configName _x,_cargoClassname,_cargoCount); - ["ace_addCargo", [_cargoClassname, _vehicle, _cargoCount]] call CBA_fnc_localEvent; + // Ignore stability check (distance check is also ignored with this, but it's ignored by default if item is a string) + _loaded = [_cargoClassname, _vehicle, _cargoCount, true] call FUNC(addCargoItem); + + // Let loop continue until the end, so that it prints everything into the rpt (there might be smaller items that could still fit in cargo) + if (_loaded != _cargoCount) then { + WARNING_5("%1 (%2) could not fit %3 %4 inside its cargo, only %5 were loaded.",_vehicle,_type,_cargoCount,_cargoClassname,_loaded); + }; } forEach ("true" configClasses (_config >> QUOTE(ADDON) >> "cargo")); }; From c03e08e51b026c6c0e4fb7d561d0c9c7f2991626 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 22 May 2024 22:08:09 +0200 Subject: [PATCH 042/290] Grenades - Change damage from M14 incendiary grenade (#9992) Doubled damage from M14 incendiary grenade --- addons/grenades/CfgAmmo.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/grenades/CfgAmmo.hpp b/addons/grenades/CfgAmmo.hpp index 5082dd432d..e911e23747 100644 --- a/addons/grenades/CfgAmmo.hpp +++ b/addons/grenades/CfgAmmo.hpp @@ -153,7 +153,7 @@ class CfgAmmo { class ACE_G_M14: SmokeShell { GVAR(incendiary) = 1; model = QPATHTOF(models\ace_anm14th3_armed.p3d); - hit = 5; + hit = 10; indirectHit = 4; indirectHitRange = 1.1; dangerRadiusHit = 50; From e1137ac9034e79f5763cc675bca93482f0cc6f86 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 22 May 2024 22:37:24 +0200 Subject: [PATCH 043/290] Fire - Remove unused plant integration (#9993) Removed unused plant integration in fire --- addons/fire/XEH_PREP.hpp | 1 - addons/fire/XEH_preInit.sqf | 2 -- addons/fire/functions/fnc_isBurning.sqf | 5 +---- addons/fire/functions/fnc_isPlant.sqf | 20 -------------------- 4 files changed, 1 insertion(+), 27 deletions(-) delete mode 100644 addons/fire/functions/fnc_isPlant.sqf diff --git a/addons/fire/XEH_PREP.hpp b/addons/fire/XEH_PREP.hpp index d9eacfdee0..8b2e8f6bd1 100644 --- a/addons/fire/XEH_PREP.hpp +++ b/addons/fire/XEH_PREP.hpp @@ -1,6 +1,5 @@ PREP(burn); PREP(isBurning); -PREP(isPlant); PREP(burnIndicator); PREP(burnReaction); PREP(fireManagerPFH); diff --git a/addons/fire/XEH_preInit.sqf b/addons/fire/XEH_preInit.sqf index 2fc794454d..894773534a 100644 --- a/addons/fire/XEH_preInit.sqf +++ b/addons/fire/XEH_preInit.sqf @@ -8,6 +8,4 @@ PREP_RECOMPILE_END; #include "initSettings.inc.sqf" -GVAR(burningPlants) = []; - ADDON = true; diff --git a/addons/fire/functions/fnc_isBurning.sqf b/addons/fire/functions/fnc_isBurning.sqf index 3bdbe560be..7cc06dc01d 100644 --- a/addons/fire/functions/fnc_isBurning.sqf +++ b/addons/fire/functions/fnc_isBurning.sqf @@ -17,7 +17,4 @@ params [["_unit", objNull, [objNull]]]; -_unit getVariable [QGVAR(burning), false] || { - GVAR(burningPlants) = GVAR(burningPlants) select {!isNull _x}; - _unit in GVAR(burningPlants) -} +_unit getVariable [QGVAR(burning), false] diff --git a/addons/fire/functions/fnc_isPlant.sqf b/addons/fire/functions/fnc_isPlant.sqf deleted file mode 100644 index f132fc72be..0000000000 --- a/addons/fire/functions/fnc_isPlant.sqf +++ /dev/null @@ -1,20 +0,0 @@ -#include "..\script_component.hpp" -/* - * Author: commy2 - * Check if object is a map placed bush or tree. - * - * Arguments: - * 0: Object - * - * Return Value: - * Is bush or tree? - * - * Example: - * cursorObject call ace_fire_fnc_isPlant - * - * Public: No - */ - -params [["_object", objNull, [objNull]]]; - -_object in nearestTerrainObjects [_object, ["TREE", "SMALL TREE", "BUSH"], 0.1] From 67fe22a5a6bce3b5cf22f614e61a61971e8cb5db Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 22 May 2024 22:38:59 +0200 Subject: [PATCH 044/290] Grenades - Make flashbang detonation sound configurable via config (#9985) * Added configurable flashbang detonation sound Updated documentation by filling missing information in * Update grenades-framework.md * Update grenades-framework.md --- addons/grenades/functions/fnc_flashbangThrownFuze.sqf | 11 +++++++++-- docs/wiki/framework/grenades-framework.md | 9 +++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/addons/grenades/functions/fnc_flashbangThrownFuze.sqf b/addons/grenades/functions/fnc_flashbangThrownFuze.sqf index f966283f96..1c9751da37 100644 --- a/addons/grenades/functions/fnc_flashbangThrownFuze.sqf +++ b/addons/grenades/functions/fnc_flashbangThrownFuze.sqf @@ -19,8 +19,15 @@ params ["_projectile"]; TRACE_1("params",_projectile); if (alive _projectile) then { - private _soundFile = format ["A3\Sounds_F\arsenal\explosives\grenades\Explosion_HE_grenade_0%1.wss", floor (random 4) + 1]; - playSound3D [_soundFile, _projectile, false, getPosASL _projectile, 5, 1.2, 400]; + private _sounds = getArray (_projectile call CBA_fnc_getObjectConfig >> QGVAR(flashbangExplodeSound)); + + (if (_sounds isEqualTo []) then { + [format ["A3\Sounds_F\arsenal\explosives\grenades\Explosion_HE_grenade_0%1.wss", floor (random 4) + 1], 5, 1.2, 400] + } else { + selectRandom _sounds + }) params ["_file", "_volume", "_pitch", "_distance"]; + + playSound3D [_file, _projectile, false, getPosASL _projectile, _volume, _pitch, _distance]; ["ace_flashbangExploded", [getPosASL _projectile]] call CBA_fnc_globalEvent; }; diff --git a/docs/wiki/framework/grenades-framework.md b/docs/wiki/framework/grenades-framework.md index fce3b480c2..14c72e1cb5 100644 --- a/docs/wiki/framework/grenades-framework.md +++ b/docs/wiki/framework/grenades-framework.md @@ -50,6 +50,10 @@ class CfgAmmo { ace_grenades_flashbangBangs = 6; // 6 bangs ace_grenades_flashbangInterval = 0.25; // 0.25 seconds between each subsequent bang ace_grenades_flashbangIntervalMaxDeviation = 0.05; // Deviation of up to ± 0.05 seconds on each fuse + ace_grenades_flashbangExplodeSound[] = { // Sound that is played upon detonation + {"A3\Sounds_F\arsenal\explosives\grenades\Explosion_HE_grenade_01.wss", 5, 1.2, 400}, // file path, volume, pitch, max distance + {"A3\Sounds_F\arsenal\explosives\grenades\Explosion_HE_grenade_02.wss", 5, 1.2, 400} + }; }; }; ``` @@ -70,6 +74,11 @@ The average amount of time in seconds, after `explosionTime` has passed, between The amount of randomness in the fuse time. +### 2.1.5 ace_grenades_flashbangExplodeSound + +The sounds that can be used when the flashbang detonates. It randomly selects an entry from this array (equal chances, there are no weights involved). +If not defined, `[format ["A3\Sounds_F\arsenal\explosives\grenades\Explosion_HE_grenade_0%1.wss", floor (random 4) + 1], 5, 1.2, 400]` is used as a default instead (4 sounds total). + ### 2.2 Incendiary Config Values ```cpp From f97f11d224388c0b433ce3524ee0cb25f2d5f167 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Wed, 22 May 2024 21:19:40 -0500 Subject: [PATCH 045/290] AdvThrowing - Fix showing wind info when no grenades in inventory (#10008) AdvThrowing - Fix showing wind info if no grenades in inventory --- addons/advanced_throwing/functions/fnc_prepare.sqf | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/addons/advanced_throwing/functions/fnc_prepare.sqf b/addons/advanced_throwing/functions/fnc_prepare.sqf index 7926c2c864..3008b8e540 100644 --- a/addons/advanced_throwing/functions/fnc_prepare.sqf +++ b/addons/advanced_throwing/functions/fnc_prepare.sqf @@ -18,15 +18,6 @@ params ["_unit"]; TRACE_1("params",_unit); -// Temporarily enable wind info, to aid in throwing smoke grenades effectively -if ( - GVAR(enableTempWindInfo) && - {!(missionNamespace getVariable [QEGVAR(weather,WindInfo), false])} -) then { - [] call EFUNC(weather,displayWindInfo); - GVAR(tempWindInfo) = true; -}; - // Select next throwable if one already in hand if (_unit getVariable [QGVAR(inHand), false]) exitWith { TRACE_1("inHand",_unit); @@ -44,6 +35,11 @@ if (isNull (_unit getVariable [QGVAR(activeThrowable), objNull]) && {(currentThr TRACE_1("no throwables",_unit); }; +// Temporarily enable wind info, to aid in throwing smoke grenades effectively +if (GVAR(enableTempWindInfo) && {!(missionNamespace getVariable [QEGVAR(weather,WindInfo), false])}) then { + [] call EFUNC(weather,displayWindInfo); + GVAR(tempWindInfo) = true; +}; _unit setVariable [QGVAR(inHand), true]; From 7c65f8503d8dd89965780a3889dfa7fea959eb82 Mon Sep 17 00:00:00 2001 From: Dystopian Date: Thu, 23 May 2024 22:47:19 +0300 Subject: [PATCH 046/290] Refuel - Add enable setting (#7613) * Add enable setting * Exclude man class init * Fix multiplayer terrain pump fuel sync * Add terrain pumps positions * Add vanilla fuel cargo restoring before destroying * Add Livonia positions by bux * Fix terrain pumps destruction * Improve settings init * Fix double settings category * Check enabled var in public functions * Fix fnc_makeSource * Handle recent CUP Terrains changes * Update includes * Fix issues introduced in #9133 * Change warning Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * Optimisations and cleanup - Use hashmaps wherever possible - Reduced pump search radius by ~30% - Sorted pumps alphabetically and sorted positions by "smallest" first, for consistency * Add init debug trace * compileScript in dev * yoda conditions & DFUNC macro * Wait until CBA settings are ready * Update Chernarus 2020 and add more maps configs * Remove vanilla fuel cargo restoring before destroying --------- Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> --- addons/refuel/ACE_Refuel_Positions.hpp | 90 ++++++++ addons/refuel/Cfg3DEN.hpp | 7 +- addons/refuel/CfgVehicles.hpp | 36 +-- addons/refuel/XEH_PREP.hpp | 1 + addons/refuel/XEH_postInit.sqf | 212 +++++++++++------- addons/refuel/XEH_preStart.sqf | 39 +++- addons/refuel/config.cpp | 1 + .../dev/exportTerrainRefuelPositions.sqf | 84 +++++++ addons/refuel/dev/test_debugConfigs.sqf | 16 +- addons/refuel/functions/fnc_getFuelCargo.sqf | 20 ++ addons/refuel/functions/fnc_makeJerryCan.sqf | 7 + addons/refuel/functions/fnc_makeSource.sqf | 19 +- addons/refuel/initSettings.inc.sqf | 10 + docs/wiki/framework/refuel-framework.md | 2 +- 14 files changed, 406 insertions(+), 138 deletions(-) create mode 100644 addons/refuel/ACE_Refuel_Positions.hpp create mode 100644 addons/refuel/dev/exportTerrainRefuelPositions.sqf create mode 100644 addons/refuel/functions/fnc_getFuelCargo.sqf diff --git a/addons/refuel/ACE_Refuel_Positions.hpp b/addons/refuel/ACE_Refuel_Positions.hpp new file mode 100644 index 0000000000..cb03f53247 --- /dev/null +++ b/addons/refuel/ACE_Refuel_Positions.hpp @@ -0,0 +1,90 @@ +class GVAR(positions) { + Altis[] = { /* Altis */ {"Land_fs_feed_F", {{3757,13478,0},{4001,12592,0},{5023,14430,0},{5769,20086,0},{6199,15081,0},{6798,15561,0},{8482,18261,0},{9026,15729,0},{9206,12112,0},{11832,14156,0},{12025,15830,0},{14173,16542,0},{14221,18303,0},{15297,17566,0},{15781,17453,0},{16751,12513,0},{16875,15469,0},{17417,13937,0},{19961,11454,0},{20785,16666,0},{21231,7117,0},{23379,19799,0},{25701,21373,0}}}}; + Stratis[] = { /* Stratis */ {"Land_FuelStation_Feed_F", {{2708,5788,0}}}}; + VR[] = {}; + Malden[] = { /* Malden 2035 */ + {"Land_fs_feed_F", {{3227,6291,0},{5111,9062,0},{5504,3500,0},{6633,8807,0},{7047,7052,0}}}, + {"Land_FuelStation_01_pump_malevil_F", {{7224,7772,0},{8047,4023,0}}}, + {"Land_FuelStation_Feed_F", {{10063,3988,0},{11600,4477,0}}} + }; + Tanoa[] = { /* Tanoa */ + {"Land_fs_feed_F", {{2132,3360,0},{2452,7435,0},{3030,11316,0},{5174,8806,0},{5380,4093,0},{5594,12508,0},{7978,7419,0},{8319,9709,0},{8494,12432,0},{8954,13678,0},{8970,10332,0},{10827,6490,0},{10941,9855,0},{11146,5152,0},{11631,2999,0},{14261,11513,0},{14365,8743,0}}}, + {"Land_FuelStation_01_pump_F", {{1865,12128,0},{5409,9905,0},{5682,10165,0},{5776,4222,0},{5793,10825,0},{6592,13080,0},{6887,7491,0},{7359,7998,0},{9954,13467,0},{11635,13047,0},{11694,2271,0},{12613,7583,0}}} + }; + Enoch[] = { /* Livonia */ + {"Land_FuelStation_03_pump_F", {{2008,7365,0},{6259,3949,0}}}, + {"Land_FuelStation_Feed_F", {{10208,2173,0}}} + }; + + Bootcamp_ACR[] = { /* CUP Bukovina */ {"Land_A_FuelStation_Feed", {{652,473,0},{2849,1612,0}}}}; + Woodland_ACR[] = { /* CUP Bystrica */ {"Land_A_FuelStation_Feed", {{447,1381,0},{1302,2185,0},{1855,6852,0},{4102,1195,0},{4755,4499,0}}}}; + chernarus[] = { /* CUP Chernarus (Autumn) */ {"Land_A_FuelStation_Feed", {{2021,2242,0},{2692,5602,0},{2997,7471,0},{3648,8968,0},{4733,6381,0},{5847,2191,0},{5849,10112,0},{6705,2996,0},{7255,7662,0},{9502,2005,0},{10154,5300,0},{10446,8866,0},{10726,10786,0},{12988,10076,0},{13385,6603,0}}}}; + chernarus_summer[] = { /* CUP Chernarus (Summer) */ {"Land_A_FuelStation_Feed", {{2021,2242,0},{2685,5606,0},{2998,7473,0},{3652,8973,0},{4733,6381,0},{5854,2193,0},{5849,10112,0},{6702,2995,0},{7255,7662,0},{9502,2005,0},{10154,5300,0},{10452,8869,0},{10726,10786,0},{13001,10074,0},{13398,6606,0}}}}; + Chernarus_Winter[] = { /* CUP Chernarus (Winter) */ {"Land_A_FuelStation_Feed", {{2021,2242,0},{2685,5604,0},{2997,7471,0},{3657,8979,0},{4733,6381,0},{5854,2193,0},{5849,10112,0},{6702,2995,0},{7255,7662,0},{9503,2019,0},{10155,5309,0},{10452,8869,0},{10726,10786,0},{12994,10075,0},{13385,6603,0}}}}; + cup_chernarus_A3[] = { /* CUP Chernarus 2020 */ + {"Land_fs_feed_F", {{2511,5279,0}}}, + {"Land_FuelStation_03_pump_F", {{313,9385,0},{1129,2400,0},{2021,2242,0},{2692,5602,0},{2991,7471,1},{3007,12654,0},{3648,8968,0},{4328,13081,0},{4733,6381,0},{5847,2191,0},{5849,10112,0},{6699,3001,0},{7255,7662,0},{7494,12662,0},{9502,2005,0},{10155,5309,0},{10452,8869,0},{10726,10786,0},{13001,10074,0},{13398,6606,0},{13569,13329,0}}} + }; + Desert_E[] = { /* CUP Desert */ }; + porto[] = { /* CUP Porto */ }; + ProvingGrounds_PMC[] = { /* CUP Proving Grounds */ {"Land_FuelStation_Feed_PMC", {{698,1208,0}}}}; + intro[] = { /* CUP Rahmadi */ }; + sara[] = { /* CUP Sahrani */ + {"Land_Benzina_schnell", {{8473,9423,0},{9227,5840,0},{9433,5187,0},{10168,6423,0},{10932,9475,0},{11233,6114,0},{11756,10227,0},{12289,6833,0}}}, + {"Land_Fuelstation_army", {{9568,9819,0},{19294,13879,0}}}, + }; + sara_dbe1[] = { /* CUP United Sahrani */ + {"Land_Benzina_schnell", {{8473,9423,0},{9227,5840,0},{9433,5187,0},{10168,6423,0},{10932,9475,0},{11233,6114,0},{11756,10227,0},{12289,6833,0}}}, + {"Land_Fuelstation_army", {{9568,9819,0},{19294,13879,0}}} + }; + saralite[] = { /* CUP Southern Sahrani */ + {"Land_Benzina_schnell", {{3593,6663,0},{4347,3080,0},{4553,2427,0},{5288,3663,0},{6052,6715,0},{6353,3354,0},{6876,7467,0},{7409,4073,0}}}, + {"Land_Fuelstation_army", {{4688,7059,0}}} + }; + Shapur_BAF[] = { /* CUP Shapur */ {"Land_Ind_FuelStation_Feed_EP1", {{1512,1298,0}}}}; + takistan[] = { /* CUP Takistan */ {"Land_Ind_FuelStation_Feed_EP1", {{2004,11720,0},{3081,9848,0},{3549,4197,0},{5538,9284,0},{5836,5771,0},{7497,1818,0},{8248,7800,0},{10422,6328,0},{10647,11021,0}}}}; + Mountains_ACR[] = { /* CUP Takistan Mountains */ {"Land_Ind_FuelStation_Feed_EP1", {{2962,4197,0},{5249,5771,0}}}}; + utes[] = { /* CUP Utes */ }; + zargabad[] = { /* CUP Zargabad */ {"Land_Ind_FuelStation_Feed_EP1", {{3736,2784,0},{3867,4208,0},{3871,5980,0},{5027,1906,0}}}}; + + pja310[] = { /* G.O.S Al Rayak */ {"Land_Ind_FuelStation_Feed_EP1", {{887,18588,0},{964,18356,0},{1196,18463,0},{1872,8754,0},{2051,8437,0},{2125,8238,0},{2240,8584,0},{2310,8566,0},{2366,3901,0},{2879,13142,0},{3880,10361,0},{4056,13261,0},{4122,13487,0},{4302,13628,0},{4475,13377,0},{4556,13742,0},{6461,3372,0},{7216,6059,0},{7228,6344,0},{7416,6099,0},{7472,6838,0},{7591,6081,0},{11650,3536,0},{14863,7292,0},{16466,18897,0},{16476,19116,0},{16642,18994,0},{16676,19199,0},{16858,10558,0},{16908,9959,0},{17120,3706,0},{17100,4375,0},{18056,4133,0},{18229,4066,0},{18235,4571,0},{18814,5010,0}}}}; + australia[] = { /* Aussie Australia v5.09 */ + {"Land_fs_feed_F", {{4614,16978,0},{5509,19273,0},{5487,19276,0},{5508,19330,0},{5540,19357,0},{5564,19377,0},{5623,19376,0},{5643,19352,0},{6355,17860,0},{12811,27772,0},{15837,33438,0},{16335,33436,0},{16367,33436,0},{17127,33902,0},{20754,12737,0},{20874,12793,0},{20901,12793,1},{22127,25635,0},{22127,25666,0},{22162,25712,0},{22194,25712,0},{22213,25630,0},{22315,19235,0},{22595,24757,0},{24909,13855,0},{25050,12786,0},{25071,12786,0},{26085,11260,1},{26212,11174,0},{26824,28005,0},{27719,17108,0},{27757,12033,0},{28473,35132,0},{30707,11879,0},{31091,5370,0},{31096,10918,0},{31096,10945,0},{31165,10914,0},{31165,10958,0},{31313,16763,0},{31515,9673,0},{31515,9652,0},{31758,4861,0},{32224,2736,0},{33919,13364,0},{33936,13350,0},{34789,26383,0},{35274,26021,2},{35786,12148,0},{35765,12170,0},{35835,12145,0},{35833,12188,0},{35812,12210,0},{36199,16479,0},{36399,13140,0},{36593,12065,0},{36574,13089,0},{36595,13089,0},{36597,13282,0},{38153,14544,0},{38520,18891,0},{38515,20173,0},{38535,20198,0},{38565,20198,0}}}, + {"Land_FuelStation_01_pump_F", {{5495,18693,0},{32067,29608,0},{32087,29611,0},{33215,4147,0},{37293,13172,0},{37293,13193,0}}}, + {"Land_FuelStation_Feed_F", {{19303,16449,0},{31064,20116,0}}} + }; + Farabad[] = { /* Farabad */ + {"Land_Benzina_schnell", {{592,7505,0},{804,1445,0},{3132,3129,0}}}, + {"Land_fs_feed_F", {{1920,4960,0},{5052,4703,1},{9456,9277,0}}}, + {"Land_FuelStation_01_pump_F", {{2378,6248,0},{7092,534,0}}}, + {"Land_Ind_FuelStation_Feed_EP1", {{4788,5525,0}}} + }; + IslaPera[] = { /* Isla Pera */ + {"Land_fs_feed_F", {{1855,2866,0}}}, + {"Land_FuelStation_01_pump_malevil_F", {{3981,2065,0},{5306,8796,0},{9236,4287,0}}} + }; + VTF_Lybor[] = { /* Lybor */ + {"Land_FuelStation_03_pump_F", {{3879,3823,0}}}, + {"Land_FuelStation_Feed_F", {{1831,2694,0},{2175,3323,0},{3304,2981,0},{4271,3024,0}}} + }; + rof_mok[] = { /* Mull of Kintyre, Scotland */ + {"Land_A_FuelStation_Feed", {{12837,5124,1},{15271,17533,0},{19453,21896,0}}}, + {"Land_fs_feed_F", {{7492,17369,0}}}, + {"Land_Fuelstation", {{10284,18679,0}}}, + {"Land_Ind_FuelStation_Feed_EP1", {{9762,16325,0}}} + }; + pulau[] = { /* Pulau */ + {"Land_fs_feed_F", {{2368,3128,0},{4891,7168,0},{7358,7368,0}}}, + {"Land_FuelStation_Feed_F", {{5994,5789,0}}} + }; + WL_Rosche[] = { /* Rosche, Germany (2.0) */ + {"Land_fs_feed_F", {{693,4803,0},{12059,6700,0},{13320,14822,0}}}, + {"Land_FuelStation_01_pump_F", {{447,6859,0}}}, + {"Land_Ind_FuelStation_Feed_EP1", {{1437,5455,0}}} + }; + Kapaulio[] = { /* Saint Kapaulio */ + {"Land_fs_feed_F", {{931,7647,0},{958,6796,0},{2034,9426,0},{2563,9427,0},{3500,8110,0},{3602,6082,0},{4222,6308,0},{4561,693,0},{8077,5906,0},{8434,13145,0},{8525,17299,0},{9265,7155,0},{10527,18267,0},{12078,1846,0},{12833,6464,0},{13433,6327,0},{14084,6308,0},{14172,7786,0},{14831,4649,0},{16080,14743,0},{17356,2312,0},{18047,5254,0},{18318,5042,0}}}, + {"Land_FuelStation_01_pump_malevil_F", {{18039,18139,0}}}, + {"Land_FuelStation_Feed_F", {{756,12133,0},{1239,7346,0},{1726,17469,0},{3113,10070,0},{3828,8362,0},{5668,16967,0},{7435,14185,0},{7543,12107,0},{8366,6086,0},{9672,9586,0},{11749,12255,0},{12802,10022,0},{13989,3591,0},{15198,10900,0},{19063,1654,0},{19378,18517,0}}} + }; +}; diff --git a/addons/refuel/Cfg3DEN.hpp b/addons/refuel/Cfg3DEN.hpp index 3383107995..00d5453d95 100644 --- a/addons/refuel/Cfg3DEN.hpp +++ b/addons/refuel/Cfg3DEN.hpp @@ -1,7 +1,4 @@ -#define GET_NUMBER(config,default) (if (isNumber (config)) then {getNumber (config)} else {default}) #define GET_1ST_ARRAY(config) (if (isArray (config)) then {getArray (config) select 0} else {[ARR_3(0,0,0)]}) - -#define DEFAULT_FUELCARGO GET_NUMBER(configOf _this >> QQGVAR(fuelCargo),REFUEL_DISABLED_FUEL) #define DEFAULT_HOOKS GET_1ST_ARRAY(configOf _this >> QQGVAR(hooks)) class Cfg3DEN { @@ -14,8 +11,8 @@ class Cfg3DEN { tooltip = CSTRING(fuelCargo_edenDesc); property = QGVAR(fuelCargo); control = "EditShort"; - expression = QUOTE(if (_value != DEFAULT_FUELCARGO) then {[ARR_2(_this,_value)] call DFUNC(makeSource)}); - defaultValue = QUOTE(DEFAULT_FUELCARGO); + expression = QUOTE(if (_value != (_this call FUNC(getFuelCargo))) then {[ARR_2(_this,_value)] call FUNC(makeSource)}); + defaultValue = QUOTE(_this call FUNC(getFuelCargo)); validate = "number"; condition = "(1-objectBrain)*(1-objectAgent)"; typeName = "NUMBER"; diff --git a/addons/refuel/CfgVehicles.hpp b/addons/refuel/CfgVehicles.hpp index 5fba336943..44575a141d 100644 --- a/addons/refuel/CfgVehicles.hpp +++ b/addons/refuel/CfgVehicles.hpp @@ -1,3 +1,5 @@ +#define XEH_INHERITED class EventHandlers {class CBA_Extended_EventHandlers: CBA_Extended_EventHandlers {};} + class CBA_Extended_EventHandlers; class CfgNonAIVehicles { @@ -45,9 +47,7 @@ class CfgVehicles { class ThingX; class GVAR(fuelNozzle): ThingX { - class EventHandlers { - class CBA_Extended_EventHandlers: CBA_Extended_EventHandlers {}; - }; + XEH_INHERITED; displayName = QGVAR(fuelNozzle); scope = 1; @@ -275,12 +275,6 @@ class CfgVehicles { GVAR(hooks)[] = {{0.38,-3.17,-0.7},{-0.41,-3.17,-0.7}}; GVAR(fuelCargo) = 2000; }; - class C_Van_01_fuel_F: Van_01_fuel_base_F { - transportFuel = 0; //1k - }; - class I_G_Van_01_fuel_F: Van_01_fuel_base_F { - transportFuel = 0; //1k - }; class Tank_F: Tank { GVAR(fuelCapacity) = 1200; @@ -295,7 +289,6 @@ class CfgVehicles { class B_APC_Tracked_01_base_F: APC_Tracked_01_base_F {}; class B_APC_Tracked_01_CRV_F: B_APC_Tracked_01_base_F { - transportFuel = 0; //3k GVAR(hooks)[] = {{-1.08,-4.81,-0.8}}; GVAR(fuelCargo) = 1000; }; @@ -407,7 +400,6 @@ class CfgVehicles { // Vanilla fuel vehicles class Truck_02_fuel_base_F: Truck_02_base_F { - transportFuel = 0; //3k GVAR(hooks)[] = {{0.99,-3.47,-0.67},{-1.04,-3.47,-0.67}}; GVAR(fuelCargo) = 10000; }; @@ -416,13 +408,11 @@ class CfgVehicles { }; class B_Truck_01_fuel_F: B_Truck_01_mover_F { - transportFuel = 0; //3k GVAR(hooks)[] = {{0.28,-4.99,-0.3},{-0.25,-4.99,-0.3}}; GVAR(fuelCargo) = 10000; }; class O_Truck_03_fuel_F: Truck_03_base_F { - transportFuel = 0; //3k GVAR(hooks)[] = {{1.3,-1.59,-0.62},{-1.16,-1.59,-0.62}}; GVAR(fuelCargo) = 10000; }; @@ -436,20 +426,17 @@ class CfgVehicles { class Pod_Heli_Transport_04_base_F: Slingload_base_F {}; class Land_Pod_Heli_Transport_04_fuel_F: Pod_Heli_Transport_04_base_F { - transportFuel = 0; //3k GVAR(hooks)[] = {{-1.49,1.41,-0.3}}; GVAR(fuelCargo) = 10000; }; class Slingload_01_Base_F: Slingload_base_F {}; class B_Slingload_01_Fuel_F: Slingload_01_Base_F { - transportFuel = 0; //3k GVAR(hooks)[] = {{0.55,3.02,-0.5},{-0.52,3.02,-0.5}}; GVAR(fuelCargo) = 10000; }; class O_Heli_Transport_04_fuel_F: Heli_Transport_04_base_F { - transportFuel = 0; //3k GVAR(hooks)[] = {{-1.52,1.14,-1.18}}; GVAR(fuelCargo) = 10000; }; @@ -466,11 +453,7 @@ class CfgVehicles { }; }; class Land_StorageBladder_01_F: StorageBladder_base_F { - class EventHandlers { - class CBA_Extended_EventHandlers: CBA_Extended_EventHandlers {}; - }; - - transportFuel = 0; //60k + XEH_INHERITED; GVAR(hooks)[] = {{-3.35,2.45,0.17}}; GVAR(fuelCargo) = 60000; }; @@ -486,36 +469,35 @@ class CfgVehicles { }; }; class Land_FlexibleTank_01_F: FlexibleTank_base_F { - transportFuel = 0; //300 GVAR(hooks)[] = {{0, 0, 0.5}}; GVAR(fuelCargo) = 300; }; // Vanilla buildings class Land_Fuelstation_Feed_F: House_Small_F { - transportFuel = 0; //50k + XEH_INHERITED; GVAR(hooks)[] = {{0,0,-0.5}}; GVAR(fuelCargo) = REFUEL_INFINITE_FUEL; }; class Land_fs_feed_F: House_Small_F { - transportFuel = 0; //50k + XEH_INHERITED; GVAR(hooks)[] = {{-0.4,0.022,-0.23}}; GVAR(fuelCargo) = REFUEL_INFINITE_FUEL; }; class Land_FuelStation_01_pump_F: House_F { - transportFuel = 0; //50k + XEH_INHERITED; GVAR(hooks)[] = {{0, 0.4, -0.5}, {0, -0.4, -0.5}}; GVAR(fuelCargo) = REFUEL_INFINITE_FUEL; }; class Land_FuelStation_01_pump_malevil_F: House_F { - transportFuel = 0; //50k + XEH_INHERITED; GVAR(hooks)[] = {{0, 0.4, -0.5}, {0, -0.4, -0.5}}; GVAR(fuelCargo) = REFUEL_INFINITE_FUEL; }; class Land_FuelStation_03_pump_F: House_F { // Enoch - transportFuel = 0; //50k + XEH_INHERITED; GVAR(hooks)[] = {{0, 0.4, -0.5}, {0, -0.4, -0.5}}; GVAR(fuelCargo) = REFUEL_INFINITE_FUEL; }; diff --git a/addons/refuel/XEH_PREP.hpp b/addons/refuel/XEH_PREP.hpp index 077c8f1aed..cb9279500b 100644 --- a/addons/refuel/XEH_PREP.hpp +++ b/addons/refuel/XEH_PREP.hpp @@ -11,6 +11,7 @@ PREP(disconnect); PREP(dropNozzle); PREP(getCapacity); PREP(getFuel); +PREP(getFuelCargo); PREP(handleDisconnect); PREP(handleRespawn); PREP(initSource); diff --git a/addons/refuel/XEH_postInit.sqf b/addons/refuel/XEH_postInit.sqf index c826efd3d4..f6f5a7d7b3 100644 --- a/addons/refuel/XEH_postInit.sqf +++ b/addons/refuel/XEH_postInit.sqf @@ -1,95 +1,151 @@ #include "script_component.hpp" -if (isServer) then { - addMissionEventHandler ["HandleDisconnect", {call FUNC(handleDisconnect)}]; -}; +["CBA_settingsInitialized", { + if (!GVAR(enabled)) exitWith {}; -[QGVAR(initSource), LINKFUNC(initSource)] call CBA_fnc_addEventHandler; + ["All", "InitPost", { + params ["_vehicle"]; + if (getFuelCargo _vehicle <= 0) exitWith {}; + TRACE_1("initPost",_vehicle); -if (!hasInterface) exitWith {}; + if (local _vehicle) then { + _vehicle setFuelCargo 0; + LOG("initPost setFuelCargo"); + }; + }, true, ["Man"], true] call CBA_fnc_addClassEventHandler; -["isNotRefueling", {!((_this select 0) getVariable [QGVAR(isRefueling), false])}] call EFUNC(common,addCanInteractWithCondition); + if (isServer) then { + addMissionEventHandler ["HandleDisconnect", {call FUNC(handleDisconnect)}]; + }; -["MouseButtonDown", LINKFUNC(onMouseButtonDown)] call CBA_fnc_addDisplayHandler; + private _cfgPositions = configFile >> QGVAR(positions) >> worldName; + if (isArray _cfgPositions) then { + { + _x params ["_class", "_positions"]; + { + private _objects = _x nearObjects [_class, 30]; + if (_objects isEqualTo []) then { + WARNING_3("no pumps %1 found near %2 %3",_class,worldName,_x); + } else { + { + // terrain fuel pumps don't trigger init and must setFuelCargo on each client + _x setFuelCargo 0; + } forEach _objects; + }; + } forEach _positions; + } forEach getArray _cfgPositions; -GVAR(mainAction) = [ - QGVAR(Refuel), - localize LSTRING(Refuel), - QPATHTOF(ui\icon_refuel_interact.paa), - {}, - { - alive _target - && {[_player, _target, [INTERACT_EXCEPTIONS]] call EFUNC(common,canInteractWith)} - && {REFUEL_DISABLED_FUEL != ([_target] call FUNC(getCapacity))} - }, - {}, [], [0,0,0], - REFUEL_ACTION_DISTANCE -] call EFUNC(interact_menu,createAction); + // placed in editor static objects don't trigger init but synchronize fuel cargo + // placed in editor vehicles both trigger init and synchronize fuel cargo + { + if (getFuelCargo _x > 0 && {local _x}) then { + TRACE_1("allMissionObjects",_x); + _x setFuelCargo 0; + }; + } forEach allMissionObjects ""; + } else { + // here are both terrain and editor static objects + WARNING_2("World %1: %2 is not configured; can load slower",worldName,QGVAR(positions)); + private _halfWorldSize = worldSize / 2; + private _worldCenter = [_halfWorldSize, _halfWorldSize]; + _halfWorldSize = _halfWorldSize * sqrt 2; + private _refuelMissionObjects = allMissionObjects "" select {getFuelCargo _x > 0}; + private _baseStaticClasses = keys (uiNamespace getVariable QGVAR(cacheRefuelClassesBaseStatic)); -GVAR(actions) = [ - [QGVAR(TakeNozzle), - localize LSTRING(TakeNozzle), + { + { + _x setFuelCargo 0; + } forEach (_worldCenter nearObjects [_x, _halfWorldSize]); + } forEach _baseStaticClasses; + }; + + [QGVAR(initSource), LINKFUNC(initSource)] call CBA_fnc_addEventHandler; + + if (!hasInterface) exitWith {}; + + ["isNotRefueling", {!((_this select 0) getVariable [QGVAR(isRefueling), false])}] call EFUNC(common,addCanInteractWithCondition); + + ["MouseButtonDown", LINKFUNC(onMouseButtonDown)] call CBA_fnc_addDisplayHandler; + + GVAR(mainAction) = [ + QGVAR(Refuel), + localize LSTRING(Refuel), QPATHTOF(ui\icon_refuel_interact.paa), - {[_player, _target] call FUNC(TakeNozzle)}, - {[_player, _target] call FUNC(canTakeNozzle)}, + {}, + { + alive _target + && {[_player, _target, [INTERACT_EXCEPTIONS]] call EFUNC(common,canInteractWith)} + && {REFUEL_DISABLED_FUEL != ([_target] call FUNC(getCapacity))} + }, {}, [], [0,0,0], REFUEL_ACTION_DISTANCE - ] call EFUNC(interact_menu,createAction), - [QGVAR(CheckFuelCounter), - localize LSTRING(CheckFuelCounter), - QPATHTOF(ui\icon_refuel_interact.paa), - {[_player, _target] call FUNC(readFuelCounter)}, - {true}, - {}, [], [0,0,0], - REFUEL_ACTION_DISTANCE - ] call EFUNC(interact_menu,createAction), - [QGVAR(CheckFuel), - localize LSTRING(CheckFuel), - QPATHTOF(ui\icon_refuel_interact.paa), - {[_player, _target] call FUNC(checkFuel)}, - {[_player, _target] call FUNC(canCheckFuel)}, - {}, [], [0,0,0], - REFUEL_ACTION_DISTANCE - ] call EFUNC(interact_menu,createAction), - [QGVAR(Return), - localize LSTRING(Return), - QPATHTOF(ui\icon_refuel_interact.paa), - {[_player, _target] call FUNC(returnNozzle)}, - {[_player, _target] call FUNC(canReturnNozzle)}, - {}, [], [0,0,0], - REFUEL_ACTION_DISTANCE - ] call EFUNC(interact_menu,createAction) -]; + ] call EFUNC(interact_menu,createAction); -// init menu for config refuel vehicles -private _cacheRefuelClasses = call (uiNamespace getVariable [QGVAR(cacheRefuelClasses), {[[],[]]}]); -_cacheRefuelClasses params [["_staticClasses", [], [[]]], ["_dynamicClasses", [], [[]]]]; + GVAR(actions) = [ + [QGVAR(TakeNozzle), + localize LSTRING(TakeNozzle), + QPATHTOF(ui\icon_refuel_interact.paa), + {[_player, _target] call FUNC(TakeNozzle)}, + {[_player, _target] call FUNC(canTakeNozzle)}, + {}, [], [0,0,0], + REFUEL_ACTION_DISTANCE + ] call EFUNC(interact_menu,createAction), + [QGVAR(CheckFuelCounter), + localize LSTRING(CheckFuelCounter), + QPATHTOF(ui\icon_refuel_interact.paa), + {[_player, _target] call FUNC(readFuelCounter)}, + {true}, + {}, [], [0,0,0], + REFUEL_ACTION_DISTANCE + ] call EFUNC(interact_menu,createAction), + [QGVAR(CheckFuel), + localize LSTRING(CheckFuel), + QPATHTOF(ui\icon_refuel_interact.paa), + {[_player, _target] call FUNC(checkFuel)}, + {[_player, _target] call FUNC(canCheckFuel)}, + {}, [], [0,0,0], + REFUEL_ACTION_DISTANCE + ] call EFUNC(interact_menu,createAction), + [QGVAR(Return), + localize LSTRING(Return), + QPATHTOF(ui\icon_refuel_interact.paa), + {[_player, _target] call FUNC(returnNozzle)}, + {[_player, _target] call FUNC(canReturnNozzle)}, + {}, [], [0,0,0], + REFUEL_ACTION_DISTANCE + ] call EFUNC(interact_menu,createAction) + ]; -{ - private _className = _x; - [_className, 0, ["ACE_MainActions"], GVAR(mainAction)] call EFUNC(interact_menu,addActionToClass); + private _staticClasses = keys (uiNamespace getVariable QGVAR(cacheRefuelClassesStatic)); + private _baseDynamicClasses = keys (uiNamespace getVariable QGVAR(cacheRefuelClassesBaseDynamic)); + + // init menu for config refuel vehicles { - [_className, 0, ["ACE_MainActions", QGVAR(Refuel)], _x] call EFUNC(interact_menu,addActionToClass); - } forEach GVAR(actions); - TRACE_1("add menu to static",_x); -} forEach _staticClasses; + private _className = _x; + [_className, 0, ["ACE_MainActions"], GVAR(mainAction)] call EFUNC(interact_menu,addActionToClass); + { + [_className, 0, ["ACE_MainActions", QGVAR(Refuel)], _x] call EFUNC(interact_menu,addActionToClass); + } forEach GVAR(actions); + TRACE_1("add menu to static",_x); + } forEach _staticClasses; -{ - private _className = _x; - [_className, 0, ["ACE_MainActions"], GVAR(mainAction), true] call EFUNC(interact_menu,addActionToClass); { - [_className, 0, ["ACE_MainActions", QGVAR(Refuel)], _x, true] call EFUNC(interact_menu,addActionToClass); - } forEach GVAR(actions); - TRACE_1("add menu to dynamic",_x); -} forEach _dynamicClasses; + private _className = _x; + [_className, 0, ["ACE_MainActions"], GVAR(mainAction), true] call EFUNC(interact_menu,addActionToClass); + { + [_className, 0, ["ACE_MainActions", QGVAR(Refuel)], _x, true] call EFUNC(interact_menu,addActionToClass); + } forEach GVAR(actions); + TRACE_1("add menu to dynamic",_x); + } forEach _baseDynamicClasses; -#ifdef DRAW_HOOKS_POS -addMissionEventHandler ["Draw3D", { - private _source = cursorObject; - private _cfgPos = getArray (configOf _source >> QGVAR(hooks)); - private _dynPos = _source getVariable [QGVAR(hooks), []]; - { - drawIcon3D ["\a3\ui_f\data\gui\cfg\hints\icon_text\group_1_ca.paa", [1,1,1,1], _source modelToWorldVisual _x, 1, 1, 0, format ["Hook %1", _forEachIndex]]; - } forEach ([_dynPos, _cfgPos] select (_dynPos isEqualTo [])); -}]; -#endif + #ifdef DRAW_HOOKS_POS + addMissionEventHandler ["Draw3D", { + private _source = cursorObject; + private _cfgPos = getArray (configOf _source >> QGVAR(hooks)); + private _dynPos = _source getVariable [QGVAR(hooks), _cfgPos]; + { + drawIcon3D ["\a3\ui_f\data\gui\cfg\hints\icon_text\group_1_ca.paa", [1,1,1,1], _source modelToWorldVisual _x, 1, 1, 0, format ["Hook %1", _forEachIndex]]; + } forEach _dynPos; + }]; + #endif +}] call CBA_fnc_addEventHandler; diff --git a/addons/refuel/XEH_preStart.sqf b/addons/refuel/XEH_preStart.sqf index fa5fe4acda..308ca30a9b 100644 --- a/addons/refuel/XEH_preStart.sqf +++ b/addons/refuel/XEH_preStart.sqf @@ -4,27 +4,44 @@ // cache refuel vehicles, see XEH_postInit.sqf private _staticClasses = []; -private _dynamicClasses = []; +private _baseStaticClasses = []; +private _baseDynamicClasses = []; +private _cacheRefuelCargo = createHashMap; { - private _fuelCargo = getNumber (_x >> QGVAR(fuelCargo)); + private _transportFuel = getNumber (_x >> "transportFuel"); + private _fuelCargo = [_x >> QGVAR(fuelCargo), "NUMBER", _transportFuel] call CBA_fnc_getConfigEntry; if (_fuelCargo > 0 || {_fuelCargo == REFUEL_INFINITE_FUEL}) then { private _sourceClass = configName _x; + private _noXEH = !isText (_x >> "EventHandlers" >> "CBA_Extended_EventHandlers" >> "init"); + private _isPublic = getNumber (_x >> "scope") == 2; // check if we can use actions with inheritance if ( - !isText (_x >> "EventHandlers" >> "CBA_Extended_EventHandlers" >> "init") // addActionToClass relies on XEH init - || {configName _x isKindOf "Static"} // CBA_fnc_addClassEventHandler doesn't support "Static" class + _noXEH // addActionToClass relies on XEH init + || {_sourceClass isKindOf "Static"} // CBA_fnc_addClassEventHandler doesn't support "Static" class ) then { - if (2 == getNumber (_x >> "scope")) then { - _staticClasses pushBackUnique _sourceClass; + if (_isPublic) then { + if (_noXEH) then { + WARNING_3("Class %1: %2 [%3] needs XEH",_sourceClass,configName inheritsFrom _x,configSourceMod _x); + }; + _staticClasses pushBack _sourceClass; + if (_baseStaticClasses findIf {_sourceClass isKindOf _x} == -1) then { + _baseStaticClasses pushBack _sourceClass; + }; }; } else { - if (-1 == _dynamicClasses findIf {_sourceClass isKindOf _x}) then { - _dynamicClasses pushBackUnique _sourceClass; + if (_baseDynamicClasses findIf {_sourceClass isKindOf _x} == -1) then { + _baseDynamicClasses pushBack _sourceClass; }; }; + if (_isPublic) then { + _cacheRefuelCargo set [_sourceClass, _fuelCargo]; + }; }; -} forEach ('true' configClasses (configFile >> "CfgVehicles")); +} forEach ("true" configClasses (configFile >> "CfgVehicles")); -TRACE_2("compiled",count _staticClasses,count _dynamicClasses); -uiNamespace setVariable [QGVAR(cacheRefuelClasses), compileFinal str [_staticClasses, _dynamicClasses]]; +TRACE_3("found",count _staticClasses,count _baseStaticClasses,count _baseDynamicClasses); +uiNamespace setVariable [QGVAR(cacheRefuelClassesStatic), compileFinal (_staticClasses createHashMapFromArray [])]; +uiNamespace setVariable [QGVAR(cacheRefuelClassesBaseStatic), compileFinal (_baseStaticClasses createHashMapFromArray [])]; +uiNamespace setVariable [QGVAR(cacheRefuelClassesBaseDynamic), compileFinal (_baseDynamicClasses createHashMapFromArray [])]; +uiNamespace setVariable [QGVAR(cacheRefuelCargo), compileFinal _cacheRefuelCargo]; diff --git a/addons/refuel/config.cpp b/addons/refuel/config.cpp index b39b665059..79b97994f1 100644 --- a/addons/refuel/config.cpp +++ b/addons/refuel/config.cpp @@ -14,6 +14,7 @@ class CfgPatches { }; }; +#include "ACE_Refuel_Positions.hpp" #include "ACE_Settings.hpp" #include "Cfg3DEN.hpp" #include "CfgEventHandlers.hpp" diff --git a/addons/refuel/dev/exportTerrainRefuelPositions.sqf b/addons/refuel/dev/exportTerrainRefuelPositions.sqf new file mode 100644 index 0000000000..72b60a3f1c --- /dev/null +++ b/addons/refuel/dev/exportTerrainRefuelPositions.sqf @@ -0,0 +1,84 @@ +// call compileScript ["z\ace\addons\refuel\dev\exportTerrainRefuelPositions.sqf"] +// can be run in Eden Editor console + +#include "\z\ace\addons\refuel\script_component.hpp" + +private _basePumps = []; +private _totalCount = 0; +private _posCount = 0; +private _message = ""; +private _halfWorldSize = worldSize / 2; +private _worldCenter = [_halfWorldSize, _halfWorldSize]; +_halfWorldSize = _halfWorldSize * sqrt 2; + +private _baseStaticClasses = keys (uiNamespace getVariable QGVAR(cacheRefuelClassesBaseStatic)); +private _class = ""; +private _objects = []; +private _positions = []; +private _object = objNull; +private _pos = []; + +{ + _class = _x; + _objects = _worldCenter nearObjects [_class, _halfWorldSize]; + if (_objects isEqualTo []) then { + continue; + }; + ADD(_totalCount,count _objects); + _positions = []; + { + _object = _x; + _pos = ASLToAGL getPosASL _object; + if (-1 < _positions findIf {60 > _x distance _pos && {20 < _x distance _pos}}) then { + _message = "INCREASE DISTANCE " + str _pos; + }; + if (-1 == _positions findIf {20 > _x distance _pos}) then { + _positions pushBack (_pos apply {round _x}); + INC(_posCount); + }; + } forEach _objects; + _positions sort true; // sort positions by smallest first + _basePumps pushBack [_class, _positions]; +} forEach _baseStaticClasses; + +_basePumps sort true; // sort pump classes alphabetically + +// check final array as it's calculated in postInit +private _checkCount = 0; +{ + _x params ["_class", "_positions"]; + { + _checkCount = _checkCount + count (_x nearObjects [_class, 30]); + } forEach _positions; +} forEach _basePumps; +if (_checkCount != _totalCount) then { + _message = "WRONG COUNT " + str _checkCount; +}; + +// export text +private _nl = toString [10]; +private _multipleBasePumps = 1 < count _basePumps; +private _output = [format [" %1[] = { /* %2 */", worldName, getText (configfile >> "CfgWorlds" >> worldName >> "description")]]; +{ + if (_forEachIndex > 0) then {_output pushBack ","}; + _x params ["_class", "_positions"]; + if (_multipleBasePumps) then { + _output pushBack (_nl + " "); + } else { + _output pushBack " "; + }; + _output pushBack format ["{""%1"", {", _class]; + { + if (_forEachIndex > 0) then {_output pushBack ","}; + _output pushBack format ["{%1,%2,%3}", _x#0, _x#1, _x#2]; + } forEach _positions; + _output pushBack "}}"; +} forEach _basePumps; +if (_multipleBasePumps) then {_output pushBack (_nl + " ")}; +if (_basePumps isEqualTo []) then {_output pushBack " "}; +_output pushBack ("};" + _nl); + +_output = _output joinString ""; + +copyToClipboard _output; +[_totalCount, _posCount, _message, _output] diff --git a/addons/refuel/dev/test_debugConfigs.sqf b/addons/refuel/dev/test_debugConfigs.sqf index f427f07d28..52ff8a962a 100644 --- a/addons/refuel/dev/test_debugConfigs.sqf +++ b/addons/refuel/dev/test_debugConfigs.sqf @@ -5,14 +5,14 @@ private _testPass = true; -diag_log text format ["[ACE-refuel] Showing CfgVehicles with vanilla transportFuel"]; -private _fuelTrucks = configProperties [configFile >> "CfgVehicles", "(isClass _x) && {(getNumber (_x >> 'transportFuel')) > 0}", true]; +INFO("Showing CfgVehicles with transportFuel and without XEH"); +private _badCfgVehicles = ' + 2 == getNumber (_x >> "scope") + && {0 < getNumber (_x >> "transportFuel")} + && {!isText (_x >> "EventHandlers" >> "CBA_Extended_EventHandlers" >> "init")} +' configClasses (configFile >> "CfgVehicles"); { - if ((configName _x) isKindOf "Car") then { - diag_log text format ["Car [%1] needs config [transportFuel: %2]", configName _x, getNumber (_x >> 'transportFuel')]; - } else { - diag_log text format ["Non-car? [%1] needs config [transportFuel: %2]", configName _x, getNumber (_x >> 'transportFuel')]; - }; -} forEach _fuelTrucks; + diag_log text format ["Class %1: %2 [%3] needs XEH", configName _x, configName inheritsFrom _x, configSourceMod _x]; +} forEach _badCfgVehicles; _testPass diff --git a/addons/refuel/functions/fnc_getFuelCargo.sqf b/addons/refuel/functions/fnc_getFuelCargo.sqf new file mode 100644 index 0000000000..360679013e --- /dev/null +++ b/addons/refuel/functions/fnc_getFuelCargo.sqf @@ -0,0 +1,20 @@ +#include "..\script_component.hpp" +/* + * Author: Dystopian + * Returns vehicle fuel amount from config (cached). + * + * Arguments: + * 0: Fuel Source + * + * Return Value: + * Fuel amount from config + * + * Example: + * cursorObject call ace_refuel_fnc_getFuelCargo + * + * Public: No + */ + +params ["_source"]; + +(uiNamespace getVariable QGVAR(cacheRefuelCargo)) getOrDefault [typeOf _source, REFUEL_DISABLED_FUEL] diff --git a/addons/refuel/functions/fnc_makeJerryCan.sqf b/addons/refuel/functions/fnc_makeJerryCan.sqf index 4b807756c9..31a91a30d7 100644 --- a/addons/refuel/functions/fnc_makeJerryCan.sqf +++ b/addons/refuel/functions/fnc_makeJerryCan.sqf @@ -16,6 +16,13 @@ * Public: Yes */ +// Only run this after the settings are initialized +if !(EGVAR(common,settingsInitFinished)) exitWith { + EGVAR(common,runAtSettingsInitialized) pushBack [FUNC(makeJerryCan), _this]; +}; + +if (!GVAR(enabled)) exitWith {}; + params [["_target", objNull, [objNull]], ["_fuelAmount", 20, [0]]]; if (isNull _target || diff --git a/addons/refuel/functions/fnc_makeSource.sqf b/addons/refuel/functions/fnc_makeSource.sqf index 38b2d8a261..30c4722377 100644 --- a/addons/refuel/functions/fnc_makeSource.sqf +++ b/addons/refuel/functions/fnc_makeSource.sqf @@ -25,19 +25,22 @@ if !(EGVAR(common,settingsInitFinished)) exitWith { EGVAR(common,runAtSettingsInitialized) pushBack [FUNC(makeSource), _this]; }; +if (!GVAR(enabled)) exitWith {}; + params [ ["_source", objNull, [objNull]], ["_fuelCargo", 0, [0]], ["_hooks", nil, [[]]] ]; -TRACE_3("makeSource",_source,_fuelCargo,_hooks); -private _fuelCargoConfig = getNumber (configOf _source >> QGVAR(fuelCargo)); +private _fuelCargoConfig = _source call FUNC(getFuelCargo); + +TRACE_4("makeSource",_source,_fuelCargo,_hooks,_fuelCargoConfig); if ( isNull _source || {_fuelCargo < 0 && {!(_fuelCargo in [REFUEL_INFINITE_FUEL, REFUEL_DISABLED_FUEL])}} - || {_fuelCargo != 0 && {_fuelCargo == _fuelCargoConfig}} + || {_fuelCargo == REFUEL_DISABLED_FUEL && {_fuelCargoConfig == REFUEL_DISABLED_FUEL}} ) exitWith {}; private _capacity = if (_fuelCargo < 0) then {_fuelCargo} else {_fuelCargoConfig max _fuelCargo}; @@ -57,10 +60,10 @@ if ( }; // only add if menu doesn't already exist -if (!(_fuelCargoConfig != 0 && {!isNil {_source getVariable QGVAR(initSource_jipID)}})) then { - private _jipID = [QGVAR(initSource), [_source]] call CBA_fnc_globalEventJIP; - [_jipID, _source] call CBA_fnc_removeGlobalEventJIP; - _source setVariable [QGVAR(initSource_jipID), _jipID]; -}; +if (_fuelCargoConfig != REFUEL_DISABLED_FUEL || {!isNil {_source getVariable QGVAR(initSource_jipID)}}) exitWith {}; + +private _jipID = [QGVAR(initSource), [_source]] call CBA_fnc_globalEventJIP; +[_jipID, _source] call CBA_fnc_removeGlobalEventJIP; +_source setVariable [QGVAR(initSource_jipID), _jipID]; [QGVAR(sourceInitialized), [_source]] call CBA_fnc_globalEvent; diff --git a/addons/refuel/initSettings.inc.sqf b/addons/refuel/initSettings.inc.sqf index f3744697a4..44df66334f 100644 --- a/addons/refuel/initSettings.inc.sqf +++ b/addons/refuel/initSettings.inc.sqf @@ -1,5 +1,15 @@ private _category = [ELSTRING(main,Category_Logistics), "str_state_refuel"]; +[ + QGVAR(enabled), "CHECKBOX", + ELSTRING(common,Enabled), + _category, + true, + 1, + {[QGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart +] call CBA_fnc_addSetting; + [ QGVAR(rate), "SLIDER", [LSTRING(RefuelSettings_speed_DisplayName), LSTRING(RefuelSettings_speed_Description)], diff --git a/docs/wiki/framework/refuel-framework.md b/docs/wiki/framework/refuel-framework.md index 325606a970..3cf10d7205 100644 --- a/docs/wiki/framework/refuel-framework.md +++ b/docs/wiki/framework/refuel-framework.md @@ -134,5 +134,5 @@ The jerry can will now have a volume of 200 liters. | Name | Arguments | Global? | Added in | | ------------- | ------------- | ----- | ------------- | -| ace_refuel_sourceInitialized | Fuel source (OBJECT), items (BOOL or ARRAY) | Yes | 3.16.0 | +| ace_refuel_sourceInitialized | Fuel source (OBJECT) | Yes | 3.16.0 | | ace_refuel_jerryCanInitalized | Jerry can (OBJECT) | Yes | 3.16.0 | From c0d74ba703fa38f2e86bc69e9793000577f1da85 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 23 May 2024 21:56:08 +0200 Subject: [PATCH 047/290] Refuel - Fix fuel source disabling (#9995) * Add enable setting * Exclude man class init * Fix multiplayer terrain pump fuel sync * Add terrain pumps positions * Add vanilla fuel cargo restoring before destroying * Add Livonia positions by bux * Fix terrain pumps destruction * Improve settings init * Fix double settings category * Check enabled var in public functions * Fix fnc_makeSource * Handle recent CUP Terrains changes * Update includes * Fix issues introduced in #9133 * Change warning Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * Optimisations and cleanup - Use hashmaps wherever possible - Reduced pump search radius by ~30% - Sorted pumps alphabetically and sorted positions by "smallest" first, for consistency * Add init debug trace * compileScript in dev * yoda conditions & DFUNC macro * Wait until CBA settings are ready * Update Chernarus 2020 and add more maps configs * Remove vanilla fuel cargo restoring before destroying * Update fnc_makeSource.sqf --------- Co-authored-by: Dystopian Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> --- addons/refuel/functions/fnc_makeSource.sqf | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/addons/refuel/functions/fnc_makeSource.sqf b/addons/refuel/functions/fnc_makeSource.sqf index 30c4722377..9d76635849 100644 --- a/addons/refuel/functions/fnc_makeSource.sqf +++ b/addons/refuel/functions/fnc_makeSource.sqf @@ -40,9 +40,24 @@ TRACE_4("makeSource",_source,_fuelCargo,_hooks,_fuelCargoConfig); if ( isNull _source || {_fuelCargo < 0 && {!(_fuelCargo in [REFUEL_INFINITE_FUEL, REFUEL_DISABLED_FUEL])}} - || {_fuelCargo == REFUEL_DISABLED_FUEL && {_fuelCargoConfig == REFUEL_DISABLED_FUEL}} ) exitWith {}; +// We might be removing fuel from an object that in config doesn't have fuel, but was given fuel via this function prior +if (_fuelCargo == REFUEL_DISABLED_FUEL && {_fuelCargoConfig == REFUEL_DISABLED_FUEL}) exitWith { + if (isNil {_source getVariable QGVAR(currentFuelCargo)}) exitWith {}; + + _source setVariable [QGVAR(currentFuelCargo), nil, true]; + _source setVariable [QGVAR(capacity), REFUEL_DISABLED_FUEL, true]; + + private _jipID = _source getVariable QGVAR(initSource_jipID); + + if (isNil "_jipID") exitWith {}; + + _jipID call CBA_fnc_removeGlobalEventJIP; + + _source setVariable [QGVAR(initSource_jipID), nil]; +}; + private _capacity = if (_fuelCargo < 0) then {_fuelCargo} else {_fuelCargoConfig max _fuelCargo}; _source setVariable [QGVAR(capacity), _capacity, true]; From c634bbe1ab32b21304b192473e9238e8c4215e76 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 23 May 2024 21:56:28 +0200 Subject: [PATCH 048/290] CSW - Force `QGVAR(handleExtraMagazinesType)` to be respected (#9903) Force QGVAR(handleExtraMagazinesType) to be respected --- addons/csw/functions/fnc_reload_handleReturnAmmo.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/csw/functions/fnc_reload_handleReturnAmmo.sqf b/addons/csw/functions/fnc_reload_handleReturnAmmo.sqf index da8383b608..ca445400b0 100644 --- a/addons/csw/functions/fnc_reload_handleReturnAmmo.sqf +++ b/addons/csw/functions/fnc_reload_handleReturnAmmo.sqf @@ -41,7 +41,7 @@ if ((_fullMagazines == 0) && {_bulletsRemaining == 0}) exitWith {}; private _container = _unloadTo getVariable [QGVAR(container), objNull]; if ((_container distance _unloadTo) > 10) then { _container = objNull; }; if (isNull _container) then { - _container = (nearestObjects [_unloadTo, [QGVAR(ammo_holder), "GroundWeaponHolder"], 10]) param [0, objNull]; + _container = (nearestObjects [_unloadTo, [["GroundWeaponHolder"], [QGVAR(ammo_holder)]] select GVAR(handleExtraMagazinesType), 10]) param [0, objNull]; }; From 05ebe1f48f13a39a9b6fc852471da782d004e768 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Thu, 23 May 2024 17:25:59 -0500 Subject: [PATCH 049/290] Medical Treatment - Allow diagnosing cardiac arrest with clear language (#9997) --- .../functions/fnc_checkResponse.sqf | 5 +++++ addons/medical_treatment/initSettings.inc.sqf | 2 +- addons/medical_treatment/stringtable.xml | 12 ++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/addons/medical_treatment/functions/fnc_checkResponse.sqf b/addons/medical_treatment/functions/fnc_checkResponse.sqf index dc76b1dbfb..ca95fcb1d1 100644 --- a/addons/medical_treatment/functions/fnc_checkResponse.sqf +++ b/addons/medical_treatment/functions/fnc_checkResponse.sqf @@ -22,6 +22,11 @@ params ["_medic", "_patient"]; private _output = if (_patient call EFUNC(common,isAwake)) then { LSTRING(Check_Response_Responsive) } else { + if (GVAR(advancedDiagnose) == 3) exitWith { + if (IN_CRDC_ARRST(_patient)) exitWith { LSTRING(Check_Response_CardiacArrestDirect) }; + if (!alive _patient) exitWith { LSTRING(Check_Response_DeadDirect) }; + LSTRING(Check_Response_UnresponsiveDirect) + }; if ((GVAR(advancedDiagnose) == 2) && {IN_CRDC_ARRST(_patient)}) exitWith { LSTRING(Check_Response_CardiacArrest) }; if ((GVAR(advancedDiagnose) == 2) && {!alive _patient}) exitWith { LSTRING(Check_Response_Dead) }; LSTRING(Check_Response_Unresponsive) diff --git a/addons/medical_treatment/initSettings.inc.sqf b/addons/medical_treatment/initSettings.inc.sqf index fbb1b170c8..d080965eb9 100644 --- a/addons/medical_treatment/initSettings.inc.sqf +++ b/addons/medical_treatment/initSettings.inc.sqf @@ -3,7 +3,7 @@ "LIST", [LSTRING(AdvancedDiagnose_DisplayName), LSTRING(AdvancedDiagnose_Description)], [ELSTRING(medical,Category), LSTRING(SubCategory_Treatment)], - [[0, 1, 2], [ELSTRING(common,Disabled), ELSTRING(common,Enabled), LSTRING(AdvancedDiagnose_DiagnoseCardiacArrest)], 1], + [[0, 1, 2, 3], [ELSTRING(common,Disabled), ELSTRING(common,Enabled), LSTRING(AdvancedDiagnose_DiagnoseCardiacArrest), LSTRING(AdvancedDiagnose_DiagnoseCardiacArrestDirect)], 1], true ] call CBA_fnc_addSetting; diff --git a/addons/medical_treatment/stringtable.xml b/addons/medical_treatment/stringtable.xml index ea38c6fbe8..477c18d019 100644 --- a/addons/medical_treatment/stringtable.xml +++ b/addons/medical_treatment/stringtable.xml @@ -77,6 +77,9 @@ Habilitado y poder diagnosticar Muerte/Parada cardíaca Abilitato e può diagnosticare Morte/Arresto Cardiaco + + Enabled & Can Diagnose Death/Cardiac Arrest [Directly] + Advanced Medication Erweiterte Medikation @@ -4153,6 +4156,9 @@ %1 沒有反應 %1 tepki vermiyor + + %1 is unconscious + %1 is not responsive, taking shallow gasps and convulsing %1 est inconscient, respire par intermittence et convulse. @@ -4165,6 +4171,9 @@ %1 не реагирует на раздражители, поверхностно дышит, в конвульсиях %1 no responde, dando pequeñas bocanadas y convulsionando + + %1 is in cardiac arrest + %1 is not responsive, motionless and cold %1 est inconscient, inanimé et froid. @@ -4177,6 +4186,9 @@ %1 не реагирует на раздражители, не шевелится и холодный %1 no responde, sin movimiento y frío + + %1 is dead + You checked %1 Вы осмотрели раненого %1 From 22c6621878d3fb3edc6e525d438e9452dbcc3fc4 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Fri, 24 May 2024 17:59:59 -0500 Subject: [PATCH 050/290] Refuel - Cleanup compats (#10011) * Refuel - Cleanup compats * add `XEH_INHERITED` --- addons/compat_cup_terrains/CfgVehicles.hpp | 18 +++++++++++++----- .../compat_cup_vehicles_refuel/CfgVehicles.hpp | 5 ----- .../compat_gm/compat_gm_refuel/CfgVehicles.hpp | 6 ------ addons/compat_gm/compat_gm_refuel/config.cpp | 1 - .../compat_rhs_afrf3_refuel/CfgVehicles.hpp | 10 ---------- .../compat_rhs_afrf3_refuel/config.cpp | 2 +- .../compat_rhs_usf3_refuel/CfgVehicles.hpp | 15 --------------- .../compat_rhs_usf3_refuel/config.cpp | 1 - addons/compat_sog/CfgVehicles/wheeled.hpp | 2 -- 9 files changed, 14 insertions(+), 46 deletions(-) delete mode 100644 addons/compat_gm/compat_gm_refuel/CfgVehicles.hpp delete mode 100644 addons/compat_rhs_afrf3/compat_rhs_afrf3_refuel/CfgVehicles.hpp delete mode 100644 addons/compat_rhs_usf3/compat_rhs_usf3_refuel/CfgVehicles.hpp diff --git a/addons/compat_cup_terrains/CfgVehicles.hpp b/addons/compat_cup_terrains/CfgVehicles.hpp index 08176b77fe..3fbd69f291 100644 --- a/addons/compat_cup_terrains/CfgVehicles.hpp +++ b/addons/compat_cup_terrains/CfgVehicles.hpp @@ -1,3 +1,6 @@ +class CBA_Extended_EventHandlers; +#define XEH_INHERITED class EventHandlers {class CBA_Extended_EventHandlers: CBA_Extended_EventHandlers {};} + class CfgVehicles { class House; class House_Small_F; @@ -5,7 +8,7 @@ class CfgVehicles { class House_EP1: House {}; class Land_Benzina_schnell: House { - transportFuel = 0; + XEH_INHERITED; EGVAR(refuel,hooks)[] = {{-1.5,-3.93,-1.25}, {2.35,-3.93,-1.25}}; EGVAR(refuel,fuelCargo) = REFUEL_INFINITE_FUEL; class ACE_Actions { @@ -18,22 +21,22 @@ class CfgVehicles { }; }; class Land_A_FuelStation_Feed: Strategic { - transportFuel = 0; + XEH_INHERITED; EGVAR(refuel,hooks)[] = {{-0.34,0,0}, {0.34,0,0}}; EGVAR(refuel,fuelCargo) = REFUEL_INFINITE_FUEL; }; class Land_Ind_FuelStation_Feed_EP1: House_EP1 { - transportFuel = 0; + XEH_INHERITED; EGVAR(refuel,hooks)[] = {{-0.34,0,0}, {0.34,0,0}}; EGVAR(refuel,fuelCargo) = REFUEL_INFINITE_FUEL; }; class Land_FuelStation_Feed_PMC: Strategic { - transportFuel = 0; + XEH_INHERITED; EGVAR(refuel,hooks)[] = {{-0.34,0,0}, {0.34,0,0}}; EGVAR(refuel,fuelCargo) = REFUEL_INFINITE_FUEL; }; class FuelStation: House_Small_F { - transportFuel = 0; + XEH_INHERITED; EGVAR(refuel,hooks)[] = {{1.25, .2, -1.1}}; EGVAR(refuel,fuelCargo) = REFUEL_INFINITE_FUEL; class ACE_Actions { @@ -45,4 +48,9 @@ class CfgVehicles { }; }; }; + class WarfareBBaseStructure; + class Base_WarfareBVehicleServicePoint: WarfareBBaseStructure { + // "vehicle service point" (a conex /w barrels) - need hooks??? + XEH_INHERITED; + }; }; diff --git a/addons/compat_cup_vehicles/compat_cup_vehicles_refuel/CfgVehicles.hpp b/addons/compat_cup_vehicles/compat_cup_vehicles_refuel/CfgVehicles.hpp index 186690908c..1042c0eacf 100644 --- a/addons/compat_cup_vehicles/compat_cup_vehicles_refuel/CfgVehicles.hpp +++ b/addons/compat_cup_vehicles/compat_cup_vehicles_refuel/CfgVehicles.hpp @@ -1,35 +1,30 @@ class CfgVehicles { class CUP_T810_Unarmed_Base; class CUP_T810_Refuel_Base: CUP_T810_Unarmed_Base { - transportFuel = 0; EGVAR(refuel,hooks)[] = {{-1.01, 0.21, -0.5},{1.08, 0.2, -0.5}}; EGVAR(refuel,fuelCargo) = 10000; }; class Truck_02_fuel_base_F; class CUP_Kamaz_5350_Refuel_Base: Truck_02_fuel_base_F { - transportFuel = 0; EGVAR(refuel,hooks)[] = {{-0.02, -3.33, -1.05}}; EGVAR(refuel,fuelCargo) = 10000; }; class CUP_Ural_Support_Base; class CUP_Ural_Refuel_Base: CUP_Ural_Support_Base { - transportFuel = 0; EGVAR(refuel,hooks)[] = {{-0.05, -3.65, -0.42}}; EGVAR(refuel,fuelCargo) = 10000; }; class CUP_V3S_Open_Base; class CUP_V3S_Refuel_Base: CUP_V3S_Open_Base { - transportFuel = 0; EGVAR(refuel,hooks)[] = {{-0.35, -3.35, -0.4},{0.40, -3.35, -0.4}}; EGVAR(refuel,fuelCargo) = 6500; }; class CUP_MTVR_Base; class CUP_MTVR_Refuel_Base: CUP_MTVR_Base { - transportFuel = 0; EGVAR(refuel,hooks)[] = {{-1.09, -0.01, -0.5},{1, -0.01, -0.5}}; EGVAR(refuel,fuelCargo) = 10000; }; diff --git a/addons/compat_gm/compat_gm_refuel/CfgVehicles.hpp b/addons/compat_gm/compat_gm_refuel/CfgVehicles.hpp deleted file mode 100644 index 46a4deeefd..0000000000 --- a/addons/compat_gm/compat_gm_refuel/CfgVehicles.hpp +++ /dev/null @@ -1,6 +0,0 @@ -class CfgVehicles { - class gm_ural4320_base; - class gm_ural4320_refuel_base: gm_ural4320_base { - transportFuel = 0; - }; -}; diff --git a/addons/compat_gm/compat_gm_refuel/config.cpp b/addons/compat_gm/compat_gm_refuel/config.cpp index 6becabe70a..05688eff70 100644 --- a/addons/compat_gm/compat_gm_refuel/config.cpp +++ b/addons/compat_gm/compat_gm_refuel/config.cpp @@ -21,4 +21,3 @@ class CfgPatches { }; #include "CfgEventHandlers.hpp" -#include "CfgVehicles.hpp" diff --git a/addons/compat_rhs_afrf3/compat_rhs_afrf3_refuel/CfgVehicles.hpp b/addons/compat_rhs_afrf3/compat_rhs_afrf3_refuel/CfgVehicles.hpp deleted file mode 100644 index 047e264c6e..0000000000 --- a/addons/compat_rhs_afrf3/compat_rhs_afrf3_refuel/CfgVehicles.hpp +++ /dev/null @@ -1,10 +0,0 @@ -class CfgVehicles { - class RHS_Ural_Support_MSV_Base_01; - class RHS_Ural_Fuel_MSV_01: RHS_Ural_Support_MSV_Base_01 { - transportFuel = 0; - }; - class rhs_kraz255b1_base; - class rhs_kraz255b1_fuel_base: rhs_kraz255b1_base { - transportFuel = 0; - }; -}; diff --git a/addons/compat_rhs_afrf3/compat_rhs_afrf3_refuel/config.cpp b/addons/compat_rhs_afrf3/compat_rhs_afrf3_refuel/config.cpp index 5101a383a3..8e1986b65f 100644 --- a/addons/compat_rhs_afrf3/compat_rhs_afrf3_refuel/config.cpp +++ b/addons/compat_rhs_afrf3/compat_rhs_afrf3_refuel/config.cpp @@ -18,4 +18,4 @@ class CfgPatches { }; }; -#include "CfgVehicles.hpp" +// ADDON kept for backward compatiblity diff --git a/addons/compat_rhs_usf3/compat_rhs_usf3_refuel/CfgVehicles.hpp b/addons/compat_rhs_usf3/compat_rhs_usf3_refuel/CfgVehicles.hpp deleted file mode 100644 index 5aaf6b4e22..0000000000 --- a/addons/compat_rhs_usf3/compat_rhs_usf3_refuel/CfgVehicles.hpp +++ /dev/null @@ -1,15 +0,0 @@ -class CfgVehicles { - class rhsusf_M1078A1P2_B_M2_fmtv_usarmy; - class rhsusf_M1078A1R_SOV_M2_D_fmtv_socom: rhsusf_M1078A1P2_B_M2_fmtv_usarmy { - transportFuel = 0; - }; - - class rhsusf_M977A4_usarmy_wd; - class rhsusf_M978A4_usarmy_wd: rhsusf_M977A4_usarmy_wd { - transportFuel = 0; - }; - - class rhsusf_M978A4_BKIT_usarmy_wd: rhsusf_M977A4_usarmy_wd { - transportFuel = 0; - }; -}; diff --git a/addons/compat_rhs_usf3/compat_rhs_usf3_refuel/config.cpp b/addons/compat_rhs_usf3/compat_rhs_usf3_refuel/config.cpp index 391e22d95e..bf600d5d5a 100644 --- a/addons/compat_rhs_usf3/compat_rhs_usf3_refuel/config.cpp +++ b/addons/compat_rhs_usf3/compat_rhs_usf3_refuel/config.cpp @@ -21,4 +21,3 @@ class CfgPatches { }; #include "CfgEventHandlers.hpp" -#include "CfgVehicles.hpp" diff --git a/addons/compat_sog/CfgVehicles/wheeled.hpp b/addons/compat_sog/CfgVehicles/wheeled.hpp index 3525328d3f..3a898519dd 100644 --- a/addons/compat_sog/CfgVehicles/wheeled.hpp +++ b/addons/compat_sog/CfgVehicles/wheeled.hpp @@ -5,7 +5,6 @@ class vn_wheeled_m54_base: vn_wheeled_truck_base { }; class vn_wheeled_m54_cab_base; class vn_wheeled_m54_fuel_base: vn_wheeled_m54_cab_base { - transportFuel = 0; EGVAR(refuel,hooks)[] = {{-1.15, -2.3, 0.28}}; EGVAR(refuel,fuelCargo) = 4542; }; @@ -25,7 +24,6 @@ class vn_wheeled_z157_base: vn_wheeled_truck_base { EGVAR(refuel,fuelCapacity) = 150; }; class vn_wheeled_z157_fuel_base: vn_wheeled_z157_base { - transportFuel = 0; EGVAR(refuel,hooks)[] = {{-1.36, -3.575, -0.4}}; EGVAR(refuel,fuelCargo) = 4000; }; From dc3753893f903d86b7791a8c759cf631d9f15ef0 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 25 May 2024 01:05:19 +0200 Subject: [PATCH 051/290] Hearing - Improve and cleanup code (#9933) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jouni Järvinen Co-authored-by: PabstMirror Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> --- addons/hearing/XEH_PREP.hpp | 1 + addons/hearing/XEH_postInit.sqf | 2 +- addons/hearing/functions/fnc_addEarPlugs.sqf | 64 ++++++------ .../hearing/functions/fnc_explosionNear.sqf | 1 - addons/hearing/functions/fnc_firedNear.sqf | 99 ++++++------------- .../hearing/functions/fnc_getAmmoLoudness.sqf | 44 +++++++++ 6 files changed, 112 insertions(+), 99 deletions(-) create mode 100644 addons/hearing/functions/fnc_getAmmoLoudness.sqf diff --git a/addons/hearing/XEH_PREP.hpp b/addons/hearing/XEH_PREP.hpp index e06fa5d56c..707c6bd96d 100644 --- a/addons/hearing/XEH_PREP.hpp +++ b/addons/hearing/XEH_PREP.hpp @@ -3,6 +3,7 @@ PREP(addEarPlugs); PREP(earRinging); PREP(explosionNear); PREP(firedNear); +PREP(getAmmoLoudness); PREP(handleRespawn); PREP(hasEarPlugsIn); PREP(moduleHearing); diff --git a/addons/hearing/XEH_postInit.sqf b/addons/hearing/XEH_postInit.sqf index e6f328ad78..4a2ca90992 100644 --- a/addons/hearing/XEH_postInit.sqf +++ b/addons/hearing/XEH_postInit.sqf @@ -14,7 +14,7 @@ if (!hasInterface) exitWith {}; #include "initKeybinds.inc.sqf" -GVAR(cacheAmmoLoudness) = call CBA_fnc_createNamespace; +GVAR(cacheAmmoLoudness) = createHashMap; GVAR(deafnessDV) = 0; GVAR(deafnessPrior) = 0; diff --git a/addons/hearing/functions/fnc_addEarPlugs.sqf b/addons/hearing/functions/fnc_addEarPlugs.sqf index fdbcfbc621..11999f7737 100644 --- a/addons/hearing/functions/fnc_addEarPlugs.sqf +++ b/addons/hearing/functions/fnc_addEarPlugs.sqf @@ -4,7 +4,7 @@ * Called on unit initialization. Adds earplugs if the unit is equipped with either a really loud primary weapon or a rocket launcher. * * Arguments: - * 0: A Soldier + * 0: Unit * * Return Value: * None @@ -15,9 +15,9 @@ * Public: No */ -// only run this after the settings are initialized -if !(EGVAR(common,settingsInitFinished)) exitWith { - EGVAR(common,runAtSettingsInitialized) pushBack [FUNC(addEarPlugs), _this]; +// Only run this after the settings are initialized +if (!EGVAR(common,settingsInitFinished)) exitWith { + EGVAR(common,runAtSettingsInitialized) pushBack [LINKFUNC(addEarPlugs), _this]; }; // Exit if hearing is disabled or if autoAdd is disabled @@ -29,42 +29,48 @@ TRACE_2("params",_unit,typeOf _unit); // Exit if the unit already has earplugs (in ears (persistence scenarios) or inventory) if (_unit call FUNC(hasEarPlugsIn) || {[_unit, "ACE_EarPlugs"] call EFUNC(common,hasItem)}) exitWith {}; -// Add earplugs if enabled for everyone or if the soldier has a rocket launcher +// Add earplugs if enabled for everyone or if the unit has a rocket launcher if (GVAR(autoAddEarplugsToUnits) == 2 || {(secondaryWeapon _unit) != ""}) exitWith { TRACE_1("has launcher - adding",_unit); _unit addItem "ACE_EarPlugs"; }; -// otherwise add earplugs if the soldier has a big rifle -if ((primaryWeapon _unit) == "") exitWith {}; +// Otherwise add earplugs if the unit has a big rifle +private _weapon = primaryWeapon _unit; -(primaryWeaponMagazine _unit) params [["_magazine", ""]]; -if (_magazine == "") exitWith {}; +if (_weapon == "") exitWith {}; -private _cfgMagazine = configFile >> "CfgMagazines" >> _magazine; - -private _initSpeed = getNumber (_cfgMagazine >> "initSpeed"); -private _ammo = getText (_cfgMagazine >> "ammo"); -private _count = getNumber (_cfgMagazine >> "count"); - -private _cfgAmmo = configFile >> "CfgAmmo"; - -private _caliber = getNumber (_cfgAmmo >> _ammo >> "ACE_caliber"); -_caliber = call { - if (_ammo isKindOf ["ShellBase", _cfgAmmo]) exitWith { 80 }; - if (_ammo isKindOf ["RocketBase", _cfgAmmo]) exitWith { 200 }; - if (_ammo isKindOf ["MissileBase", _cfgAmmo]) exitWith { 600 }; - if (_ammo isKindOf ["SubmunitionBase", _cfgAmmo]) exitWith { 80 }; - [_caliber, 6.5] select (_caliber <= 0); +if (isNil QGVAR(cacheMaxAmmoLoudness)) then { + GVAR(cacheMaxAmmoLoudness) = createHashMap; }; -private _loudness = (_caliber ^ 1.25 / 10) * (_initspeed / 1000) / 5; -//If unit has a machine gun boost effective loudness 50% -if (_count >= 50) then {_loudness = _loudness * 1.5}; +// Cache maximum loudness for future calls +private _maxLoudness = GVAR(cacheMaxAmmoLoudness) getOrDefaultCall [_weapon, { + // Get the weapon's compatible magazines, so that all magazines are cached + // From all the loudness factors, take the max + private _maxLoudness = selectMax ((compatibleMagazines _weapon) apply {_x call FUNC(getAmmoLoudness)}); -TRACE_2("primaryWeapon",_unit,_loudness); + // ace_gunbag_fnc_isMachineGun + private _config = _weapon call CBA_fnc_getItemConfig; -if (_loudness > 0.2) then { + // Definition of a machine gun by BIS_fnc_itemType + private _cursor = getText (_config >> "cursor"); + + if (toLowerANSI _cursor in ["", "emptycursor"]) then { + _cursor = getText (_config >> "cursorAim"); + }; + + // If unit has a machine gun boost effective loudness 50% + if (_cursor == "MG") then { + _maxLoudness = _maxLoudness * 1.5; + }; + + _maxLoudness +}, true]; + +TRACE_3("primaryWeapon",_unit,_weapon,_maxLoudness); + +if (_maxLoudness > 0.2) then { TRACE_1("loud gun - adding",_unit); _unit addItem "ACE_EarPlugs"; }; diff --git a/addons/hearing/functions/fnc_explosionNear.sqf b/addons/hearing/functions/fnc_explosionNear.sqf index c65cf31c76..fd632947ac 100644 --- a/addons/hearing/functions/fnc_explosionNear.sqf +++ b/addons/hearing/functions/fnc_explosionNear.sqf @@ -21,7 +21,6 @@ params ["_unit", "_damage"]; TRACE_2("explosion near player",_unit,_damage); private _strength = (0 max _damage) * 30; -if (_strength < 0.01) exitWith {}; // Call inmediately, as it will get pick up later anyway by the update thread [_strength] call FUNC(earRinging); diff --git a/addons/hearing/functions/fnc_firedNear.sqf b/addons/hearing/functions/fnc_firedNear.sqf index 4dd81862b9..45364cc0b6 100644 --- a/addons/hearing/functions/fnc_firedNear.sqf +++ b/addons/hearing/functions/fnc_firedNear.sqf @@ -4,97 +4,60 @@ * Handles deafness due to large-caliber weapons going off near the player. * * Arguments: - * 0: Unit - Object the event handler is assigned to - * 1: Firer: Object - Object which fires a weapon near the unit - * 2: Distance - Distance in meters between the unit and firer - * 3: weapon - Fired weapon - * 4: muzzle - Muzzle that was used (not used) - * 5: mode - Current mode of the fired weapon (not used) - * 6: ammo - Ammo used + * 0: Object the event handler is assigned to (unused) + * 1: Object which fires a weapon near the unit + * 2: Distance in meters between the unit and firer + * 3: Weapon + * 4: Muzzle + * 5: Current mode of the fired weapon + * 6: Ammo + * 7: Unit that fired the weapon * * Return Value: * None * * Example: - * [clientFiredNearEvent] call ace_hearing_fnc_firedNear - * [player, player, 10, "arifle_MX_ACO_pointer_F", "arifle_MX_ACO_pointer_F", "single", "B_65x39_Caseless"] call ace_hearing_fnc_firedNear + * [player, player, 10, "arifle_MX_ACO_pointer_F", "arifle_MX_ACO_pointer_F", "single", "B_65x39_Caseless", player] call ace_hearing_fnc_firedNear * * Public: No */ -params ["_object", "_firer", "_distance", "_weapon", "", "", "_ammo"]; +params ["", "_firer", "_distance", "_weapon", "_muzzle", "_mode", "_ammo", "_gunner"]; if (_weapon in ["Throw", "Put"]) exitWith {}; if (_distance > 50) exitWith {}; -private _vehAttenuation = [GVAR(playerVehAttenuation), 1] select ( - (ACE_player == (vehicle ACE_player)) || {isTurnedOut ACE_player} -); -private _distance = 1 max _distance; - -private _silencer = switch (_weapon) do { - case (primaryWeapon _firer) : {(primaryWeaponItems _firer) select 0}; - case (secondaryWeapon _firer) : {(secondaryWeaponItems _firer) select 0}; - case (handgunWeapon _firer) : {(handgunItems _firer) select 0}; - default {""}; -}; - +_distance = 1 max _distance; private _audibleFireCoef = 1; -if (_silencer != "") then { - _audibleFireCoef = getNumber (configFile >> "CfgWeapons" >> _silencer >> "ItemInfo" >> "AmmoCoef" >> "audibleFire"); -}; -private _loudness = GVAR(cacheAmmoLoudness) getVariable (format ["%1%2",_weapon,_ammo]); -if (isNil "_loudness") then { - private _muzzles = getArray (configFile >> "CfgWeapons" >> _weapon >> "muzzles"); - private _weaponMagazines = getArray (configFile >> "CfgWeapons" >> _weapon >> "magazines"); - { - if (_x != "this") then { - private _muzzleMagazines = getArray (configFile >> "CfgWeapons" >> _weapon >> _x >> "magazines"); - _weaponMagazines append _muzzleMagazines; - }; - } forEach _muzzles; - { - private _ammoType = getText(configFile >> "CfgMagazines" >> _x >> "ammo"); - _weaponMagazines set [_forEachIndex, [_x, _ammoType]]; - } forEach _weaponMagazines; +// Unit that fired is on foot +private _magazine = if (_gunner == _firer) then { + // Check if the unit has a suppressor + private _suppressor = (_firer weaponAccessories _weapon) select 0; - private _magazine = ""; - { - _x params ["_magazineType", "_ammoType"]; - if (_ammoType == _ammo) exitWith { - _magazine = _magazineType; - }; - } forEach _weaponMagazines; - - if (_magazine == "") then { - _loudness = 0; - TRACE_2("No mag for Weapon/Ammo??",_weapon,_ammo); - } else { - private _initSpeed = getNumber(configFile >> "CfgMagazines" >> _magazine >> "initSpeed"); - private _caliber = getNumber (configFile >> "CfgAmmo" >> _ammo >> "ACE_caliber"); - _caliber = call { - // If explicilty defined, use ACE_caliber - if ((count configProperties [(configFile >> "CfgAmmo" >> _ammo), "configName _x == 'ACE_caliber'", false]) == 1) exitWith {_caliber}; - if (_ammo isKindOf ["ShellBase", (configFile >> "CfgAmmo")]) exitWith { 80 }; - if (_ammo isKindOf ["RocketBase", (configFile >> "CfgAmmo")]) exitWith { 200 }; - if (_ammo isKindOf ["MissileBase", (configFile >> "CfgAmmo")]) exitWith { 600 }; - if (_ammo isKindOf ["SubmunitionBase", (configFile >> "CfgAmmo")]) exitWith { 80 }; - [_caliber, 6.5] select (_caliber <= 0) - }; - - _loudness = (_caliber ^ 1.25 / 10) * (_initspeed / 1000) / 5; - TRACE_6("building cache",_weapon,_ammo,_magazine,_initSpeed,_caliber,_loudness); + if (_suppressor != "") then { + _audibleFireCoef = getNumber (configFile >> "CfgWeapons" >> _suppressor >> "ItemInfo" >> "AmmoCoef" >> "audibleFire"); }; - GVAR(cacheAmmoLoudness) setVariable [(format ["%1%2",_weapon,_ammo]), _loudness]; + + (_firer weaponState _muzzle) select 3 +} else { + // Unit that fired is in a vehicle + (weaponState [_firer, _firer unitTurret _gunner, _weapon, _muzzle, _mode]) select 3 }; +if (_magazine == "") exitWith { + TRACE_5("No mag for weapon/ammo??",_weapon,_muzzle,_ammo,_firer,_gunner); +}; + +TRACE_6("mag",_magazine,_weapon,_muzzle,_ammo,_firer,_gunner); + +private _vehAttenuation = [GVAR(playerVehAttenuation), 1] select (isNull objectParent ACE_player || {isTurnedOut ACE_player}); +private _loudness = _magazine call FUNC(getAmmoLoudness); + _loudness = _loudness * _audibleFireCoef; private _strength = _vehAttenuation * (_loudness - (_loudness / 50 * _distance)); // linear drop off TRACE_1("result",_strength); -if (_strength < 0.01) exitWith {}; - // Call inmediately, as it will get pick up later anyway by the update thread [_strength] call FUNC(earRinging); diff --git a/addons/hearing/functions/fnc_getAmmoLoudness.sqf b/addons/hearing/functions/fnc_getAmmoLoudness.sqf new file mode 100644 index 0000000000..062b96fa71 --- /dev/null +++ b/addons/hearing/functions/fnc_getAmmoLoudness.sqf @@ -0,0 +1,44 @@ +#include "..\script_component.hpp" +/* + * Author: KoffeinFlummi, commy2, johnb43 + * Get the loudness of ammo. + * However, because `initSpeed` is a magazine attribute, the magazine name needs to be used instead of the ammo. + * + * Arguments: + * 0: Magazine + * + * Return Value: + * None + * + * Example: + * "30Rnd_65x39_caseless_mag" call ace_hearing_fnc_getAmmoLoudness + * + * Public: No + */ + +params ["_magazine"]; + +GVAR(cacheAmmoLoudness) getOrDefaultCall [_magazine, { + private _magazineConfig = configFile >> "CfgMagazines" >> _magazine; + private _ammo = getText (_magazineConfig >> "ammo"); + private _initSpeed = getNumber (_magazineConfig >> "initSpeed"); + + private _cfgAmmo = configFile >> "CfgAmmo"; + private _ammoConfig = _cfgAmmo >> _ammo; + private _caliber = getNumber (_ammoConfig >> "ACE_caliber"); + + _caliber = switch (true) do { + // If explicilty defined, use ACE_caliber + case (inheritsFrom (_ammoConfig >> "ACE_caliber") isEqualTo _ammoConfig): {_caliber}; + case (_ammo isKindOf ["ShellBase", _cfgAmmo]): {80}; + case (_ammo isKindOf ["RocketBase", _cfgAmmo]): {200}; + case (_ammo isKindOf ["MissileBase", _cfgAmmo]): {600}; + case (_ammo isKindOf ["SubmunitionBase", _cfgAmmo]): {80}; + default {[_caliber, 6.5] select (_caliber <= 0)}; + }; + + private _loudness = (_caliber ^ 1.25 / 10) * (_initspeed / 1000) / 5; + TRACE_5("building cache",_ammo,_magazine,_initSpeed,_caliber,_loudness); + + _loudness +}, true] From d7c1984a5adee4a01afddcdd8129fb9e65b52925 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 25 May 2024 01:06:13 +0200 Subject: [PATCH 052/290] Grenades - Fix not being able to switch throw modes in FFV (#10012) --- addons/grenades/XEH_postInit.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/grenades/XEH_postInit.sqf b/addons/grenades/XEH_postInit.sqf index c23640bca5..e5cfb56783 100644 --- a/addons/grenades/XEH_postInit.sqf +++ b/addons/grenades/XEH_postInit.sqf @@ -17,7 +17,7 @@ GVAR(flashbangPPEffectCC) ppEffectForceInNVG true; // Add keybinds ["ACE3 Weapons", QGVAR(switchGrenadeMode), localize LSTRING(SwitchGrenadeMode), { // Conditions: canInteract - if !([ACE_player, objNull, ["isNotEscorting"]] call EFUNC(common,canInteractWith)) exitWith {false}; + if !([ACE_player, objNull, ["isNotEscorting", "isNotInside"]] call EFUNC(common,canInteractWith)) exitWith {false}; // Conditions: specific if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; // Don't change mode or show hint if advanced throwing is active From be77ef233ee87e00cca6e71a2ae307c6b073c6ca Mon Sep 17 00:00:00 2001 From: JonBons Date: Fri, 24 May 2024 18:06:33 -0500 Subject: [PATCH 053/290] Cookoff - Delay full vehicle destruction (#9061) Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> --- addons/cookoff/functions/fnc_cookOff.sqf | 37 +++++++++++++++++++----- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/addons/cookoff/functions/fnc_cookOff.sqf b/addons/cookoff/functions/fnc_cookOff.sqf index 57cde71682..94cf63cb40 100644 --- a/addons/cookoff/functions/fnc_cookOff.sqf +++ b/addons/cookoff/functions/fnc_cookOff.sqf @@ -61,24 +61,45 @@ if (_smokeDelayEnabled) then { [{ params ["_vehicle", "_positions", "_intensity", "_ammoDetonationChance", "_detonateAfterCookoff", "_instigator", "_fireSource", "_canRing", "_canJet"]; _vehicle setVariable [QGVAR(intensity), _intensity]; - private _smokeEffects = _vehicle getVariable [QGVAR(effects), []]; [{ params ["_args", "_pfh"]; - _args params ["_vehicle", "_positions", "_ammoDetonationChance", "_detonateAfterCookoff", "_instigator", "_fireSource", "_canRing", "_canJet", "_smokeEffects"]; + _args params ["_vehicle", "_positions", "_ammoDetonationChance", "_detonateAfterCookoff", "_instigator", "_fireSource", "_canRing", "_canJet"]; private _intensity = _vehicle getVariable [QGVAR(intensity), 0]; + private _nextFlameTime = _vehicle getVariable [QGVAR(nextFlame), 0]; if (isNull _vehicle || {_intensity <= 1}) exitWith { - [QGVAR(cleanupEffects), [_vehicle, _smokeEffects]] call CBA_fnc_globalEvent; - _vehicle setVariable [QGVAR(isCookingOff), false, true]; [_pfh] call CBA_fnc_removePerFrameHandler; - if (GVAR(destroyVehicleAfterCookoff) || _detonateAfterCookoff) then { - _vehicle setDamage [1, true]; + if (isNull _vehicle) exitWith {}; + + if (GVAR(destroyVehicleAfterCookoff) || _detonateAfterCookoff) exitWith { + if (_fireSource isEqualTo "") then { + _fireSource = selectRandom _positions; + }; + + if (_nextFlameTime <= 0) then { + _nextFlameTime = MIN_TIME_BETWEEN_FLAMES max random MAX_TIME_BETWEEN_FLAMES; + }; + + [{ + params ["_vehicle", "_fireSource"]; + + if (isNull _vehicle) exitWith {}; + + [QGVAR(cleanupEffects), _vehicle] call CBA_fnc_globalEvent; + _vehicle setVariable [QGVAR(isCookingOff), false, true]; + + createVehicle ["ACE_ammoExplosionLarge", (_vehicle modelToWorld (_vehicle selectionPosition _fireSource)), [], 0 , "CAN_COLLIDE"]; + + _vehicle setDamage [1, true]; + }, [_vehicle, _fireSource], _nextFlameTime] call CBA_fnc_waitAndExecute; }; + + [QGVAR(cleanupEffects), _vehicle] call CBA_fnc_globalEvent; + _vehicle setVariable [QGVAR(isCookingOff), false, true]; }; private _lastFlameTime = _vehicle getVariable [QGVAR(lastFlame), 0]; - private _nextFlameTime = _vehicle getVariable [QGVAR(nextFlame), 0]; // Wait until we are ready for the next flame // dt = Tcurrent - Tlast @@ -125,5 +146,5 @@ if (_smokeDelayEnabled) then { _vehicle setVariable [QGVAR(nextExplosiveDetonation), random 60]; }; }; - }, 0.25, [_vehicle, _positions, _ammoDetonationChance, _detonateAfterCookoff, _instigator, _fireSource, _canRing, _canJet, _smokeEffects]] call CBA_fnc_addPerFrameHandler + }, 0.25, [_vehicle, _positions, _ammoDetonationChance, _detonateAfterCookoff, _instigator, _fireSource, _canRing, _canJet]] call CBA_fnc_addPerFrameHandler }, [_vehicle, _positions, _intensity, _ammoDetonationChance, _detonateAfterCookoff, _instigator, _fireSource, _canRing, _canJet], _delay] call CBA_fnc_waitAndExecute; From be9797d11d267b0e16065a746f56a5717c79ac86 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 27 May 2024 11:19:52 +0200 Subject: [PATCH 054/290] Grenades - Add grenade rolling (#10005) * Add grenade rolling * Added some safeguards * Use `setVectorDirAndUp` instead of rotation * Don't allow players to roll grenades when in vehicles * Grenades - Rolling only add PFEH when needed (#10015) * Grenades - Rolling only add PFEH when needed * Corrected minor typo, moved variable init in preInit, fixed bugs --------- Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * Don't switch modes if grenade can't be thrown * Minor tweaks --------- Co-authored-by: PabstMirror --- addons/compat_rhs_afrf3/CfgAmmo.hpp | 4 ++ addons/compat_sog/CfgAmmo/grenades.hpp | 7 +++ addons/grenades/XEH_postInit.sqf | 24 ++++++++++ addons/grenades/XEH_preInit.sqf | 3 ++ addons/grenades/functions/fnc_nextMode.sqf | 48 +++++++++++++++++-- .../grenades/functions/fnc_throwGrenade.sqf | 19 ++++++-- addons/grenades/script_component.hpp | 2 + addons/grenades/stringtable.xml | 3 ++ docs/wiki/feature/grenades.md | 2 + docs/wiki/framework/grenades-framework.md | 6 +++ 10 files changed, 111 insertions(+), 7 deletions(-) diff --git a/addons/compat_rhs_afrf3/CfgAmmo.hpp b/addons/compat_rhs_afrf3/CfgAmmo.hpp index 54ff3bd2c2..11aee03d79 100644 --- a/addons/compat_rhs_afrf3/CfgAmmo.hpp +++ b/addons/compat_rhs_afrf3/CfgAmmo.hpp @@ -219,6 +219,10 @@ class CfgAmmo { EGVAR(frag,force) = 0; }; + class SmokeShell; + class rhs_ammo_rdg2_white: SmokeShell { + EGVAR(grenades,rollVectorDirAndUp)[] = {{0, 1, 0}, {0, 0, 1}}; + }; class Sh_125mm_APFSDS; class Sh_125mm_HE; diff --git a/addons/compat_sog/CfgAmmo/grenades.hpp b/addons/compat_sog/CfgAmmo/grenades.hpp index d280443b6e..6395756f64 100644 --- a/addons/compat_sog/CfgAmmo/grenades.hpp +++ b/addons/compat_sog/CfgAmmo/grenades.hpp @@ -4,6 +4,13 @@ class vn_molotov_grenade_ammo: vn_grenadehand { EGVAR(frag,enabled) = 0; }; +class vn_t67_grenade_ammo: vn_grenadehand { + EGVAR(grenades,rollVectorDirAndUp)[] = {{-1, 0, 0}, {0, 0, 1}}; +}; +class vn_chicom_grenade_ammo: vn_grenadehand { + EGVAR(grenades,rollVectorDirAndUp)[] = {{1, 0, 0}, {0, 0, 1}}; +}; + class SmokeShell; class vn_m14_grenade_ammo: SmokeShell { EGVAR(grenades,incendiary) = 1; diff --git a/addons/grenades/XEH_postInit.sqf b/addons/grenades/XEH_postInit.sqf index e5cfb56783..21282ab1ce 100644 --- a/addons/grenades/XEH_postInit.sqf +++ b/addons/grenades/XEH_postInit.sqf @@ -32,3 +32,27 @@ GVAR(flashbangPPEffectCC) ppEffectForceInNVG true; [] call FUNC(addChangeFuseItemContextMenuOptions); }; }] call CBA_fnc_addEventHandler; + +["vehicle", { + private _currentThrowable = currentThrowable ACE_player; + + // Make sure grenade can be rolled if in roll mode (detonation time has to be >= 1 second and player isn't in a vehicle) + if !( + GVAR(currentThrowMode) == 3 && + {_currentThrowable isNotEqualTo []} && + { + !isNull objectParent ACE_player || + {getNumber (configFile >> "CfgAmmo" >> getText (configFile >> "CfgMagazines" >> _currentThrowable select 0 >> "ammo") >> "explosionTime") < MIN_EXPLOSION_TIME_FOR_ROLL} + } + ) exitWith {}; + + // If the player can't use throwables, don't change it + if !(ACE_player call CBA_fnc_canUseWeapon) exitWith {}; + + // Force the user into the normal throw mode + // Next throw mode after roll would be drop, which isn't ideal if the user tries to throw unknowingly... + [format [LLSTRING(RollGrenadeDisabled), LLSTRING(NormalThrow)], 2] call EFUNC(common,displayTextStructured); + + GVAR(currentThrowMode) = 0; + GVAR(throwModePFEH) call CBA_fnc_removePerFrameHandler; +}, true] call CBA_fnc_addPlayerEventHandler; diff --git a/addons/grenades/XEH_preInit.sqf b/addons/grenades/XEH_preInit.sqf index 894773534a..9456dc9c9f 100644 --- a/addons/grenades/XEH_preInit.sqf +++ b/addons/grenades/XEH_preInit.sqf @@ -6,6 +6,9 @@ PREP_RECOMPILE_START; #include "XEH_PREP.hpp" PREP_RECOMPILE_END; +GVAR(currentThrowMode) = 0; +GVAR(throwModePFEH) = -1; + #include "initSettings.inc.sqf" ADDON = true; diff --git a/addons/grenades/functions/fnc_nextMode.sqf b/addons/grenades/functions/fnc_nextMode.sqf index 1a64cf9f7b..d3d25027b1 100644 --- a/addons/grenades/functions/fnc_nextMode.sqf +++ b/addons/grenades/functions/fnc_nextMode.sqf @@ -15,7 +15,7 @@ * Public: No */ -private _mode = missionNamespace getVariable [QGVAR(currentThrowMode), 0]; +private _mode = GVAR(currentThrowMode); if (_mode == 4) then { _mode = 0; @@ -23,9 +23,18 @@ if (_mode == 4) then { _mode = _mode + 1; }; -// ROLL GRENADE DOESN'T WORK RIGHT NOW -if (_mode == 3) then { - _mode = 4; +private _currentThrowable = currentThrowable ACE_player; + +// Make sure grenade can be rolled if in roll mode (detonation time has to be >= 1 second and player isn't in a vehicle) +if ( + _mode == 3 && + {_currentThrowable isNotEqualTo []} && + { + !isNull objectParent ACE_player || + {getNumber (configFile >> "CfgAmmo" >> getText (configFile >> "CfgMagazines" >> _currentThrowable select 0 >> "ammo") >> "explosionTime") < MIN_EXPLOSION_TIME_FOR_ROLL} + } +) then { + _mode = _mode + 1; }; private _hint = localize ([ @@ -38,6 +47,37 @@ private _hint = localize ([ [_hint] call EFUNC(common,displayTextStructured); +GVAR(throwModePFEH) call CBA_fnc_removePerFrameHandler; GVAR(currentThrowMode) = _mode; +// If in rolling mode, check every frame if current throwable is rollable +if (GVAR(currentThrowMode) == 3) then { + GVAR(currentThrowable) = _currentThrowable; + + GVAR(throwModePFEH) = { + private _currentThrowable = currentThrowable ACE_player; + + if (GVAR(currentThrowable) isEqualTo _currentThrowable) exitWith {}; + + GVAR(currentThrowable) = _currentThrowable; + + // Make sure grenade can be rolled if in roll mode (detonation time has to be >= 1 second and player isn't in a vehicle) + if !( + GVAR(currentThrowMode) == 3 && + {_currentThrowable isNotEqualTo []} && + { + !isNull objectParent ACE_player || + {getNumber (configFile >> "CfgAmmo" >> getText (configFile >> "CfgMagazines" >> _currentThrowable select 0 >> "ammo") >> "explosionTime") < MIN_EXPLOSION_TIME_FOR_ROLL} + } + ) exitWith {}; + + // Force the user into the normal throw mode + // Next throw mode after roll would be drop, which isn't ideal if the user tries to throw unknowingly... + [format [LLSTRING(RollGrenadeDisabled), LLSTRING(NormalThrow)], 2] call EFUNC(common,displayTextStructured); + + GVAR(throwModePFEH) call CBA_fnc_removePerFrameHandler; + GVAR(currentThrowMode) = 0; + } call CBA_fnc_addPerFrameHandler; +}; + true diff --git a/addons/grenades/functions/fnc_throwGrenade.sqf b/addons/grenades/functions/fnc_throwGrenade.sqf index 9a0168da3e..939e0755da 100644 --- a/addons/grenades/functions/fnc_throwGrenade.sqf +++ b/addons/grenades/functions/fnc_throwGrenade.sqf @@ -85,7 +85,7 @@ if (getNumber (_config >> QGVAR(incendiary)) == 1) then { if (_unit != ACE_player) exitWith {}; if (_unit getVariable [QEGVAR(advanced_throwing,primed), false]) exitWith {LOG("advanced_throwing throw");}; -private _mode = missionNamespace getVariable [QGVAR(currentThrowMode), 0]; +private _mode = GVAR(currentThrowMode); if (_mode != 0) then { private _velocity = velocity _projectile; @@ -103,9 +103,22 @@ if (_mode != 0) then { case 2 : { _velocity = (_unit weaponDirection _weapon) vectorMultiply (vectorMagnitude _velocity); }; - //roll grande + //roll grenade case 3 : { - //@todo + private _posASL = getPosASL _projectile; + + // getPos is unreliable, as surfaces in some ruins are not recognised as surfaces + private _lisPos = (lineIntersectsSurfaces [_posASL, _posASL vectorAdd [0, 0, -1e11], ACE_player, objNull, true, 1, "ROADWAY", "FIRE"]) select 0; + _projectile setPosASL ((_lisPos select 0) vectorAdd [0, 0, 0.2]); + + // Rotate throwables by 90° to the side by default, so cylindrical throwables can be rolled + private _vectorDirAndUp = getArray (_config >> QGVAR(rollVectorDirAndUp)); + _vectorDirAndUp params [["_vectorDir", [0, 1, 0], [[]], 3], ["_vectorUp", [1, 0, 0], [[]], 3]]; + + // Do as if object were facing north + _projectile setVectorDirAndUp ([[_vectorDir, _vectorUp], -(direction _projectile), 0, 0] call BIS_fnc_transformVectorDirAndUp); + + _velocity = (vectorDir _unit) vectorMultiply 10; }; //drop grenade case 4 : { diff --git a/addons/grenades/script_component.hpp b/addons/grenades/script_component.hpp index 49dbe92a3f..3da453de6f 100644 --- a/addons/grenades/script_component.hpp +++ b/addons/grenades/script_component.hpp @@ -20,3 +20,5 @@ #define EFFECT_STAGE_DELETELIGHT 1 #define EFFECT_STAGE_PARTIALRECOVERY 2 #define EFFECT_STAGE_FULLRECOVERY 3 + +#define MIN_EXPLOSION_TIME_FOR_ROLL 1 diff --git a/addons/grenades/stringtable.xml b/addons/grenades/stringtable.xml index d5c1b142a6..ec009fa2ba 100644 --- a/addons/grenades/stringtable.xml +++ b/addons/grenades/stringtable.xml @@ -103,6 +103,9 @@ 下丟投擲 Bombayı Yere Bırak + + Can't roll this grenade, switched to %1 + M84 Stun Grenade M84 Blendgranate diff --git a/docs/wiki/feature/grenades.md b/docs/wiki/feature/grenades.md index 679b309b1e..2b60c08d4e 100644 --- a/docs/wiki/feature/grenades.md +++ b/docs/wiki/feature/grenades.md @@ -23,6 +23,8 @@ version: ### 1.1 Throw modes Provides different modes for throwing grenades (high throw, precision throw and drop mode). +A grenade is only rollable if the fuse time (`explosionTime`) is >= 1 second and the player isn't in a vehicle. + ### 1.2 Hand flares Adds throwable hand flares in the colors white, red, green and yellow. Additionally buffs existing flares by making them brighter and last longer. diff --git a/docs/wiki/framework/grenades-framework.md b/docs/wiki/framework/grenades-framework.md index 14c72e1cb5..755773c171 100644 --- a/docs/wiki/framework/grenades-framework.md +++ b/docs/wiki/framework/grenades-framework.md @@ -112,6 +112,12 @@ If set to zero or left undefined, the grenade is not treated as a flare. If it i Sets the color of the emitted light. The first 3 values of the array of the color, the last is the light intensity. +### 2.4 Grenade Rolling + +#### 2.4.1 ace_grenades_rollVectorDirAndUp + +Sets the `setVectorDirAndUp` of the grenade when the grenade is rolled. + ## 3. Events ### 3.1 Listenable From be61424fed5798d1d592bca06e0868500d3aa9d9 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 29 May 2024 17:40:32 +0200 Subject: [PATCH 055/290] Hearing - Fix volume being force updated when loadouts are set on AI (#10044) * Update XEH_preInit.sqf * Update XEH_preInit.sqf --- addons/hearing/XEH_preInit.sqf | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addons/hearing/XEH_preInit.sqf b/addons/hearing/XEH_preInit.sqf index 7a6195ec46..7a4ba739c1 100644 --- a/addons/hearing/XEH_preInit.sqf +++ b/addons/hearing/XEH_preInit.sqf @@ -13,7 +13,10 @@ PREP_RECOMPILE_END; if (_extendedInfo getOrDefault ["ace_earplugs", false]) then { _unit setVariable ["ACE_hasEarPlugsIn", true, true]; - [QGVAR(updateVolume), [[true]], _unit] call CBA_fnc_targetEvent; + // Only force update volume if unit is a player (including remote controlled) + if (_unit call EFUNC(common,isPlayer)) then { + [QGVAR(updateVolume), [[true]], _unit] call CBA_fnc_targetEvent; + }; }; }] call CBA_fnc_addEventHandler; From e535988479976f471663cc5ef137c58e220cfc33 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 29 May 2024 19:01:39 +0200 Subject: [PATCH 056/290] Hearing - Code cleanup (#10041) * Hearing cleanup * Update fnc_updateHearingProtection.sqf * Fixes + tweaks * Update initSettings.inc.sqf * Update fnc_removeEarplugs.sqf --- addons/hearing/CfgEventHandlers.hpp | 1 - addons/hearing/CfgVehicles.hpp | 4 +-- addons/hearing/CfgWeapons.hpp | 2 +- addons/hearing/XEH_PREP.hpp | 1 - addons/hearing/XEH_postInit.sqf | 24 ++++++++++---- addons/hearing/XEH_preInit.sqf | 4 ++- addons/hearing/functions/fnc_earRinging.sqf | 9 +++--- .../hearing/functions/fnc_explosionNear.sqf | 8 ++--- addons/hearing/functions/fnc_firedNear.sqf | 4 +-- .../hearing/functions/fnc_handleRespawn.sqf | 20 ++++++------ .../hearing/functions/fnc_hasEarPlugsIn.sqf | 7 ++-- .../hearing/functions/fnc_moduleHearing.sqf | 4 ++- .../hearing/functions/fnc_putInEarplugs.sqf | 25 +++++++-------- .../hearing/functions/fnc_removeEarplugs.sqf | 27 ++++++++-------- .../functions/fnc_updateHearingProtection.sqf | 32 ++++++++++++------- .../fnc_updatePlayerVehAttenuation.sqf | 14 ++++---- addons/hearing/functions/fnc_updateVolume.sqf | 31 ++++++++++-------- addons/hearing/initKeybinds.inc.sqf | 15 +++++---- addons/hearing/initSettings.inc.sqf | 23 +++++++------ 19 files changed, 146 insertions(+), 109 deletions(-) diff --git a/addons/hearing/CfgEventHandlers.hpp b/addons/hearing/CfgEventHandlers.hpp index 8143e2ce0d..59cd1b3629 100644 --- a/addons/hearing/CfgEventHandlers.hpp +++ b/addons/hearing/CfgEventHandlers.hpp @@ -1,4 +1,3 @@ - class Extended_PreStart_EventHandlers { class ADDON { init = QUOTE(call COMPILE_SCRIPT(XEH_preStart)); diff --git a/addons/hearing/CfgVehicles.hpp b/addons/hearing/CfgVehicles.hpp index a762534460..636184ecd2 100644 --- a/addons/hearing/CfgVehicles.hpp +++ b/addons/hearing/CfgVehicles.hpp @@ -5,7 +5,7 @@ class CfgVehicles { class ACE_Equipment { class ACE_PutInEarplugs { displayName = CSTRING(EarPlugs_On); - condition = QUOTE(GVAR(EnableCombatDeafness) && {!([_player] call FUNC(hasEarPlugsIn)) && {'ACE_EarPlugs' in items _player}}); + condition = QUOTE(GVAR(enableCombatDeafness) && {!(_player call FUNC(hasEarPlugsIn)) && {[ARR_2(_player,'ACE_EarPlugs')] call EFUNC(common,hasItem)}}); exceptions[] = {"isNotSwimming", "isNotInside", "isNotSitting"}; statement = QUOTE([ARR_2(_player,true)] call FUNC(putInEarPlugs)); showDisabled = 0; @@ -13,7 +13,7 @@ class CfgVehicles { }; class ACE_RemoveEarplugs { displayName = CSTRING(EarPlugs_Off); - condition = QUOTE(GVAR(EnableCombatDeafness) && {[_player] call FUNC(hasEarPlugsIn)}); + condition = QUOTE(GVAR(enableCombatDeafness) && {_player call FUNC(hasEarPlugsIn)}); exceptions[] = {"isNotSwimming", "isNotInside", "isNotSitting"}; statement = QUOTE([ARR_2(_player,true)] call FUNC(removeEarPlugs)); showDisabled = 0; diff --git a/addons/hearing/CfgWeapons.hpp b/addons/hearing/CfgWeapons.hpp index 23ebe5c1d2..8cef02edfd 100644 --- a/addons/hearing/CfgWeapons.hpp +++ b/addons/hearing/CfgWeapons.hpp @@ -80,7 +80,7 @@ class CfgWeapons { class H_HelmetO_ocamo: H_HelmetB { HEARING_PROTECTION_PELTOR; - }; // Defender and Assasin Helmet inherit. + }; // Defender and Assassin Helmet inherit. class H_HelmetO_ViperSP_hex_f: H_HelmetB { HEARING_PROTECTION_PELTOR; diff --git a/addons/hearing/XEH_PREP.hpp b/addons/hearing/XEH_PREP.hpp index 707c6bd96d..a2bcbb708a 100644 --- a/addons/hearing/XEH_PREP.hpp +++ b/addons/hearing/XEH_PREP.hpp @@ -1,4 +1,3 @@ - PREP(addEarPlugs); PREP(earRinging); PREP(explosionNear); diff --git a/addons/hearing/XEH_postInit.sqf b/addons/hearing/XEH_postInit.sqf index 4a2ca90992..4261933bd9 100644 --- a/addons/hearing/XEH_postInit.sqf +++ b/addons/hearing/XEH_postInit.sqf @@ -2,9 +2,10 @@ if (isServer) then { ["CBA_settingsInitialized", { - TRACE_1("settingInit - server",GVAR(EnableCombatDeafness)); + TRACE_1("settingInit - server",GVAR(enableCombatDeafness)); + // Only install event handler if combat deafness is enabled - if (!GVAR(EnableCombatDeafness)) exitWith {}; + if (!GVAR(enableCombatDeafness)) exitWith {}; ["CAManBase", "Init", LINKFUNC(addEarPlugs), true, [], true] call CBA_fnc_addClassEventHandler; }] call CBA_fnc_addEventHandler; @@ -26,18 +27,20 @@ GVAR(volumeAttenuation) = 1; GVAR(lastPlayerVehicle) = objNull; ["CBA_settingsInitialized", { - TRACE_1("settingInit",GVAR(EnableCombatDeafness)); + TRACE_1("settingInit",GVAR(enableCombatDeafness)); + // Only run PFEH and install event handlers if combat deafness is enabled - if (!GVAR(EnableCombatDeafness)) exitWith {}; + if (!GVAR(enableCombatDeafness)) exitWith {}; // Spawn volume updating process - [LINKFUNC(updateVolume), 1, [false]] call CBA_fnc_addPerFrameHandler; + [LINKFUNC(updateVolume), 1, false] call CBA_fnc_addPerFrameHandler; [QGVAR(updateVolume), LINKFUNC(updateVolume)] call CBA_fnc_addEventHandler; // Update veh attunation when player veh changes ["vehicle", { params ["_player", "_vehicle"]; + TRACE_2("vehicle change",_player,_vehicle); _this call FUNC(updatePlayerVehAttenuation); @@ -48,6 +51,7 @@ GVAR(lastPlayerVehicle) = objNull; GVAR(lastPlayerVehicle) = objNull; TRACE_2("removed veh eh",_firedEH,GVAR(lastPlayerVehicle)); }; + if ((!isNull _vehicle) && {_player != _vehicle}) then { private _firedEH = _vehicle addEventHandler ["FiredNear", {call FUNC(firedNear)}]; _vehicle setVariable [QGVAR(firedEH), _firedEH]; @@ -55,8 +59,8 @@ GVAR(lastPlayerVehicle) = objNull; TRACE_2("added veh eh",_firedEH,GVAR(lastPlayerVehicle)); }; }, true] call CBA_fnc_addPlayerEventHandler; - ["turret", LINKFUNC(updatePlayerVehAttenuation), false] call CBA_fnc_addPlayerEventHandler; + ["turret", LINKFUNC(updatePlayerVehAttenuation), false] call CBA_fnc_addPlayerEventHandler; // Reset deafness on respawn (or remote control player switch) ["unit", { @@ -67,9 +71,11 @@ GVAR(lastPlayerVehicle) = objNull; private _firedEH = _oldPlayer getVariable [QGVAR(firedEH), -1]; _oldPlayer removeEventHandler ["FiredNear", _firedEH]; _oldPlayer setVariable [QGVAR(firedEH), nil]; + private _explosionEH = _oldPlayer getVariable [QGVAR(explosionEH), -1]; _oldPlayer removeEventHandler ["Explosion", _explosionEH]; _oldPlayer setVariable [QGVAR(explosionEH), nil]; + TRACE_3("removed unit eh",_oldPlayer,_firedEH,_explosionEH); }; // Don't add a new EH if the unit respawned @@ -77,17 +83,21 @@ GVAR(lastPlayerVehicle) = objNull; if ((getNumber (configOf _player >> "isPlayableLogic")) == 1) exitWith { TRACE_1("skipping playable logic",typeOf _player); // VirtualMan_F (placeable logic zeus / spectator) }; + private _firedEH = _player addEventHandler ["FiredNear", {call FUNC(firedNear)}]; _player setVariable [QGVAR(firedEH), _firedEH]; + private _explosionEH = _player addEventHandler ["Explosion", {call FUNC(explosionNear)}]; _player setVariable [QGVAR(explosionEH), _explosionEH]; + TRACE_3("added unit eh",_player,_firedEH,_explosionEH); }; GVAR(deafnessDV) = 0; GVAR(deafnessPrior) = 0; GVAR(time3) = 0; - [] call FUNC(updateHearingProtection); + + call FUNC(updateHearingProtection); }, true] call CBA_fnc_addPlayerEventHandler; // Update protection on possible helmet change diff --git a/addons/hearing/XEH_preInit.sqf b/addons/hearing/XEH_preInit.sqf index 7a4ba739c1..e47eafa56e 100644 --- a/addons/hearing/XEH_preInit.sqf +++ b/addons/hearing/XEH_preInit.sqf @@ -10,18 +10,20 @@ PREP_RECOMPILE_END; ["CBA_loadoutSet", { params ["_unit", "_loadout", "_extendedInfo"]; + if (_extendedInfo getOrDefault ["ace_earplugs", false]) then { _unit setVariable ["ACE_hasEarPlugsIn", true, true]; // Only force update volume if unit is a player (including remote controlled) if (_unit call EFUNC(common,isPlayer)) then { - [QGVAR(updateVolume), [[true]], _unit] call CBA_fnc_targetEvent; + [QGVAR(updateVolume), true, _unit] call CBA_fnc_targetEvent; }; }; }] call CBA_fnc_addEventHandler; ["CBA_loadoutGet", { params ["_unit", "_loadout", "_extendedInfo"]; + if (_unit getVariable ["ACE_hasEarPlugsin", false]) then { _extendedInfo set ["ace_earplugs", true] }; diff --git a/addons/hearing/functions/fnc_earRinging.sqf b/addons/hearing/functions/fnc_earRinging.sqf index f5a2a714db..57888e90a2 100644 --- a/addons/hearing/functions/fnc_earRinging.sqf +++ b/addons/hearing/functions/fnc_earRinging.sqf @@ -1,24 +1,25 @@ #include "..\script_component.hpp" /* * Author: KoffeinFlummi, commy2, Rocko, Rommel, Ruthberg - * Handle new sound souce near ace_player and apply hearing damage + * Handle new sound souce near ace_player and apply hearing damage. * * Arguments: - * 0: strength of ear ringing + * 0: Strength of ear ringing * * Return Value: * None * * Example: - * [_strength] call ace_hearing_fnc_earRinging + * 10 call ace_hearing_fnc_earRinging * * Public: No */ + params ["_strength"]; if (_strength < 0.05) exitWith {}; if (!isNull curatorCamera) exitWith {}; -if ((!GVAR(enabledForZeusUnits)) && {player != ACE_player}) exitWith {}; +if (!GVAR(enabledForZeusUnits) && {player != ACE_player}) exitWith {}; TRACE_2("adding",_strength * GVAR(damageCoefficent),GVAR(deafnessDV)); diff --git a/addons/hearing/functions/fnc_explosionNear.sqf b/addons/hearing/functions/fnc_explosionNear.sqf index fd632947ac..583c55749e 100644 --- a/addons/hearing/functions/fnc_explosionNear.sqf +++ b/addons/hearing/functions/fnc_explosionNear.sqf @@ -4,8 +4,8 @@ * Handles deafness due to explosions going off near the player. * * Arguments: - * 0: vehicle - Object the event handler is assigned to (player) - * 1: damage - Damage inflicted to the object + * 0: Unit + * 1: Damage inflicted to the unit * * Return Value: * None @@ -22,5 +22,5 @@ TRACE_2("explosion near player",_unit,_damage); private _strength = (0 max _damage) * 30; -// Call inmediately, as it will get pick up later anyway by the update thread -[_strength] call FUNC(earRinging); +// Call immediately, as it will get picked up later by the update thread anyway +_strength call FUNC(earRinging); diff --git a/addons/hearing/functions/fnc_firedNear.sqf b/addons/hearing/functions/fnc_firedNear.sqf index 45364cc0b6..1c9a1c5496 100644 --- a/addons/hearing/functions/fnc_firedNear.sqf +++ b/addons/hearing/functions/fnc_firedNear.sqf @@ -59,5 +59,5 @@ private _strength = _vehAttenuation * (_loudness - (_loudness / 50 * _distance)) TRACE_1("result",_strength); -// Call inmediately, as it will get pick up later anyway by the update thread -[_strength] call FUNC(earRinging); +// Call immediately, as it will get picked up later by the update thread anyway +_strength call FUNC(earRinging); diff --git a/addons/hearing/functions/fnc_handleRespawn.sqf b/addons/hearing/functions/fnc_handleRespawn.sqf index b436aa7c41..a075d7901e 100644 --- a/addons/hearing/functions/fnc_handleRespawn.sqf +++ b/addons/hearing/functions/fnc_handleRespawn.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: PabstMirror - * Reset earplugs on respawn, and then re-add if appropriate + * Reset earplugs on respawn, and then re-add if appropriate. * * Arguments: * 0: Unit @@ -10,29 +10,29 @@ * None * * Example: - * [player] call ACE_hearing_fnc_handleRespawn; + * player call ace_hearing_fnc_handleRespawn; * * Public: No */ +// Do not add or remove earplugs if gear should be preserved +if (missionNamespace getVariable [QEGVAR(respawn,savePreDeathGear), false]) exitWith {}; + params ["_unit"]; TRACE_2("params",_unit,typeOf _unit); -if (!local _unit) exitWith {}; //XEH should only be called on local units - -//Do not add or remove earplugs if gear should be preserved -if (missionNamespace getVariable [QEGVAR(respawn,SavePreDeathGear), false]) exitWith {}; +if (!local _unit) exitWith {}; // XEH should only be called on local units private _respawn = [0] call BIS_fnc_missionRespawnType; -//if respawn is not Group or side: +// If respawn is not group or side: if (_respawn <= 3) then { - //Remove earplugs if they have them: + // Remove earplugs if they have them: if (_unit getVariable ["ACE_hasEarPlugsin", false]) then { TRACE_1("had EarPlugs in - removing",_unit); _unit setVariable ["ACE_hasEarPlugsin", false, true]; }; }; -//Re-add if they need them: -[_unit] call FUNC(addEarPlugs); +// Re-add if they need them +_unit call FUNC(addEarPlugs); diff --git a/addons/hearing/functions/fnc_hasEarPlugsIn.sqf b/addons/hearing/functions/fnc_hasEarPlugsIn.sqf index f4b84281fb..fd6682e4de 100644 --- a/addons/hearing/functions/fnc_hasEarPlugsIn.sqf +++ b/addons/hearing/functions/fnc_hasEarPlugsIn.sqf @@ -4,16 +4,17 @@ * Check if the unit has earplugs put in. * * Arguments: - * 0: Unit (player) + * 0: Unit * * Return Value: - * Have Earplugs in + * Has Earplugs in * * Example: - * [ace_player] call ace_hearing_fnc_hasEarPlugsIn + * player call ace_hearing_fnc_hasEarPlugsIn * * Public: No */ + params ["_unit"]; _unit getVariable ["ACE_hasEarPlugsin", false] diff --git a/addons/hearing/functions/fnc_moduleHearing.sqf b/addons/hearing/functions/fnc_moduleHearing.sqf index 924f2baa21..f7943a712e 100644 --- a/addons/hearing/functions/fnc_moduleHearing.sqf +++ b/addons/hearing/functions/fnc_moduleHearing.sqf @@ -10,7 +10,7 @@ * None * * Example: - * [player] call ACE_hearing_fnc_moduleHearing + * player call ace_hearing_fnc_moduleHearing * * Public: No */ @@ -23,6 +23,8 @@ params ["_logic"]; if ((_logic getVariable "DisableEarRinging") != -1) then { [_logic, QGVAR(DisableEarRinging), "DisableEarRinging"] call EFUNC(common,readSettingFromModule); }; + [_logic, QGVAR(enabledForZeusUnits), "enabledForZeusUnits"] call EFUNC(common,readSettingFromModule); [_logic, QGVAR(autoAddEarplugsToUnits), "autoAddEarplugsToUnits"] call EFUNC(common,readSettingFromModule); + INFO("Hearing Module Initialized."); diff --git a/addons/hearing/functions/fnc_putInEarplugs.sqf b/addons/hearing/functions/fnc_putInEarplugs.sqf index 2af4df8e86..aa2166a112 100644 --- a/addons/hearing/functions/fnc_putInEarplugs.sqf +++ b/addons/hearing/functions/fnc_putInEarplugs.sqf @@ -1,38 +1,35 @@ #include "..\script_component.hpp" /* - * Author: Hope Johnson and commy2 + * Author: Hope Johnson, commy2 * Puts in earplugs. * * Arguments: - * 0: Unit (player) + * 0: Unit * 1: Display hint (default: false) * * Return Value: * None * * Example: - * [ace_player, false] call ace_hearing_fnc_putInEarplugs + * [player, false] call ace_hearing_fnc_putInEarplugs * * Public: No */ -params ["_player", ["_displayHint", false, [false]]]; +if (!GVAR(enableCombatDeafness)) exitWith {}; -if (!GVAR(EnableCombatDeafness)) exitWith {}; +params ["_unit", ["_displayHint", false]]; // Plugs in inventory, putting them in -_player removeItem "ACE_EarPlugs"; +_unit removeItem "ACE_EarPlugs"; -_player setVariable ["ACE_hasEarPlugsIn", true, true]; +_unit setVariable ["ACE_hasEarPlugsIn", true, true]; if (_displayHint) then { - [localize LSTRING(EarPlugs_Are_On)] call EFUNC(common,displayTextStructured); + [LLSTRING(EarPlugs_Are_On)] call EFUNC(common,displayTextStructured); }; -//Force an immediate fast volume update: -[[true]] call FUNC(updateVolume); +// Force an immediate volume update +true call FUNC(updateVolume); -// No Earplugs in inventory, telling user -//[localize LSTRING(NoPlugs)] call EFUNC(common,displayTextStructured); - -[] call FUNC(updateHearingProtection); +call FUNC(updateHearingProtection); diff --git a/addons/hearing/functions/fnc_removeEarplugs.sqf b/addons/hearing/functions/fnc_removeEarplugs.sqf index 20a49bb530..743e89ef53 100644 --- a/addons/hearing/functions/fnc_removeEarplugs.sqf +++ b/addons/hearing/functions/fnc_removeEarplugs.sqf @@ -1,39 +1,40 @@ #include "..\script_component.hpp" /* - * Author: Hope Johnson and commy2 + * Author: Hope Johnson, commy2 * Takes out earplugs. * * Arguments: - * 0: Unit (player) - * 1: Display hint (default false) + * 0: Unit + * 1: Display hint (default: false) * * Return Value: * None * * Example: - * [ace_player, false] call ace_hearing_fnc_removeEarplugs + * [player, false] call ace_hearing_fnc_removeEarplugs * * Public: No */ -params ["_player", ["_displayHint", false, [false]]]; +if (!GVAR(enableCombatDeafness)) exitWith {}; -if (!GVAR(EnableCombatDeafness)) exitWith {}; +params ["_unit", ["_displayHint", false]]; -if !([_player, "ACE_EarPlugs"] call CBA_fnc_canAddItem) exitWith { // inventory full +// Inventory full +if !([_unit, "ACE_EarPlugs"] call CBA_fnc_canAddItem) exitWith { [LELSTRING(common,Inventory_Full)] call EFUNC(common,displayTextStructured); }; // Plugs already in and removing them. -_player addItem "ACE_EarPlugs"; +_unit addItem "ACE_EarPlugs"; -_player setVariable ["ACE_hasEarPlugsIn", false, true]; +_unit setVariable ["ACE_hasEarPlugsIn", false, true]; if (_displayHint) then { - [localize LSTRING(EarPlugs_Are_Off)] call EFUNC(common,displayTextStructured); + [LLSTRING(EarPlugs_Are_Off)] call EFUNC(common,displayTextStructured); }; -//Force an immediate fast volume update: -[[true]] call FUNC(updateVolume); +// Force an immediate volume update +true call FUNC(updateVolume); -[] call FUNC(updateHearingProtection); +call FUNC(updateHearingProtection); diff --git a/addons/hearing/functions/fnc_updateHearingProtection.sqf b/addons/hearing/functions/fnc_updateHearingProtection.sqf index 15973b73a9..b9d7f1f9a0 100644 --- a/addons/hearing/functions/fnc_updateHearingProtection.sqf +++ b/addons/hearing/functions/fnc_updateHearingProtection.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: PabstMirror - * Updates the hearing protection and volume attenuation for player on earbuds/helmet change + * Updates the hearing protection and volume attenuation for player on earbuds/helmet change. * * Arguments: * None @@ -10,12 +10,12 @@ * None * * Example: - * [] call ace_hearing_fnc_updateHearingProtection + * call ace_hearing_fnc_updateHearingProtection * * Public: No */ -TRACE_1("params",_this); +LOG("updateHearingProtection"); if (isNull ACE_player) exitWith { GVAR(damageCoefficent) = 0; @@ -23,22 +23,32 @@ if (isNull ACE_player) exitWith { }; // Handle Earplugs -private _hasEarPlugsIn = [ACE_player] call FUNC(hasEarPlugsIn); +private _hasEarPlugsIn = ACE_player call FUNC(hasEarPlugsIn); GVAR(damageCoefficent) = [1, 0.25] select _hasEarPlugsIn; -GVAR(volumeAttenuation) = [1, GVAR(EarplugsVolume)] select _hasEarPlugsIn; +GVAR(volumeAttenuation) = [1, GVAR(earplugsVolume)] select _hasEarPlugsIn; // Handle Headgear -if (headgear ACE_player != "") then { - private _protection = getNumber (configFile >> "CfgWeapons" >> headgear ACE_player >> QGVAR(protection)) min 1; +private _headgear = headgear ACE_player; + +if (_headgear != "") then { + private _heargearConfig = configFile >> "CfgWeapons" >> _headgear; + + private _protection = getNumber (_heargearConfig >> QGVAR(protection)) min 1; GVAR(damageCoefficent) = GVAR(damageCoefficent) * (1 - _protection); - private _attenuation = getNumber (configFile >> "CfgWeapons" >> headgear ACE_player >> QGVAR(lowerVolume)) min 1; + + private _attenuation = getNumber (_heargearConfig >> QGVAR(lowerVolume)) min 1; GVAR(volumeAttenuation) = GVAR(volumeAttenuation) * (1 - _attenuation); }; // Handle Goggles -if (goggles ACE_player != "") then { - private _protection = getNumber (configFile >> "CfgGlasses" >> goggles ACE_player >> QGVAR(protection)) min 1; +private _goggles = goggles ACE_player; + +if (_goggles != "") then { + private _gogglesConfig = configFile >> "CfgGlasses" >> _goggles; + + private _protection = getNumber (_gogglesConfig >> QGVAR(protection)) min 1; GVAR(damageCoefficent) = GVAR(damageCoefficent) * (1 - _protection); - private _attenuation = getNumber (configFile >> "CfgGlasses" >> goggles ACE_player >> QGVAR(lowerVolume)) min 1; + + private _attenuation = getNumber (_gogglesConfig >> QGVAR(lowerVolume)) min 1; GVAR(volumeAttenuation) = GVAR(volumeAttenuation) * (1 - _attenuation); }; diff --git a/addons/hearing/functions/fnc_updatePlayerVehAttenuation.sqf b/addons/hearing/functions/fnc_updatePlayerVehAttenuation.sqf index 207c0f07a3..856b694a3f 100644 --- a/addons/hearing/functions/fnc_updatePlayerVehAttenuation.sqf +++ b/addons/hearing/functions/fnc_updatePlayerVehAttenuation.sqf @@ -7,10 +7,10 @@ * None * * Return Value: - * Ammount that unit can hear outside + * Amount that unit can hear outside * * Example: - * [] call ace_hearing_fnc_updatePlayerVehAttenuation + * call ace_hearing_fnc_updatePlayerVehAttenuation * * Public: No */ @@ -20,12 +20,14 @@ private _vehicle = vehicle ACE_player; if (isNull _vehicle) exitWith {}; private _newAttenuation = 1; + if (ACE_player != _vehicle) then { - private _turretPath = [ACE_player] call EFUNC(common,getTurretIndex); - private _effectType = getText (configOf _vehicle >> "attenuationEffectType"); + private _vehicleConfig = configOf _vehicle; + private _turretPath = _vehicle unitTurret ACE_player; + private _effectType = getText (_vehicleConfig >> "attenuationEffectType"); if (_turretPath isNotEqualTo []) then { - private _turretConfig = [(configOf _vehicle), _turretPath] call EFUNC(common,getTurretConfigPath); + private _turretConfig = [_vehicleConfig, _turretPath] call EFUNC(common,getTurretConfigPath); if ((getNumber (_turretConfig >> "disableSoundAttenuation")) == 1) then { _effectType = ""; @@ -40,7 +42,7 @@ if (ACE_player != _vehicle) then { case (_effectType == ""): {1}; case (_effectType == "CarAttenuation"); case (_effectType == "RHS_CarAttenuation"): { // Increase protection for armored cars - private _armor = getNumber (configOf _vehicle >> "HitPoints" >> "HitBody" >> "armor"); + private _armor = getNumber (_vehicleConfig >> "HitPoints" >> "HitBody" >> "armor"); linearConversion [2, 8, _armor, 0.5, 0.3, true];}; case (_effectType == "OpenCarAttenuation"): {1}; case (_effectType == "TankAttenuation"): {0.1}; diff --git a/addons/hearing/functions/fnc_updateVolume.sqf b/addons/hearing/functions/fnc_updateVolume.sqf index 0029cdc4de..0a36367466 100644 --- a/addons/hearing/functions/fnc_updateVolume.sqf +++ b/addons/hearing/functions/fnc_updateVolume.sqf @@ -1,55 +1,60 @@ #include "..\script_component.hpp" /* - * Author: commy2 and esteldunedain and Ruthberg + * Author: commy2, esteldunedain, Ruthberg * Updates and applies the current deafness. Called every 1 sec from a PFEH. * * Arguments: - * 0: Args - * - 0: Just update volume (skip ringing/recovery) (default: false) + * 0: Update volume only (skip ringing/recovery) (default: false) * * Return Value: * None * * Example: - * [] call ace_hearing_fnc_updateVolume + * call ace_hearing_fnc_updateVolume * * Public: No */ if (!alive ACE_player) exitWith { - if (missionNameSpace getVariable [QGVAR(disableVolumeUpdate), false]) exitWith {}; + if (missionNamespace getVariable [QGVAR(disableVolumeUpdate), false]) exitWith {}; + TRACE_1("dead - removing hearing effects",ACE_player); + [QUOTE(ADDON), 1, true] call EFUNC(common,setHearingCapability); }; -(_this select 0) params [["_justUpdateVolume", false]]; +params [["_updateVolumeOnly", false]]; GVAR(deafnessDV) = (GVAR(deafnessDV) min 20) max 0; GVAR(volume) = (1 - (GVAR(deafnessDV) / 20)) max 0.05; + TRACE_3("",GVAR(volume),GVAR(deafnessDV),GVAR(deafnessDV) - GVAR(deafnessPrior)); -if (!_justUpdateVolume) then { +if (!_updateVolumeOnly) then { // Ring if we got a big increase in the last second or enough accumulated damage if (GVAR(deafnessDV) - GVAR(deafnessPrior) > 1 || GVAR(deafnessDV) > 10) then { if (CBA_missionTime - GVAR(time3) < 3) exitWith {}; + GVAR(time3) = CBA_missionTime; if (!isGameFocused) exitWith {}; + if (GVAR(deafnessDV) > 19.75) then { - playSound (["ACE_Combat_Deafness_Heavy", "ACE_Combat_Deafness_Heavy_NoRing"] select GVAR(DisableEarRinging)); + playSound (["ACE_Combat_Deafness_Heavy", "ACE_Combat_Deafness_Heavy_NoRing"] select GVAR(disableEarRinging)); } else { - playSound (["ACE_Combat_Deafness_Medium", "ACE_Combat_Deafness_Medium_NoRing"] select GVAR(DisableEarRinging)); + playSound (["ACE_Combat_Deafness_Medium", "ACE_Combat_Deafness_Medium_NoRing"] select GVAR(disableEarRinging)); }; }; + GVAR(deafnessPrior) = GVAR(deafnessDV); // Hearing takes longer to return to normal after it hits rock bottom - GVAR(deafnessDV) = (GVAR(deafnessDV) - (0.5 * (GVAR(volume) max 0.1))) max 0; + GVAR(deafnessDV) = (GVAR(deafnessDV) - (0.5 * (GVAR(volume) max 0.1))) max 0; }; -if (missionNameSpace getVariable [QGVAR(disableVolumeUpdate), false]) exitWith {}; +if (missionNamespace getVariable [QGVAR(disableVolumeUpdate), false]) exitWith {}; private _volume = GVAR(volume); @@ -57,8 +62,8 @@ private _volume = GVAR(volume); _volume = _volume min GVAR(volumeAttenuation); // Reduce volume if player is unconscious -if (ACE_player getVariable ["ACE_isUnconscious", false]) then { - _volume = _volume min GVAR(UnconsciousnessVolume); +if (lifeState ACE_player == "INCAPACITATED") then { + _volume = _volume min GVAR(unconsciousnessVolume); }; [QUOTE(ADDON), _volume, true] call EFUNC(common,setHearingCapability); diff --git a/addons/hearing/initKeybinds.inc.sqf b/addons/hearing/initKeybinds.inc.sqf index 22cf132add..d129966198 100644 --- a/addons/hearing/initKeybinds.inc.sqf +++ b/addons/hearing/initKeybinds.inc.sqf @@ -2,14 +2,17 @@ // Conditions: specific if !([ACE_player, objNull, ["isNotSwimming", "isNotInside", "isNotSitting"]] call EFUNC(common,canInteractWith)) exitWith {false}; - if (GVAR(EnableCombatDeafness) && {!([ACE_player] call FUNC(hasEarPlugsIn))} && {[ACE_player, "ACE_EarPlugs"] call EFUNC(common,hasItem)}) exitWith { + if (GVAR(enableCombatDeafness) && {!(ACE_player call FUNC(hasEarPlugsIn))} && {[ACE_player, "ACE_EarPlugs"] call EFUNC(common,hasItem)}) exitWith { [ACE_player, true] call FUNC(putInEarPlugs); - true + + true // return }; - if (GVAR(EnableCombatDeafness) && {[ACE_player] call FUNC(hasEarPlugsIn)}) exitWith { + + if (GVAR(enableCombatDeafness) && {ACE_player call FUNC(hasEarPlugsIn)}) exitWith { [ACE_player, true] call FUNC(removeEarPlugs); - true + + true // return }; - - false + + false // return }] call CBA_fnc_addKeybind; // UNBOUND diff --git a/addons/hearing/initSettings.inc.sqf b/addons/hearing/initSettings.inc.sqf index 61b6d239c5..adc6c6def7 100644 --- a/addons/hearing/initSettings.inc.sqf +++ b/addons/hearing/initSettings.inc.sqf @@ -1,7 +1,8 @@ -private _category = format ["ACE %1", localize LSTRING(Module_DisplayName)]; +private _category = format ["ACE %1", LLSTRING(Module_DisplayName)]; [ - QGVAR(enableCombatDeafness), "CHECKBOX", + QGVAR(enableCombatDeafness), + "CHECKBOX", [LSTRING(EnableCombatDeafness_DisplayName), LSTRING(EnableCombatDeafness_Description)], _category, true, @@ -11,7 +12,8 @@ private _category = format ["ACE %1", localize LSTRING(Module_DisplayName)]; ] call CBA_fnc_addSetting; [ - QGVAR(earplugsVolume), "SLIDER", + QGVAR(earplugsVolume), + "SLIDER", [LSTRING(earplugsVolume_DisplayName), LSTRING(earplugsVolume_Description)], _category, [0, 1, 0.5, 1], @@ -19,7 +21,8 @@ private _category = format ["ACE %1", localize LSTRING(Module_DisplayName)]; ] call CBA_fnc_addSetting; [ - QGVAR(unconsciousnessVolume), "SLIDER", + QGVAR(unconsciousnessVolume), + "SLIDER", [LSTRING(unconsciousnessVolume_DisplayName), LSTRING(unconsciousnessVolume_Description)], _category, [0, 1, 0.4, 1], @@ -27,15 +30,16 @@ private _category = format ["ACE %1", localize LSTRING(Module_DisplayName)]; ] call CBA_fnc_addSetting; [ - QGVAR(disableEarRinging), "CHECKBOX", + QGVAR(disableEarRinging), + "CHECKBOX", [LSTRING(DisableEarRinging_DisplayName), LSTRING(DisableEarRinging_Description)], _category, - false, - 0 + false ] call CBA_fnc_addSetting; [ - QGVAR(enabledForZeusUnits), "CHECKBOX", + QGVAR(enabledForZeusUnits), + "CHECKBOX", [LSTRING(enabledForZeusUnits_DisplayName), LSTRING(enabledForZeusUnits_Description)], _category, true, @@ -43,7 +47,8 @@ private _category = format ["ACE %1", localize LSTRING(Module_DisplayName)]; ] call CBA_fnc_addSetting; [ - QGVAR(autoAddEarplugsToUnits), "LIST", + QGVAR(autoAddEarplugsToUnits), + "LIST", [LSTRING(autoAddEarplugsToUnits_DisplayName), LSTRING(autoAddEarplugsToUnits_Description)], _category, [[0, 1, 2], [ELSTRING(common,Disabled), LSTRING(heavyWeaponUnits), ELSTRING(common,Enabled)], 1], From 0034f4b9cca428232ef62e7d00311a6021e08b6b Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 29 May 2024 20:40:41 +0200 Subject: [PATCH 057/290] Arsenal - Fix insignia not reapplying after switching vests & backpacks (#10046) Fix insignia not reapplying --- addons/arsenal/functions/fnc_onSelChangedLeft.sqf | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/addons/arsenal/functions/fnc_onSelChangedLeft.sqf b/addons/arsenal/functions/fnc_onSelChangedLeft.sqf index 5bf08245c8..e25016b303 100644 --- a/addons/arsenal/functions/fnc_onSelChangedLeft.sqf +++ b/addons/arsenal/functions/fnc_onSelChangedLeft.sqf @@ -382,6 +382,9 @@ switch (GVAR(currentLeftPanel)) do { }; GVAR(currentItems) set [IDX_CURR_VEST, _item]; + + [GVAR(center), ""] call BIS_fnc_setUnitInsignia; + [GVAR(center), GVAR(currentInsignia)] call BIS_fnc_setUnitInsignia; }; TOGGLE_RIGHT_PANEL_CONTAINER @@ -420,6 +423,9 @@ switch (GVAR(currentLeftPanel)) do { }; GVAR(currentItems) set [IDX_CURR_BACKPACK, _item]; + + [GVAR(center), ""] call BIS_fnc_setUnitInsignia; + [GVAR(center), GVAR(currentInsignia)] call BIS_fnc_setUnitInsignia; }; TOGGLE_RIGHT_PANEL_CONTAINER From 440b9d572185ea9a5a3bd842d911ac7635876b3e Mon Sep 17 00:00:00 2001 From: mharis001 <34453221+mharis001@users.noreply.github.com> Date: Wed, 29 May 2024 14:48:34 -0400 Subject: [PATCH 058/290] Zeus - Add spectator module (#6202) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ozan Eğitmen Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- addons/zeus/CfgVehicles.hpp | 6 + addons/zeus/XEH_PREP.hpp | 2 + addons/zeus/XEH_postInit.sqf | 1 + addons/zeus/config.cpp | 6 + addons/zeus/functions/fnc_moduleSpectator.sqf | 39 +++ addons/zeus/functions/fnc_ui_spectator.sqf | 265 ++++++++++++++++++ addons/zeus/stringtable.xml | 24 ++ addons/zeus/ui/RscAttributes.hpp | 228 +++++++++++++++ 8 files changed, 571 insertions(+) create mode 100644 addons/zeus/functions/fnc_moduleSpectator.sqf create mode 100644 addons/zeus/functions/fnc_ui_spectator.sqf diff --git a/addons/zeus/CfgVehicles.hpp b/addons/zeus/CfgVehicles.hpp index 2a1f261125..5fb4a4f61a 100644 --- a/addons/zeus/CfgVehicles.hpp +++ b/addons/zeus/CfgVehicles.hpp @@ -256,6 +256,12 @@ class CfgVehicles { displayName = CSTRING(ModuleSimulation_DisplayName); function = QFUNC(moduleSimulation); }; + class GVAR(moduleSpectator): GVAR(moduleBase) { + curatorCanAttach = 1; + category = QGVAR(Utility); + displayName = ECSTRING(spectator,Module_DisplayName); + curatorInfoType = QGVAR(RscSpectator); + }; class GVAR(moduleSuicideBomber): GVAR(moduleBase) { curatorCanAttach = 1; category = QGVAR(AI); diff --git a/addons/zeus/XEH_PREP.hpp b/addons/zeus/XEH_PREP.hpp index 8de15147bd..69dd7b18a6 100644 --- a/addons/zeus/XEH_PREP.hpp +++ b/addons/zeus/XEH_PREP.hpp @@ -34,6 +34,7 @@ PREP(moduleSetMedicalVehicle); PREP(moduleSetRepairFacility); PREP(moduleSetRepairVehicle); PREP(moduleSimulation); +PREP(moduleSpectator); PREP(moduleSuicideBomber); PREP(moduleSuppressiveFire); PREP(moduleSuppressiveFireLocal); @@ -56,6 +57,7 @@ PREP(ui_groupSide); PREP(ui_patrolArea); PREP(ui_searchArea); PREP(ui_setEngineer); +PREP(ui_spectator); PREP(ui_suicideBomber); PREP(ui_teleportPlayers); PREP(ui_toggleFlashlight); diff --git a/addons/zeus/XEH_postInit.sqf b/addons/zeus/XEH_postInit.sqf index b4d1302ab5..15b4c15f76 100644 --- a/addons/zeus/XEH_postInit.sqf +++ b/addons/zeus/XEH_postInit.sqf @@ -11,6 +11,7 @@ QGVAR(GlobalSkillAI) addPublicVariableEventHandler FUNC(moduleGlobalSetSkill); [QGVAR(moduleSearchNearby), CBA_fnc_searchNearby] call CBA_fnc_addEventHandler; [QGVAR(moduleSearchArea), CBA_fnc_taskSearchArea] call CBA_fnc_addEventHandler; [QGVAR(suppressiveFire), LINKFUNC(moduleSuppressiveFireLocal)] call CBA_fnc_addEventHandler; +[QGVAR(moduleSpectator), LINKFUNC(moduleSpectator)] call CBA_fnc_addEventHandler; // Editable object commands must be ran on server, this events are used in the respective module if (isServer) then { diff --git a/addons/zeus/config.cpp b/addons/zeus/config.cpp index 2714c247b0..d90c906294 100644 --- a/addons/zeus/config.cpp +++ b/addons/zeus/config.cpp @@ -99,6 +99,11 @@ class CfgPatches { QGVAR(moduleLayTrench) }; }; + class GVAR(spectator): ADDON { + units[] = { + QGVAR(moduleSpectator) + }; + }; }; class ACE_Curator { @@ -112,6 +117,7 @@ class ACE_Curator { GVAR(arsenal) = "ace_arsenal"; GVAR(fire) = "ace_fire"; GVAR(trenches) = "ace_trenches"; + GVAR(spectator) = "ace_spectator"; }; #include "CfgFactionClasses.hpp" diff --git a/addons/zeus/functions/fnc_moduleSpectator.sqf b/addons/zeus/functions/fnc_moduleSpectator.sqf new file mode 100644 index 0000000000..fb9ca2a63b --- /dev/null +++ b/addons/zeus/functions/fnc_moduleSpectator.sqf @@ -0,0 +1,39 @@ +#include "..\script_component.hpp" +/* + * Author: mharis001 + * Zeus module function to make the local player an ACE Spectator. + * + * Arguments: + * 0: Force interface + * 1: Hide player + * 2: Sides available to spectate + * 3: Camera modes available + * 4: Vision modes available + * + * Return Value: + * None + * + * Example: + * [true, true, [west], [0, 1, 2], [-2, -1, 0, 1]] call ace_zeus_fnc_moduleSpectator + * + * Public: No + */ + +params ["_force", "_hide", "_sides", "_modes", "_visions"]; +TRACE_1("params",_this); + +// Update sides available to spectate +[_sides, [west, east, independent, civilian] - _sides] call EFUNC(spectator,updateSides); + +// Update available camera modes +[_modes, [0, 1, 2] - _modes] call EFUNC(spectator,updateCameraModes); + +// Update available vision modes +[_visions, [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7] - _visions] call EFUNC(spectator,updateVisionModes); + +// Make unit spectator (close Zeus camera if open) +if (!isNull curatorCamera) then { + (findDisplay 312) closeDisplay 2; +}; + +[true, _force, _hide] call EFUNC(spectator,setSpectator); diff --git a/addons/zeus/functions/fnc_ui_spectator.sqf b/addons/zeus/functions/fnc_ui_spectator.sqf new file mode 100644 index 0000000000..fe9b4a3668 --- /dev/null +++ b/addons/zeus/functions/fnc_ui_spectator.sqf @@ -0,0 +1,265 @@ +#include "..\script_component.hpp" +/* + * Author: mharis001 + * Initializes the "Spectator" Zeus module display. + * + * Arguments: + * 0: spectator controls group + * + * Return Value: + * None + * + * Example: + * [CONTROL] call ace_zeus_fnc_ui_spectator + * + * Public: No + */ + +#define SIDE_IDCs [92540, 92541, 92542, 92543] +#define CAMERA_IDCs [92550, 92551, 92552] +#define VISION_IDCs [92558, 92559, 92560, 92561] + +params ["_control"]; + +private _display = ctrlParent _control; +private _ctrlButtonOK = _display displayCtrl 1; // IDC_OK +private _logic = missionNamespace getVariable ["BIS_fnc_initCuratorAttributes_target", objNull]; +TRACE_1("Logic Object",_logic); + +_control ctrlRemoveAllEventHandlers "SetFocus"; + +// Validate module target +private _unit = attachedTo _logic; +TRACE_1("Unit",_unit); + +scopeName "Main"; +private _fnc_errorAndClose = { + params ["_msg"]; + _display closeDisplay 0; + deleteVehicle _logic; + [_msg] call FUNC(showMessage); + breakOut "Main"; +}; + +switch (false) do { + case (["ace_spectator"] call EFUNC(common,isModLoaded)): { + [LSTRING(RequiresAddon)] call _fnc_errorAndClose; + }; + case (!isNull _unit): { + [LSTRING(NothingSelected)] call _fnc_errorAndClose; + }; + case (_unit isKindOf "CAManBase"): { + [LSTRING(OnlyInfantry)] call _fnc_errorAndClose; + }; + case (alive _unit): { + [LSTRING(OnlyAlive)] call _fnc_errorAndClose; + }; + case ([_unit, true] call EFUNC(common,isPlayer)): { + [LSTRING(OnlyPlayers)] call _fnc_errorAndClose; + }; +}; + +// Specific onLoad stuff +private _side = side _unit; + +// Spectate sides +private _fnc_onSideSelection = { + params ["_ctrl"]; + + private _display = ctrlParent _ctrl; + if (isNull _display) exitWith {}; + + private _color = _ctrl getVariable "color"; + private _scale = 1; + + private _sides = _display getVariable [QGVAR(spectateSides), []]; + private _selectedSide = (ctrlIDC _ctrl) - 92540; + + // Add or remove from spectatable sides and update color and scale + if (_selectedSide in _sides) then { + _display setVariable [QGVAR(spectateSides), _sides - [_selectedSide]]; + _color set [3, 0.5]; + } else { + _display setVariable [QGVAR(spectateSides), _sides + [_selectedSide]]; + _color set [3, 1]; + _scale = 1.2; + }; + + _ctrl ctrlSetTextColor _color; + [_ctrl, _scale, 0.1] call BIS_fnc_ctrlSetScale; +}; + +// Use the unit's side as default +private _activeSide = [east, west, independent, civilian] find _side; + +// Handle sides other than default four (sideEnemy) +if (_activeSide != -1) then { + _display setVariable [QGVAR(spectateSides), [_activeSide]]; +}; + +{ + private _ctrl = _display displayCtrl _x; + private _side = _x - 92540; + private _color = [_side] call BIS_fnc_sideColor; + _ctrl setVariable ["color", _color]; + _ctrl ctrlSetActiveColor _color; + _color set [3, 0.5]; + + if (_side == _activeSide) then { + [_ctrl, 1.2, 0] call BIS_fnc_ctrlSetScale; + _color set [3, 1]; + }; + + _ctrl ctrlSetTextColor _color; + + _ctrl ctrlAddEventHandler ["ButtonClick", _fnc_onSideSelection]; +} forEach SIDE_IDCs; + +// Camera modes +private _fnc_onModesSelection = { + params ["_ctrl"]; + + private _display = ctrlParent _ctrl; + if (isNull _display) exitWith {}; + + private _color = [1, 1, 1, 0.5]; + private _scale = 1; + + private _modes = _display getVariable [QGVAR(cameraModes), []]; + private _selectedMode = (ctrlIDC _ctrl) - 92550; + + // Add or remove from camera modes and update color and scale + if (_selectedMode in _modes) then { + _display setVariable [QGVAR(cameraModes), _modes - [_selectedMode]]; + } else { + _display setVariable [QGVAR(cameraModes), _modes + [_selectedMode]]; + _color set [3, 1]; + _scale = 1.2; + }; + + _ctrl ctrlSetTextColor _color; + [_ctrl, _scale, 0.1] call BIS_fnc_ctrlSetScale; +}; + +// Use setting as default since global variable will change +private _availableModes = [[0, 1, 2], [1, 2], [0], [1], [2]] select EGVAR(spectator,restrictModes); +_display setVariable [QGVAR(cameraModes), _availableModes]; + +{ + private _ctrl = _display displayCtrl _x; + private _color = [1, 1, 1, 0.5]; + + if ((_x - 92550) in _availableModes) then { + [_ctrl, 1.2, 0] call BIS_fnc_ctrlSetScale; + _color set [3, 1]; + }; + + _ctrl ctrlSetTextColor _color; + + _ctrl ctrlAddEventHandler ["ButtonClick", _fnc_onModesSelection]; +} forEach CAMERA_IDCs; + +// Vision Modes +private _fnc_onVisionSelection = { + params ["_ctrl", "_state"]; + + private _display = ctrlParent _ctrl; + if (isNull _display) exitwith {}; + + // Convert to boolean since EH returns state as 0 or 1 + private _state = [false, true] select _state; + + private _visions = _display getVariable [QGVAR(visionModes), []]; + private _selectedVision = (ctrlIDC _ctrl) - 92560; + + // Add or remove from vision modes + if (_state) then { + _display setVariable [QGVAR(visionModes), _visions + [_selectedVision]]; + } else { + _display setVariable [QGVAR(visionModes), _visions - [_selectedVision]]; + }; + + // Handle all checked/unchecked + private _allCheckboxes = VISION_IDCs apply {cbChecked (_display displayCtrl _x)}; + + if (_allCheckboxes isEqualTo [_state, _state, _state, _state]) then { + (_display displayCtrl 92557) cbSetChecked _state; + }; +}; + +// Use setting as default since global variable will change +private _availableVisions = [[-2,-1,0,1], [-2,-1], [-2,0,1], [-2]] select EGVAR(spectator,restrictVisions); +_display setVariable [QGVAR(visionModes), _availableVisions]; + +{ + private _ctrl = _display displayCtrl _x; + + if ((_x - 92560) in _availableVisions) then { + _ctrl cbSetChecked true; + }; + + _ctrl ctrlAddEventHandler ["CheckedChanged", _fnc_onVisionSelection]; +} forEach VISION_IDCs; + +// Init all visions checkbox +private _fnc_onVisionsAll = { + params ["_ctrl", "_state"]; + + private _display = ctrlParent _ctrl; + if (isNull _display) exitWith {}; + + // Convert to boolean since EH returns state as 0 or 1 + _state = _state == 1; + + // Set state of all checkboxes + { + (_display displayCtrl _x) cbSetChecked _state; + } forEach VISION_IDCs; + + // Store new visions mode setting + private _setting = [[], [-2, -1, 0, 1]] select _state; + _display setVariable [QGVAR(visionModes), _setting]; +}; + +private _allCheckbox = _display displayCtrl 92557; + +// Set to checked by default if setting is all vision modes +if (_availableVisions isEqualTo [-2, -1, 0, 1]) then { + _allCheckbox cbSetChecked true; +}; + +_allCheckbox ctrlAddEventHandler ["CheckedChanged", _fnc_onVisionsAll]; + +// Confirm and Cancel +private _fnc_onUnload = { + private _logic = missionNamespace getVariable ["BIS_fnc_initCuratorAttributes_target", objNull]; + if (isNull _logic) exitWith {}; + + deleteVehicle _logic; +}; + +private _fnc_onConfirm = { + params [["_ctrlButtonOK", controlNull, [controlNull]]]; + + private _display = ctrlParent _ctrlButtonOK; + if (isNull _display) exitWith {}; + + private _logic = missionNamespace getVariable ["BIS_fnc_initCuratorAttributes_target", objNull]; + if (isNull _logic) exitWith {}; + + private _unit = attachedTo _logic; + if (isNull _unit) exitWith {}; + + private _force = lbCurSel (_display displayCtrl 92531) > 0; + private _hide = lbCurSel (_display displayCtrl 92532) > 0; + private _sides = (_display getVariable [QGVAR(spectateSides), []]) apply {_x call BIS_fnc_sideType}; + private _modes = _display getVariable [QGVAR(cameraModes), []]; + private _visions = _display getVariable [QGVAR(visionModes), []]; + + [QGVAR(moduleSpectator), [_force, _hide, _sides, _modes, _visions], _unit] call CBA_fnc_targetEvent; + + deleteVehicle _logic; +}; + +_display displayAddEventHandler ["Unload", _fnc_onUnload]; +_ctrlButtonOK ctrlAddEventHandler ["ButtonClick", _fnc_onConfirm]; diff --git a/addons/zeus/stringtable.xml b/addons/zeus/stringtable.xml index 329a0a3bd7..4ad75cefdc 100644 --- a/addons/zeus/stringtable.xml +++ b/addons/zeus/stringtable.xml @@ -1097,6 +1097,9 @@ 需要一個不存在的插件 현재 없는 애드온을 필요로 합니다 + + Only Players + None Keiner @@ -1993,5 +1996,26 @@ +SHIFT на принудительное (может укладываться только на Север/Юг или Восток/Запад) +SHIFT para forzar (Puede solo colocar en N/S or E/O) + + Forces the spectator interface preventing the player from closing it with the Escape key + + + Hide player + + + Hides the player by making them invisible, invulnerable, muted, and removing them from their group + + + Sets the sides that are available to spectate + + + White Hot + + + Black Hot + + + Toggle All + diff --git a/addons/zeus/ui/RscAttributes.hpp b/addons/zeus/ui/RscAttributes.hpp index 0ff21b145f..da3f53364f 100644 --- a/addons/zeus/ui/RscAttributes.hpp +++ b/addons/zeus/ui/RscAttributes.hpp @@ -915,3 +915,231 @@ class GVAR(RscSuicideBomber): RscDisplayAttributes { class ButtonCancel: ButtonCancel {}; }; }; + +class GVAR(RscSpectator): RscDisplayAttributes { + onLoad = QUOTE([ARR_3('onLoad',_this,QQGVAR(RscSpectator))] call FUNC(zeusAttributes)); + onUnload = QUOTE([ARR_3('onUnload',_this,QQGVAR(RscSpectator))] call FUNC(zeusAttributes)); + class Controls: Controls { + class Background: Background {}; + class Title: Title {}; + class Content: Content { + class Controls { + class spectator: RscControlsGroupNoScrollbars { + onSetFocus = QUOTE(_this call FUNC(ui_spectator)); + idc = 92530; + x = 0; + y = 0; + w = QUOTE(W_PART(26)); + h = QUOTE(H_PART(10.7)); + class controls { + class ForceInterfaceLabel: RscText { + idc = -1; + text = "$STR_a3_cfgvehicles_modulecurator_f_arguments_forced"; + tooltip = CSTRING(ModuleSpectator_ForceInterface_Tooltip); + x = 0; + y = 0; + w = QUOTE(W_PART(10)); + h = QUOTE(H_PART(1)); + colorBackground[] = {0, 0, 0, 0.5}; + }; + class ForceInterface: ctrlToolbox { + idc = 92531; + x = QUOTE(W_PART(10.1)); + y = 0; + w = QUOTE(W_PART(15.9)); + h = QUOTE(H_PART(1)); + rows = 1; + columns = 2; + strings[] = {ECSTRING(common,No), ECSTRING(common,Yes)}; + }; + class HidePlayerLabel: ForceInterfaceLabel { + text = CSTRING(ModuleSpectator_HidePlayer); + tooltip = CSTRING(ModuleSpectator_HidePlayer_Tooltip); + y = QUOTE(H_PART(1.1)); + }; + class HidePlayer: ForceInterface { + idc = 92532; + y = QUOTE(H_PART(1.1)); + }; + class SpectateSides: RscControlsGroupNoScrollbars { + idc = 92533; + x = 0; + y = QUOTE(H_PART(2.2)); + w = QUOTE(W_PART(26)); + h = QUOTE(H_PART(2.5)); + class controls { + class Label: RscText { + idc = -1; + text = "$STR_A3_Spectator_Eden_WhitelistedSides_Name"; + tooltip = CSTRING(ModuleSpectator_SpectableSides_Tooltip); + x = 0; + y = 0; + w = QUOTE(W_PART(10)); + h = QUOTE(H_PART(2.5)); + colorBackground[] = {0, 0, 0, 0.5}; + }; + class Background: RscText { + idc = -1; + x = QUOTE(W_PART(10)); + y = 0; + w = QUOTE(W_PART(16)); + h = QUOTE(H_PART(2.5)); + colorBackground[] = {1, 1, 1, 0.1}; + }; + class BLUFOR: RscActivePicture { + idc = 92541; + text = "\a3\Ui_F_Curator\Data\Displays\RscDisplayCurator\side_west_ca.paa"; + x = QUOTE(W_PART(12.5)); + y = QUOTE(H_PART(0.25)); + w = QUOTE(W_PART(2)); + h = QUOTE(H_PART(2)); + tooltip = "$STR_WEST"; + }; + class OPFOR: BLUFOR { + idc = 92540; + text = "\a3\Ui_F_Curator\Data\Displays\RscDisplayCurator\side_east_ca.paa"; + x = QUOTE(W_PART(15.5)); + tooltip = "$STR_EAST"; + }; + class Independent: BLUFOR { + idc = 92542; + text = "\a3\Ui_F_Curator\Data\Displays\RscDisplayCurator\side_guer_ca.paa"; + x = QUOTE(W_PART(18.5)); + tooltip = "$STR_guerrila"; + }; + class Civilian: BLUFOR { + idc = 92543; + text = "\a3\Ui_F_Curator\Data\Displays\RscDisplayCurator\side_civ_ca.paa"; + x = QUOTE(W_PART(21.5)); + tooltip = "$STR_Civilian"; + }; + }; + }; + class CameraModes: RscControlsGroupNoScrollbars { + idc = 92534; + x = 0; + y = QUOTE(H_PART(4.8)); + w = QUOTE(W_PART(26)); + h = QUOTE(H_PART(2.5)); + class controls { + class Label: RscText { + idc = -1; + text = ECSTRING(spectator,modes_DisplayName); + tooltip = ECSTRING(spectator,modes_Description); + x = 0; + y = 0; + w = QUOTE(W_PART(10)); + h = QUOTE(H_PART(2.5)); + colorBackground[] = {0, 0, 0, 0.5}; + }; + class Background: RscText { + idc = -1; + x =QUOTE(W_PART(10)); + y = 0; + w = QUOTE(W_PART(16)); + h = QUOTE(H_PART(2.5)); + colorBackground[] = {1, 1, 1, 0.1}; + }; + class Free: RscActivePicture { + idc = 92550; + text = "a3\Ui_f\data\GUI\Rsc\RscDisplayEGSpectator\Free.paa"; + x = QUOTE(W_PART(13.375)); + y = QUOTE(H_PART(0.375)); + w = QUOTE(W_PART(1.75)); + h = QUOTE(H_PART(1.75)); + tooltip = "$STR_A3_Spectator_free_camera_tooltip"; + }; + class Follow: Free { + idc = 92552; + text = "a3\Ui_f\data\GUI\Rsc\RscDisplayEGSpectator\Follow.paa"; + x = QUOTE(W_PART(17.125)); + tooltip = "$STR_A3_Spectator_3pp_camera_tooltip"; + }; + class FirstPerson: Free { + idc = 92551; + text = "a3\Ui_f\data\GUI\Rsc\RscDisplayEGSpectator\Fps.paa"; + x = QUOTE(W_PART(20.875)); + tooltip = "$STR_A3_Spectator_1pp_camera_tooltip"; + }; + }; + }; + class VisionModes: RscControlsGroupNoScrollbars { + idc = 92535; + x = 0; + y = QUOTE(H_PART(7.4)); + w = QUOTE(W_PART(26)); + h = QUOTE(H_PART(3.3)); + class controls { + class Label: RscText { + idc = -1; + text = ECSTRING(spectator,visions_DisplayName); + tooltip = ECSTRING(spectator,visions_Description); + x = 0; + y = 0; + w = QUOTE(W_PART(26)); + h = QUOTE(H_PART(1)); + colorBackground[] = {0, 0, 0, 0.5}; + }; + class Background: RscText { + idc = -1; + x = 0; + y = QUOTE(H_PART(1)); + w = QUOTE(W_PART(26)); + h = QUOTE(H_PART(2.3)); + colorBackground[] = {1, 1, 1, 0.1}; + }; + class AllCheckBox: RscCheckBox { + idc = 92557; + tooltip = CSTRING(ToggleAll); + x = QUOTE(W_PART(25)); + y = 0; + w = QUOTE(W_PART(1)); + h = QUOTE(H_PART(1)); + }; + class NormalLabel: Label { + text = "$STR_speed_normal"; + tooltip = ""; + x = QUOTE(W_PART(1)); + y = QUOTE(H_PART(1.1)); + w = QUOTE(W_PART(10.8)); + colorBackground[] = {0, 0, 0, 0.6}; + }; + class Normal: AllCheckBox { + idc = 92558; + x = QUOTE(W_PART(11.9)); + y = QUOTE(H_PART(1.1)); + }; + class NightVisionLabel: NormalLabel { + text = "$STR_usract_night_vision"; + y = QUOTE(H_PART(2.2)); + }; + class NightVision: Normal { + idc = 92559; + y = QUOTE(H_PART(2.2)); + }; + class WhiteHotLabel: NormalLabel { + text = CSTRING(ModuleSpectator_WhiteHot); + x = QUOTE(W_PART(13.1)); + }; + class WhiteHot: Normal { + idc = 92560; + x = QUOTE(W_PART(24)); + }; + class BlackHotLabel: WhiteHotLabel { + text = CSTRING(ModuleSpectator_BlackHot); + y = QUOTE(Y_PART(2.2)); + }; + class BlackHot: WhiteHot { + idc = 92561; + y = QUOTE(H_PART(2.2)); + }; + }; + }; + }; + }; + }; + }; + class ButtonOK: ButtonOK {}; + class ButtonCancel: ButtonCancel {}; + }; +}; From 120589512eb5ab478e557671789df73ee913d50a Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 29 May 2024 20:49:59 +0200 Subject: [PATCH 059/290] Headless - Improve group transfer and add API (#9874) --- addons/headless/XEH_PREP.hpp | 1 + addons/headless/XEH_postInit.sqf | 15 ++ addons/headless/functions/fnc_blacklist.sqf | 51 +++++ .../headless/functions/fnc_transferGroups.sqf | 184 ++++++++++++------ addons/headless/script_component.hpp | 4 + docs/wiki/framework/events-framework.md | 10 +- docs/wiki/framework/headless-framework.md | 23 ++- 7 files changed, 227 insertions(+), 61 deletions(-) create mode 100644 addons/headless/functions/fnc_blacklist.sqf diff --git a/addons/headless/XEH_PREP.hpp b/addons/headless/XEH_PREP.hpp index 11e09adf10..e1c65cc083 100644 --- a/addons/headless/XEH_PREP.hpp +++ b/addons/headless/XEH_PREP.hpp @@ -1,3 +1,4 @@ +ACEX_PREP(blacklist); ACEX_PREP(endMissionNoPlayers); ACEX_PREP(handleConnectHC); ACEX_PREP(handleDisconnect); diff --git a/addons/headless/XEH_postInit.sqf b/addons/headless/XEH_postInit.sqf index d1c76a332b..d1106b40c9 100644 --- a/addons/headless/XEH_postInit.sqf +++ b/addons/headless/XEH_postInit.sqf @@ -10,6 +10,21 @@ }; // Add disconnect EH addMissionEventHandler ["HandleDisconnect", {call FUNC(handleDisconnect)}]; + + [QGVAR(transferGroupsRebalance), { + params ["_groups", "_owner", "_rebalance"]; + + if (_groups isNotEqualTo [] && {_owner > 1}) then { + { + _x setGroupOwner _owner; + } forEach _groups; + }; + + // Rebalance units + if (_rebalance in [REBALANCE, FORCED_REBALANCE]) then { + (_rebalance == FORCED_REBALANCE) call FUNC(rebalance); + }; + }] call CBA_fnc_addEventHandler; } else { // Register HC (this part happens on HC only) [QXGVAR(headlessClientJoined), [player]] call CBA_fnc_globalEvent; // Global event for API purposes diff --git a/addons/headless/functions/fnc_blacklist.sqf b/addons/headless/functions/fnc_blacklist.sqf new file mode 100644 index 0000000000..1c15406ba6 --- /dev/null +++ b/addons/headless/functions/fnc_blacklist.sqf @@ -0,0 +1,51 @@ +#include "..\script_component.hpp" +/* + * Author: johnb43 + * Modifies which units are blacklisted from being transferred to HCs. + * + * Arguments: + * 0: Units + * 1: Add (true) or remove (false) from blacklist (default: true) + * 2: Owner to transfer units to (default: -1) + * 3: Rebalance (default: 0) + * + * Return Value: + * None + * + * Example: + * [cursorObject, true] call ace_headless_fnc_blacklist + * + * Public: Yes + */ + +params [["_units", objNull, [objNull, grpNull, []]], ["_blacklist", true, [false]], ["_owner", -1, [false]], ["_rebalance", NO_REBALANCE, [0]]]; + +if !(_units isEqualType []) then { + _units = [_units]; +}; + +// Make sure passed arguments are objects or groups +_units = _units select {_x isEqualType objNull || {_x isEqualType grpNull}}; +_units = _units select {!isNull _x}; + +if (_units isEqualTo []) exitWith {}; + +private _transfer = _blacklist && {_owner > 1}; +private _groups = []; + +{ + _x setVariable [QXGVAR(blacklist), _blacklist, true]; + + if (_transfer) then { + if (_x isEqualType objNull) then { + _groups pushBack group _x; + } else { + _groups pushBack _x; + }; + }; +} forEach _units; + +// Try to move AI to new owner; Also takes care of rebalancing groups +if (_transfer || {_rebalance in [REBALANCE, FORCED_REBALANCE]}) then { + [QGVAR(transferGroupsRebalance), [_groups arrayIntersect _groups, _owner, _rebalance]] call CBA_fnc_serverEvent; +}; diff --git a/addons/headless/functions/fnc_transferGroups.sqf b/addons/headless/functions/fnc_transferGroups.sqf index 60d3c093d1..0efbe26365 100644 --- a/addons/headless/functions/fnc_transferGroups.sqf +++ b/addons/headless/functions/fnc_transferGroups.sqf @@ -17,6 +17,9 @@ params ["_force"]; +// Filter out any invalid entries +GVAR(headlessClients) = GVAR(headlessClients) select {!isNull _x}; + GVAR(headlessClients) params [ ["_HC1", objNull, [objNull]], ["_HC2", objNull, [objNull]], @@ -36,12 +39,13 @@ private _idHC2 = -1; private _idHC3 = -1; private _currentHC = 0; -if (!local _HC1) then { +// objNull is never local +if (!local _HC1 && !isNull _HC1) then { _idHC1 = owner _HC1; _currentHC = 1; }; -if (!local _HC2) then { +if (!local _HC2 && !isNull _HC2) then { _idHC2 = owner _HC2; if (_currentHC == 0) then { @@ -49,7 +53,7 @@ if (!local _HC2) then { }; }; -if (!local _HC3) then { +if (!local _HC3 && !isNull _HC3) then { _idHC3 = owner _HC3; if (_currentHC == 0) then { @@ -57,84 +61,150 @@ if (!local _HC3) then { }; }; +if (_currentHC == 0) exitWith { + TRACE_1("No Valid HC to transfer to",_currentHC); + + if (XGVAR(log)) then { + INFO("No Valid HC to transfer to"); + }; +}; + // Prepare statistics private _numTransferredHC1 = 0; private _numTransferredHC2 = 0; private _numTransferredHC3 = 0; +private _units = []; +private _transfer = false; +private _previousOwner = -1; + // Transfer AI groups { - // No transfer if empty group - private _transfer = ((units _x) isNotEqualTo []) && {!(_x getVariable [QXGVAR(blacklist), false])}; - if (_transfer) then { - // No transfer if waypoints with synchronized triggers exist for the group - private _allWaypointsWithTriggers = (waypoints _x) select {(synchronizedTriggers _x) isNotEqualTo []}; - if (_allWaypointsWithTriggers isNotEqualTo []) exitWith { + _units = units _x; + + // No transfer if empty group or if group is blacklisted + if (_units isEqualTo [] || {_x getVariable [QXGVAR(blacklist), false]}) then { + continue; + }; + + // No transfer if waypoints with synchronized triggers exist for the group + if (((waypoints _x) select {(synchronizedTriggers _x) isNotEqualTo []}) isNotEqualTo []) then { + continue; + }; + + { + // No transfer if already transferred + if (!_force && {(owner _x) in [_idHC1, _idHC2, _idHC3]}) exitWith { _transfer = false; }; - { - // No transfer if already transferred - if (!_force && {(owner _x) in [_idHC1, _idHC2, _idHC3]}) exitWith { - _transfer = false; - }; + // No transfer if any unit in group is blacklisted + if (_x getVariable [QXGVAR(blacklist), false]) exitWith { + _transfer = false; + }; - // No transfer if player or UAV in this group - if (isPlayer _x || {unitIsUAV _x}) exitWith { - _transfer = false; - }; + // No transfer if player or UAV in this group + if (isPlayer _x || {unitIsUAV _x}) exitWith { + _transfer = false; + }; - // No transfer if any unit in group is blacklisted - if (_x getVariable [QXGVAR(blacklist), false]) exitWith { - _transfer = false; - }; + private _vehicle = objectParent _x; - private _vehicle = objectParent _x; + // No transfer if the vehicle the unit is in or if the crew in that vehicle is blacklisted + if ((_vehicle getVariable [QXGVAR(blacklist), false]) || {unitIsUAV _vehicle}) exitWith { + _transfer = false; + }; - // No transfer if the vehicle the unit is in or if the crew in that vehicle is blacklisted - if ((_vehicle getVariable [QXGVAR(blacklist), false]) || {unitIsUAV _vehicle}) exitWith { - _transfer = false; - }; + // Save gear if unit about to be transferred with current loadout (naked unit work-around) + if (XGVAR(transferLoadout) == 1) then { + _x setVariable [QGVAR(loadout), _x call CBA_fnc_getLoadout, true]; + }; + } forEach _units; - // Save gear if unit about to be transferred with current loadout (naked unit work-around) - if (XGVAR(transferLoadout) == 1) then { - _x setVariable [QGVAR(loadout), _x call CBA_fnc_getLoadout, true]; - }; - } forEach (units _x); + if (!_transfer) then { + continue; }; // Round robin between HCs if load balance enabled, else pass all to one HC - if (_transfer) then { - switch (_currentHC) do { - case 1: { - private _transferred = _x setGroupOwner _idHC1; - if (_loadBalance) then { - _currentHC = [3, 2] select (!local _HC2); - }; - if (_transferred) then { - _numTransferredHC1 = _numTransferredHC1 + 1; + _previousOwner = groupOwner _x; + + switch (_currentHC) do { + case 1: { + if (_loadBalance) then { + // Find the next valid HC + // If none are valid, _currentHC will remain the same + if (_idHC2 != -1) then { + _currentHC = 2; + } else { + if (_idHC3 != -1) then { + _currentHC = 3; + }; }; }; - case 2: { - private _transferred = _x setGroupOwner _idHC2; - if (_loadBalance) then { - _currentHC = [1, 3] select (!local _HC3); - }; - if (_transferred) then { - _numTransferredHC2 = _numTransferredHC2 + 1; + + // Don't transfer if it's already local to HC1 + if (_previousOwner == _idHC1) exitWith {}; + + [QGVAR(groupTransferPre), [_x, _HC1, _previousOwner, _idHC1], [_previousOwner, _idHC1]] call CBA_fnc_targetEvent; // API + + private _transferred = _x setGroupOwner _idHC1; + + [QGVAR(groupTransferPost), [_x, _HC1, _previousOwner, _idHC1, _transferred], [_previousOwner, _idHC1]] call CBA_fnc_targetEvent; // API + + if (_transferred) then { + _numTransferredHC1 = _numTransferredHC1 + 1; + }; + }; + case 2: { + if (_loadBalance) then { + // Find the next valid HC + // If none are valid, _currentHC will remain the same + if (_idHC3 != -1) then { + _currentHC = 3; + } else { + if (_idHC1 != -1) then { + _currentHC = 1; + }; }; }; - case 3: { - private _transferred = _x setGroupOwner _idHC3; - if (_loadBalance) then { - _currentHC = [2, 1] select (!local _HC1); - }; - if (_transferred) then { - _numTransferredHC3 = _numTransferredHC3 + 1; + + // Don't transfer if it's already local to HC2 + if (_previousOwner == _idHC2) exitWith {}; + + [QGVAR(groupTransferPre), [_x, _HC2, _previousOwner, _idHC2], [_previousOwner, _idHC2]] call CBA_fnc_targetEvent; // API + + private _transferred = _x setGroupOwner _idHC2; + + [QGVAR(groupTransferPost), [_x, _HC2, _previousOwner, _idHC2, _transferred], [_previousOwner, _idHC2]] call CBA_fnc_targetEvent; // API + + if (_transferred) then { + _numTransferredHC2 = _numTransferredHC2 + 1; + }; + }; + case 3: { + if (_loadBalance) then { + // Find the next valid HC + // If none are valid, _currentHC will remain the same + if (_idHC1 != -1) then { + _currentHC = 1; + } else { + if (_idHC2 != -1) then { + _currentHC = 2; + }; }; }; - default { - TRACE_1("No Valid HC to transfer to",_currentHC); + + // Don't transfer if it's already local to HC3 + if (_previousOwner == _idHC3) exitWith {}; + + [QGVAR(groupTransferPre), [_x, _HC3, _previousOwner, _idHC3], [_previousOwner, _idHC3]] call CBA_fnc_targetEvent; // API + + private _transferred = _x setGroupOwner _idHC2; + + [QGVAR(groupTransferPost), [_x, _HC3, _previousOwner, _idHC3, _transferred], [_previousOwner, _idHC3]] call CBA_fnc_targetEvent; // API + + if (_transferred) then { + _numTransferredHC3 = _numTransferredHC3 + 1; }; }; }; diff --git a/addons/headless/script_component.hpp b/addons/headless/script_component.hpp index 73761a7bb1..272b288d5f 100644 --- a/addons/headless/script_component.hpp +++ b/addons/headless/script_component.hpp @@ -17,3 +17,7 @@ #include "\z\ace\addons\main\script_macros.hpp" #define DELAY_DEFAULT 15 + +#define NO_REBALANCE 0 +#define REBALANCE 1 +#define FORCED_REBALANCE 2 diff --git a/docs/wiki/framework/events-framework.md b/docs/wiki/framework/events-framework.md index bec6492c96..5712acb0a0 100644 --- a/docs/wiki/framework/events-framework.md +++ b/docs/wiki/framework/events-framework.md @@ -156,9 +156,15 @@ MenuType: 0 = Interaction, 1 = Self Interaction | Event Key | Parameters | Locality | Type | Description | |---------- |------------|----------|------|-------------| -|---------- |------------|----------|------|-------------| | `ace_interaction_doorOpeningStarted` | [_house, _door, _animations] | Local | Listen | Called when local unit starts interacting with doors -| `ace_interaction_doorOpeningStopped` | [_house, _door, _animations] | Local | Listen | Called when local unit stopps interacting with doors +| `ace_interaction_doorOpeningStopped` | [_house, _door, _animations] | Local | Listen | Called when local unit stops interacting with doors + +### 2.17 Headless (`ace_headless`) + +| Event Key | Parameters | Locality | Type | Description | +|---------- |------------|----------|------|-------------| +| `ace_headless_groupTransferPre` | [_group, _HC (OBJECT), _previousOwner, _idHC] | Target | Listen | Called just before a group is transferred from any machine to a HC. Called where group currently is local and on the HC, where group is going to be local. +| `ace_headless_groupTransferPost` | [_group, _HC (OBJECT), _previousOwner, _idHC, _transferredSuccessfully] | Target | Listen | Called just after a group is transferred from a machine to a HC. Called where group was local and on the HC, where group is now local. `_transferredSuccessfully` is passed so mods can actually check if the locality was properly transferred, as ownership transfer is not guaranteed. ## 3. Usage Also Reference [CBA Events System](https://github.com/CBATeam/CBA_A3/wiki/Custom-Events-System){:target="_blank"} documentation. diff --git a/docs/wiki/framework/headless-framework.md b/docs/wiki/framework/headless-framework.md index 6dbc83c512..7a2a5a0822 100644 --- a/docs/wiki/framework/headless-framework.md +++ b/docs/wiki/framework/headless-framework.md @@ -30,14 +30,29 @@ As of ACEX v3.2.0 _(before merge into ACE3)_ this feature can also be enabled wi ## 2. Scripting -### 2.1 Disable Transferring for a Group +### 2.1 Manipulating HC Transfers of Groups via function -To prevent a group from transferring to a Headless Client use the following line on a group leader (or every unit in a group in case group leader may not spawn): +`ace_headless_fnc_blacklist` + + | Arguments | Type | Optional (default value) +---| --------- | ---- | ------------------------ +0 | Units | Object, Group or Array of both | Required +1 | Add (true) or remove (false) from blacklist | Bool | Optional (default: `true`) +2 | Owner to transfer units to | Number | Optional (default: `-1`) +3 | Rebalance (0 = no rebalance, 1 = rebalance, 2 = force rebalance) | Number | (default: `0`) +**R** | None | None | Return value + +`Force rebalance` means that all units, including the ones that are on the HCs, are rebalanced amongst the HCs, whereas `rebalance` means that newly spawned units are going to be evenly distributed amongst HCs. Therefore, `rebalance` does not guarantee that the HCs will have an equal amount of groups, whereas `force rebalance` does. + +### 2.2 Disable Transferring for a Group via variable + +To prevent a group from transferring to a Headless Client use the following line on a unit within a group: ```sqf this setVariable ["acex_headless_blacklist", true]; ``` +This variable can also be set on vehicles, disabling transferal of any groups having units in said vehicles. ## 3. Limitations @@ -48,3 +63,7 @@ Some Arma 3 features are incompatible, this is up to BI to add support. Disable Additionally, groups will not be transferred due to lack of support if they: - Have waypoints with synchronized triggers (waypoint would not change status based on trigger condition) (added in ACEX v3.2.0 - _before merge into ACE3_) + +Groups will not be transferred to avoid issues: +- If a player is within the group. +- If they contain UAVs. From 8c0d0944c6c437d31dfc8226cfaef9228fc0abf3 Mon Sep 17 00:00:00 2001 From: Fabio Schick <58027418+mrschick@users.noreply.github.com> Date: Wed, 29 May 2024 20:50:18 +0200 Subject: [PATCH 060/290] Parachute - Make Jet Ejection Seats use Non-Steerable Parachutes (#9963) --- addons/parachute/CfgVehicles.hpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/addons/parachute/CfgVehicles.hpp b/addons/parachute/CfgVehicles.hpp index f764494224..545d9a3705 100644 --- a/addons/parachute/CfgVehicles.hpp +++ b/addons/parachute/CfgVehicles.hpp @@ -101,4 +101,36 @@ class CfgVehicles { class B_Soldier_05_f; class B_Pilot_F: B_Soldier_05_f {backpack = "ACE_NonSteerableParachute";}; class I_Soldier_04_F; class I_pilot_F: I_Soldier_04_F {backpack = "ACE_NonSteerableParachute";}; class O_helipilot_F; class O_Pilot_F: O_helipilot_F {backpack = "ACE_NonSteerableParachute";}; + + class Plane_Base_F; + class Plane_CAS_01_base_F: Plane_Base_F { + class EjectionSystem { + EjectionParachute = "NonSteerable_Parachute_F"; + }; + }; + class Plane_CAS_02_base_F: Plane_Base_F { + class EjectionSystem { + EjectionParachute = "NonSteerable_Parachute_F"; + }; + }; + class Plane_Fighter_01_base_F: Plane_Base_F { + class EjectionSystem { + EjectionParachute = "NonSteerable_Parachute_F"; + }; + }; + class Plane_Fighter_02_base_F: Plane_Base_F { + class EjectionSystem { + EjectionParachute = "NonSteerable_Parachute_F"; + }; + }; + class Plane_Fighter_03_base_F: Plane_Base_F { + class EjectionSystem { + EjectionParachute = "NonSteerable_Parachute_F"; + }; + }; + class Plane_Fighter_04_base_F: Plane_Base_F { + class EjectionSystem { + EjectionParachute = "NonSteerable_Parachute_F"; + }; + }; }; From d9a2aa01a493fd2ac3f552c35b770526761d3be8 Mon Sep 17 00:00:00 2001 From: Mike-MF Date: Wed, 29 May 2024 19:51:18 +0100 Subject: [PATCH 061/290] Realistic Names - Add missing classes (#10013) Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- addons/realisticnames/Attachments.hpp | 174 +++++++++++++++++++++++ addons/realisticnames/CfgVehicles.hpp | 13 ++ addons/realisticnames/CfgWeapons.hpp | 191 ++++---------------------- addons/realisticnames/stringtable.xml | 36 +++++ 4 files changed, 246 insertions(+), 168 deletions(-) create mode 100644 addons/realisticnames/Attachments.hpp diff --git a/addons/realisticnames/Attachments.hpp b/addons/realisticnames/Attachments.hpp new file mode 100644 index 0000000000..a861bb4a04 --- /dev/null +++ b/addons/realisticnames/Attachments.hpp @@ -0,0 +1,174 @@ +//attachments + +class ItemCore; + +class acc_flashlight: ItemCore { + displayName = CSTRING(flashlight_Name); +}; + +class optic_MRD: ItemCore { + displayName = CSTRING(optic_mrd_Name); +}; +class optic_MRD_black: optic_MRD { + displayName = CSTRING(optic_mrd_black_Name); +}; + +class optic_Hamr: ItemCore { + displayName = CSTRING(optic_hamr); +}; +class optic_Hamr_khk_F: optic_Hamr { + displayName = CSTRING(optic_hamr_khk); +}; +class ACE_optic_Hamr_2D: optic_Hamr { + displayName = CSTRING(optic_hamr_2d); +}; +class ACE_optic_Hamr_PIP: ACE_optic_Hamr_2D { + displayName = CSTRING(optic_hamr_pip); +}; + +class optic_Arco: ItemCore { + displayName = CSTRING(optic_arco); +}; +class optic_Arco_blk_F: optic_Arco { + displayName = CSTRING(optic_arco_blk); +}; +class optic_Arco_ghex_F: optic_Arco { + displayName = CSTRING(optic_arco_ghex); +}; +class ACE_optic_Arco_2D: optic_Arco { + displayName = CSTRING(optic_arco_2d); +}; +class ACE_optic_Arco_PIP: ACE_optic_Arco_2D { + displayName = CSTRING(optic_arco_pip); +}; +class optic_Arco_lush_F: optic_Arco { + displayName = CSTRING(optic_arco_lush); +}; +class optic_Arco_arid_F: optic_Arco { + displayName = CSTRING(optic_arco_arid); +}; +class optic_Arco_AK_blk_F: optic_Arco_blk_F { + displayName = CSTRING(optic_arco_ak_blk); +}; +class optic_Arco_AK_lush_F: optic_Arco_lush_F { + displayName = CSTRING(optic_arco_ak_lush); +}; +class optic_Arco_AK_arid_F: optic_Arco_arid_F { + displayName = CSTRING(optic_arco_ak_arid); +}; + +class optic_ERCO_blk_f: optic_Arco { + displayName = CSTRING(optic_erco_blk); +}; +class optic_ERCO_khk_f: optic_ERCO_blk_f { + displayName = CSTRING(optic_erco_khk); +}; +class optic_ERCO_snd_f: optic_ERCO_blk_f { + displayName = CSTRING(optic_erco_snd); +}; + +class optic_LRPS: ItemCore { + displayName = CSTRING(optic_lrps); +}; +class optic_LRPS_ghex_F: optic_LRPS { + displayName = CSTRING(optic_lrps_ghex); +}; +class optic_LRPS_tna_F: optic_LRPS { + displayName = CSTRING(optic_lrps_tna); +}; +class ACE_optic_LRPS_2D: optic_LRPS { + displayName = CSTRING(optic_lrps_2d); +}; +class ACE_optic_LRPS_PIP: ACE_optic_LRPS_2D { + displayName = CSTRING(optic_lrps_pip); +}; + +class optic_AMS_base; +class optic_AMS: optic_AMS_base { + displayName = CSTRING(optic_ams); +}; +class optic_AMS_khk: optic_AMS { + displayName = CSTRING(optic_ams_khk); +}; +class optic_AMS_snd: optic_AMS { + displayName = CSTRING(optic_ams_snd); +}; + +class optic_KHS_base; +class optic_KHS_blk: optic_KHS_base { + displayName = CSTRING(optic_khs_blk); +}; +class optic_KHS_hex: optic_KHS_blk { + displayName = CSTRING(optic_khs_hex); +}; +class optic_KHS_old: ItemCore { + displayName = CSTRING(optic_khs_old); +}; +class optic_KHS_tan: optic_KHS_blk { + displayName = CSTRING(optic_khs_tan); +}; + +class optic_DMS: ItemCore { + displayName = CSTRING(optic_dms); +}; +class optic_DMS_ghex_F: optic_DMS { + displayName = CSTRING(optic_dms_ghex); +}; +class optic_DMS_weathered_F: optic_DMS { + displayName = CSTRING(optic_dms_weathered); +}; +class optic_DMS_weathered_Kir_F: optic_DMS_weathered_F { + displayName = CSTRING(optic_dms_weathered_kir); +}; + +class optic_holosight: ItemCore { + displayName = CSTRING(optic_holosight); +}; +class optic_Holosight_blk_F: optic_holosight { + displayName = CSTRING(optic_holosight_blk); +}; +class optic_Holosight_khk_F: optic_holosight { + displayName = CSTRING(optic_holosight_khk); +}; +class optic_Holosight_lush_F: optic_holosight { + displayName = CSTRING(optic_holosight_lush); +}; +class optic_Holosight_arid_F: optic_holosight { + displayName = CSTRING(optic_holosight_arid); +}; +class optic_Holosight_smg: ItemCore { + displayName = CSTRING(optic_holosight_smg); +}; +class optic_Holosight_smg_blk_F: optic_Holosight_smg { + displayName = CSTRING(optic_holosight_smg_blk); +}; +class optic_Holosight_smg_khk_F: optic_Holosight_smg { + displayName = CSTRING(optic_holosight_smg_khk); +}; + +class optic_MRCO: ItemCore { + displayName = CSTRING(optic_MRCO); +}; +class ACE_optic_MRCO_2D: optic_MRCO { + displayName = CSTRING(optic_MRCO_2d); +}; +class ACE_optic_MRCO_PIP: ACE_optic_MRCO_2D { + displayName = CSTRING(optic_MRCO_pip); +}; + +class optic_Yorris: ItemCore { + displayName = CSTRING(optic_Yorris); +}; + +class optic_ACO: ItemCore { + displayName = CSTRING(optic_ACO); +}; +class optic_ACO_grn: ItemCore { + displayName = CSTRING(optic_ACO_grn); +}; +class optic_ACO_smg: ItemCore { + displayName = CSTRING(optic_ACO_smg); +}; +class optic_ACO_grn_smg: ItemCore { + displayName = CSTRING(optic_ACO_grn_smg); +}; diff --git a/addons/realisticnames/CfgVehicles.hpp b/addons/realisticnames/CfgVehicles.hpp index 8d4d0c2f4a..29ac412957 100644 --- a/addons/realisticnames/CfgVehicles.hpp +++ b/addons/realisticnames/CfgVehicles.hpp @@ -249,6 +249,10 @@ class CfgVehicles { class O_Truck_02_medical_F: Truck_02_medical_base_F { displayName = CSTRING(Truck_02_medical_Name); }; + class Truck_02_water_base_F; + class C_IDAP_Truck_02_water_F: Truck_02_water_base_F { + displayName = CSTRING(Truck_02_water_Name); + }; class I_Truck_02_transport_F: Truck_02_transport_base_F { displayName = CSTRING(Truck_02_transport_Name); }; @@ -283,6 +287,12 @@ class CfgVehicles { class C_Truck_02_box_F: Truck_02_box_base_F { displayName = CSTRING(Truck_02_box_Name); }; + class C_IDAP_Truck_02_transport_F: Truck_02_transport_base_F { + displayName = CSTRING(Truck_02_transport_Name); + }; + class C_IDAP_Truck_02_F: Truck_02_base_F { + displayName = CSTRING(Truck_02_covered_Name); + }; class Truck_03_base_F; class O_Truck_03_transport_F: Truck_03_base_F { @@ -384,6 +394,9 @@ class CfgVehicles { class I_Heli_Transport_02_F: Heli_Transport_02_base_F { displayName = CSTRING(Heli_Transport_02_Name); }; + class C_IDAP_Heli_Transport_02_F: Heli_Transport_02_base_F { + displayName = CSTRING(Heli_Transport_02_Name); + }; // planes class Plane_CAS_01_base_F; diff --git a/addons/realisticnames/CfgWeapons.hpp b/addons/realisticnames/CfgWeapons.hpp index 953f981051..5b0e33e98c 100644 --- a/addons/realisticnames/CfgWeapons.hpp +++ b/addons/realisticnames/CfgWeapons.hpp @@ -2,6 +2,7 @@ class Mode_SemiAuto; class Mode_FullAuto; class CfgWeapons { + #include "Attachments.hpp" // assault rifles // MX @@ -707,176 +708,20 @@ class CfgWeapons { }; }; - //attachments - - class ItemCore; - - class acc_flashlight: ItemCore { - displayName = "UTG Defender 126"; - }; - - class optic_Hamr: ItemCore { - displayName = CSTRING(optic_hamr); - }; - class optic_Hamr_khk_F: optic_Hamr { - displayName = CSTRING(optic_hamr_khk); - }; - class ACE_optic_Hamr_2D: optic_Hamr { - displayName = CSTRING(optic_hamr_2d); - }; - class ACE_optic_Hamr_PIP: ACE_optic_Hamr_2D { - displayName = CSTRING(optic_hamr_pip); - }; - - class optic_Arco: ItemCore { - displayName = CSTRING(optic_arco); - }; - class optic_Arco_blk_F: optic_Arco { - displayName = CSTRING(optic_arco_blk); - }; - class optic_Arco_ghex_F: optic_Arco { - displayName = CSTRING(optic_arco_ghex); - }; - class ACE_optic_Arco_2D: optic_Arco { - displayName = CSTRING(optic_arco_2d); - }; - class ACE_optic_Arco_PIP: ACE_optic_Arco_2D { - displayName = CSTRING(optic_arco_pip); - }; - class optic_Arco_lush_F: optic_Arco { - displayName = CSTRING(optic_arco_lush); - }; - class optic_Arco_arid_F: optic_Arco { - displayName = CSTRING(optic_arco_arid); - }; - class optic_Arco_AK_blk_F: optic_Arco_blk_F { - displayName = CSTRING(optic_arco_ak_blk); - }; - class optic_Arco_AK_lush_F: optic_Arco_lush_F { - displayName = CSTRING(optic_arco_ak_lush); - }; - class optic_Arco_AK_arid_F: optic_Arco_arid_F { - displayName = CSTRING(optic_arco_ak_arid); - }; - - class optic_ERCO_blk_f: optic_Arco { - displayName = CSTRING(optic_erco_blk); - }; - class optic_ERCO_khk_f: optic_ERCO_blk_f { - displayName = CSTRING(optic_erco_khk); - }; - class optic_ERCO_snd_f: optic_ERCO_blk_f { - displayName = CSTRING(optic_erco_snd); - }; - - class optic_LRPS: ItemCore { - displayName = CSTRING(optic_lrps); - }; - class optic_LRPS_ghex_F: optic_LRPS { - displayName = CSTRING(optic_lrps_ghex); - }; - class optic_LRPS_tna_F: optic_LRPS { - displayName = CSTRING(optic_lrps_tna); - }; - class ACE_optic_LRPS_2D: optic_LRPS { - displayName = CSTRING(optic_lrps_2d); - }; - class ACE_optic_LRPS_PIP: ACE_optic_LRPS_2D { - displayName = CSTRING(optic_lrps_pip); - }; - - class optic_AMS_base; - class optic_AMS: optic_AMS_base { - displayName = CSTRING(optic_ams); - }; - class optic_AMS_khk: optic_AMS { - displayName = CSTRING(optic_ams_khk); - }; - class optic_AMS_snd: optic_AMS { - displayName = CSTRING(optic_ams_snd); - }; - - class optic_KHS_base; - class optic_KHS_blk: optic_KHS_base { - displayName = CSTRING(optic_khs_blk); - }; - class optic_KHS_hex: optic_KHS_blk { - displayName = CSTRING(optic_khs_hex); - }; - class optic_KHS_old: ItemCore { - displayName = CSTRING(optic_khs_old); - }; - class optic_KHS_tan: optic_KHS_blk { - displayName = CSTRING(optic_khs_tan); - }; - - class optic_DMS: ItemCore { - displayName = CSTRING(optic_dms); - }; - class optic_DMS_ghex_F: optic_DMS { - displayName = CSTRING(optic_dms_ghex); - }; - class optic_DMS_weathered_F: optic_DMS { - displayName = CSTRING(optic_dms_weathered); - }; - class optic_DMS_weathered_Kir_F: optic_DMS_weathered_F { - displayName = CSTRING(optic_dms_weathered_kir); - }; - - class optic_holosight: ItemCore { - displayName = CSTRING(optic_holosight); - }; - class optic_Holosight_blk_F: optic_holosight { - displayName = CSTRING(optic_holosight_blk); - }; - class optic_Holosight_khk_F: optic_holosight { - displayName = CSTRING(optic_holosight_khk); - }; - class optic_Holosight_lush_F: optic_holosight { - displayName = CSTRING(optic_holosight_lush); - }; - class optic_Holosight_arid_F: optic_holosight { - displayName = CSTRING(optic_holosight_arid); - }; - class optic_Holosight_smg: ItemCore { - displayName = CSTRING(optic_holosight_smg); - }; - class optic_Holosight_smg_blk_F: optic_Holosight_smg { - displayName = CSTRING(optic_holosight_smg_blk); - }; - class optic_Holosight_smg_khk_F: optic_Holosight_smg { - displayName = CSTRING(optic_holosight_smg_khk); - }; - - class optic_MRCO: ItemCore { - displayName = CSTRING(optic_MRCO); - }; - class ACE_optic_MRCO_2D: optic_MRCO { - displayName = CSTRING(optic_MRCO_2d); - }; - class ACE_optic_MRCO_PIP: ACE_optic_MRCO_2D { - displayName = CSTRING(optic_MRCO_pip); - }; - - class optic_Yorris: ItemCore { - displayName = CSTRING(optic_Yorris); - }; - - class optic_ACO: ItemCore { - displayName = CSTRING(optic_ACO); - }; - class optic_ACO_grn: ItemCore { - displayName = CSTRING(optic_ACO_grn); - }; - class optic_ACO_smg: ItemCore { - displayName = CSTRING(optic_ACO_smg); - }; - class optic_ACO_grn_smg: ItemCore { - displayName = CSTRING(optic_ACO_grn_smg); - }; - // APEX/Tanoa + // Type 115 + class arifle_ARX_base_F; + class arifle_ARX_blk_F: arifle_ARX_base_F { + displayName = CSTRING(arifle_arx_blk_Name); + }; + class arifle_ARX_ghex_F: arifle_ARX_base_F { + displayName = CSTRING(arifle_arx_ghex_Name); + }; + class arifle_ARX_hex_F: arifle_ARX_base_F { + displayName = CSTRING(arifle_arx_hex_Name); + }; + // QBZ-95 and variants class arifle_CTAR_base_F; class arifle_CTAR_blk_F: arifle_CTAR_base_F { @@ -1018,6 +863,16 @@ class CfgWeapons { // Contact/Livonia + // CZ 581 Shotgun + class sgun_HunterShotgun_01_base_F; + class sgun_HunterShotgun_01_F: sgun_HunterShotgun_01_base_F { + displayName = CSTRING(sgun_huntershotgun_01_Name); + }; + class sgun_HunterShotgun_01_sawedoff_base_F; + class sgun_HunterShotgun_01_sawedoff_F: sgun_HunterShotgun_01_sawedoff_base_F { + displayName = CSTRING(sgun_huntershotgun_sawedoff_01_Name); + }; + // FNX-45 (Green) class hgun_Pistol_heavy_01_green_F: hgun_Pistol_heavy_01_F { displayName = CSTRING(hgun_Pistol_heavy_01_green_Name); diff --git a/addons/realisticnames/stringtable.xml b/addons/realisticnames/stringtable.xml index 6130f6aaf4..47c5f27c68 100644 --- a/addons/realisticnames/stringtable.xml +++ b/addons/realisticnames/stringtable.xml @@ -698,6 +698,10 @@ "卡玛兹"(医疗) KamAZ Medikal + + KamAZ Water + KamAZ Água + KamAZ MRL KamAS MRL @@ -1655,6 +1659,14 @@ FNX-45戰術型手槍 FNX-45 战术型 + + CZ 581 + CZ 581 + + + CZ 581 (Sawed-Off) + CZ 581 (Cano serrado) + FNX-45 Tactical (Green) FNX-45 Tactical (Grün) @@ -3056,6 +3068,18 @@ "柏拉格" 战斗无人机 Burraq UCAV + + Type 115 (Black) + Type 115 (Preto) + + + Type 115 (Green Hex) + Type 115 (Verde Hex) + + + Type 115 (Hex) + Type 115 (Hex) + QBZ-95-1 (Black) QBZ-95-1 (Černá) @@ -3840,6 +3864,18 @@ Wiesel 2 RFCV (Radar) 비젤 2 RFCV (레이더) + + UTG Defender 126 + UTG Defender 126 + + + EOTech MRDS + EOTech MRDS + + + EOTech MRDS (Black) + EOTech MRDS (Preto) + Leupold Mark 4 HAMR Leupold Mark 4 HAMR From 98f4b51c52818a953e9a420591a4cd730833bfce Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 29 May 2024 20:55:17 +0200 Subject: [PATCH 062/290] Hearing - Fix deafness reducing when game is paused (#10039) Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> --- addons/hearing/functions/fnc_updateVolume.sqf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/hearing/functions/fnc_updateVolume.sqf b/addons/hearing/functions/fnc_updateVolume.sqf index 0a36367466..5b42607996 100644 --- a/addons/hearing/functions/fnc_updateVolume.sqf +++ b/addons/hearing/functions/fnc_updateVolume.sqf @@ -15,6 +15,8 @@ * Public: No */ +if (isGamePaused) exitWith {}; + if (!alive ACE_player) exitWith { if (missionNamespace getVariable [QGVAR(disableVolumeUpdate), false]) exitWith {}; @@ -39,8 +41,6 @@ if (!_updateVolumeOnly) then { GVAR(time3) = CBA_missionTime; - if (!isGameFocused) exitWith {}; - if (GVAR(deafnessDV) > 19.75) then { playSound (["ACE_Combat_Deafness_Heavy", "ACE_Combat_Deafness_Heavy_NoRing"] select GVAR(disableEarRinging)); } else { From d30c01aee9238002d5924e8c0b665da023951e15 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Thu, 30 May 2024 03:34:19 -0500 Subject: [PATCH 063/290] Hearing - prevent audio from stacking when tabbed out (#10048) --- addons/hearing/functions/fnc_updateVolume.sqf | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/hearing/functions/fnc_updateVolume.sqf b/addons/hearing/functions/fnc_updateVolume.sqf index 5b42607996..bb1d57e3c1 100644 --- a/addons/hearing/functions/fnc_updateVolume.sqf +++ b/addons/hearing/functions/fnc_updateVolume.sqf @@ -38,6 +38,7 @@ if (!_updateVolumeOnly) then { GVAR(deafnessDV) > 10) then { if (CBA_missionTime - GVAR(time3) < 3) exitWith {}; + if (!isGameFocused) exitWith {}; // prevent audio from stacking when tabbed out GVAR(time3) = CBA_missionTime; From 5a1e3bc58550e3c2af1305103c1bc20a03300421 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Thu, 30 May 2024 07:58:46 -0500 Subject: [PATCH 064/290] Zeus - Add a translation (#10047) --- addons/zeus/stringtable.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/addons/zeus/stringtable.xml b/addons/zeus/stringtable.xml index 4ad75cefdc..a1ae4d554e 100644 --- a/addons/zeus/stringtable.xml +++ b/addons/zeus/stringtable.xml @@ -1099,6 +1099,19 @@ Only Players + プレイヤーのみ + Nur Spieler + 오직 플레이어만 + Tylko gracze + Joueurs seulement + Solo Giocatori + 仅玩家 + 只有玩家 + Только игроки + Apenas Jogadores + Pouze hráči + Solo jugadores + Sadece Oyuncular None From 9f2ee9fb6fb5992fb9235ff0df2d6a4fc079b274 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Fri, 31 May 2024 22:07:50 +0200 Subject: [PATCH 065/290] Common - Add `setDead` API (#10045) * Added `setDead` API * Update XEH_PREP.hpp * Update fnc_setDead.sqf * Update addons/common/functions/fnc_disableUserInput.sqf Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> * Update fnc_setDead.sqf * Added warning for non-local units --------- Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> --- addons/common/XEH_PREP.hpp | 1 + .../common/functions/fnc_disableUserInput.sqf | 6 +-- addons/common/functions/fnc_setDead.sqf | 44 +++++++++++++++++++ .../functions/fnc_handleEffects.sqf | 6 +-- .../medical_status/functions/fnc_setDead.sqf | 12 ++--- 5 files changed, 53 insertions(+), 16 deletions(-) create mode 100644 addons/common/functions/fnc_setDead.sqf diff --git a/addons/common/XEH_PREP.hpp b/addons/common/XEH_PREP.hpp index fb64d464df..68fdaaf77d 100644 --- a/addons/common/XEH_PREP.hpp +++ b/addons/common/XEH_PREP.hpp @@ -161,6 +161,7 @@ PREP(sendRequest); PREP(serverLog); PREP(setAimCoef); PREP(setApproximateVariablePublic); +PREP(setDead); PREP(setDefinedVariable); PREP(setDisableUserInputStatus); PREP(setHearingCapability); diff --git a/addons/common/functions/fnc_disableUserInput.sqf b/addons/common/functions/fnc_disableUserInput.sqf index 8db3c7e811..b89750e656 100644 --- a/addons/common/functions/fnc_disableUserInput.sqf +++ b/addons/common/functions/fnc_disableUserInput.sqf @@ -143,11 +143,7 @@ if (_state) then { _ctrl ctrlSetEventHandler ["ButtonClick", toString { closeDialog 0; - if (["ace_medical"] call FUNC(isModLoaded)) then { - [player, "respawn_button"] call EFUNC(medical_status,setDead); - } else { - player setDamage 1; - }; + [player, "respawn_button"] call FUNC(setDead); [false] call FUNC(disableUserInput); }]; diff --git a/addons/common/functions/fnc_setDead.sqf b/addons/common/functions/fnc_setDead.sqf new file mode 100644 index 0000000000..316f7346cc --- /dev/null +++ b/addons/common/functions/fnc_setDead.sqf @@ -0,0 +1,44 @@ +#include "..\script_component.hpp" +/* + * Author: johnb43 + * Kills a unit without changing visual appearance. + * + * Arguments: + * 0: Unit + * 1: Reason for death (only used if ace_medical is loaded) (default: "") + * 2: Killer (vehicle that killed unit) (default: objNull) + * 3: Instigator (unit who pulled trigger) (default: objNull) + * + * Return Value: + * None + * + * Example: + * [cursorObject, "", player, player] call ace_common_fnc_setDead; + * + * Public: Yes + */ + +params [["_unit", objNull, [objNull]], ["_reason", "", [""]], ["_source", objNull, [objNull]], ["_instigator", objNull, [objNull]]]; + +if (!local _unit) exitWith { + WARNING_1("setDead executed on non-local unit - %1",_this); +}; + +if (["ace_medical"] call EFUNC(common,isModLoaded)) then { + [_unit, _reason, _source, _instigator] call EFUNC(medical_status,setDead); +} else { + // From 'ace_medical_status_fnc_setDead': Kill the unit without changing visual appearance + + // (#8803) Reenable damage if disabled to prevent having live units in dead state + // Keep this after death event for compatibility with third party hooks + if (!isDamageAllowed _unit) then { + WARNING_1("setDead executed on unit with damage blocked - %1",_this); + _unit allowDamage true; + }; + + private _currentDamage = _unit getHitPointDamage "HitHead"; + + _unit setHitPointDamage ["HitHead", 1, true, _source, _instigator]; + + _unit setHitPointDamage ["HitHead", _currentDamage, true, _source, _instigator]; +}; diff --git a/addons/field_rations/functions/fnc_handleEffects.sqf b/addons/field_rations/functions/fnc_handleEffects.sqf index 1981cc5f99..b118f6acce 100644 --- a/addons/field_rations/functions/fnc_handleEffects.sqf +++ b/addons/field_rations/functions/fnc_handleEffects.sqf @@ -21,11 +21,7 @@ params ["_player", "_thirst", "_hunger"]; // Kill unit with max thirst or hunger if ((_thirst > 99.9 || {_hunger > 99.9}) && {random 1 < 0.5}) exitWith { - if (["ace_medical"] call EFUNC(common,isModLoaded)) then { - [_player, "Hunger/Thirst empty"] call EFUNC(medical_status,setDead); - } else { - _player setDamage 1; - }; + [_player, "Hunger/Thirst empty"] call EFUNC(common,setDead); }; // Exit if unit is not awake, below are animation based consequences diff --git a/addons/medical_status/functions/fnc_setDead.sqf b/addons/medical_status/functions/fnc_setDead.sqf index cb1e1f1d6f..138948c038 100644 --- a/addons/medical_status/functions/fnc_setDead.sqf +++ b/addons/medical_status/functions/fnc_setDead.sqf @@ -7,6 +7,7 @@ * 0: The unit * 1: Reason for death * 2: Killer + * 3: Instigator * * Return Value: * None @@ -14,9 +15,8 @@ * Public: No */ -params ["_unit", ["_reason", "#setDead"], ["_instigator", objNull]]; -TRACE_3("setDead",_unit,_reason,_instigator); - +params ["_unit", ["_reason", "#setDead"], ["_source", objNull], ["_instigator", objNull]]; +TRACE_4("setDead",_unit,_reason,_source,_instigator); // No heart rate or blood pressure to measure when dead _unit setVariable [VAR_HEART_RATE, 0, true]; @@ -38,7 +38,7 @@ if (_unitState isNotEqualTo "Dead") then { // (#8803) Reenable damage if disabled to prevent having live units in dead state // Keep this after death event for compatibility with third party hooks -if !(isDamageAllowed _unit) then { +if (!isDamageAllowed _unit) then { WARNING_1("setDead executed on unit with damage blocked - %1",_this); _unit allowDamage true; }; @@ -46,6 +46,6 @@ if !(isDamageAllowed _unit) then { // Kill the unit without changing visual apperance private _prevDamage = _unit getHitPointDamage "HitHead"; -_unit setHitPointDamage ["HitHead", 1, true, _instigator]; +_unit setHitPointDamage ["HitHead", 1, true, _source, _instigator]; -_unit setHitPointDamage ["HitHead", _prevDamage]; +_unit setHitPointDamage ["HitHead", _prevDamage, true, _source, _instigator]; From dc56cdbd8b51ef8aecddc7b9e240e2a6b38fa7af Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Fri, 31 May 2024 22:15:46 +0200 Subject: [PATCH 066/290] Vehicle Damage - Fix applying medical damage to non-local and invulnerable units (#9988) * Make medical damage apply to non-local units * Update addons/vehicle_damage/functions/fnc_medicalDamage.sqf Co-authored-by: PabstMirror * Update addons/vehicle_damage/functions/fnc_medicalDamage.sqf * Update fnc_medicalDamage.sqf * Specify reason for death --------- Co-authored-by: PabstMirror --- addons/vehicle_damage/XEH_PREP.hpp | 1 + addons/vehicle_damage/XEH_postInit.sqf | 2 + .../vehicle_damage/functions/fnc_detonate.sqf | 7 +--- .../functions/fnc_medicalDamage.sqf | 39 +++++++++++++++++++ .../functions/fnc_processHit.sqf | 8 ++-- 5 files changed, 47 insertions(+), 10 deletions(-) create mode 100644 addons/vehicle_damage/functions/fnc_medicalDamage.sqf diff --git a/addons/vehicle_damage/XEH_PREP.hpp b/addons/vehicle_damage/XEH_PREP.hpp index 524fe6ea9d..a7eb519881 100644 --- a/addons/vehicle_damage/XEH_PREP.hpp +++ b/addons/vehicle_damage/XEH_PREP.hpp @@ -11,3 +11,4 @@ PREP(knockOut); PREP(addDamage); PREP(handleDamageEjectIfDestroyed); PREP(blowOffTurret); +PREP(medicalDamage); diff --git a/addons/vehicle_damage/XEH_postInit.sqf b/addons/vehicle_damage/XEH_postInit.sqf index ce563302e3..d14770dea0 100644 --- a/addons/vehicle_damage/XEH_postInit.sqf +++ b/addons/vehicle_damage/XEH_postInit.sqf @@ -3,6 +3,8 @@ ["ace_settingsInitialized", { TRACE_1("settings init",GVAR(enabled)); if (GVAR(enabled)) then { + [QGVAR(medicalDamage), LINKFUNC(medicalDamage)] call CBA_fnc_addEventHandler; + [QGVAR(bailOut), { params ["_center", "_crewman", "_vehicle"]; TRACE_3("bailOut",_center,_crewman,_vehicle); diff --git a/addons/vehicle_damage/functions/fnc_detonate.sqf b/addons/vehicle_damage/functions/fnc_detonate.sqf index 67d64da442..feca2dd792 100644 --- a/addons/vehicle_damage/functions/fnc_detonate.sqf +++ b/addons/vehicle_damage/functions/fnc_detonate.sqf @@ -27,9 +27,6 @@ if (_vehicleAmmo isEqualTo []) then { if ((_vehicleAmmo select 1) > 0) then { { - // random amount of injuries - for "_i" from 0 to random 5 do { - [_x, random 1 , selectRandom ["Head", "Body", "LeftArm", "RightArm", "LeftLeg", "RightLeg"], selectRandom ["bullet", "shell", "explosive"], _injurer] call EFUNC(medical,addDamageToUnit); - }; - } forEach crew _vehicle; + [QGVAR(medicalDamage), [_x, _injurer, _injurer], _x] call CBA_fnc_targetEvent; + } forEach (crew _vehicle); }; diff --git a/addons/vehicle_damage/functions/fnc_medicalDamage.sqf b/addons/vehicle_damage/functions/fnc_medicalDamage.sqf new file mode 100644 index 0000000000..2aa8969644 --- /dev/null +++ b/addons/vehicle_damage/functions/fnc_medicalDamage.sqf @@ -0,0 +1,39 @@ +#include "..\script_component.hpp" +/* + * Author: johnb43 + * Applies medical damage to a unit. + * + * Arguments: + * 0: Target + * 1: Source + * 2: Instigator + * 3: Guarantee death? (default: false) + * + * Return Value: + * None + * + * Example: + * [cursorObject, player, player] call ace_vehicle_damage_fnc_medicalDamage; + * + * Public: No + */ + +params ["_unit", "_source", "_instigator", ["_guaranteeDeath", false]]; + +// Check if unit is invulnerable +if !(isDamageAllowed _unit && {_unit getVariable [QEGVAR(medical,allowDamage), true]}) exitWith {}; + +if (["ace_medical"] call EFUNC(common,isModLoaded)) then { + for "_i" from 0 to floor (4 + random 3) do { + [_unit, random [0, 0.66, 1], selectRandom ["Head", "Body", "LeftArm", "RightArm", "LeftLeg", "RightLeg"], selectRandom ["bullet", "shell", "explosive"], _instigator] call EFUNC(medical,addDamageToUnit); + }; +} else { + { + _unit setHitPointDamage [_x, (_unit getHitPointDamage _x) + random [0, 0.66, 1], true, _source, _instigator]; + } forEach ["HitFace", "HitNeck", "HitHead", "HitPelvis", "HitAbdomen", "HitDiaphragm", "HitChest", "HitBody", "HitArms", "HitHands", "HitLegs"]; +}; + +// If guaranteed death is wished +if (_guaranteeDeath && {alive _unit}) then { + [_unit, QGVAR(medicalDamage), _source, _instigator] call EFUNC(common,setDead); +}; diff --git a/addons/vehicle_damage/functions/fnc_processHit.sqf b/addons/vehicle_damage/functions/fnc_processHit.sqf index 73e70bbf57..1eb7328466 100644 --- a/addons/vehicle_damage/functions/fnc_processHit.sqf +++ b/addons/vehicle_damage/functions/fnc_processHit.sqf @@ -37,12 +37,10 @@ if (_newDamage >= 15) exitWith { TRACE_2("immediate destruction - high damage",_newDamage,_currentPartDamage); [_vehicle] call FUNC(knockOut); [_vehicle, 1] call FUNC(handleDetonation); - // kill everyone inside for very insane damage + // Kill everyone inside for very insane damage { - _x setDamage 1; - _x setVariable [QEGVAR(medical,lastDamageSource), _injurer]; - _x setVariable [QEGVAR(medical,lastInstigator), _injurer]; - } forEach crew _vehicle; + [QGVAR(medicalDamage), [_x, _injurer, _injurer, true], _x] call CBA_fnc_targetEvent; + } forEach (crew _vehicle); _vehicle setDamage 1; _return = false; _return From 1cca2db9647788abac503da2471d1f0c994eda6e Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Fri, 31 May 2024 22:20:21 +0200 Subject: [PATCH 067/290] General - Cleaned up `cbaSettings_settingChanged` (#10050) Adapted `cbaSettings_settingChanged` --- addons/artillerytables/initSettings.inc.sqf | 4 +-- addons/cargo/initSettings.inc.sqf | 24 +++++---------- addons/common/XEH_postInit.sqf | 3 ++ .../fnc_cbaSettings_settingChanged.sqf | 8 ++--- addons/cookoff/initSettings.inc.sqf | 12 ++------ addons/csw/initSettings.inc.sqf | 9 ++---- addons/fastroping/initSettings.inc.sqf | 4 +-- addons/headless/initSettings.inc.sqf | 18 +++++------ addons/interact_menu/initSettings.inc.sqf | 4 +-- addons/interaction/initSettings.inc.sqf | 2 +- addons/map/initSettings.inc.sqf | 13 ++------ addons/microdagr/initSettings.inc.sqf | 4 +-- addons/parachute/initSettings.inc.sqf | 4 +-- addons/rearm/initSettings.inc.sqf | 11 +++---- addons/refuel/initSettings.inc.sqf | 12 +++----- addons/repair/initSettings.inc.sqf | 30 +++++++------------ addons/sitting/initSettings.inc.sqf | 2 +- addons/tagging/initSettings.inc.sqf | 5 +--- addons/vehicle_damage/initSettings.inc.sqf | 4 +-- addons/vehiclelock/initSettings.inc.sqf | 3 +- addons/viewrestriction/initSettings.inc.sqf | 10 +++---- addons/volume/initSettings.inc.sqf | 24 ++------------- addons/weaponselect/initSettings.inc.sqf | 4 +-- addons/weather/initSettings.inc.sqf | 3 +- 24 files changed, 67 insertions(+), 150 deletions(-) diff --git a/addons/artillerytables/initSettings.inc.sqf b/addons/artillerytables/initSettings.inc.sqf index 762010b2ca..f34190f910 100644 --- a/addons/artillerytables/initSettings.inc.sqf +++ b/addons/artillerytables/initSettings.inc.sqf @@ -15,7 +15,5 @@ private _categoryName = [format ["ACE %1", localize "str_a3_cfgmarkers_nato_art" [LSTRING(disableArtilleryComputer_displayName), LSTRING(disableArtilleryComputer_description)], _categoryName, false, // default value - true, // isGlobal - {[QGVAR(disableArtilleryComputer), _this] call EFUNC(common,cbaSettings_settingChanged)}, - false // Needs mission restart + true // isGlobal ] call CBA_fnc_addSetting; diff --git a/addons/cargo/initSettings.inc.sqf b/addons/cargo/initSettings.inc.sqf index 029a845a25..4f92934d46 100644 --- a/addons/cargo/initSettings.inc.sqf +++ b/addons/cargo/initSettings.inc.sqf @@ -6,8 +6,7 @@ private _category = [ELSTRING(main,Category_Logistics), LSTRING(openMenu)]; [LSTRING(ModuleSettings_enable), LSTRING(ModuleSettings_enable_Description)], _category, true, - 1, - {[QGVAR(enable), _this] call EFUNC(common,cbaSettings_settingChanged)} + 1 ] call CBA_fnc_addSetting; [ @@ -16,8 +15,7 @@ private _category = [ELSTRING(main,Category_Logistics), LSTRING(openMenu)]; [LSTRING(loadTimeCoefficient), LSTRING(loadTimeCoefficient_description)], _category, [0, 10, 5, 1], - 1, - {[QGVAR(loadTimeCoefficient), _this, true] call EFUNC(common,cbaSettings_settingChanged)} + 1 ] call CBA_fnc_addSetting; [ @@ -26,8 +24,7 @@ private _category = [ELSTRING(main,Category_Logistics), LSTRING(openMenu)]; [LSTRING(paradropTimeCoefficent), LSTRING(paradropTimeCoefficent_description)], _category, [0, 10, 2.5, 1], - 1, - {[QGVAR(paradropTimeCoefficent), _this, true] call EFUNC(common,cbaSettings_settingChanged)} + 1 ] call CBA_fnc_addSetting; [ @@ -35,9 +32,7 @@ private _category = [ELSTRING(main,Category_Logistics), LSTRING(openMenu)]; "LIST", [LSTRING(openAfterUnload), LSTRING(openAfterUnload_description)], _category, - [[0, 1, 2, 3], [ELSTRING(common,never), LSTRING(unloadObject), LSTRING(paradropButton), ELSTRING(common,both)], 0], - 0, - {[QGVAR(openAfterUnload), _this, true] call EFUNC(common,cbaSettings_settingChanged)} + [[0, 1, 2, 3], [ELSTRING(common,never), LSTRING(unloadObject), LSTRING(paradropButton), ELSTRING(common,both)], 0] ] call CBA_fnc_addSetting; [ @@ -45,9 +40,7 @@ private _category = [ELSTRING(main,Category_Logistics), LSTRING(openMenu)]; "CHECKBOX", [LSTRING(carryAfterUnload), LSTRING(carryAfterUnload_description)], _category, - true, - 0, - {[QGVAR(carryAfterUnload), _this] call EFUNC(common,cbaSettings_settingChanged)} + true ] call CBA_fnc_addSetting; [ @@ -56,8 +49,7 @@ private _category = [ELSTRING(main,Category_Logistics), LSTRING(openMenu)]; [LSTRING(enableDeploy), LSTRING(enableDeploy_description)], _category, true, - 1, - {[QGVAR(enableDeploy), _this] call EFUNC(common,cbaSettings_settingChanged)} + 1 ] call CBA_fnc_addSetting; [ @@ -65,7 +57,5 @@ private _category = [ELSTRING(main,Category_Logistics), LSTRING(openMenu)]; "CHECKBOX", [LSTRING(ModuleSettings_enableRename), LSTRING(ModuleSettings_enableRename_Description)], _category, - true, - 0, - {[QGVAR(enableRename), _this, true] call EFUNC(common,cbaSettings_settingChanged)} + true ] call CBA_fnc_addSetting; diff --git a/addons/common/XEH_postInit.sqf b/addons/common/XEH_postInit.sqf index f97009808f..9b11ec49e6 100644 --- a/addons/common/XEH_postInit.sqf +++ b/addons/common/XEH_postInit.sqf @@ -222,6 +222,9 @@ if (isServer) then { [QGVAR(claimSafe), LINKFUNC(claimSafeServer)] call CBA_fnc_addEventHandler; }; +["CBA_SettingChanged", { + ["ace_settingChanged", _this] call CBA_fnc_localEvent; +}] call CBA_fnc_addEventHandler; ////////////////////////////////////////////////// // Set up remote execution diff --git a/addons/common/functions/fnc_cbaSettings_settingChanged.sqf b/addons/common/functions/fnc_cbaSettings_settingChanged.sqf index 43711d4c97..cf9f18166a 100644 --- a/addons/common/functions/fnc_cbaSettings_settingChanged.sqf +++ b/addons/common/functions/fnc_cbaSettings_settingChanged.sqf @@ -1,8 +1,8 @@ #include "..\script_component.hpp" /* * Author: PabstMirror - * Function for handeling a cba setting being changed. - * Adds warning if global setting is changed after ace_settingsInitialized + * Function for handling a cba setting being changed. + * Adds warning if global setting is changed after ace_settingsInitialized. * * Arguments: * 0: Setting Name @@ -21,9 +21,7 @@ params ["_settingName", "_newValue", ["_canBeChanged", false]]; TRACE_2("",_settingName,_newValue); -["ace_settingChanged", [_settingName, _newValue]] call CBA_fnc_localEvent; - -if (!((toLower _settingName) in CBA_settings_needRestart)) exitWith {}; +if !((toLower _settingName) in CBA_settings_needRestart) exitWith {}; if (_canBeChanged) exitWith {WARNING_1("update cba setting [%1] to use correct Need Restart param",_settingName);}; if (!GVAR(settingsInitFinished)) exitWith {}; // Ignore changed event before CBA_settingsInitialized diff --git a/addons/cookoff/initSettings.inc.sqf b/addons/cookoff/initSettings.inc.sqf index 8912636fd6..47f4681365 100644 --- a/addons/cookoff/initSettings.inc.sqf +++ b/addons/cookoff/initSettings.inc.sqf @@ -13,9 +13,7 @@ [LSTRING(enableFire_name), LSTRING(enableFire_tooltip)], LSTRING(category_displayName), true, // default value - true, // isGlobal - {[QGVAR(enableFire), _this] call EFUNC(common,cbaSettings_settingChanged)}, - false // Needs mission restart + true // isGlobal ] call CBA_fnc_addSetting; [ @@ -23,9 +21,7 @@ [LSTRING(destroyVehicleAfterCookoff_name), LSTRING(destroyVehicleAfterCookoff_tooltip)], LSTRING(category_displayName), false, // default value - true, // isGlobal - {[QGVAR(destroyVehicleAfterCookoff), _this] call EFUNC(common,cbaSettings_settingChanged)}, - false // Needs mission restart + true // isGlobal ] call CBA_fnc_addSetting; [ @@ -33,9 +29,7 @@ [LSTRING(enableAmmoCookoff_name), LSTRING(enableAmmoCookoff_tooltip)], LSTRING(category_displayName), true, // default value - true, // isGlobal - {[QGVAR(enableAmmoCookoff), _this] call EFUNC(common,cbaSettings_settingChanged)}, - false // Needs mission restart + true // isGlobal ] call CBA_fnc_addSetting; [ diff --git a/addons/csw/initSettings.inc.sqf b/addons/csw/initSettings.inc.sqf index de3976896b..bc157e1164 100644 --- a/addons/csw/initSettings.inc.sqf +++ b/addons/csw/initSettings.inc.sqf @@ -45,17 +45,12 @@ private _categoryArray = [format ["ACE %1", localize LSTRING(DisplayName)]]; [LSTRING(progressBarTimeCoefficent_displayName), LSTRING(progressBarTimeCoefficent_description)], _categoryArray, [0,2,1,2], // [min, max, default value, trailing decimals (-1 for whole numbers only)] - true, // isGlobal - {[QGVAR(progressBarTimeCoefficent), _this] call EFUNC(common,cbaSettings_settingChanged)}, - false // Needs mission restart + true // isGlobal ] call CBA_fnc_addSetting; [ QGVAR(dragAfterDeploy), "CHECKBOX", [LSTRING(dragAfterDeploy_displayName), LSTRING(dragAfterDeploy_description)], _categoryArray, - false, // default value - false, // isGlobal - {[QGVAR(dragAfterDeploy), _this] call EFUNC(common,cbaSettings_settingChanged)}, - false // Needs mission restart + false // default value ] call CBA_fnc_addSetting; diff --git a/addons/fastroping/initSettings.inc.sqf b/addons/fastroping/initSettings.inc.sqf index 844de927a2..cde4a32b47 100644 --- a/addons/fastroping/initSettings.inc.sqf +++ b/addons/fastroping/initSettings.inc.sqf @@ -5,9 +5,7 @@ private _category = [LELSTRING(common,categoryUncategorized), LLSTRING(setting_c [LSTRING(setting_requireRopeItems_displayName)], _category, false, // default value - true, // isGlobal - {[QGVAR(requireRopeItems), _this] call EFUNC(common,cbaSettings_settingChanged)}, - false // needRestart + true // isGlobal ] call CBA_fnc_addSetting; [ diff --git a/addons/headless/initSettings.inc.sqf b/addons/headless/initSettings.inc.sqf index d00cb6eb30..ec720fce7c 100644 --- a/addons/headless/initSettings.inc.sqf +++ b/addons/headless/initSettings.inc.sqf @@ -5,8 +5,8 @@ format ["ACE %1", LLSTRING(Module)], false, 1, - {[QGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged)}, - true + {[QXGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart ] call CBA_fnc_addSetting; [ @@ -15,8 +15,7 @@ [LSTRING(Delay), LSTRING(DelayDesc)], format ["ACE %1", LLSTRING(Module)], [0, 60, 15, -1], - 1, - {[QGVAR(delay), _this] call EFUNC(common,cbaSettings_settingChanged)} + 1 ] call CBA_fnc_addSetting; [ @@ -26,8 +25,8 @@ format ["ACE %1", LLSTRING(Module)], [[0, 1, 2], [ELSTRING(Common,Disabled), LSTRING(Instant), LSTRING(Delayed)], 0], 1, - {[QGVAR(delay), _this] call EFUNC(common,cbaSettings_settingChanged)}, - true + {[QXGVAR(endMission), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart ] call CBA_fnc_addSetting; [ @@ -36,8 +35,7 @@ [LSTRING(Log), LSTRING(LogDesc)], format ["ACE %1", LLSTRING(Module)], false, - 1, - {[QGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged)} + 1 ] call CBA_fnc_addSetting; [ @@ -47,6 +45,6 @@ format ["ACE %1", LLSTRING(Module)], [[0, 1, 2], [ELSTRING(Common,Disabled), LSTRING(TransferLoadoutCurrent), LSTRING(TransferLoadoutConfig)], 0], 1, - {}, - true // needs mission restart + {[QXGVAR(transferLoadout), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart ] call CBA_fnc_addSetting; diff --git a/addons/interact_menu/initSettings.inc.sqf b/addons/interact_menu/initSettings.inc.sqf index 22287189c3..c175bd17c2 100644 --- a/addons/interact_menu/initSettings.inc.sqf +++ b/addons/interact_menu/initSettings.inc.sqf @@ -46,9 +46,7 @@ private _categoryColors = [_category, format ["| %1 |", LELSTRING(common,subcate QGVAR(textSize), "LIST", LSTRING(textSize), _category, - [[0, 1, 2, 3, 4], ["str_very_small", "str_small", "str_medium", "str_large", "str_very_large"], 2], - 0, - {[QGVAR(textSize), _this] call EFUNC(common,cbaSettings_settingChanged)} + [[0, 1, 2, 3, 4], ["str_very_small", "str_small", "str_medium", "str_large", "str_very_large"], 2] ] call CBA_fnc_addSetting; [ diff --git a/addons/interaction/initSettings.inc.sqf b/addons/interaction/initSettings.inc.sqf index b502ed36b0..2cefb162a7 100644 --- a/addons/interaction/initSettings.inc.sqf +++ b/addons/interaction/initSettings.inc.sqf @@ -20,7 +20,7 @@ false, true, {[QGVAR(disableNegativeRating), _this] call EFUNC(common,cbaSettings_settingChanged)}, - true + true // Needs mission restart ] call CBA_fnc_addSetting; [ diff --git a/addons/map/initSettings.inc.sqf b/addons/map/initSettings.inc.sqf index 8de301eaa1..20665b5a71 100644 --- a/addons/map/initSettings.inc.sqf +++ b/addons/map/initSettings.inc.sqf @@ -67,14 +67,11 @@ false, true, { - [QGVAR(BFT_Enabled), _this] call EFUNC(common,cbaSettings_settingChanged); - if (GVAR(BFT_Enabled) && {isNil QGVAR(BFT_markers)}) then { GVAR(BFT_markers) = []; [LINKFUNC(blueForceTrackingUpdate), GVAR(BFT_Interval), []] call CBA_fnc_addPerFrameHandler; }; - }, - false + } ] call CBA_fnc_addSetting; [ @@ -94,9 +91,7 @@ [localize LSTRING(BFT_ShowPlayerNames_DisplayName), localize LSTRING(BFT_ShowPlayerNames_Description)], [format ["ACE %1", localize LSTRING(Module_DisplayName)], localize LSTRING(BFT_Module_DisplayName)], false, - true, - {[QGVAR(BFT_ShowPlayerNames), _this] call EFUNC(common,cbaSettings_settingChanged)}, - false + true ] call CBA_fnc_addSetting; [ @@ -105,7 +100,5 @@ [localize LSTRING(BFT_HideAiGroups_DisplayName), localize LSTRING(BFT_HideAiGroups_Description)], [format ["ACE %1", localize LSTRING(Module_DisplayName)], localize LSTRING(BFT_Module_DisplayName)], false, - true, - {[QGVAR(BFT_HideAiGroups), _this] call EFUNC(common,cbaSettings_settingChanged)}, - false + true ] call CBA_fnc_addSetting; diff --git a/addons/microdagr/initSettings.inc.sqf b/addons/microdagr/initSettings.inc.sqf index 8810939302..aacc5fd24b 100644 --- a/addons/microdagr/initSettings.inc.sqf +++ b/addons/microdagr/initSettings.inc.sqf @@ -15,7 +15,5 @@ private _category = [LELSTRING(common,categoryUncategorized), LLSTRING(itemName) [LSTRING(WaypointPrecision_DisplayName), LSTRING(WaypointPrecision_Description)], _category, [[1, 2, 3], [LSTRING(WaypointPrecision_medium), LSTRING(WaypointPrecision_close), LSTRING(WaypointPrecision_exact)], 2], // [values, titles, defaultIndex] - true, // isGlobal - {[QGVAR(waypointPrecision), _this] call EFUNC(common,cbaSettings_settingChanged)}, - false // require mission restart + true // isGlobal ] call CBA_fnc_addSetting; diff --git a/addons/parachute/initSettings.inc.sqf b/addons/parachute/initSettings.inc.sqf index 0cfc3f8ca0..0c6804cff7 100644 --- a/addons/parachute/initSettings.inc.sqf +++ b/addons/parachute/initSettings.inc.sqf @@ -5,9 +5,7 @@ private _category = [LELSTRING(common,categoryUncategorized), localize "str_dn_p "CHECKBOX", [LSTRING(HideAltimeter), LSTRING(HideAltimeter_tooltip)], _category, - true, - false, - {[QGVAR(hideAltimeter), _this, false] call EFUNC(common,cbaSettings_settingChanged)} + true ] call CBA_fnc_addSetting; [ diff --git a/addons/rearm/initSettings.inc.sqf b/addons/rearm/initSettings.inc.sqf index 37535d8d90..6489bd9326 100644 --- a/addons/rearm/initSettings.inc.sqf +++ b/addons/rearm/initSettings.inc.sqf @@ -7,7 +7,7 @@ private _category = [ELSTRING(main,Category_Logistics), LLSTRING(DisplayName)]; true, true, {[QGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged)}, - true + true // Needs mission restart ] call CBA_fnc_addSetting; [ @@ -15,8 +15,7 @@ private _category = [ELSTRING(main,Category_Logistics), LLSTRING(DisplayName)]; [LSTRING(RearmSettings_level_DisplayName), LSTRING(RearmSettings_level_Description)], _category, [[0,1,2],[LSTRING(RearmSettings_vehicle), LSTRING(RearmSettings_magazine), LSTRING(RearmSettings_caliber)],0], // [values, titles, defaultIndex] - true, // isGlobal - {[QGVAR(level), _this] call EFUNC(common,cbaSettings_settingChanged)} + true // isGlobal ] call CBA_fnc_addSetting; [ @@ -24,8 +23,7 @@ private _category = [ELSTRING(main,Category_Logistics), LLSTRING(DisplayName)]; [LSTRING(RearmSettings_supply_DisplayName), LSTRING(RearmSettings_supply_Description)], _category, [[0,1,2],[LSTRING(RearmSettings_unlimited), LSTRING(RearmSettings_limited), LSTRING(RearmSettings_magazineSupply)],0], // [values, titles, defaultIndex] - true, // isGlobal - {[QGVAR(supply), _this] call EFUNC(common,cbaSettings_settingChanged)} + true // isGlobal ] call CBA_fnc_addSetting; [ @@ -33,6 +31,5 @@ private _category = [ELSTRING(main,Category_Logistics), LLSTRING(DisplayName)]; [LLSTRING(RearmSettings_distance_DisplayName), LLSTRING(RearmSettings_distance_Description)], _category, [10, 50, 20, 0], - true, // isGlobal - {[QGVAR(supply), _this] call EFUNC(common,cbaSettings_settingChanged)} + true // isGlobal ] call CBA_fnc_addSetting; diff --git a/addons/refuel/initSettings.inc.sqf b/addons/refuel/initSettings.inc.sqf index 44df66334f..2888ad190c 100644 --- a/addons/refuel/initSettings.inc.sqf +++ b/addons/refuel/initSettings.inc.sqf @@ -15,8 +15,7 @@ private _category = [ELSTRING(main,Category_Logistics), "str_state_refuel"]; [LSTRING(RefuelSettings_speed_DisplayName), LSTRING(RefuelSettings_speed_Description)], _category, [0,25,1,1], // [min, max, default value, trailing decimals (-1 for whole numbers only)] - true, // isGlobal - {[QGVAR(rate), _this] call EFUNC(common,cbaSettings_settingChanged)} + true // isGlobal ] call CBA_fnc_addSetting; [ @@ -24,8 +23,7 @@ private _category = [ELSTRING(main,Category_Logistics), "str_state_refuel"]; [LSTRING(RefuelSettings_speedCargo_DisplayName), LSTRING(RefuelSettings_speedCargo_Description)], _category, [0,250,10,1], // [min, max, default value, trailing decimals (-1 for whole numbers only)] - true, // isGlobal - {[QGVAR(cargoRate), _this] call EFUNC(common,cbaSettings_settingChanged)} + true // isGlobal ] call CBA_fnc_addSetting; [ @@ -33,8 +31,7 @@ private _category = [ELSTRING(main,Category_Logistics), "str_state_refuel"]; [LSTRING(RefuelSettings_hoseLength_DisplayName)], _category, [0,50,12,1], // [min, max, default value, trailing decimals (-1 for whole numbers only)] - true, // isGlobal - {[QGVAR(hoseLength), _this] call EFUNC(common,cbaSettings_settingChanged)} + true // isGlobal ] call CBA_fnc_addSetting; [ @@ -42,6 +39,5 @@ private _category = [ELSTRING(main,Category_Logistics), "str_state_refuel"]; [LSTRING(RefuelSettings_progressDuration_DisplayName), LSTRING(RefuelSettings_progressDuration_Description)], _category, [0, 10, 2], // [min, max, default value] - true, // isGlobal - {[QGVAR(progressDuration), _this] call EFUNC(common,cbaSettings_settingChanged)} + true // isGlobal ] call CBA_fnc_addSetting; diff --git a/addons/repair/initSettings.inc.sqf b/addons/repair/initSettings.inc.sqf index 26d502e757..e39bb93a76 100644 --- a/addons/repair/initSettings.inc.sqf +++ b/addons/repair/initSettings.inc.sqf @@ -8,16 +8,14 @@ private _catFullRepair = [_category, LLSTRING(fullRepair)]; true, true, {[QGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged)}, - true + true // Needs mission restart ] call CBA_fnc_addSetting; [ QGVAR(displayTextOnRepair), "CHECKBOX", [LSTRING(SettingDisplayTextName), LSTRING(SettingDisplayTextDesc)], _category, - true, // default value - false, // isGlobal - {[QGVAR(displayTextOnRepair), _this] call EFUNC(common,cbaSettings_settingChanged)} + true // default value ] call CBA_fnc_addSetting; [ @@ -25,8 +23,7 @@ private _catFullRepair = [_category, LLSTRING(fullRepair)]; [LSTRING(engineerSetting_Repair_name), LSTRING(engineerSetting_Repair_description)], _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)} + true // isGlobal ] call CBA_fnc_addSetting; [ @@ -34,8 +31,7 @@ private _catFullRepair = [_category, LLSTRING(fullRepair)]; [LSTRING(engineerSetting_Wheel_name), LSTRING(engineerSetting_Wheel_description)], _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)} + true // isGlobal ] call CBA_fnc_addSetting; [ @@ -69,8 +65,7 @@ private _catFullRepair = [_category, LLSTRING(fullRepair)]; [LSTRING(repairDamageThreshold_name), LSTRING(repairDamageThreshold_description)], _category, [0, 1, 0.6, 1, true], - true, // isGlobal - {[QGVAR(repairDamageThreshold), _this] call EFUNC(common,cbaSettings_settingChanged)} + true // isGlobal ] call CBA_fnc_addSetting; [ @@ -78,8 +73,7 @@ private _catFullRepair = [_category, LLSTRING(fullRepair)]; [LSTRING(repairDamageThreshold_Engineer_name), LSTRING(repairDamageThreshold_Engineer_description)], _category, [0, 1, 0.4, 1, true], - true, // isGlobal - {[QGVAR(repairDamageThreshold_engineer), _this] call EFUNC(common,cbaSettings_settingChanged)} + true // isGlobal ] call CBA_fnc_addSetting; [ @@ -87,8 +81,7 @@ private _catFullRepair = [_category, LLSTRING(fullRepair)]; [LSTRING(consumeItem_ToolKit_name), LSTRING(consumeItem_ToolKit_description)], _category, [[0,1],[ELSTRING(common,No), ELSTRING(common,Yes)],0], // [values, titles, defaultIndex] - true, // isGlobal - {[QGVAR(consumeItem_toolKit), _this] call EFUNC(common,cbaSettings_settingChanged)} + true // isGlobal ] call CBA_fnc_addSetting; [ @@ -105,8 +98,7 @@ private _catFullRepair = [_category, LLSTRING(fullRepair)]; [LSTRING(fullRepairLocation), LSTRING(fullRepairLocation_description)], _catFullRepair, [[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)} + true // isGlobal ] call CBA_fnc_addSetting; [ @@ -114,8 +106,7 @@ private _catFullRepair = [_category, LLSTRING(fullRepair)]; [LSTRING(engineerSetting_fullRepair_name), LSTRING(engineerSetting_fullRepair_description)], _catFullRepair, [[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)} + true // isGlobal ] call CBA_fnc_addSetting; [ @@ -168,8 +159,7 @@ private _catFullRepair = [_category, LLSTRING(fullRepair)]; [LSTRING(autoShutOffEngineWhenStartingRepair_name), LSTRING(autoShutOffEngineWhenStartingRepair_description)], _category, false, // default value - true, // isGlobal - {[QGVAR(autoShutOffEngineWhenStartingRepair), _this] call EFUNC(common,cbaSettings_settingChanged)} + true // isGlobal ] call CBA_fnc_addSetting; [ diff --git a/addons/sitting/initSettings.inc.sqf b/addons/sitting/initSettings.inc.sqf index 744c188e9f..ee1af1ec8e 100644 --- a/addons/sitting/initSettings.inc.sqf +++ b/addons/sitting/initSettings.inc.sqf @@ -6,5 +6,5 @@ true, true, {[QGVAR(enable), _this] call EFUNC(common,cbaSettings_settingChanged)}, - true + true // Needs mission restart ] call CBA_fnc_addSetting; diff --git a/addons/tagging/initSettings.inc.sqf b/addons/tagging/initSettings.inc.sqf index 4fc35b83d1..e05146c081 100644 --- a/addons/tagging/initSettings.inc.sqf +++ b/addons/tagging/initSettings.inc.sqf @@ -4,8 +4,5 @@ private _category = [LELSTRING(common,categoryUncategorized), LLSTRING(Tagging)] QGVAR(quickTag), "LIST", [LLSTRING(QuickTag), LLSTRING(QuickTagDesc)], _category, - [[0,1,2,3], [LELSTRING(Common,Disabled), LLSTRING(LastUsed), LLSTRING(RandomX), LLSTRING(Random)], 1], // [values, titles, defaultIndex] - false, // isGlobal - {[QGVAR(quickTag), _this] call EFUNC(common,cbaSettings_settingChanged)}, - false // Needs mission restart + [[0,1,2,3], [LELSTRING(Common,Disabled), LLSTRING(LastUsed), LLSTRING(RandomX), LLSTRING(Random)], 1] // [values, titles, defaultIndex] ] call CBA_fnc_addSetting; diff --git a/addons/vehicle_damage/initSettings.inc.sqf b/addons/vehicle_damage/initSettings.inc.sqf index ae322a6fd8..5841145cf9 100644 --- a/addons/vehicle_damage/initSettings.inc.sqf +++ b/addons/vehicle_damage/initSettings.inc.sqf @@ -13,9 +13,7 @@ [LSTRING(removeAmmoAfterCookoff_setting_enable), LSTRING(removeAmmoAfterCookoff_setting_description)], LSTRING(category_displayName), true, // default value - true, // isGlobal - {[QGVAR(removeAmmoDuringCookoff), _this] call EFUNC(common,cbaSettings_settingChanged)}, - false // Needs mission restart + true // isGlobal ] call CBA_settings_fnc_init; [ diff --git a/addons/vehiclelock/initSettings.inc.sqf b/addons/vehiclelock/initSettings.inc.sqf index 9f68c77e7c..dcb520e7e2 100644 --- a/addons/vehiclelock/initSettings.inc.sqf +++ b/addons/vehiclelock/initSettings.inc.sqf @@ -3,8 +3,7 @@ [LSTRING(DefaultLockpickStrength_DisplayName), LSTRING(DefaultLockpickStrength_Description)], LSTRING(DisplayName), [-1,60,10,1], // [min, max, default value, trailing decimals (-1 for whole numbers only)] - true, // isGlobal - {[QGVAR(defaultLockpickStrength), _this] call EFUNC(common,cbaSettings_settingChanged)} + true // isGlobal ] call CBA_fnc_addSetting; [ diff --git a/addons/viewrestriction/initSettings.inc.sqf b/addons/viewrestriction/initSettings.inc.sqf index 3ed47c10ef..80382f5b19 100644 --- a/addons/viewrestriction/initSettings.inc.sqf +++ b/addons/viewrestriction/initSettings.inc.sqf @@ -6,7 +6,7 @@ [[0, 1, 2, 3], [LSTRING(Disabled), LSTRING(FirstPerson), LSTRING(ThirdPerson), LSTRING(Selective)], 0], true, {[QGVAR(mode), _this] call EFUNC(common,cbaSettings_settingChanged)}, - true + true // Needs mission restart ] call CBA_fnc_addSetting; [ @@ -17,7 +17,7 @@ [[0, 1, 2], [LSTRING(Disabled), LSTRING(FirstPerson), LSTRING(ThirdPerson)], 0], true, {[QGVAR(modeSelectiveFoot), _this] call EFUNC(common,cbaSettings_settingChanged)}, - true + true // Needs mission restart ] call CBA_fnc_addSetting; [ @@ -28,7 +28,7 @@ [[0, 1, 2], [LSTRING(Disabled), LSTRING(FirstPerson), LSTRING(ThirdPerson)], 0], true, {[QGVAR(modeSelectiveLand), _this] call EFUNC(common,cbaSettings_settingChanged)}, - true + true // Needs mission restart ] call CBA_fnc_addSetting; [ @@ -39,7 +39,7 @@ [[0, 1, 2], [LSTRING(Disabled), LSTRING(FirstPerson), LSTRING(ThirdPerson)], 0], true, {[QGVAR(modeSelectiveAir), _this] call EFUNC(common,cbaSettings_settingChanged)}, - true + true // Needs mission restart ] call CBA_fnc_addSetting; [ @@ -50,7 +50,7 @@ [[0, 1, 2], [LSTRING(Disabled), LSTRING(FirstPerson), LSTRING(ThirdPerson)], 0], true, {[QGVAR(modeSelectiveSea), _this] call EFUNC(common,cbaSettings_settingChanged)}, - true + true // Needs mission restart ] call CBA_fnc_addSetting; [ diff --git a/addons/volume/initSettings.inc.sqf b/addons/volume/initSettings.inc.sqf index 8735f81527..44bb464a1e 100644 --- a/addons/volume/initSettings.inc.sqf +++ b/addons/volume/initSettings.inc.sqf @@ -3,9 +3,6 @@ "CHECKBOX", [ELSTRING(common,Enabled), LSTRING(KeybindDescription)], format ["ACE %1", LLSTRING(Name)], - false, - false, - {[QGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged)}, false ] call CBA_fnc_addSetting; @@ -14,10 +11,7 @@ "LIST", [LSTRING(Reduction), LSTRING(ReductionDescription)], format ["ACE %1", LLSTRING(Name)], - [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], ["0%", "10%", "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%", "100%"], 5], - false, - {[QGVAR(reduction), _this] call EFUNC(common,cbaSettings_settingChanged)}, - false + [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], ["0%", "10%", "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%", "100%"], 5] ] call CBA_fnc_addSetting; [ @@ -25,10 +19,7 @@ "LIST", [LSTRING(FadeDelay), LSTRING(FadeDelayDescription)], format ["ACE %1", LLSTRING(Name)], - [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], ["0s", "1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s", "9s", "10s"], 1], - false, - {[QGVAR(fadeDelay), _this] call EFUNC(common,cbaSettings_settingChanged)}, - false + [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], ["0s", "1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s", "9s", "10s"], 1] ] call CBA_fnc_addSetting; [ @@ -36,9 +27,6 @@ "CHECKBOX", [LSTRING(LowerInVehicles), LSTRING(LowerInVehiclesDescription)], format ["ACE %1", LLSTRING(Name)], - false, - false, - {[QGVAR(lowerInVehicles), _this] call EFUNC(common,cbaSettings_settingChanged)}, false ] call CBA_fnc_addSetting; @@ -47,10 +35,7 @@ "CHECKBOX", [LSTRING(ShowNotification), LSTRING(ShowNotificationDescription)], format ["ACE %1", LLSTRING(Name)], - true, - false, - {[QGVAR(showNotification), _this] call EFUNC(common,cbaSettings_settingChanged)}, - false + true ] call CBA_fnc_addSetting; [ @@ -58,8 +43,5 @@ "CHECKBOX", [LSTRING(RemindIfLowered), LSTRING(RemindIfLoweredDescription)], format ["ACE %1", LLSTRING(Name)], - false, - false, - {[QGVAR(remindIfLowered), _this] call EFUNC(common,cbaSettings_settingChanged)}, false ] call CBA_fnc_addSetting; diff --git a/addons/weaponselect/initSettings.inc.sqf b/addons/weaponselect/initSettings.inc.sqf index 029c5201cb..f5695748b4 100644 --- a/addons/weaponselect/initSettings.inc.sqf +++ b/addons/weaponselect/initSettings.inc.sqf @@ -2,7 +2,5 @@ QGVAR(displayText), "CHECKBOX", [LSTRING(SettingDisplayTextName), LSTRING(SettingDisplayTextDesc)], ELSTRING(common,ACEKeybindCategoryWeapons), - true, // default value - false, // isGlobal - {[QGVAR(displayText), _this] call EFUNC(common,cbaSettings_settingChanged)} + true // default value ] call CBA_fnc_addSetting; diff --git a/addons/weather/initSettings.inc.sqf b/addons/weather/initSettings.inc.sqf index fb11e31e75..26f4442084 100644 --- a/addons/weather/initSettings.inc.sqf +++ b/addons/weather/initSettings.inc.sqf @@ -34,6 +34,5 @@ private _category = [format ["ACE %1", LLSTRING(Module_DisplayName)]]; QGVAR(showCheckAirTemperature), "CHECKBOX", [LSTRING(showCheckAirTemperature_DisplayName), LELSTRING(common,showActionInSelfInteraction)], _category, - true, // default value - false // isGlobal + true // default value ] call CBA_fnc_addSetting; From 99bb6983bb0fe67269e2762c589ca505b3ec5c8f Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 1 Jun 2024 18:52:18 +0200 Subject: [PATCH 068/290] Common - Improve `addWeapon` (#10051) Improve `addWeapon` --- addons/common/functions/fnc_addWeapon.sqf | 48 +++++++++++++++++++++-- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/addons/common/functions/fnc_addWeapon.sqf b/addons/common/functions/fnc_addWeapon.sqf index 16ae92c4f5..787c9fb24a 100644 --- a/addons/common/functions/fnc_addWeapon.sqf +++ b/addons/common/functions/fnc_addWeapon.sqf @@ -2,22 +2,33 @@ /* * Author: commy2, johnb43 * Adds weapon to unit without taking a magazine. - * Same as CBA_fnc_addWeaponWithoutItems, but doesn't remove linked items. + * Same as CBA_fnc_addWeaponWithoutItems, but doesn't remove linked items by default. * * Arguments: - * 0: Unit to add the weapon to + * 0: Unit to add the weapon to * 1: Weapon to add + * 2: If linked items should be removed or not (default: false) + * 3: Magazines that should be added to the weapon (default: []) + * - 0: Magazine classname + * - 1: Ammo count * * Return Value: * None * * Example: - * [player, "arifle_AK12_F"] call ace_common_fnc_addWeapon + * [player, "arifle_MX_GL_F", true, [["30Rnd_65x39_caseless_mag", 30], ["1Rnd_HE_Grenade_shell", 1]]] call ace_common_fnc_addWeapon * * Public: Yes */ -params ["_unit", "_weapon"]; +params [ + ["_unit", objNull, [objNull]], + ["_weapon", "", [""]], + ["_removeLinkedItems", false, [false]], + ["_magazines", [], [[]]] +]; + +if (isNull _unit || {_weapon == ""}) exitWith {}; // Config case private _compatibleMagazines = compatibleMagazines _weapon; @@ -45,6 +56,35 @@ private _backpackMagazines = (magazinesAmmoCargo _backpack) select { // Add weapon _unit addWeapon _weapon; +// This doesn't remove magazines, but linked items can't be magazines, so it's fine +if (_removeLinkedItems) then { + switch (_weapon call FUNC(getConfigName)) do { + case (primaryWeapon _unit): { + removeAllPrimaryWeaponItems _unit; + }; + case (secondaryWeapon _unit): { + removeAllSecondaryWeaponItems _unit; + }; + case (handgunWeapon _unit): { + removeAllHandgunItems _unit; + }; + case (binocular _unit): { + removeAllBinocularItems _unit; + }; + }; +}; + +// Add magazines directly now, so that AI don't reload +if (_magazines isNotEqualTo []) then { + { + _x params [["_magazine", "", [""]], ["_ammoCount", -1, [0]]]; + + if (_magazine != "" && {_ammoCount > -1}) then { + _unit addWeaponItem [_weapon, [_magazine, _ammoCount], true]; + }; + } forEach _magazines; +}; + // Add all magazines back { _uniform addMagazineAmmoCargo [_x select 0, 1, _x select 1]; From 60eabda47e16c660911a0a98327ace33359f0e75 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 1 Jun 2024 18:55:56 +0200 Subject: [PATCH 069/290] Vehicle Damage - Add API to prevent AI from dismounting from immobile vehicles (#9990) * Add API to prevent AI from dismounting from immobile vehicles * Update vehicledamage-framework.md --- addons/vehicle_damage/functions/fnc_abandon.sqf | 2 ++ docs/wiki/framework/vehicledamage-framework.md | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/addons/vehicle_damage/functions/fnc_abandon.sqf b/addons/vehicle_damage/functions/fnc_abandon.sqf index 6a9d4eeb29..83b06a80df 100644 --- a/addons/vehicle_damage/functions/fnc_abandon.sqf +++ b/addons/vehicle_damage/functions/fnc_abandon.sqf @@ -18,6 +18,8 @@ params ["_vehicle"]; TRACE_2("abandon",_vehicle,(crew _vehicle) select {alive _x}); +if (_vehicle getVariable [QGVAR(allowCrewInImmobile), false]) exitWith {}; // check for API + [{ params ["_vehicle"]; _vehicle allowCrewInImmobile false; diff --git a/docs/wiki/framework/vehicledamage-framework.md b/docs/wiki/framework/vehicledamage-framework.md index 7e22bccf5d..ac94bd30fb 100644 --- a/docs/wiki/framework/vehicledamage-framework.md +++ b/docs/wiki/framework/vehicledamage-framework.md @@ -126,3 +126,11 @@ Default ARMA config value. We assume that the warheads are vanilla strings, so o - `TandemHEAT` If no `ace_vehicle_damage_incendiary` defined, this value will be used to assume a default based on above table of common values (excluding `Incendiary Bullet` which is 0). + +## 3. Disabling crew bailing for individual vehicles + +Crew bailing when their vehicle is disabled (immobile or can't shoot) can be disabled for a specific vehicle: + +``` +_vehicle setVariable ["ace_vehicle_damage_allowCrewInImmobile", true, true]; +``` From fe9f59bed7f91bd8a897b4fee7bc5788816b9cbc Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Mon, 3 Jun 2024 04:00:12 -0500 Subject: [PATCH 070/290] Refuel - Fix for SOG/SPE (#10049) * Refuel - Fix SOG/SPE Compats * fix export * Added missing fuel sources, improved some existing hook positions * Removed outdated todo * Add default code if refuel isn't loaded --------- Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- addons/compat_sog/CfgEventHandlers.hpp | 10 ++++ addons/compat_sog/CfgVehicles/land.hpp | 49 ++++++++++++++++--- addons/compat_sog/config.cpp | 3 +- .../compat_spe_refuel/CfgVehicles.hpp | 2 - addons/refuel/ACE_Refuel_Positions.hpp | 8 ++- .../dev/exportTerrainRefuelPositions.sqf | 13 ++++- 6 files changed, 73 insertions(+), 12 deletions(-) diff --git a/addons/compat_sog/CfgEventHandlers.hpp b/addons/compat_sog/CfgEventHandlers.hpp index fc6d80fc5f..d28b79fb99 100644 --- a/addons/compat_sog/CfgEventHandlers.hpp +++ b/addons/compat_sog/CfgEventHandlers.hpp @@ -32,6 +32,16 @@ class Extended_InitPost_EventHandlers { init = QUOTE((_this select 0) setMass 1e-12); }; }; + class Land_vn_canisterfuel_f { + class ADDON { + init = QUOTE(call (missionNamespace getVariable [ARR_2(QQEFUNC(refuel,makeJerryCan),{})])); + }; + }; + class Land_vn_fuelcan { + class ADDON { + init = QUOTE(call (missionNamespace getVariable [ARR_2(QQEFUNC(refuel,makeJerryCan),{})])); + }; + }; class vn_bicycle_base { class ADDON { init = QUOTE(call FUNC(disableCookoff)); diff --git a/addons/compat_sog/CfgVehicles/land.hpp b/addons/compat_sog/CfgVehicles/land.hpp index c939026590..70b305a31d 100644 --- a/addons/compat_sog/CfgVehicles/land.hpp +++ b/addons/compat_sog/CfgVehicles/land.hpp @@ -1,18 +1,19 @@ +#define XEH_INHERITED class EventHandlers {class CBA_Extended_EventHandlers: CBA_Extended_EventHandlers {};} // fuel pumps class Land_vn_commercial_base; class Land_vn_fuelstation_01_pump_f: Land_vn_commercial_base { - transportFuel = 0; + XEH_INHERITED; EGVAR(refuel,hooks)[] = {{0, 0.4, -0.5}, {0, -0.4, -0.5}}; EGVAR(refuel,fuelCargo) = REFUEL_INFINITE_FUEL; }; class Land_vn_fuelstation_02_pump_f: Land_vn_commercial_base { - transportFuel = 0; + XEH_INHERITED; EGVAR(refuel,hooks)[] = {{0, 0.4, -0.5}, {0, -0.4, -0.5}}; EGVAR(refuel,fuelCargo) = REFUEL_INFINITE_FUEL; }; class Land_vn_fuelstation_feed_f: Land_vn_commercial_base { - transportFuel = 0; + XEH_INHERITED; EGVAR(refuel,hooks)[] = {{0, 0.4, -0.5}, {0, -0.4, -0.5}}; EGVAR(refuel,fuelCargo) = REFUEL_INFINITE_FUEL; }; @@ -20,13 +21,47 @@ class Land_vn_fuelstation_feed_f: Land_vn_commercial_base { // fuel objects class Land_vn_building_b_base; class Land_vn_usaf_fueltank_75_01: Land_vn_building_b_base { - transportFuel = 0; - EGVAR(refuel,hooks)[] = {{0, -0.4, -0.5}}; + XEH_INHERITED; + EGVAR(refuel,hooks)[] = {{-2.52, -2.2, -2.05}, {2.5, 0, -1.3}}; EGVAR(refuel,fuelCargo) = 2840; // 750 * 3.785 }; +class Land_vn_b_prop_fuelbladder_01: Land_vn_usaf_fueltank_75_01 { + EGVAR(refuel,hooks)[] = {{-1.75, -6.7, -1}}; + EGVAR(refuel,fuelCargo) = 3785; // 1000 * 3.785 +}; +class Land_vn_b_prop_fuelbladder_03: Land_vn_b_prop_fuelbladder_01 { + EGVAR(refuel,hooks)[] = {{-1.55, -6.5, -1}}; +}; +class Land_vn_building_industrial_base; +class Land_vn_fuel_tank_stairs: Land_vn_building_industrial_base { + XEH_INHERITED; + EGVAR(refuel,hooks)[] = {{0, 0.4, -1.3}, {0, -0.4, -1.3}}; + EGVAR(refuel,fuelCargo) = 10000; // reference is B_Slingload_01_Fuel_F +}; class Land_vn_object_b_base; class Land_vn_b_prop_fueldrum_01: Land_vn_object_b_base { - transportFuel = 0; - EGVAR(refuel,hooks)[] = {{0, 0, 0.5}}; // reference is Land_FlexibleTank_01_F + XEH_INHERITED; + EGVAR(refuel,hooks)[] = {{0, 0, 0}}; EGVAR(refuel,fuelCargo) = 300; // reference is Land_FlexibleTank_01_F }; +class Land_vn_b_prop_fueldrum_02: Land_vn_b_prop_fueldrum_01 { + EGVAR(refuel,hooks)[] = {{0, -1.3, -0.15}, {2.3, 1.25, -0.15}}; + EGVAR(refuel,fuelCargo) = 14100; // (23 + 24) * 300 +}; +class vn_b_ammobox_supply_07; +class vn_b_ammobox_supply_09: vn_b_ammobox_supply_07 { // just a pallet + XEH_INHERITED; +}; +class vn_object_c_base_02; +class Land_vn_canisterfuel_f: vn_object_c_base_02 { + EGVAR(cargo,size) = 1; + EGVAR(cargo,canLoad) = 1; + EGVAR(cargo,noRename) = 1; +}; +class Land_vn_object_c_base; +class Land_vn_fuelcan: Land_vn_object_c_base { + XEH_INHERITED; + EGVAR(cargo,size) = 1; + EGVAR(cargo,canLoad) = 1; + EGVAR(cargo,noRename) = 1; +}; diff --git a/addons/compat_sog/config.cpp b/addons/compat_sog/config.cpp index 62b235773b..04db68293c 100644 --- a/addons/compat_sog/config.cpp +++ b/addons/compat_sog/config.cpp @@ -1,5 +1,4 @@ #include "script_component.hpp" -// ToDo: move refuel to subconfig #include "\z\ace\addons\refuel\defines.hpp" #include "\z\ace\addons\hearing\script_macros_hearingProtection.hpp" @@ -47,6 +46,8 @@ class CfgPatches { }; }; +class CBA_Extended_EventHandlers; + #include "ACE_CSW_Groups.hpp" #include "ACE_Medical_Injuries.hpp" #include "ACE_Triggers.hpp" diff --git a/addons/compat_spe/compat_spe_refuel/CfgVehicles.hpp b/addons/compat_spe/compat_spe_refuel/CfgVehicles.hpp index f47d6877f7..fc1ebc9b4e 100644 --- a/addons/compat_spe/compat_spe_refuel/CfgVehicles.hpp +++ b/addons/compat_spe/compat_spe_refuel/CfgVehicles.hpp @@ -1,13 +1,11 @@ class CfgVehicles { class SPE_Halftrack_base; class SPE_US_M3_Halftrack_Fuel: SPE_Halftrack_base { - transportFuel = 0; EGVAR(refuel,hooks)[] = {{-0.23,-2.58,-0.59}}; EGVAR(refuel,fuelCargo) = 2000; }; class SPE_OpelBlitz_base; class SPE_OpelBlitz_Fuel: SPE_OpelBlitz_base { - transportFuel = 0; EGVAR(refuel,hooks)[] = {{-0.23,-2.58,-0.59}}; EGVAR(refuel,fuelCargo) = 2000; }; diff --git a/addons/refuel/ACE_Refuel_Positions.hpp b/addons/refuel/ACE_Refuel_Positions.hpp index cb03f53247..78af5b6d48 100644 --- a/addons/refuel/ACE_Refuel_Positions.hpp +++ b/addons/refuel/ACE_Refuel_Positions.hpp @@ -31,7 +31,7 @@ class GVAR(positions) { intro[] = { /* CUP Rahmadi */ }; sara[] = { /* CUP Sahrani */ {"Land_Benzina_schnell", {{8473,9423,0},{9227,5840,0},{9433,5187,0},{10168,6423,0},{10932,9475,0},{11233,6114,0},{11756,10227,0},{12289,6833,0}}}, - {"Land_Fuelstation_army", {{9568,9819,0},{19294,13879,0}}}, + {"Land_Fuelstation_army", {{9568,9819,0},{19294,13879,0}}} }; sara_dbe1[] = { /* CUP United Sahrani */ {"Land_Benzina_schnell", {{8473,9423,0},{9227,5840,0},{9433,5187,0},{10168,6423,0},{10932,9475,0},{11233,6114,0},{11756,10227,0},{12289,6833,0}}}, @@ -87,4 +87,10 @@ class GVAR(positions) { {"Land_FuelStation_01_pump_malevil_F", {{18039,18139,0}}}, {"Land_FuelStation_Feed_F", {{756,12133,0},{1239,7346,0},{1726,17469,0},{3113,10070,0},{3828,8362,0},{5668,16967,0},{7435,14185,0},{7543,12107,0},{8366,6086,0},{9672,9586,0},{11749,12255,0},{12802,10022,0},{13989,3591,0},{15198,10900,0},{19063,1654,0},{19378,18517,0}}} }; + pabst_yellowstone[] = { /* Yellowstone */ + {"Land_fs_feed_F", {{3075,7426,0},{7060,3626,0},{7950,4060,0},{7974,4072,0}}}, + {"Land_FuelStation_01_pump_F", {{4565,1953,0}}}, + {"Land_FuelStation_01_pump_malevil_F", {{7072,3676,0}}}, + {"Land_FuelStation_Feed_F", {{4678,3971,0},{6391,5174,0}}} + }; }; diff --git a/addons/refuel/dev/exportTerrainRefuelPositions.sqf b/addons/refuel/dev/exportTerrainRefuelPositions.sqf index 72b60a3f1c..c7f9abfb2f 100644 --- a/addons/refuel/dev/exportTerrainRefuelPositions.sqf +++ b/addons/refuel/dev/exportTerrainRefuelPositions.sqf @@ -3,6 +3,14 @@ #include "\z\ace\addons\refuel\script_component.hpp" +{ + if (!isArray (configFile >> QGVAR(positions) >> configName _x)) then { + WARNING_1("need configs on [%1]",configName _x); + }; +} forEach ("true" configClasses (configFile >> "CfgWorldList")); + + + private _basePumps = []; private _totalCount = 0; private _posCount = 0; @@ -47,9 +55,12 @@ _basePumps sort true; // sort pump classes alphabetically private _checkCount = 0; { _x params ["_class", "_positions"]; + private _pumps = []; { - _checkCount = _checkCount + count (_x nearObjects [_class, 30]); + _pumps append (_x nearObjects [_class, 30]); } forEach _positions; + _pumps = _pumps arrayIntersect _pumps; + _checkCount = _checkCount + count _pumps; } forEach _basePumps; if (_checkCount != _totalCount) then { _message = "WRONG COUNT " + str _checkCount; From 7c689bdff74a67e5fc4f94f343c4a240998b2995 Mon Sep 17 00:00:00 2001 From: Mike-MF Date: Mon, 3 Jun 2024 13:52:59 +0100 Subject: [PATCH 071/290] Compat WS - Update realistic names (#10014) * Compat WS - Update realistic names * Fix duplicate class * WS 1.1.3 * alter SLR para barrel length * RPG-32 --- addons/compat_ws/CfgWeapons.hpp | 5 + .../compat_ws_realisticnames/Attachments.hpp | 75 +++++++++++ .../compat_ws_realisticnames/CfgVehicles.hpp | 60 +++++++++ .../compat_ws_realisticnames/CfgWeapons.hpp | 20 +++ .../compat_ws_realisticnames/config.cpp | 1 + .../compat_ws_realisticnames/stringtable.xml | 120 ++++++++++++++++++ 6 files changed, 281 insertions(+) create mode 100644 addons/compat_ws/compat_ws_realisticnames/Attachments.hpp create mode 100644 addons/compat_ws/compat_ws_realisticnames/CfgVehicles.hpp diff --git a/addons/compat_ws/CfgWeapons.hpp b/addons/compat_ws/CfgWeapons.hpp index 30e6882b08..a8b27fb1f3 100644 --- a/addons/compat_ws/CfgWeapons.hpp +++ b/addons/compat_ws/CfgWeapons.hpp @@ -37,6 +37,11 @@ class CfgWeapons { ACE_twistDirection = 1; }; + class arifle_SLR_V_lxWS; + class arifle_SLR_Para_lxWS: arifle_SLR_V_lxWS { + ACE_barrelLength = 266.7; + }; + // Velko R4/R5 class arifle_Velko_base_lxWS: arifle_Galat_base_lxWS { ACE_barrelLength = 460; diff --git a/addons/compat_ws/compat_ws_realisticnames/Attachments.hpp b/addons/compat_ws/compat_ws_realisticnames/Attachments.hpp new file mode 100644 index 0000000000..95801e04e9 --- /dev/null +++ b/addons/compat_ws/compat_ws_realisticnames/Attachments.hpp @@ -0,0 +1,75 @@ +class optic_Arco; +class optic_arco_hex_lxWS: optic_Arco { + displayName = SUBCSTRING(arco_hex_Name); +}; + +class optic_Holosight; +class optic_Holosight_snake_lxWS: optic_Holosight { + displayName = SUBCSTRING(holosight_snake_Name); +}; + +class optic_Holosight_smg; +class optic_Holosight_smg_snake_lxWS: optic_Holosight_smg { + displayName = SUBCSTRING(holosight_snake_smg_Name); +}; + +class optic_Hamr; +class optic_Hamr_arid_lxWS: optic_Hamr { + displayName = SUBCSTRING(hamr_arid_Name); +}; +class optic_Hamr_lush_lxWS: optic_Hamr { + displayName = SUBCSTRING(hamr_lush_Name); +}; +class optic_Hamr_sand_lxWS: optic_Hamr { + displayName = SUBCSTRING(hamr_sand_Name); +}; +class optic_Hamr_snake_lxWS: optic_Hamr { + displayName = SUBCSTRING(hamr_snake_Name); +}; + +class ItemCore; +class optic_r1_high_lxWS: ItemCore { + displayName = SUBCSTRING(r1_high_black_Name); +}; +class optic_r1_high_khaki_lxWS: optic_r1_high_lxWS { + displayName = SUBCSTRING(r1_high_khaki_Name); +}; +class optic_r1_high_sand_lxWS: optic_r1_high_lxWS { + displayName = SUBCSTRING(r1_high_sand_Name); +}; +class optic_r1_high_snake_lxWS: optic_r1_high_lxWS { + displayName = SUBCSTRING(r1_high_snake_Name); +}; +class optic_r1_high_arid_lxWS: optic_r1_high_lxWS { + displayName = SUBCSTRING(r1_high_arid_Name); +}; +class optic_r1_high_lush_lxWS: optic_r1_high_lxWS { + displayName = SUBCSTRING(r1_high_lush_Name); +}; +class optic_r1_high_black_sand_lxWS: optic_r1_high_lxWS { + displayName = SUBCSTRING(r1_high_black_sand_Name); +}; + +class optic_r1_low_lxWS: optic_r1_high_lxWS { + displayName = SUBCSTRING(r1_low_black_Name); +}; +class optic_r1_low_khaki_lxWS: optic_r1_high_lxWS { + displayName = SUBCSTRING(r1_low_khaki_Name); +}; +class optic_r1_low_sand_lxWS: optic_r1_high_lxWS { + displayName = SUBCSTRING(r1_low_sand_Name); +}; +class optic_r1_low_snake_lxWS: optic_r1_high_lxWS { + displayName = SUBCSTRING(r1_low_snake_Name); +}; +class optic_r1_low_arid_lxWS: optic_r1_high_lxWS { + displayName = SUBCSTRING(r1_low_arid_Name); +}; +class optic_r1_low_lush_lxWS: optic_r1_high_lxWS { + displayName = SUBCSTRING(r1_low_lush_Name); +}; + +class optic_DMS; +class optic_DMS_snake_lxWS: optic_DMS { + displayName = SUBCSTRING(dms_snake_Name); +}; diff --git a/addons/compat_ws/compat_ws_realisticnames/CfgVehicles.hpp b/addons/compat_ws/compat_ws_realisticnames/CfgVehicles.hpp new file mode 100644 index 0000000000..fe1aed7e17 --- /dev/null +++ b/addons/compat_ws/compat_ws_realisticnames/CfgVehicles.hpp @@ -0,0 +1,60 @@ +class CfgVehicles { + class APC_Wheeled_01_base_F; + class APC_Wheeled_01_atgm_base_lxWS: APC_Wheeled_01_base_F { + displayName = SUBCSTRING(apc_wheeled_01_atgm_Name); + }; + class APC_Wheeled_01_command_base_lxWS: APC_Wheeled_01_base_F { + displayName = SUBCSTRING(apc_wheeled_01_command_Name); + }; + class APC_Wheeled_01_mortar_base_lxWS: APC_Wheeled_01_base_F { + displayName = SUBCSTRING(apc_wheeled_01_mortar_Name); + }; + + class Truck_02_base_F; + class Truck_02_aa_base_lxWS: Truck_02_base_F { + displayName = SUBCSTRING(truck_02_aa_Name); + }; + class Truck_02_cargo_base_lxWS: Truck_02_base_F { + displayName = SUBCSTRING(truck_02_cargo_Name); + }; + class Truck_02_box_base_lxWS: Truck_02_base_F { + displayName = SUBCSTRING(truck_02_repair_Name); + }; + class C_Truck_02_racing_lxWS: Truck_02_box_base_lxWS { + displayName = SUBCSTRING(truck_02_racing_Name); + }; + class Truck_02_Ammo_base_lxWS: Truck_02_base_F { + displayName = SUBCSTRING(truck_02_ammo_Name); + }; + class Truck_02_flatbed_base_lxWS: Truck_02_cargo_base_lxWS { + displayName = SUBCSTRING(truck_02_flatbed_Name); + }; + + class Heli_Transport_02_base_F; + class B_UN_Heli_Transport_02_lxWS: Heli_Transport_02_base_F { + displayName = SUBCSTRING(heli_transport_02_Name); + }; + + class O_APC_Tracked_02_cannon_F; + class O_APC_Tracked_02_30mm_lxWS: O_APC_Tracked_02_cannon_F { + displayName = SUBCSTRING(apc_tracked_02_Name); + }; + + class APC_Wheeled_02_base_v2_F; + class APC_Wheeled_02_hmg_base_lxws: APC_Wheeled_02_base_v2_F { + displayName = SUBCSTRING(apc_wheeled_02_hmg_Name); + }; + class APC_Wheeled_02_unarmed_base_lxws: APC_Wheeled_02_base_v2_F { + displayName = SUBCSTRING(apc_wheeled_02_unarmed_Name); + }; + + class O_Heli_Light_02_dynamicLoadout_F; + class B_ION_Heli_Light_02_dynamicLoadout_lxWS: O_Heli_Light_02_dynamicLoadout_F { + displayName = SUBCSTRING(heli_light_02_armed_Name); + }; + + class O_Heli_Light_02_unarmed_F; + class B_ION_Heli_Light_02_unarmed_lxWS: O_Heli_Light_02_unarmed_F { + displayName = SUBCSTRING(heli_light_02_unarmed_Name); + }; +}; diff --git a/addons/compat_ws/compat_ws_realisticnames/CfgWeapons.hpp b/addons/compat_ws/compat_ws_realisticnames/CfgWeapons.hpp index c09400a03c..e9cf3c6934 100644 --- a/addons/compat_ws/compat_ws_realisticnames/CfgWeapons.hpp +++ b/addons/compat_ws/compat_ws_realisticnames/CfgWeapons.hpp @@ -1,4 +1,6 @@ class CfgWeapons { + #include "Attachments.hpp" + // AA12 class sgun_aa40_base_lxWS; class sgun_aa40_lxWS: sgun_aa40_base_lxWS { @@ -99,6 +101,12 @@ class CfgWeapons { class arifle_SLR_V_camo_lxWS: arifle_SLR_V_lxWS { displayName = SUBCSTRING(SLR_Camo_Name); }; + class arifle_SLR_Para_lxWS: arifle_SLR_V_lxWS { + displayName = SUBCSTRING(SLR_Para_Name); + }; + class arifle_SLR_Para_snake_lxWS: arifle_SLR_Para_lxWS { + displayName = SUBCSTRING(SLR_Para_Snake_Name); + }; // Vektor R4/R5 class arifle_Velko_base_lxWS; @@ -156,4 +164,16 @@ class CfgWeapons { class arifle_XMS_M_Sand_lxWS: arifle_XMS_M_lxWS { displayName = SUBCSTRING(XMS_SW_Sand_Name); }; + + // GM6 Lynx + class srifle_GM6_F; + class srifle_GM6_snake_lxWS: srifle_GM6_F { + displayName = SUBCSTRING(gm6_snake_Name); + }; + + // RPG-32 + class launch_RPG32_F; + class launch_RPG32_tan_lxWS: launch_RPG32_F { + displayName = SUBCSTRING(rpg32_tan_Name); + }; }; diff --git a/addons/compat_ws/compat_ws_realisticnames/config.cpp b/addons/compat_ws/compat_ws_realisticnames/config.cpp index 5c8e166e00..0eb75926a8 100644 --- a/addons/compat_ws/compat_ws_realisticnames/config.cpp +++ b/addons/compat_ws/compat_ws_realisticnames/config.cpp @@ -19,3 +19,4 @@ class CfgPatches { }; #include "CfgWeapons.hpp" +#include "CfgVehicles.hpp" diff --git a/addons/compat_ws/compat_ws_realisticnames/stringtable.xml b/addons/compat_ws/compat_ws_realisticnames/stringtable.xml index 714f869d8d..26504b497f 100644 --- a/addons/compat_ws/compat_ws_realisticnames/stringtable.xml +++ b/addons/compat_ws/compat_ws_realisticnames/stringtable.xml @@ -256,6 +256,12 @@ FN FAL 50.00 (Jungle) FN FAL 50.00 (Jungla) + + FN FAL 50.00 Para + + + FN FAL 50.00 Para (Snake) + Vektor R4 벡터 R4 @@ -448,5 +454,119 @@ XMS SW (모래) XMS SW (サンド) + + GM6 Lynx (Snake) + + + RPG-32 (Sand) + + + ELCAN SpecterOS (Hex) + + + EOTech XPS3 (Snake) + + + EOTech XPS3 SMG (Snake) + + + Leupold Mark 4 HAMR (Arid) + + + Leupold Mark 4 HAMR (Lush) + + + Leupold Mark 4 HAMR (Sand) + + + Leupold Mark 4 HAMR (Snake) + + + Aimpoint Micro R-1 (High, Black) + + + Aimpoint Micro R-1 (High, Khaki) + + + Aimpoint Micro R-1 (High, Sand) + + + Aimpoint Micro R-1 (High, Snake) + + + Aimpoint Micro R-1 (High, Arid) + + + Aimpoint Micro R-1 (High, Lush) + + + Aimpoint Micro R-1 (High, Black/Sand) + + + Aimpoint Micro R-1 (Low, Black) + + + Aimpoint Micro R-1 (Low, Khaki) + + + Aimpoint Micro R-1 (Low, Sand) + + + Aimpoint Micro R-1 (Low, Snake) + + + Aimpoint Micro R-1 (Low, Arid) + + + Aimpoint Micro R-1 (Low, Lush) + + + Burris XTR II (Snake) + + + Badger IFV (ATGM) + + + Badger IFV (Command) + + + Badger IFV (Mortar) + + + KamAZ (Zu-23-2) + + + KamAZ Cargo + + + KamAZ Repair + + + KamAZ Racing + + + KamAZ Ammo + + + KamAZ Flatbed + + + AW101 Merlin + + + BM-2T Stalker (Bumerang-BM) + + + Otokar ARMA (HMG) + + + Otokar ARMA (Unarmed) + + + Ka-60 Kasatka (UP) + + + Ka-60 Kasatka (UP, Unarmed) + From 29728352e265f85862c33fec5fcbc5bf1a76c184 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 5 Jun 2024 08:32:41 +0200 Subject: [PATCH 072/290] Rearm - Optimise getting magazine names (#10052) * Optimise getting rearm magazine names * Replace using regex and localize CSW entries * Added comments about prefix --- addons/csw/stringtable.xml | 17 +++++++ addons/rearm/XEH_postInit.sqf | 4 +- .../rearm/functions/fnc_getMagazineName.sqf | 46 +++++++++---------- 3 files changed, 42 insertions(+), 25 deletions(-) diff --git a/addons/csw/stringtable.xml b/addons/csw/stringtable.xml index 4aea2a24b4..7c241a8a51 100644 --- a/addons/csw/stringtable.xml +++ b/addons/csw/stringtable.xml @@ -1120,5 +1120,22 @@ [CSW] Сумка с СПГ-9М орудием [CSW] SPG-9M 발사기 가방 + + + ^\[CSW\] + ^\[CSW\] + ^\[CSW\] + ^\[CSW\] + ^\[CSW\] + ^\[CSW\] + ^\[CSW\] + ^\[班组\] + ^\[CSW\] + ^\[CSW\] + ^\[CSW\] + ^\[CSW\] + ^\[CSW\] + ^\[CSW\] + diff --git a/addons/rearm/XEH_postInit.sqf b/addons/rearm/XEH_postInit.sqf index f156fb71d6..0c79790ec0 100644 --- a/addons/rearm/XEH_postInit.sqf +++ b/addons/rearm/XEH_postInit.sqf @@ -2,8 +2,8 @@ GVAR(hardpointGroupsCache) = [] call CBA_fnc_createNamespace; GVAR(configTypesAdded) = []; -GVAR(magazineNameCache) = [] call CBA_fnc_createNamespace; -GVAR(originalMagazineNames) = []; +GVAR(magazineNameCache) = createHashMap; +GVAR(usedMagazineNames) = createHashMap; [QGVAR(initSupplyVehicle), { TRACE_1("initSupplyVehicle EH",_this); // Warning: this can run before settings are init diff --git a/addons/rearm/functions/fnc_getMagazineName.sqf b/addons/rearm/functions/fnc_getMagazineName.sqf index 2ee4a988ed..e961831c8c 100644 --- a/addons/rearm/functions/fnc_getMagazineName.sqf +++ b/addons/rearm/functions/fnc_getMagazineName.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* - * Author: PabstMirror - * Gets a non-ambigious display name for a magazine using displayNameShort (AP/HE) + * Author: PabstMirror, johnb43 + * Gets a non-ambigious display name for a magazine using displayNameShort (AP/HE). * * Arguments: * 0: Magazine Classname @@ -10,7 +10,7 @@ * Display Name * * Example: - * ["B_20mm_AP"] call ace_rearm_fnc_getMagazineName + * "60Rnd_20mm_AP_shells" call ace_rearm_fnc_getMagazineName * * Public: No */ @@ -18,31 +18,31 @@ params ["_className"]; TRACE_1("getMagazineName",_className); -private _magName = GVAR(magazineNameCache) getVariable _className; -if (isNil "_magName") then { - private _displayName = getText(configFile >> "CfgMagazines" >> _className >> "displayName"); +GVAR(magazineNameCache) getOrDefaultCall [_className, { + private _cfgMagazines = configFile >> "CfgMagazines"; + private _displayName = getText (_cfgMagazines >> _className >> "displayName"); + if (_displayName == "") then { _displayName = _className; WARNING_1("Magazine is missing display name [%1]",_className); }; - if ((_displayName select [0,6]) == "[CSW] ") then { _displayName = _displayName select [6]; }; + // [CSW] prefix is localised + if (["ace_csw"] call EFUNC(common,isModLoaded)) then { + _displayName = trim (_displayName regexReplace [LELSTRING(csw,regex), ""]); + }; - GVAR(magazineNameCache) setVariable [_className, _displayName]; - GVAR(originalMagazineNames) pushBack _displayName; + // If the display name exists already, add displayNameShort to the existing entry + private _existingClassname = GVAR(usedMagazineNames) get _displayName; + + if (!isNil "_existingClassname") then { + GVAR(magazineNameCache) set [_existingClassname, format ["%1: %2", _displayName, getText (_cfgMagazines >> _existingClassname >> "displayNameShort")]]; + + _displayName = format ["%1: %2", _displayName, getText (_cfgMagazines >> _className >> "displayNameShort")]; + }; + + GVAR(usedMagazineNames) set [_displayName, _className]; TRACE_2("Adding to cache",_className,_displayName); - // go through all existing cache entries and update if there now are duplicates - { - private _xMagName = GVAR(magazineNameCache) getVariable _x; - if ((_xMagName == _displayName) && {({_xMagName == _x} count GVAR(originalMagazineNames)) > 1}) then { - private _xMagName = format ["%1: %2", _displayName, getText(configFile >> "CfgMagazines" >> _x >> "displayNameShort")]; - GVAR(magazineNameCache) setVariable [_x, _xMagName]; - TRACE_2("Using unique name",_x,_xMagName); - }; - } forEach (allVariables GVAR(magazineNameCache)); - - _magName = GVAR(magazineNameCache) getVariable _className; -}; - -_magName + _displayName +}, true] // return From 06f47e600dabe823fa112e56110f91388d2ceec5 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 5 Jun 2024 15:22:09 +0200 Subject: [PATCH 073/290] Cookoff - Change cook-off fire damage (#9991) Increase cookoff fire damage --- addons/cookoff/functions/fnc_cookOffEffect.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/cookoff/functions/fnc_cookOffEffect.sqf b/addons/cookoff/functions/fnc_cookOffEffect.sqf index 44282f2f6b..c755fc6fbb 100644 --- a/addons/cookoff/functions/fnc_cookOffEffect.sqf +++ b/addons/cookoff/functions/fnc_cookOffEffect.sqf @@ -38,7 +38,7 @@ if (isServer) then { }; if (_ring) then { - private _intensity = 6; + private _intensity = 20; private _radius = 1.5 * ((boundingBoxReal _obj) select 2); [QEGVAR(fire,addFireSource), [_obj, _radius, _intensity, format [QGVAR(%1), hashValue _obj]]] call CBA_fnc_localEvent; }; From 738a32dba9a4aab0a568830066fb6ffd42bfdfe9 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 5 Jun 2024 15:22:19 +0200 Subject: [PATCH 074/290] Gunbag - Optimise weapon taking/storing code (#10053) Optimise gunbag code --- .../functions/fnc_offGunbagCallback.sqf | 31 +++------ .../functions/fnc_swapGunbagCallback.sqf | 65 +++++++------------ .../gunbag/functions/fnc_toGunbagCallback.sqf | 26 +++----- 3 files changed, 44 insertions(+), 78 deletions(-) diff --git a/addons/gunbag/functions/fnc_offGunbagCallback.sqf b/addons/gunbag/functions/fnc_offGunbagCallback.sqf index 8edd3e4582..68b22fb1ef 100644 --- a/addons/gunbag/functions/fnc_offGunbagCallback.sqf +++ b/addons/gunbag/functions/fnc_offGunbagCallback.sqf @@ -11,7 +11,7 @@ * None * * Example: - * [player, target] call ace_gunbag_fnc_offGunbagCallback + * [player, cursorObject] call ace_gunbag_fnc_offGunbagCallback * * Public: No */ @@ -23,39 +23,28 @@ private _gunbag = backpackContainer _target; private _state = _gunbag getVariable [QGVAR(gunbagWeapon), []]; if (_state isEqualTo []) exitWith { - [localize LSTRING(empty)] call EFUNC(common,displayTextStructured); + [LLSTRING(empty)] call EFUNC(common,displayTextStructured); }; _state params ["_weapon", "_items", "_magazines"]; -_unit addWeapon _weapon; +[_unit, _weapon, true, _magazines] call EFUNC(common,addWeapon); -// Game will auto add magazines from player's inventory, put these back in player inventory as they will be overwritten -([_unit, _weapon] call EFUNC(common,getWeaponState)) params ["", "", "_addedMags", "_addedAmmo"]; +// Add attachments { - if (((_x select 0) != "") && {(_addedMags select _forEachIndex) != ""}) then { - TRACE_2("Re-adding mag",_x,_addedMags select _forEachIndex); - _unit addMagazine [_addedMags select _forEachIndex, _addedAmmo select _forEachIndex]; - }; -} forEach _magazines; - -removeAllPrimaryWeaponItems _unit; - -{ - _unit addWeaponItem [_weapon, _x]; -} forEach (_items + _magazines); + _unit addWeaponItem [_weapon, _x, true]; +} forEach (_items select {_x != ""}); _unit selectWeapon _weapon; -_magazines = _magazines apply {_x select 0}; +private _mass = [_weapon, _items, _magazines apply {_x select 0}] call FUNC(calculateMass); -private _mass = [_weapon, _items, _magazines] call FUNC(calculateMass); - -// remove virtual load +// Remove virtual load [_target, _gunbag, -_mass] call EFUNC(movement,addLoadToUnitContainer); + _gunbag setVariable [QGVAR(gunbagWeapon), [], true]; -// play sound +// Play sound if (["ace_backpacks"] call EFUNC(common,isModLoaded)) then { [_target, _gunbag] call EFUNC(backpacks,backpackOpened); }; diff --git a/addons/gunbag/functions/fnc_swapGunbagCallback.sqf b/addons/gunbag/functions/fnc_swapGunbagCallback.sqf index a7d319506b..cb4bca2ea4 100644 --- a/addons/gunbag/functions/fnc_swapGunbagCallback.sqf +++ b/addons/gunbag/functions/fnc_swapGunbagCallback.sqf @@ -1,6 +1,6 @@ #include "..\script_component.hpp" /* - * Author: Ir0n1E and mjc4wilton + * Author: Ir0n1E, mjc4wilton * Swap primary weapon and weapon in gunbag. * * Arguments: @@ -11,66 +11,49 @@ * None * * Example: - * [player, target] call ace_gunbag_fnc_swapGunbagCallback + * [player, cursorObject] call ace_gunbag_fnc_swapGunbagCallback * * Public: No */ params ["_unit", "_target"]; -private _currentWeapon = primaryWeapon _unit; //Get Current Weapon + +// Set up current weapon for storing private _gunbag = backpackContainer _target; +private _currentItems = (getUnitLoadout _unit) select 0; +private _currentMagazines = _currentItems select [4, 2]; +_currentItems deleteRange [4, 2]; -//---Set up current weapon for storing -private _currentWeaponState = [_unit, _currentWeapon] call EFUNC(common,getWeaponState); //Gets weapon attachments +private _currentWeapon = _currentItems deleteAt 0; -/* - * example return value _state - * [["","","optic_Aco",""],["arifle_MX_GL_ACO_F","GL_3GL_F"],["30Rnd_65x39_caseless_mag","1Rnd_HE_Grenade_shell"],[30,1]] - */ +private _currentMass = [_currentWeapon, _currentItems, _currentMagazines apply {_x select 0}] call FUNC(calculateMass); -_currentWeaponState params ["_currentWeaponItems", "", "_currentWeaponMagazines", "_currentWeaponAmmo"]; //Extract Weapon Attachments to separate arrays +// Set up weapon in gunbag +private _newState = _gunbag getVariable [QGVAR(gunbagWeapon), []]; -private _currentWeaponMass = [_currentWeapon, _currentWeaponItems, _currentWeaponMagazines] call FUNC(calculateMass); - -{ - _currentWeaponMagazines set [_forEachIndex, [_x, _currentWeaponAmmo select _forEachIndex]]; -} forEach _currentWeaponMagazines; - -//---Set up weapon in gunbag -private _newWeaponState = _gunbag getVariable [QGVAR(gunbagWeapon), []]; - -if (_newWeaponState isEqualTo []) exitWith { +if (_newState isEqualTo []) exitWith { [LLSTRING(empty)] call EFUNC(common,displayTextStructured); }; -_newWeaponState params ["_newWeapon", "_newWeaponItems", "_newWeaponMagazines"]; +_newState params ["_newWeapon", "_newItems", "_newMagazines"]; -//---Swap Weapons +// Swap Weapons _unit removeWeapon _currentWeapon; -_unit addWeapon _newWeapon; -// Game will auto add magazines from player's inventory, put these back in player inventory as they will be overwritten -([_unit, _newWeapon] call EFUNC(common,getWeaponState)) params ["", "", "_addedMags", "_addedAmmo"]; +[_unit, _newWeapon, true, _newMagazines] call EFUNC(common,addWeapon); + +// Add attachments { - if (((_x select 0) != "") && {(_addedMags select _forEachIndex) != ""}) then { - TRACE_2("Re-adding mag",_x,_addedMags select _forEachIndex); - _unit addMagazine [_addedMags select _forEachIndex, _addedAmmo select _forEachIndex]; - }; -} forEach _newWeaponMagazines; - -removeAllPrimaryWeaponItems _unit; - -{ - _unit addWeaponItem [_newWeapon, _x]; -} forEach (_newWeaponItems + _newWeaponMagazines); + _unit addWeaponItem [_newWeapon, _x, true]; +} forEach (_newItems select {_x != ""}); _unit selectWeapon _newWeapon; -_newWeaponMagazines = _newWeaponMagazines apply {_x select 0}; +private _newMass = [_newWeapon, _newItems, _newMagazines apply {_x select 0}] call FUNC(calculateMass); -private _newWeaponMass = [_newWeapon, _newWeaponItems, _newWeaponMagazines] call FUNC(calculateMass); +// Update virtual load +[_target, _gunbag, _currentMass - _newMass] call EFUNC(movement,addLoadToUnitContainer); -// update virtual load -[_target, _gunbag, _currentWeaponMass - _newWeaponMass] call EFUNC(movement,addLoadToUnitContainer); -_gunbag setVariable [QGVAR(gunbagWeapon), [_currentWeapon, _currentWeaponItems, _currentWeaponMagazines], true]; //Replace weapon in gunbag +// Replace weapon in gunbag +_gunbag setVariable [QGVAR(gunbagWeapon), [_currentWeapon, _currentItems, _currentMagazines], true]; diff --git a/addons/gunbag/functions/fnc_toGunbagCallback.sqf b/addons/gunbag/functions/fnc_toGunbagCallback.sqf index 4930d1d95a..9958eed32b 100644 --- a/addons/gunbag/functions/fnc_toGunbagCallback.sqf +++ b/addons/gunbag/functions/fnc_toGunbagCallback.sqf @@ -11,38 +11,32 @@ * None * * Example: - * [player, target] call ace_gunbag_fnc_toGunbagCallback + * [player, cursorObject] call ace_gunbag_fnc_toGunbagCallback * * Public: No */ params ["_unit", "_target"]; -private _weapon = primaryWeapon _unit; +// Set up current weapon for storing private _gunbag = backpackContainer _target; +private _items = (getUnitLoadout _unit) select 0; -private _state = [_unit, _weapon] call EFUNC(common,getWeaponState); +private _magazines = _items select [4, 2]; +_items deleteRange [4, 2]; -/* - * example return value _state - * [["","","optic_Aco",""],["arifle_MX_GL_ACO_F","GL_3GL_F"],["30Rnd_65x39_caseless_mag","1Rnd_HE_Grenade_shell"],[30,1]] - */ +private _weapon = _items deleteAt 0; -_state params ["_items", "", "_magazines", "_ammo"]; - -private _mass = [_weapon, _items, _magazines] call FUNC(calculateMass); - -{ - _magazines set [_forEachIndex, [_x, _ammo select _forEachIndex]]; -} forEach _magazines; +private _mass = [_weapon, _items, _magazines apply {_x select 0}] call FUNC(calculateMass); _unit removeWeapon _weapon; -// add virtual load +// Add virtual load [_target, _gunbag, _mass] call EFUNC(movement,addLoadToUnitContainer); + _gunbag setVariable [QGVAR(gunbagWeapon), [_weapon, _items, _magazines], true]; -// play sound +// Play sound if (["ace_backpacks"] call EFUNC(common,isModLoaded)) then { [_target, _gunbag] call EFUNC(backpacks,backpackOpened); }; From 73111fa0fd958592c597e71c5a5130ce427aa962 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 5 Jun 2024 17:51:14 +0200 Subject: [PATCH 075/290] Nametags - Add documentation (#10055) Create nametags-framework.md --- docs/wiki/framework/nametags-framework.md | 45 +++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 docs/wiki/framework/nametags-framework.md diff --git a/docs/wiki/framework/nametags-framework.md b/docs/wiki/framework/nametags-framework.md new file mode 100644 index 0000000000..d27a358b17 --- /dev/null +++ b/docs/wiki/framework/nametags-framework.md @@ -0,0 +1,45 @@ +--- +layout: wiki +title: Nametags Framework +description: Explains how to implement rank icons for factions. +group: framework +order: 5 +parent: wiki +mod: ace +version: + major: 3 + minor: 13 + patch: 0 +--- + +## 1. Config Values + +### 1.1 Faction rank icons + +Defines the rank icons used by a faction. + +```cpp +class CfgFactionClasses { + class MyFaction { + ace_nametags_rankIcons[] = { + "\z\ace\addons\nametags\UI\icons_germany\private_gs.paa", // path to private rank icon + "\z\ace\addons\nametags\UI\icons_germany\corporal_gs.paa", // path to corporal rank icon + "\z\ace\addons\nametags\UI\icons_germany\sergeant_gs.paa", // path to sergeant rank icon + "\z\ace\addons\nametags\UI\icons_germany\lieutenant_gs.paa", // path to lieutenant rank icon + "\z\ace\addons\nametags\UI\icons_germany\captain_gs.paa", // path to captain rank icon + "\z\ace\addons\nametags\UI\icons_germany\major_gs.paa", // path to major rank icon + "\z\ace\addons\nametags\UI\icons_germany\colonel_gs.paa" // path to colonel rank icon + }; + }; +}; +``` + +## 2. Mission Variables + +### 2.1 Faction rank icon usage + +If disabled, it won't use the faction icons defined via the config entry listed above. +Needs to be set before postInit. +```sqf +ace_nametags_useFactionIcons = false; // by default true +``` From c44a1e7ea71c5011ef683ea12fd7a04aba49bac2 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 5 Jun 2024 21:36:39 +0200 Subject: [PATCH 076/290] Cookoff - Mini-Rewrite (#9758) * Cook-off improvements * More changes * Update fnc_getVehicleAmmo.sqf * Better engine fire placement * Update fnc_detonateAmmunition.sqf * Update XEH_postInit.sqf * Update fnc_getVehicleAmmo.sqf * Update events-framework.md * Various improvements * Separate effect handling * Tweaks * Update XEH_postInit.sqf * Prevent double ammo detonation * Fixed objects not being able to cook-off again * Added incendiary rounds as source of box cookoff * Converted enable setting to bool * Fixed brackets * Update fnc_cookOff.sqf * Update CfgEden.hpp * Removed GVAR(enable), added GVAR(enableFire) back * Update initSettings.inc.sqf * Update events-framework.md * Update addons/cookoff/functions/fnc_cookOffEffect.sqf * Restructured, redid API events * Fix effect for JIP, minor optimisations * Removed `cbaSettings_settingChanged` * Renamed variables, tweaked string table entries * Update fire damage #9991 * Capitalize comments again * Fix cookoff for very short durations and fix effect removal being too quick --- addons/common/XEH_postInit.sqf | 1 + addons/cookoff/ACE_Settings.hpp | 6 +- addons/cookoff/CfgCloudlets.hpp | 1 - addons/cookoff/CfgEden.hpp | 17 +- addons/cookoff/CfgEventHandlers.hpp | 1 - addons/cookoff/CfgSFX.hpp | 1 - addons/cookoff/CfgVehicles.hpp | 37 +-- addons/cookoff/XEH_PREP.hpp | 18 +- addons/cookoff/XEH_postInit.sqf | 93 +++---- addons/cookoff/functions/fnc_cookOff.sqf | 150 ------------ addons/cookoff/functions/fnc_cookOffBox.sqf | 74 ------ .../cookoff/functions/fnc_cookOffBoxLocal.sqf | 52 ++++ .../functions/fnc_cookOffBoxServer.sqf | 50 ++++ .../cookoff/functions/fnc_cookOffEffect.sqf | 200 --------------- addons/cookoff/functions/fnc_cookOffLocal.sqf | 229 ++++++++++++++++++ .../cookoff/functions/fnc_cookOffServer.sqf | 202 +++++++++++++++ .../functions/fnc_detonateAmmunition.sqf | 132 ---------- .../fnc_detonateAmmunitionServer.sqf | 54 +++++ .../fnc_detonateAmmunitionServerLoop.sqf | 181 ++++++++++++++ addons/cookoff/functions/fnc_engineFire.sqf | 51 ---- .../cookoff/functions/fnc_engineFireLocal.sqf | 81 +++++++ .../functions/fnc_engineFireServer.sqf | 34 +++ .../cookoff/functions/fnc_getVehicleAmmo.sqf | 71 +++--- .../cookoff/functions/fnc_handleDamageBox.sqf | 82 +++---- .../cookoff/functions/fnc_isMagazineFlare.sqf | 12 +- addons/cookoff/functions/fnc_smoke.sqf | 19 +- addons/cookoff/initSettings.inc.sqf | 108 +++++---- addons/cookoff/script_component.hpp | 13 +- addons/cookoff/stringtable.xml | 225 +++++------------ addons/grenades/functions/fnc_incendiary.sqf | 15 +- .../functions/fnc_addDamage.sqf | 4 +- .../vehicle_damage/functions/fnc_detonate.sqf | 13 +- .../functions/fnc_handleCookoff.sqf | 24 +- .../functions/fnc_handleDetonation.sqf | 11 +- .../functions/fnc_processHit.sqf | 8 +- addons/vehicle_damage/initSettings.inc.sqf | 8 - addons/vehicle_damage/stringtable.xml | 24 -- docs/wiki/framework/cookoff-framework.md | 39 +-- docs/wiki/framework/events-framework.md | 13 +- .../wiki/framework/vehicledamage-framework.md | 2 +- 40 files changed, 1205 insertions(+), 1151 deletions(-) delete mode 100644 addons/cookoff/functions/fnc_cookOff.sqf delete mode 100644 addons/cookoff/functions/fnc_cookOffBox.sqf create mode 100644 addons/cookoff/functions/fnc_cookOffBoxLocal.sqf create mode 100644 addons/cookoff/functions/fnc_cookOffBoxServer.sqf delete mode 100644 addons/cookoff/functions/fnc_cookOffEffect.sqf create mode 100644 addons/cookoff/functions/fnc_cookOffLocal.sqf create mode 100644 addons/cookoff/functions/fnc_cookOffServer.sqf delete mode 100644 addons/cookoff/functions/fnc_detonateAmmunition.sqf create mode 100644 addons/cookoff/functions/fnc_detonateAmmunitionServer.sqf create mode 100644 addons/cookoff/functions/fnc_detonateAmmunitionServerLoop.sqf delete mode 100644 addons/cookoff/functions/fnc_engineFire.sqf create mode 100644 addons/cookoff/functions/fnc_engineFireLocal.sqf create mode 100644 addons/cookoff/functions/fnc_engineFireServer.sqf diff --git a/addons/common/XEH_postInit.sqf b/addons/common/XEH_postInit.sqf index 9b11ec49e6..0d4b55ae28 100644 --- a/addons/common/XEH_postInit.sqf +++ b/addons/common/XEH_postInit.sqf @@ -191,6 +191,7 @@ if (isServer) then { [QGVAR(switchMove), {(_this select 0) switchMove (_this select 1)}] call CBA_fnc_addEventHandler; [QGVAR(setVectorDirAndUp), {(_this select 0) setVectorDirAndUp (_this select 1)}] call CBA_fnc_addEventHandler; [QGVAR(addWeaponItem), {(_this select 0) addWeaponItem [(_this select 1), (_this select 2)]}] call CBA_fnc_addEventHandler; +[QGVAR(removeMagazinesTurret), {(_this select 0) removeMagazinesTurret [_this select 1, _this select 2]}] call CBA_fnc_addEventHandler; [QGVAR(setVanillaHitPointDamage), { params ["_object", "_hitPointAnddamage"]; diff --git a/addons/cookoff/ACE_Settings.hpp b/addons/cookoff/ACE_Settings.hpp index ba4447dba9..37594bed51 100644 --- a/addons/cookoff/ACE_Settings.hpp +++ b/addons/cookoff/ACE_Settings.hpp @@ -1,12 +1,8 @@ - class ACE_Settings { - class GVAR(enable) { - movedToSqf = 1; - }; class GVAR(enableAmmobox) { movedToSQF = 1; }; - class GVAR(enableAmmoCookoff) { // For CBA Setting Switch: we can eliminate and just use (ammoCookoffDuration == 0) + class GVAR(enableAmmoCookoff) { movedToSQF = 1; }; class GVAR(ammoCookoffDuration) { diff --git a/addons/cookoff/CfgCloudlets.hpp b/addons/cookoff/CfgCloudlets.hpp index c167177705..a328451a7b 100644 --- a/addons/cookoff/CfgCloudlets.hpp +++ b/addons/cookoff/CfgCloudlets.hpp @@ -1,4 +1,3 @@ - class CfgCloudlets { class GVAR(CookOff) { interval = 0.004; diff --git a/addons/cookoff/CfgEden.hpp b/addons/cookoff/CfgEden.hpp index 2b58daa304..f973ef4026 100644 --- a/addons/cookoff/CfgEden.hpp +++ b/addons/cookoff/CfgEden.hpp @@ -1,28 +1,27 @@ - class Cfg3DEN { class Object { class AttributeCategories { class ace_attributes { class Attributes { - class GVAR(enable) { - property = QGVAR(enable); + class GVAR(enable) { // setting was previously GVAR(enable), so maintain for backwards compatiblity with missions + property = QGVAR(enable); // same as above control = "Checkbox"; - displayName = CSTRING(enable_hd_name); - tooltip = CSTRING(enable_hd_tooltip); - expression = QUOTE(if !(_value) then {_this setVariable [ARR_3('%s',_value,true)];};); + displayName = CSTRING(enableFire_name); + tooltip = CSTRING(enableFire_tooltip); + expression = QUOTE(if (!_value) then {_this setVariable [ARR_3('%s',_value,true)]}); typeName = "BOOL"; condition = "objectVehicle"; - defaultValue = QUOTE((GETMVAR(QGVAR(enable),0)) in [ARR_2(1,2)]); + defaultValue = QUOTE(GETMVAR(QGVAR(enableFire),true)); }; class GVAR(enableAmmoCookoff) { property = QGVAR(enableAmmoCookoff); control = "Checkbox"; displayName = CSTRING(enableAmmoCookoff_name); tooltip = CSTRING(enableAmmoCookoff_tooltip); - expression = QUOTE(if !(_value) then {_this setVariable [ARR_3('%s',_value,true)];};); + expression = QUOTE(if (!_value) then {_this setVariable [ARR_3('%s',_value,true)]}); typeName = "BOOL"; condition = "objectHasInventoryCargo"; - defaultValue = QUOTE(if (_this isKindOf 'ReammoBox_F') then { GETMVAR(QGVAR(enableAmmobox),true) } else { GETMVAR(QGVAR(enableAmmoCookoff),true) };); + defaultValue = QUOTE(if (_this isKindOf 'ReammoBox_F') then {GETMVAR(QGVAR(enableAmmobox),true)} else {GETMVAR(QGVAR(enableAmmoCookoff),true)}); }; }; }; diff --git a/addons/cookoff/CfgEventHandlers.hpp b/addons/cookoff/CfgEventHandlers.hpp index 6c29240403..f6503c2479 100644 --- a/addons/cookoff/CfgEventHandlers.hpp +++ b/addons/cookoff/CfgEventHandlers.hpp @@ -1,4 +1,3 @@ - class Extended_PreStart_EventHandlers { class ADDON { init = QUOTE(call COMPILE_SCRIPT(XEH_preStart)); diff --git a/addons/cookoff/CfgSFX.hpp b/addons/cookoff/CfgSFX.hpp index 0d670ead86..24329862fc 100644 --- a/addons/cookoff/CfgSFX.hpp +++ b/addons/cookoff/CfgSFX.hpp @@ -1,4 +1,3 @@ - class CfgSFX { class GVAR(CookOff_low) { name = QGVAR(cookoff_low); diff --git a/addons/cookoff/CfgVehicles.hpp b/addons/cookoff/CfgVehicles.hpp index 78cbd0c623..4451d12080 100644 --- a/addons/cookoff/CfgVehicles.hpp +++ b/addons/cookoff/CfgVehicles.hpp @@ -1,4 +1,3 @@ - class CfgVehicles { class Sound; class GVAR(Sound_low): Sound { @@ -7,7 +6,6 @@ class CfgVehicles { scope = 1; sound = QGVAR(CookOff_low); }; - class GVAR(Sound_mid): GVAR(Sound_low) { sound = QGVAR(CookOff_mid); }; @@ -17,47 +15,14 @@ class CfgVehicles { class Tank; class Tank_F: Tank { - GVAR(ammoLocation) = "HitHull"; GVAR(cookoffSelections)[] = {"poklop_gunner","poklop_commander"}; - GVAR(probability) = 0.5; - }; - class MBT_02_base_F: Tank_F { - GVAR(ammoLocation) = "HitTurret"; }; class Car_F; class Wheeled_APC_F: Car_F { - GVAR(ammoLocation) = "HitHull"; GVAR(cookoffSelections)[] = {"poklop_gunner","poklop_commander"}; - GVAR(probability) = 0.8; - // big explosions for wheeled APCs (same as for tanks) + // Big explosions for wheeled APCs (same as for tanks) explosionEffect = "FuelExplosionBig"; }; - - - class MRAP_01_base_F: Car_F { - GVAR(engineSmokeOffset)[] = {0,-2,0}; - }; - - class MRAP_02_base_F: Car_F { - GVAR(engineSmokeOffset)[] = {0,-2,0}; - }; - - class MRAP_03_base_F: Car_F { - GVAR(engineSmokeOffset)[] = {0,-2,0}; - }; - - class Quadbike_01_base_F: Car_F { - GVAR(engineSmokeOffset)[] = {0,1,0}; - }; - - class Truck_F; - class Truck_02_base_F: Truck_F { - GVAR(engineSmokeOffset)[] = {0,-2.6,-0.1}; - }; - - class Truck_02_MRL_base_F: Truck_02_base_F { - GVAR(engineSmokeOffset)[] = {0,0.3,-0.1}; - }; }; diff --git a/addons/cookoff/XEH_PREP.hpp b/addons/cookoff/XEH_PREP.hpp index 2cd87efaa7..9405908953 100644 --- a/addons/cookoff/XEH_PREP.hpp +++ b/addons/cookoff/XEH_PREP.hpp @@ -1,10 +1,12 @@ - -PREP(handleDamageBox); -PREP(engineFire); -PREP(cookOff); -PREP(smoke); -PREP(cookOffEffect); -PREP(cookOffBox); -PREP(detonateAmmunition); +PREP(cookOffBoxLocal); +PREP(cookOffBoxServer); +PREP(cookOffLocal); +PREP(cookOffServer); +PREP(detonateAmmunitionServer); +PREP(detonateAmmunitionServerLoop); +PREP(engineFireLocal); +PREP(engineFireServer); PREP(getVehicleAmmo); +PREP(handleDamageBox); PREP(isMagazineFlare); +PREP(smoke); diff --git a/addons/cookoff/XEH_postInit.sqf b/addons/cookoff/XEH_postInit.sqf index eba4eeced0..b99212c5b7 100644 --- a/addons/cookoff/XEH_postInit.sqf +++ b/addons/cookoff/XEH_postInit.sqf @@ -1,63 +1,64 @@ #include "script_component.hpp" -[QGVAR(engineFire), LINKFUNC(engineFire)] call CBA_fnc_addEventHandler; -[QGVAR(cookOff), { - params ["_vehicle"]; - if (local _vehicle) then { - _this call FUNC(cookOff); - }; -}] call CBA_fnc_addEventHandler; -[QGVAR(cookOffEffect), LINKFUNC(cookOffEffect)] call CBA_fnc_addEventHandler; +[QGVAR(cookOffBoxLocal), LINKFUNC(cookOffBoxLocal)] call CBA_fnc_addEventHandler; +[QGVAR(cookOffLocal), LINKFUNC(cookOffLocal)] call CBA_fnc_addEventHandler; +[QGVAR(engineFireLocal), LINKFUNC(engineFireLocal)] call CBA_fnc_addEventHandler; [QGVAR(smoke), LINKFUNC(smoke)] call CBA_fnc_addEventHandler; -[QGVAR(cookOffBox), LINKFUNC(cookOffBox)] call CBA_fnc_addEventHandler; -// handle cleaning up effects when vehicle is deleted mid-cookoff -[QGVAR(addCleanupHandlers), { - params ["_vehicle"]; +if (isServer) then { + [QGVAR(cookOffBoxServer), LINKFUNC(cookOffBoxServer)] call CBA_fnc_addEventHandler; + [QGVAR(cookOffServer), LINKFUNC(cookOffServer)] call CBA_fnc_addEventHandler; + [QGVAR(detonateAmmunitionServer), LINKFUNC(detonateAmmunitionServer)] call CBA_fnc_addEventHandler; + [QGVAR(engineFireServer), LINKFUNC(engineFire)] call CBA_fnc_addEventHandler; +}; - // Don't add a new EH if cookoff is run multiple times - if ((_vehicle getVariable [QGVAR(deletedEH), -1]) == -1) then { - private _deletedEH = _vehicle addEventHandler ["Deleted", { - params ["_vehicle"]; +// Handle cleaning up effects when objects are deleted mid cook-off +["AllVehicles", "Deleted", { + { + deleteVehicle _x; + } forEach ((_this select 0) getVariable [QGVAR(effects), []]); +}, true, ["CAManBase", "StaticWeapon"], true] call CBA_fnc_addClassEventHandler; - [QGVAR(cleanupEffects), [_vehicle]] call CBA_fnc_localEvent; - }]; - - _vehicle setVariable [QGVAR(deletedEH), _deletedEH]; - }; -}] call CBA_fnc_addEventHandler; +["ReammoBox_F", "Deleted", { + { + deleteVehicle _x; + } forEach ((_this select 0) getVariable [QGVAR(effects), []]); +}, true, [], true] call CBA_fnc_addClassEventHandler; +// Raised when the flames have subsided or after the ammo of a box has finished cooking off [QGVAR(cleanupEffects), { - params ["_vehicle", ["_effects", []]]; + params ["_object"]; - _effects = _effects + (_vehicle getVariable [QGVAR(effects), []]); - if (_effects isNotEqualTo []) then { - { deleteVehicle _x } count _effects; - }; + { + deleteVehicle _x; + } forEach (_object getVariable [QGVAR(effects), []]); + + _object setVariable [QGVAR(effects), nil]; }] call CBA_fnc_addEventHandler; +// Ammo box damage handling ["ReammoBox_F", "init", { - (_this select 0) addEventHandler ["HandleDamage", { - if ((_this select 0) getVariable [QGVAR(enableAmmoCookoff), GVAR(enableAmmobox)]) then { - _this call FUNC(handleDamageBox); - }; - }]; -}, nil, nil, true] call CBA_fnc_addClassEventHandler; + // Calling this function inside curly brackets allows the usage of "exitWith", which would be broken with "HandleDamage" otherwise + (_this select 0) addEventHandler ["HandleDamage", {_this call FUNC(handleDamageBox)}]; +}, true, [], true] call CBA_fnc_addClassEventHandler; + +// Vehicle ammo cook-off (secondary explosions) +["AllVehicles", "Killed", { + if (!GVAR(enableAmmoCookoff) || {GVAR(ammoCookoffDuration) == 0}) exitWith {}; -// secondary explosions -["AllVehicles", "killed", { params ["_vehicle", "", "", "_useEffects"]; - if ( - _useEffects && - _vehicle getVariable [QGVAR(enableAmmoCookoff), GVAR(enableAmmoCookoff)] - ) then { - if (GVAR(ammoCookoffDuration) == 0) exitWith {}; - ([_vehicle] call FUNC(getVehicleAmmo)) params ["_mags", "_total"]; - private _delay = (random MAX_AMMO_DETONATION_START_DELAY) max MIN_AMMO_DETONATION_START_DELAY; - [FUNC(detonateAmmunition), [_vehicle, _mags, _total], _delay] call CBA_fnc_waitAndExecute; + if (_useEffects && {_vehicle getVariable [QGVAR(enableAmmoCookoff), true]}) then { + // We don't need to pass source and instigator, as vehicle is already dead + [QGVAR(detonateAmmunitionServer), [ + _vehicle, + false, + objNull, + objNull, + random [MIN_AMMO_DETONATION_START_DELAY, (MIN_AMMO_DETONATION_START_DELAY + MAX_AMMO_DETONATION_START_DELAY) / 2, MAX_AMMO_DETONATION_START_DELAY] + ]] call CBA_fnc_serverEvent; }; -}, nil, ["Man","StaticWeapon"]] call CBA_fnc_addClassEventHandler; +}, true, ["CAManBase", "StaticWeapon"], true] call CBA_fnc_addClassEventHandler; if (hasInterface) then { // Plays a sound locally, so that different sounds can be used for various distances @@ -68,7 +69,7 @@ if (hasInterface) then { private _distance = _object distance (positionCameraToWorld [0, 0, 0]); - TRACE_3("",_object,_sound,_maxDistance); + TRACE_2("",_object,_sound); // 3 classes of distances: close, mid and far, each having different sound files private _classDistance = switch (true) do { @@ -94,6 +95,6 @@ if (hasInterface) then { if (!fileExists _sound) exitWith {}; // Obeys speed of sound and takes doppler effects into account - playSound3D [_sound, objNull, insideBuilding _object >= 0.5, getPosASL _object, _volume, _pitch + (random 0.2) - 0.1, _maxDistance, 0, true]; + playSound3D [_sound, objNull, false, getPosASL _object, _volume, _pitch + (random 0.2) - 0.1, _maxDistance, 0, true]; }] call CBA_fnc_addEventHandler; }; diff --git a/addons/cookoff/functions/fnc_cookOff.sqf b/addons/cookoff/functions/fnc_cookOff.sqf deleted file mode 100644 index 94cf63cb40..0000000000 --- a/addons/cookoff/functions/fnc_cookOff.sqf +++ /dev/null @@ -1,150 +0,0 @@ -#include "..\script_component.hpp" -/* - * Author: tcvm - * Start a cook-off in the given vehicle. - * - * Arguments: - * 0: Vehicle - * 1: Intensity of fire - * - * Return Value: - * None - * - * Example: - * [(vehicle player), 3] call ace_cookoff_fnc_cookOff - * - * Public: No - */ - -params ["_vehicle", "_intensity", ["_instigator", objNull], ["_smokeDelayEnabled", true], ["_ammoDetonationChance", 0], ["_detonateAfterCookoff", false], ["_fireSource", ""], ["_canRing", true], ["_maxIntensity", MAX_COOKOFF_INTENSITY, [0]], ["_canJet", true, [true]]]; - -if (GVAR(enable) == 0) exitWith {}; -if !(GVAR(enableFire)) exitWith {}; -if (_vehicle getVariable [QGVAR(enable), GVAR(enable)] in [0, false]) exitWith {}; -// exit if cook-off enabled only for players and no players in vehicle crew found -if (_vehicle getVariable [QGVAR(enable), GVAR(enable)] isEqualTo 1 && {fullCrew [_vehicle, "", false] findIf {isPlayer (_x select 0)} == -1}) exitWith {}; - - -TRACE_2("cooking off",_vehicle,_intensity); -TRACE_8("",_instigator,_smokeDelayEnabled,_ammoDetonationChance,_detonateAfterCookoff,_fireSource,_canRing,_maxIntensity,_canJet); - -if (_vehicle getVariable [QGVAR(isCookingOff), false]) exitWith {}; -_vehicle setVariable [QGVAR(isCookingOff), true, true]; - -[QGVAR(addCleanupHandlers), [_vehicle]] call CBA_fnc_globalEvent; - -// limit maximum value of intensity to prevent very long cook-off times -_intensity = _intensity min _maxIntensity; - -private _config = configOf _vehicle; -private _positions = getArray (_config >> QGVAR(cookoffSelections)) select {(_vehicle selectionPosition _x) isNotEqualTo [0,0,0]}; - -if (_positions isEqualTo []) then { - WARNING_1("no valid selection for cookoff found. %1",typeOf _vehicle); - { - private _pos = _vehicle selectionPosition _x; - if (_pos isEqualTo [0, 0, 0]) exitWith {}; - _positions pushBack _x; - } forEach DEFAULT_COMMANDER_HATCHES; - - if (_positions isEqualTo []) then { - _positions pushBack "#noselection"; - }; -}; - -private _delay = 0; -if (_smokeDelayEnabled) then { - _delay = SMOKE_TIME + random SMOKE_TIME; -}; -[QGVAR(smoke), [_vehicle, _positions]] call CBA_fnc_globalEvent; - -[{ - params ["_vehicle", "_positions", "_intensity", "_ammoDetonationChance", "_detonateAfterCookoff", "_instigator", "_fireSource", "_canRing", "_canJet"]; - _vehicle setVariable [QGVAR(intensity), _intensity]; - - [{ - params ["_args", "_pfh"]; - _args params ["_vehicle", "_positions", "_ammoDetonationChance", "_detonateAfterCookoff", "_instigator", "_fireSource", "_canRing", "_canJet"]; - private _intensity = _vehicle getVariable [QGVAR(intensity), 0]; - private _nextFlameTime = _vehicle getVariable [QGVAR(nextFlame), 0]; - if (isNull _vehicle || {_intensity <= 1}) exitWith { - [_pfh] call CBA_fnc_removePerFrameHandler; - - if (isNull _vehicle) exitWith {}; - - if (GVAR(destroyVehicleAfterCookoff) || _detonateAfterCookoff) exitWith { - if (_fireSource isEqualTo "") then { - _fireSource = selectRandom _positions; - }; - - if (_nextFlameTime <= 0) then { - _nextFlameTime = MIN_TIME_BETWEEN_FLAMES max random MAX_TIME_BETWEEN_FLAMES; - }; - - [{ - params ["_vehicle", "_fireSource"]; - - if (isNull _vehicle) exitWith {}; - - [QGVAR(cleanupEffects), _vehicle] call CBA_fnc_globalEvent; - _vehicle setVariable [QGVAR(isCookingOff), false, true]; - - createVehicle ["ACE_ammoExplosionLarge", (_vehicle modelToWorld (_vehicle selectionPosition _fireSource)), [], 0 , "CAN_COLLIDE"]; - - _vehicle setDamage [1, true]; - }, [_vehicle, _fireSource], _nextFlameTime] call CBA_fnc_waitAndExecute; - }; - - [QGVAR(cleanupEffects), _vehicle] call CBA_fnc_globalEvent; - _vehicle setVariable [QGVAR(isCookingOff), false, true]; - }; - - private _lastFlameTime = _vehicle getVariable [QGVAR(lastFlame), 0]; - - // Wait until we are ready for the next flame - // dt = Tcurrent - Tlast - // dt >= Tnext - if ((CBA_missionTime - _lastFlameTime) >= _nextFlameTime) then { - private _ring = (0.2 > random 1); - if (!_ring && _intensity >= 2) then { - _ring = (0.7 > random 1); - }; - - if !(_canRing) then { - _ring = false; - }; - - private _time = linearConversion [0, 10, _intensity, 3, 20] + random COOKOFF_TIME; - - if (_fireSource isEqualTo "") then { - _fireSource = selectRandom _positions; - }; - - [QGVAR(cookOffEffect), [_vehicle, _canJet, _ring, _time, _fireSource, _intensity]] call CBA_fnc_globalEvent; - - _intensity = _intensity - (0.5 max random 1); - _vehicle setVariable [QGVAR(intensity), _intensity]; - _vehicle setVariable [QGVAR(lastFlame), CBA_missionTime]; - _vehicle setVariable [QGVAR(nextFlame), _time + (MIN_TIME_BETWEEN_FLAMES max random MAX_TIME_BETWEEN_FLAMES)]; - - { - [QEGVAR(fire,burn), [_x, _intensity * 1.5, _instigator]] call CBA_fnc_globalEvent; - } forEach crew _vehicle - }; - - if (_ammoDetonationChance > random 1) then { - private _lastExplosiveDetonationTime = _vehicle getVariable [QGVAR(lastExplosiveDetonation), 0]; - private _nextExplosiveDetonation = _vehicle getVariable [QGVAR(nextExplosiveDetonation), 0]; - - if ((CBA_missionTime - _lastExplosiveDetonationTime) > _nextExplosiveDetonation) then { - if (_fireSource isEqualTo "") then { - _fireSource = selectRandom _positions; - }; - createVehicle ["ACE_ammoExplosionLarge", (_vehicle modelToWorld (_vehicle selectionPosition _fireSource)), [], 0 , "CAN_COLLIDE"]; - - _vehicle setVariable [QGVAR(lastExplosiveDetonation), CBA_missionTime]; - _vehicle setVariable [QGVAR(nextExplosiveDetonation), random 60]; - }; - }; - }, 0.25, [_vehicle, _positions, _ammoDetonationChance, _detonateAfterCookoff, _instigator, _fireSource, _canRing, _canJet]] call CBA_fnc_addPerFrameHandler -}, [_vehicle, _positions, _intensity, _ammoDetonationChance, _detonateAfterCookoff, _instigator, _fireSource, _canRing, _canJet], _delay] call CBA_fnc_waitAndExecute; diff --git a/addons/cookoff/functions/fnc_cookOffBox.sqf b/addons/cookoff/functions/fnc_cookOffBox.sqf deleted file mode 100644 index 8b8e60891c..0000000000 --- a/addons/cookoff/functions/fnc_cookOffBox.sqf +++ /dev/null @@ -1,74 +0,0 @@ -#include "..\script_component.hpp" -/* - * Author: KoffeinFlummi, commy2, kymckay - * Start a cook-off in the given ammo box. - * - * Arguments: - * 0: Ammo box - * - * Return Value: - * None - * - * Example: - * [_box] call ace_cookoff_fnc_cookOffBox - * - * Public: No - */ - -params ["_box"]; - -if (_box getVariable [QGVAR(isCookingOff), false]) exitWith {}; -_box setVariable [QGVAR(isCookingOff), true]; - -if (local _box) then { - [QGVAR(cookOffBox), _box] call CBA_fnc_globalEvent; -}; - -[{ - params ["_box"]; - - // Box will start smoking - private _smoke = "#particlesource" createVehicleLocal [0,0,0]; - _smoke setParticleClass "AmmoSmokeParticles2"; - _smoke attachTo [_box, [0,0,0]]; - - private _effects = [_smoke]; - - if (isServer) then { - private _sound = createSoundSource ["Sound_Fire", position _box, [], 0]; - _effects pushBack _sound; - }; - - [{ - params ["_box", "_effects"]; - - // These functions are smart and do all the cooking off work - if (local _box) then { - if (GVAR(ammoCookoffDuration) == 0) exitWith {}; - ([_box] call FUNC(getVehicleAmmo)) params ["_mags", "_total"]; - [_box, _mags, _total] call FUNC(detonateAmmunition); - - // This shit is busy being on fire, magazines aren't accessible/usable - clearMagazineCargoGlobal _box; - }; - - // Light the fire (also handles lighting) - private _fire = "#particlesource" createVehicleLocal [0,0,0]; - _fire setParticleClass "AmmoBulletCore"; - _fire attachTo [_box, [0,0,0]]; - - _effects pushBack _fire; - - [{ - params ["_box", "_effects"]; - - { - deleteVehicle _x; - } forEach _effects; - - if (local _box) then { - _box setDamage 1; - }; - }, [_box, _effects], COOKOFF_TIME_BOX] call CBA_fnc_waitAndExecute; // TODO: Change so that box is alive until no ammo left, with locality in mind - }, [_box, _effects], SMOKE_TIME] call CBA_fnc_waitAndExecute; -}, _box, IGNITE_TIME] call CBA_fnc_waitAndExecute; diff --git a/addons/cookoff/functions/fnc_cookOffBoxLocal.sqf b/addons/cookoff/functions/fnc_cookOffBoxLocal.sqf new file mode 100644 index 0000000000..8285104daf --- /dev/null +++ b/addons/cookoff/functions/fnc_cookOffBoxLocal.sqf @@ -0,0 +1,52 @@ +#include "..\script_component.hpp" +/* + * Author: KoffeinFlummi, commy2, kymckay, johnb43 + * Spawns local cook-off effects for ammo boxes. + * + * Arguments: + * 0: Box + * 1: Source + * 2: Instigator + * 3: Start time of the cook-off + * + * Return Value: + * None + * + * Example: + * [cursorObject, player, player, CBA_missionTime + 10] call ace_cookoff_fnc_cookOffBoxLocal + * + * Public: No + */ + +params ["", "", "", "_startTime"]; + +[{ + params ["_box", "_source", "_instigator"]; + + // If box was deleted before smoke could be spawned, just exit + if (isNull _box) exitWith {}; + + private _boxPos = ASLToAGL getPosASL _box; + private _effects = []; + + // Box will start smoking + if (hasInterface) then { + private _smoke = createVehicleLocal ["#particlesource", _boxPos, [], 0, "CAN_COLLIDE"]; + _smoke setParticleClass "AmmoSmokeParticles2"; + _smoke attachTo [_box]; + + _effects pushBack _smoke; + }; + + if (isServer) then { + private _sound = createSoundSource ["Sound_Fire", _boxPos, [], 0]; + _sound attachTo [_box]; + + _effects pushBack _sound; + + // Detonate the ammunition + [QGVAR(detonateAmmunitionServer), [_box, true, _source, _instigator, random [DETONATION_DELAY / 2, DETONATION_DELAY, DETONATION_DELAY / 2 * 3]]] call CBA_fnc_localEvent; + }; + + _box setVariable [QGVAR(effects), _effects]; +}, _this, (_startTime - CBA_missionTime) max 0] call CBA_fnc_waitAndExecute; // This delay allows for synchronisation for JIP players diff --git a/addons/cookoff/functions/fnc_cookOffBoxServer.sqf b/addons/cookoff/functions/fnc_cookOffBoxServer.sqf new file mode 100644 index 0000000000..10d57876a7 --- /dev/null +++ b/addons/cookoff/functions/fnc_cookOffBoxServer.sqf @@ -0,0 +1,50 @@ +#include "..\script_component.hpp" +/* + * Author: KoffeinFlummi, commy2, kymckay, johnb43 + * Start an ammo cook-off in the given ammo box. + * + * Arguments: + * 0: Ammo box + * 1: Source (default: objNull) + * 2: Instigator (default: objNull) + * + * Return Value: + * None + * + * Example: + * cursorObject call ace_cookoff_fnc_cookOffBoxServer + * + * Public: No + */ + +if (!isServer) exitWith {}; +if (!GVAR(enableAmmobox) || {GVAR(ammoCookoffDuration) == 0}) exitWith {}; + +params ["_box", ["_source", objNull], ["_instigator", objNull]]; + +// Make sure it's a box (important, because deleted EH is assigned to ReammoBox_F only in postInit) +if !(_box isKindOf "ReammoBox_F") exitWith {}; + +if !(_box getVariable [QGVAR(enableAmmoCookoff), true]) exitWith {}; + +// Allow only 1 cook-off per box at a time +if (_box getVariable [QGVAR(isCookingOff), false]) exitWith {}; + +_box setVariable [QGVAR(isCookingOff), true, true]; + +private _delay = random [SMOKE_DELAY / 2, SMOKE_DELAY, SMOKE_DELAY / 2 * 3]; + +// Spawn cook-off effects on all connected machines and JIP +private _jipID = [QGVAR(cookOffBoxLocal), [ + _box, + _source, + _instigator, + CBA_missionTime + _delay // Generate a globally synced timestamp +]] call CBA_fnc_globalEventJIP; + +[_jipID, _box] call CBA_fnc_removeGlobalEventJIP; + +_box setVariable [QGVAR(cookoffBoxJipID), _jipID]; + +// API +[QGVAR(cookOffBox), [_box, _source, _instigator, _delay]] call CBA_fnc_globalEvent; diff --git a/addons/cookoff/functions/fnc_cookOffEffect.sqf b/addons/cookoff/functions/fnc_cookOffEffect.sqf deleted file mode 100644 index c755fc6fbb..0000000000 --- a/addons/cookoff/functions/fnc_cookOffEffect.sqf +++ /dev/null @@ -1,200 +0,0 @@ -#include "..\script_component.hpp" -/* - * Author: tcvm - * Spawn cook-off effects - * - * Arguments: - * 0: Vehicle - * 1: Spawn fire jet - * 2: Spawn fire ring - * 3: How long effect will last (Max 20 seconds) - * 4: What selection will fire originate from - * 5: Cookoff intensity value - * - * Return Value: - * None - * - * Example: - * [vehicle player, true, false, 15, "commander_turret"] call ace_cookoff_fnc_cookOffEffect - * - * Public: No - */ - -params ["_obj", "_jet", "_ring", "_time", "_fireSelection", "_intensity"]; -private _light = "#lightpoint" createVehicleLocal [0,0,0]; -_light setLightBrightness 5; -_light setLightAmbient [0.8, 0.6, 0.2]; -_light setLightColor [1, 0.5, 0.2]; -_light lightAttachObject [_obj, [0,0,0]]; -_time = 0 max (_time min 20); - -private _sound = objNull; -if (isServer) then { - // ironically biggest performance hit is this. Creating a new sound source takes up aprox 400 milliseconds. - // I dont think there is an alternative that takes into effect distance and whatever, but if you find one please fix! - if (_jet || _ring) then { - private _soundName = selectRandomWeighted [QGVAR(Sound_low), 0.1, QGVAR(Sound_mid), 0.25, QGVAR(Sound_high), 0.65]; - _sound = createSoundSource [_soundName, position _obj, [], 0]; - }; - - if (_ring) then { - private _intensity = 20; - private _radius = 1.5 * ((boundingBoxReal _obj) select 2); - [QEGVAR(fire,addFireSource), [_obj, _radius, _intensity, format [QGVAR(%1), hashValue _obj]]] call CBA_fnc_localEvent; - }; -}; - -[{ - params ["_args", "_pfh"]; - _args params ["_obj", "_jet", "_ring", "_time", "_startTime", "_light", "_fireSelection", "_sound", "_intensity"]; - private _elapsedTime = CBA_missionTime - _startTime; - if (_elapsedTime >= _time) exitWith { - deleteVehicle _light; - deleteVehicle _sound; - if (isServer) then { - [QEGVAR(fire,removeFireSource), [format [QGVAR(%1), hashValue _obj]]] call CBA_fnc_localEvent; - }; - [_pfh] call CBA_fnc_removePerFrameHandler; - }; - private _factor = (1 + (_elapsedTime / 2) min 2); - private _flameSize = 1.5; - - if (_elapsedTime > (_time * (3 / 4))) then { - _factor = _factor * linearConversion [_time * (3 / 4), _time, _elapsedTime, 1, 0.5]; - }; - - _light setLightBrightness 5 * (_factor / 5); - - if (_jet) then { - private _particlePosition = (_obj selectionPosition _fireSelection) vectorAdd [-0.1 + random 0.2, -0.1 + random 0.2, 0]; - - drop [ - ["\A3\data_f\ParticleEffects\Universal\Universal", 16, 2, 32], - "", - "Billboard", - 1, - (0.1 + (random 0.2)) * _factor, - _particlePosition, - [0, 0, 15 * (_factor / 2)], - 0, - 10, - 7.9, - 0.075, - [1.25 * _factor, 2.5 * _factor], - [[1, 1, 1, -2], [1, 1, 1, -2], [1, 1, 1, -1], [1, 1, 1, -0]], - [2 + random 1], - 1, - 0, - "", - "", - _obj - ]; - - // make flame push object into ground to make effect seem more "alive" - if (!isGamePaused && { local _obj }) then { - private _force = [0, 0, _factor * -(0.5 min random 1.5) * (0.3 min random 1)] vectorMultiply getMass _obj; - _obj addForce [_force, vectorUpVisual _obj]; - }; - }; - - if (_ring) then { - private _ringOrigin = (_obj selectionPosition _fireSelection) vectorAdd [-0.1 + random 0.2, -0.1 + random 0.2, -1]; - drop [ - ["\A3\data_f\ParticleEffects\Universal\Universal",16,2,32], - "", "Billboard", 1, (0.1 + (random 0.2)) * _factor, - _ringOrigin, - [0, 20 * (_factor / 2), 0], - 0, 10, 7.9, 0.075, - [1.25 * _factor, _flameSize * _factor], - [[1, 1, 1, -2], [1, 1, 1, -2], [1, 1, 1, -1], [1, 1, 1, -0]], - [2 + random 1], 1, 0, "", "", _obj - ]; - drop [ - ["\A3\data_f\ParticleEffects\Universal\Universal", 16, 2, 32], - "", "Billboard", 1, (0.1 + (random 0.2)) * _factor, - _ringOrigin, - [0, -20 * (_factor / 2), 0], - 0, 10, 7.9, 0.075, - [1.25 * _factor, _flameSize * _factor], - [[1, 1, 1, -2], [1, 1, 1, -2], [1, 1, 1, -1], [1, 1, 1, -0]], - [2 + random 1], 1, 0, "", "", _obj - ]; - drop [ - ["\A3\data_f\ParticleEffects\Universal\Universal", 16, 2, 32], - "", "Billboard", 1, (0.1 + (random 0.2)) * _factor, - _ringOrigin, - [20 * (_factor / 2), 0, 0], - 0, 10, 7.9, 0.075, - [1.25 * _factor, _flameSize * _factor], - [[1, 1, 1, -2], [1, 1, 1, -2], [1, 1, 1, -1], [1, 1, 1, -0]], - [2 + random 1], 1, 0, "", "", _obj - ]; - drop [ - ["\A3\data_f\ParticleEffects\Universal\Universal", 16, 2, 32], - "", "Billboard", 1, (0.1 + (random 0.2)) * _factor, - [-0.1 + random 0.2, -0.1 + random 0.2, -1], - [-20 * (_factor / 2), 0, 0], - 0, 10, 7.9, 0.075, - [1.25 * _factor, _flameSize * _factor], - [[1, 1, 1, -2], [1, 1, 1, -2], [1, 1, 1, -1], [1, 1, 1, -0]], - [2 + random 1], 1, 0, "", "", _obj - ]; - - private _dir = 20 * (_factor / 2); - drop [ - ["\A3\data_f\ParticleEffects\Universal\Universal", 16, 2, 32], - "", "Billboard", 1, (0.1 + (random 0.2)) * _factor, - _ringOrigin, - [_dir, _dir, 0], - 0, 10, 7.9, 0.075, - [1.25 * _factor, _flameSize * _factor], - [[1, 1, 1, -2],[1, 1, 1, -2], [1, 1, 1, -1], [1, 1, 1, -0]], - [2 + random 1], 1, 0, "", "", _obj - ]; - - _dir = -20 * (_factor / 2); - drop [ - ["\A3\data_f\ParticleEffects\Universal\Universal", 16, 2, 32], - "", "Billboard", 1, (0.1 + (random 0.2)) * _factor, - _ringOrigin, - [_dir, _dir, 0], - 0, 10, 7.9, 0.075, - [1.25 * _factor, _flameSize * _factor], - [[1, 1, 1, -2],[1, 1, 1, -2], [1, 1, 1, -1], [1, 1, 1, -0]], - [2 + random 1], 1, 0, "", "", _obj - ]; - - _dir = 20 * (_factor / 2); - drop [ - ["\A3\data_f\ParticleEffects\Universal\Universal",16,2,32], - "", "Billboard", 1, (0.1 + (random 0.2)) * _factor, - _ringOrigin, - [_dir, -_dir, 0], - 0, 10, 7.9, 0.075, - [1.25 * _factor, _flameSize * _factor], - [[1, 1, 1, -2], [1, 1, 1, -2], [1, 1, 1, -1], [1, 1, 1, -0]], - [2 + random 1], 1, 0, "", "", _obj - ]; - - _dir = 20 * (_factor / 2); - drop [ - ["\A3\data_f\ParticleEffects\Universal\Universal", 16, 2, 32], - "", "Billboard", 1, (0.1 + (random 0.2)) * _factor, - _ringOrigin, - [-_dir, _dir, 0], - 0, 10, 7.9, 0.075, - [1.25 * _factor, _flameSize * _factor], - [[1, 1, 1, -2], [1, 1, 1, -2], [1, 1, 1, -1], [1, 1, 1, -0]], - [2 + random 1], 1, 0, "", "", _obj - ]; - }; - - (getVehicleTIPars _obj) params ["_tiEngine", "_tiWheels", "_tiWeapon"]; - _obj setVehicleTIPars [ - // formula is designed to have the temperature ramp up quickly and then level out - (_tiEngine + (_intensity * 0.01))/1.005, - (_tiWheels + (_intensity * 0.004))/1.002, // wheels//tracks are further away from burning parts - (_tiWeapon + (_intensity * 0.01))/1.005 - ]; - -}, 0, [_obj, _jet, _ring, _time, CBA_missionTime, _light, _fireSelection, _sound, _intensity]] call CBA_fnc_addPerFrameHandler; diff --git a/addons/cookoff/functions/fnc_cookOffLocal.sqf b/addons/cookoff/functions/fnc_cookOffLocal.sqf new file mode 100644 index 0000000000..cbd160bba1 --- /dev/null +++ b/addons/cookoff/functions/fnc_cookOffLocal.sqf @@ -0,0 +1,229 @@ +#include "..\script_component.hpp" +/* + * Author: tcvm, johnb43 + * Spawn cook-off fire effects. + * + * Arguments: + * 0: Vehicle + * 1: Spawn fire jet + * 2: Spawn fire ring + * 3: What selection fire will originate from + * 4: Cookoff intensity value + * 5: Start time + * 6: Duration of effect (max 20 seconds) + * + * Return Value: + * None + * + * Example: + * [cursorObject, true, false, "commander_turret", 6, CBA_missionTime, 15] call ace_cookoff_fnc_cookOffLocal + * + * Public: No + */ + +#define FLAME_SIZE 1.5 +#define FIRE_INTENSITY 20 + +params ["_vehicle", "_jet", "_ring", "_fireSelection", "_intensity", "_startTime", "_duration"]; + +// Check if still valid for JIP players +if (isNull _vehicle || {CBA_missionTime - _startTime >= _duration}) exitWith {}; + +// Spawn light +private _light = objNull; + +if (hasInterface) then { + _light = "#lightpoint" createVehicleLocal [0, 0, 0]; + _light setLightBrightness 5; + _light setLightAmbient [0.8, 0.6, 0.2]; + _light setLightColor [1, 0.5, 0.2]; + _light lightAttachObject [_vehicle, [0, 0, 0]]; +}; + +_duration = 0 max _duration min 20; + +private _sound = objNull; +private _fireKey = ""; + +if (isServer) then { + // Spawn sound effect + if (_jet || _ring) then { + private _soundName = selectRandomWeighted [QGVAR(Sound_low), 0.1, QGVAR(Sound_mid), 0.25, QGVAR(Sound_high), 0.65]; + _sound = createSoundSource [_soundName, ASLToAGL getPosASL _vehicle, [], 0]; + _sound attachTo [_vehicle]; + }; + + // Make the ring a source of fire + if (_ring && {["ace_fire"] call EFUNC(common,isModLoaded)}) then { + _fireKey = format [QGVAR(cookoffFire_%1), hashValue _vehicle]; + + [QEGVAR(fire,addFireSource), [_vehicle, FLAME_SIZE * ((boundingBoxReal _vehicle) select 2), FIRE_INTENSITY, _fireKey]] call CBA_fnc_localEvent; + }; +}; + +[{ + (_this select 0) params ["_vehicle", "_jet", "_ring", "_startTime", "_duration", "_light", "_fireSelection", "_sound", "_intensity", "_fireKey"]; + + private _elapsedTime = CBA_missionTime - _startTime; + + // Clean up effects once effects have finished or vehicle has been deleted + if (isNull _vehicle || {_elapsedTime >= _duration}) exitWith { + (_this select 1) call CBA_fnc_removePerFrameHandler; + + deleteVehicle _light; + + if (isServer) then { + deleteVehicle _sound; + + if (["ace_fire"] call EFUNC(common,isModLoaded)) then { + [QEGVAR(fire,removeFireSource), _fireKey] call CBA_fnc_localEvent; + }; + }; + }; + + private _factor = 1 + (_elapsedTime / 2) min 2; + + if (_elapsedTime > _duration * 3 / 4) then { + _factor = _factor * linearConversion [_duration * 3 / 4, _duration, _elapsedTime, 1, 0.5]; + }; + + // Make flame push object into ground to make effect seem more "alive" + if (_jet && !isGamePaused && {local _vehicle} && {_vehicle getVariable [QGVAR(nextForceTime), 0] <= CBA_missionTime}) then { + private _force = [0, 0, _factor * -(0.5 min random 1.5) * (0.3 min random 1)] vectorMultiply getMass _vehicle; + _vehicle addForce [_force, vectorUpVisual _vehicle]; + _vehicle setVariable [QGVAR(nextForceTime), CBA_missionTime + 0.01]; // This prevents bad behaviour when setAccTime is small + }; + + // Don't spawn visual effects on machines without interfaces + if (!hasInterface) exitWith {}; + + _light setLightBrightness _factor; + + if (_jet) then { + private _particlePosition = (_vehicle selectionPosition _fireSelection) vectorAdd [-0.1 + random 0.2, -0.1 + random 0.2, 0]; + + drop [ + ["\A3\data_f\ParticleEffects\Universal\Universal", 16, 2, 32], + "", + "Billboard", + 1, + (0.1 + random 0.2) * _factor, + _particlePosition, + [0, 0, 15 * (_factor / 2)], + 0, + 10, + 7.9, + 0.075, + [1.25 * _factor, 2.5 * _factor], + [[1, 1, 1, -2], [1, 1, 1, -2], [1, 1, 1, -1], [1, 1, 1, -0]], + [2 + random 1], + 1, + 0, + "", + "", + _vehicle + ]; + }; + + if (_ring) then { + private _ringOrigin = (_vehicle selectionPosition _fireSelection) vectorAdd [-0.1 + random 0.2, -0.1 + random 0.2, -1]; + + drop [ + ["\A3\data_f\ParticleEffects\Universal\Universal",16,2,32], + "", "Billboard", 1, (0.1 + random 0.2) * _factor, + _ringOrigin, + [0, 20 * (_factor / 2), 0], + 0, 10, 7.9, 0.075, + [1.25 * _factor, FLAME_SIZE * _factor], + [[1, 1, 1, -2], [1, 1, 1, -2], [1, 1, 1, -1], [1, 1, 1, -0]], + [2 + random 1], 1, 0, "", "", _vehicle + ]; + drop [ + ["\A3\data_f\ParticleEffects\Universal\Universal", 16, 2, 32], + "", "Billboard", 1, (0.1 + random 0.2) * _factor, + _ringOrigin, + [0, -20 * (_factor / 2), 0], + 0, 10, 7.9, 0.075, + [1.25 * _factor, FLAME_SIZE * _factor], + [[1, 1, 1, -2], [1, 1, 1, -2], [1, 1, 1, -1], [1, 1, 1, -0]], + [2 + random 1], 1, 0, "", "", _vehicle + ]; + drop [ + ["\A3\data_f\ParticleEffects\Universal\Universal", 16, 2, 32], + "", "Billboard", 1, (0.1 + random 0.2) * _factor, + _ringOrigin, + [20 * (_factor / 2), 0, 0], + 0, 10, 7.9, 0.075, + [1.25 * _factor, FLAME_SIZE * _factor], + [[1, 1, 1, -2], [1, 1, 1, -2], [1, 1, 1, -1], [1, 1, 1, -0]], + [2 + random 1], 1, 0, "", "", _vehicle + ]; + drop [ + ["\A3\data_f\ParticleEffects\Universal\Universal", 16, 2, 32], + "", "Billboard", 1, (0.1 + random 0.2) * _factor, + [-0.1 + random 0.2, -0.1 + random 0.2, -1], + [-20 * (_factor / 2), 0, 0], + 0, 10, 7.9, 0.075, + [1.25 * _factor, FLAME_SIZE * _factor], + [[1, 1, 1, -2], [1, 1, 1, -2], [1, 1, 1, -1], [1, 1, 1, -0]], + [2 + random 1], 1, 0, "", "", _vehicle + ]; + + private _dir = 20 * (_factor / 2); + drop [ + ["\A3\data_f\ParticleEffects\Universal\Universal", 16, 2, 32], + "", "Billboard", 1, (0.1 + random 0.2) * _factor, + _ringOrigin, + [_dir, _dir, 0], + 0, 10, 7.9, 0.075, + [1.25 * _factor, FLAME_SIZE * _factor], + [[1, 1, 1, -2],[1, 1, 1, -2], [1, 1, 1, -1], [1, 1, 1, -0]], + [2 + random 1], 1, 0, "", "", _vehicle + ]; + + _dir = -20 * (_factor / 2); + drop [ + ["\A3\data_f\ParticleEffects\Universal\Universal", 16, 2, 32], + "", "Billboard", 1, (0.1 + (random 0.2)) * _factor, + _ringOrigin, + [_dir, _dir, 0], + 0, 10, 7.9, 0.075, + [1.25 * _factor, FLAME_SIZE * _factor], + [[1, 1, 1, -2],[1, 1, 1, -2], [1, 1, 1, -1], [1, 1, 1, -0]], + [2 + random 1], 1, 0, "", "", _vehicle + ]; + + _dir = 20 * (_factor / 2); + drop [ + ["\A3\data_f\ParticleEffects\Universal\Universal",16,2,32], + "", "Billboard", 1, (0.1 + (random 0.2)) * _factor, + _ringOrigin, + [_dir, -_dir, 0], + 0, 10, 7.9, 0.075, + [1.25 * _factor, FLAME_SIZE * _factor], + [[1, 1, 1, -2], [1, 1, 1, -2], [1, 1, 1, -1], [1, 1, 1, -0]], + [2 + random 1], 1, 0, "", "", _vehicle + ]; + + _dir = 20 * (_factor / 2); + drop [ + ["\A3\data_f\ParticleEffects\Universal\Universal", 16, 2, 32], + "", "Billboard", 1, (0.1 + random 0.2) * _factor, + _ringOrigin, + [-_dir, _dir, 0], + 0, 10, 7.9, 0.075, + [1.25 * _factor, FLAME_SIZE * _factor], + [[1, 1, 1, -2], [1, 1, 1, -2], [1, 1, 1, -1], [1, 1, 1, -0]], + [2 + random 1], 1, 0, "", "", _vehicle + ]; + }; + + (getVehicleTIPars _vehicle) params ["_tiEngine", "_tiWheels", "_tiWeapon"]; + + // Formula is designed to have the temperature ramp up quickly and then level out + _vehicle setVehicleTIPars [ + (_tiEngine + _intensity * 0.01) / 1.005, + (_tiWheels + _intensity * 0.004) / 1.002, // Wheels/tracks are further away from burning parts + (_tiWeapon + _intensity * 0.01) / 1.005 + ]; +}, 0, [_vehicle, _jet, _ring, _startTime, _duration, _light, _fireSelection, _sound, _intensity, _fireKey]] call CBA_fnc_addPerFrameHandler; diff --git a/addons/cookoff/functions/fnc_cookOffServer.sqf b/addons/cookoff/functions/fnc_cookOffServer.sqf new file mode 100644 index 0000000000..303555ba28 --- /dev/null +++ b/addons/cookoff/functions/fnc_cookOffServer.sqf @@ -0,0 +1,202 @@ +#include "..\script_component.hpp" +/* + * Author: tcvm, johnb43 + * Start a cook-off in the given vehicle. + * Spews flames in multiple directions at the same time (ring) or from the turret towards the sky (jet). + * + * Arguments: + * 0: Vehicle + * 1: Intensity of fire + * 2: Source (default: objNull) + * 3: Instigator (default: objNull) + * 4: Delay between smoke and fire enabled (default: true) + * 5: Ammo detonation chance (default: 0) + * 6: Detonate after cook-off (default: false) + * 7: Selection for fire source (default: "") + * 8: Can spawn fire ring (default: true) + * 9: Can spawn fire jet (default: true) + * 10: Maximum intensity (default: MAX_COOKOFF_INTENSITY) + * + * Return Value: + * None + * + * Example: + * [cursorObject, 3] call ace_cookoff_fnc_cookOffServer + * + * Public: No + */ + +if (!isServer) exitWith {}; +if (!GVAR(enableFire) || {GVAR(cookoffDuration) == 0}) exitWith {}; + +params [ + "_vehicle", + "_intensity", + ["_source", objNull], + ["_instigator", objNull], + ["_delayBetweenSmokeAndFire", true], + ["_ammoDetonationChance", 0], + ["_detonateAfterCookoff", false], + ["_fireSelection", ""], + ["_canRing", true], + ["_canJet", true], + ["_maxIntensity", MAX_COOKOFF_INTENSITY] +]; + +// Make sure it's a vehicle (important, because deleted EH is assigned to AllVehicles only in postInit) +if !(_vehicle isKindOf "AllVehicles") exitWith {}; + +if (_vehicle isKindOf "CAManBase" || {_vehicle isKindOf "StaticWeapon"}) exitWith {}; + +// If under water, ignore +// underwater is not very reliable, so use model center instead +if (underwater _vehicle || {private _posASL = getPosWorld _vehicle; surfaceIsWater _posASL && {(_posASL select 2) < 0}}) exitWith {}; + +// Check if cook-off is disabled on vehicle specifically +if !(_vehicle getVariable [QGVAR(enable), true]) exitWith {}; // QGVAR(enable) is API + +TRACE_3("cooking off",_vehicle,_intensity,_maxIntensity); +TRACE_8("",_source,_instigator,_delayBetweenSmokeAndFire,_ammoDetonationChance,_detonateAfterCookoff,_fireSelection,_canRing,_canJet); + +if (_vehicle getVariable [QGVAR(isCookingOff), false]) exitWith {}; + +_vehicle setVariable [QGVAR(isCookingOff), true, true]; + +// Limit maximum value of intensity to prevent very long cook-off times +_intensity = _intensity min _maxIntensity; + +private _selections = getArray (configOf _vehicle >> QGVAR(cookoffSelections)) select {(_vehicle selectionPosition _x) isNotEqualTo [0, 0, 0]}; + +if (_selections isEqualTo []) then { + WARNING_1("no valid selection for cookoff found. %1",typeOf _vehicle); + + { + if ((_vehicle selectionPosition _x) isNotEqualTo [0, 0, 0]) then { + _selections pushBack _x; + }; + } forEach DEFAULT_COMMANDER_HATCHES; + + if (_selections isEqualTo []) then { + _selections pushBack "#noselection"; + }; +}; + +// Not guaranteed to be active/used, but reserve it nonetheless +private _fireJipID = format [QGVAR(cookOffLocal_%1), hashValue _vehicle]; +[_fireJipID, _vehicle] call CBA_fnc_removeGlobalEventJIP; + +// Spawn smoke +private _smokeJipID = [QGVAR(smoke), [_vehicle, _selections]] call CBA_fnc_globalEventJIP; +[_smokeJipID, _vehicle] call CBA_fnc_removeGlobalEventJIP; + +// Save intensity for looping purposes +_vehicle setVariable [QGVAR(intensity), _intensity]; + +private _delay = 0; + +if (_delayBetweenSmokeAndFire) then { + _delay = random [SMOKE_DELAY, 1.5 * SMOKE_DELAY, 2 * SMOKE_DELAY]; +}; + +[{ + [{ + (_this select 0) params ["_vehicle", "_selections", "_ammoDetonationChance", "_detonateAfterCookoff", "_source", "_instigator", "_fireSelection", "_canRing", "_canJet", "_smokeJipID", "_fireJipID"]; + + if ( + isNull _vehicle || + !GVAR(enableFire) || + {!(_vehicle getVariable [QGVAR(enable), true])} || // QGVAR(enable) is API + {GVAR(cookoffDuration) == 0} || + {underwater _vehicle} || + {private _posASL = getPosWorld _vehicle; surfaceIsWater _posASL && {(_posASL select 2) < 0}} // Underwater is not very reliable, so use model center instead + ) exitWith { + // Effects are deleted when vehicle is deleted + (_this select 1) call CBA_fnc_removePerFrameHandler; + }; + + private _intensity = _vehicle getVariable [QGVAR(intensity), 0]; + + if (_intensity <= 1) exitWith { + (_this select 1) call CBA_fnc_removePerFrameHandler; + + // Wait until the previous flame has finished + private _nextFlameTime = (_vehicle getVariable [QGVAR(endCurrentFlame), CBA_missionTime]) - CBA_missionTime + (MIN_TIME_BETWEEN_FLAMES max random MAX_TIME_BETWEEN_FLAMES); + + if (_fireSelection isEqualTo "") then { + _fireSelection = selectRandom _selections; + }; + + [{ + params ["_vehicle", "_source", "_instigator", "_detonateAfterCookoff", "_fireSelection", "_smokeJipID", "_fireJipID"]; + + // Effects are deleted when vehicle is deleted + if (isNull _vehicle) exitWith {}; + + // Remove effects from JIP + _smokeJipID call CBA_fnc_removeGlobalEventJIP; + _fireJipID call CBA_fnc_removeGlobalEventJIP; + + // Remove effects + [QGVAR(cleanupEffects), _vehicle] call CBA_fnc_globalEvent; + + // Reset variable, so it can cook-off again + _vehicle setVariable [QGVAR(isCookingOff), nil, true]; + + if (GVAR(destroyVehicleAfterCookoff) || _detonateAfterCookoff) then { + createVehicle ["ACE_ammoExplosionLarge", _vehicle modelToWorld (_vehicle selectionPosition _fireSelection), [], 0 , "CAN_COLLIDE"]; + + _vehicle setDamage [1, true, _source, _instigator]; // Because it's running on the server, source and instigator can be set + }; + }, [_vehicle, _source, _instigator, _detonateAfterCookoff, _fireSelection, _smokeJipID, _fireJipID], _nextFlameTime] call CBA_fnc_waitAndExecute; + }; + + // Wait until we are ready for the next flame + if ((_vehicle getVariable [QGVAR(nextFlame), 0]) <= CBA_missionTime) then { + private _ring = false; + + if (_canRing) then { + _ring = 0.2 > random 1; + + if (!_ring && {_intensity >= 2}) then { + _ring = 0.7 > random 1; + }; + }; + + private _duration = linearConversion [0, 10, _intensity, 3, 20] + random COOKOFF_TIME; + + if (_fireSelection isEqualTo "") then { + _fireSelection = selectRandom _selections; + }; + + // Sync for JIP players + [QGVAR(cookOffLocal), [_vehicle, _canJet, _ring, _fireSelection, _intensity, CBA_missionTime, _duration], _fireJipID] call CBA_fnc_globalEventJIP; + + // If there are any crew, burn them + if (["ace_fire"] call EFUNC(common,isModLoaded)) then { + // Use current intensity, in case GVAR(cookoffDuration) is very large and only 1 flameout stage happens + { + [QEGVAR(fire,burn), [_x, _intensity * 1.5, _instigator]] call CBA_fnc_globalEvent; + } forEach (crew _vehicle); + }; + + _intensity = (_intensity - (0.5 max random 1) / GVAR(cookoffDuration)) max 0; + + _vehicle setVariable [QGVAR(intensity), _intensity]; + _vehicle setVariable [QGVAR(endCurrentFlame), CBA_missionTime + _duration]; + _vehicle setVariable [QGVAR(nextFlame), CBA_missionTime + _duration + (MIN_TIME_BETWEEN_FLAMES max random MAX_TIME_BETWEEN_FLAMES)]; + }; + + if (_ammoDetonationChance > random 1 && {_vehicle getVariable [QGVAR(nextExplosiveDetonation), 0] <= CBA_missionTime}) then { + if (_fireSelection isEqualTo "") then { + _fireSelection = selectRandom _selections; + }; + + createVehicle ["ACE_ammoExplosionLarge", _vehicle modelToWorld (_vehicle selectionPosition _fireSelection), [], 0 , "CAN_COLLIDE"]; + + _vehicle setVariable [QGVAR(nextExplosiveDetonation), CBA_missionTime + random 60]; + }; + }, 0.25, _this] call CBA_fnc_addPerFrameHandler; +}, [_vehicle, _selections, _ammoDetonationChance, _detonateAfterCookoff, _source, _instigator, _fireSelection, _canRing, _canJet, _smokeJipID, _fireJipID], _delay] call CBA_fnc_waitAndExecute; + +// API +[QGVAR(cookoff), [_vehicle, _intensity, _instigator, _smokeDelayEnabled, _ammoDetonationChance, _detonateAfterCookoff, _fireSelection, _canRing, _maxIntensity, _canJet]] call CBA_fnc_globalEvent; diff --git a/addons/cookoff/functions/fnc_detonateAmmunition.sqf b/addons/cookoff/functions/fnc_detonateAmmunition.sqf deleted file mode 100644 index 9b3c19ab42..0000000000 --- a/addons/cookoff/functions/fnc_detonateAmmunition.sqf +++ /dev/null @@ -1,132 +0,0 @@ -#include "..\script_component.hpp" -/* - * Author: Glowbal - * Detonates ammunition from a vehicle until no ammo left - * - * Arguments: - * 0: vehicle - * 1: Ammo Array - * - 0: Magazine Classname - * - 1: Ammo Count - * 2: Total Ammo Count - * - * Return Value: - * None - * - * Example: - * [_vehicle, magazinesAmmo _vehicle] call ace_cookoff_fnc_detonateAmmunition - * - * Public: No - */ - -params ["_vehicle", "_magazines", "_totalAmmo"]; - -if (GVAR(enable) == 0) exitWith {}; -if !(GVAR(enableAmmoCookoff)) exitWith {}; - -if (isNull _vehicle) exitWith {}; // vehicle got deleted -if (_magazines isEqualTo []) exitWith {}; // nothing to detonate anymore -if (underwater _vehicle) exitWith {}; - -private _magazineIndex = floor random(count _magazines); -private _magazine = _magazines select _magazineIndex; -_magazine params ["_magazineClassname", "_amountOfMagazines"]; - -if (_amountOfMagazines < 0) exitWith { - ERROR_1("mag with no ammo - %1",_magazine); -}; -private _removed = _amountOfMagazines min floor(1 + random(6 / GVAR(ammoCookoffDuration))); - -_amountOfMagazines = _amountOfMagazines - _removed; -if (_amountOfMagazines <= 0) then { - _magazines deleteAt _magazineIndex; -} else { - _magazine set [1, _amountOfMagazines]; // clear out the magazine -}; -private _timeBetweenAmmoDetonation = (((random 10) / (sqrt _totalAmmo)) min MAX_TIME_BETWEEN_AMMO_DET) max 0.1; -TRACE_2("",_totalAmmo,_timeBetweenAmmoDetonation); -_totalAmmo = _totalAmmo - _removed; - -private _ammo = getText (configFile >> "CfgMagazines" >> _magazineClassname >> "ammo"); -private _ammoCfg = configFile >> "CfgAmmo" >> _ammo; - -private _speedOfAmmo = getNumber (configFile >> "CfgMagazines" >> _magazineClassname >> "initSpeed"); -private _simType = getText (_ammoCfg >> "simulation"); - -private _effect2pos = _vehicle selectionPosition "destructionEffect2"; - -private _spawnProjectile = { - params ["_vehicle", "_ammo", "_speed", "_flyAway"]; - - private _spawnPos = _vehicle modelToWorld [-0.2 + (random 0.4), -0.2 + (random 0.4), random 3]; - if (_spawnPos select 2 < 0) then { - _spawnPos set [2, 0]; - }; - - private _projectile = createVehicle [_ammo, _spawnPos, [], 0, "CAN_COLLIDE"]; - if (_flyAway) then { - private _vectorAmmo = [(-1 + (random 2)), (-1 + (random 2)), -0.2 + (random 1)]; - private _velVec = _vectorAmmo vectorMultiply _speed; - _projectile setVectorDir _velVec; - _projectile setVelocity _velVec; - } else { - _projectile setDamage 1; - }; - - _projectile; -}; - -private _speed = random (_speedOfAmmo / 10) max 1; -_simType = toLowerANSI _simType; -switch (_simType) do { - case ("shotbullet"): { - [QGVAR(playCookoffSound), [_vehicle, _simType]] call CBA_fnc_globalEvent; - if (random 1 < 0.6) then { - [_vehicle, _ammo, _speed, true] call _spawnProjectile; - }; - }; - case ("shotshell"): { - [QGVAR(playCookoffSound), [_vehicle, _simType]] call CBA_fnc_globalEvent; - if (random 1 < 0.15) then { - [_vehicle, _ammo, _speed, true] call _spawnProjectile; - }; - }; - case ("shotgrenade"): { - if (random 1 < 0.9) then { - _speed = 0; - }; - [_vehicle, _ammo, _speed, random 1 < 0.5] call _spawnProjectile; - }; - case ("shotrocket"); - case ("shotmissile"); - case ("shotsubmunitions"): { - if (random 1 < 0.1) then { - [QGVAR(playCookoffSound), [_vehicle, _simType]] call CBA_fnc_globalEvent; - [_vehicle, _ammo, _speed, random 1 < 0.3] call _spawnProjectile; - } else { - createvehicle ["ACE_ammoExplosionLarge", (_vehicle modelToWorld _effect2pos), [], 0 , "CAN_COLLIDE"]; - }; - }; - case ("shotmine"); - case ("shotdirectionalbomb"): { - if (random 1 < 0.5) then { - // Not all explosives detonate on destruction, some have scripted alternatives - private _scripted = getNumber (_ammoCfg >> "triggerWhenDestroyed") == 1; - if !(_scripted) then { - _ammo = getText (_ammoCfg >> "ace_explosives_Explosive"); - }; - // If a scripted alternative doesn't exist use generic explosion - if (_ammo != "") then { - [_vehicle, _ammo, 0, false] call _spawnProjectile; - } else { - createvehicle ["SmallSecondary", (_vehicle modelToWorld _effect2pos), [], 0 , "CAN_COLLIDE"]; - }; - }; - }; - case ("shotilluminating"): { - if (random 1 < 0.15) then { - [_vehicle, _ammo, _speed, random 1 < 0.3] call _spawnProjectile; - }; - }; -}; -[FUNC(detonateAmmunition), [_vehicle, _magazines, _totalAmmo], _timeBetweenAmmoDetonation] call CBA_fnc_waitAndExecute; diff --git a/addons/cookoff/functions/fnc_detonateAmmunitionServer.sqf b/addons/cookoff/functions/fnc_detonateAmmunitionServer.sqf new file mode 100644 index 0000000000..43ac730e09 --- /dev/null +++ b/addons/cookoff/functions/fnc_detonateAmmunitionServer.sqf @@ -0,0 +1,54 @@ +#include "..\script_component.hpp" +/* + * Author: johnb43 + * Starts detonating ammunition from an object (e.g. vehicle or crate). + * + * Arguments: + * 0: Object + * 1: Destroy when finished (default: false) + * 2: Source (default: objNull) + * 3: Instigator (default: objNull) + * 4: Initial delay (default: 0) + * + * Return Value: + * None + * + * Example: + * [cursorObject] call ace_cookoff_fnc_detonateAmmunitionServer + * + * Public: No + */ + +if (!isServer) exitWith {}; + +params ["_object", ["_destroyWhenFinished", false], ["_source", objNull], ["_instigator", objNull], ["_initialDelay", 0]]; + +if (isNull _object) exitWith {}; + +// Check if the object can cook its ammo off +if ( + underwater _object || + {private _posASL = getPosWorld _object; surfaceIsWater _posASL && {(_posASL select 2) < 0}} || // Underwater is not very reliable, so use model center instead + {GVAR(ammoCookoffDuration) == 0} || + {!([GVAR(enableAmmoCookoff), GVAR(enableAmmobox)] select (_object isKindOf "ReammoBox_F"))} || + {!(_object getVariable [QGVAR(enableAmmoCookoff), true])} +) exitWith {}; + +// Don't have an object detonate its ammo twice +if (_object getVariable [QGVAR(isAmmoDetonating), false]) exitWith {}; + +_object setVariable [QGVAR(isAmmoDetonating), true, true]; + +_object setVariable [QGVAR(cookoffMagazines), _object call FUNC(getVehicleAmmo)]; + +// TODO: When setMagazineTurretAmmo and magazineTurretAmmo are fixed (https://feedback.bistudio.com/T79689), +// we can add gradual ammo removal during cook-off +if (GVAR(removeAmmoDuringCookoff)) then { + clearMagazineCargoGlobal _object; + + { + [QEGVAR(common,removeMagazinesTurret), [_object, _x select 0, _x select 1], _object, _x select 1] call CBA_fnc_turretEvent; + } forEach (magazinesAllTurrets _object); +}; + +[LINKFUNC(detonateAmmunitionServerLoop), [_object, _destroyWhenFinished, _source, _instigator], _initialDelay] call CBA_fnc_waitAndExecute; diff --git a/addons/cookoff/functions/fnc_detonateAmmunitionServerLoop.sqf b/addons/cookoff/functions/fnc_detonateAmmunitionServerLoop.sqf new file mode 100644 index 0000000000..7fdcedda51 --- /dev/null +++ b/addons/cookoff/functions/fnc_detonateAmmunitionServerLoop.sqf @@ -0,0 +1,181 @@ +#include "..\script_component.hpp" +/* + * Author: Glowbal, johnb43 + * Detonates ammunition from an object (e.g. vehicle or crate) until no ammo is left. + * + * Arguments: + * 0: Object + * 1: Destroy when finished + * 2: Source + * 3: Instigator + * + * Return Value: + * None + * + * Example: + * [cursorObject, true, player, player] call ace_cookoff_fnc_detonateAmmunitionServerLoop + * + * Public: No + */ + +params ["_object", "_destroyWhenFinished", "_source", "_instigator"]; + +if (isNull _object) exitWith {}; + +(_object getVariable QGVAR(cookoffMagazines)) params ["_magazines", "_totalAmmo"]; + +private _hasFinished = _totalAmmo <= 0 || {_magazines isEqualTo []}; + +// If the cook-off has finished or been interrupted, clean up the effects for boxes (no vehicle effects) +if ( + _hasFinished || + {underwater _object} || + {private _posASL = getPosWorld _object; surfaceIsWater _posASL && {(_posASL select 2) < 0}} || // Underwater is not very reliable, so use model center instead + {GVAR(ammoCookoffDuration) == 0} || + {!([GVAR(enableAmmoCookoff), GVAR(enableAmmobox)] select (_object isKindOf "ReammoBox_F"))} || + {!(_object getVariable [QGVAR(enableAmmoCookoff), true])} +) exitWith { + // Box cook-off fire ends after the ammo has detonated (vehicle cook-off fire does not depend on the ammo detonation) + if (_object isKindOf "ReammoBox_F") then { + [QGVAR(cleanupEffects), _object] call CBA_fnc_globalEvent; + + // Reset variable, so the box can cook-off again + _object setVariable [QGVAR(isCookingOff), nil, true]; + + // Remove cook-off effects from box + private _jipID = _object getVariable QGVAR(cookoffBoxJipID); + + if (isNil "_jipID") exitWith {}; + + _jipID call CBA_fnc_removeGlobalEventJIP; + + _object setVariable [QGVAR(cookoffBoxJipID), nil]; + }; + + // Reset variables, so the object can detonate its ammo again + _object setVariable [QGVAR(cookoffMagazines), nil]; + _object setVariable [QGVAR(isAmmoDetonating), nil, true]; + + // If done, destroy the object if necessary + if (_hasFinished && _destroyWhenFinished) then { + _object setDamage [1, true, _source, _instigator]; + }; +}; + +private _magazineIndex = floor random (count _magazines); +private _magazine = _magazines select _magazineIndex; +_magazine params ["_magazineClassname", "_ammoCount", "_spawnProjectile"]; + +// Make sure ammo is at least 0 +_ammoCount = _ammoCount max 0; + +// Remove some ammo, which will be detonated +private _removed = _ammoCount min floor (1 + random (6 / GVAR(ammoCookoffDuration))); + +_ammoCount = _ammoCount - _removed; + +if (_ammoCount <= 0) then { + _magazines deleteAt _magazineIndex; +} else { + _magazine set [1, _ammoCount]; // remove ammo that was detonated +}; + +private _timeBetweenAmmoDetonation = ((random 10 / sqrt _totalAmmo) min MAX_TIME_BETWEEN_AMMO_DET) max 0.1; +TRACE_2("",_totalAmmo,_timeBetweenAmmoDetonation); +_totalAmmo = _totalAmmo - _removed; + +_object setVariable [QGVAR(cookoffMagazines), [_magazines, _totalAmmo]]; + +// Get magazine info, which is used to spawn projectiles +private _configMagazine = configFile >> "CfgMagazines" >> _magazineClassname; +private _ammo = getText (_configMagazine >> "ammo"); +private _configAmmo = configFile >> "CfgAmmo" >> _ammo; + +private _simType = toLower getText (_configAmmo >> "simulation"); +private _speed = linearConversion [0, 1, random 1, 1, 20, true]; +private _effect2pos = _object selectionPosition "destructionEffect2"; + +// Spawns the projectiles, making them either fly in random directions or explode +private _fnc_spawnProjectile = { + // If the magazines are inside of the cargo (inventory), don't let their projectiles escape the interior of the vehicle + if (!_spawnProjectile) exitWith {}; + + params ["_object", "_ammo", "_speed", "_flyAway"]; + + private _spawnPos = _object modelToWorld [-0.2 + random 0.4, -0.2 + random 0.4, random 3]; + + if (_spawnPos select 2 < 0) then { + _spawnPos set [2, 0]; + }; + + private _projectile = createVehicle [_ammo, _spawnPos, [], 0, "CAN_COLLIDE"]; + + if (_flyAway) then { + private _vectorAmmo = [-1 + random 2, -1 + random 2, -0.2 + random 1]; + private _vectorVelocity = _vectorAmmo vectorMultiply _speed; + + _projectile setVectorDir _vectorVelocity; + _projectile setVelocity _vectorVelocity; + } else { + _projectile setDamage 1; + }; +}; + +switch (_simType) do { + case "shotbullet": { + [QGVAR(playCookoffSound), [_object, _simType]] call CBA_fnc_globalEvent; + + if (random 1 < 0.6) then { + [_object, _ammo, _speed, true] call _fnc_spawnProjectile; + }; + }; + case "shotshell": { + [QGVAR(playCookoffSound), [_object, _simType]] call CBA_fnc_globalEvent; + + if (random 1 < 0.15) then { + [_object, _ammo, _speed, true] call _fnc_spawnProjectile; + }; + }; + case "shotgrenade": { + if (random 1 < 0.9) then { + _speed = 0; + }; + + [_object, _ammo, _speed, random 1 < 0.5] call _fnc_spawnProjectile; + }; + case "shotrocket"; + case "shotmissile"; + case "shotsubmunitions": { + if (random 1 < 0.1) then { + [QGVAR(playCookoffSound), [_object, _simType]] call CBA_fnc_globalEvent; + + [_object, _ammo, _speed, random 1 < 0.3] call _fnc_spawnProjectile; + } else { + createVehicle ["ACE_ammoExplosionLarge", _object modelToWorld _effect2pos, [], 0 , "CAN_COLLIDE"]; + }; + }; + case "shotdirectionalbomb"; + case "shotmine": { + if (random 1 < 0.5) then { + // Not all explosives detonate on destruction, some have scripted alternatives + if (getNumber (_configAmmo >> "triggerWhenDestroyed") != 1) then { + _ammo = getText (_configAmmo >> QEGVAR(explosives,explosive)); + }; + + // If a scripted alternative doesn't exist use generic explosion + if (_ammo != "") then { + [_object, _ammo, 0, false] call _fnc_spawnProjectile; + } else { + createVehicle ["SmallSecondary", _object modelToWorld _effect2pos, [], 0 , "CAN_COLLIDE"]; + }; + }; + }; + case "shotilluminating": { + if (random 1 < 0.15) then { + [_object, _ammo, _speed, random 1 < 0.3] call _fnc_spawnProjectile; + }; + }; +}; + +// Detonate the remaining ammo after a delay +[LINKFUNC(detonateAmmunitionServerLoop), [_object, _destroyWhenFinished, _source, _instigator], _timeBetweenAmmoDetonation] call CBA_fnc_waitAndExecute; diff --git a/addons/cookoff/functions/fnc_engineFire.sqf b/addons/cookoff/functions/fnc_engineFire.sqf deleted file mode 100644 index 118537b30a..0000000000 --- a/addons/cookoff/functions/fnc_engineFire.sqf +++ /dev/null @@ -1,51 +0,0 @@ -#include "..\script_component.hpp" -/* - * Author: KoffeinFlummi, commy2 - * Start fire in engine block of a car. - * - * Arguments: - * 0: Vehicle - * - * Return Value: - * None - * - * Example: - * (vehicle player) call ace_cookoff_fnc_engineFire - * - * Public: No - */ - -params ["_vehicle"]; - -if (_vehicle getVariable [QGVAR(isEngineSmoking), false]) exitWith {}; -_vehicle setVariable [QGVAR(isEngineSmoking), true]; - -if (local _vehicle) then { - [QGVAR(engineFire), _vehicle] call CBA_fnc_globalEvent; -}; - -private _offset = getArray (_vehicle call CBA_fnc_getObjectConfig >> QGVAR(engineSmokeOffset)); - -if (_offset isEqualTo []) then { - _offset = [0,0,0]; -}; - -private _position = [ - 0, - (boundingBoxReal _vehicle select 1 select 1) - 2, - (boundingBoxReal _vehicle select 0 select 2) + 2 -] vectorAdd _offset; - -private _smoke = "#particlesource" createVehicleLocal [0,0,0]; -_smoke setParticleClass "ObjectDestructionSmoke1_2Smallx"; -_smoke attachTo [_vehicle, _position]; - -[{ - (_this select 0) params ["_vehicle", "_smoke", "_time"]; - - if (isNull _vehicle || {!alive _vehicle} || {_vehicle getHitPointDamage "HitEngine" < 0.9} || {CBA_missionTime > _time}) then { - deleteVehicle _smoke; - _vehicle setVariable [QGVAR(isEngineSmoking), false]; - [_this select 1] call CBA_fnc_removePerFrameHandler; - }; -}, 5, [_vehicle, _smoke, CBA_missionTime + 240]] call CBA_fnc_addPerFrameHandler; diff --git a/addons/cookoff/functions/fnc_engineFireLocal.sqf b/addons/cookoff/functions/fnc_engineFireLocal.sqf new file mode 100644 index 0000000000..afd6827d6b --- /dev/null +++ b/addons/cookoff/functions/fnc_engineFireLocal.sqf @@ -0,0 +1,81 @@ +#include "..\script_component.hpp" +/* + * Author: KoffeinFlummi, commy2, johnb43 + * Start fire in engine block of a car. + * + * Arguments: + * 0: Vehicle + * 1: End time + * + * Return Value: + * None + * + * Example: + * [cursorObject, CBA_missionTime + 10] call ace_cookoff_fnc_engineFireLocal + * + * Public: No + */ + +params ["_vehicle", "_endTime"]; + +// For JIP players and if the time wasn't set properly +if (_endTime < CBA_missionTime) exitWith {}; + +private _smoke = objNull; + +if (hasInterface) then { + private _hitPoints = getAllHitPointsDamage _vehicle; + + // Get hitpoint for engine + private _index = (_hitPoints select 0) findIf {_x == "hitengine"}; + + // Get corresponding selection + private _position = if (_index != -1) then { + _vehicle selectionPosition [(_hitPoints select 1) select _index, "HitPoints", "AveragePoint"] + } else { + [0, 0, 0] + }; + + if (_position isEqualTo [0, 0, 0]) then { + // Get offset for engine smoke if there is one + private _offset = getArray (configOf _vehicle >> QGVAR(engineSmokeOffset)); + + if (_offset isEqualTo []) then { + _offset = [0, 0, 0]; + }; + + _position = [ + 0, + (boundingBoxReal _vehicle select 1 select 1) - 2, + (boundingBoxReal _vehicle select 0 select 2) + 2 + ] vectorAdd _offset; + }; + + // Spawn smoke + _smoke = createVehicleLocal ["#particlesource", ASLToAGL getPosASL _vehicle, [], 0, "CAN_COLLIDE"];; + _smoke setParticleClass "ObjectDestructionSmoke1_2Smallx"; + _smoke attachTo [_vehicle, _position]; +}; + +[{ + (_this select 0) params ["_vehicle", "_smoke", "_endTime"]; + + if (alive _vehicle && {_vehicle getHitPointDamage "HitEngine" >= 0.9} && {CBA_missionTime < _endTime}) exitWith {}; + + (_this select 1) call CBA_fnc_removePerFrameHandler; + + deleteVehicle _smoke; + + if (!isServer || {isNull _vehicle}) exitWith {}; + + // Reset variable, so engine can smoke again in the future + _vehicle setVariable [QGVAR(isEngineSmoking), nil, true]; + + private _jipID = _vehicle getVariable QGVAR(engineFireJipID); + + if (isNil "_jipID") exitWith {}; + + _jipID call CBA_fnc_removeGlobalEventJIP; + + _vehicle setVariable [QGVAR(engineFireJipID), nil]; +}, 5, [_vehicle, _smoke, _endTime]] call CBA_fnc_addPerFrameHandler; diff --git a/addons/cookoff/functions/fnc_engineFireServer.sqf b/addons/cookoff/functions/fnc_engineFireServer.sqf new file mode 100644 index 0000000000..0d435029b8 --- /dev/null +++ b/addons/cookoff/functions/fnc_engineFireServer.sqf @@ -0,0 +1,34 @@ +#include "..\script_component.hpp" +/* + * Author: KoffeinFlummi, commy2, johnb43 + * Start fire in engine block of a car. + * + * Arguments: + * 0: Vehicle + * + * Return Value: + * None + * + * Example: + * cursorObject call ace_cookoff_fnc_engineFireServer + * + * Public: No + */ + +if (!isServer) exitWith {}; + +params ["_vehicle"]; + +// If already smoking, stop +if (_vehicle getVariable [QGVAR(isEngineSmoking), false]) exitWith {}; + +_vehicle setVariable [QGVAR(isEngineSmoking), true, true]; + +// Spawn engine fire effects on all connected machines +private _jipID = [QGVAR(engineFireLocal), [_vehicle, CBA_missionTime + random [ENGINE_FIRE_TIME / 2, ENGINE_FIRE_TIME, ENGINE_FIRE_TIME / 2 * 3]]] call CBA_fnc_globalEventJIP; +[_jipID, _vehicle] call CBA_fnc_removeGlobalEventJIP; + +_vehicle setVariable [QGVAR(engineFireJipID), _jipID]; + +// API +[QGVAR(engineFire), [_vehicle]] call CBA_fnc_globalEvent; diff --git a/addons/cookoff/functions/fnc_getVehicleAmmo.sqf b/addons/cookoff/functions/fnc_getVehicleAmmo.sqf index f6be84c1f9..df4385d30d 100644 --- a/addons/cookoff/functions/fnc_getVehicleAmmo.sqf +++ b/addons/cookoff/functions/fnc_getVehicleAmmo.sqf @@ -1,65 +1,76 @@ #include "..\script_component.hpp" /* * Author: PabstMirror - * Gets all magazines inside of a vehicle. + * Gets all magazines inside of an object. * * Arguments: - * 0: Vehicle + * 0: Object * * Return Value: - * 0: Ammo Array - * - 0: Magazine Classname - * - 1: Ammo Count - * 1: Total Ammo Count + * 0: Ammo array + * - 0: Magazine classname + * - 1: Ammo count + * - 2: If a projectile should be spawned upon detonation + * 1: Total ammo count * * Example: - * [vehicle player] call ace_cookoff_fnc_getVehicleAmmo + * cursorObject call ace_cookoff_fnc_getVehicleAmmo * * Public: No */ -params ["_vehicle"]; -TRACE_1("getVehicleAmmo",_vehicle); +params ["_object"]; +TRACE_1("getVehicleAmmo",_object); private _ammoToDetonate = []; private _totalAmmo = 0; +private _cfgMagazines = configFile >> "CfgMagazines"; +private _cfgAmmo = configFile >> "CfgAmmo"; +private _ammo = ""; // Get ammo from turrets { - _x params ["_mag", "_turret", "_count"]; - // if the turret is an FFV seat, it takes magazines from the soldier - if (_count > 0) then { - if (_mag call FUNC(isMagazineFlare)) then {continue}; - private _ammo = getText (configFile >> "CfgMagazines" >> _mag >> "ammo"); - private _model = getText (configFile >> "CfgAmmo" >> _ammo >> "model"); - if (_model == "\A3\weapons_f\empty") exitWith {TRACE_3("skipping",_mag,_ammo,_model);}; - _ammoToDetonate pushBack [_mag, _count]; + // If the turret is an FFV seat, it takes magazines from the soldier + _x params ["_magazine", "", "_count"]; + + if (_count > 0 && {!(_magazine call FUNC(isMagazineFlare))}) then { + _ammo = getText (_cfgMagazines >> _magazine >> "ammo"); + + if (getText (_cfgAmmo >> _ammo >> "model") == "\A3\weapons_f\empty") then { + TRACE_2("skipping",_magazine,_ammo); + + continue; + }; + + _ammoToDetonate pushBack [_magazine, _count, true]; _totalAmmo = _totalAmmo + _count; }; -} forEach (magazinesAllTurrets [_vehicle, true]); +} forEach (magazinesAllTurrets [_object, true]); // Get ammo from cargo space { - _x params ["_mag", "_count"]; - if (_count > 0) then { - if (_mag call FUNC(isMagazineFlare)) then {continue}; - _ammoToDetonate pushBack [_mag, _count]; + _x params ["_magazine", "_count"]; + + if (_count > 0 && {!(_magazine call FUNC(isMagazineFlare))}) then { + _ammoToDetonate pushBack [_magazine, _count, false]; _totalAmmo = _totalAmmo + _count; }; -} forEach (magazinesAmmoCargo _vehicle); +} forEach (magazinesAmmoCargo _object); // Get ammo from transportAmmo / ace_rearm -private _vehCfg = configOf _vehicle; +private _configVehicle = configOf _object; +private _configSupply = (getNumber (_configVehicle >> "transportAmmo")) max (getNumber (_configVehicle >> QEGVAR(rearm,defaultSupply))); -private _configSupply = (getNumber (_vehCfg >> "transportAmmo")) max (getNumber (_vehCfg >> QEGVAR(rearm,defaultSupply))); -if (_vehicle getVariable [QEGVAR(rearm,isSupplyVehicle), (_configSupply > 0)]) then { - TRACE_1("transportAmmo vehicle - adding virtual ammo",typeOf _vehicle); +if (_object getVariable [QEGVAR(rearm,isSupplyVehicle), _configSupply > 0]) then { + TRACE_1("transportAmmo vehicle - adding virtual ammo",typeOf _object); - _ammoToDetonate pushBack ["2000Rnd_65x39_belt", 2000]; + _ammoToDetonate pushBack ["2000Rnd_65x39_belt", 2000, false]; _totalAmmo = _totalAmmo + 2000; - _ammoToDetonate pushBack ["20Rnd_105mm_HEAT_MP", 100]; + + _ammoToDetonate pushBack ["20Rnd_105mm_HEAT_MP", 100, true]; _totalAmmo = _totalAmmo + 100; - _ammoToDetonate pushBack ["SatchelCharge_Remote_Mag", 10]; + + _ammoToDetonate pushBack ["SatchelCharge_Remote_Mag", 10, true]; _totalAmmo = _totalAmmo + 10; }; diff --git a/addons/cookoff/functions/fnc_handleDamageBox.sqf b/addons/cookoff/functions/fnc_handleDamageBox.sqf index 9368cd3193..2d55db0fd0 100644 --- a/addons/cookoff/functions/fnc_handleDamageBox.sqf +++ b/addons/cookoff/functions/fnc_handleDamageBox.sqf @@ -1,13 +1,13 @@ #include "..\script_component.hpp" /* - * Author: KoffeinFlummi, commy2 - * Handles all incoming damage for boxi + * Author: KoffeinFlummi, commy2, johnb43 + * Handles all incoming damage for boxes. * * Arguments: * HandleDamage EH * * Return Value: - * Damage to be inflicted. + * Damage to be inflicted (can be nil) * * Example: * _this call ace_cookoff_fnc_handleDamageBox @@ -15,58 +15,48 @@ * Public: No */ -params ["_vehicle", "", "_damage", "_source", "_ammo", "_hitIndex", "_shooter"]; +// If cookoff for boxes is disabled, exit +if (!GVAR(enableAmmobox) || {GVAR(ammoCookoffDuration) == 0}) exitWith {}; -// it's already dead, who cares? -if (damage _vehicle >= 1) exitWith {}; +params ["_box", "", "_damage", "_source", "_ammo", "", "_instigator", "_hitPoint"]; -// If cookoff is disabled exit -if (_vehicle getVariable [QGVAR(enable), GVAR(enable)] in [0, false]) exitWith {}; +if (!local _box) exitWith {}; -// get hitpoint name -private _hitpoint = "#structural"; +// If it's already dead, ignore +if (!alive _box) exitWith {}; -if (_hitIndex != -1) then { - _hitpoint = toLowerANSI ((getAllHitPointsDamage _vehicle param [0, []]) select _hitIndex); -}; +if !(_box getVariable [QGVAR(enableAmmoCookoff), true]) exitWith {}; -// get change in damage -private _oldDamage = 0; +if !(_hitPoint == "" && {_damage > 0.5}) exitWith {}; // "" means structural damage -if (_hitpoint isEqualTo "#structural") then { - _oldDamage = damage _vehicle; +private _ammoConfig = _ammo call CBA_fnc_getObjectConfig; + +// Catch fire when hit by an explosive or incendiary round +if ((getNumber (_ammoConfig >> "explosive") >= 0.5) || {getNumber (_ammoConfig >> QEGVAR(vehicle_damage,incendiary)) > random 1}) then { + [QGVAR(cookOffBoxServer), [_box, _source, _instigator]] call CBA_fnc_serverEvent; } else { - _oldDamage = _vehicle getHitIndex _hitIndex; -}; + // There is a small chance of cooking a box off if it's shot by tracer ammo + if (random 1 >= _damage * 0.05) exitWith {}; -if (_hitpoint == "#structural" && _damage > 0.5) then { - // Almost always catch fire when hit by an explosive - if (IS_EXPLOSIVE_AMMO(_ammo)) then { - _vehicle call FUNC(cookOffBox); + // Need magazine to check for tracers + private _magazine = if (_source == _instigator) then { + currentMagazine _source } else { - // Need magazine to check for tracers - private _mag = ""; - if (_source == _shooter) then { - _mag = currentMagazine _source; - } else { - _mag = _source currentMagazineTurret ([_shooter] call CBA_fnc_turretPath); - }; - private _magCfg = configFile >> "CfgMagazines" >> _mag; - - // Magazine could have changed during flight time (just ignore if so) - if (getText (_magCfg >> "ammo") == _ammo) then { - // If magazine's tracer density is high enough then low chance for cook off - private _tracers = getNumber (_magCfg >> "tracersEvery"); - if (_tracers >= 1 && {_tracers <= 4}) then { - if (random 1 < _oldDamage*0.05) then { - _vehicle call FUNC(cookOffBox); - }; - }; - }; + _source currentMagazineTurret (_source unitTurret _instigator) }; - // prevent destruction, let cook-off handle it if necessary - _damage min 0.89 -} else { - _damage + private _configMagazine = configFile >> "CfgMagazines" >> _magazine; + + // Magazine could have changed during flight time (just ignore if so) + if (getText (_configMagazine >> "ammo") == _ammo) then { + // If magazine's tracer density is high enough then low chance for cook off + private _tracers = getNumber (_configMagazine >> "tracersEvery"); + + if (_tracers >= 1 && {_tracers <= 4}) then { + [QGVAR(cookOffBoxServer), [_box, _source, _instigator]] call CBA_fnc_serverEvent; + }; + }; }; + +// Prevent destruction, let cook-off handle it if necessary +_damage min 0.89 diff --git a/addons/cookoff/functions/fnc_isMagazineFlare.sqf b/addons/cookoff/functions/fnc_isMagazineFlare.sqf index b6c8a604be..f856b21a9a 100644 --- a/addons/cookoff/functions/fnc_isMagazineFlare.sqf +++ b/addons/cookoff/functions/fnc_isMagazineFlare.sqf @@ -1,24 +1,22 @@ #include "..\script_component.hpp" /* * Author: Cyruz - * Checks if the magazine has ammo which is a flare + * Checks if the magazine's ammo are flares. * * Arguments: * 0: Magazine * * Return Value: - * 0: If magazine is type of flare + * If magazine is type of flare * * Example: - * ["3Rnd_UGL_FlareWhite_F"] call ace_cookoff_fnc_isMagazineFlare + * "3Rnd_UGL_FlareWhite_F" call ace_cookoff_fnc_isMagazineFlare * * Public: No */ params ["_magazine"]; -private _ammo = getText (configFile >> "CfgMagazines" >> _magazine >> "ammo"); -private _intensity = getNumber (configFile >> "CfgAmmo" >> _ammo >> "intensity"); -private _flare = getNumber (configFile >> "CfgAmmo" >> _ammo >> QEGVAR(grenades,flare)); +private _configAmmo = configFile >> "CfgAmmo" >> getText (configFile >> "CfgMagazines" >> _magazine >> "ammo"); -_intensity != 0 || _flare == 1 +getNumber (_configAmmo >> "intensity") != 0 || {getNumber (_configAmmo >> QEGVAR(grenades,flare)) == 1} diff --git a/addons/cookoff/functions/fnc_smoke.sqf b/addons/cookoff/functions/fnc_smoke.sqf index ce50043413..94055041de 100644 --- a/addons/cookoff/functions/fnc_smoke.sqf +++ b/addons/cookoff/functions/fnc_smoke.sqf @@ -5,7 +5,7 @@ * * Arguments: * 0: Vehicle - * 1. Selections for smoke to come out of (default: []) + * 1: Selections for smoke to come out of * * Return Value: * None @@ -16,12 +16,11 @@ * Public: No */ -params ["_vehicle", ["_positions", []]]; +params ["_vehicle", "_selections"]; -private _turretConfig = [_vehicle, [0]] call CBA_fnc_getTurret; -private _positionBarrelEnd = getText (_turretConfig >> "gunBeg"); +private _positionBarrelEnd = getText ([_vehicle, [0]] call CBA_fnc_getTurret >> "gunBeg"); -// smoke out of cannon and hatches +// Smoke out of cannon and hatches private _smokeBarrel = "#particlesource" createVehicleLocal [0, 0, 0]; _smokeBarrel setParticleClass "MediumDestructionSmoke"; _smokeBarrel attachTo [_vehicle, [0, 0, 0], _positionBarrelEnd]; @@ -29,10 +28,10 @@ _smokeBarrel attachTo [_vehicle, [0, 0, 0], _positionBarrelEnd]; private _effects = [_smokeBarrel]; { - private _position = [0, -2, 0]; - - if (_x isNotEqualTo "#noselection") then { - _position = _vehicle selectionPosition _x; + private _position = if (_x != "#noselection") then { + _vehicle selectionPosition _x + } else { + [0, -2, 0] }; private _smoke = "#particlesource" createVehicleLocal [0, 0, 0]; @@ -40,6 +39,6 @@ private _effects = [_smokeBarrel]; _smoke attachTo [_vehicle, _position]; _effects pushBack _smoke; -} forEach _positions; +} forEach _selections; _vehicle setVariable [QGVAR(effects), _effects]; diff --git a/addons/cookoff/initSettings.inc.sqf b/addons/cookoff/initSettings.inc.sqf index 47f4681365..c7f1be8ffd 100644 --- a/addons/cookoff/initSettings.inc.sqf +++ b/addons/cookoff/initSettings.inc.sqf @@ -1,63 +1,71 @@ [ - QGVAR(enable), "LIST", - [LSTRING(enable_hd_name), LSTRING(enable_hd_tooltip)], - LSTRING(category_displayName), - [[0, 1, 2], ["STR_A3_OPTIONS_DISABLED", ELSTRING(common,playerOnly), ELSTRING(common,playersAndAI)], 2], - true, // isGlobal - {[QGVAR(enable), _this] call EFUNC(common,cbaSettings_settingChanged)}, - true // Needs mission restart -] call CBA_fnc_addSetting; - -[ - QGVAR(enableFire), "CHECKBOX", + QGVAR(enableFire), + "CHECKBOX", [LSTRING(enableFire_name), LSTRING(enableFire_tooltip)], LSTRING(category_displayName), - true, // default value - true // isGlobal + true, + 1 ] call CBA_fnc_addSetting; [ - QGVAR(destroyVehicleAfterCookoff), "CHECKBOX", - [LSTRING(destroyVehicleAfterCookoff_name), LSTRING(destroyVehicleAfterCookoff_tooltip)], + QGVAR(cookoffDuration), + "SLIDER", + [LSTRING(cookoffDuration_name), LSTRING(cookoffDuration_tooltip)], LSTRING(category_displayName), - false, // default value - true // isGlobal + [0, 10, 1, 2], + 1 ] call CBA_fnc_addSetting; [ - QGVAR(enableAmmoCookoff), "CHECKBOX", - [LSTRING(enableAmmoCookoff_name), LSTRING(enableAmmoCookoff_tooltip)], - LSTRING(category_displayName), - true, // default value - true // isGlobal -] call CBA_fnc_addSetting; - -[ - QGVAR(enableAmmobox), "CHECKBOX", - [LSTRING(enableBoxCookoff_name), LSTRING(enableBoxCookoff_tooltip)], - LSTRING(category_displayName), - true, // default value - true, // isGlobal - {[QGVAR(enableAmmobox), _this] call EFUNC(common,cbaSettings_settingChanged)}, - true // Needs mission restart -] call CBA_fnc_addSetting; - -[ - QGVAR(ammoCookoffDuration), "SLIDER", - [LSTRING(ammoCookoffDuration_name), LSTRING(ammoCookoffDuration_tooltip)], - LSTRING(category_displayName), - [0,5,1,1], // [min, max, default value, trailing decimals (-1 for whole numbers only)] - true, // isGlobal - {[QGVAR(ammoCookoffDuration), _this] call EFUNC(common,cbaSettings_settingChanged)}, - true // Needs mission restart -] call CBA_fnc_addSetting; - -[ - QGVAR(probabilityCoef), "SLIDER", + QGVAR(probabilityCoef), + "SLIDER", [LSTRING(probabilityCoef_name), LSTRING(probabilityCoef_tooltip)], LSTRING(category_displayName), - [0,5,1,1], // [min, max, default value, trailing decimals (-1 for whole numbers only)] - true, // isGlobal - {[QGVAR(probabilityCoef), _this] call EFUNC(common,cbaSettings_settingChanged)}, - true // Needs mission restart + [0, 10, 1, 2], + 1 +] call CBA_fnc_addSetting; + +[ + QGVAR(destroyVehicleAfterCookoff), + "CHECKBOX", + [LSTRING(destroyVehicleAfterCookoff_name), LSTRING(destroyVehicleAfterCookoff_tooltip)], + LSTRING(category_displayName), + false, + 1 +] call CBA_fnc_addSetting; + +[ + QGVAR(enableAmmoCookoff), + "CHECKBOX", + [LSTRING(enableAmmoCookoff_name), LSTRING(enableAmmoCookoff_tooltip)], + LSTRING(category_displayName), + true, + 1 +] call CBA_fnc_addSetting; + +[ + QGVAR(enableAmmobox), + "CHECKBOX", + [LSTRING(enableBoxCookoff_name), LSTRING(enableBoxCookoff_tooltip)], + LSTRING(category_displayName), + true, + 1 +] call CBA_fnc_addSetting; + +[ + QGVAR(ammoCookoffDuration), + "SLIDER", + [LSTRING(ammoCookoffDuration_name), LSTRING(ammoCookoffDuration_tooltip)], + LSTRING(category_displayName), + [0, 10, 1, 2], + 1 +] call CBA_fnc_addSetting; + +[ + QGVAR(removeAmmoDuringCookoff), + "CHECKBOX", + [LSTRING(removeAmmoDuringCookoff_name), LSTRING(removeAmmoDuringCookoff_tooltip)], + LSTRING(category_displayName), + true, + 1 ] call CBA_fnc_addSetting; diff --git a/addons/cookoff/script_component.hpp b/addons/cookoff/script_component.hpp index d41b8f675c..bf8fd62dd5 100644 --- a/addons/cookoff/script_component.hpp +++ b/addons/cookoff/script_component.hpp @@ -16,14 +16,12 @@ #include "\z\ace\addons\main\script_macros.hpp" -#define IS_EXPLOSIVE_AMMO(ammo) (getNumber (ammo call CBA_fnc_getObjectConfig >> "explosive") > 0.5) - // Stages of cookoff in order (in seconds) -// Should be no un-synced randomness in these as the effects must be ran on each client -#define IGNITE_TIME 3 -#define SMOKE_TIME 10.5 +// Should be no un-synced randomness in these as the effects must be run on each client +#define SMOKE_DELAY 10.5 +#define DETONATION_DELAY 3 #define COOKOFF_TIME 14 // Cook off time should be 20s at most due to length of sound files -#define COOKOFF_TIME_BOX 82.5 // Cook off time for boxes should be significant to allow time for ammo to burn +#define ENGINE_FIRE_TIME 240 #define MIN_TIME_BETWEEN_FLAMES 5 #define MAX_TIME_BETWEEN_FLAMES 15 #define MAX_TIME_BETWEEN_AMMO_DET 25 @@ -32,9 +30,6 @@ #define MIN_AMMO_DETONATION_START_DELAY 1 // Min time to wait before a vehicle's ammo starts to cookoff #define MAX_AMMO_DETONATION_START_DELAY 6 // Max time to wait before a vehicle's ammo starts to cookoff -// Delay between flame effect for players in a cooking off vehicle -#define FLAME_EFFECT_DELAY 0.4 - // Common commander hatch defines for default vehicles #define DEFAULT_COMMANDER_HATCHES ["osa_poklop_commander", "hatch_commander_axis"] diff --git a/addons/cookoff/stringtable.xml b/addons/cookoff/stringtable.xml index 49654d8435..c068edb811 100644 --- a/addons/cookoff/stringtable.xml +++ b/addons/cookoff/stringtable.xml @@ -2,7 +2,7 @@ - ACE Cook off + ACE Cook-off ACE Detonación inducida por calor ACE Detonazione Munizioni ACE 殉爆效果 @@ -16,158 +16,26 @@ ACE Cook off ACE Vznícení munice - - Damage handling and turret effects - Daño y efectos de torreta - Schadensberechnung und Geschützturmeffekte - 損傷処理と砲塔の効果 - Обработка урона и эффектов срыва башни - Manipulação de dano e efeitos de torre - Dégâts et effets de tourelle - 傷害控制及炮塔效果 - 损坏处理和炮塔效果 - Gestione danni ed effetti torretta - Poškodit ovládání a efekty věže - Obsługa obrażeń i efekty wieży - 피해량 조절 및 포탑에 효과 부여 + + Enable vehicle cook-off fire - - Changes damage handling for cook off and turret explosion effects - Cambia el daño de la detonación inducida por calor y los efectos de la explosión de la torreta - Ändert die Schadensberechnung für die Durchzündung und die Explosionseffekte des Geschützturmes - 誘爆の損傷処理と砲塔の爆発効果を変更します。 - Изменяет обработку урона для возгорания и эффекта срыва башни - Modifica a manipulação de dano para o cozinhamento de munição e efeitos de explosão da torre - Modifie la gestion des dégâts pour l'auto-inflammation et les effets d'explosion de tourelle. - 更改殉爆以及炮塔爆炸之傷害控制 - 改变殉爆和炮塔爆炸的损坏处理效果 - Modifica la gestione dei danni per l'esplosione di munizioni e gli effetti di esplosione della torretta - Změní poškození ovládání a efekty výbuchu veže - Zmienia obsługę obrażeń podczas samozapłonu i eksplozji wieży - 쿡오프로 인해 피해량의 변화와 포탑 터짐현상을 결정합니다. + + Enables vehicle cook-off fire effects.\nThis doesn't include ammunition detonations. - - Enable ammo box cook off - Habilitar detonación inducida por calor en las cajas de munición - 弾薬箱の誘爆を有効化 - Durchzündung für Munitionskisten ermöglichen - 탄약 상자 쿡오프 현상 활성화 - Aktywuj samozapłon skrzyń z amunicją - Auto-inflammation des caisses de munitions - Abilita esplosione casse munizioni - 開啟彈藥箱殉爆效果 - 开启弹药箱殉爆效果 - Разрешить детонацию ящиков с боеприпасами - Permitir cozinhar caixas de munição - Povolit vynícení munice v krabicích + + Vehicle cook-off fire duration multiplier - - Enables cooking off of ammo boxes. - Habilita la detonación inducida por calor en las cajas de munición - 弾薬箱が誘爆するようになります。 - Ermöglicht Durchzündung von Munitionskisten. - 탄약 상자에 쿡오프 현상을 적용합니다. - Aktywuje samozapłon skrzyń z amunicją - Permet l'auto-inflammation des caisses de munitions. - Abilita l'esplosione di casse di munizioni distrutte. - 開啟彈藥箱殉爆效果 - 开启弹药箱殉爆效果 - Активирует детонацию ящиков с боеприпасами - Permitir que caixas de munição cozinhem. - Zapíná vznícení munice v krabicích. - - - Enable Ammunition cook off - Habilitar la detonación inducida por calor en la munición - 弾薬の誘爆を有効化 - Durchzündung für Munition ermöglichen - 탄약 쿡오프 현상 활성화 - Aktywuj samozapłon amunicji - Auto-inflammation des munitions - Abilita Esplosione Munizioni - 開啟彈藥殉爆效果 - 开启弹药殉爆效果 - Разрешить детонацию боекомплекта - Permitir cozinhar munição - Povolit vznícení munice - - - Enables Ammunition cook off. Fires ammunition projectiles while vehicle is on fire and has ammunition. - Habilita la detonación inducida por calor en la munición. Dispara proyectiles de munición mientras el vehículo está ardiendo y tiene munición - 弾薬が誘爆します。車両が燃えると、搭載している弾薬が激しく燃え上がります。 - Ermöglicht Durchzündung von Munition. Feuert Projektile der Munition ab, solange das Fahrzeug brennt und Munition besitzt. - Aktywuje samozapłon amunicji. Wystrzeliwuje pociski podczas gdy pojazd płonie i posiada amunicję. - Permet l'auto-inflammation des munitions. Tire des projectiles tant que le véhicule est en feu et contient des munitions. - Abilita l'esplosione di munizioni. Spara proiettili di munizioni quando il veicolo va a fuoco e contiene ancora munizioni. - 開啟彈藥殉爆效果。當一台載有彈藥的載具起火時, 將會有殉爆的效果 - 开启弹药殉爆效果。当一台载有弹药的载具起火时,将会有殉爆的效果。 - 쿡오프 현상을 활성화 합니다. 이것은 탄약에 불이 붙어 있는 동안 주변에 발사체를 발사합니다. - Активирует детонацию боекомплекта в горящей технике. - Permite que a munição cozinhe. Dispara projéteis de munição enquanto o veículo está em chamas e tem munição. - Zapíná vznícení munice. Vystřeluje projektily po dobu kdy vozidlo hoří a má munici. - - - Ammunition cook off duration - Duración de la detonación inducida por calor de la munición - Munitionsdurchzündungsdauer - Czas trwania samozapłonu amunicji - 弾薬の誘爆持続時間 - Durée d'auto-inflammation des munitions - Durata Esplosione Munizioni - 彈藥殉爆效果持續時間 - 弹药殉爆效果持续时间 - 쿡오프 지속 시간 - Длительность детонации боеприпасов - Duração do cozinhamento de munição - Doba trvání vznícení munice - - - Multiplier for how long cook off lasts [Setting to 0 will disable ammo cookoff] - Multiplicador de cuanto dura la detonación inducida por calor [Ponerlo a cero la deshabilita] - Faktor für die Munitionsdurchzündungsdauer [0 zum Deaktivieren] - Multiplicateur permettant de régler la durée durant laquelle les munitions continuent d'exploser [Une valeur de 0 désactive l'auto-inflammation]. - Mnożnik decydujący jak długo ma trwać samozapłon amunicji [Ustawienie na 0 spowoduje wyłącznie samozapłonu] - 誘爆の持続時間を乗数で設定します。[0 に設定で誘爆を無効化] - Moltiplicatore della durata delle esplosioni di munizioni [Se impostato su 0 disabiliterà le esplosioni delle munizioni] - 設定彈藥殉爆效果會持續多久時間 [輸入0來關閉殉爆效果] - 设定弹药殉爆效果会持续多久时间 [输入0来关闭殉爆效果] - 쿡오프 지속 시간의 배수 [0 이면 비활성] - Множитель длительности детонации [0 - отключает детонацию боеприпасов] - Multiplicação da duração do cozinhamento [0 faz com que o cozinhamento seja desativado] - Multiplikátor doby trvání vznícení munice [Nastavte 0 pro vypnutí vznícení munice] + + Multiplier for how long vehicle cook-off fire lasts.\nSetting to 0 will disable vehicle cook-off fire. - Cook-off probability coefficient - Coeficiente de probabilidad de detonación inducida por calor - 誘爆の可能性係数 - Coefficiente Probabilità Esplosione - Faktor für Wahrscheinlichkeit der Durchzündung - 殉爆發生機率係數 - 殉爆发生机率系数 - Coefficient de probabilité d'auto-inflammation - Współczynnik prawdopodobieństwa samozapłonu - Коэф. вероятности детонации - Probabilidade de Cozinhar - Koeficient pravděpodobnosti vznícení munice - 쿡오프 발생 확률 계수 + Vehicle cook-off fire probability multiplier - Multiplier for cook-off probability. Higher value results in higher cook-off probability - Multiplicador de probabilidad de detonación inducida por calor. Valores más altos producen mayor probabilidad - 誘爆する可能性の乗数。高い値では誘爆する可能性が高まります。 - Moltiplicatore per la probabilità dell'esplosione di munizioni. Un valore più alto aumenta la probabilità. - Faktor für Wahrscheinlichkeit der Durchzündung. Ein höherer Wert führt zu höherer Durchzündungswahrscheinlichkeit. - 調整殉爆發生機率係數。值越高代表越容易發生殉爆 - 调整殉爆发生机率系数。值越高代表越容易发生殉爆。 - Multiplicateur de probabilité de l'auto-inflammation. Plus la valeur est élevée, plus la probabilité de combustion est grande. - Mnożnik prawdopodobieństwa samozapłonu. Większa wartość oznacza większe prawdopodobieństwo samozapłonu - Множитель коэффициента вероятности детонации. Чем выше значение, тем выше вероятность - Multiplicador para a chance de cozinhamento. Valores mais altos aumentam as chances de ocorrer. - Multiplikátor pro pravděpodobnost vznícení munice. Vyšší hodnota znamená vyšší šanci vznícení munice. - 쿡오프가 일어날 확률에 계수를 곱합니다. 더 큰 숫자는 더 높은 확률의 쿡오프를 일으킵니다. + Multiplier for vehicle cook-off fire probability. Higher value results in higher cook-off probability.\nSetting to 0 will disable vehicle cook-off fire. - Destroy Vehicles After Cook-off + Destroy vehicles after cook-off 쿡오프 후 차량 파괴 殉爆发生后摧毁载具 Уничтожать технику после детонации @@ -191,31 +59,52 @@ Определяет, всегда ли транспортные средства будут уничтожаться после детонации. Controla si los vehículos siempre será destruidos despues de la detonación inducida por calor. - - Enable Cook-Off Vehicle Fire - 誘爆火災を有効化 - Véhicules - Feu durant l'auto-inflammation - Вкл. горение техники от детонации - Aktiviert das in Brand setzen des Fahrzeugs während des Durchzündens der Munition - Abilita incendiamento veicoli - Włącz pożar pojazdu podczas samozapłonu - 启用殉爆载具火灾 - 차량 쿡오프 화재 활성화 - Habilitar incendio a causa de la detonación inducida por calor - Ativar incêndio de veículo durante cozinhamento + + Enable vehicle ammo cook-off - - Whether or not vehicles will catch on fire during cook-off - 誘爆により車両が炎上するかどうかを設定します。 - Définit si les véhicules prennent feu durant l'auto-inflammation de leurs munitions. - Будет ли техника гореть при детонации боеприпасов - Ob Fahrzeuge in Brand gesetzt werden, während deren Munition durchzündet. - Determina se veicoli cominceranno a bruciare se le loro munizioni esplodono. - Określa, czy pojazdy zapalą się podczas samozapłonu ich amunicji. - 车辆在殉爆过程中是否会起火 - 쿡오프가 일어나면 차량에 불이 붙습니다. - Define si los vehículos salen ardiendo despues de una detonación inducida por calor. - Define se os veículos pegarão fogo durante o cozinhamento. + + Enables cooking off of vehicle ammunition. Fires ammunition projectiles while vehicle has ammunition remaining.\nThis doesn't include fire effects. + + + Enable ammo box cook-off + Habilitar detonación inducida por calor en las cajas de munición + 弾薬箱の誘爆を有効化 + Durchzündung für Munitionskisten ermöglichen + 탄약 상자 쿡오프 현상 활성화 + Aktywuj samozapłon skrzyń z amunicją + Auto-inflammation des caisses de munitions + Abilita esplosione casse munizioni + 開啟彈藥箱殉爆效果 + 开启弹药箱殉爆效果 + Разрешить детонацию ящиков с боеприпасами + Permitir cozinhar caixas de munição + Povolit vynícení munice v krabicích + + + Enables cooking off of ammo boxes.\nThis doesn't include fire effects. + + + Ammo cook-off duration multiplier + + + Multiplier for how long ammunition cook-off lasts, for both vehicles and ammo boxes.\nSetting to 0 will disable ammo cook-off for both vehicles and ammo boxes. + + + Enable ammo removal during cook-off + 誘爆中の弾薬除去を有効/無効にする + Retirer les munitions durant l'auto-inflammation + Aktiviert/Deaktiviert Entfernung der Munition beim Durchzünden + Abilita rimozione munizioni dopo l'esplosione + Włącz/Wyłącz usuwanie amunicji podczas samozapłonu + 启用/禁用殉爆过程中的弹药移除功能 + 쿡오프시 탄약 제거 활성화/비활성화 + Удалять боеприпасы из-за детонации + Habilita/Deshabilita ka eliminación de munición durante la detonación inducida por calor + + + Removes all ammo during cook-off. + Retire des munitions des véhicules durant une auto-inflammation. + Entfernt Munition während dem Durchzünden der Munition eines Fahrzeuges. diff --git a/addons/grenades/functions/fnc_incendiary.sqf b/addons/grenades/functions/fnc_incendiary.sqf index 11d89d4ca5..c59d463511 100644 --- a/addons/grenades/functions/fnc_incendiary.sqf +++ b/addons/grenades/functions/fnc_incendiary.sqf @@ -175,10 +175,12 @@ if (isServer) then { }; if (_x isKindOf "ReammoBox_F") then { if ( - "ace_cookoff" call EFUNC(common,isModLoaded) && - {GETVAR(_x,EGVAR(cookoff,enableAmmoCookoff),EGVAR(cookoff,enableAmmobox))} + (["ace_cookoff"] call EFUNC(common,isModLoaded)) && + {EGVAR(cookoff,enableAmmobox)} && + {EGVAR(cookoff,ammoCookoffDuration) != 0} && + {_x getVariable [QEGVAR(cookoff,enableAmmoCookoff), true]} ) then { - _x call EFUNC(cookoff,cookOffBox); + [QEGVAR(cookOff,cookOffBoxServer), _box] call CBA_fnc_serverEvent; } else { _x setDamage 1; }; @@ -232,10 +234,7 @@ private _enginePosition = _vehicle modelToWorld (_vehicle selectionPosition _eng if (_position distance _enginePosition < EFFECT_SIZE * 2) then { _vehicle setHit [_engineSelection, 1]; - if ("ace_cookoff" call EFUNC(common,isModLoaded)) then { - private _enabled = _vehicle getVariable [QEGVAR(cookoff,enable), EGVAR(cookoff,enable)]; - if (_enabled in [2, true] || {_enabled isEqualTo 1 && {fullCrew [_vehicle, "", false] findIf {isPlayer (_x select 0)} != -1}}) then { - _vehicle call EFUNC(cookoff,engineFire); - }; + if (["ace_cookoff"] call EFUNC(common,isModLoaded)) then { + [QEGVAR(cookoff,engineFireServer), _vehicle] call CBA_fnc_serverEvent; }; }; diff --git a/addons/vehicle_damage/functions/fnc_addDamage.sqf b/addons/vehicle_damage/functions/fnc_addDamage.sqf index 75d72da340..35475bd36c 100644 --- a/addons/vehicle_damage/functions/fnc_addDamage.sqf +++ b/addons/vehicle_damage/functions/fnc_addDamage.sqf @@ -37,6 +37,6 @@ if (_hitIndex >= 0) then { _vehicle setHitPointDamage [_hitPoint, _damage, true]; }; -if (_hitPoint isEqualTo "hitengine" && { _damage > 0.9 }) then { - _vehicle call EFUNC(cookoff,engineFire); +if (_hitPoint == "hitengine" && {_damage > 0.9}) then { + [QEGVAR(cookoff,engineFireServer), _vehicle] call CBA_fnc_serverEvent; }; diff --git a/addons/vehicle_damage/functions/fnc_detonate.sqf b/addons/vehicle_damage/functions/fnc_detonate.sqf index feca2dd792..7f0dce28c9 100644 --- a/addons/vehicle_damage/functions/fnc_detonate.sqf +++ b/addons/vehicle_damage/functions/fnc_detonate.sqf @@ -6,7 +6,6 @@ * Arguments: * 0: The vehicle * 1: Person who caused detonation (default: objNull) - * 2: An array of vehicle ammo in vehicle (default: []) * * Return Value: * None @@ -17,16 +16,12 @@ * Public: No */ -params ["_vehicle", ["_injurer", objNull], ["_vehicleAmmo", []]]; +params ["_vehicle", ["_injurer", objNull]]; -if (_vehicleAmmo isEqualTo []) then { - _vehicleAmmo = [_vehicle] call EFUNC(cookoff,getVehicleAmmo); -}; - -([_vehicle] + _vehicleAmmo) call EFUNC(cookoff,detonateAmmunition); - -if ((_vehicleAmmo select 1) > 0) then { +if (((_vehicle call EFUNC(cookoff,getVehicleAmmo)) select 1) > 0) then { { [QGVAR(medicalDamage), [_x, _injurer, _injurer], _x] call CBA_fnc_targetEvent; } forEach (crew _vehicle); }; + +[QEGVAR(cookoff,detonateAmmunitionServer), [_vehicle, false, _injurer, _injurer]] call CBA_fnc_serverEvent; diff --git a/addons/vehicle_damage/functions/fnc_handleCookoff.sqf b/addons/vehicle_damage/functions/fnc_handleCookoff.sqf index 7cf6337796..3e7b83ebb6 100644 --- a/addons/vehicle_damage/functions/fnc_handleCookoff.sqf +++ b/addons/vehicle_damage/functions/fnc_handleCookoff.sqf @@ -23,9 +23,12 @@ params ["_vehicle", "_chanceOfFire", "_intensity", ["_injurer", objNull], ["_hitPart", ""], ["_canRing", false], ["_canJet", true]]; -private _alreadyCookingOff = _vehicle getVariable [QGVAR(cookingOff), false]; +// Ignore if the vehicle is already cooking off +if (_vehicle getVariable [QEGVAR(cookoff,isCookingOff), false]) exitWith {true}; -if (!_alreadyCookingOff && { _chanceOfFire >= random 1 }) exitWith { +_chanceOfFire = _chanceOfFire * EGVAR(cookoff,probabilityCoef); + +if (_chanceOfFire >= random 1) exitWith { private _configOf = configOf _vehicle; private _fireDetonateChance = [_configOf >> QGVAR(detonationDuringFireProb), "number", 0] call CBA_fnc_getConfigEntry; if (_canRing) then { @@ -44,28 +47,13 @@ if (!_alreadyCookingOff && { _chanceOfFire >= random 1 }) exitWith { _source = ["hit_engine_point", "HitPoints"]; }; - // sending nil for _maxIntensity (9th param) to use default value in ace_cookoff_fnc_cookOff - [QEGVAR(cookOff,cookOff), [_vehicle, _intensity, _injurer, _delayWithSmoke, _fireDetonateChance, _detonateAfterCookoff, _source, _canRing, nil, _canJet]] call CBA_fnc_localEvent; - _vehicle setVariable [QGVAR(cookingOff), true]; + [QEGVAR(cookOff,cookOffServer), [_vehicle, _intensity, _injurer, _injurer, _delayWithSmoke, _fireDetonateChance, _detonateAfterCookoff, _source, _canRing, _canJet]] call CBA_fnc_serverEvent; LOG_4("Cooking-off [%1] with a chance-of-fire [%2] - Delayed Smoke | Detonate after cookoff [%3 | %4]",_vehicle,_chanceOfFire,_delayWithSmoke,_detonateAfterCookoff); [_vehicle] spawn FUNC(abandon); LOG_1("[%1] is on fire is bailing",_vehicle); - // cant setVehicleAmmo 0 here because it removes FFV unit's ammo - if (GVAR(removeAmmoDuringCookoff)) then { - private _ammo = [_vehicle] call EFUNC(cookoff,getVehicleAmmo); - _ammo params ["_magazines"]; - TRACE_1("removing magazines",_magazines); - { - _x params ["_magazine"]; - _vehicle removeMagazines _magazine; - } forEach _magazines; - }; true }; -// Avoid RPT spam -if (_alreadyCookingOff) exitWith { true }; - LOG_2("[%1] No Cook-off - Chance of fire [%2]",_vehicle,_chanceOfFire); false diff --git a/addons/vehicle_damage/functions/fnc_handleDetonation.sqf b/addons/vehicle_damage/functions/fnc_handleDetonation.sqf index 9556cea424..8f317323fa 100644 --- a/addons/vehicle_damage/functions/fnc_handleDetonation.sqf +++ b/addons/vehicle_damage/functions/fnc_handleDetonation.sqf @@ -21,18 +21,17 @@ */ params ["_vehicle", "_chanceOfDetonate", "_vehicleAmmo", "_explosiveAmmoCount", "_nonExplosiveAmmoCount", ["_injurer", objNull]]; -private _alreadyDetonating = _vehicle getVariable [QGVAR(detonating), false]; + private _isKnockedOut = _explosiveAmmoCount > 0; -if (!_alreadyDetonating && { _chanceOfDetonate >= random 1 }) exitWith { +// Ignore if the vehicle is already detonating ammo +if (_vehicle getVariable [QEGVAR(cookoff,isAmmoDetonating), false]) exitWith {_isKnockedOut}; + +if (_chanceOfDetonate >= random 1) exitWith { [_vehicle, _injurer, _vehicleAmmo] call FUNC(detonate); LOG_2("Detonating [%1] with a chance-to-detonate [%2]",_vehicle,_chanceOfDetonate); - _vehicle setVariable [QGVAR(detonating), true]; _isKnockedOut }; -// Avoid RPT spam -if (_alreadyDetonating) exitWith { _isKnockedOut }; - LOG_2("[%1] No Detonation - Chance of detonation [%2]",_vehicle,_chanceOfDetonate); false diff --git a/addons/vehicle_damage/functions/fnc_processHit.sqf b/addons/vehicle_damage/functions/fnc_processHit.sqf index 1eb7328466..2402df7fc2 100644 --- a/addons/vehicle_damage/functions/fnc_processHit.sqf +++ b/addons/vehicle_damage/functions/fnc_processHit.sqf @@ -117,7 +117,7 @@ if (_isCar) then { _ammoEffectiveness = (_ammoEffectiveness + (_ammoEffectiveness * 0.5)) min 1; }; -private _currentVehicleAmmo = [_vehicle] call EFUNC(cookoff,getVehicleAmmo); +private _currentVehicleAmmo = _vehicle call EFUNC(cookoff,getVehicleAmmo); private _chanceOfDetonation = 0; private _explosiveAmmoCount = 0; private _nonExplosiveAmmoCount = 0; @@ -161,7 +161,7 @@ switch (_hitArea) do { _chanceOfFire = 0; // no cookoff for cars }; - if ([_vehicle, _chanceToDetonate, _currentVehicleAmmo, _explosiveAmmoCount, _nonExplosiveAmmoCount, _injurer] call FUNC(handleDetonation)) exitWith { + if ([_vehicle, _chanceToDetonate, _explosiveAmmoCount, _nonExplosiveAmmoCount, _injurer] call FUNC(handleDetonation)) exitWith { [_vehicle] call FUNC(knockOut); }; @@ -189,7 +189,7 @@ switch (_hitArea) do { _chanceOfFire = 0; // no cookoff for cars }; - if ([_vehicle, _chanceToDetonate, _currentVehicleAmmo, _explosiveAmmoCount, _nonExplosiveAmmoCount, _injurer] call FUNC(handleDetonation)) exitWith { + if ([_vehicle, _chanceToDetonate, _explosiveAmmoCount, _nonExplosiveAmmoCount, _injurer] call FUNC(handleDetonation)) exitWith { [_vehicle, _hitIndex, _hitpointName, 0.89 * _penChance] call FUNC(addDamage); [_vehicle] call FUNC(knockOut); }; @@ -263,7 +263,7 @@ switch (_hitArea) do { _chanceOfFire = 0; // no cookoff for cars }; - if ([_vehicle, _chanceToDetonate, _currentVehicleAmmo, _explosiveAmmoCount, _nonExplosiveAmmoCount, _injurer] call FUNC(handleDetonation)) exitWith { + if ([_vehicle, _chanceToDetonate, _explosiveAmmoCount, _nonExplosiveAmmoCount, _injurer] call FUNC(handleDetonation)) exitWith { [_vehicle] call FUNC(knockOut); }; diff --git a/addons/vehicle_damage/initSettings.inc.sqf b/addons/vehicle_damage/initSettings.inc.sqf index 5841145cf9..0d3f324af2 100644 --- a/addons/vehicle_damage/initSettings.inc.sqf +++ b/addons/vehicle_damage/initSettings.inc.sqf @@ -8,14 +8,6 @@ true // Needs mission restart ] call CBA_settings_fnc_init; -[ - QGVAR(removeAmmoDuringCookoff), "CHECKBOX", - [LSTRING(removeAmmoAfterCookoff_setting_enable), LSTRING(removeAmmoAfterCookoff_setting_description)], - LSTRING(category_displayName), - true, // default value - true // isGlobal -] call CBA_settings_fnc_init; - [ QGVAR(enableCarDamage), "CHECKBOX", [LSTRING(carDamage_setting_enable), LSTRING(carDamage_setting_description)], diff --git a/addons/vehicle_damage/stringtable.xml b/addons/vehicle_damage/stringtable.xml index 5581408f74..4a8fdb4264 100644 --- a/addons/vehicle_damage/stringtable.xml +++ b/addons/vehicle_damage/stringtable.xml @@ -49,30 +49,6 @@ Продвинутое повреждение машин Habilitar/Deshabilitar daño avanzado de coche (Experimental) - - Removes all vehicle ammo after cook-off - 誘爆後に車両から全ての弾薬を削除 - Retire toutes les munitions des véhicules après une auto-inflammation. - Entfernt die gesamte Munition nach dem Durchzünden der Munition eines Fahrzeuges. - Rimuove tutte le munizioni dal veicolo dopo l'esplosione delle stesse - Usuwa całą amunicję z pojazdu po samozapłonie - 殉爆后移除所有车辆弹药 - 쿡오프 현상 후 차량에서 모든 탄약을 제거합니다. - Удалять все боеприпасы из техники после их детонации - Elimina toda la munición del vehículo despues ser inducida a detonar por calor - - - Enable/Disable Ammo Removal During Cook-Off - 誘爆中の弾薬除去を有効/無効にする - Retirer les munitions durant l'auto-inflammation - Aktiviert/Deaktiviert Entfernung der Munition beim Durchzünden - Abilita rimozione munizioni dopo l'esplosione - Włącz/Wyłącz usuwanie amunicji podczas samozapłonu - 启用/禁用殉爆过程中的弹药移除功能 - 쿡오프시 탄약 제거 활성화/비활성화 - Удалять боеприпасы из-за детонации - Habilita/Deshabilita ka eliminación de munición durante la detonación inducida por calor - Wreck (Turret) Épave (tourelle) diff --git a/docs/wiki/framework/cookoff-framework.md b/docs/wiki/framework/cookoff-framework.md index b53fea2049..8129699154 100644 --- a/docs/wiki/framework/cookoff-framework.md +++ b/docs/wiki/framework/cookoff-framework.md @@ -12,43 +12,22 @@ version: patch: 0 --- -## 1. Disabling / Enabling Cook off for individual vehicles +## 1. Disabling cook-off fire for individual vehicles -You can dynamically enable and/or disable vehicle cook off for individual vehicles by using `setVariable`: +Cook-off fire can be disabled for a specific vehicle (does not affect ammo cook-off): ``` -VEHICLE setVariable ["ace_cookoff_enable", true, true]; +_vehicle setVariable ["ace_cookoff_enable", false, true]; ``` -The above will enable cook off for that specific vehicle, no matter the mission settings. +Mission settings will always apply however, so you can't enable cook-off on a vehicle if the mission settings have cook-off for vehicles disabled. -Likewise, cook off can also be disabled for a specific vehicle: +## 2. Disabling ammunition cook-off for individual vehicles and boxes + +Ammunition cook-off can be disabled for a specific vehicle or box (does not affect cook-off fire): ``` -VEHICLE setVariable ["ace_cookoff_enable", false, true]; +_vehicleOrBox setVariable ["ace_cookoff_enableAmmoCookoff", false, true]; ``` -## 2. Cook off probability - -You can set the probability of cook off for individual vehicle types by changing the `ace_cookoff_probability` value in the vehicle's config: - -``` -class MyVehicle { - ace_cookoff_probability = 0.6; -}; -``` - -Global cook off probability can also be adjusted with the `ace_cookoff_probabilityCoef` mission setting. - -Higher values will make cook-off more probable, whilst lower values will make cook-off less probable. - -## 3. Ignore damage to turret - -For use on vehicles when damage to the main turret would not cause a vehicle cookoff. -e.g. RCWS turrets - -``` -class MyVehicle { - ace_vehicle_damage_turretFireProb = 0; -}; -``` +Mission settings will always apply however, so you can't enable ammunition cook-off on a vehicle or box if the mission settings have ammunition cook-off disabled. diff --git a/docs/wiki/framework/events-framework.md b/docs/wiki/framework/events-framework.md index 5712acb0a0..860cd90068 100644 --- a/docs/wiki/framework/events-framework.md +++ b/docs/wiki/framework/events-framework.md @@ -103,18 +103,17 @@ MenuType: 0 = Interaction, 1 = Self Interaction | Event Key | Parameters | Locality | Type | Description | |----------|---------|---------|---------|---------| -|`ace_refuel_started` | [_source, _target] | Local | Listen | Refueling has started | +|`ace_refuel_started` | [_source, _target] | Local | Listen | Refuelling has started | |`ace_refuel_tick` | [_source, _target, _amount] | Local | Listen | Amount of fuel transferred in a tick | -|`ace_refuel_stopped` | [_source, _target] | Local | Listen | Refueling has stopped | +|`ace_refuel_stopped` | [_source, _target] | Local | Listen | Refuelling has stopped | ### 2.10 Cook Off (`ace_cookoff`) | Event Key | Parameters | Locality | Type | Description | -|----------|---------|---------|---------|---------| -|`ace_cookoff_cookOff` | _vehicle | Global | Listen | Vehicle cook off has started -|`ace_cookoff_cookOffBox` | _box | Global | Listen | Ammo box cook off has started | -|`ace_cookoff_engineFire` | _vehicle | Global | Listen | Engine fire has started | - +|----------|---------|---------|---------|---------|---------| +|`ace_cookoff_cookOff` | [_vehicle, _intensity, _instigator, _smokeDelayEnabled, _ammoDetonationChance, _detonateAfterCookoff, _fireSource, _canRing, _maxIntensity, _canJet] | Global | Listen | Vehicle cook-off has started | +|`ace_cookoff_cookOffBox` | [_box, _source, _instigator, _delay] | Global | Listen | Ammo box cook-off has started | +|`ace_cookoff_engineFire` | [_vehicle] | Global | Listen | Engine fire has started | ### 2.11 Attach (`ace_attach`) diff --git a/docs/wiki/framework/vehicledamage-framework.md b/docs/wiki/framework/vehicledamage-framework.md index ac94bd30fb..0d4268bf5e 100644 --- a/docs/wiki/framework/vehicledamage-framework.md +++ b/docs/wiki/framework/vehicledamage-framework.md @@ -47,7 +47,7 @@ Default: 0.5 #### 1.1.5 `ace_vehicle_damage_turretFireProb` -The probabilitiy for the vehicle to catch on fire upon its turret being penetrated +The probability for the vehicle to catch on fire upon its turret being penetrated Default: 0.2 From 33dc7e3dbd27f7c408f54a453749b193c05ebba1 Mon Sep 17 00:00:00 2001 From: Will/KJW <100206101+SpicyBagpipes@users.noreply.github.com> Date: Thu, 6 Jun 2024 12:49:15 +0100 Subject: [PATCH 077/290] Hit Reactions - Add weapon dropping on arm hit (#9539) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Create fnc_checkWeaponDrop.sqf * Update fnc_checkWeaponDrop.sqf * Create XEH_postInit.sqf * Update XEH_postInit.sqf * Update XEH_postInit.sqf * Update fnc_checkWeaponDrop.sqf * fix spelling issue * Update initSettings.sqf Add weaponDropEnabled setting * Update stringtable.xml * Update fnc_checkWeaponDrop.sqf * Update initSettings.sqf Forgot a bracket * Add weapon drop chance setting * Update XEH_postInit.sqf * Update CfgEventHandlers.hpp actually make it run postinit * Update XEH_PREP.hpp * Update stringtable.xml * Update initSettings.sqf No need, set chance to 0 * Update XEH_postInit.sqf already comparing against chance, can just set to 0 * Update initSettings.sqf * Update stringtable.xml * Update XEH_postInit.sqf * add arm hit chance fix weapon thing too * Update stringtable.xml * Update addons/hitreactions/functions/fnc_checkWeaponDrop.sqf Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> * Update addons/hitreactions/functions/fnc_checkWeaponDrop.sqf Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> * appearance stuff * Update addons/hitreactions/initSettings.sqf Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> * Update addons/hitreactions/functions/fnc_checkWeaponDrop.sqf Co-authored-by: Jouni Järvinen * kjw's poor arithmetic * Update fnc_checkWeaponDrop.sqf wrong check * remove systemchat debug whoops * Update fnc_checkWeaponDrop.sqf * Update XEH_postInit.sqf * Update fnc_checkWeaponDrop.sqf * Early exit, wait for clear * Make default setting 0 * Update script_component.hpp * Update XEH_postInit.sqf * Update script_component.hpp * Update XEH_postInit.sqf * Update XEH_postInit.sqf * Update addons/hitreactions/functions/fnc_checkWeaponDrop.sqf * Update XEH_postInit.sqf Unsure if exitWith in postInit is proper? Seems better than nesting all of that in another scope imo * Update XEH_preInit.sqf * Update fnc_checkWeaponDrop.sqf * Update addons/hitreactions/XEH_preInit.sqf Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> * Update hitreactions.md * Update hitreactions.md * Update addons/hitreactions/functions/fnc_checkWeaponDrop.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * Update addons/hitreactions/functions/fnc_checkWeaponDrop.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * Update addons/hitreactions/initSettings.sqf * Update XEH_postInit.sqf * Update addons/hitreactions/XEH_postInit.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * Update addons/hitreactions/XEH_postInit.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * Update addons/hitreactions/functions/fnc_checkWeaponDrop.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * Update addons/hitreactions/functions/fnc_checkWeaponDrop.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * Update XEH_postInit.sqf * Update XEH_postInit.sqf * Update fnc_checkWeaponDrop.sqf * Spacing fixes * Update addons/hitreactions/XEH_postInit.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * Take _hitEntity into account if exists * Update fnc_checkWeaponDrop.sqf _didHitGun will no longer ever be true * Minor component cleanup * Removed gun hits, added double hit detection * Decouple AI and player probabilities * Tweaks and fixes * Update XEH_PREP.hpp * Add missing param * Fixed bugged state AI are in after using TakeWeapon * Fixes and cleanup * Made API clear, moved undroppable to config entry * Update fnc_checkWeaponDrop.sqf * Check for Zeus RC and avoid `setUnitLoadout` * Expand `addWeapon`'s capabilities * Cleaned up `addWeapon` * Removed weapon replacement as it's apparently not necessary * Defined undefined variable --------- Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> Co-authored-by: Jouni Järvinen Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- addons/hitreactions/ACE_Settings.hpp | 1 - addons/hitreactions/CfgEventHandlers.hpp | 7 +- addons/hitreactions/XEH_PREP.hpp | 2 +- addons/hitreactions/XEH_postInit.sqf | 86 +++++++++++++++++++ addons/hitreactions/XEH_preInit.sqf | 12 +++ .../functions/fnc_checkWeaponDrop.sqf | 33 +++++++ addons/hitreactions/initSettings.inc.sqf | 21 ++++- addons/hitreactions/script_component.hpp | 2 + addons/hitreactions/stringtable.xml | 6 ++ docs/wiki/feature/hitreactions.md | 3 + docs/wiki/framework/hitreactions-framework.md | 32 +++++++ 11 files changed, 201 insertions(+), 4 deletions(-) create mode 100644 addons/hitreactions/XEH_postInit.sqf create mode 100644 addons/hitreactions/functions/fnc_checkWeaponDrop.sqf create mode 100644 docs/wiki/framework/hitreactions-framework.md diff --git a/addons/hitreactions/ACE_Settings.hpp b/addons/hitreactions/ACE_Settings.hpp index 90c1445eba..78a510a141 100644 --- a/addons/hitreactions/ACE_Settings.hpp +++ b/addons/hitreactions/ACE_Settings.hpp @@ -1,4 +1,3 @@ - class ACE_Settings { class GVAR(minDamageToTrigger) { movedToSQF = 1; diff --git a/addons/hitreactions/CfgEventHandlers.hpp b/addons/hitreactions/CfgEventHandlers.hpp index eecf08c69d..b737b7bcbf 100644 --- a/addons/hitreactions/CfgEventHandlers.hpp +++ b/addons/hitreactions/CfgEventHandlers.hpp @@ -1,4 +1,3 @@ - class Extended_PreStart_EventHandlers { class ADDON { init = QUOTE(call COMPILE_SCRIPT(XEH_preStart)); @@ -11,6 +10,12 @@ class Extended_PreInit_EventHandlers { }; }; +class Extended_PostInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_SCRIPT(XEH_postInit)); + }; +}; + class Extended_Hit_EventHandlers { class CAManBase { class ADDON { diff --git a/addons/hitreactions/XEH_PREP.hpp b/addons/hitreactions/XEH_PREP.hpp index 7701b8ef19..eea48dcaa8 100644 --- a/addons/hitreactions/XEH_PREP.hpp +++ b/addons/hitreactions/XEH_PREP.hpp @@ -1,3 +1,3 @@ - +PREP(checkWeaponDrop); PREP(fallDown); PREP(getRandomAnimation); diff --git a/addons/hitreactions/XEH_postInit.sqf b/addons/hitreactions/XEH_postInit.sqf new file mode 100644 index 0000000000..d45d4f3df2 --- /dev/null +++ b/addons/hitreactions/XEH_postInit.sqf @@ -0,0 +1,86 @@ +#include "script_component.hpp" + +["ace_firedNonPlayer", { + if (GVAR(weaponDropChanceArmHitPlayer) + GVAR(weaponDropChanceArmHitAI) == 0) exitWith {}; + + (_this select 6) addEventHandler ["HitPart", { + params ["", "_entity", "", "", "", "", "_selections"]; + + [_entity, _selections] call FUNC(checkWeaponDrop); + }]; +}] call CBA_fnc_addEventHandler; + +["ace_firedPlayer", { + if (GVAR(weaponDropChanceArmHitPlayer) + GVAR(weaponDropChanceArmHitAI) == 0) exitWith {}; + + (_this select 6) addEventHandler ["HitPart", { + params ["", "_entity", "", "", "", "", "_selections"]; + + [_entity, _selections] call FUNC(checkWeaponDrop); + }]; +}] call CBA_fnc_addEventHandler; + +[QGVAR(dropWeapon), { + params ["_unit"]; + + if !(_unit getVariable [QGVAR(canDropWeapon), true]) exitWith {}; + + // Prevents AI from losing both primary and pistol when being shot with their pistol out + _unit setVariable [QGVAR(canDropWeapon), false]; + + private _weapon = currentWeapon _unit; + private _thrownWeapon = _unit call EFUNC(common,throwWeapon); + + [{ + params ["_unit"]; + + _unit setVariable [QGVAR(canDropWeapon), nil]; + }, _unit, 0.5] call CBA_fnc_waitAndExecute; + + if (_unit call EFUNC(common,isPlayer)) exitWith {}; // Don't make players pick their own weapons up + + // Wait before executing, as otherwise the unit would pick up the weapon immediately + [{ + [{ + (_this select 0) params ["_unit", "_weapon", "_thrownWeapon", "_timeout"]; + + // If the unit has been deleted or dead, if the weapon doesn't exist anymore or if it's been too long, stop + if (!alive _unit || {!local _unit} || {isNull _thrownWeapon} || {CBA_missionTime >= _timeout}) exitWith { + (_this select 1) call CBA_fnc_removePerFrameHandler; + }; + + // Don't pick up weapon when unit is unconscious + if (lifeState _unit == "INCAPACITATED") exitWith {}; + + // If the unit has no essential weapons, force them to get their weapon, otherwise wait until no enemies are present + if !( + (primaryWeapon _unit == "" && {handgunWeapon _unit == ""}) || + {(_unit distance (_unit findNearestEnemy _unit)) > missionNamespace getVariable [QGVAR(safePickupDistance), DEFAULT_PICKUP_DISTANCE]} + ) exitWith {}; + + // If the unit is too far away, make them move closer + if (_unit distance _thrownWeapon >= 4) exitWith { + private _pos = getPosATL _thrownWeapon; + + _unit setDestination [_pos, "LEADER PLANNED", true]; + _unit doMove _pos; + }; + + (_this select 1) call CBA_fnc_removePerFrameHandler; + + _unit action ["TakeWeapon", _thrownWeapon, _weapon]; + + // Make the unit switch weapons + [{ + (_this select 0) hasWeapon (_this select 1) + }, { + params ["_unit", "_weapon"]; + + if (!alive _unit || {!local _unit} || {primaryWeapon _unit != _weapon}) exitWith {}; + + // Switch to the primary weapon, if it was picked up + _unit selectWeapon _weapon; + }, [_unit, _weapon], 5] call CBA_fnc_waitUntilAndExecute; + }, 5, _this] call CBA_fnc_addPerFrameHandler; + }, [_unit, _weapon, _thrownWeapon, CBA_missionTime + 300], random [2, 3, 4]] call CBA_fnc_waitAndExecute; +}] call CBA_fnc_addEventHandler; diff --git a/addons/hitreactions/XEH_preInit.sqf b/addons/hitreactions/XEH_preInit.sqf index 894773534a..9aa0acea0e 100644 --- a/addons/hitreactions/XEH_preInit.sqf +++ b/addons/hitreactions/XEH_preInit.sqf @@ -9,3 +9,15 @@ PREP_RECOMPILE_END; #include "initSettings.inc.sqf" ADDON = true; + +GVAR(armSelections) = [ + "leftshoulder", + "rightshoulder", + "lefthand", + "leftforearm", + "leftarmroll", + "rightforearm", + "rightarmroll", + "righthand", + "rightarm" +]; diff --git a/addons/hitreactions/functions/fnc_checkWeaponDrop.sqf b/addons/hitreactions/functions/fnc_checkWeaponDrop.sqf new file mode 100644 index 0000000000..ad4e7c4a41 --- /dev/null +++ b/addons/hitreactions/functions/fnc_checkWeaponDrop.sqf @@ -0,0 +1,33 @@ +#include "..\script_component.hpp" +/* + * Author: KJW + * Checks if an entity should drop their weapon based on projectile hit info. + * + * Arguments: + * 0: Entity that was hit + * 1: Selection names that were hit + * + * Return Value: + * None + * + * Example: + * [player, []] call ace_hitreactions_fnc_checkWeaponDrop + * + * Public: No + */ + +params ["_entity", "_selections"]; + +// Make sure entity is a unit +if !(_entity isKindOf "CAManBase") exitWith {}; + +// Don't throw weapon if unit is unconscious or dead +if !(lifeState _entity in ["HEALTHY", "INJURED"]) exitWith {}; + +if (random 1 >= ([GVAR(weaponDropChanceArmHitAI), GVAR(weaponDropChanceArmHitPlayer)] select (_entity call EFUNC(common,isPlayer)))) exitWith {}; + +if (_selections findAny GVAR(armSelections) == -1) exitWith {}; + +if (getNumber ((currentWeapon _entity) call CBA_fnc_getItemConfig >> QGVAR(undroppable)) == 1) exitWith {}; + +[QGVAR(dropWeapon), _entity, _entity] call CBA_fnc_targetEvent; diff --git a/addons/hitreactions/initSettings.inc.sqf b/addons/hitreactions/initSettings.inc.sqf index 2ca4ceaeac..2f51a25647 100644 --- a/addons/hitreactions/initSettings.inc.sqf +++ b/addons/hitreactions/initSettings.inc.sqf @@ -1,9 +1,28 @@ private _category = [LELSTRING(common,categoryUncategorized), QUOTE(COMPONENT_BEAUTIFIED)]; [ - QGVAR(minDamageToTrigger), "SLIDER", + QGVAR(minDamageToTrigger), + "SLIDER", LSTRING(minDamageToTrigger_displayName), _category, [-1, 1, 0.1, 1], 1 ] call CBA_fnc_addSetting; + +[ + QGVAR(weaponDropChanceArmHitPlayer), + "SLIDER", + LSTRING(weaponDropChanceArmHitPlayer_displayName), + _category, + [0, 1, 0, 2, true], + 1 +] call CBA_fnc_addSetting; + +[ + QGVAR(weaponDropChanceArmHitAI), + "SLIDER", + LSTRING(weaponDropChanceArmHitAI_displayName), + _category, + [0, 1, 0, 2, true], + 1 +] call CBA_fnc_addSetting; diff --git a/addons/hitreactions/script_component.hpp b/addons/hitreactions/script_component.hpp index dccbef24f7..dd407a914b 100644 --- a/addons/hitreactions/script_component.hpp +++ b/addons/hitreactions/script_component.hpp @@ -15,3 +15,5 @@ #endif #include "\z\ace\addons\main\script_macros.hpp" + +#define DEFAULT_PICKUP_DISTANCE 8 diff --git a/addons/hitreactions/stringtable.xml b/addons/hitreactions/stringtable.xml index b07e9be9a0..8ff2316dec 100644 --- a/addons/hitreactions/stringtable.xml +++ b/addons/hitreactions/stringtable.xml @@ -17,5 +17,11 @@ Düşmeyi tetikleyen min hasar Daño mínimo para provocar la caída + + Player Weapon Drop Chance (Arm Hit) + + + AI Weapon Drop Chance (Arm Hit) + diff --git a/docs/wiki/feature/hitreactions.md b/docs/wiki/feature/hitreactions.md index 7d12c1cb12..a84d1c0b78 100644 --- a/docs/wiki/feature/hitreactions.md +++ b/docs/wiki/feature/hitreactions.md @@ -18,3 +18,6 @@ version: ### 1.1 Falling under fire If a unit is shot while running it falls to the ground in a prone position, the area where the shot lands does not matters. Note that the shot needs to inflict a certain amount of damage to make the unit fall, a small cut won't make the unit stumble. + +### 1.2 Weapon dropping +If a unit's arm is shot it will cause the gun to be dropped based on the chance set. The default is 0. diff --git a/docs/wiki/framework/hitreactions-framework.md b/docs/wiki/framework/hitreactions-framework.md new file mode 100644 index 0000000000..ca3ff93f5b --- /dev/null +++ b/docs/wiki/framework/hitreactions-framework.md @@ -0,0 +1,32 @@ +--- +layout: wiki +title: Hit Reactions Framework +description: Explains how to set-up weapons with ACE3 hit reactions system. +group: framework +order: 5 +parent: wiki +mod: ace +version: + major: 3 + minor: 18 + patch: 0 +--- + +## 1. Config Values + +```cpp +class CfgWeapons { + class MyWeapon { + ace_hitreactions_undroppable = 1; // Prevents weapon from being dropped + }; +}; +``` + +## 2. Mission Variables + +### 2.1 Safe pickup distance for AI + +Allows 3rd party mods to set the distance between AI and the nearest hostile that is considered safe to go pickup a dropped weapon. +```sqf +ace_hitreactions_safePickupDistance = 10; // default is 8 +``` From 565d64d50ed775dafbbefafe05457577e955712b Mon Sep 17 00:00:00 2001 From: Mike-MF Date: Thu, 6 Jun 2024 22:12:49 +0100 Subject: [PATCH 078/290] Reaction Forces Compatibility (#10016) * Reaction Forces Compatibility * Fix Desert Eagle Name, add RAM 1500 variants * Mortars, Drone and lower cased Ram because thats how baer likes it --- addons/compat_rf/$PBOPREFIX$ | 1 + addons/compat_rf/CfgWeapons.hpp | 42 ++++ .../CfgVehicles.hpp | 12 + .../config.cpp | 21 ++ .../script_component.hpp | 3 + .../compat_rf_realisticnames/Attachments.hpp | 41 ++++ .../compat_rf_realisticnames/CfgMagazines.hpp | 24 ++ .../compat_rf_realisticnames/CfgVehicles.hpp | 134 +++++++++++ .../compat_rf_realisticnames/CfgWeapons.hpp | 111 +++++++++ .../compat_rf_realisticnames/config.cpp | 23 ++ .../script_component.hpp | 3 + .../compat_rf_realisticnames/stringtable.xml | 221 ++++++++++++++++++ addons/compat_rf/config.cpp | 18 ++ addons/compat_rf/script_component.hpp | 6 + 14 files changed, 660 insertions(+) create mode 100644 addons/compat_rf/$PBOPREFIX$ create mode 100644 addons/compat_rf/CfgWeapons.hpp create mode 100644 addons/compat_rf/compat_rf_nouniformrestrictions/CfgVehicles.hpp create mode 100644 addons/compat_rf/compat_rf_nouniformrestrictions/config.cpp create mode 100644 addons/compat_rf/compat_rf_nouniformrestrictions/script_component.hpp create mode 100644 addons/compat_rf/compat_rf_realisticnames/Attachments.hpp create mode 100644 addons/compat_rf/compat_rf_realisticnames/CfgMagazines.hpp create mode 100644 addons/compat_rf/compat_rf_realisticnames/CfgVehicles.hpp create mode 100644 addons/compat_rf/compat_rf_realisticnames/CfgWeapons.hpp create mode 100644 addons/compat_rf/compat_rf_realisticnames/config.cpp create mode 100644 addons/compat_rf/compat_rf_realisticnames/script_component.hpp create mode 100644 addons/compat_rf/compat_rf_realisticnames/stringtable.xml create mode 100644 addons/compat_rf/config.cpp create mode 100644 addons/compat_rf/script_component.hpp diff --git a/addons/compat_rf/$PBOPREFIX$ b/addons/compat_rf/$PBOPREFIX$ new file mode 100644 index 0000000000..78e6f45daf --- /dev/null +++ b/addons/compat_rf/$PBOPREFIX$ @@ -0,0 +1 @@ +z\ace\addons\compat_rf diff --git a/addons/compat_rf/CfgWeapons.hpp b/addons/compat_rf/CfgWeapons.hpp new file mode 100644 index 0000000000..d1daa7c710 --- /dev/null +++ b/addons/compat_rf/CfgWeapons.hpp @@ -0,0 +1,42 @@ +class CfgWeapons { + // Ballistics + class Pistol_Base_F; + class hgun_Glock19_RF: Pistol_Base_F { + ace_barrelTwist = 254; + ace_barrelLength = 102; + ace_twistDirection = 1; + }; + + class hgun_DEagle_RF: Pistol_Base_F { + ace_barrelTwist = 482; + ace_barrelLength = 127; + ace_twistDirection = 1; + }; + + class Rifle_Long_Base_F; + class srifle_h6_base_rf: Rifle_Long_Base_F { + ace_barrelTwist = 228.6; + ace_barrelLength = 460; + ace_twistDirection = 1; + }; + + class Rifle_Base_F; + class arifle_ash12_base_RF: Rifle_Base_F { + ace_barrelTwist = 228.6; + ace_barrelLength = 400; + ace_twistDirection = 1; + }; + + class arifle_ash12_LR_base_RF: arifle_ash12_base_RF { + ace_barrelLength = 450; + }; + + // Hearing + class H_HelmetIA; + class H_HelmetIA_sb_arid_RF: H_HelmetIA { + ace_hearing_protection = 0.75; + }; + class H_HelmetIA_sb_digital_RF: H_HelmetIA { + ace_hearing_protection = 0.75; + }; +}; diff --git a/addons/compat_rf/compat_rf_nouniformrestrictions/CfgVehicles.hpp b/addons/compat_rf/compat_rf_nouniformrestrictions/CfgVehicles.hpp new file mode 100644 index 0000000000..553c199ee6 --- /dev/null +++ b/addons/compat_rf/compat_rf_nouniformrestrictions/CfgVehicles.hpp @@ -0,0 +1,12 @@ +// Generated using ace_nouniformrestrictions_fnc_exportConfig +class CfgVehicles { + class B_Helipilot_F; + class C_Helipilot_Green_UniformHolder_RF; + + class C_Helipilot_Rescue_UniformHolder_RF: B_Helipilot_F { + modelSides[] = {6}; + }; + class B_Helipilot_Green_UniformHolder_RF: C_Helipilot_Green_UniformHolder_RF { + modelSides[] = {6}; + }; +}; diff --git a/addons/compat_rf/compat_rf_nouniformrestrictions/config.cpp b/addons/compat_rf/compat_rf_nouniformrestrictions/config.cpp new file mode 100644 index 0000000000..2de1cf9673 --- /dev/null +++ b/addons/compat_rf/compat_rf_nouniformrestrictions/config.cpp @@ -0,0 +1,21 @@ +#include "script_component.hpp" + +class CfgPatches { + class SUBADDON { + name = COMPONENT_NAME; + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = { + "RF_Data_Loadorder", + "ace_nouniformrestrictions" + }; + skipWhenMissingDependencies = 1; + author = ECSTRING(common,ACETeam); + authors[] = {"Mike"}; + url = ECSTRING(main,URL); + VERSION_CONFIG; + }; +}; + +#include "CfgVehicles.hpp" diff --git a/addons/compat_rf/compat_rf_nouniformrestrictions/script_component.hpp b/addons/compat_rf/compat_rf_nouniformrestrictions/script_component.hpp new file mode 100644 index 0000000000..0b98185fa0 --- /dev/null +++ b/addons/compat_rf/compat_rf_nouniformrestrictions/script_component.hpp @@ -0,0 +1,3 @@ +#define SUBCOMPONENT nouniformrestrictions +#define SUBCOMPONENT_BEAUTIFIED No Uniform Restrictions +#include "..\script_component.hpp" diff --git a/addons/compat_rf/compat_rf_realisticnames/Attachments.hpp b/addons/compat_rf/compat_rf_realisticnames/Attachments.hpp new file mode 100644 index 0000000000..6f6f4f9a17 --- /dev/null +++ b/addons/compat_rf/compat_rf_realisticnames/Attachments.hpp @@ -0,0 +1,41 @@ +class optic_MRD; +class optic_MRD_khk_RF: optic_MRD { + displayName = SUBCSTRING(optic_mrd_khk_Name); +}; +class optic_MRD_tan_RF: optic_MRD { + displayName = SUBCSTRING(optic_mrd_tan_Name); +}; + +class optic_ACO_grn; +class optic_ACO_grn_desert_RF: optic_ACO_grn { + displayName = SUBCSTRING(optic_aco_grn_desert_Name); +}; +class optic_ACO_grn_wood_RF: optic_ACO_grn { + displayName = SUBCSTRING(optic_aco_grn_wood_Name); +}; + +class optic_Aco; +class optic_ACO_desert_RF: optic_Aco { + displayName = SUBCSTRING(optic_aco_desert_Name); +}; +class optic_ACO_wood_RF: optic_Aco { + displayName = SUBCSTRING(optic_aco_wood_Name); +}; + +class ItemCore; +class optic_rds_RF: ItemCore { + displayName = SUBCSTRING(optic_rds_Name); +}; + +class optic_VRCO_RF: ItemCore { + displayName = SUBCSTRING(optic_vrco_Name); +}; +class optic_VRCO_tan_RF: optic_VRCO_RF { + displayName = SUBCSTRING(optic_vrco_tan_Name); +}; +class optic_VRCO_khk_RF: optic_VRCO_RF { + displayName = SUBCSTRING(optic_vrco_khk_Name); +}; +class optic_VRCO_pistol_RF: optic_VRCO_RF { + displayName = SUBCSTRING(optic_vrco_Name); +}; diff --git a/addons/compat_rf/compat_rf_realisticnames/CfgMagazines.hpp b/addons/compat_rf/compat_rf_realisticnames/CfgMagazines.hpp new file mode 100644 index 0000000000..52231bcf07 --- /dev/null +++ b/addons/compat_rf/compat_rf_realisticnames/CfgMagazines.hpp @@ -0,0 +1,24 @@ +class CfgMagazines { + class CA_Magazine; + class 1Rnd_RC40_shell_RF: CA_Magazine { + displayName = SUBCSTRING(rc40_Name); + }; + class 1Rnd_RC40_HE_shell_RF: 1Rnd_RC40_shell_RF { + displayName = SUBCSTRING(rc40_he_Name); + }; + class 1Rnd_RC40_SmokeWhite_shell_RF: 1Rnd_RC40_shell_RF { + displayName = SUBCSTRING(rc40_white_Name); + }; + class 1Rnd_RC40_SmokeBlue_shell_RF: 1Rnd_RC40_shell_RF { + displayName = SUBCSTRING(rc40_blue_Name); + }; + class 1Rnd_RC40_SmokeRed_shell_RF: 1Rnd_RC40_shell_RF { + displayName = SUBCSTRING(rc40_red_Name); + }; + class 1Rnd_RC40_SmokeGreen_shell_RF: 1Rnd_RC40_shell_RF { + displayName = SUBCSTRING(rc40_green_Name); + }; + class 1Rnd_RC40_SmokeOrange_shell_RF: 1Rnd_RC40_shell_RF { + displayName = SUBCSTRING(rc40_orange_Name); + }; +}; diff --git a/addons/compat_rf/compat_rf_realisticnames/CfgVehicles.hpp b/addons/compat_rf/compat_rf_realisticnames/CfgVehicles.hpp new file mode 100644 index 0000000000..016a569c50 --- /dev/null +++ b/addons/compat_rf/compat_rf_realisticnames/CfgVehicles.hpp @@ -0,0 +1,134 @@ +class CfgVehicles { + class Heli_light_03_dynamicLoadout_base_F; + class B_Heli_light_03_dynamicLoadout_RF: Heli_light_03_dynamicLoadout_base_F { + displayName = SUBCSTRING(heli_light_03_Name); + }; + + class Heli_light_03_unarmed_base_F; + class B_Heli_light_03_unarmed_RF: Heli_light_03_unarmed_base_F { + displayName = SUBCSTRING(heli_light_03_unarmed_Name); + }; + + class I_Heli_light_03_dynamicLoadout_RF; + class I_E_Heli_light_03_dynamicLoadout_RF: I_Heli_light_03_dynamicLoadout_RF { + displayName = SUBCSTRING(heli_light_03_Name); + }; + + class I_Heli_light_03_unarmed_RF; + class I_E_Heli_light_03_unarmed_RF: I_Heli_light_03_unarmed_RF { + displayName = SUBCSTRING(heli_light_03_unarmed_Name); + }; + + class Heli_EC_01A_base_RF; + class Heli_EC_01A_military_base_RF: Heli_EC_01A_base_RF { + displayName = SUBCSTRING(ec_01a_military_Name); + }; + + class Helicopter_Base_H; + class Heli_EC_01_base_RF: Helicopter_Base_H { + displayName = SUBCSTRING(ec_01_base_Name); + }; + + class Heli_EC_01_civ_base_RF: Heli_EC_01_base_RF { + displayName = SUBCSTRING(ec_01_Name); + }; + + class Heli_EC_01A_civ_base_RF: Heli_EC_01A_base_RF { + displayName = SUBCSTRING(ec_01a_Name); + }; + + class Heli_EC_02_base_RF: Heli_EC_01_base_RF { + displayName = SUBCSTRING(ec_02_Name); + }; + + class Heli_EC_03_base_RF: Heli_EC_01_base_RF { + displayName = SUBCSTRING(ec_03_Name); + }; + + class Heli_EC_04_base_RF: Heli_EC_01_base_RF { + displayName = SUBCSTRING(ec_04_Name); + }; + + // Typhoon + class O_Truck_03_fuel_F; + class C_Truck_03_water_rf: O_Truck_03_fuel_F { + displayName = SUBCSTRING(truck_03_water_Name); + }; + + // RAM 1500 (Pickup) + class Offroad_01_unarmed_base_F; + class Pickup_01_base_rf: Offroad_01_unarmed_base_F { + displayName = SUBCSTRING(pickup_01_Name); + }; + class Pickup_fuel_base_rf: Pickup_01_base_rf { + displayName = SUBCSTRING(pickup_01_fuel_Name); + }; + class Pickup_service_base_rf: Pickup_01_base_rf { + displayName = SUBCSTRING(pickup_01_service_Name); + }; + class Pickup_repair_base_rf: Pickup_service_base_rf { + displayName = SUBCSTRING(pickup_01_repair_Name); + }; + class Pickup_comms_base_rf: Pickup_service_base_rf { + displayName = SUBCSTRING(pickup_01_comms_Name); + }; + class Pickup_repair_ig_base_rf: Pickup_repair_base_rf { + displayName = SUBCSTRING(pickup_01_repair_Name); + }; + class Pickup_01_hmg_base_rf: Pickup_01_base_rf { + displayName = SUBCSTRING(pickup_01_hmg_Name); + }; + class Pickup_01_mmg_base_rf: Pickup_01_base_rf { + displayName = SUBCSTRING(pickup_01_mmg_Name); + }; + class Pickup_01_mrl_base_rf: Pickup_01_base_rf { + displayName = SUBCSTRING(pickup_01_mrl_Name); + }; + class Pickup_01_aat_base_rf: Pickup_01_base_rf { + displayName = SUBCSTRING(pickup_01_aa_Name); + }; + class Pickup_covered_base_rf: Pickup_service_base_rf { + displayName = SUBCSTRING(pickup_01_covered_Name); + }; + + class C_IDAP_Pickup_rf; + class C_IDAP_Pickup_water_rf: C_IDAP_Pickup_rf { + displayName = SUBCSTRING(pickup_01_water_Name); + }; + + class StaticMortar; + class CommandoMortar_base_RF: StaticMortar { + displayName = SUBCSTRING(commando_Name); + }; + + class StaticMGWeapon; + class TwinMortar_base_RF: StaticMGWeapon { + displayName = SUBCSTRING(twinmortar_Name); + }; + + class Helicopter_Base_F; + class UAV_RC40_Base_RF: Helicopter_Base_F { + displayName = SUBCSTRING(rc40_base_Name); + }; + class UAV_RC40_Base_Sensor_RF: UAV_RC40_Base_RF { + displayName = SUBCSTRING(rc40_Name); + }; + class UAV_RC40_Base_HE_RF: UAV_RC40_Base_RF { + displayName = SUBCSTRING(rc40_he_Name); + }; + class UAV_RC40_Base_SmokeWhite_RF: UAV_RC40_Base_HE_RF { + displayName = SUBCSTRING(rc40_white_Name); + }; + class UAV_RC40_Base_SmokeBlue_RF: UAV_RC40_Base_HE_RF { + displayName = SUBCSTRING(rc40_blue_Name); + }; + class UAV_RC40_Base_SmokeRed_RF: UAV_RC40_Base_HE_RF { + displayName = SUBCSTRING(rc40_red_Name); + }; + class UAV_RC40_Base_SmokeGreen_RF: UAV_RC40_Base_HE_RF { + displayName = SUBCSTRING(rc40_green_Name); + }; + class UAV_RC40_Base_SmokeOrange_RF: UAV_RC40_Base_HE_RF { + displayName = SUBCSTRING(rc40_orange_Name); + }; +}; diff --git a/addons/compat_rf/compat_rf_realisticnames/CfgWeapons.hpp b/addons/compat_rf/compat_rf_realisticnames/CfgWeapons.hpp new file mode 100644 index 0000000000..c2d9003f11 --- /dev/null +++ b/addons/compat_rf/compat_rf_realisticnames/CfgWeapons.hpp @@ -0,0 +1,111 @@ +class CfgWeapons { + #include "Attachments.hpp" + + class Pistol_Base_F; + class hgun_Glock19_RF: Pistol_Base_F { + displayName = SUBCSTRING(glock19_Name); + }; + class hgun_Glock19_khk_RF: hgun_Glock19_RF { + displayName = SUBCSTRING(glock19_khk_Name); + }; + class hgun_Glock19_Tan_RF: hgun_Glock19_RF { + displayName = SUBCSTRING(glock19_tan_Name); + }; + class hgun_Glock19_auto_RF: hgun_Glock19_RF { + displayName = SUBCSTRING(glock19_auto_Name); + }; + class hgun_Glock19_auto_khk_RF: hgun_Glock19_auto_RF { + displayName = SUBCSTRING(glock19_auto_khk_Name); + }; + class hgun_Glock19_auto_Tan_RF: hgun_Glock19_auto_RF { + displayName = SUBCSTRING(glock19_auto_tan_Name); + }; + + class hgun_DEagle_RF: Pistol_Base_F { + displayName = SUBCSTRING(deagle_Name); + }; + class hgun_DEagle_classic_RF: hgun_DEagle_RF { + displayName = SUBCSTRING(deagle_classic_Name); + }; + class hgun_DEagle_bronze_RF: hgun_DEagle_RF { + displayName = SUBCSTRING(deagle_bronze_Name); + }; + class hgun_DEagle_copper_RF: hgun_DEagle_RF { + displayName = SUBCSTRING(deagle_copper_Name); + }; + class hgun_DEagle_gold_RF: hgun_DEagle_RF { + displayName = SUBCSTRING(deagle_gold_Name); + }; + + class srifle_h6_base_rf; + class srifle_h6_tan_rf: srifle_h6_base_rf { + displayName = SUBCSTRING(h6_tan_Name); + }; + class srifle_h6_oli_rf: srifle_h6_tan_rf { + displayName = SUBCSTRING(h6_oli_Name); + }; + class srifle_h6_blk_rf: srifle_h6_tan_rf { + displayName = SUBCSTRING(h6_blk_Name); + }; + class srifle_h6_digi_rf: srifle_h6_tan_rf { + displayName = SUBCSTRING(h6_digi_Name); + }; + class srifle_h6_gold_rf: srifle_h6_tan_rf { + displayName = SUBCSTRING(h6_gold_Name); + }; + + class srifle_DMR_01_F; + class srifle_DMR_01_black_RF: srifle_DMR_01_F { + displayName = SUBCSTRING(dmr_01_black_Name); + }; + class srifle_DMR_01_tan_RF: srifle_DMR_01_black_RF { + displayName = SUBCSTRING(dmr_01_tan_Name); + }; + + class SMG_01_F; + class SMG_01_black_RF: SMG_01_F { + displayName = SUBCSTRING(smg_01_black_Name); + }; + + class arifle_ash12_base_RF; + class arifle_ash12_blk_RF: arifle_ash12_base_RF { + displayName = SUBCSTRING(ash12_blk_Name); + }; + class arifle_ash12_desert_RF: arifle_ash12_base_RF { + displayName = SUBCSTRING(ash12_desert_Name); + }; + class arifle_ash12_urban_RF: arifle_ash12_base_RF { + displayName = SUBCSTRING(ash12_urban_Name); + }; + class arifle_ash12_wood_RF: arifle_ash12_base_RF { + displayName = SUBCSTRING(ash12_wood_Name); + }; + + class arifle_ash12_GL_base_RF; + class arifle_ash12_GL_blk_RF: arifle_ash12_GL_base_RF { + displayName = SUBCSTRING(ash12_gl_blk_Name); + }; + class arifle_ash12_GL_desert_RF: arifle_ash12_GL_blk_RF { + displayName = SUBCSTRING(ash12_gl_desert_Name); + }; + class arifle_ash12_GL_urban_RF: arifle_ash12_GL_blk_RF { + displayName = SUBCSTRING(ash12_gl_urban_Name); + }; + class arifle_ash12_GL_wood_RF: arifle_ash12_GL_blk_RF { + displayName = SUBCSTRING(ash12_gl_wood_Name); + }; + + class arifle_ash12_LR_base_RF; + class arifle_ash12_LR_blk_RF: arifle_ash12_LR_base_RF { + displayName = SUBCSTRING(ash12_lr_blk_Name); + }; + class arifle_ash12_LR_desert_RF: arifle_ash12_LR_blk_RF { + displayName = SUBCSTRING(ash12_lr_desert_Name); + }; + class arifle_ash12_LR_urban_RF: arifle_ash12_LR_blk_RF { + displayName = SUBCSTRING(ash12_lr_urban_Name); + }; + class arifle_ash12_LR_wood_RF: arifle_ash12_LR_blk_RF { + displayName = SUBCSTRING(ash12_lr_wood_Name); + }; +}; diff --git a/addons/compat_rf/compat_rf_realisticnames/config.cpp b/addons/compat_rf/compat_rf_realisticnames/config.cpp new file mode 100644 index 0000000000..47003c4a42 --- /dev/null +++ b/addons/compat_rf/compat_rf_realisticnames/config.cpp @@ -0,0 +1,23 @@ +#include "script_component.hpp" + +class CfgPatches { + class SUBADDON { + name = COMPONENT_NAME; + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = { + "RF_Data_Loadorder", + "ace_realisticnames" + }; + skipWhenMissingDependencies = 1; + author = ECSTRING(common,ACETeam); + authors[] = {"Mike", "Marc"}; + url = ECSTRING(main,URL); + VERSION_CONFIG; + }; +}; + +#include "CfgMagazines.hpp" +#include "CfgWeapons.hpp" +#include "CfgVehicles.hpp" diff --git a/addons/compat_rf/compat_rf_realisticnames/script_component.hpp b/addons/compat_rf/compat_rf_realisticnames/script_component.hpp new file mode 100644 index 0000000000..b8d0682fa4 --- /dev/null +++ b/addons/compat_rf/compat_rf_realisticnames/script_component.hpp @@ -0,0 +1,3 @@ +#define SUBCOMPONENT realisticnames +#define SUBCOMPONENT_BEAUTIFIED Realistic Names +#include "..\script_component.hpp" diff --git a/addons/compat_rf/compat_rf_realisticnames/stringtable.xml b/addons/compat_rf/compat_rf_realisticnames/stringtable.xml new file mode 100644 index 0000000000..dfd7c8fd07 --- /dev/null +++ b/addons/compat_rf/compat_rf_realisticnames/stringtable.xml @@ -0,0 +1,221 @@ + + + + + EOTech MRDS (Khaki) + + + EOTech MRDS (Tan) + + + C-More Railway (Green, Desert) + + + C-More Railway (Green, Woodland) + + + C-More Railway (Red, Desert) + + + C-More Railway (Red, Woodland) + + + Aimpoint Micro R-1 Reflex + + + Vortex Spitfire Prism + + + Vortex Spitfire Prism (Tan) + + + Vortex Spitfire Prism (Khaki) + + + Glock 19X + + + Glock 19X (Khaki) + + + Glock 19X (Tan) + + + Glock 19X Auto + + + Glock 19X Auto (Khaki) + + + Glock 19X Auto (Tan) + + + Desert Eagle Mark XIX L5 + + + Desert Eagle Mark XIX L5 (Classic) + + + Desert Eagle Mark XIX L5 (Bronze) + + + Desert Eagle Mark XIX L5 (Copper) + + + Desert Eagle Mark XIX L5 (Gold) + + + Hera H6 (Tan) + + + Hera H6 (Olive) + + + Hera H6 (Black) + + + Hera H6 (Digital) + + + Hera H6 (Gold) + + + VS-121 (Black) + + + VS-121 (Tan) + + + Vector SMG (Black) + + + ASh-12 (Black) + + + ASh-12 (Desert) + + + ASh-12 (Urban) + + + ASh-12 (Woodland) + + + ASh-12 GL (Black) + + + ASh-12 GL (Desert) + + + ASh-12 GL (Urban) + + + ASh-12 GL (Woodland) + + + ASh-12 LR (Black) + + + ASh-12 LR (Desert) + + + ASh-12 LR (Urban) + + + ASh-12 LR (Woodland) + + + AW159 Wildcat + + + AW159 Wildcat (Unarmed) + + + H225M Super Cougar HADR + + + H225M Super Cougar Transport + + + H225 Super Puma Transport + + + H225 Super Puma VIP + + + H225M Super Cougar SOCAT + + + H225M Super Cougar CSAR + + + H225 Super Puma SAR + + + Typhoon Water + + + Ram 1500 + + + Ram 1500 (Fuel) + + + Ram 1500 (Services) + + + Ram 1500 (Repair) + + + Ram 1500 (Comms) + + + Ram 1500 (HMG) + + + Ram 1500 (MMG) + + + Ram 1500 (MRL) + + + Ram 1500 (AA) + + + Ram 1500 (Covered) + + + Ram 1500 (Water) + + + RSG60 + + + AMOS + + + Drone40 + + + Drone40 Scout + + + Drone40 HE + + + Drone40 Smoke (White) + + + Drone40 Smoke (Blue) + + + Drone40 Smoke (Red) + + + Drone40 Smoke (Green) + + + Drone40 Smoke (Orange) + + + diff --git a/addons/compat_rf/config.cpp b/addons/compat_rf/config.cpp new file mode 100644 index 0000000000..ab6fb94275 --- /dev/null +++ b/addons/compat_rf/config.cpp @@ -0,0 +1,18 @@ +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + name = COMPONENT_NAME; + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = {"RF_Data_Loadorder"}; + skipWhenMissingDependencies = 1; + author = ECSTRING(common,ACETeam); + authors[] = {"Mike"}; + url = ECSTRING(main,URL); + VERSION_CONFIG; + }; +}; + +#include "CfgWeapons.hpp" diff --git a/addons/compat_rf/script_component.hpp b/addons/compat_rf/script_component.hpp new file mode 100644 index 0000000000..2cc45da490 --- /dev/null +++ b/addons/compat_rf/script_component.hpp @@ -0,0 +1,6 @@ +#define COMPONENT compat_rf +#define COMPONENT_BEAUTIFIED Reaction Forces Compatibility + +#include "\z\ace\addons\main\script_mod.hpp" + +#include "\z\ace\addons\main\script_macros.hpp" From 130348d3a59397c89bf31c540d83be2ce651fd9d Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Sun, 9 Jun 2024 18:20:17 -0500 Subject: [PATCH 079/290] Hit Reactions - Prevent AI's hitpart EH running on all clients (#10057) also dynamically add ehs --- addons/hitreactions/XEH_postInit.sqf | 42 ++++++++++++++---------- addons/hitreactions/XEH_preInit.sqf | 4 +-- addons/hitreactions/initSettings.inc.sqf | 6 ++-- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/addons/hitreactions/XEH_postInit.sqf b/addons/hitreactions/XEH_postInit.sqf index d45d4f3df2..2750ae1159 100644 --- a/addons/hitreactions/XEH_postInit.sqf +++ b/addons/hitreactions/XEH_postInit.sqf @@ -1,27 +1,35 @@ #include "script_component.hpp" -["ace_firedNonPlayer", { - if (GVAR(weaponDropChanceArmHitPlayer) + GVAR(weaponDropChanceArmHitAI) == 0) exitWith {}; - (_this select 6) addEventHandler ["HitPart", { - params ["", "_entity", "", "", "", "", "_selections"]; - - [_entity, _selections] call FUNC(checkWeaponDrop); - }]; -}] call CBA_fnc_addEventHandler; - -["ace_firedPlayer", { - if (GVAR(weaponDropChanceArmHitPlayer) + GVAR(weaponDropChanceArmHitAI) == 0) exitWith {}; - - (_this select 6) addEventHandler ["HitPart", { - params ["", "_entity", "", "", "", "", "_selections"]; - - [_entity, _selections] call FUNC(checkWeaponDrop); - }]; +[QGVAR(updateFiredEHs), { + TRACE_2("updateFiredEH",GVAR(weaponDropChanceArmHitPlayer),GVAR(weaponDropChanceArmHitAI)); + if (GVAR(weaponDropChanceArmHitPlayer) + GVAR(weaponDropChanceArmHitAI) == 0) then { + if (isNil QGVAR(firedEHs)) exitWith {}; + { + _x call CBA_fnc_removeEventHandler; + } forEach GVAR(firedEHs); + GVAR(firedEHs) = nil; + TRACE_1("removed EHs",GVAR(firedEHs)); + } else { + if (!isNil QGVAR(firedEHs)) exitWith {}; + private _firedEH = { + if (!local (_this select 0)) exitWith {}; + (_this select 6) addEventHandler ["HitPart", { + params ["", "_entity", "", "", "", "", "_selections"]; + [_entity, _selections] call FUNC(checkWeaponDrop); + }]; + }; + GVAR(firedEHs) = []; + { + GVAR(firedEHs) pushBack [_x, [_x, _firedEH] call CBA_fnc_addEventHandler]; + } forEach ["ace_firedNonPlayer", "ace_firedPlayer"]; + TRACE_1("added EHs",GVAR(firedEHs)); + }; }] call CBA_fnc_addEventHandler; [QGVAR(dropWeapon), { params ["_unit"]; + TRACE_1("dropWeaponEH",_unit); if !(_unit getVariable [QGVAR(canDropWeapon), true]) exitWith {}; diff --git a/addons/hitreactions/XEH_preInit.sqf b/addons/hitreactions/XEH_preInit.sqf index 9aa0acea0e..296279c7eb 100644 --- a/addons/hitreactions/XEH_preInit.sqf +++ b/addons/hitreactions/XEH_preInit.sqf @@ -8,8 +8,6 @@ PREP_RECOMPILE_END; #include "initSettings.inc.sqf" -ADDON = true; - GVAR(armSelections) = [ "leftshoulder", "rightshoulder", @@ -21,3 +19,5 @@ GVAR(armSelections) = [ "righthand", "rightarm" ]; + +ADDON = true; diff --git a/addons/hitreactions/initSettings.inc.sqf b/addons/hitreactions/initSettings.inc.sqf index 2f51a25647..820f664767 100644 --- a/addons/hitreactions/initSettings.inc.sqf +++ b/addons/hitreactions/initSettings.inc.sqf @@ -15,7 +15,8 @@ private _category = [LELSTRING(common,categoryUncategorized), QUOTE(COMPONENT_BE LSTRING(weaponDropChanceArmHitPlayer_displayName), _category, [0, 1, 0, 2, true], - 1 + 1, + {[QGVAR(updateFiredEHs)] call CBA_fnc_localEvent} ] call CBA_fnc_addSetting; [ @@ -24,5 +25,6 @@ private _category = [LELSTRING(common,categoryUncategorized), QUOTE(COMPONENT_BE LSTRING(weaponDropChanceArmHitAI_displayName), _category, [0, 1, 0, 2, true], - 1 + 1, + {[QGVAR(updateFiredEHs)] call CBA_fnc_localEvent} ] call CBA_fnc_addSetting; From 97bc371f5c55373d809d1a5144d9b462874d7392 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Sun, 9 Jun 2024 18:20:39 -0500 Subject: [PATCH 080/290] Common - Add `addPlayerEH` for adding EHs to ace_player (#10056) * Common - Add `addPlayerEH` for adding EHs to ace_player * Update fnc_addPlayerEH.sqf * convert ui to use new func --- addons/common/XEH_PREP.hpp | 1 + addons/common/functions/fnc_addPlayerEH.sqf | 61 +++++++++++++++++++ addons/ui/XEH_PREP.hpp | 1 - addons/ui/XEH_clientInit.sqf | 2 +- .../ui/functions/fnc_handlePlayerChanged.sqf | 32 ---------- 5 files changed, 63 insertions(+), 34 deletions(-) create mode 100644 addons/common/functions/fnc_addPlayerEH.sqf delete mode 100644 addons/ui/functions/fnc_handlePlayerChanged.sqf diff --git a/addons/common/XEH_PREP.hpp b/addons/common/XEH_PREP.hpp index 68fdaaf77d..5a2893eeaf 100644 --- a/addons/common/XEH_PREP.hpp +++ b/addons/common/XEH_PREP.hpp @@ -265,6 +265,7 @@ PREP(_handleRequestAllSyncedEvents); PREP(addActionEventHandler); PREP(addActionMenuEventHandler); PREP(addMapMarkerCreatedEventHandler); +PREP(addPlayerEH); PREP(removeActionEventHandler); PREP(removeActionMenuEventHandler); diff --git a/addons/common/functions/fnc_addPlayerEH.sqf b/addons/common/functions/fnc_addPlayerEH.sqf new file mode 100644 index 0000000000..81d030fb62 --- /dev/null +++ b/addons/common/functions/fnc_addPlayerEH.sqf @@ -0,0 +1,61 @@ +#include "..\script_component.hpp" +/* + * Author: PabstMirror + * Adds event handler just to ACE_player + * + * Arguments: + * 0: Key + * 1: Event Type + * 2: Event Code + * 3: Ignore Virtual Units (spectators, virtual zeus, uav RC) (default: false) + * + * Return Value: + * None + * + * Example: + * ["example", "FiredNear", {systemChat str _this}] call ace_common_fnc_addPlayerEH + * + * Public: Yes +*/ +params [["_key", "", [""]], ["_type", "", [""]], ["_code", {}, [{}]], ["_ignoreVirtual", false, [false]]]; +TRACE_3("addPlayerEH",_key,_type,_ignoreVirtual); + +if (isNil QGVAR(playerEventsHash)) then { // first-run init + GVAR(playerEventsHash) = createHashMap; + ["unit", { + params ["_newPlayer", "_oldPlayer"]; + // uav check only applies to direct controlling UAVs from zeus, no effect on normal UAV operation + private _isVirutal = (unitIsUAV _newPlayer) || {getNumber (configOf _newPlayer >> "isPlayableLogic") == 1}; + + TRACE_4("",_newPlayer,_oldPlayer,_isVirutal,count GVAR(playerEventsHash)); + { + _y params ["_type", "_code", "_ignoreVirtual"]; + + private _oldEH = _oldPlayer getVariable [_x, -1]; + if (_oldEH != -1) then { + _oldPlayer removeEventHandler [_type, _oldEH]; + _oldPlayer setVariable [_x, nil]; + }; + + _oldEH = _newPlayer getVariable [_x, -1]; + if (_oldEH != -1) then { continue }; // if respawned then var and EH already exists + if (_ignoreVirtual && _isVirutal) then { continue }; + + private _newEH = _newPlayer addEventHandler [_type, _code]; + _newPlayer setVariable [_x, _newEH]; + } forEach GVAR(playerEventsHash); + }, false] call CBA_fnc_addPlayerEventHandler; +}; + + +_key = format [QGVAR(playerEvents_%1), toLower _key]; +if (_key in GVAR(playerEventsHash)) exitWith { ERROR_1("bad key %1",_this); }; + +GVAR(playerEventsHash) set [_key, [_type, _code, _ignoreVirtual]]; + +if (isNull ACE_player) exitWith {}; +if (_ignoreVirtual && {(unitIsUAV ACE_player) || {getNumber (configOf ACE_player >> "isPlayableLogic") == 1}}) exitWith {}; + +// Add event now +private _newEH = ACE_player addEventHandler [_type, _code]; +ACE_player setVariable [_key, _newEH]; diff --git a/addons/ui/XEH_PREP.hpp b/addons/ui/XEH_PREP.hpp index f7edabcc3f..436e59361c 100644 --- a/addons/ui/XEH_PREP.hpp +++ b/addons/ui/XEH_PREP.hpp @@ -1,5 +1,4 @@ PREP(compileConfigUI); -PREP(handlePlayerChanged); PREP(handleSpeedIndicator); PREP(moduleInit); PREP(onAnimChanged); diff --git a/addons/ui/XEH_clientInit.sqf b/addons/ui/XEH_clientInit.sqf index 1ef328b176..d7f1df73fb 100644 --- a/addons/ui/XEH_clientInit.sqf +++ b/addons/ui/XEH_clientInit.sqf @@ -48,4 +48,4 @@ GVAR(elementsSet) = call CBA_fnc_createNamespace; }] call CBA_fnc_addEventHandler; }] call CBA_fnc_addEventHandler; -["unit", LINKFUNC(handlePlayerChanged), true] call CBA_fnc_addPlayerEventHandler; +[QUOTE(ADDON), "AnimChanged", LINKFUNC(onAnimChanged)] call EFUNC(common,addPlayerEH); diff --git a/addons/ui/functions/fnc_handlePlayerChanged.sqf b/addons/ui/functions/fnc_handlePlayerChanged.sqf deleted file mode 100644 index 94f317a18c..0000000000 --- a/addons/ui/functions/fnc_handlePlayerChanged.sqf +++ /dev/null @@ -1,32 +0,0 @@ -#include "..\script_component.hpp" -/* - * Author: veteran29 - * Handles switching units. - * - * Arguments: - * 0: New Unit - * 1: Old Unit - * - * Return Value: - * None - * - * Example: - * [newbob, oldbob] call ace_ui_fnc_handlePlayerChanged - * - * Public: No - */ -params ["_newUnit", "_oldUnit"]; -TRACE_2("unit changed",_newUnit,_oldUnit); - -if (!isNull _oldUnit) then { - _oldUnit removeEventHandler ["AnimChanged", _oldUnit getVariable [QGVAR(animHandler), -1]]; - _oldUnit setVariable [QGVAR(animHandler), nil]; - TRACE_1("remove old",_oldUnit getVariable QGVAR(animHandler)); -}; - -// Don't add a new EH if the unit respawned -if (_newUnit getVariable [QGVAR(animHandler), -1] == -1) then { - private _animHandler = _newUnit addEventHandler ["AnimChanged", LINKFUNC(onAnimChanged)]; - TRACE_1("add new",_animHandler); - _newUnit setVariable [QGVAR(animHandler), _animHandler]; -}; From 46e840b5a2896c041d733dbe986bb8d345631717 Mon Sep 17 00:00:00 2001 From: Apricot <50947830+Apricot-ale@users.noreply.github.com> Date: Mon, 10 Jun 2024 08:21:00 +0900 Subject: [PATCH 081/290] Translations and Compat - Improve Japanese and CDLC WS/RF localization (#10058) * Update Japanese * rename smoke * Leo2SG * Rename FAL Para to FAL OSW Para * Fix wood as woodland in japanese * change camo to aaf camo in jp * Rename RF R1 to equalize with WS R1 * Add dedicated name config VRCO-S * Add stringtable for VRCO-S --- .../compat_rf_realisticnames/Attachments.hpp | 2 +- .../compat_rf_realisticnames/stringtable.xml | 78 ++++++++++++++++++- .../compat_ws_realisticnames/stringtable.xml | 68 ++++++++++++---- addons/cookoff/stringtable.xml | 16 +++- addons/grenades/stringtable.xml | 1 + addons/hitreactions/stringtable.xml | 4 +- addons/medical_treatment/stringtable.xml | 4 + addons/realisticnames/stringtable.xml | 23 ++++-- addons/zeus/stringtable.xml | 11 ++- 9 files changed, 179 insertions(+), 28 deletions(-) diff --git a/addons/compat_rf/compat_rf_realisticnames/Attachments.hpp b/addons/compat_rf/compat_rf_realisticnames/Attachments.hpp index 6f6f4f9a17..9915ad1d44 100644 --- a/addons/compat_rf/compat_rf_realisticnames/Attachments.hpp +++ b/addons/compat_rf/compat_rf_realisticnames/Attachments.hpp @@ -37,5 +37,5 @@ class optic_VRCO_khk_RF: optic_VRCO_RF { displayName = SUBCSTRING(optic_vrco_khk_Name); }; class optic_VRCO_pistol_RF: optic_VRCO_RF { - displayName = SUBCSTRING(optic_vrco_Name); + displayName = SUBCSTRING(optic_vrco_pistol_Name); }; diff --git a/addons/compat_rf/compat_rf_realisticnames/stringtable.xml b/addons/compat_rf/compat_rf_realisticnames/stringtable.xml index dfd7c8fd07..994739faff 100644 --- a/addons/compat_rf/compat_rf_realisticnames/stringtable.xml +++ b/addons/compat_rf/compat_rf_realisticnames/stringtable.xml @@ -3,219 +3,295 @@ EOTech MRDS (Khaki) + EOTech MRDS (カーキ) EOTech MRDS (Tan) + EOTech MRDS (タン) C-More Railway (Green, Desert) + C-More レイルウェイ (グリーン、砂漠迷彩) C-More Railway (Green, Woodland) + C-More レイルウェイ (グリーン、森林迷彩) C-More Railway (Red, Desert) + C-More レイルウェイ (グリーン、砂漠迷彩) C-More Railway (Red, Woodland) + C-More レイルウェイ (グリーン、森林迷彩) - Aimpoint Micro R-1 Reflex + Aimpoint Micro R-1 + Aimpoint マイクロ R-1 Vortex Spitfire Prism + Vortex スピットファイア プリズム Vortex Spitfire Prism (Tan) + Vortex スピットファイア プリズム (タン) Vortex Spitfire Prism (Khaki) + Vortex スピットファイア プリズム (カーキ) + + + Vortex Spitfire Prism (Pistol) + Vortex スピットファイア プリズム (ピストル用) Glock 19X + グロック 19X Glock 19X (Khaki) + グロック 19X (カーキ) Glock 19X (Tan) + グロック 19X (タン) Glock 19X Auto + グロック 19X オート Glock 19X Auto (Khaki) + グロック 19X オート (カーキ) Glock 19X Auto (Tan) + グロック 19X オート (タン) Desert Eagle Mark XIX L5 + デザートイーグル Mark XIX L5 Desert Eagle Mark XIX L5 (Classic) + デザートイーグル Mark XIX L5 (クラシック) Desert Eagle Mark XIX L5 (Bronze) + デザートイーグル Mark XIX L5 (ブロンズ) Desert Eagle Mark XIX L5 (Copper) + デザートイーグル Mark XIX L5 (カッパー) Desert Eagle Mark XIX L5 (Gold) + デザートイーグル Mark XIX L5 (ゴールド) Hera H6 (Tan) + ヘラ H6 (タン) Hera H6 (Olive) + ヘラ H6 (オリーブ) Hera H6 (Black) + ヘラ H6 (ブラック) Hera H6 (Digital) + ヘラ H6 (AAF迷彩) Hera H6 (Gold) + ヘラ H6 (ゴールド) VS-121 (Black) + VS-121 (ブラック) VS-121 (Tan) + VS-121 (タン) Vector SMG (Black) + ベクター SMG (ブラック) ASh-12 (Black) + ASh-12 (ブラック) ASh-12 (Desert) + ASh-12 (砂漠迷彩) ASh-12 (Urban) + ASh-12 (市街地迷彩) ASh-12 (Woodland) + ASh-12 (森林迷彩) ASh-12 GL (Black) + ASh-12 GL (ブラック) ASh-12 GL (Desert) + ASh-12 GL (砂漠迷彩) ASh-12 GL (Urban) + ASh-12 GL (市街地迷彩) ASh-12 GL (Woodland) + ASh-12 GL (森林迷彩) ASh-12 LR (Black) + ASh-12 LR (ブラック) ASh-12 LR (Desert) + ASh-12 LR (砂漠迷彩) ASh-12 LR (Urban) + ASh-12 LR (市街地迷彩) ASh-12 LR (Woodland) + ASh-12 LR (森林迷彩) AW159 Wildcat + AW159 ワイルドキャット AW159 Wildcat (Unarmed) + AW159 ワイルドキャット (非武装) H225M Super Cougar HADR + H225M シュペル クーガー HADR H225M Super Cougar Transport + H225M シュペル クーガー 輸送 H225 Super Puma Transport + H225 シュペル ピューマ 輸送 H225 Super Puma VIP + H225 シュペル ピューマ VIP H225M Super Cougar SOCAT + H225M シュペル クーガー SOCAT H225M Super Cougar CSAR + H225M シュペル クーガー CSAR H225 Super Puma SAR + H225 シュペル ピューマ SAR Typhoon Water + タイフーン 給水 Ram 1500 + ラム 1500 Ram 1500 (Fuel) + ラム 1500 (燃料) Ram 1500 (Services) + ラム 1500 (サービス) Ram 1500 (Repair) + ラム 1500 (修理) Ram 1500 (Comms) + ラム 1500 (通信) Ram 1500 (HMG) + ラム 1500 (HMG) Ram 1500 (MMG) + ラム 1500 (MMG) Ram 1500 (MRL) + ラム 1500 (MRL) Ram 1500 (AA) + ラム 1500 (対空) Ram 1500 (Covered) + ラム 1500 (カバー) Ram 1500 (Water) + ラム 1500 (給水) RSG60 + RSG60 AMOS + AMOS Drone40 + ドローン40 Drone40 Scout + ドローン40 偵察 Drone40 HE + ドローン40 榴弾 Drone40 Smoke (White) + ドローン40 発煙 (白) Drone40 Smoke (Blue) + ドローン40 発煙 (青) Drone40 Smoke (Red) + ドローン40 発煙 (赤) Drone40 Smoke (Green) + ドローン40 発煙 (緑) Drone40 Smoke (Orange) + ドローン40 発煙 (橙) diff --git a/addons/compat_ws/compat_ws_realisticnames/stringtable.xml b/addons/compat_ws/compat_ws_realisticnames/stringtable.xml index 26504b497f..30b53b7926 100644 --- a/addons/compat_ws/compat_ws_realisticnames/stringtable.xml +++ b/addons/compat_ws/compat_ws_realisticnames/stringtable.xml @@ -26,7 +26,7 @@ AA-12 (뱀 위장) AA12 (Schlange) AA12 (Serpe) - AA12 (ヘビ柄) + AA12 (ヘビ柄迷彩) AA12 (Змея) AA12 (Serpiente) @@ -45,7 +45,7 @@ 갈릴 ARM (낡음) Galil ARM (Alt) Galil ARM (Vecchio) - ガリル ARM (使い古し) + ガリル ARM (古びた) Galil ARM (Старый) Galil ARM (Ancien) Galil ARM (Vieja) @@ -65,7 +65,7 @@ GLX-160 (뱀 위장) GLX 160 (Schlange) GLX-160 (Serpe) - GLX 160 (ヘビ柄) + GLX 160 (ヘビ柄迷彩) GLX 160 (Змея) GLX 160 (Serpiente) @@ -94,7 +94,7 @@ GLX-160 (위장) GLX 160 (Tarn) GLX-160 (Mimetica) - GLX 160 (迷彩) + GLX 160 (AAF迷彩) GLX 160 (Камуфляж) GLX 160 (Camo) GLX 160 (Camo) @@ -124,7 +124,7 @@ Mk.14 Mod 1 EBR (뱀 위장) Mk14 Mod 1 EBR (Schlange) Mk14 Mod 1 EBR (Serpe) - Mk14 Mod 1 EBR (ヘビ柄) + Mk14 Mod 1 EBR (ヘビ柄迷彩) Mk14 Mod 1 EBR (Змея) Mk14 Mod 1 EBR (Serpiente) @@ -142,7 +142,7 @@ 벡터 SS-77 (위장) Vektor SS-77 (Tarn) Vektor SS-77 (Mimetica) - ヴェクター SS-77 (迷彩) + ヴェクター SS-77 (AAF迷彩) Vektor SS-77 (Камуфляж) Vektor SS-77 (Camo) Vektor SS-77 (Camo) @@ -192,7 +192,7 @@ 벡터 SS-77 단축형 (뱀 위장) Vektor SS-77 Compact (Schlange) Vektor SS-77 Compatto (Serpe) - ヴェクター SS-77 コンパクト (ヘビ柄) + ヴェクター SS-77 コンパクト (ヘビ柄迷彩) Vektor SS-77 Compact (змея) Vektor SS-77 Compacta (Serpiente) @@ -201,7 +201,7 @@ FN FAL 50.00 (목재) FN FAL 50.00 (Holz) FN FAL 50.00 (Legno) - FN FAL 50.00 (森林迷彩) + FN FAL 50.00 (木製) FN FAL 50.00 (лесной) FN FAL 50.00 (Bois) FN FAL 50.00 (Madera) @@ -211,7 +211,7 @@ FN FAL 50.00 GL (목재) FN FAL 50.00 GL (Holz) FN FAL 50.00 GL (Legno) - FN FAL 50.00 GL (森林迷彩) + FN FAL 50.00 GL (木製) FN FAL 50.00 GL (лесной) FN FAL 50.00 GL (Bois) FN FAL 50.00 GL (Madera) @@ -257,17 +257,19 @@ FN FAL 50.00 (Jungla) - FN FAL 50.00 Para + FN FAL OSW Para + FN FAL OSW パラ - FN FAL 50.00 Para (Snake) + FN FAL OSW Para (Snake) + FN FAL OSW パラ (ヘビ柄迷彩) Vektor R4 벡터 R4 Vektor R4 Vektor R4 - ヴェクター R5 + ヴェクター R4 Vektor R4 Vektor R4 Vektor R4 @@ -297,7 +299,7 @@ 벡터 R5 카빈 (뱀 위장) Vektor R5 Carbine (Schlange) Vektor R5 Carabina (Serpe) - ヴェクター R5 カービン (ヘビ柄) + ヴェクター R5 カービン (ヘビ柄迷彩) Vektor R5 Carbine (Змея) Vektor R5 Carabina (Serpiente) @@ -306,7 +308,7 @@ 벡터 R5 카빈 GL (뱀 위장) Vektor R5 Carbine GL (Schlange) Vektor R5 Carabina GL (Serpe) - ヴェクター R5 カービン GL (ヘビ柄) + ヴェクター R5 カービン GL (ヘビ柄迷彩) Vektor R5 Carbine GL (Змея) Vektor R5 Carabina GL (Serpiente) @@ -456,117 +458,155 @@ GM6 Lynx (Snake) + GM6 リンクス (ヘビ柄迷彩) RPG-32 (Sand) + RPG-32 (サンド) ELCAN SpecterOS (Hex) + ELCAN SpecterOS (六角形迷彩) EOTech XPS3 (Snake) + EOTech XPS3 (ヘビ柄迷彩) EOTech XPS3 SMG (Snake) + EOTech XPS3 SMG (ヘビ柄迷彩) Leupold Mark 4 HAMR (Arid) + Leupold Mark 4 HAMR (乾燥地帯迷彩) Leupold Mark 4 HAMR (Lush) + Leupold Mark 4 HAMR (緑地迷彩) Leupold Mark 4 HAMR (Sand) + Leupold Mark 4 HAMR (サンド) Leupold Mark 4 HAMR (Snake) + Leupold Mark 4 HAMR (ヘビ柄迷彩) Aimpoint Micro R-1 (High, Black) + Aimpoint マイクロ R-1 (ハイマウント、ブラック) Aimpoint Micro R-1 (High, Khaki) + Aimpoint マイクロ R-1 (ハイマウント、カーキ) Aimpoint Micro R-1 (High, Sand) + Aimpoint マイクロ R-1 (ハイマウント、サンド) Aimpoint Micro R-1 (High, Snake) + Aimpoint マイクロ R-1 (ハイマウント、ヘビ柄迷彩) Aimpoint Micro R-1 (High, Arid) + Aimpoint マイクロ R-1 (ハイマウント、乾燥地帯迷彩) Aimpoint Micro R-1 (High, Lush) + Aimpoint マイクロ R-1 (ハイマウント、緑地迷彩) Aimpoint Micro R-1 (High, Black/Sand) + Aimpoint マイクロ R-1 (ハイマウント、ブラック/サンド) Aimpoint Micro R-1 (Low, Black) + Aimpoint マイクロ R-1 (ローマウント、ブラック) Aimpoint Micro R-1 (Low, Khaki) + Aimpoint マイクロ R-1 (ローマウント、カーキ) Aimpoint Micro R-1 (Low, Sand) + Aimpoint マイクロ R-1 (ローマウント、サンド) Aimpoint Micro R-1 (Low, Snake) + Aimpoint マイクロ R-1 (ローマウント、ヘビ柄迷彩) Aimpoint Micro R-1 (Low, Arid) + Aimpoint マイクロ R-1 (ローマウント、乾燥地帯迷彩) Aimpoint Micro R-1 (Low, Lush) + Aimpoint マイクロ R-1 (ローマウント、緑地迷彩) Burris XTR II (Snake) + Burris XTR II (ヘビ柄迷彩) Badger IFV (ATGM) + バジャー IFV (ATGM) Badger IFV (Command) + バジャー IFV (指揮) Badger IFV (Mortar) + バジャー IFV (迫撃砲) KamAZ (Zu-23-2) + KamAZ (Zu-23-2) KamAZ Cargo + KamAZ 貨物 KamAZ Repair + KamAZ 修理 KamAZ Racing + KamAZ レース仕様 KamAZ Ammo + KamAZ 弾薬 KamAZ Flatbed + KamAZ フラットベッド AW101 Merlin + AW101 マーリン BM-2T Stalker (Bumerang-BM) + BM-2T ストーカー (ブーメランク-BM) Otokar ARMA (HMG) + オトカ アルマ (HMG) Otokar ARMA (Unarmed) + オトカ アルマ (非武装) Ka-60 Kasatka (UP) + Ka-60 カサートカ (UP) Ka-60 Kasatka (UP, Unarmed) + Ka-60 カサートカ (UP、非武装) diff --git a/addons/cookoff/stringtable.xml b/addons/cookoff/stringtable.xml index c068edb811..504dc797ac 100644 --- a/addons/cookoff/stringtable.xml +++ b/addons/cookoff/stringtable.xml @@ -18,21 +18,27 @@ Enable vehicle cook-off fire + 車両の誘爆火災を有効化 Enables vehicle cook-off fire effects.\nThis doesn't include ammunition detonations. + 車両の誘爆火災エフェクトを有効化します。\nこれには弾薬の爆発は含まれません。 Vehicle cook-off fire duration multiplier + 車両の誘爆火災の持続時間倍率 Multiplier for how long vehicle cook-off fire lasts.\nSetting to 0 will disable vehicle cook-off fire. + 車両の誘爆火災の持続時間をどのくらいの長さにするかの倍率。\n0に設定すると車両の誘爆火災が無効化されます。 Vehicle cook-off fire probability multiplier + 車両の誘爆火災の可能性倍率 Multiplier for vehicle cook-off fire probability. Higher value results in higher cook-off probability.\nSetting to 0 will disable vehicle cook-off fire. + 車両の誘爆火災がどのくらいの可能性で発生するかの倍率。高い数値は高い誘爆の可能性につながります。\n0に設定すると車両の誘爆火災が無効化されます。 Destroy vehicles after cook-off @@ -49,7 +55,7 @@ Controls whether vehicles will always be destroyed after cooking off. - 誘爆後に車両を破壊するかどうかを設定する。 + 誘爆の終了後に車両を必ず完全破壊するかどうかを設定します。 Kontroluje, czy pojazdy będą zawsze niszczone po samozapłonie. Steuert, ob Fahrzeuge nach dem Durchzünden immer zerstört werden. Determina se veicoli saranno sempre distrutti dall'esplosione delle munizioni. @@ -61,9 +67,11 @@ Enable vehicle ammo cook-off + 車両弾薬の誘爆を有効化 Enables cooking off of vehicle ammunition. Fires ammunition projectiles while vehicle has ammunition remaining.\nThis doesn't include fire effects. + 車両弾薬の誘爆を有効化します。車両に積載されたままの弾薬と弾頭が発射されます。\nこれには火災エフェクトは含まれません。 Enable ammo box cook-off @@ -82,16 +90,19 @@ Enables cooking off of ammo boxes.\nThis doesn't include fire effects. + 弾薬箱の誘爆を有効化します。\nこれには火災エフェクトは含まれません。 Ammo cook-off duration multiplier + 弾薬の誘爆の持続時間倍率 Multiplier for how long ammunition cook-off lasts, for both vehicles and ammo boxes.\nSetting to 0 will disable ammo cook-off for both vehicles and ammo boxes. + 弾薬の誘爆の持続時間をどのくらいの長さにするかの倍率。車両弾薬と弾薬箱どちらにも影響します。\n0に設定すると弾薬の誘爆が無効化されます。 Enable ammo removal during cook-off - 誘爆中の弾薬除去を有効/無効にする + 誘爆による弾薬の除去を有効化 Retirer les munitions durant l'auto-inflammation Aktiviert/Deaktiviert Entfernung der Munition beim Durchzünden Abilita rimozione munizioni dopo l'esplosione @@ -105,6 +116,7 @@ Removes all ammo during cook-off. Retire des munitions des véhicules durant une auto-inflammation. Entfernt Munition während dem Durchzünden der Munition eines Fahrzeuges. + 誘爆によって全ての弾薬を除去します。 diff --git a/addons/grenades/stringtable.xml b/addons/grenades/stringtable.xml index ec009fa2ba..eab327d8cf 100644 --- a/addons/grenades/stringtable.xml +++ b/addons/grenades/stringtable.xml @@ -105,6 +105,7 @@ Can't roll this grenade, switched to %1 + この手榴弾は転がせません、 %1 に切り替えます M84 Stun Grenade diff --git a/addons/hitreactions/stringtable.xml b/addons/hitreactions/stringtable.xml index 8ff2316dec..a3f2717451 100644 --- a/addons/hitreactions/stringtable.xml +++ b/addons/hitreactions/stringtable.xml @@ -6,7 +6,7 @@ Danno Minimo per far cadere 觸發倒下前最低需受到多少傷害 触发倒下前最低需受到多少伤害 - 崩れ落ちるまでの最低損傷値 + 転倒が発生するダメージの最低値 넘어질 때 발생하는 최소 피해량 Mindestschaden, um Sturz auszulösen Minimalne obrażenie, żeby aktywować spadanie @@ -19,9 +19,11 @@ Player Weapon Drop Chance (Arm Hit) + プレイヤーが武器を落とす確率 (腕部への被弾) AI Weapon Drop Chance (Arm Hit) + AIが武器を落とす確率 (腕部への被弾) diff --git a/addons/medical_treatment/stringtable.xml b/addons/medical_treatment/stringtable.xml index 477c18d019..a8bf4159a8 100644 --- a/addons/medical_treatment/stringtable.xml +++ b/addons/medical_treatment/stringtable.xml @@ -79,6 +79,7 @@ Enabled & Can Diagnose Death/Cardiac Arrest [Directly] + 有効 & 死亡/心停止状態を診断可能 [直接的に] Advanced Medication @@ -4158,6 +4159,7 @@ %1 is unconscious + %1 は意識がない %1 is not responsive, taking shallow gasps and convulsing @@ -4173,6 +4175,7 @@ %1 is in cardiac arrest + %1 は心停止している %1 is not responsive, motionless and cold @@ -4188,6 +4191,7 @@ %1 is dead + %1 は死亡している You checked %1 diff --git a/addons/realisticnames/stringtable.xml b/addons/realisticnames/stringtable.xml index 47c5f27c68..f01104ebab 100644 --- a/addons/realisticnames/stringtable.xml +++ b/addons/realisticnames/stringtable.xml @@ -46,7 +46,7 @@ XM312 (Alta) XM312 (Magasított) XM312 (Alto) - XM312 (高) + XM312 (ハイマウント) XM312 (높음) XM312重機槍 (高射腳架) XM312(高) @@ -97,7 +97,7 @@ XM307 (Alta) XM307 (Magasított) XM307 (Alto) - XM307 (高) + XM307 (ハイマウント) XM307 (높음) XM307榴彈機槍 (高射腳架) XM307(高) @@ -556,7 +556,7 @@ Leopard 2SG Leopard 2SG Leopard 2SG - レオパルト 2SG + レオパルト2SG 레오파르트 2SG "豹2型新加坡版"主戰坦克 "豹"2 新加坡版 @@ -701,6 +701,7 @@ KamAZ Water KamAZ Água + KamAZ 給水 KamAZ MRL @@ -1662,10 +1663,12 @@ CZ 581 CZ 581 + CZ 581 CZ 581 (Sawed-Off) CZ 581 (Cano serrado) + CZ 581 (ソードオフ) FNX-45 Tactical (Green) @@ -2333,7 +2336,7 @@ Scorpion Evo 3 A1 Scorpion Evo 3 A1 Scorpion Evo 3 A1 - スコーピオン エボ 3 A1 + スコーピオン Evo 3 A1 스콜피온 에보 3 A1 "蠍式"Evo 3 A1衝鋒槍 Evo 3 A1 "蝎" @@ -2384,7 +2387,7 @@ Stoner 99 LMG Stoner 99 LMG Stoner 99 LMG - ストーナー 99 LMG + ストーナー99 LMG 스토너 99 LMG 斯通納99輕機槍 斯通纳 99 @@ -3071,14 +3074,17 @@ Type 115 (Black) Type 115 (Preto) + Type 115 (ブラック) Type 115 (Green Hex) Type 115 (Verde Hex) + Type 115 (緑六角形迷彩) Type 115 (Hex) Type 115 (Hex) + Type 115 (六角形迷彩) QBZ-95-1 (Black) @@ -3675,7 +3681,7 @@ Polaris DAGOR (light) Polaris DAGOR (leicht) - ポラリス DAGOR (軽) + ポラリス DAGOR (軽装) "北極星"先進佈署越野車 (輕型) "北极星"(轻型) Polaris DAGOR (leggero) @@ -3867,14 +3873,17 @@ UTG Defender 126 UTG Defender 126 + UTG ディフェンダー 126 EOTech MRDS EOTech MRDS + EOTech MRDS EOTech MRDS (Black) EOTech MRDS (Preto) + EOTech MRDS (ブラック) Leupold Mark 4 HAMR @@ -4308,7 +4317,7 @@ KAHLES Helia (Tan) KAHLES Helia (Tan) KAHLES Helia(沙色) - KAHLES Helia (タン) + KAHLES ヘリア (タン) KAHLES Helia (Tan) KAHLES Helia (Marroncino) KAHLES Helia (пустынный) diff --git a/addons/zeus/stringtable.xml b/addons/zeus/stringtable.xml index a1ae4d554e..aaa9fdd8c4 100644 --- a/addons/zeus/stringtable.xml +++ b/addons/zeus/stringtable.xml @@ -1500,7 +1500,7 @@ Fill from top to bottom Von oben nach unten befüllen Remplir de haut en bas - 上から下まで占拠 + 上から下へと占拠 Riempi dall'alto al basso 由上而下進行填滿 由上而下进行填满 @@ -2005,30 +2005,37 @@ +MAJ pour forcer (Disponible uniquement sur les alignements N/S ou E/O) +SHIFT zum Erzwingen (Kann nur nach N/S oder E/W legen) +SHIFT per forzare (Può piazzare solo N/S o E/O - +SHIFTキー で強制的に敷設 (北/南または東/西方向にのみ配置可能) + =+SHIFTキー で強制的に敷設 (北/南または東/西方向にのみ配置可能) +SHIFT на принудительное (может укладываться только на Север/Юг или Восток/Запад) +SHIFT para forzar (Puede solo colocar en N/S or E/O) Forces the spectator interface preventing the player from closing it with the Escape key + 観戦インターフェイスを強制し、ユーザーがEscキーでも閉じられないようにします。 Hide player + プレイヤーを隠す Hides the player by making them invisible, invulnerable, muted, and removing them from their group + 透明化、無敵化、ミュート、グループからの除外を行いプレーヤーを隠します Sets the sides that are available to spectate + 指定の陣営を観戦可能に設定します White Hot + 白=熱源 Black Hot + 黒=熱源 Toggle All + 全てを切り替え From d66c3904d03ab5086c31e88d7fd41428b5800d6a Mon Sep 17 00:00:00 2001 From: Nilia119 <88453817+Nilia119@users.noreply.github.com> Date: Mon, 10 Jun 2024 01:21:36 +0200 Subject: [PATCH 082/290] Translation - Add Missing German (#9975) * Added Missing German Translation * Improved German Translation * Update Medical_treatment * Update Medical_treatment stringtable.xml * Update addons/common/stringtable.xml Co-authored-by: BaerMitUmlaut * Update stringtable.xml * Update stringtable.xml * Update stringtable.xml * Update stringtable.xml * Update addons/arsenal/stringtable.xml --------- Co-authored-by: BaerMitUmlaut Co-authored-by: Mike-MF --- addons/arsenal/stringtable.xml | 2 ++ addons/cargo/stringtable.xml | 5 +++++ addons/common/stringtable.xml | 3 +++ .../compat_cup_weapons_csw/stringtable.xml | 17 +++++++++++++++++ .../stringtable.xml | 2 ++ addons/fieldmanual/stringtable.xml | 4 ++++ addons/hearing/stringtable.xml | 2 ++ addons/killtracker/stringtable.xml | 5 ++++- addons/maptools/stringtable.xml | 18 ++++++++++++++++++ addons/medical_treatment/stringtable.xml | 4 ++++ addons/medical_vitals/stringtable.xml | 3 +++ addons/overheating/stringtable.xml | 6 ++++++ 12 files changed, 70 insertions(+), 1 deletion(-) diff --git a/addons/arsenal/stringtable.xml b/addons/arsenal/stringtable.xml index 25ce1f75ae..cf858ec24d 100644 --- a/addons/arsenal/stringtable.xml +++ b/addons/arsenal/stringtable.xml @@ -1245,6 +1245,7 @@ Интегрирован тепловизор. 열화상 내장 Thermique intégrée + Thermal integriert Térmica integrada @@ -1254,6 +1255,7 @@ Интегрирован тепловизор и осн.прицел. 열화상과 주무기 내장 Thermique et primaire intégrés + Thermal und in Primärwaffe integriert Térmica y Primaria integrada diff --git a/addons/cargo/stringtable.xml b/addons/cargo/stringtable.xml index e74fd742c2..4e8d707f61 100644 --- a/addons/cargo/stringtable.xml +++ b/addons/cargo/stringtable.xml @@ -40,6 +40,7 @@ 配置する 배치하기 Déployer + Aufstellen Desplegar @@ -288,6 +289,7 @@ Загружаем %1 в %2... %1을(를) %2에 싣는 중... Chargement %1 dans %2... + %1 wird in %2 geladen... Unloading %1 from %2... @@ -297,6 +299,7 @@ Выгружаем %1 из %2... %1을(를) %2(으)로부터 내리는 중... Déchargement %1 de %2... + %1 wird von %2 entladen... %1<br/>could not be loaded @@ -587,6 +590,7 @@ 配置機能を有効化 배치 활성화 Permettre le placement + Aktiviere Aufbauen Habilitar despliegue @@ -596,6 +600,7 @@ 配置機能を介して貨物アイテムを降ろすことが出来るかどうかを制御します。 배치 방법을 통해 화물 아이템을 내릴 수 있는지 여부를 제어합니다. Contrôler si les éléments de cargaison peuvent être déchargés via la méthode de déploiement. + Steuert, ob Frachtgegenstände über die Aufbaumethode entladen werden können. Controla si los objetos de la carga pueden ser descargados mediante el método de despliegue. diff --git a/addons/common/stringtable.xml b/addons/common/stringtable.xml index f49e2cedde..96ad037cc1 100644 --- a/addons/common/stringtable.xml +++ b/addons/common/stringtable.xml @@ -1834,6 +1834,7 @@ 무기 흔들림 Oscillation de l'arme Колебание оружия + Waffen schwanken Oscilación del arma Oscillazione arma @@ -1843,6 +1844,7 @@ 무기 흔들림 추가 Activer l'oscillation de l'arme Включить колебание оружия + Aktiviere Waffen schwanken Habilitar oscilación del arma Abilita oscillazione arma @@ -1852,6 +1854,7 @@ 흔들림 계수, 자세, 피로도, 건강 상태 등의 요인에 영향을 받는 무기 흔들림을 활성화합니다.\n이 설정을 비활성화하면 바닐라 또는 다른 모드의 흔들림으로 대체됩니다. Active l'oscillation de l'arme influencé par les facteurs d'oscillation, tels que la position, la fatigue et l'état de santé.\nLa désactivation de ce paramètre reportera l'oscillation à vanilla ou à d'autres mods. Активируйте колебание оружия в зависимости от таких факторов, как стойка, усталость и состояние здоровья.\nОтключение этого параметра приведет к переносу раскачивания на vanilla или другие моды. + Ermöglicht die Beeinflussung des Waffen-Schwankens durch Beeinflussungsfaktoren wie Haltung, Müdigkeit und Gesundheitszustand.\nDie Deaktivierung dieser Einstellung erlaubt die Beeinflussung durch Vanilla oder andere Mods. Habilita la oscilación del arma afectado por factores como la postura, la fatiga y la condición médica.\nDeshabilitar esta opción hará que el comportamiento de la oscilación venga definido por Vanilla o por otros mods. Abilita l'oscillazione ACE, influenzata da fattori come postura, fatica e condizione medica.\nDisabilitare questa impostazione farà controllare l'oscillazione al gioco vanilla o altre mod. diff --git a/addons/compat_cup_weapons/compat_cup_weapons_csw/stringtable.xml b/addons/compat_cup_weapons/compat_cup_weapons_csw/stringtable.xml index 4ce86a2606..112c335638 100644 --- a/addons/compat_cup_weapons/compat_cup_weapons_csw/stringtable.xml +++ b/addons/compat_cup_weapons/compat_cup_weapons_csw/stringtable.xml @@ -6,6 +6,7 @@ [CSW] AGS30 ベルト [CSW] Лента AGS 30 [CSW] AGS-30 벨트 + [CSW] AGS30 Gurt [CSW] Cinta de AGS30 @@ -13,6 +14,7 @@ [CSW] Mk19 ベルト [CSW] Лента Mk19 [CSW] Mk.19 벨트 + [CSW] MK19 Gurt [CSW] Cinta de MK19 @@ -20,6 +22,7 @@ [CSW] TOW チューブ [CSW] Туба TOW [CSW] TOW 튜브 + [CSW] TOW Rohr [CSW] Tubo de TOW @@ -27,6 +30,7 @@ [CSW] TOW2 チューブ [CSW] Туба TOW-2 [CSW] TOW2 튜브 + [CSW] TOW2 Rohr [CSW] Tubo de TOW2 @@ -34,6 +38,7 @@ [CSW] PG-9 砲弾 [CSW] Снаряд ПГ-9 [CSW] PG-9 대전차고폭탄 + [CSW] PG-9 Rakete [CSW] Carga de PG-9 @@ -41,6 +46,7 @@ [CSW] OG-9 砲弾 [CSW] Снаряд OГ-9 [CSW] OG-9 고폭파편탄 + [CSW] OG-9 Rakete [CSW] Carga de OG-9 @@ -49,6 +55,7 @@ [CSW] M1 HE [CSW] M1 고폭탄 [CSW] M1 HE + [CSW] M1 HE [CSW] HE de M1 @@ -57,6 +64,7 @@ [CSW] M84 Дымовая [CSW] M84 연막탄 [CSW] M84 Fumigène + [CSW] M84 Rauch [CSW] Humo M84 @@ -65,6 +73,7 @@ [CSW] M60A2 WP [CSW] M60A2 백린연막탄 [CSW] M60A2 WP + [CSW] M60A2 WP [CSW] M60A2 WP @@ -73,6 +82,7 @@ [CSW] M67 AT Laser Guided [CSW] M67 레이저유도 대전차탄 [CSW] M67 AT Guidé laser + [CSW] M67 AT Lasergelenkt [CSW] AT Guiado por Láser M67 @@ -81,6 +91,7 @@ [CSW] M314 Осветительная [CSW] M314 조명탄 [CSW] M314 Illumination + [CSW] M314 Beleuchtung [CSW] Iluminación M314 @@ -89,6 +100,7 @@ [CSW] 3OF56 HE [CSW] 3OF56 고폭탄 [CSW] 3OF56 HE + [CSW] 3OF56 HE [CSW] HE de 3OF56 @@ -97,6 +109,7 @@ [CSW] 3OF69M Laser Guided [CSW] 3OF69M 레이저유도탄 [CSW] 3OF69M Guidé laser + [CSW] 3OF69M Lasergelenkt [CSW] 3OF69M Guiado por Láser @@ -105,6 +118,7 @@ [CSW] 122mm WP [CSW] 122mm 백린탄 [CSW] 122mm WP + [CSW] 122mm WP [CSW] WP de 122mm @@ -113,6 +127,7 @@ [CSW] D-462 Дымовая [CSW] D-462 연막탄 [CSW] D-462 Fumigène + [CSW] D-462 Rauch [CSW] Humo D-462 @@ -121,6 +136,7 @@ [CSW] S-463 Осветительная [CSW] S-463 조명탄 [CSW] S-463 Eclairante + [CSW] S-463 Beleuchtung [CSW] Iluminación S-463 @@ -129,6 +145,7 @@ [CSW] BK-6M HEAT [CSW] BK-6M 대전차고폭탄 [CSW] BK-6M HEAT + [CSW] BK-6M HEAT [CSW] BK-6M HEAT diff --git a/addons/compat_cup_weapons/compat_cup_weapons_nightvision/stringtable.xml b/addons/compat_cup_weapons/compat_cup_weapons_nightvision/stringtable.xml index e3166d6f42..e1afbe21c8 100644 --- a/addons/compat_cup_weapons/compat_cup_weapons_nightvision/stringtable.xml +++ b/addons/compat_cup_weapons/compat_cup_weapons_nightvision/stringtable.xml @@ -51,6 +51,7 @@ AN/PVS-15 (설상, 백색광) AN/PVS-15 (Белый, БФ) AN/PVS-15 (Blanc, WP) + AN/PVS-15 (Winter, WP) AN/PVS-15 (Blancas, WP) @@ -92,6 +93,7 @@ GPNVG (설상, 백색광) AN/PVS-15 (Белый, БФ) GPNVG (Blanc, WP) + GPNVG (Winter, WP) GPNVG (Blancas, WP) diff --git a/addons/fieldmanual/stringtable.xml b/addons/fieldmanual/stringtable.xml index 98756c4910..78b7ad6fe8 100644 --- a/addons/fieldmanual/stringtable.xml +++ b/addons/fieldmanual/stringtable.xml @@ -245,6 +245,7 @@ 傷口が開くのを防ぐ Предотвратить повторное открытие ран Empêcher la réouverture des plaies + Verhindert, dass sich Wunden wieder öffnen Prevenir la reapertura de heridas @@ -254,6 +255,7 @@ O %3Kit Cirúrgico%4 é utilizado para prevenir a reabertura de feridas após a aplicação de bandagens. A depender das configurações, ele também pode remover traumas e pode requerir %3Suturas%4 adicionais para fechar feridas. Suturas são consumíveis, tal como as bandagens, e não são substituem o Kit Cirúrgico.<br/><br/>%3Uso:%4<br/>%2Utilize [%3%13%4] ou [%3%14%4] e selecione %3Tratamento Avançado%4.<br/>%2Selecione %3Usar Kit Cirúrgico%4. Un %3Kit Chirurgico%4 è usato per impedire che ferite bendate si riaprano. A seconda delle impostazioni, può anche azzerare danni o potrebbe richiedere %3Suture%4 aggiuntive per chiudere ferite. Suture sono consumabili proprio come bende, non sono un sostituto per un Kit Chirurgico.<br/><br/>%3Utilizzo:%4<br/>%2Usa [%3%13%4] o [%3%14%4] e seleziona %3Trattamenti Avanzati%4.<br/>%2Seleziona %3Usa Kit Chirurgico%4. %3手術キット%4は包帯を巻いた傷口が再度開いて出血するのを防ぎます。設定によっては、負傷を取り除いたり、傷口を閉じるのに%3糸付縫合針%4を必要としたりします。糸付縫合針は消耗品で包帯のように使用され、手術キットを代替するものではありません。<br/><br/>%3使用方法:%4<br/>%2[%3%13%4] または [%3%14%4] を使って%3高度な治療%4を選択する。<br/>%2%3手術キット%4を選択して使用します。 + Ein %3Chirurgisches Kit%4 wird verwendet, um zu verhindern, dass sich Wunden nach dem Verbinden wieder öffnen. Abhängig von den Einstellungen kann es auch Traumata beseitigen und erfordert möglicherweise zusätzliche %3Nähte%4, um Wunden zu schließen. Nahtmaterial ist, ähnlich wie Bandagen, Verbrauchsmaterial und kein Ersatz für das Chirurgie-Set.<br/><br/>%3Verwendung:%4<br/>%2Verwenden Sie [%3%13%4] oder [%3% 14%4] und wählen Sie %3Erweiterte Behandlung%4.<br/>%2Wählen Sie %3Chirurgisches Kit verwenden%4. El %3Kit Quirúrgico%4 se usa para prevenir la reapertura de heridas despues de ser vendadas. Dependiendo de las opciones, tambien puede curar traumatismos y puede requerir %3Sutura%4 adicional para cerrar las heridas. Las Suturas son consumibles, al igual que las vendas, y no son un reemplazo para el Kit Quirúgico.<br/><br/>%3Uso:%4<br/>%2Usar [%3%13%4] o [%3%14%4] y seleccionar %3Tratamientos Avanzados%4.<br/>%2Seleccionar %3Usar Kit Quirúgico%4. @@ -265,6 +267,7 @@ 出血を止める Остановить кровотечение Arrêter les saignements + Stoppt Blutung Parar Sangrado @@ -274,6 +277,7 @@ O %3Torniquete%4 interrompe o sangramento temporariamente, para que feridas possam ser enfaixadas. Seu uso é restrito aos membros.<br/><br/>%3Uso:%4<br/>%2Utilize [%3%13%4] ou [%3%14%4] e selecione um membro afetado.<br/>%2Selecione %3Aplicar Torniquete%4. Un %3Laccio Emostatico%4 ferma emorragie temporaneamente in modo da poter bendare ferite con calma. Utilizzabile su arti.<br/><br/>%3Utilizzo:%4<br/>%2Usa [%3%13%4] o [%3%14%4] e seleziona un arto afflitto.<br/>%2Seleziona %3Applica Laccio Emostatico%4. %3止血帯%4は一時的に出血を止め、その間に傷に包帯を巻くことができます。四肢にのみ使用できます。<br/><br/>%3使用方法:%4<br/>%2[%3%13%4] または [%3%14%4] を使って使用したい四肢を選択します。<br/>%2%3止血帯を巻く%4を選択して使用します。 + Ein %3Tourniquet%4 stoppt die Blutung vorübergehend, sodass eine oder mehrere Wunden verbunden werden können. Kann nur an Gliedmaßen verwendet werden.<br/><br/>%3Verwendung:%4<br/>%2Verwenden Sie [%3%13%4] oder [%3%14%4] und wählen Sie ein betroffenes Glied aus.< br/>%2Wählen Sie %3Tourniquet anwenden%4. El %3Torniquete%4 para temporalmente el sangrado hasta que la herida sea vendada. Sólo puede ser usado en extremidades.<br/><br/>%3Uso:%4<br/>%2Usar [%3%13%4] o [%3%14%4] y seleccionar la extremidad afectada.<br/>%2Seleccionar %3Aplicar Torniquete%4. diff --git a/addons/hearing/stringtable.xml b/addons/hearing/stringtable.xml index ff912a75d1..5b7c3da063 100644 --- a/addons/hearing/stringtable.xml +++ b/addons/hearing/stringtable.xml @@ -370,12 +370,14 @@ Metti/Togli tappi 귀마개 토글 Mettre/enlever les bouchons + Ohrstöpsel einsetzen/herausnehmen Poner/quitar tapones Only units with heavy weapons Uniquement les unités dotées d'armes lourdes Только юниты с тяжелым вооружением + Nur Einheiten mit schweren Waffen 重火器を装備したユニットのみ Sólo unidades con armas pesadas Solo a unità con armi pesanti diff --git a/addons/killtracker/stringtable.xml b/addons/killtracker/stringtable.xml index 63196a442e..5b2f8f9de8 100644 --- a/addons/killtracker/stringtable.xml +++ b/addons/killtracker/stringtable.xml @@ -9,12 +9,13 @@ ACE キルトラッカー ACE 킬트래커 ACE Suivi des morts + ACE Abschüsse ACE Contador de Muertes ACE Killed Events ACE キルイベント - ACE Abgeschossene Ereignisse + ACE Abschusszähler ACE Eventi di Morte ACE Licznik Zabójstw ACE 击杀事件 @@ -104,6 +105,7 @@ プレイヤーに殺害されたAIユニットを追跡 플레이어가 죽인 AI 트래킹 Suivi de l'IA tuée par les joueurs + Zähle vom Spieler getöteten KI-Einheiten Cuenta las unidades de IA matadas por el jugador @@ -114,6 +116,7 @@ ミッションデブリーフィングのキルトラッカーに殺害されたAIが表示されるかどうかを定義します。 사후강평 중 살해된 AI가 킬트래킹에 표시되는지 여부를 정의합니다. Définit si les IA tuées seront affichées dans le tracker pendant le débriefing de la mission. + Legt fest, ob getötete KIs während des Endbildschirms der Mission in den Abschüssen angezeigt werden. Define si las IAs matadas se mostrarán en el contador de muertes en el debiefring de la misión. diff --git a/addons/maptools/stringtable.xml b/addons/maptools/stringtable.xml index f71cc8489f..7e1d0cee97 100644 --- a/addons/maptools/stringtable.xml +++ b/addons/maptools/stringtable.xml @@ -42,6 +42,7 @@ Tavola di calcolo Графическая доска Planche traçante + Wurfparabel Kartenwerkzeug Tablero de Trazado @@ -51,6 +52,7 @@ La tavola di calcolo è uno strumento utilizzato per dirigere fuoco di artiglieria a corto raggio. Графическая доска - это картографический инструмент, предназначенный для использования при ведении непрямого огня с малой дистанции. Une planche traçante est un outil cartographique conçu pour diriger des tirs indirects à courte distance. + Das Wurfparabel-Kartenwerkzeug ist ein Werkzeug, das für die Steuerung indirekten Feuers auf kurze Distanz entwickelt wurde. El Tablero de Trazado es una herramienta de mapa utilizada para dirigir fuego indirecto de corto alcance. @@ -277,6 +279,7 @@ Canali ammessi su tavola di calcolo Разрешить создание каналов на миллиметровой доске. Canaux autorisés sur la planche traçante + Wurfparabel Kartenwerkzeug erlaubte Kanäle Permitir Canales de Dibujado de Tablero de Trazado @@ -286,6 +289,7 @@ Canali in cui si può disegnare sulla tavola di calcolo. Каналы, в которых включено рисование на миллиметровой доске. Canaux dans lesquels vous pouvez dessiner sur le planche traçante + Kanäle, in denen das Zeichnen mit dem Wurfparabel-Kartenwerkzeug auf der Karte erlaubt ist. Canales en los que el tablero de trazado está habilitado. @@ -295,6 +299,7 @@ Comunicazioni Dirette (solo linee) Разрешать только прямую связь (только полилинии) Communications directes uniquement (lignes uniquement) + Nur direkte Kommunikation zulassen (nur Polylinien) Permitir Sólo Comunicaciones Directas (Sólo Polylineas) @@ -304,6 +309,7 @@ Comunicazioni dirette/gruppo (linee e marker) Разрешить прямую/групповую связь (полилинии и групповые маркеры) Autoriser les communications directes/de groupe (polylignes et marqueurs de groupe) + Direkte/Gruppenkommunikation zulassen (Polylinien und Gruppenmarkierungen) Permitir Comunicaciones Directas/Grupales (Polylineas y Marcadores de Grupo) @@ -313,6 +319,7 @@ Tavola di calcolo Миллиметровая доска Planche traçante + Wurfparabel Kartenwerkzeug Tablero de Trazado @@ -322,6 +329,7 @@ Acrilico tavola di calcolo Миллиметровая доска акрилловая Planche traçante Acrylique + Wurfparabel Kartenwerkzeug Acryl Tablero de Trazado Acrílico @@ -331,6 +339,7 @@ Righello tavola di calcolo Линейка для миллиметровой доски Règle de la planche traçante + Wurfparabel Kartenwerkzeug Lineal Regla de Tablero de Trazado @@ -340,6 +349,7 @@ Su tavola di calcolo К миллиметровой доске. Sur la planche traçante + Zum Wurfparabel Kartenwerkzeug A Tablero de Trazado @@ -349,6 +359,7 @@ Su acrilico tavola di calcolo К миллиметровой доске акрилловой Sur la planche traçante Acrylique + Zum Wurfparabel Kartenwerkzeug Acryl A Tablero de Trazado Acrílico @@ -358,6 +369,7 @@ Su righello tavola di calcolo К линейке миллиметровой доски. Sur la règle de la planche traçante + Zum Wurfparabel Kartenwerkzeug Lineal A Regla de Tablero de Trazado @@ -367,6 +379,7 @@ Cancella tutti i disegni dalla tavola Сотрите все маркеры с миллиметровой доски. Effacer tous les dessins de la planche traçante + Alle Markierungen vom Wurfparabel Kartenwerkzeug entfernen Borrar todas las marcas del Tablero de Trazado @@ -376,6 +389,7 @@ Mostra tavola di calcolo Показать миллиметровую доску. Afficher la planche traçante + Zeige Wurfparabel Kartenwerkzeug Mostrar Tablero de Trazado @@ -385,6 +399,7 @@ Nascondi tavola di calcolo Скрыть миллиметровую доску. Masquer la planche traçante + Verstecke Wurfparabel Kartenwerkzeug Ocultar Tablero de Trazado @@ -394,6 +409,7 @@ Mostra/Nascondi Righello Переключить линейку миллиметровой доски. Afficher/masquer la règle + Schalte das Lineal des Wurfparabel-Kartenwerkzeuges um Alternar Regla de Tablero de Trazado @@ -445,6 +461,7 @@ Su Вверх Monter + Nach oben Arriba @@ -454,6 +471,7 @@ Su strumento cartografico К инструментам карты Outil cartographique + Zum Kartenwerkzeug A Herramienta de Mapa diff --git a/addons/medical_treatment/stringtable.xml b/addons/medical_treatment/stringtable.xml index a8bf4159a8..6e093e8c5f 100644 --- a/addons/medical_treatment/stringtable.xml +++ b/addons/medical_treatment/stringtable.xml @@ -5044,6 +5044,7 @@ 鎮痛剤を投与 진통제 투여 Administrer des analgésiques + Verabreiche Schmerztabletten Administrar Analgésicos @@ -5053,6 +5054,7 @@ 鎮痛剤を投与しています・・・ 진통제 투여 중... Administration d'analgésiques... + Verabreiche Schmerztablette... Administrando Analgésicos... @@ -5062,6 +5064,7 @@ 軽度から中程度の痛みに対処するために使用される市販の鎮痛薬。 가벼운 통증부터 중간 정도의 통증을 퇴치하는 데 사용되는 일반의약품 진통제입니다. Analgésique sans ordonnance utilisé pour lutter contre les douleurs légères à modérées. + Rezeptfreies Analgetikum zur Bekämpfung leichter bis mittelschwerer Schmerzen. Analgésico sin receta médica usado para aplacar dolores de ligeros a moderados. @@ -5071,6 +5074,7 @@ 軽度から中程度の痛みに対処するために使用される市販の鎮痛薬。 가벼운 통증부터 중간 정도의 통증을 퇴치하는 데 사용되는 일반의약품 진통제입니다. Analgésique sans ordonnance utilisé pour lutter contre les douleurs légères à modérées. + Rezeptfreies Analgetikum zur Bekämpfung leichter bis mittelschwerer Schmerzen. Analgésico sin receta médica usado para aplacar dolores de ligeros a moderados. diff --git a/addons/medical_vitals/stringtable.xml b/addons/medical_vitals/stringtable.xml index 54c19f53fa..2fe7336dc0 100644 --- a/addons/medical_vitals/stringtable.xml +++ b/addons/medical_vitals/stringtable.xml @@ -9,6 +9,7 @@ バイタル 생명 Paramètres vitaux + Vitalwerte Vitales @@ -18,6 +19,7 @@ SpO2シミュレーションを有効化 산소포화도 시뮬레이션 활성화 Activer la simulation de la SpO2 + SpO2-Simulation aktivieren Habilitar Simulación SpO2 @@ -27,6 +29,7 @@ 酸素飽和度シミュレーションを有効にし、身体活動や標高に基づいて変動する心拍数と酸素要求量の機能を提供します。 気道管理に必要です。 산소포화도 시뮬레이션을 활성화하여 신체 활동과 고도에 따라 다양한 심박수와 산소 요구량을 제공합니다. 기도 관리에 필요합니다. Permet de simuler la saturation en oxygène, de modifier la fréquence cardiaque et la consommation d'oxygène en fonction de l'activité physique et de l'altitude. Nécessaire pour la gestion des voies respiratoires. + Aktiviert die Simulation der Sauerstoffsättigung und bietet variable Herzfrequenz und Sauerstoffbedarf basierend auf körperlicher Aktivität und Geländehöhe. Erforderlich für das Atemwegsmanagement. Habilita la saturación de oxígeno, utilizando la demanda de oxígeno y ritmo cardíaco basado en la actividad física y la altitud. Requerido para el Manejo de las Vías Aéreas. diff --git a/addons/overheating/stringtable.xml b/addons/overheating/stringtable.xml index 8676ff67bb..ef20ae9e81 100644 --- a/addons/overheating/stringtable.xml +++ b/addons/overheating/stringtable.xml @@ -882,6 +882,7 @@ 노리쇠 방식 Тип болта Type d'obturateur + Art des Verschlusses Tipo de Cerrojo @@ -891,6 +892,7 @@ 오픈 볼트 Открыть болт Obturateur ouvert + Offener Verschluss Cerrojo Abierto @@ -900,6 +902,7 @@ 클로즈드 볼트 Закрыть болт Obturateur fermé + Geschlossener Verschluss Cerrojo Cerrado @@ -909,6 +912,7 @@ 총열 방식 Тип ствола Type de canon + Lauftyp Tipo de Cañón @@ -918,6 +922,7 @@ 제거 불가 Несъемный Inamovible + Nicht entfernbar No-Desmontable @@ -927,6 +932,7 @@ 신속 교체 Быстросъемный Changement rapide + Schnellwechsel Cambiado Rápido From 41d6cae93b94bb3f12b07f492021f3114777c20c Mon Sep 17 00:00:00 2001 From: V1nsyara Date: Tue, 11 Jun 2024 05:28:30 +0300 Subject: [PATCH 083/290] Translation - Update Russian for new features (#10060) --- addons/cookoff/stringtable.xml | 14 +++++++++++++- addons/grenades/stringtable.xml | 1 + addons/hitreactions/stringtable.xml | 2 ++ addons/medical_treatment/stringtable.xml | 3 +++ addons/realisticnames/stringtable.xml | 9 +++++++++ addons/zeus/stringtable.xml | 7 +++++++ 6 files changed, 35 insertions(+), 1 deletion(-) diff --git a/addons/cookoff/stringtable.xml b/addons/cookoff/stringtable.xml index 504dc797ac..205b8d2b4d 100644 --- a/addons/cookoff/stringtable.xml +++ b/addons/cookoff/stringtable.xml @@ -19,26 +19,32 @@ Enable vehicle cook-off fire 車両の誘爆火災を有効化 + Вкл. возгорание техники Enables vehicle cook-off fire effects.\nThis doesn't include ammunition detonations. 車両の誘爆火災エフェクトを有効化します。\nこれには弾薬の爆発は含まれません。 + Вкл. эффект горения техники. \nНе включает детонацию боекомплекта Vehicle cook-off fire duration multiplier 車両の誘爆火災の持続時間倍率 + Увел. продолжительности горения техники Multiplier for how long vehicle cook-off fire lasts.\nSetting to 0 will disable vehicle cook-off fire. 車両の誘爆火災の持続時間をどのくらいの長さにするかの倍率。\n0に設定すると車両の誘爆火災が無効化されます。 + Увел. продолжительности горения техники. \nУстановка значения на 0 выключает возгорание техники. Vehicle cook-off fire probability multiplier 車両の誘爆火災の可能性倍率 + Возможность усиления пожара при детонации техники Multiplier for vehicle cook-off fire probability. Higher value results in higher cook-off probability.\nSetting to 0 will disable vehicle cook-off fire. 車両の誘爆火災がどのくらいの可能性で発生するかの倍率。高い数値は高い誘爆の可能性につながります。\n0に設定すると車両の誘爆火災が無効化されます。 + Увел. вероятности возникновения возгорания техники. Большое значение указывает на высокую вероятность детонации. \nУстановка значения 0 предотвращает возгорание техники. Destroy vehicles after cook-off @@ -68,10 +74,12 @@ Enable vehicle ammo cook-off 車両弾薬の誘爆を有効化 + Вкл. детонацию боеприпасов в технике. Enables cooking off of vehicle ammunition. Fires ammunition projectiles while vehicle has ammunition remaining.\nThis doesn't include fire effects. 車両弾薬の誘爆を有効化します。車両に積載されたままの弾薬と弾頭が発射されます。\nこれには火災エフェクトは含まれません。 + Вкл. детонацию боеприпасов на технике. Боеприпасы и боеголовки, которые остаются заряженными на транспортном средстве, будут приведены в действие. \nЭто не включает эффекты пожара. Enable ammo box cook-off @@ -91,14 +99,17 @@ Enables cooking off of ammo boxes.\nThis doesn't include fire effects. 弾薬箱の誘爆を有効化します。\nこれには火災エフェクトは含まれません。 + Вкл. детонацию ящика с боеприпасами. \nЭто не включает эффекты огня. Ammo cook-off duration multiplier 弾薬の誘爆の持続時間倍率 + Увеличение продолжительности детонации боеприпасов. Multiplier for how long ammunition cook-off lasts, for both vehicles and ammo boxes.\nSetting to 0 will disable ammo cook-off for both vehicles and ammo boxes. 弾薬の誘爆の持続時間をどのくらいの長さにするかの倍率。車両弾薬と弾薬箱どちらにも影響します。\n0に設定すると弾薬の誘爆が無効化されます。 + Увеличение продолжительности детонации боеприпасов. Это влияет как на боеприпасы в технике, так и на ящики с боеприпасами. \nУстановка значения 0 отключает детонацию боеприпасов. Enable ammo removal during cook-off @@ -109,7 +120,7 @@ Włącz/Wyłącz usuwanie amunicji podczas samozapłonu 启用/禁用殉爆过程中的弹药移除功能 쿡오프시 탄약 제거 활성화/비활성화 - Удалять боеприпасы из-за детонации + Вкл. удаление боеприпасов из-за детонации Habilita/Deshabilita ka eliminación de munición durante la detonación inducida por calor @@ -117,6 +128,7 @@ Retire des munitions des véhicules durant une auto-inflammation. Entfernt Munition während dem Durchzünden der Munition eines Fahrzeuges. 誘爆によって全ての弾薬を除去します。 + Все боеприпасы уничтожаются путем подрыва. diff --git a/addons/grenades/stringtable.xml b/addons/grenades/stringtable.xml index eab327d8cf..1a571093f8 100644 --- a/addons/grenades/stringtable.xml +++ b/addons/grenades/stringtable.xml @@ -106,6 +106,7 @@ Can't roll this grenade, switched to %1 この手榴弾は転がせません、 %1 に切り替えます + Эта граната не может быть брошена, переключитесь на %1 M84 Stun Grenade diff --git a/addons/hitreactions/stringtable.xml b/addons/hitreactions/stringtable.xml index a3f2717451..421f806e32 100644 --- a/addons/hitreactions/stringtable.xml +++ b/addons/hitreactions/stringtable.xml @@ -20,10 +20,12 @@ Player Weapon Drop Chance (Arm Hit) プレイヤーが武器を落とす確率 (腕部への被弾) + Шанс выпадения оружия у игрока (попадание в руку) AI Weapon Drop Chance (Arm Hit) AIが武器を落とす確率 (腕部への被弾) + Шанс выпадения оружия у ИИ (попадание в руку) diff --git a/addons/medical_treatment/stringtable.xml b/addons/medical_treatment/stringtable.xml index 6e093e8c5f..8b8cc640eb 100644 --- a/addons/medical_treatment/stringtable.xml +++ b/addons/medical_treatment/stringtable.xml @@ -4160,6 +4160,7 @@ %1 is unconscious %1 は意識がない + %1 находится без сознания %1 is not responsive, taking shallow gasps and convulsing @@ -4176,6 +4177,7 @@ %1 is in cardiac arrest %1 は心停止している + У %1 произошла остановка сердца %1 is not responsive, motionless and cold @@ -4192,6 +4194,7 @@ %1 is dead %1 は死亡している + %1 мертв You checked %1 diff --git a/addons/realisticnames/stringtable.xml b/addons/realisticnames/stringtable.xml index f01104ebab..833c83db94 100644 --- a/addons/realisticnames/stringtable.xml +++ b/addons/realisticnames/stringtable.xml @@ -702,6 +702,7 @@ KamAZ Water KamAZ Água KamAZ 給水 + КамАЗ (водоноситель) KamAZ MRL @@ -1664,11 +1665,13 @@ CZ 581 CZ 581 CZ 581 + CZ 581 CZ 581 (Sawed-Off) CZ 581 (Cano serrado) CZ 581 (ソードオフ) + CZ 581 (Sawed-Off) FNX-45 Tactical (Green) @@ -3075,16 +3078,19 @@ Type 115 (Black) Type 115 (Preto) Type 115 (ブラック) + Type 115 (чёрный) Type 115 (Green Hex) Type 115 (Verde Hex) Type 115 (緑六角形迷彩) + Type 115 (зелёный гекс) Type 115 (Hex) Type 115 (Hex) Type 115 (六角形迷彩) + Type 115 (гекс) QBZ-95-1 (Black) @@ -3874,16 +3880,19 @@ UTG Defender 126 UTG Defender 126 UTG ディフェンダー 126 + UTG Defender 126 EOTech MRDS EOTech MRDS EOTech MRDS + EOTech MRDS EOTech MRDS (Black) EOTech MRDS (Preto) EOTech MRDS (ブラック) + EOTech MRDS (чёрный) Leupold Mark 4 HAMR diff --git a/addons/zeus/stringtable.xml b/addons/zeus/stringtable.xml index aaa9fdd8c4..7e079869e3 100644 --- a/addons/zeus/stringtable.xml +++ b/addons/zeus/stringtable.xml @@ -2012,30 +2012,37 @@ Forces the spectator interface preventing the player from closing it with the Escape key 観戦インターフェイスを強制し、ユーザーがEscキーでも閉じられないようにします。 + Активирует интерфейс spectator, не позволяя игроку закрыть его с помощью клавиши Escape. Hide player プレイヤーを隠す + Скрыть игрока Hides the player by making them invisible, invulnerable, muted, and removing them from their group 透明化、無敵化、ミュート、グループからの除外を行いプレーヤーを隠します + Скрывает игрока, делая его невидимым, неуязвимым, отключая звук и удаляя из группы. Sets the sides that are available to spectate 指定の陣営を観戦可能に設定します + Устанавливает стороны, доступные для режима spectator White Hot 白=熱源 + Белый Black Hot 黒=熱源 + Чёрный Toggle All 全てを切り替え + Выключить все From c862c4761744fdef50c34d7e72d29eaaba3de6c3 Mon Sep 17 00:00:00 2001 From: Apricot <50947830+Apricot-ale@users.noreply.github.com> Date: Tue, 11 Jun 2024 11:29:28 +0900 Subject: [PATCH 084/290] Translations - Improve Japanese (Mortar and some) (#10061) Tweaks --- .../compat_rf_realisticnames/stringtable.xml | 12 ++++++------ addons/mk6mortar/stringtable.xml | 14 +++++++------- addons/zeus/stringtable.xml | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/addons/compat_rf/compat_rf_realisticnames/stringtable.xml b/addons/compat_rf/compat_rf_realisticnames/stringtable.xml index 994739faff..a31221294c 100644 --- a/addons/compat_rf/compat_rf_realisticnames/stringtable.xml +++ b/addons/compat_rf/compat_rf_realisticnames/stringtable.xml @@ -267,7 +267,7 @@ Drone40 Scout - ドローン40 偵察 + ドローン40 偵察型 Drone40 HE @@ -275,23 +275,23 @@ Drone40 Smoke (White) - ドローン40 発煙 (白) + ドローン40 発煙弾 (白) Drone40 Smoke (Blue) - ドローン40 発煙 (青) + ドローン40 発煙弾 (青) Drone40 Smoke (Red) - ドローン40 発煙 (赤) + ドローン40 発煙弾 (赤) Drone40 Smoke (Green) - ドローン40 発煙 (緑) + ドローン40 発煙弾 (緑) Drone40 Smoke (Orange) - ドローン40 発煙 (橙) + ドローン40 発煙弾 (橙) diff --git a/addons/mk6mortar/stringtable.xml b/addons/mk6mortar/stringtable.xml index a0d8612aa5..4195579998 100644 --- a/addons/mk6mortar/stringtable.xml +++ b/addons/mk6mortar/stringtable.xml @@ -163,7 +163,7 @@ A távmérő és számítógép megjelenítése (ezeket el KELL távolítani ha a légellenállás engedélyezve van) Показывает компьютер и дальномер (это НУЖНО отключить, если вы включаете сопротивление воздуха) Consenti l'utilizzo del Computer Balistico e del Telemetro (questi DEVONO essere disabilitati se vuoi abilitare la resistenza dell'aria) - 砲撃コンピュータと距離計を表示します (空気抵抗を仕様する場合は必ず無効化する必要があります) + 砲撃コンピュータと距離計を表示します (空気抵抗を有効化する場合はこれらを取り除く必要があります) 탄도계산컴퓨터와 거리측정기를 보여줍니다(공기저항을 활성화했을 경우 이 항목은 비활성화 되어야 합니다) 显示弹道计算机和测距仪(如果有启用空气阻力功能时,须停用此项功能) 顯示射控電腦和測距儀 (如果有啟用空氣阻力功能時,須停用此項功能) @@ -241,7 +241,7 @@ Rimuove i caricatori di colpi dal mortaio. Un operatore dovrà caricare proiettili singoli prima di poter fare fuoco. Non viene applicato su operatori IA. Elimina os carregadores do morteiro, requerendo que o atirador ou carregador utilize de forma individual a munição. Não afeta os morteiros controlados pela IA. Удаляет артиллерийские магазины, требует загрузку отдельных снарядов стрелком или заряжающим. Не влияет на артиллерию ИИ. - 迫撃砲から弾薬を除去します。射手か装填手により予め装填されている必要があります。AI迫撃砲へ影響を与えません。 + 迫撃砲から弾倉を除去します。一発ずつ射手か装填手によって装填される必要があります。AIの迫撃砲には影響を与えません。 박격포 탄창을 제거합니다, 사수나 장전수가 개별적으로 탄환을 넣어줘야 합니다. 인공지능은 영향을 받지 않습니다. 开启此功能时。迫击炮的弹药需由炮手与装填手共同合作来进行装填。此功能并不影响由 AI 射击的迫击炮 開啟此功能時。迫擊砲的彈藥需由砲手與裝填手共同合作來進行裝填。此功能並不影響由AI射擊的迫擊砲 @@ -257,7 +257,7 @@ Odstranit náboj Remover munição Извлечь снаряд - 弾薬を除去 + 砲弾を取り除く 탄약 제거 卸除弹头 卸除彈頭 @@ -273,7 +273,7 @@ Nabít minomet Carregar morteiro Зарядить миномет - 弾薬を装填 + 砲弾を装填 탄약 장전 装载弹头 裝載彈頭 @@ -288,7 +288,7 @@ Togliendo Proiettile Descarregar munição Извлечение снаряда - 弾薬を除去しています + 砲弾を取り除いています 탄약 제거 중 正在卸除弹头 卸除彈頭中 @@ -305,7 +305,7 @@ Připavuji náboj Preparar munição Подготовка снаряда - 砲弾を事前装填 + 砲弾を準備 탄약 준비 중 正在准备弹头 準備彈頭中 @@ -544,7 +544,7 @@ [ACE] Bedna se standardní 82mm municí [ACE] Caixa de Munição 82mm Padrão [ACE] Ящик снарядов 82мм (стандартный) - [ACE] 82mm 保管箱 + [ACE] 82mm 標準砲弾セット入り弾薬箱 [ACE] 82mm 기본 장비 상자 [ACE] 82 mm 预设弹药箱 [ACE] 82毫米預設彈藥箱 diff --git a/addons/zeus/stringtable.xml b/addons/zeus/stringtable.xml index 7e079869e3..e871ef85ef 100644 --- a/addons/zeus/stringtable.xml +++ b/addons/zeus/stringtable.xml @@ -2005,7 +2005,7 @@ +MAJ pour forcer (Disponible uniquement sur les alignements N/S ou E/O) +SHIFT zum Erzwingen (Kann nur nach N/S oder E/W legen) +SHIFT per forzare (Può piazzare solo N/S o E/O - =+SHIFTキー で強制的に敷設 (北/南または東/西方向にのみ配置可能) + +SHIFTキー で強制的に敷設 (北/南または東/西方向にのみ配置可能) +SHIFT на принудительное (может укладываться только на Север/Юг или Восток/Запад) +SHIFT para forzar (Puede solo colocar en N/S or E/O) From a85074a797a067646c273f4beb2bcaad3c06e5c2 Mon Sep 17 00:00:00 2001 From: Grim <69561145+LinkIsGrim@users.noreply.github.com> Date: Tue, 11 Jun 2024 11:11:28 -0300 Subject: [PATCH 085/290] Medical Engine - Remove ACE_HDBracket hitpoint (#9732) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Medical Engine - Remove ACE_HDBracket hitpoint * skip context 4 * move checks to vars * skip uav/logic entities * add check for arm/leg hitpoints * Update addons/medical_engine/functions/fnc_handleDamage.sqf Co-authored-by: Jouni Järvinen * don't skip context 2 * clearer custom hitpoint array name * reenable compile cache * remove debug mode * lazy eval * whitespace * update comment * Update fnc_handleDamage.sqf header * Update addons/medical_engine/functions/fnc_handleDamage.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * Update addons/medical_engine/XEH_postInit.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * update hitpoint test * missing " * Update addons/medical/dev/test_hitpointConfigs.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --------- Co-authored-by: Jouni Järvinen Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- addons/medical/dev/test_hitpointConfigs.sqf | 21 +++---- addons/medical_engine/XEH_postInit.sqf | 28 ++++----- addons/medical_engine/XEH_preInit.sqf | 2 + .../functions/fnc_handleDamage.sqf | 58 +++++++++---------- .../medical_engine/script_macros_config.hpp | 11 ---- 5 files changed, 49 insertions(+), 71 deletions(-) diff --git a/addons/medical/dev/test_hitpointConfigs.sqf b/addons/medical/dev/test_hitpointConfigs.sqf index 9de5c5e686..7bdeb189c2 100644 --- a/addons/medical/dev/test_hitpointConfigs.sqf +++ b/addons/medical/dev/test_hitpointConfigs.sqf @@ -21,23 +21,16 @@ INFO_1("Checking uniforms for correct medical hitpoints [%1 units]",count _units private _testPass = true; { private _typeOf = configName _x; - private _hitpoints = (configProperties [_x >> "HitPoints", "isClass _x", true]) apply {configName _x}; + private _hitpoints = (configProperties [_x >> "HitPoints", "isClass _x", true]) apply {toLowerANSI configName _x}; + private _expectedHitPoints = ["hitleftarm","hitrightarm","hitleftleg","hitrightleg","hithead","hitbody"]; + private _missingHitPoints = _expectedHitPoints select {!(_x in _hitpoints)}; + if (_missingHitPoints isNotEqualTo []) then { + WARNING_3("%1 missing ace hitpoints: %2 - class hitpoints: %3",_typeOf,_missingHitPoints,_hitpoints); + _testPass = false; + }; // _typeOf createUnit [position player, group player, "z = this"]; // deleteVehicle z; - - private _lastHitpoint = (_hitpoints param [(count _hitpoints) - 1, "#array"]); - if (_lastHitpoint != "ACE_HDBracket") then { - WARNING_2("%1 has bad last hitpoint: %2",_typeOf,_hitpoints); - _testPass = false; - }; - - if (((_hitpoints findIf {_x == "HitLeftArm"}) == -1) || {(_hitpoints findIf {_x == "HitRightArm"}) == -1} - || {(_hitpoints findIf {_x == "HitLeftLeg"}) == -1} || {(_hitpoints findIf {_x == "HitRightLeg"}) == -1} - || {(_hitpoints findIf {_x == "HitHead"}) == -1} || {(_hitpoints findIf {_x == "HitBody"}) == -1}) then { - WARNING_2("%1 missing ace hitpoints: %2",_typeOf,_hitpoints); - _testPass = false; - }; } forEach _units; _testPass diff --git a/addons/medical_engine/XEH_postInit.sqf b/addons/medical_engine/XEH_postInit.sqf index 2514c62254..ed66091498 100644 --- a/addons/medical_engine/XEH_postInit.sqf +++ b/addons/medical_engine/XEH_postInit.sqf @@ -6,27 +6,23 @@ [_new] call FUNC(updateDamageEffects); // Run on new controlled unit to update QGVAR(aimFracture) }, true] call CBA_fnc_addPlayerEventHandler; - ["CAManBase", "init", { params ["_unit"]; - // Check if last hit point is our dummy. - private _allHitPoints = getAllHitPointsDamage _unit param [0, []]; - reverse _allHitPoints; - while {(_allHitPoints param [0, ""]) select [0,1] == "#"} do { WARNING_1("Ignoring Reflector hitpoint %1",_allHitPoints deleteAt 0); }; + if (unitIsUAV _unit) exitWith {TRACE_1("ignore UAV AI",typeOf _unit);}; + if (getNumber (configOf _unit >> "isPlayableLogic") == 1) exitWith {TRACE_1("ignore logic unit",typeOf _unit);}; - if (_allHitPoints param [0, ""] != "ACE_HDBracket") then { - if (unitIsUAV _unit) exitWith {TRACE_1("ignore UAV AI",typeOf _unit);}; - if (getNumber ((configOf _unit) >> "isPlayableLogic") == 1) exitWith {TRACE_1("ignore logic unit",typeOf _unit)}; + private _allHitPoints = getAllHitPointsDamage _unit param [0, []]; + if ((GVAR(customHitpoints) arrayIntersect _allHitPoints) isNotEqualTo GVAR(customHitpoints)) exitWith { ERROR_1("Bad hitpoints for unit type ""%1""",typeOf _unit); - } else { - // Calling this function inside curly brackets allows the usage of - // "exitWith", which would be broken with "HandleDamage" otherwise. - _unit setVariable [ - QEGVAR(medical,HandleDamageEHID), - _unit addEventHandler ["HandleDamage", {_this call FUNC(handleDamage)}] - ]; }; + + // Calling this function inside curly brackets allows the usage of + // "exitWith", which would be broken with "HandleDamage" otherwise. + _unit setVariable [ + QEGVAR(medical,HandleDamageEHID), + _unit addEventHandler ["HandleDamage", {_this call FUNC(handleDamage)}] + ]; }, nil, [IGNORE_BASE_UAVPILOTS], true] call CBA_fnc_addClassEventHandler; #ifdef DEBUG_MODE_FULL @@ -88,7 +84,7 @@ }; }] call CBA_fnc_addEventHandler; -["CAManBase", "deleted", { +["CAManBase", "Deleted", { params ["_unit"]; TRACE_3("unit deleted",_unit,objectParent _unit,local _unit); if ((!isNull objectParent _unit) && {local objectParent _unit}) then { diff --git a/addons/medical_engine/XEH_preInit.sqf b/addons/medical_engine/XEH_preInit.sqf index b0304f167f..02e431103a 100644 --- a/addons/medical_engine/XEH_preInit.sqf +++ b/addons/medical_engine/XEH_preInit.sqf @@ -46,6 +46,8 @@ GVAR(animations) setVariable [QUNCON_ANIM(faceDown), [QUNCON_ANIM(1),QUNCON_ANIM GVAR(animations) setVariable [QUNCON_ANIM(faceLeft), [QUNCON_ANIM(7),QUNCON_ANIM(8),QUNCON_ANIM(1_1),QUNCON_ANIM(7_1),QUNCON_ANIM(8_1)]]; GVAR(animations) setVariable [QUNCON_ANIM(faceRight), [QUNCON_ANIM(5),QUNCON_ANIM(6),QUNCON_ANIM(10),QUNCON_ANIM(5_1),QUNCON_ANIM(6_1)]]; +GVAR(customHitpoints) = ["hitleftarm", "hitrightarm", "hitleftleg", "hitrightleg"]; + private _fnc_fixStatic = { params ["_vehicle"]; private _type = typeOf _vehicle; diff --git a/addons/medical_engine/functions/fnc_handleDamage.sqf b/addons/medical_engine/functions/fnc_handleDamage.sqf index a60816222f..61de4997b9 100644 --- a/addons/medical_engine/functions/fnc_handleDamage.sqf +++ b/addons/medical_engine/functions/fnc_handleDamage.sqf @@ -1,9 +1,9 @@ #include "..\script_component.hpp" /* - * Author: commy2, kymckay + * Author: commy2, kymckay, LinkIsGrim * HandleDamage EH where wound events are raised based on incoming damage. * Be aware that for each source of damage, the EH can fire multiple times (once for each hitpoint). - * We store these incoming damages and compare them on our final hitpoint: "ace_hdbracket". + * We store these incoming damages and compare them on last iteration of the event (_context == 2). * * Arguments: * Handle damage EH @@ -13,15 +13,16 @@ * * Public: No */ -params ["_unit", "_selection", "_damage", "_shooter", "_ammo", "_hitPointIndex", "_instigator", "_hitpoint"]; +params ["_unit", "_selection", "_damage", "_shooter", "_ammo", "_hitPointIndex", "_instigator", "_hitpoint", "_directHit", "_context"]; // HD sometimes triggers for remote units - ignore. if !(local _unit) exitWith {nil}; // Get missing meta info private _oldDamage = 0; +private _structuralDamage = _context == 0; -if (_hitPoint isEqualTo "") then { +if (_structuralDamage) then { _hitPoint = "#structural"; _oldDamage = damage _unit; } else { @@ -33,26 +34,29 @@ if !(isDamageAllowed _unit && {_unit getVariable [QEGVAR(medical,allowDamage), t private _newDamage = _damage - _oldDamage; -// Happens occasionally for vehiclehit events (see line 80 onwards) -// Just exit early to save some frametime -if (_newDamage == 0 && {_hitpoint isNotEqualTo "ace_hdbracket"}) exitWith {_oldDamage}; +// _newDamage == 0 happens occasionally for vehiclehit events (see line 80 onwards), just exit early to save some frametime +// context 4 is engine "bleeding". For us, it's just a duplicate event for #structural which we can ignore without any issues +if (_context != 2 && {_context == 4 || _newDamage == 0}) exitWith { + TRACE_4("Skipping engine bleeding or zero damage",_ammo,_newDamage,_directHit,_context); + _oldDamage +}; // Get scaled armor value of hitpoint and calculate damage before armor // We scale using passThrough to handle explosive-resistant armor properly (#9063) // We need realDamage to determine which limb was hit correctly [_unit, _hitpoint] call FUNC(getHitpointArmor) params ["_armor", "_armorScaled"]; private _realDamage = _newDamage * _armor; -if (_hitPoint isNotEqualTo "#structural") then { +if (!_structuralDamage) then { private _armorCoef = _armor/_armorScaled; private _damageCoef = linearConversion [0, 1, GVAR(damagePassThroughEffect), 1, _armorCoef]; _newDamage = _newDamage * _damageCoef; }; -TRACE_4("Received hit",_hitpoint,_ammo,_newDamage,_realDamage); +TRACE_6("Received hit",_hitpoint,_ammo,_newDamage,_realDamage,_directHit,_context); // Drowning doesn't fire the EH for each hitpoint so the "ace_hdbracket" code never runs // Damage occurs in consistent increments if ( - _hitPoint isEqualTo "#structural" && + _structuralDamage && {getOxygenRemaining _unit <= 0.5} && {_damage isEqualTo (_oldDamage + 0.005)} ) exitWith { @@ -64,14 +68,14 @@ if ( // Faster than (vehicle _unit), also handles dead units private _vehicle = objectParent _unit; +private _inVehicle = !isNull _vehicle; +private _environmentDamage = _ammo == ""; // Crashing a vehicle doesn't fire the EH for each hitpoint so the "ace_hdbracket" code never runs // It does fire the EH multiple times, but this seems to scale with the intensity of the crash if ( EGVAR(medical,enableVehicleCrashes) && - {_hitPoint isEqualTo "#structural"} && - {_ammo isEqualTo ""} && - {!isNull _vehicle} && + {_environmentDamage && _inVehicle && _structuralDamage} && {vectorMagnitude (velocity _vehicle) > 5} // todo: no way to detect if stationary and another vehicle hits you ) exitWith { @@ -83,11 +87,8 @@ if ( // Receiving explosive damage inside a vehicle doesn't trigger for each hitpoint // This is the case for mines, explosives, artillery, and catasthrophic vehicle explosions -// Triggers twice, but that doesn't matter as damage is low if ( - _hitPoint isEqualTo "#structural" && - {!isNull _vehicle} && - {_ammo isNotEqualTo ""} && + (!_environmentDamage && _inVehicle && _structuralDamage) && { private _ammoCfg = configFile >> "CfgAmmo" >> _ammo; GET_NUMBER(_ammoCfg >> "explosive",0) > 0 || @@ -104,9 +105,13 @@ if ( 0 }; -// This hitpoint is set to trigger last, evaluate all the stored damage values -// to determine where wounds are applied -if (_hitPoint isEqualTo "ace_hdbracket") exitWith { +// Damages are stored for last iteration of the HandleDamage event (_context == 2) +_unit setVariable [format [QGVAR($%1), _hitPoint], [_realDamage, _newDamage]]; + +// Ref https://community.bistudio.com/wiki/Arma_3:_Event_Handlers#HandleDamage +// Context 2 means this is the last iteration of HandleDamage, so figure out which hitpoint took the most real damage and send wound event +// Don't exit, as the last iteration can be one of the hitpoints that we need to keep _oldDamage for +if (_context == 2) then { _unit setVariable [QEGVAR(medical,lastDamageSource), _shooter]; _unit setVariable [QEGVAR(medical,lastInstigator), _instigator]; @@ -157,7 +162,7 @@ if (_hitPoint isEqualTo "ace_hdbracket") exitWith { // Environmental damage sources all have empty ammo string // No explicit source given, we infer from differences between them - if (_ammo isEqualTo "") then { + if (_environmentDamage) then { // Any collision with terrain/vehicle/object has a shooter // Check this first because burning can happen at any velocity if !(isNull _shooter) then { @@ -199,16 +204,9 @@ if (_hitPoint isEqualTo "ace_hdbracket") exitWith { QGVAR($HitLeftArm),QGVAR($HitRightArm),QGVAR($HitLeftLeg),QGVAR($HitRightLeg), QGVAR($#structural) ]; - - 0 }; -// Damages are stored for "ace_hdbracket" event triggered last -_unit setVariable [format [QGVAR($%1), _hitPoint], [_realDamage, _newDamage]]; - // Engine damage to these hitpoints controls blood visuals, limping, weapon sway // Handled in fnc_damageBodyPart, persist here -if (_hitPoint in ["hithead", "hitbody", "hithands", "hitlegs"]) exitWith {_oldDamage}; - -// We store our own damage values so engine damage is unnecessary -0 +// For all other hitpoints, we store our own damage values, so engine damage is unnecessary +[0, _oldDamage] select (_hitPoint in ["hithead", "hitbody", "hithands", "hitlegs"]) diff --git a/addons/medical_engine/script_macros_config.hpp b/addons/medical_engine/script_macros_config.hpp index 611a8ad356..7f65a4b912 100644 --- a/addons/medical_engine/script_macros_config.hpp +++ b/addons/medical_engine/script_macros_config.hpp @@ -47,15 +47,4 @@ };\ class HitRightLeg: HitLeftLeg {\ name = "leg_r";\ - };\ - class ACE_HDBracket {\ - armor = 1;\ - material = -1;\ - name = "head";\ - passThrough = 0;\ - radius = 1;\ - explosionShielding = 1;\ - visual = "";\ - minimalHit = 0;\ - depends = "HitHead";\ } From 2bd1f39de7ecf4b895e8e44566b66814d0d1b6fa Mon Sep 17 00:00:00 2001 From: Grim <69561145+LinkIsGrim@users.noreply.github.com> Date: Tue, 11 Jun 2024 11:46:14 -0300 Subject: [PATCH 086/290] Medical - Add `ace_medical_enabled` variable for future-proofing API (#9996) * add ace_medical_enabled setting * Update addons/medical_engine/XEH_preInit.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --------- Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- addons/medical_engine/XEH_preInit.sqf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/medical_engine/XEH_preInit.sqf b/addons/medical_engine/XEH_preInit.sqf index 02e431103a..ee27143bde 100644 --- a/addons/medical_engine/XEH_preInit.sqf +++ b/addons/medical_engine/XEH_preInit.sqf @@ -86,4 +86,7 @@ addMissionEventHandler ["Loaded", { [] call FUNC(disableThirdParty); +// Future-proofing +EGVAR(medical,enabled) = true; // TODO: remove when medical enable setting is implemented + ADDON = true; From 9760095c42d5f459dff7f43d73767bec28f604b7 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Tue, 11 Jun 2024 16:59:36 +0200 Subject: [PATCH 087/290] Grenades - Fix how incendiary grenades do damage to vehicles (#9983) * Allow incendiary grenades to damage multiple vehicles Disable incendiaries damaging invulnerable vehicles * Apply fire damage to vehicles even after grenade detonation * Update fnc_damageEngineAndWheels.sqf * Update fnc_incendiary.sqf * Update fnc_damageEngineAndWheels.sqf * british people don't exist --------- Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> --- addons/grenades/XEH_PREP.hpp | 2 +- addons/grenades/XEH_postInit.sqf | 1 + .../functions/fnc_damageEngineAndWheels.sqf | 60 +++++++++++++++++ addons/grenades/functions/fnc_incendiary.sqf | 65 +++++++------------ addons/grenades/script_component.hpp | 2 + 5 files changed, 86 insertions(+), 44 deletions(-) create mode 100644 addons/grenades/functions/fnc_damageEngineAndWheels.sqf diff --git a/addons/grenades/XEH_PREP.hpp b/addons/grenades/XEH_PREP.hpp index 6b5fb57801..6feaff3a69 100644 --- a/addons/grenades/XEH_PREP.hpp +++ b/addons/grenades/XEH_PREP.hpp @@ -1,4 +1,4 @@ - +PREP(damageEngineAndWheels); PREP(flare); PREP(flashbangExplosionEH); PREP(flashbangThrownFuze); diff --git a/addons/grenades/XEH_postInit.sqf b/addons/grenades/XEH_postInit.sqf index 21282ab1ce..312e22fa6e 100644 --- a/addons/grenades/XEH_postInit.sqf +++ b/addons/grenades/XEH_postInit.sqf @@ -3,6 +3,7 @@ #include "script_component.hpp" ["ace_flashbangExploded", LINKFUNC(flashbangExplosionEH)] call CBA_fnc_addEventHandler; +[QGVAR(damageEngineAndWheels), LINKFUNC(damageEngineAndWheels)] call CBA_fnc_addEventHandler; // Register fired event handlers ["ace_firedPlayer", LINKFUNC(throwGrenade)] call CBA_fnc_addEventHandler; diff --git a/addons/grenades/functions/fnc_damageEngineAndWheels.sqf b/addons/grenades/functions/fnc_damageEngineAndWheels.sqf new file mode 100644 index 0000000000..fa0032e87e --- /dev/null +++ b/addons/grenades/functions/fnc_damageEngineAndWheels.sqf @@ -0,0 +1,60 @@ +#include "..\script_component.hpp" +/* + * Author: commy2, johnb43 + * Damage a vehicle's wheels and engine. + * + * Arguments: + * 0: Vehicle + * 1: Incendiary position AGL + * + * Return Value: + * None + * + * Example: + * [cursorObject, position cursorObject] call ace_grenades_fnc_damageEngineAndWheels + * + * Public: No + */ + +params ["_vehicle", "_position"]; +TRACE_1("damageWheelsAndEngine",_vehicle); + +// Vehicle needs to be local and vulnerable +if !(local _vehicle && {isDamageAllowed _vehicle}) exitWith {}; + +// Burn tires +private _fnc_isWheelHitPoint = { + params ["_selectionName"]; + // Wheels must use a selection named "wheel_X_Y_steering" for PhysX to work + _selectionName select [0, 6] == "wheel_" && { + _selectionName select [count _selectionName - 9] == "_steering" + } // return +}; + +private _config = configOf _vehicle >> "HitPoints"; + +{ + private _wheelSelection = getText (_config >> _x >> "name"); + + if (_wheelSelection call _fnc_isWheelHitPoint) then { + private _wheelPosition = _vehicle modelToWorld (_vehicle selectionPosition _wheelSelection); + + if (_position distance _wheelPosition < EFFECT_SIZE * 2) then { + _vehicle setHit [_wheelSelection, 1]; + }; + }; +} forEach (getAllHitPointsDamage _vehicle param [0, []]); + +// Burn car engines only +if (_vehicle isKindOf "Wheeled_APC_F") exitWith {}; + +private _engineSelection = getText (_config >> "HitEngine" >> "name"); +private _enginePosition = _vehicle modelToWorld (_vehicle selectionPosition _engineSelection); + +if (_position distance _enginePosition < EFFECT_SIZE * 2) then { + _vehicle setHit [_engineSelection, 1]; + + if (["ace_cookoff"] call EFUNC(common,isModLoaded)) then { + [QEGVAR(cookoff,engineFireServer), _vehicle] call CBA_fnc_serverEvent; + }; +}; diff --git a/addons/grenades/functions/fnc_incendiary.sqf b/addons/grenades/functions/fnc_incendiary.sqf index c59d463511..337065cae3 100644 --- a/addons/grenades/functions/fnc_incendiary.sqf +++ b/addons/grenades/functions/fnc_incendiary.sqf @@ -30,11 +30,11 @@ #define PARTICLE_SMOKE_LIFTING 1 #define PARTICLE_SMOKE_WIND_EFFECT 1 -#define EFFECT_SIZE 1 #define ORIENTATION 5.4 #define EXPANSION 1 #define DESTRUCTION_RADIUS 1.8 +#define SEARCH_RADIUS 5 params ["_projectile", "_timeToLive", "_center"]; @@ -157,7 +157,24 @@ if (isServer) then { _sound = createSoundSource ["Sound_Fire", _position, [], 0]; private _radius = 1.5 * getNumber (configOf _projectile >> "indirectHitRange"); private _intensity = getNumber (configOf _projectile >> "hit"); - [QEGVAR(fire,addFireSource), [_projectile, _radius, _intensity, _projectile, {CBA_missionTime < _this}, CBA_missionTime + _timeToLive]] call CBA_fnc_serverEvent; + [QEGVAR(fire,addFireSource), [_projectile, _radius, _intensity, _projectile, { + params ["_endTime", "_projectile"]; + + // If incendiary no longer exists, exit + if (isNull _projectile) exitWith { + false + }; + + // Need to get the position every time, as grenade might have been moved + private _position = position _projectile; + + { + // Damage vehicles + [QGVAR(damageEngineAndWheels), [_x, _position], _x] call CBA_fnc_targetEvent; + } forEach (_position nearEntities ["Car", SEARCH_RADIUS]); + + CBA_missionTime < _endTime // return + }, [CBA_missionTime + _timeToLive, _projectile]]] call CBA_fnc_serverEvent; }; [{ @@ -196,45 +213,7 @@ if (isServer) then { }; } forEach (_position nearObjects DESTRUCTION_RADIUS); -// --- damage local vehicle -private _vehicle = _position nearestObject "Car"; - -if (!local _vehicle) exitWith {}; - -private _config = configOf _vehicle; - -// --- burn tyres -private _fnc_isWheelHitPoint = { - params ["_selectionName"]; - - // wheels must use a selection named "wheel_X_Y_steering" for PhysX to work - _selectionName select [0, 6] == "wheel_" && { - _selectionName select [count _selectionName - 9] == "_steering" - } // return -}; - { - private _wheelSelection = getText (_config >> "HitPoints" >> _x >> "name"); - - if (_wheelSelection call _fnc_isWheelHitPoint) then { - private _wheelPosition = _vehicle modelToWorld (_vehicle selectionPosition _wheelSelection); - - if (_position distance _wheelPosition < EFFECT_SIZE * 2) then { - _vehicle setHit [_wheelSelection, 1]; - }; - }; -} forEach (getAllHitPointsDamage _vehicle param [0, []]); - -// --- burn car engine -if (_vehicle isKindOf "Wheeled_APC_F") exitWith {}; - -private _engineSelection = getText (_config >> "HitPoints" >> "HitEngine" >> "name"); -private _enginePosition = _vehicle modelToWorld (_vehicle selectionPosition _engineSelection); - -if (_position distance _enginePosition < EFFECT_SIZE * 2) then { - _vehicle setHit [_engineSelection, 1]; - - if (["ace_cookoff"] call EFUNC(common,isModLoaded)) then { - [QEGVAR(cookoff,engineFireServer), _vehicle] call CBA_fnc_serverEvent; - }; -}; + // Damage vehicles (locality is checked in FUNC(damageEngineAndWheels)) + [_x, _position] call FUNC(damageEngineAndWheels); +} forEach (_position nearEntities ["Car", SEARCH_RADIUS]); diff --git a/addons/grenades/script_component.hpp b/addons/grenades/script_component.hpp index 3da453de6f..ba673d0f33 100644 --- a/addons/grenades/script_component.hpp +++ b/addons/grenades/script_component.hpp @@ -21,4 +21,6 @@ #define EFFECT_STAGE_PARTIALRECOVERY 2 #define EFFECT_STAGE_FULLRECOVERY 3 +#define EFFECT_SIZE 1 + #define MIN_EXPLOSION_TIME_FOR_ROLL 1 From 898daff7f62dedf187309de88368eb45c3370882 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Tue, 11 Jun 2024 10:00:50 -0500 Subject: [PATCH 088/290] General - Cleanup event capitalization (#10062) --- addons/arsenal/functions/fnc_onArsenalClose.sqf | 2 +- addons/arsenal/functions/fnc_onArsenalOpen.sqf | 2 +- addons/arsenal/missions/Arsenal.VR/fnc_createTarget.sqf | 2 +- addons/common/functions/fnc_errorMessage.sqf | 8 ++++---- addons/slideshow/functions/fnc_mapImage_init.sqf | 2 +- .../vehicle_damage/functions/fnc_handleVehicleDamage.sqf | 2 +- addons/weather/init3DEN.sqf | 2 +- addons/zeus/functions/fnc_getModuleDestination.sqf | 4 ++-- addons/zeus/functions/fnc_ui_globalSetSkill.sqf | 6 +++--- addons/zeus/functions/fnc_ui_groupSide.sqf | 8 ++++---- addons/zeus/functions/fnc_ui_setEngineer.sqf | 2 +- addons/zeus/functions/fnc_ui_teleportPlayers.sqf | 6 +++--- 12 files changed, 23 insertions(+), 23 deletions(-) diff --git a/addons/arsenal/functions/fnc_onArsenalClose.sqf b/addons/arsenal/functions/fnc_onArsenalClose.sqf index f2316bc9d5..6803d2d5de 100644 --- a/addons/arsenal/functions/fnc_onArsenalClose.sqf +++ b/addons/arsenal/functions/fnc_onArsenalClose.sqf @@ -18,7 +18,7 @@ (_this select 1) params ["", "_exitCode"]; [QGVAR(displayClosed), []] call CBA_fnc_localEvent; -removeMissionEventHandler ["draw3D", GVAR(camPosUpdateHandle)]; +removeMissionEventHandler ["Draw3D", GVAR(camPosUpdateHandle)]; if (is3DEN) then { private _centerOriginParent = objectParent GVAR(centerOrigin); diff --git a/addons/arsenal/functions/fnc_onArsenalOpen.sqf b/addons/arsenal/functions/fnc_onArsenalOpen.sqf index f307c932b1..0f0a5817c6 100644 --- a/addons/arsenal/functions/fnc_onArsenalOpen.sqf +++ b/addons/arsenal/functions/fnc_onArsenalOpen.sqf @@ -278,4 +278,4 @@ showCinemaBorder false; //--------------- Reset camera pos [nil, [controlNull, 0, 0]] call FUNC(handleMouse); -GVAR(camPosUpdateHandle) = addMissionEventHandler ["draw3D", {call FUNC(updateCamPos)}]; +GVAR(camPosUpdateHandle) = addMissionEventHandler ["Draw3D", {call FUNC(updateCamPos)}]; diff --git a/addons/arsenal/missions/Arsenal.VR/fnc_createTarget.sqf b/addons/arsenal/missions/Arsenal.VR/fnc_createTarget.sqf index a93611d329..502f7b888d 100644 --- a/addons/arsenal/missions/Arsenal.VR/fnc_createTarget.sqf +++ b/addons/arsenal/missions/Arsenal.VR/fnc_createTarget.sqf @@ -63,7 +63,7 @@ _target switchMove "amovpercmstpslowwrfldnon"; _target setVariable ["origin", _position]; // When killed, respawn AI -_target addEventHandler ["killed", { +_target addEventHandler ["Killed", { params ["_target"]; // Killed may fire twice, 2nd will be null - https://github.com/acemod/ACE3/pull/7561 diff --git a/addons/common/functions/fnc_errorMessage.sqf b/addons/common/functions/fnc_errorMessage.sqf index 021fdba10c..72344299f3 100644 --- a/addons/common/functions/fnc_errorMessage.sqf +++ b/addons/common/functions/fnc_errorMessage.sqf @@ -137,11 +137,11 @@ if (_onCancel isEqualTo {}) then { ctrlSetFocus _ctrlButtonCancel; }; -_ctrlButtonOK ctrlAddEventHandler ["buttonClick", {(ctrlParent (_this select 0)) closeDisplay 1; true}]; -_ctrlButtonCancel ctrlAddEventHandler ["buttonClick", {(ctrlParent (_this select 0)) closeDisplay 2; true}]; +_ctrlButtonOK ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay 1; true}]; +_ctrlButtonCancel ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay 2; true}]; GVAR(errorOnOK) = _onOK; GVAR(errorOnCancel) = _onCancel; -_display displayAddEventHandler ["unload", {call ([{}, GVAR(errorOnOK), GVAR(errorOnCancel)] select (_this select 1))}]; -_display displayAddEventHandler ["keyDown", {_this select 1 == 1}]; +_display displayAddEventHandler ["Unload", {call ([{}, GVAR(errorOnOK), GVAR(errorOnCancel)] select (_this select 1))}]; +_display displayAddEventHandler ["KeyDown", {_this select 1 == 1}]; diff --git a/addons/slideshow/functions/fnc_mapImage_init.sqf b/addons/slideshow/functions/fnc_mapImage_init.sqf index 5235315bd0..3fb6e4c7f8 100644 --- a/addons/slideshow/functions/fnc_mapImage_init.sqf +++ b/addons/slideshow/functions/fnc_mapImage_init.sqf @@ -50,7 +50,7 @@ ctrlMapAnimCommit _map; // add drawEH to draw markers next update (they will get drawn 3 times total) _map setVariable ["markers", _markers]; -_map ctrlAddEventHandler ["draw", { +_map ctrlAddEventHandler ["Draw", { params ["_map"]; private _markers = _map getVariable ["markers", []]; TRACE_2("drawing markers",_map,count _markers); diff --git a/addons/vehicle_damage/functions/fnc_handleVehicleDamage.sqf b/addons/vehicle_damage/functions/fnc_handleVehicleDamage.sqf index e18d8a3814..02033b83be 100644 --- a/addons/vehicle_damage/functions/fnc_handleVehicleDamage.sqf +++ b/addons/vehicle_damage/functions/fnc_handleVehicleDamage.sqf @@ -28,7 +28,7 @@ TRACE_6("handleVehicleDamage",_vehicle,_hitPoint,_hitIndex,_injurer,_oldDamage,_ if !(alive _vehicle) exitWith { private _eventHandler = _vehicle getVariable[QGVAR(handleDamage), nil]; if !(isNil "_eventHandler") then { - _vehicle removeEventHandler ["handleDamage", _eventHandler]; + _vehicle removeEventHandler ["HandleDamage", _eventHandler]; }; LOG_1("Vehicle [%1] no longer alive",_vehicle); true diff --git a/addons/weather/init3DEN.sqf b/addons/weather/init3DEN.sqf index 34b7dc2d5b..74af5fbaf1 100644 --- a/addons/weather/init3DEN.sqf +++ b/addons/weather/init3DEN.sqf @@ -5,7 +5,7 @@ // cannot create checkboxes which have the default value "true" // 3den uses inverted checkboxes instead, but those only change in appearence // we have to auto set these settings manually - on mission creation -add3DENEventHandler ["onMissionNew", { +add3DENEventHandler ["OnMissionNew", { set3DENMissionAttributes [ ["Intel", "IntelWavesIsForced", true], ["Intel", "IntelWindIsForced", true] diff --git a/addons/zeus/functions/fnc_getModuleDestination.sqf b/addons/zeus/functions/fnc_getModuleDestination.sqf index b328201d6c..10d7acae9e 100644 --- a/addons/zeus/functions/fnc_getModuleDestination.sqf +++ b/addons/zeus/functions/fnc_getModuleDestination.sqf @@ -113,9 +113,9 @@ GVAR(moduleDestination_mapDrawEH) = [((findDisplay 312) displayCtrl 50), "draw", } else { TRACE_4("cleaning up",_this select 1,GVAR(moduleDestination_displayEHMouse),GVAR(moduleDestination_displayEHKeyboard),GVAR(moduleDestination_mapDrawEH)); (_this select 1) call CBA_fnc_removePerFrameHandler; - (findDisplay 312) displayRemoveEventHandler ["mouseButtonDown", GVAR(moduleDestination_displayEHMouse)]; + (findDisplay 312) displayRemoveEventHandler ["MouseButtonDown", GVAR(moduleDestination_displayEHMouse)]; (findDisplay 312) displayRemoveEventHandler ["KeyDown", GVAR(moduleDestination_displayEHKeyboard)]; - ((findDisplay 312) displayCtrl 50) ctrlRemoveEventHandler ["draw", GVAR(moduleDestination_mapDrawEH)]; + ((findDisplay 312) displayCtrl 50) ctrlRemoveEventHandler ["Draw", GVAR(moduleDestination_mapDrawEH)]; GVAR(moduleDestination_displayEHMouse) = nil; GVAR(moduleDestination_displayEHKeyboard) = nil; GVAR(moduleDestination_mapDrawEH) = nil; diff --git a/addons/zeus/functions/fnc_ui_globalSetSkill.sqf b/addons/zeus/functions/fnc_ui_globalSetSkill.sqf index 31f41d76c6..5a7c5fc5e0 100644 --- a/addons/zeus/functions/fnc_ui_globalSetSkill.sqf +++ b/addons/zeus/functions/fnc_ui_globalSetSkill.sqf @@ -24,7 +24,7 @@ private _ctrlButtonOK = _display displayCtrl 1; //IDC_OK private _logic = GETMVAR(BIS_fnc_initCuratorAttributes_target,objNull); TRACE_1("logicObject",_logic); -_control ctrlRemoveAllEventHandlers "setFocus"; +_control ctrlRemoveAllEventHandlers "SetFocus"; //Specific on-load stuff: private _fnc_sliderMove = { @@ -74,5 +74,5 @@ private _fnc_onConfirm = { [QGVAR(GlobalSkillAI),GVAR(GlobalSkillAI)] call FUNC(moduleGlobalSetSkill); }; -_display displayAddEventHandler ["unload", _fnc_onUnload]; -_ctrlButtonOK ctrlAddEventHandler ["buttonclick", _fnc_onConfirm]; +_display displayAddEventHandler ["Unload", _fnc_onUnload]; +_ctrlButtonOK ctrlAddEventHandler ["ButtonClick", _fnc_onConfirm]; diff --git a/addons/zeus/functions/fnc_ui_groupSide.sqf b/addons/zeus/functions/fnc_ui_groupSide.sqf index 4dff592f62..110e2e302d 100644 --- a/addons/zeus/functions/fnc_ui_groupSide.sqf +++ b/addons/zeus/functions/fnc_ui_groupSide.sqf @@ -24,7 +24,7 @@ private _ctrlButtonOK = _display displayCtrl 1; //IDC_OK private _logic = GETMVAR(BIS_fnc_initCuratorAttributes_target,objNull); TRACE_1("logicObject",_logic); -_control ctrlRemoveAllEventHandlers "setFocus"; +_control ctrlRemoveAllEventHandlers "SetFocus"; //Validate the module target: private _unit = effectiveCommander (attachedTo _logic); @@ -101,7 +101,7 @@ private _fnc_onSelection = { _ctrl ctrlSetTextColor _color; - _ctrl ctrlAddEventHandler ["buttonclick", _fnc_onSelection]; + _ctrl ctrlAddEventHandler ["ButtonClick", _fnc_onSelection]; } forEach IDCs; private _fnc_onUnload = { @@ -129,5 +129,5 @@ private _fnc_onConfirm = { deleteVehicle _logic; }; -_display displayAddEventHandler ["unload", _fnc_onUnload]; -_ctrlButtonOK ctrlAddEventHandler ["buttonClick", _fnc_onConfirm]; +_display displayAddEventHandler ["Unload", _fnc_onUnload]; +_ctrlButtonOK ctrlAddEventHandler ["ButtonClick", _fnc_onConfirm]; diff --git a/addons/zeus/functions/fnc_ui_setEngineer.sqf b/addons/zeus/functions/fnc_ui_setEngineer.sqf index b2515c311d..3f008403cc 100644 --- a/addons/zeus/functions/fnc_ui_setEngineer.sqf +++ b/addons/zeus/functions/fnc_ui_setEngineer.sqf @@ -23,7 +23,7 @@ private _ctrlButtonOK = _display displayCtrl 1; // IDC_OK private _logic = GETMVAR(BIS_fnc_initCuratorAttributes_target,objNull); TRACE_1("logicObject",_logic); -_control ctrlRemoveAllEventHandlers "setFocus"; +_control ctrlRemoveAllEventHandlers "SetFocus"; // Validate module target private _unit = attachedTo _logic; diff --git a/addons/zeus/functions/fnc_ui_teleportPlayers.sqf b/addons/zeus/functions/fnc_ui_teleportPlayers.sqf index 1becc04004..b7aab41126 100644 --- a/addons/zeus/functions/fnc_ui_teleportPlayers.sqf +++ b/addons/zeus/functions/fnc_ui_teleportPlayers.sqf @@ -23,7 +23,7 @@ private _ctrlButtonOK = _display displayCtrl 1; //IDC_OK private _logic = GETMVAR(BIS_fnc_initCuratorAttributes_target,objNull); TRACE_1("logicObject",_logic); -_control ctrlRemoveAllEventHandlers "setFocus"; +_control ctrlRemoveAllEventHandlers "SetFocus"; //Specific on-load stuff: private _listbox = _display displayCtrl 16189; @@ -91,5 +91,5 @@ private _fnc_onConfirm = { }; _display displayAddEventHandler ["KeyUp", _fnc_onKeyUp]; -_display displayAddEventHandler ["unload", _fnc_onUnload]; -_ctrlButtonOK ctrlAddEventHandler ["buttonclick", _fnc_onConfirm]; +_display displayAddEventHandler ["Unload", _fnc_onUnload]; +_ctrlButtonOK ctrlAddEventHandler ["ButtonClick", _fnc_onConfirm]; From 59af3e1f6d66ee08a1f8e4fd847efd45bb9ef73e Mon Sep 17 00:00:00 2001 From: Grim <69561145+LinkIsGrim@users.noreply.github.com> Date: Tue, 11 Jun 2024 12:34:32 -0300 Subject: [PATCH 089/290] General - Change CBA Namespaces to HashMap (#8801) * medical_treatment * advanced_throwing * common, csw * Update fnc_replaceRegisteredItems.sqf * Sanitised numerous components * Update XEH_postInit.sqf * Update XEH_postInit.sqf * FUNC -> LINKFUNC * Changed tagging hashmap * Reverted some changes * Reverted some changes * Update XEH_clientInit.sqf * Tweaks and fixes * Fix number replacements * Minor cleanup * Update fnc_getMagazineName.sqf * Update fnc_getMagazineName.sqf * Minor improvement * Made factions case-sensitive and added `toLowerANSI` to be safe * Update fnc_getDetectedObject.sqf * Update addons/common/functions/fnc_actionKeysNamesConverted.sqf Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> * Throw error if item doesn't exist --------- Co-authored-by: Salluci <69561145+Salluci@users.noreply.github.com> Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- addons/advanced_throwing/XEH_postInit.sqf | 10 ----- addons/advanced_throwing/XEH_preStart.sqf | 18 +++++++++ .../functions/fnc_drawThrowable.sqf | 11 ++---- addons/captives/XEH_postInit.sqf | 2 +- addons/common/XEH_postInit.sqf | 2 +- .../fnc_actionKeysNamesConverted.sqf | 10 ++--- .../common/functions/fnc_getSettingData.sqf | 3 +- .../functions/fnc_registerItemReplacement.sqf | 15 ++++++-- .../functions/fnc_replaceRegisteredItems.sqf | 6 +-- addons/dagr/XEH_postInit.sqf | 2 +- addons/dogtags/XEH_preInit.sqf | 2 +- .../dogtags/functions/fnc_canCheckDogtag.sqf | 2 +- .../dogtags/functions/fnc_canTakeDogtag.sqf | 2 +- .../functions/fnc_disableFactionDogtags.sqf | 7 +++- .../explosives/functions/fnc_addClacker.sqf | 2 +- addons/frag/XEH_postInit.sqf | 2 +- addons/frag/functions/fnc_findReflections.sqf | 2 +- addons/frag/functions/fnc_fired.sqf | 4 +- addons/map/XEH_postInitClient.sqf | 2 +- addons/map/functions/fnc_isFlashlight.sqf | 15 ++------ addons/map_gestures/XEH_preInit.sqf | 2 +- .../functions/fnc_addGroupColorMapping.sqf | 2 +- .../functions/fnc_drawMapGestures.sqf | 2 +- addons/medical_blood/XEH_preInit.sqf | 16 +------- addons/medical_blood/XEH_preStart.sqf | 5 +-- .../functions/fnc_createBlood.sqf | 2 +- .../functions/fnc_handleWoundReceived.sqf | 2 +- addons/medical_engine/XEH_preInit.sqf | 11 +++--- .../functions/fnc_applyAnimAfterRagdoll.sqf | 2 +- addons/medical_treatment/XEH_preInit.sqf | 38 +++++++++---------- .../functions/fnc_treatment.sqf | 2 +- addons/minedetector/XEH_postInit.sqf | 11 +----- addons/minedetector/XEH_preStart.sqf | 4 +- .../functions/fnc_getDetectedObject.sqf | 12 +++--- .../functions/fnc_getDetectorConfig.sqf | 11 ++---- addons/nametags/XEH_postInit.sqf | 2 +- .../functions/fnc_drawNameTagIcon.sqf | 2 +- .../functions/fnc_setFactionRankIcons.sqf | 9 ++++- addons/pylons/functions/fnc_showDialog.sqf | 2 +- addons/rearm/XEH_postInit.sqf | 1 - addons/tagging/XEH_postInit.sqf | 8 ---- addons/tagging/XEH_preStart.sqf | 4 +- .../tagging/functions/fnc_checkTaggable.sqf | 6 +-- addons/tagging/functions/fnc_tag.sqf | 4 +- addons/ui/XEH_clientInit.sqf | 9 ++--- addons/ui/functions/fnc_compileConfigUI.sqf | 2 +- .../ui/functions/fnc_setAdvancedElement.sqf | 6 ++- .../ui/functions/fnc_setElementVisibility.sqf | 9 ++--- addons/weaponselect/XEH_preInit.sqf | 12 ++++-- .../functions/fnc_selectNextGrenade.sqf | 12 +++--- 50 files changed, 152 insertions(+), 177 deletions(-) diff --git a/addons/advanced_throwing/XEH_postInit.sqf b/addons/advanced_throwing/XEH_postInit.sqf index 774c99b3e6..b732f033f9 100644 --- a/addons/advanced_throwing/XEH_postInit.sqf +++ b/addons/advanced_throwing/XEH_postInit.sqf @@ -10,16 +10,6 @@ if (!hasInterface) exitWith {}; // Temporary Wind Info indication GVAR(tempWindInfo) = false; -// Ammo/Magazines look-up hash for correctness of initSpeed -GVAR(ammoMagLookup) = call CBA_fnc_createNamespace; -{ - { - private _ammo = getText (configFile >> "CfgMagazines" >> _x >> "ammo"); - if (_ammo != "") then { GVAR(ammoMagLookup) setVariable [_ammo, _x]; }; - } forEach (getArray (configFile >> "CfgWeapons" >> "Throw" >> _x >> "magazines")); -} forEach getArray (configFile >> "CfgWeapons" >> "Throw" >> "muzzles"); - - // Add keybinds ["ACE3 Weapons", QGVAR(prepare), localize LSTRING(Prepare), { // Condition diff --git a/addons/advanced_throwing/XEH_preStart.sqf b/addons/advanced_throwing/XEH_preStart.sqf index 022888575e..efd2ca1f7e 100644 --- a/addons/advanced_throwing/XEH_preStart.sqf +++ b/addons/advanced_throwing/XEH_preStart.sqf @@ -1,3 +1,21 @@ #include "script_component.hpp" #include "XEH_PREP.hpp" + +// Ammo/Magazines look-up hash for correctness of initSpeed +private _cfgMagazines = configFile >> "CfgMagazines"; +private _cfgAmmo = configFile >> "CfgAmmo"; +private _cfgThrow = configFile >> "CfgWeapons" >> "Throw"; + +private _ammoMagLookup = createHashMap; + +{ + { + private _ammo = getText (_cfgMagazines >> _x >> "ammo"); + if (_ammo != "") then { + _ammoMagLookup set [configName (_cfgAmmo >> _ammo), _x]; + }; + } forEach (getArray (_cfgThrow >> _x >> "magazines")); +} forEach (getArray (_cfgThrow >> "muzzles")); + +uiNamespace setVariable [QGVAR(ammoMagLookup), compileFinal _ammoMagLookup]; diff --git a/addons/advanced_throwing/functions/fnc_drawThrowable.sqf b/addons/advanced_throwing/functions/fnc_drawThrowable.sqf index 5bc3f22b57..f85c33dbde 100644 --- a/addons/advanced_throwing/functions/fnc_drawThrowable.sqf +++ b/addons/advanced_throwing/functions/fnc_drawThrowable.sqf @@ -43,13 +43,10 @@ if ((!_primed) && {!((_throwableMag in (uniformItems ACE_player)) || {_throwable // Get correct throw power for primed grenade if (_primed) then { - private _ammoType = typeOf _activeThrowable; - _throwableMag = GVAR(ammoMagLookup) getVariable _ammoType; - if (isNil "_throwableMag") then { - // What we're trying to throw must not be a normal throwable because it is not in our lookup hash (e.g. 40mm smoke) - // Just use HandGrenade as it has an average initSpeed value - _throwableMag = "HandGrenade"; - }; + // If ammo type is not found: + // What we're trying to throw must not be a normal throwable because it is not in our lookup hash (e.g. 40mm smoke) + // Just use HandGrenade as it has an average initSpeed value + _throwableMag = (uiNamespace getVariable QGVAR(ammoMagLookup)) getOrDefault [typeOf _activeThrowable, "HandGrenade"]; }; // Some throwables have different classname for magazine and ammo diff --git a/addons/captives/XEH_postInit.sqf b/addons/captives/XEH_postInit.sqf index 951a710771..2580e72463 100644 --- a/addons/captives/XEH_postInit.sqf +++ b/addons/captives/XEH_postInit.sqf @@ -24,7 +24,7 @@ if (isServer) then { }]; }; -["unit", FUNC(handlePlayerChanged)] call CBA_fnc_addPlayerEventHandler; +["unit", LINKFUNC(handlePlayerChanged)] call CBA_fnc_addPlayerEventHandler; [QGVAR(moveInCaptive), LINKFUNC(vehicleCaptiveMoveIn)] call CBA_fnc_addEventHandler; [QGVAR(moveOutCaptive), LINKFUNC(vehicleCaptiveMoveOut)] call CBA_fnc_addEventHandler; diff --git a/addons/common/XEH_postInit.sqf b/addons/common/XEH_postInit.sqf index 0d4b55ae28..b569a4608e 100644 --- a/addons/common/XEH_postInit.sqf +++ b/addons/common/XEH_postInit.sqf @@ -145,7 +145,7 @@ if (isServer) then { INFO_3("[%1] DC - Was Zeus [%2] while controlling unit [%3] - manually clearing `bis_fnc_moduleRemoteControl_owner`",[_x] call FUNC(getName),_dcPlayer,_x); _x setVariable ["bis_fnc_moduleRemoteControl_owner", nil, true]; }; - } forEach (curatorEditableObjects _zeusLogic); + } forEach (curatorEditableObjects _zeusLogic); }; }]; }; diff --git a/addons/common/functions/fnc_actionKeysNamesConverted.sqf b/addons/common/functions/fnc_actionKeysNamesConverted.sqf index dd62fc8789..27c3597a9b 100644 --- a/addons/common/functions/fnc_actionKeysNamesConverted.sqf +++ b/addons/common/functions/fnc_actionKeysNamesConverted.sqf @@ -43,10 +43,10 @@ if (isNil "_keyTable") then { }; }; -private _keyCache = uiNamespace getVariable [QGVAR(keyNameCache), locationNull]; +private _keyCache = uiNamespace getVariable QGVAR(keyNameCache); // @TODO: Move cache creation to preStart/somewhere else -if (isNull _keyCache) then { - _keyCache = call CBA_fnc_createNamespace; +if (isNil "_keyCache") then { + _keyCache = createHashMap; uiNamespace setVariable [QGVAR(keyNameCache), _keyCache]; }; @@ -54,7 +54,7 @@ params [["_action", "", [""]]]; private _keybinds = actionKeysNamesArray _action apply { private _keyName = _x; - private _keybind = _keyCache getVariable _keyName; + private _keybind = _keyCache get _keyName; if (isNil "_keybind") then { private _key = -1; @@ -101,7 +101,7 @@ private _keybinds = actionKeysNamesArray _action apply { // cache _keybind = [_key, _shift, _ctrl, _alt]; - _keyCache setVariable [_keyName, _keybind]; + _keyCache set [_keyName, _keybind]; }; _keybind diff --git a/addons/common/functions/fnc_getSettingData.sqf b/addons/common/functions/fnc_getSettingData.sqf index a2dceb746c..eeb8dff1d8 100644 --- a/addons/common/functions/fnc_getSettingData.sqf +++ b/addons/common/functions/fnc_getSettingData.sqf @@ -32,7 +32,6 @@ scopeName "main"; if (_x select 0 == _name) then { _x breakOut "main"; }; - false -} count GVAR(settings); +} forEach GVAR(settings); [] diff --git a/addons/common/functions/fnc_registerItemReplacement.sqf b/addons/common/functions/fnc_registerItemReplacement.sqf index ce2fd7e393..f1e068c322 100644 --- a/addons/common/functions/fnc_registerItemReplacement.sqf +++ b/addons/common/functions/fnc_registerItemReplacement.sqf @@ -20,15 +20,23 @@ params [["_oldItem", "", [0,""]], ["_newItems", "", ["", []]], ["_replaceInherited", false, [false]]]; TRACE_3("registerItemReplacement",_oldItem,_newItems,_replaceInherited); - // Setup on first run if (isNil QGVAR(itemReplacements)) then { - GVAR(itemReplacements) = [] call CBA_fnc_createNamespace; + GVAR(itemReplacements) = createHashMap; GVAR(inheritedReplacements) = []; GVAR(oldItems) = []; ["loadout", LINKFUNC(replaceRegisteredItems)] call CBA_fnc_addPlayerEventHandler; }; +// Get config case - if item doesn't exist, "" is returned +if (_oldItem isEqualType "") then { + _oldItem = _oldItem call FUNC(getConfigName); +}; + +if (_oldItem isEqualTo "") exitWith { + ERROR("Item doesn't exist"); +}; + // Save item replacement // $ prefix is used for types (numbers) and replacements with inheritance if (_replaceInherited) then { @@ -42,9 +50,8 @@ if (_newItems isEqualType "") then { _newItems = [_newItems]; }; -private _oldReplacements = GVAR(itemReplacements) getVariable [_oldItem, []]; +private _oldReplacements = GVAR(itemReplacements) getOrDefault [_oldItem, [], true]; _oldReplacements append _newItems; -GVAR(itemReplacements) setVariable [_oldItem, _oldReplacements]; // Force item scan when new replacement was registered in PostInit if !(isNull ACE_player) then { diff --git a/addons/common/functions/fnc_replaceRegisteredItems.sqf b/addons/common/functions/fnc_replaceRegisteredItems.sqf index bfe2e493e0..baa591c8d8 100644 --- a/addons/common/functions/fnc_replaceRegisteredItems.sqf +++ b/addons/common/functions/fnc_replaceRegisteredItems.sqf @@ -42,7 +42,7 @@ for "_i" from 0 to count _newItems - 1 do { private _replacements = []; // Determine replacement items: direct replacements, ... - private _directReplacements = GVAR(itemReplacements) getVariable _item; + private _directReplacements = GVAR(itemReplacements) get _item; if (!isNil "_directReplacements") then { _doReplace = true; _replacements append _directReplacements; @@ -50,7 +50,7 @@ for "_i" from 0 to count _newItems - 1 do { // ... item type replacements ... private _type = getNumber (_cfgWeapons >> _item >> "ItemInfo" >> "type"); - private _typeReplacements = GVAR(itemReplacements) getVariable ("$" + str _type); + private _typeReplacements = GVAR(itemReplacements) get ("$" + str _type); if (!isNil "_typeReplacements") then { _doReplace = true; _replacements append _typeReplacements; @@ -59,7 +59,7 @@ for "_i" from 0 to count _newItems - 1 do { // ... and inherited replacements { if (_item isKindOf [_x, _cfgWeapons]) then { - private _inheritedReplacements = GVAR(itemReplacements) getVariable _x; + private _inheritedReplacements = GVAR(itemReplacements) get _x; if (!isNil "_inheritedReplacements") then { _doReplace = true; _replacements append _inheritedReplacements; diff --git a/addons/dagr/XEH_postInit.sqf b/addons/dagr/XEH_postInit.sqf index 6996ced7f2..34dc981843 100644 --- a/addons/dagr/XEH_postInit.sqf +++ b/addons/dagr/XEH_postInit.sqf @@ -30,4 +30,4 @@ GVAR(vectorConnected) = false; GVAR(noVectorData) = true; GVAR(vectorGrid) = "00000000"; -[QEGVAR(vector,rangefinderData), FUNC(handleRangeFinderData)] call CBA_fnc_addEventHandler; +[QEGVAR(vector,rangefinderData), LINKFUNC(handleRangeFinderData)] call CBA_fnc_addEventHandler; diff --git a/addons/dogtags/XEH_preInit.sqf b/addons/dogtags/XEH_preInit.sqf index 5ad43b0229..f5fcb406b1 100644 --- a/addons/dogtags/XEH_preInit.sqf +++ b/addons/dogtags/XEH_preInit.sqf @@ -6,6 +6,6 @@ PREP_RECOMPILE_START; #include "XEH_PREP.hpp" PREP_RECOMPILE_END; -GVAR(disabledFactions) = [] call CBA_fnc_createNamespace; +GVAR(disabledFactions) = createHashMap; ADDON = true; diff --git a/addons/dogtags/functions/fnc_canCheckDogtag.sqf b/addons/dogtags/functions/fnc_canCheckDogtag.sqf index 399ad5db25..bec3ef0dfa 100644 --- a/addons/dogtags/functions/fnc_canCheckDogtag.sqf +++ b/addons/dogtags/functions/fnc_canCheckDogtag.sqf @@ -21,6 +21,6 @@ params ["_player", "_target"]; if (isNull _target) exitWith {false}; // check if disabled for faction -if ([GVAR(disabledFactions) getVariable faction _target] param [0, false]) exitWith {false}; +if ((faction _target) in GVAR(disabledFactions)) exitWith {false}; (!alive _target) || {_target getVariable ["ACE_isUnconscious", false]} diff --git a/addons/dogtags/functions/fnc_canTakeDogtag.sqf b/addons/dogtags/functions/fnc_canTakeDogtag.sqf index 7ae38f7c41..c482d74c1c 100644 --- a/addons/dogtags/functions/fnc_canTakeDogtag.sqf +++ b/addons/dogtags/functions/fnc_canTakeDogtag.sqf @@ -21,6 +21,6 @@ params ["_player", "_target"]; if (isNull _target) exitWith {false}; // check if disabled for faction -if ([GVAR(disabledFactions) getVariable faction _target] param [0, false]) exitWith {false}; +if ((faction _target) in GVAR(disabledFactions)) exitWith {false}; (!alive _target) || {_target getVariable ["ACE_isUnconscious", false]} diff --git a/addons/dogtags/functions/fnc_disableFactionDogtags.sqf b/addons/dogtags/functions/fnc_disableFactionDogtags.sqf index f1ea5f5c06..c4642ef4b5 100644 --- a/addons/dogtags/functions/fnc_disableFactionDogtags.sqf +++ b/addons/dogtags/functions/fnc_disableFactionDogtags.sqf @@ -17,4 +17,9 @@ params [["_faction", "", [""]]]; -GVAR(disabledFactions) setVariable [_faction, true]; +_faction = configName (configFile >> "CfgFactionClasses" >> _faction); + +// Faction doesn't exist +if (_faction == "") exitWith {}; + +GVAR(disabledFactions) set [_faction, true]; diff --git a/addons/explosives/functions/fnc_addClacker.sqf b/addons/explosives/functions/fnc_addClacker.sqf index 2292bfcb79..794aec0a10 100644 --- a/addons/explosives/functions/fnc_addClacker.sqf +++ b/addons/explosives/functions/fnc_addClacker.sqf @@ -31,7 +31,7 @@ private _detonators = [_unit] call FUNC(getDetonators); if !(_x in _detonators) exitWith{ _hasRequired = false; }; -} count _requiredItems; +} forEach _requiredItems; if !(_hasRequired) exitWith {}; private _config = ConfigFile >> "CfgMagazines" >> _magazineClass >> "ACE_Triggers" >> configName _config; diff --git a/addons/frag/XEH_postInit.sqf b/addons/frag/XEH_postInit.sqf index 096b4dde97..cc58e1d15b 100644 --- a/addons/frag/XEH_postInit.sqf +++ b/addons/frag/XEH_postInit.sqf @@ -18,7 +18,7 @@ if (isServer) then { }] call CBA_fnc_addEventHandler; // Cache for ammo type configs -GVAR(cacheRoundsTypesToTrack) = [false] call CBA_fnc_createNamespace; +GVAR(cacheRoundsTypesToTrack) = createHashMap; // Debug stuff: diff --git a/addons/frag/functions/fnc_findReflections.sqf b/addons/frag/functions/fnc_findReflections.sqf index b0ae161597..53931c3fda 100644 --- a/addons/frag/functions/fnc_findReflections.sqf +++ b/addons/frag/functions/fnc_findReflections.sqf @@ -120,7 +120,7 @@ if (_zIndex < 5) then { // _dirvec = _pos vectorFromTo ((player modelToWorldVisualWorld (player selectionPosition "Spine3"))); // _dirvec = _dirvec vectorMultiply 100; // _can setVelocity _dirvec; - [DFUNC(doExplosions), 0, [_explosions, 0]] call CBA_fnc_addPerFrameHandler; + [LINKFUNC(doExplosions), 0, [_explosions, 0]] call CBA_fnc_addPerFrameHandler; [_pfhID] call CBA_fnc_removePerFrameHandler; }; END_COUNTER(fnc_findReflections); diff --git a/addons/frag/functions/fnc_fired.sqf b/addons/frag/functions/fnc_fired.sqf index 7ea4212d9a..03d2fab609 100644 --- a/addons/frag/functions/fnc_fired.sqf +++ b/addons/frag/functions/fnc_fired.sqf @@ -19,7 +19,7 @@ //IGNORE_PRIVATE_WARNING ["_unit", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile", "_vehicle", "_gunner", "_turret"]; TRACE_10("firedEH:",_unit,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile,_vehicle,_gunner,_turret); -private _shouldAdd = GVAR(cacheRoundsTypesToTrack) getVariable _ammo; +private _shouldAdd = GVAR(cacheRoundsTypesToTrack) get _ammo; if (isNil "_shouldAdd") then { TRACE_1("no cache for round",_ammo); @@ -40,7 +40,7 @@ if (isNil "_shouldAdd") then { }; TRACE_6("Setting Cache",_skip,_explosive,_indirectRange,_force,_fragPower,_shouldAdd); - GVAR(cacheRoundsTypesToTrack) setVariable [_ammo, _shouldAdd]; + GVAR(cacheRoundsTypesToTrack) set [_ammo, _shouldAdd]; }; if (_shouldAdd) then { diff --git a/addons/map/XEH_postInitClient.sqf b/addons/map/XEH_postInitClient.sqf index ea3ce19464..534b37da8b 100644 --- a/addons/map/XEH_postInitClient.sqf +++ b/addons/map/XEH_postInitClient.sqf @@ -8,7 +8,7 @@ LOG(MSG_INIT); // Calculate the maximum zoom allowed for this map call FUNC(determineZoom); -GVAR(flashlights) = [] call CBA_fnc_createNamespace; +GVAR(flashlights) = createHashMap; ["CBA_settingsInitialized", { if (isMultiplayer && {GVAR(DefaultChannel) != -1}) then { diff --git a/addons/map/functions/fnc_isFlashlight.sqf b/addons/map/functions/fnc_isFlashlight.sqf index e563d74114..ae26b41569 100644 --- a/addons/map/functions/fnc_isFlashlight.sqf +++ b/addons/map/functions/fnc_isFlashlight.sqf @@ -17,14 +17,12 @@ params [["_class", "", [""]]]; -private _isFlashlight = GVAR(flashlights) getVariable _class; - -if (isNil "_isFlashlight") then { +GVAR(flashlights) getOrDefaultCall [_class, { private _items = ([_class] + (_class call CBA_fnc_switchableAttachments)); private _cfgWeapons = configFile >> "CfgWeapons"; // if this item or any of the switchable items is a flashlight - _isFlashlight = _items findIf { + _items findIf { private _weaponConfig = _cfgWeapons >> _x; [ @@ -34,10 +32,5 @@ if (isNil "_isFlashlight") then { isText (_x >> "ACE_Flashlight_Colour") || {!(getArray (_x >> "ambient") in [[], [0,0,0]]) && {getNumber (_x >> "irLight") == 0}} } != -1 // return - } != -1; - - // cache value - GVAR(flashlights) setVariable [_class, _isFlashlight]; -}; - -_isFlashlight // return + } != -1 // return +}, true] // return diff --git a/addons/map_gestures/XEH_preInit.sqf b/addons/map_gestures/XEH_preInit.sqf index e603e5398a..42090ac724 100644 --- a/addons/map_gestures/XEH_preInit.sqf +++ b/addons/map_gestures/XEH_preInit.sqf @@ -8,6 +8,6 @@ PREP_RECOMPILE_END; #include "initSettings.inc.sqf" -GVAR(GroupColorCfgMappingNew) = call CBA_fnc_createNamespace; +GVAR(GroupColorCfgMappingNew) = createHashMap; ADDON = true; diff --git a/addons/map_gestures/functions/fnc_addGroupColorMapping.sqf b/addons/map_gestures/functions/fnc_addGroupColorMapping.sqf index 17a8ffbb04..d7d1bd3305 100644 --- a/addons/map_gestures/functions/fnc_addGroupColorMapping.sqf +++ b/addons/map_gestures/functions/fnc_addGroupColorMapping.sqf @@ -28,4 +28,4 @@ if (_group == "") exitWith {ERROR("Group ID is blank, which is not valid.")}; if (!([_leadColor] call FUNC(isValidColorArray))) exitWith {ERROR("leadColor is not a valid color array.")}; if (!([_unitColor] call FUNC(isValidColorArray))) exitWith {ERROR("color is not a valid color array.")}; -GVAR(GroupColorCfgMappingNew) setVariable [_group, [_leadColor, _unitColor]]; +GVAR(GroupColorCfgMappingNew) set [toLower _group, [_leadColor, _unitColor]]; diff --git a/addons/map_gestures/functions/fnc_drawMapGestures.sqf b/addons/map_gestures/functions/fnc_drawMapGestures.sqf index 2f0c80de3e..0a69c1924b 100644 --- a/addons/map_gestures/functions/fnc_drawMapGestures.sqf +++ b/addons/map_gestures/functions/fnc_drawMapGestures.sqf @@ -41,7 +41,7 @@ private _players = [_positions, FUNC(getProximityPlayers), missionNamespace, QGV }; // If color settings for the group exist, then use those, otherwise fall back to the default colors - private _colorMap = GVAR(GroupColorCfgMappingNew) getVariable [(groupID (group _x)), [GVAR(defaultLeadColor), GVAR(defaultColor)]]; + private _colorMap = GVAR(GroupColorCfgMappingNew) getOrDefault [toLower groupID (group _x), [GVAR(defaultLeadColor), GVAR(defaultColor)]]; private _color = _colorMap select (_x != leader _x); TRACE_2("",_colorMap,_color); diff --git a/addons/medical_blood/XEH_preInit.sqf b/addons/medical_blood/XEH_preInit.sqf index 852b4dbe73..93da039be5 100644 --- a/addons/medical_blood/XEH_preInit.sqf +++ b/addons/medical_blood/XEH_preInit.sqf @@ -8,22 +8,8 @@ PREP_RECOMPILE_END; #include "initSettings.inc.sqf" -// Damage types which do not cause blood spurts -GVAR(noBloodDamageTypes) = createHashMapFromArray (call (uiNamespace getVariable QGVAR(noBloodDamageTypes))); - // blood object model namespace -GVAR(models) = [] call CBA_fnc_createNamespace; - -{ - _x params ["_name", "_model"]; - - // createSimpleObject expects a path without the leading slash - if ((_model select [0,1]) isEqualTo "\") then { - _model = _model select [1]; - }; - - GVAR(models) setVariable [_name, _model]; -} forEach [ +GVAR(models) = createHashMapFromArray [ // higher number means bigger model ["blooddrop_1", QPATHTOF(data\ace_drop_1.p3d)], ["blooddrop_2", QPATHTOF(data\ace_drop_2.p3d)], diff --git a/addons/medical_blood/XEH_preStart.sqf b/addons/medical_blood/XEH_preStart.sqf index d051879f3c..e2683ff586 100644 --- a/addons/medical_blood/XEH_preStart.sqf +++ b/addons/medical_blood/XEH_preStart.sqf @@ -4,7 +4,4 @@ // Damage types which do not cause blood spurts private _noBloodDamageTypes = "getNumber (_x >> 'noBlood') == 1" configClasses (configFile >> "ACE_Medical_Injuries" >> "damageTypes"); -uiNamespace setVariable [ - QGVAR(noBloodDamageTypes), - compileFinal str (_noBloodDamageTypes apply {[configName _x, nil]}) -]; +uiNamespace setVariable [QGVAR(noBloodDamageTypes), compileFinal (_noBloodDamageTypes createHashMapFromArray [])]; diff --git a/addons/medical_blood/functions/fnc_createBlood.sqf b/addons/medical_blood/functions/fnc_createBlood.sqf index e6740ef459..fbff6cc3c6 100644 --- a/addons/medical_blood/functions/fnc_createBlood.sqf +++ b/addons/medical_blood/functions/fnc_createBlood.sqf @@ -21,7 +21,7 @@ params ["_type", "_position", "_source"]; TRACE_3("Creating blood",_type,_position,_source); -private _model = GVAR(models) getVariable _type; +private _model = GVAR(models) get _type; private _bloodDrop = createSimpleObject [_model, [0, 0, 0]]; _bloodDrop setDir random 360; diff --git a/addons/medical_blood/functions/fnc_handleWoundReceived.sqf b/addons/medical_blood/functions/fnc_handleWoundReceived.sqf index 8b46233af2..53d5d2361b 100644 --- a/addons/medical_blood/functions/fnc_handleWoundReceived.sqf +++ b/addons/medical_blood/functions/fnc_handleWoundReceived.sqf @@ -22,7 +22,7 @@ params ["_unit", "_allDamages", "_shooter", "_damageType"]; (_allDamages select 0) params ["_damage"]; // Don't bleed if damage type does not cause bleeding -if (_damageType in GVAR(noBloodDamageTypes)) exitWith {}; +if (_damageType in (uiNamespace getVariable QGVAR(noBloodDamageTypes))) exitWith {}; // Don't bleed when players only and a non-player unit is wounded if (GVAR(enabledFor) == BLOOD_ONLY_PLAYERS && {!isPlayer _unit && {_unit != ACE_player}}) exitWith {}; diff --git a/addons/medical_engine/XEH_preInit.sqf b/addons/medical_engine/XEH_preInit.sqf index ee27143bde..aa6954e744 100644 --- a/addons/medical_engine/XEH_preInit.sqf +++ b/addons/medical_engine/XEH_preInit.sqf @@ -40,11 +40,12 @@ GVAR(armorCache) = createHashMap; // with handle damage not returning full results. GVAR(fixedStatics) = []; -GVAR(animations) = [] call CBA_fnc_createNamespace; -GVAR(animations) setVariable [QUNCON_ANIM(faceUp), [QUNCON_ANIM(2),QUNCON_ANIM(2_1),QUNCON_ANIM(7_1),QUNCON_ANIM(8_1),QUNCON_ANIM(5_1),QUNCON_ANIM(6_1)]]; -GVAR(animations) setVariable [QUNCON_ANIM(faceDown), [QUNCON_ANIM(1),QUNCON_ANIM(3),QUNCON_ANIM(4),"unconscious",QUNCON_ANIM(9),QUNCON_ANIM(3_1),QUNCON_ANIM(4_1)]]; -GVAR(animations) setVariable [QUNCON_ANIM(faceLeft), [QUNCON_ANIM(7),QUNCON_ANIM(8),QUNCON_ANIM(1_1),QUNCON_ANIM(7_1),QUNCON_ANIM(8_1)]]; -GVAR(animations) setVariable [QUNCON_ANIM(faceRight), [QUNCON_ANIM(5),QUNCON_ANIM(6),QUNCON_ANIM(10),QUNCON_ANIM(5_1),QUNCON_ANIM(6_1)]]; +GVAR(animations) = createHashMapFromArray [ + [QUNCON_ANIM(faceUp), [QUNCON_ANIM(2),QUNCON_ANIM(2_1),QUNCON_ANIM(7_1),QUNCON_ANIM(8_1),QUNCON_ANIM(5_1),QUNCON_ANIM(6_1)]], + [QUNCON_ANIM(faceDown), [QUNCON_ANIM(1),QUNCON_ANIM(3),QUNCON_ANIM(4),"unconscious",QUNCON_ANIM(9),QUNCON_ANIM(3_1),QUNCON_ANIM(4_1)]], + [QUNCON_ANIM(faceLeft), [QUNCON_ANIM(7),QUNCON_ANIM(8),QUNCON_ANIM(1_1),QUNCON_ANIM(7_1),QUNCON_ANIM(8_1)]], + [QUNCON_ANIM(faceRight), [QUNCON_ANIM(5),QUNCON_ANIM(6),QUNCON_ANIM(10),QUNCON_ANIM(5_1),QUNCON_ANIM(6_1)]] +]; GVAR(customHitpoints) = ["hitleftarm", "hitrightarm", "hitleftleg", "hitrightleg"]; diff --git a/addons/medical_engine/functions/fnc_applyAnimAfterRagdoll.sqf b/addons/medical_engine/functions/fnc_applyAnimAfterRagdoll.sqf index db522b2bf7..d834f37774 100644 --- a/addons/medical_engine/functions/fnc_applyAnimAfterRagdoll.sqf +++ b/addons/medical_engine/functions/fnc_applyAnimAfterRagdoll.sqf @@ -23,7 +23,7 @@ if !(IS_UNCONSCIOUS(_unit) && // do not run if unit is conscio {alive _unit && // do not run if unit is dead {isNull objectParent _unit}}) exitWith {}; // do not run if unit in any vehicle -private _animsArray = GVAR(animations) getVariable [_anim, [""]]; +private _animsArray = GVAR(animations) getOrDefault [_anim, [""]]; private _random = (toArray (hashValue _unit)) param [0, 0]; private _index = _random % (count _animsArray); private _unconsciousAnimation = _animsArray select _index; diff --git a/addons/medical_treatment/XEH_preInit.sqf b/addons/medical_treatment/XEH_preInit.sqf index bc01e267c1..e6210a7372 100644 --- a/addons/medical_treatment/XEH_preInit.sqf +++ b/addons/medical_treatment/XEH_preInit.sqf @@ -14,27 +14,23 @@ PREP_RECOMPILE_END; // adjusting these is trail and error // if the animation is cut of ingame, increase these values // if the unit idles too much, decrease them -GVAR(animDurations) = [] call CBA_fnc_createNamespace; - -{ - GVAR(animDurations) setVariable _x; -} forEach [ - ["AinvPknlMstpSlayWnonDnon_medic", 7.5], - ["AinvPpneMstpSlayWnonDnon_medic", 7], - ["AinvPknlMstpSlayWrflDnon_medic", 7], - ["AinvPpneMstpSlayWrflDnon_medic", 9.5], - ["AinvPknlMstpSlayWlnrDnon_medic", 9], - ["AinvPknlMstpSlayWpstDnon_medic", 9.5], - ["AinvPpneMstpSlayWpstDnon_medic", 10], - ["AinvPknlMstpSlayWnonDnon_medicOther", 8.5], - ["AinvPpneMstpSlayWnonDnon_medicOther", 8.5], - ["AinvPknlMstpSlayWrflDnon_medicOther", 7], - ["AinvPpneMstpSlayWrflDnon_medicOther", 9], - ["AinvPknlMstpSlayWlnrDnon_medicOther", 9], - ["AinvPknlMstpSlayWpstDnon_medicOther", 10], - ["AinvPpneMstpSlayWpstDnon_medicOther", 8.5], - ["AinvPknlMstpSnonWnonDnon_medic1", 10], - ["AinvPknlMstpSnonWnonDr_medic0", 12] +GVAR(animDurations) = createHashMapFromArray [ + ["ainvpknlmstpslaywnondnon_medic", 7.5], + ["ainvppnemstpslaywnondnon_medic", 7], + ["ainvpknlmstpslaywrfldnon_medic", 7], + ["ainvppnemstpslaywrfldnon_medic", 9.5], + ["ainvpknlmstpslaywlnrdnon_medic", 9], + ["ainvpknlmstpslaywpstdnon_medic", 9.5], + ["ainvppnemstpslaywpstdnon_medic", 10], + ["ainvpknlmstpslaywnondnon_medicother", 8.5], + ["ainvppnemstpslaywnondnon_medicother", 8.5], + ["ainvpknlmstpslaywrfldnon_medicother", 7], + ["ainvppnemstpslaywrfldnon_medicother", 9], + ["ainvpknlmstpslaywlnrdnon_medicother", 9], + ["ainvpknlmstpslaywpstdnon_medicother", 10], + ["ainvppnemstpslaywpstdnon_medicother", 8.5], + ["ainvpknlmstpsnonwnondnon_medic1", 10], + ["ainvpknlmstpsnonwnondr_medic0", 12] ]; // class names of medical facilities (config case) diff --git a/addons/medical_treatment/functions/fnc_treatment.sqf b/addons/medical_treatment/functions/fnc_treatment.sqf index c524fd7ebb..5f6df40e31 100644 --- a/addons/medical_treatment/functions/fnc_treatment.sqf +++ b/addons/medical_treatment/functions/fnc_treatment.sqf @@ -76,7 +76,7 @@ if (_medic isNotEqualTo player || {!_isInZeus}) then { }; // Determine the animation length - private _animDuration = GVAR(animDurations) getVariable _medicAnim; + private _animDuration = GVAR(animDurations) get toLowerANSI _medicAnim; if (isNil "_animDuration") then { WARNING_2("animation [%1] for [%2] has no duration defined",_medicAnim,_classname); _animDuration = 10; diff --git a/addons/minedetector/XEH_postInit.sqf b/addons/minedetector/XEH_postInit.sqf index 77f2f6761c..f5f5de0ca8 100644 --- a/addons/minedetector/XEH_postInit.sqf +++ b/addons/minedetector/XEH_postInit.sqf @@ -1,16 +1,7 @@ #include "script_component.hpp" // Create a dictionary to store detector configs -GVAR(detectorConfigs) = call CBA_fnc_createNamespace; - -// Create a dictionary of detectable classnames -GVAR(detectableClasses) = call CBA_fnc_createNamespace; - -private _detectableClasses = call (uiNamespace getVariable [QGVAR(detectableClasses), {[]}]); //See XEH_preStart.sqf -{ - GVAR(detectableClasses) setVariable [_x, true]; -} forEach _detectableClasses; -TRACE_1("built cache",count allVariables GVAR(detectableClasses)); +GVAR(detectorConfigs) = createHashMap; [QGVAR(enableDetector), LINKFUNC(enableDetector)] call CBA_fnc_addEventHandler; [QGVAR(disableDetector), LINKFUNC(disableDetector)] call CBA_fnc_addEventHandler; diff --git a/addons/minedetector/XEH_preStart.sqf b/addons/minedetector/XEH_preStart.sqf index 48f003d08e..046c037364 100644 --- a/addons/minedetector/XEH_preStart.sqf +++ b/addons/minedetector/XEH_preStart.sqf @@ -15,5 +15,5 @@ private _detectableClasses = []; }; } forEach (configProperties [configFile >> "CfgAmmo", "isClass _x", true]); -TRACE_1("compiled",count _detectableClasses); -uiNamespace setVariable [QGVAR(detectableClasses), compileFinal str _detectableClasses]; +TRACE_1("built cache",count _detectableClasses); +uiNamespace setVariable [QGVAR(detectableClasses), compileFinal (_detectableClasses createHashMapFromArray [])]; diff --git a/addons/minedetector/functions/fnc_getDetectedObject.sqf b/addons/minedetector/functions/fnc_getDetectedObject.sqf index 810e4d4ff4..7811b3eaaa 100644 --- a/addons/minedetector/functions/fnc_getDetectedObject.sqf +++ b/addons/minedetector/functions/fnc_getDetectedObject.sqf @@ -38,15 +38,13 @@ private _mine = objNull; private _distance = -1; { - private _objectType = typeOf _x; - - _isDetectable = GVAR(detectableClasses) getVariable _objectType; - if (isNil "_isDetectable" || {(getModelInfo _x) select 0 == "empty.p3d"}) then { - _isDetectable = false; + if ((getModelInfo _x) select 0 == "empty.p3d") then { + continue; }; - // If a nun-null object was detected exit the search - if (_isDetectable && {!isNull _x}) exitWith { + // If an object was detected, exit the search + if ((typeOf _x) in (uiNamespace getVariable QGVAR(detectableClasses))) exitWith { + _isDetectable = true; _distance = _detectorPointAGL distance _x; _mine = _x; TRACE_3("return",_isDetectable,_mine,_distance); diff --git a/addons/minedetector/functions/fnc_getDetectorConfig.sqf b/addons/minedetector/functions/fnc_getDetectorConfig.sqf index fe7a888ebf..a5566cbfbf 100644 --- a/addons/minedetector/functions/fnc_getDetectorConfig.sqf +++ b/addons/minedetector/functions/fnc_getDetectorConfig.sqf @@ -19,18 +19,15 @@ params ["_detectorType"]; if (_detectorType isEqualTo "") exitWith {[]}; -private _detectorConfig = GVAR(detectorConfigs) getVariable _detectorType; -if (isNil "_detectorConfig") then { +GVAR(detectorConfigs) getOrDefaultCall [_detectorType, { private _cfgEntry = (configFile >> "ACE_detector" >> "detectors" >> _detectorType); if (isClass _cfgEntry) then { - _detectorConfig = [ + [ _detectorType, getNumber (_cfgEntry >> "radius"), getArray (_cfgEntry >> "sounds") ]; } else { - _detectorConfig = []; + [] }; - GVAR(detectorConfigs) setVariable [_detectorType, _detectorConfig]; -}; -_detectorConfig +}, true] diff --git a/addons/nametags/XEH_postInit.sqf b/addons/nametags/XEH_postInit.sqf index 85115690b4..a3fb7307f2 100644 --- a/addons/nametags/XEH_postInit.sqf +++ b/addons/nametags/XEH_postInit.sqf @@ -50,7 +50,7 @@ if (missionNamespace getVariable [QGVAR(useFactionIcons), true]) then { { if (isArray (_x >> QGVAR(rankIcons))) then { private _faction = configName _x; - if (!isNil {GVAR(factionRanks) getVariable _faction}) exitWith {}; // don't overwrite if already set + if (_faction in GVAR(factionRanks)) exitWith {}; // don't overwrite if already set private _icons = getArray (_x >> QGVAR(rankIcons)); [_faction, _icons] call FUNC(setFactionRankIcons); }; diff --git a/addons/nametags/functions/fnc_drawNameTagIcon.sqf b/addons/nametags/functions/fnc_drawNameTagIcon.sqf index 428cf037d5..efe0c6bf15 100644 --- a/addons/nametags/functions/fnc_drawNameTagIcon.sqf +++ b/addons/nametags/functions/fnc_drawNameTagIcon.sqf @@ -42,7 +42,7 @@ _fnc_parameters = { default { private _targetFaction = _target getVariable [QGVAR(faction), faction _target]; - private _customRankIcons = GVAR(factionRanks) getVariable _targetFaction; + private _customRankIcons = GVAR(factionRanks) get _targetFaction; if (!isNil "_customRankIcons") then { _customRankIcons param [ALL_RANKS find rank _target, ""] // return diff --git a/addons/nametags/functions/fnc_setFactionRankIcons.sqf b/addons/nametags/functions/fnc_setFactionRankIcons.sqf index 88fd880833..42d3ed40cb 100644 --- a/addons/nametags/functions/fnc_setFactionRankIcons.sqf +++ b/addons/nametags/functions/fnc_setFactionRankIcons.sqf @@ -25,7 +25,7 @@ */ if (isNil QGVAR(factionRanks)) then { - GVAR(factionRanks) = [] call CBA_fnc_createNamespace; + GVAR(factionRanks) = createHashMap; }; params [["_faction", "", [""]], ["_icons", [], [[]], [7]]]; @@ -33,6 +33,11 @@ TRACE_2("setFactionRankIcons",_faction,_icons); if !(_faction != "" && {_icons isEqualTypeAll ""}) exitWith {false}; -GVAR(factionRanks) setVariable [_faction, _icons]; +_faction = configName (configFile >> "CfgFactionClasses" >> _faction); + +// Faction doesn't exist +if (_faction == "") exitWith {false}; + +GVAR(factionRanks) set [_faction, _icons]; true diff --git a/addons/pylons/functions/fnc_showDialog.sqf b/addons/pylons/functions/fnc_showDialog.sqf index a06cb6f114..9c0faab52d 100644 --- a/addons/pylons/functions/fnc_showDialog.sqf +++ b/addons/pylons/functions/fnc_showDialog.sqf @@ -107,7 +107,7 @@ GVAR(comboBoxes) = []; private _mirroredIndex = getNumber (_x >> "mirroredMissilePos"); private _button = controlNull; - if (count allTurrets [_aircraft, false] > 0) then { + if ((allTurrets [_aircraft, false]) isNotEqualTo []) then { _button = _display ctrlCreate ["ctrlButtonPictureKeepAspect", -1]; private _turret = [_aircraft, _forEachIndex] call EFUNC(common,getPylonTurret); [_button, false, _turret] call FUNC(onButtonTurret); diff --git a/addons/rearm/XEH_postInit.sqf b/addons/rearm/XEH_postInit.sqf index 0c79790ec0..61ec35b8de 100644 --- a/addons/rearm/XEH_postInit.sqf +++ b/addons/rearm/XEH_postInit.sqf @@ -1,6 +1,5 @@ #include "script_component.hpp" -GVAR(hardpointGroupsCache) = [] call CBA_fnc_createNamespace; GVAR(configTypesAdded) = []; GVAR(magazineNameCache) = createHashMap; GVAR(usedMagazineNames) = createHashMap; diff --git a/addons/tagging/XEH_postInit.sqf b/addons/tagging/XEH_postInit.sqf index dd46b7fb98..02e082648a 100644 --- a/addons/tagging/XEH_postInit.sqf +++ b/addons/tagging/XEH_postInit.sqf @@ -1,14 +1,6 @@ // by esteldunedain #include "script_component.hpp" - -// Cache for static objects -GVAR(cacheStaticModels) = [false] call CBA_fnc_createNamespace; -private _cacheStaticModels = call (uiNamespace getVariable [QGVAR(cacheStaticModels), {[]}]); -{ - GVAR(cacheStaticModels) setVariable [_x, true]; -} forEach _cacheStaticModels; - if (hasInterface) then { // Compile and cache config tags call FUNC(compileConfigTags); diff --git a/addons/tagging/XEH_preStart.sqf b/addons/tagging/XEH_preStart.sqf index e1ac396c48..eb8f7ab767 100644 --- a/addons/tagging/XEH_preStart.sqf +++ b/addons/tagging/XEH_preStart.sqf @@ -26,9 +26,9 @@ private _cfgBase = configFile >> "CfgNonAIVehicles"; private _array = _model splitString "\"; _cacheStaticModels pushBackUnique toLowerANSI (_array select -1); }; -} forEach (_nonaivehicleClasses select {(configName _x) isKindOf ["Bridge_base_F", _cfgBase]}); +} forEach (_nonAIVehicleClasses select {(configName _x) isKindOf ["Bridge_base_F", _cfgBase]}); -uiNamespace setVariable [QGVAR(cacheStaticModels), compileFinal str _cacheStaticModels]; +uiNamespace setVariable [QGVAR(cacheStaticModels), compileFinal (_cacheStaticModels createHashMapFromArray [])]; TRACE_1("compiled",count _cacheStaticModels); // force preload of stencil texture to avoid error popup diff --git a/addons/tagging/functions/fnc_checkTaggable.sqf b/addons/tagging/functions/fnc_checkTaggable.sqf index 7eab60c1ba..ef20062a32 100644 --- a/addons/tagging/functions/fnc_checkTaggable.sqf +++ b/addons/tagging/functions/fnc_checkTaggable.sqf @@ -43,14 +43,14 @@ if (_object isKindOf "Static") exitWith {false}; // Taggable vehicle, do not exit - if (((_object getVariable [QGVAR(canTag), getNumber (configOf _object >> QGVAR(canTag))]) in [1, true]) + if (((_object getVariable [QGVAR(canTag), getNumber (configOf _object >> QGVAR(canTag))]) in [1, true]) && {getText (configOf _object >> "selectionClan") in selectionNames _object}) exitWith { false }; // If the class is not categorized correctly search the cache - private _modelName = (getModelInfo _object) select 0; - private _isStatic = GVAR(cacheStaticModels) getVariable [_modelName, false]; + private _modelName = toLowerANSI ((getModelInfo _object) select 0); + private _isStatic = _modelName in (uiNamespace getVariable QGVAR(cacheStaticModels)); TRACE_2("Object:",_modelName,_isStatic); // If the class in not on the cache, exit (!_isStatic) diff --git a/addons/tagging/functions/fnc_tag.sqf b/addons/tagging/functions/fnc_tag.sqf index aa0ba9fac9..f130e1322b 100644 --- a/addons/tagging/functions/fnc_tag.sqf +++ b/addons/tagging/functions/fnc_tag.sqf @@ -60,8 +60,8 @@ if ((!isNull _object) && { }; // If the class is not categorized correctly search the cache - private _modelName = (getModelInfo _object) select 0; - private _isStatic = GVAR(cacheStaticModels) getVariable [_modelName, false]; + private _modelName = toLowerANSI ((getModelInfo _object) select 0); + private _isStatic = _modelName in (uiNamespace getVariable QGVAR(cacheStaticModels)); TRACE_2("Object:",_modelName,_isStatic); // If the class in not on the cache, exit (!_isStatic) diff --git a/addons/ui/XEH_clientInit.sqf b/addons/ui/XEH_clientInit.sqf index d7f1df73fb..2c8cd3e4b4 100644 --- a/addons/ui/XEH_clientInit.sqf +++ b/addons/ui/XEH_clientInit.sqf @@ -4,11 +4,11 @@ if (!hasInterface) exitWith {}; // Compile and cache config UI -GVAR(configCache) = call CBA_fnc_createNamespace; +GVAR(configCache) = createHashMap; call FUNC(compileConfigUI); // Scripted API namespace -GVAR(elementsSet) = call CBA_fnc_createNamespace; +GVAR(elementsSet) = createHashMap; // Attach all event handlers where UI has to be updated ["CBA_settingsInitialized", { @@ -21,7 +21,7 @@ GVAR(elementsSet) = call CBA_fnc_createNamespace; // Defaults must be set in this EH to make sure controls are activated and advanced settings can be modified { [_x, missionNamespace getVariable (format [QGVAR(%1), _x]), false, !GVAR(allowSelectiveUI)] call FUNC(setAdvancedElement); - } forEach (allVariables GVAR(configCache)); + } forEach (keys GVAR(configCache)); // Execute local event for when it's safe to modify UI through this API // infoDisplayChanged can execute multiple times, make sure it only happens once @@ -40,8 +40,7 @@ GVAR(elementsSet) = call CBA_fnc_createNamespace; [true] call FUNC(setElements); } else { private _nameNoPrefix = toLowerANSI (_name select [7]); - private _cachedElement = GVAR(configCache) getVariable _nameNoPrefix; - if (!isNil "_cachedElement") then { + if (_nameNoPrefix in GVAR(configCache)) then { [_nameNoPrefix, _value, true] call FUNC(setAdvancedElement); }; }; diff --git a/addons/ui/functions/fnc_compileConfigUI.sqf b/addons/ui/functions/fnc_compileConfigUI.sqf index ef6ec1026a..960db9aed4 100644 --- a/addons/ui/functions/fnc_compileConfigUI.sqf +++ b/addons/ui/functions/fnc_compileConfigUI.sqf @@ -40,6 +40,6 @@ TRACE_1("Caching Condition",_x); } forEach (configProperties [_x >> "conditions"]); - GVAR(configCache) setVariable [_class, [_idd, _elements, _location, _conditions]]; + GVAR(configCache) set [_class, [_idd, _elements, _location, _conditions]]; }; } forEach ("true" configClasses (configFile >> "ACE_UI")); diff --git a/addons/ui/functions/fnc_setAdvancedElement.sqf b/addons/ui/functions/fnc_setAdvancedElement.sqf index 6751d9700c..86a1134802 100644 --- a/addons/ui/functions/fnc_setAdvancedElement.sqf +++ b/addons/ui/functions/fnc_setAdvancedElement.sqf @@ -20,7 +20,9 @@ params ["_element", "_show", ["_showHint", false, [true]], ["_force", false, [true]]]; -private _cachedElement = GVAR(configCache) getVariable _element; +_element = toLowerANSI _element; + +private _cachedElement = GVAR(configCache) get _element; if (isNil "_cachedElement") exitWith {TRACE_1("nil element",_this)}; if (!_force && {!GVAR(allowSelectiveUI)}) exitWith { @@ -56,7 +58,7 @@ if ( // Get setting from scripted API if (!_force) then { - private _setElement = GVAR(elementsSet) getVariable _element; + private _setElement = GVAR(elementsSet) get _element; if (!isNil "_setElement") then { _setElement params ["_sourceSet", "_showSet"]; if (_showHint) then { diff --git a/addons/ui/functions/fnc_setElementVisibility.sqf b/addons/ui/functions/fnc_setElementVisibility.sqf index f7f8dccd0c..938fb2da7d 100644 --- a/addons/ui/functions/fnc_setElementVisibility.sqf +++ b/addons/ui/functions/fnc_setElementVisibility.sqf @@ -32,12 +32,11 @@ if (_source == "" || {_element == ""}) exitWith { _element = toLowerANSI _element; // Verify element is bound -private _cachedElement = GVAR(configCache) getVariable _element; -if (isNil "_cachedElement") exitWith { +if !(_element in GVAR(configCache)) exitWith { WARNING_2("Element '%1' does not exist - modification by '%2' failed.",_element,_source); }; -private _setElement = GVAR(elementsSet) getVariable _element; +private _setElement = GVAR(elementsSet) get _element; private _return = false; if (isNil "_setElement") then { @@ -45,7 +44,7 @@ if (isNil "_setElement") then { private _success = [_element, _show, false, true] call FUNC(setAdvancedElement); if (_success) then { - GVAR(elementsSet) setVariable [_element, [_source, _show]]; + GVAR(elementsSet) set [_element, [_source, _show]]; _return = true; }; } else { @@ -57,7 +56,7 @@ if (isNil "_setElement") then { }; } else { TRACE_3("Unsetting element",_sourceSet,_element,_show); - GVAR(elementsSet) setVariable [_element, nil]; + GVAR(elementsSet) set [_element, nil]; [_element, _show, false, true] call FUNC(setAdvancedElement); _return = true; diff --git a/addons/weaponselect/XEH_preInit.sqf b/addons/weaponselect/XEH_preInit.sqf index 92ba1b06a6..e699f3d2f3 100644 --- a/addons/weaponselect/XEH_preInit.sqf +++ b/addons/weaponselect/XEH_preInit.sqf @@ -11,18 +11,22 @@ GVAR(GrenadesAll) = []; GVAR(GrenadesFrag) = []; GVAR(GrenadesNonFrag) = []; +private _cfgMagazines = configFile >> "CfgMagazines"; +private _cfgAmmo = configFile >> "CfgAmmo"; +private _cfgThrow = configFile >> "CfgWeapons" >> "Throw"; + { - private _magazines = getArray (configFile >> "CfgWeapons" >> "Throw" >> _x >> "magazines"); + private _magazines = getArray (_cfgThrow >> _x >> "magazines"); GVAR(GrenadesAll) append _magazines; { - private _ammo = getText (configFile >> "CfgMagazines" >> _x >> "ammo"); - private _explosive = getNumber (configFile >> "CfgAmmo" >> _ammo >> "explosive"); + private _ammo = getText (_cfgMagazines >> _x >> "ammo"); + private _explosive = getNumber (_cfgAmmo >> _ammo >> "explosive"); ([GVAR(GrenadesFrag), GVAR(GrenadesNonFrag)] select (_explosive == 0)) pushBack _x; } forEach _magazines; -} forEach getArray (configFile >> "CfgWeapons" >> "Throw" >> "muzzles"); +} forEach getArray (_cfgThrow >> "muzzles"); #include "initSettings.inc.sqf" diff --git a/addons/weaponselect/functions/fnc_selectNextGrenade.sqf b/addons/weaponselect/functions/fnc_selectNextGrenade.sqf index ff111a93f6..ad17c7f18d 100644 --- a/addons/weaponselect/functions/fnc_selectNextGrenade.sqf +++ b/addons/weaponselect/functions/fnc_selectNextGrenade.sqf @@ -61,14 +61,14 @@ private _vestGrenades = vestItems _unit select {_x in GVAR(GrenadesAll) private _backpackGrenades = backpackItems _unit select {_x in GVAR(GrenadesAll) && {_x != _nextGrenade}}; // remove all grenades except those we are switching to --> this breaks the selector -{_unit removeItemFromUniform _x; false} count _uniformGrenades; -{_unit removeItemFromVest _x; false} count _vestGrenades; -{_unit removeItemFromBackpack _x; false} count _backpackGrenades; +{_unit removeItemFromUniform _x} forEach _uniformGrenades; +{_unit removeItemFromVest _x} forEach _vestGrenades; +{_unit removeItemFromBackpack _x} forEach _backpackGrenades; // readd grenades -{_unit addItemToUniform _x; false} count _uniformGrenades; -{_unit addItemToVest _x; false} count _vestGrenades; -{_unit addItemToBackpack _x; false} count _backpackGrenades; +{_unit addItemToUniform _x} forEach _uniformGrenades; +{_unit addItemToVest _x} forEach _vestGrenades; +{_unit addItemToBackpack _x} forEach _backpackGrenades; [_nextGrenade, {_x == _nextGrenade} count _magazines] call FUNC(displayGrenadeTypeAndNumber); From 70b0a4c4343d6976477dfe3b4860df825f1bdeae Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Tue, 11 Jun 2024 12:37:43 -0500 Subject: [PATCH 090/290] Medical - Cleanup refs to hdBracket (#10064) --- addons/medical_engine/functions/fnc_handleDamage.sqf | 4 ++-- addons/medical_engine/script_macros_config.hpp | 7 ------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/addons/medical_engine/functions/fnc_handleDamage.sqf b/addons/medical_engine/functions/fnc_handleDamage.sqf index 61de4997b9..168203366c 100644 --- a/addons/medical_engine/functions/fnc_handleDamage.sqf +++ b/addons/medical_engine/functions/fnc_handleDamage.sqf @@ -53,7 +53,7 @@ if (!_structuralDamage) then { }; TRACE_6("Received hit",_hitpoint,_ammo,_newDamage,_realDamage,_directHit,_context); -// Drowning doesn't fire the EH for each hitpoint so the "ace_hdbracket" code never runs +// Drowning doesn't fire the EH for each hitpoint and never triggers _context=2 (LastHitPoint) // Damage occurs in consistent increments if ( _structuralDamage && @@ -71,7 +71,7 @@ private _vehicle = objectParent _unit; private _inVehicle = !isNull _vehicle; private _environmentDamage = _ammo == ""; -// Crashing a vehicle doesn't fire the EH for each hitpoint so the "ace_hdbracket" code never runs +// Crashing a vehicle doesn't fire the EH for each hitpoint and never triggers _context=2 (LastHitPoint) // It does fire the EH multiple times, but this seems to scale with the intensity of the crash if ( EGVAR(medical,enableVehicleCrashes) && diff --git a/addons/medical_engine/script_macros_config.hpp b/addons/medical_engine/script_macros_config.hpp index 7f65a4b912..4c276d7b18 100644 --- a/addons/medical_engine/script_macros_config.hpp +++ b/addons/medical_engine/script_macros_config.hpp @@ -20,13 +20,6 @@ // This used to take the armor values as parameters; it now inherits the values // of `armor`, `passThrough` and `explosionShielding` from the existing hitpoints // for vanilla consistency. -// "ACE_HDBracket" is a special hit point. It is designed in a way where the -// "HandleDamage" event handler will compute it at the end of every damage -// calculation step. This way we can figure out which hit point took the most -// damage from one projectile and should be receiving the ACE medical wound. -// the hit point itself should not take any damage -// It is important that the "ACE_HDBracket" hit point is the last in the config, -// but has the same selection as the first one (always "HitHead" for soldiers). #define ADD_ACE_HITPOINTS\ class HitLeftArm: HitHands {\ material = -1;\ From 690ee553698dd29e525058ce91d79023a415f072 Mon Sep 17 00:00:00 2001 From: Mike-MF Date: Thu, 13 Jun 2024 13:10:20 +0100 Subject: [PATCH 091/290] Compat CUP Units - Goggles Compatibility (#10065) --- addons/compat_cup_units/CfgGlasses.hpp | 492 +++++++++++++++++++++++++ addons/compat_cup_units/config.cpp | 1 + 2 files changed, 493 insertions(+) create mode 100644 addons/compat_cup_units/CfgGlasses.hpp diff --git a/addons/compat_cup_units/CfgGlasses.hpp b/addons/compat_cup_units/CfgGlasses.hpp new file mode 100644 index 0000000000..1620f74212 --- /dev/null +++ b/addons/compat_cup_units/CfgGlasses.hpp @@ -0,0 +1,492 @@ +class CfgGlasses { + + #define ESS_OVERLAY \ + ace_overlay = QPATHTOEF(goggles,textures\hud\combatgoggles.paa); \ + ace_overlayCracked = QPATHTOEF(goggles,textures\hud\combatgogglescracked.paa) + + class None; + class CUP_G_PMC_RadioHeadset_Glasses; + + // ESS Goggles - Dark + class CUP_G_ESS_BLK_Dark: None { + ace_protection = 1; + ace_resistance = 1; + ace_tintAmount = 8; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_Blk: None { + ace_protection = 1; + ace_resistance = 1; + ace_tintAmount = 8; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_Blk_Beard: None { + ace_protection = 1; + ace_resistance = 1; + ace_tintAmount = 8; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_Blk_Beard_Blonde: None { + ace_protection = 1; + ace_resistance = 1; + ace_tintAmount = 8; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_Face_Blk: None { + ace_protection = 1; + ace_resistance = 1; + ace_tintAmount = 8; + ESS_OVERLAY; + }; + class CUP_G_ESS_CBR_Dark: None { + ace_protection = 1; + ace_resistance = 1; + ace_tintAmount = 8; + ESS_OVERLAY; + }; + class CUP_G_ESS_KHK_Dark: None { + ace_protection = 1; + ace_resistance = 1; + ace_tintAmount = 8; + ESS_OVERLAY; + }; + class CUP_G_ESS_RGR_Dark: None { + ace_protection = 1; + ace_resistance = 1; + ace_tintAmount = 8; + ESS_OVERLAY; + }; + + // ESS Goggles - Ember + class CUP_G_ESS_BLK_Ember: None { + ace_color[] = {1, 0, 0}; + ace_protection = 1; + ace_resistance = 1; + ace_tintAmount = 8; + ESS_OVERLAY; + }; + class CUP_G_ESS_CBR_Ember: None { + ace_color[] = {1, 0, 0}; + ace_protection = 1; + ace_resistance = 1; + ace_tintAmount = 8; + ESS_OVERLAY; + }; + class CUP_G_ESS_RGR_Ember: None { + ace_color[] = {1, 0, 0}; + ace_protection = 1; + ace_resistance = 1; + ace_tintAmount = 8; + ESS_OVERLAY; + }; + class CUP_G_ESS_KHK_Ember: None { + ace_color[] = {1, 0, 0}; + ace_protection = 1; + ace_resistance = 1; + ace_tintAmount = 8; + ESS_OVERLAY; + }; + class CUP_G_ESS_KHK_Facewrap_White: None { + ace_color[] = {1, 0, 0}; + ace_protection = 1; + ace_resistance = 1; + ace_tintAmount = 8; + ESS_OVERLAY; + }; + + // ESS Goggles - Clear + class CUP_G_ESS_BLK: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_CBR: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_KHK: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_RGR: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Facewrap_Black: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Facewrap_Black_GPS: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_Face_Grn: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_Face_Grn_GPS: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_Face_Red: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_Face_White: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_Face_White_GPS: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_Grn: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_Grn_Beard: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_Grn_Beard_Blonde: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_Grn_GPS: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_Grn_GPS_Beard: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_Grn_GPS_Beard_Blonde: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_Red: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_Red_Beard: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_Red_Beard_Blonde: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_White: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_White_Beard: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_White_Beard_Blonde: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_White_GPS: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_White_GPS_Beard: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_BLK_Scarf_White_GPS_Beard_Blonde: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_CBR_Facewrap_Red: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_KHK_Facewrap_Tan: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_KHK_Scarf_Face_Tan: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_KHK_Scarf_Face_Tan_GPS: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_KHK_Scarf_Tan: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_KHK_Scarf_Tan_Beard: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_KHK_Scarf_Tan_Beard_Blonde: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_KHK_Scarf_Tan_GPS: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_KHK_Scarf_Tan_GPS_Beard: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_KHK_Scarf_Tan_GPS_Beard_Blonde: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_RGR_Facewrap_Ranger: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_RGR_Facewrap_Skull: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + class CUP_G_ESS_RGR_Facewrap_Tropical: None { + ace_protection = 1; + ace_resistance = 1; + ESS_OVERLAY; + }; + + // Oakleys - Dark + class CUP_G_Oakleys_Drk: None { + ace_resistance = 1; + ace_tintAmount = 8; + }; + class CUP_G_PMC_Facewrap_Black_Glasses_Dark: None { + ace_resistance = 1; + ace_tintAmount = 8; + }; + class CUP_G_PMC_Facewrap_Black_Glasses_Dark_Headset: None { + ace_resistance = 1; + ace_tintAmount = 8; + }; + class CUP_G_PMC_Facewrap_Tan_Glasses_Dark: CUP_G_PMC_Facewrap_Black_Glasses_Dark { + ace_resistance = 1; + ace_tintAmount = 8; + }; + class CUP_G_PMC_Facewrap_Tan_Glasses_Dark_Headset: None { + ace_resistance = 1; + ace_tintAmount = 8; + }; + class CUP_G_PMC_Facewrap_Tropical_Glasses_Dark: CUP_G_PMC_Facewrap_Black_Glasses_Dark { + ace_resistance = 1; + ace_tintAmount = 8; + }; + class CUP_G_PMC_Facewrap_Tropical_Glasses_Dark_Headset: None { + ace_resistance = 1; + ace_tintAmount = 8; + }; + class CUP_G_PMC_Facewrap_Winter_Glasses_Dark: CUP_G_PMC_Facewrap_Black_Glasses_Dark { + ace_resistance = 1; + ace_tintAmount = 8; + }; + class CUP_G_PMC_Facewrap_Winter_Glasses_Dark_Headset: None { + ace_resistance = 1; + ace_tintAmount = 8; + }; + class CUP_G_PMC_RadioHeadset_Glasses_Dark: CUP_G_PMC_RadioHeadset_Glasses { + ace_resistance = 1; + ace_tintAmount = 8; + }; + + // Oakleys - Ember + class CUP_G_Oakleys_Embr: None { + ace_color[] = {1, 0, 0}; + ace_resistance = 1; + ace_tintAmount = 8; + }; + class CUP_G_PMC_Facewrap_Black_Glasses_Ember: CUP_G_PMC_Facewrap_Black_Glasses_Dark { + ace_color[] = {1, 0, 0}; + ace_resistance = 1; + ace_tintAmount = 8; + }; + class CUP_G_PMC_Facewrap_Tan_Glasses_Ember: CUP_G_PMC_Facewrap_Black_Glasses_Dark { + ace_color[] = {1, 0, 0}; + ace_resistance = 1; + ace_tintAmount = 8; + }; + class CUP_G_PMC_Facewrap_Tropical_Glasses_Ember: CUP_G_PMC_Facewrap_Black_Glasses_Dark { + ace_color[] = {1, 0, 0}; + ace_resistance = 1; + ace_tintAmount = 8; + }; + class CUP_G_PMC_Facewrap_Winter_Glasses_Ember: CUP_G_PMC_Facewrap_Black_Glasses_Dark { + ace_color[] = {1, 0, 0}; + ace_resistance = 1; + ace_tintAmount = 8; + }; + class CUP_G_PMC_RadioHeadset_Glasses_Ember: CUP_G_PMC_RadioHeadset_Glasses { + ace_color[] = {1, 0, 0}; + ace_resistance = 1; + ace_tintAmount = 8; + }; + + // Shades - Dark + class CUP_G_Beard_Shades_Black: None { + ace_resistance = 1; + ace_tintAmount = 8; + }; + class CUP_G_Beard_Shades_Blonde: CUP_G_Beard_Shades_Black { + ace_resistance = 1; + ace_tintAmount = 8; + }; + + // Shades - Clear + class CUP_G_Grn_Scarf_Shades: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_Grn_Scarf_Shades_Beard: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_Grn_Scarf_Shades_Beard_Blonde: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_Grn_Scarf_Shades_GPS: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_Grn_Scarf_Shades_GPS_Beard: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_Grn_Scarf_Shades_GPS_Beard_Blonde: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_Grn_Scarf_Shades_GPSCombo: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_Grn_Scarf_Shades_GPSCombo_Beard: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_Grn_Scarf_Shades_GPSCombo_Beard_Blonde: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_Tan_Scarf_Shades: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_Tan_Scarf_Shades_Beard: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_Tan_Scarf_Shades_Beard_Blonde: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_Tan_Scarf_Shades_GPS: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_Tan_Scarf_Shades_GPS_Beard: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_Tan_Scarf_Shades_GPS_Beard_Blonde: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_Tan_Scarf_Shades_GPSCombo: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_Tan_Scarf_Shades_GPSCombo_Beard: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_Tan_Scarf_Shades_GPSCombo_Beard_Blonde: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_White_Scarf_Shades: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_White_Scarf_Shades_Beard: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_White_Scarf_Shades_Beard_Blonde: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_White_Scarf_Shades_GPS: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_White_Scarf_Shades_GPS_Beard: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_White_Scarf_Shades_GPS_Beard_Blonde: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_White_Scarf_Shades_GPSCombo: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_White_Scarf_Shades_GPSCombo_Beard: None { + ace_protection = 1; + ace_resistance = 1; + }; + class CUP_G_White_Scarf_Shades_GPSCombo_Beard_Blonde: None { + ace_protection = 1; + ace_resistance = 1; + }; + + // Thug - Dark + class CUP_PMC_G_thug: None { + ace_tintAmount = 8; + }; +}; diff --git a/addons/compat_cup_units/config.cpp b/addons/compat_cup_units/config.cpp index bde1052a11..c3ba110e74 100644 --- a/addons/compat_cup_units/config.cpp +++ b/addons/compat_cup_units/config.cpp @@ -15,4 +15,5 @@ class CfgPatches { }; }; +#include "CfgGlasses.hpp" #include "CfgWeapons.hpp" From d4d69b914198ab2b8de9bbedd54a2e7e37837ece Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Thu, 13 Jun 2024 07:11:21 -0500 Subject: [PATCH 092/290] Medical Engine - Fix death animation hash keys (#10067) --- addons/medical_engine/XEH_preInit.sqf | 8 ++++---- .../functions/fnc_applyAnimAfterRagdoll.sqf | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/addons/medical_engine/XEH_preInit.sqf b/addons/medical_engine/XEH_preInit.sqf index aa6954e744..035b9f4b05 100644 --- a/addons/medical_engine/XEH_preInit.sqf +++ b/addons/medical_engine/XEH_preInit.sqf @@ -41,10 +41,10 @@ GVAR(armorCache) = createHashMap; GVAR(fixedStatics) = []; GVAR(animations) = createHashMapFromArray [ - [QUNCON_ANIM(faceUp), [QUNCON_ANIM(2),QUNCON_ANIM(2_1),QUNCON_ANIM(7_1),QUNCON_ANIM(8_1),QUNCON_ANIM(5_1),QUNCON_ANIM(6_1)]], - [QUNCON_ANIM(faceDown), [QUNCON_ANIM(1),QUNCON_ANIM(3),QUNCON_ANIM(4),"unconscious",QUNCON_ANIM(9),QUNCON_ANIM(3_1),QUNCON_ANIM(4_1)]], - [QUNCON_ANIM(faceLeft), [QUNCON_ANIM(7),QUNCON_ANIM(8),QUNCON_ANIM(1_1),QUNCON_ANIM(7_1),QUNCON_ANIM(8_1)]], - [QUNCON_ANIM(faceRight), [QUNCON_ANIM(5),QUNCON_ANIM(6),QUNCON_ANIM(10),QUNCON_ANIM(5_1),QUNCON_ANIM(6_1)]] + [toLowerANSI QUNCON_ANIM(faceUp), [QUNCON_ANIM(2),QUNCON_ANIM(2_1),QUNCON_ANIM(7_1),QUNCON_ANIM(8_1),QUNCON_ANIM(5_1),QUNCON_ANIM(6_1)]], + [toLowerANSI QUNCON_ANIM(faceDown), [QUNCON_ANIM(1),QUNCON_ANIM(3),QUNCON_ANIM(4),"unconscious",QUNCON_ANIM(9),QUNCON_ANIM(3_1),QUNCON_ANIM(4_1)]], + [toLowerANSI QUNCON_ANIM(faceLeft), [QUNCON_ANIM(7),QUNCON_ANIM(8),QUNCON_ANIM(1_1),QUNCON_ANIM(7_1),QUNCON_ANIM(8_1)]], + [toLowerANSI QUNCON_ANIM(faceRight), [QUNCON_ANIM(5),QUNCON_ANIM(6),QUNCON_ANIM(10),QUNCON_ANIM(5_1),QUNCON_ANIM(6_1)]] ]; GVAR(customHitpoints) = ["hitleftarm", "hitrightarm", "hitleftleg", "hitrightleg"]; diff --git a/addons/medical_engine/functions/fnc_applyAnimAfterRagdoll.sqf b/addons/medical_engine/functions/fnc_applyAnimAfterRagdoll.sqf index d834f37774..726a606344 100644 --- a/addons/medical_engine/functions/fnc_applyAnimAfterRagdoll.sqf +++ b/addons/medical_engine/functions/fnc_applyAnimAfterRagdoll.sqf @@ -23,7 +23,7 @@ if !(IS_UNCONSCIOUS(_unit) && // do not run if unit is conscio {alive _unit && // do not run if unit is dead {isNull objectParent _unit}}) exitWith {}; // do not run if unit in any vehicle -private _animsArray = GVAR(animations) getOrDefault [_anim, [""]]; +private _animsArray = GVAR(animations) getOrDefault [toLowerANSI _anim, [""]]; private _random = (toArray (hashValue _unit)) param [0, 0]; private _index = _random % (count _animsArray); private _unconsciousAnimation = _animsArray select _index; From 34362d48eb695fd41d243755f2cad06e3d337bac Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 13 Jun 2024 18:49:31 +0200 Subject: [PATCH 093/290] Grenades - Fix incendiary grenades damaging invulnerable objects (#10068) Disable damage from incendiaries when object is invulnerable --- addons/grenades/functions/fnc_incendiary.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/grenades/functions/fnc_incendiary.sqf b/addons/grenades/functions/fnc_incendiary.sqf index 337065cae3..f0c2effac3 100644 --- a/addons/grenades/functions/fnc_incendiary.sqf +++ b/addons/grenades/functions/fnc_incendiary.sqf @@ -183,7 +183,7 @@ if (isServer) then { // --- damage { - if (local _x) then { + if (local _x && {isDamageAllowed _x}) then { //systemChat format ["burn: %1", _x]; // --- destroy nearby static weapons and ammo boxes From 7a6c837f1b7884ebdc2bf834731170478ba89a5d Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Fri, 14 Jun 2024 20:02:13 +0200 Subject: [PATCH 094/290] Headless - Add warning about duplicate loadout validation (#9878) * Warn users about duplicate loadout validation * Update XEH_postInit.sqf --- addons/headless/XEH_postInit.sqf | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/addons/headless/XEH_postInit.sqf b/addons/headless/XEH_postInit.sqf index d1106b40c9..90677042f4 100644 --- a/addons/headless/XEH_postInit.sqf +++ b/addons/headless/XEH_postInit.sqf @@ -1,5 +1,7 @@ #include "script_component.hpp" +if (!isMultiplayer) exitWith {}; + ["CBA_settingsInitialized", { // Register and remove HCs if not client that is not server and distribution or end mission enabled if ((!hasInterface || isServer) && {XGVAR(enabled) || XGVAR(endMission) != 0}) then { @@ -25,6 +27,23 @@ (_rebalance == FORCED_REBALANCE) call FUNC(rebalance); }; }] call CBA_fnc_addEventHandler; + + // If CBA's loadout validation is enabled, warn users + if (XGVAR(transferLoadout) > 0 && {(missionNamespace getVariable ["CBA_network_loadoutValidation", 0]) isEqualTo 2}) then { + WARNING("CBA_network_loadoutValidation is enabled - acex_headless_transferLoadout should therefore be disabled"); + [QEGVAR(common,displayTextStructured), ["CBA_network_loadoutValidation is enabled - acex_headless_transferLoadout should therefore be disabled", 3]] call CBA_fnc_globalEvent; + }; + + ["CBA_SettingChanged", { + params ["_setting", "_value"]; + + if (_setting != "CBA_network_loadoutValidation") exitWith {}; + + if (XGVAR(transferLoadout) > 0 && {_value isEqualTo 2}) then { + WARNING("CBA_network_loadoutValidation is enabled - acex_headless_transferLoadout should therefore be disabled"); + [QEGVAR(common,displayTextStructured), ["CBA_network_loadoutValidation is enabled - acex_headless_transferLoadout should therefore be disabled", 3]] call CBA_fnc_globalEvent; + }; + }] call CBA_fnc_addEventHandler; } else { // Register HC (this part happens on HC only) [QXGVAR(headlessClientJoined), [player]] call CBA_fnc_globalEvent; // Global event for API purposes From 2dc0cd4fc4f7ee2ddc858dc4fbaeecf7c6b3d17e Mon Sep 17 00:00:00 2001 From: Mike-MF Date: Fri, 14 Jun 2024 22:21:53 +0100 Subject: [PATCH 095/290] Documentation - Remove Hashes from Coding guidelines (#10072) Remove Hashes from Coding guidelines --- docs/wiki/development/coding-guidelines.md | 75 ---------------------- 1 file changed, 75 deletions(-) diff --git a/docs/wiki/development/coding-guidelines.md b/docs/wiki/development/coding-guidelines.md index 786a5d74e8..fcecbfbce4 100644 --- a/docs/wiki/development/coding-guidelines.md +++ b/docs/wiki/development/coding-guidelines.md @@ -632,81 +632,6 @@ player addEventHandler ["Fired", FUNC(handleFired)]; // bad player addEventHandler ["Fired", {call FUNC(handleFired)}]; // good ``` -### 7.4 Hashes - -When a key value pair is required, make use of the hash implementation from ACE3. - -Hashes are a variable type that store key value pairs. They are not implemented natively in SQF, so there are a number of macros and functions for their usage in ACE3. If you are unfamiliar with the idea, they are similar in function to `setVariable`/`getVariable` but do not require an object to use. - -The following example is a simple usage using our macros which will be explained further below. - -```sqf -_hash = HASHCREATE; -HASH_SET(_hash,"key","value"); -if (HASH_HASKEY(_hash,"key")) then { - player sideChat format ["val: %1", HASH_GET(_hash,"key"); // will print out "val: value" -}; -HASH_REM(_hash,"key"); -if (HASH_HASKEY(_hash,"key")) then { - // this will never execute because we removed the hash key/val pair "key" -}; -``` - -A description of the above macros is below. - -| Macro | Use | -| ------|-------| -|`HASHCREATE` | Used to create an empty hash. | -|`HASH_SET(hash,key,val)` | Will set the hash key to that value, a key can be anything, even objects. | -|`HASH_GET(hash,key)` | Will return the value of that key (or nil if it doesn't exist). | -|`HASH_HASKEY(hash,key)` | Will return true/false if that key exists in the hash. | -|`HASH_REM(hash,key)` | Will remove that hash key. | - -#### 7.4.1 Hashlists - -A hashlist is an extension of a hash. It is a list of hashes! The reason for having this special type of storage container rather than using a normal array is that an array of normal hashes that are similar will duplicate a large amount of data in their storage of keys. A hashlist on the other hand uses a common list of keys and an array of unique value containers. The following will demonstrate its usage. - -```sqf -_defaultKeys = ["key1", "key2", "key3"]; -// create a new hashlist using the above keys as default -_hashList = HASHLIST_CREATELIST(_defaultKeys); - -//lets get a blank hash template out of this hashlist -_hash = HASHLIST_CREATEHASH(_hashList); - -//_hash is now a standard hash... -HASH_SET(_hash,"key1","1"); - -//to store it to the list we need to push it to the list -HASHLIST_PUSH(_hashList, _hash); - -//now lets get it out and store it in something else for fun -//it was pushed to an empty list, so it's index is 0 -_anotherHash = HASHLIST_SELECT(_hashList,0); - -// this should print "val: 1" -player sideChat format["val: %1", HASH_GET(_anotherHash,"key1")]; - -//Say we need to add a new key to the hashlist -//that we didn't initialize it with? We can simply -//set a new key using the standard HASH_SET macro -HASH_SET(_anotherHash,"anotherKey","another value"); -``` - -As you can see above working with hashlists are fairly simple, a more in depth explanation of the macros is below. - -| Macro | Use | -| -------|---------| -|`HASHLIST_CREATELIST(keys)` | Creates a new hashlist with the default keys, pass [] for no default keys. | -|`HASHLIST_CREATEHASH(hashlist)` | Returns a blank hash template from a hashlist. | -|`HASHLIST_PUSH(hashList, hash)` | Pushes a new hash onto the end of the list. | -|`HASHLIST_SELECT(hashlist, index)` | Returns the hash at that index in the list. | -|`HASHLIST_SET(hashlist, index, hash)` | Sets a specific index to that hash. | - -##### 7.4.1.1 A note on pass by reference and hashes - -Hashes and hashlists are implemented with SQF arrays, and as such they are passed by reference to other functions. Remember to make copies (using the `+` operator) if you intend for the hash or hashlist to be modified with out the need for changing the original value. - ## 8. Performance Considerations ### 8.1 Adding Elements to Arrays From f3722bf5e868e8cd317f038fe2163cdeb359dc91 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sun, 16 Jun 2024 03:59:01 +0200 Subject: [PATCH 096/290] Cookoff - Fix engine fire not starting (#10074) Fix engine fire not starting --- addons/cookoff/XEH_postInit.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/cookoff/XEH_postInit.sqf b/addons/cookoff/XEH_postInit.sqf index b99212c5b7..63e1486c82 100644 --- a/addons/cookoff/XEH_postInit.sqf +++ b/addons/cookoff/XEH_postInit.sqf @@ -9,7 +9,7 @@ if (isServer) then { [QGVAR(cookOffBoxServer), LINKFUNC(cookOffBoxServer)] call CBA_fnc_addEventHandler; [QGVAR(cookOffServer), LINKFUNC(cookOffServer)] call CBA_fnc_addEventHandler; [QGVAR(detonateAmmunitionServer), LINKFUNC(detonateAmmunitionServer)] call CBA_fnc_addEventHandler; - [QGVAR(engineFireServer), LINKFUNC(engineFire)] call CBA_fnc_addEventHandler; + [QGVAR(engineFireServer), LINKFUNC(engineFireServer)] call CBA_fnc_addEventHandler; }; // Handle cleaning up effects when objects are deleted mid cook-off From c28a3d6cdfbc2159f8a0e042dcf42cd4aa02b2a9 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Sun, 16 Jun 2024 22:04:40 -0500 Subject: [PATCH 097/290] Kill Tracker - Add setting to show kills from vehicle to crew (#10069) * Kill Tracker - Add setting to show kills from vehicle to crew * Update addons/killtracker/XEH_postInit.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --------- Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- addons/killtracker/XEH_postInit.sqf | 43 +++++++++++-------- addons/killtracker/initSettings.inc.sqf | 9 ++++ addons/killtracker/stringtable.xml | 6 +++ .../functions/fnc_enteredStateDeath.sqf | 3 +- 4 files changed, 43 insertions(+), 18 deletions(-) diff --git a/addons/killtracker/XEH_postInit.sqf b/addons/killtracker/XEH_postInit.sqf index c5adc26692..73ade6c94b 100644 --- a/addons/killtracker/XEH_postInit.sqf +++ b/addons/killtracker/XEH_postInit.sqf @@ -73,11 +73,11 @@ GVAR(killCount) = 0; }; }; private _unitIsPlayer = hasInterface && {_unit in [player, ace_player]}; // isPlayer check will fail at this point - private _killerIsPlayer = (!isNull _instigator) && {_unit != _instigator} && {[_instigator] call EFUNC(common,isPlayer)}; - TRACE_2("",_unitIsPlayer,_killerIsPlayer); + private _instigatorIsPlayer = (!isNull _instigator) && {_unit != _instigator} && {[_instigator] call EFUNC(common,isPlayer)}; + TRACE_2("",_unitIsPlayer,_instigatorIsPlayer); // Don't do anything if neither are players - if (!(_unitIsPlayer || _killerIsPlayer)) exitWith {}; + if (!(_unitIsPlayer || _instigatorIsPlayer)) exitWith {}; // Log firendly fire private _fnc_getSideFromConfig = { @@ -110,23 +110,23 @@ GVAR(killCount) = 0; // If unit was player then send event to self if (_unitIsPlayer) then { - private _killerName = "Self?"; - if ((!isNull _killer) && {_unit != _killer}) then { - if (_killerIsPlayer) then { - _killerName = [_killer, true, false] call EFUNC(common,getName); + private _instigatorName = "Self?"; + if ((!isNull _instigator) && {_unit != _instigator}) then { + if (_instigatorIsPlayer) then { + _instigatorName = [_instigator, true, false] call EFUNC(common,getName); } else { - _killerName = _killer getVariable [QGVAR(aiName), ""]; // allow setting a custom AI name (e.g. VIP Target) - if (_killerName == "") then { - _killerName = format ["*AI* - %1", getText ((configOf _killer) >> "displayName")]; + _instigatorName = _instigator getVariable [QGVAR(aiName), ""]; // allow setting a custom AI name (e.g. VIP Target) + if (_instigatorName == "") then { + _instigatorName = format ["*AI* - %1", getText ((configOf _instigator) >> "displayName")]; }; }; }; - TRACE_3("send death event",_unit,_killerName,_killInfo); - [QGVAR(death), [_killerName, _killInfo]] call CBA_fnc_localEvent; + TRACE_3("send death event",_unit,_instigatorName,_killInfo); + [QGVAR(death), [_instigatorName, _killInfo]] call CBA_fnc_localEvent; }; - // If killer was player then send event to killer - if (_killerIsPlayer) then { + // If shooter was player then send event to them (and optionally the whole crew) + if (_instigatorIsPlayer && {_unitIsPlayer || GVAR(trackAI)}) then { private _unitName = ""; if (_unitIsPlayer) then { _unitName = [_unit, true, false] call EFUNC(common,getName); // should be same as profileName @@ -136,9 +136,18 @@ GVAR(killCount) = 0; _unitName = format ["*AI* - %1", getText ((configOf _unit) >> "displayName")]; }; }; - if (_unitIsPlayer || GVAR(trackAI)) then { - TRACE_3("send kill event",_killer,_unitName,_killInfo); - [QGVAR(kill), [_unitName, _killInfo], _killer] call CBA_fnc_targetEvent; + TRACE_3("send kill event",_instigator,_unitName,_killInfo); + [QGVAR(kill), [_unitName, _killInfo], _instigator] call CBA_fnc_targetEvent; + + if (GVAR(showCrewKills) && {!(_killer isKindOf "CAManBase")}) then { + private _crew = [driver _killer, gunner _killer, commander _killer] - [_instigator]; + _crew = _crew select {[_x] call EFUNC(common,isPlayer)}; + _crew = _crew arrayIntersect _crew; + TRACE_1("showCrewKills",_crew); + _killInfo = format [" - [%1, %2", localize "str_a3_rscdisplaygarage_tab_crew", _killInfo select [4]]; + { + [QGVAR(kill), [_unitName, _killInfo], _x] call CBA_fnc_targetEvent; + } forEach _crew; }; }; }] call CBA_fnc_addEventHandler; diff --git a/addons/killtracker/initSettings.inc.sqf b/addons/killtracker/initSettings.inc.sqf index ebe1e55ccb..9e4775bd7f 100644 --- a/addons/killtracker/initSettings.inc.sqf +++ b/addons/killtracker/initSettings.inc.sqf @@ -6,3 +6,12 @@ true, 1 ] call CBA_fnc_addSetting; + +[ + QGVAR(showCrewKills), + "CHECKBOX", + [LSTRING(showCrewKills_DisplayName), LSTRING(showCrewKills_Description)], + LSTRING(Category), + false, + 1 +] call CBA_fnc_addSetting; diff --git a/addons/killtracker/stringtable.xml b/addons/killtracker/stringtable.xml index 5b2f8f9de8..916dac6877 100644 --- a/addons/killtracker/stringtable.xml +++ b/addons/killtracker/stringtable.xml @@ -119,5 +119,11 @@ Legt fest, ob getötete KIs während des Endbildschirms der Mission in den Abschüssen angezeigt werden. Define si las IAs matadas se mostrarán en el contador de muertes en el debiefring de la misión. + + Show vehicle kills to other crew members + + + Show kills from a vehicle to driver, gunner and commander + diff --git a/addons/medical_statemachine/functions/fnc_enteredStateDeath.sqf b/addons/medical_statemachine/functions/fnc_enteredStateDeath.sqf index 537c356651..8be1d358df 100644 --- a/addons/medical_statemachine/functions/fnc_enteredStateDeath.sqf +++ b/addons/medical_statemachine/functions/fnc_enteredStateDeath.sqf @@ -25,6 +25,7 @@ if (isNull _unit || {!isNil {_unit getVariable QEGVAR(medical,causeOfDeath)}}) e TRACE_4("enteredStateDeath",_this,_thisOrigin,_thisTransition,CBA_missionTime); private _causeOfDeath = format ["%1:%2", _thisOrigin, _thisTransition]; +private _source = _unit getVariable [QEGVAR(medical,lastDamageSource), objNull]; private _instigator = _unit getVariable [QEGVAR(medical,lastInstigator), objNull]; -[_unit, _causeOfDeath, _instigator] call EFUNC(medical_status,setDead); +[_unit, _causeOfDeath, _source, _instigator] call EFUNC(medical_status,setDead); From 421071027e827de2c6316ec089b7b01baa0d81cd Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 17 Jun 2024 19:31:35 +0200 Subject: [PATCH 098/290] Common - Add wheel hitpoint function (#10075) * Add wheel hitpoint function * Moved cache to missionNamespace --- addons/common/XEH_PREP.hpp | 1 + addons/common/XEH_preInit.sqf | 1 + .../fnc_getWheelHitPointsWithSelections.sqf | 104 ++++++++++++++++++ .../functions/fnc_damageEngineAndWheels.sqf | 28 +---- addons/repair/XEH_PREP.hpp | 1 - addons/repair/dev/draw_showRepairInfo.sqf | 3 +- .../repair/functions/fnc_addRepairActions.sqf | 2 +- .../functions/fnc_getSelectionsToIgnore.sqf | 2 +- .../fnc_getWheelHitPointsWithSelections.sqf | 97 ---------------- 9 files changed, 116 insertions(+), 123 deletions(-) create mode 100644 addons/common/functions/fnc_getWheelHitPointsWithSelections.sqf delete mode 100644 addons/repair/functions/fnc_getWheelHitPointsWithSelections.sqf diff --git a/addons/common/XEH_PREP.hpp b/addons/common/XEH_PREP.hpp index 5a2893eeaf..f46d1689f9 100644 --- a/addons/common/XEH_PREP.hpp +++ b/addons/common/XEH_PREP.hpp @@ -103,6 +103,7 @@ PREP(getWeaponAzimuthAndInclination); PREP(getWeaponIndex); PREP(getWeaponState); PREP(getWeight); +PREP(getWheelHitPointsWithSelections); PREP(getWindDirection); PREP(getZoom); PREP(goKneeling); diff --git a/addons/common/XEH_preInit.sqf b/addons/common/XEH_preInit.sqf index 9b5d27d12c..b559cb5dd9 100644 --- a/addons/common/XEH_preInit.sqf +++ b/addons/common/XEH_preInit.sqf @@ -10,6 +10,7 @@ PREP_RECOMPILE_END; GVAR(syncedEvents) = createHashMap; GVAR(showHudHash) = createHashMap; GVAR(vehicleIconCache) = createHashMap; // for getVehicleIcon +GVAR(wheelSelections) = createHashMap; GVAR(blockItemReplacement) = false; diff --git a/addons/common/functions/fnc_getWheelHitPointsWithSelections.sqf b/addons/common/functions/fnc_getWheelHitPointsWithSelections.sqf new file mode 100644 index 0000000000..2194c2aca0 --- /dev/null +++ b/addons/common/functions/fnc_getWheelHitPointsWithSelections.sqf @@ -0,0 +1,104 @@ +#include "..\script_component.hpp" +/* + * Author: commy2, johnb43 + * Returns the wheel hitpoints and their selections. + * + * Arguments: + * 0: Vehicle + * + * Return Value: + * 0: Wheel hitpoints + * 1: Wheel hitpoint selections + * + * Example: + * cursorObject call ace_common_fnc_getWheelHitPointsWithSelections + * + * Public: No + */ + +params ["_vehicle"]; +TRACE_1("params",_vehicle); + +// TODO: Fix for GM vehicles +GVAR(wheelSelections) getOrDefaultCall [typeOf _vehicle, { + // Get the vehicles wheel config + private _wheels = configOf _vehicle >> "Wheels"; + + if (isClass _wheels) then { + // Get all hitpoints and selections + (getAllHitPointsDamage _vehicle) params ["_hitPoints", "_hitPointSelections"]; + + // Get all wheels and read selections from config + _wheels = "true" configClasses _wheels; + + private _wheelHitPoints = []; + private _wheelHitPointSelections = []; + + { + private _wheelName = configName _x; + private _wheelCenter = getText (_x >> "center"); + private _wheelBone = getText (_x >> "boneName"); + private _wheelBoneNameResized = _wheelBone select [0, 9]; // Count "wheel_X_Y"; // this is a requirement for physx. Should work for all addon vehicles. + + TRACE_4("",_wheelName,_wheelCenter,_wheelBone,_wheelBoneNameResized); + + private _wheelHitPoint = ""; + private _wheelHitPointSelection = ""; + + // Commy's orginal method + { + if ((_wheelBoneNameResized != "") && {_x find _wheelBoneNameResized == 0}) exitWith { // same as above. Requirement for physx. + _wheelHitPoint = _hitPoints select _forEachIndex; + _wheelHitPointSelection = _hitPointSelections select _forEachIndex; + TRACE_2("wheel found [Orginal]",_wheelName,_wheelHitPoint); + }; + } forEach _hitPointSelections; + + + if (_vehicle isKindOf "Car") then { + // Backup method, search for the closest hitpoint to the wheel's center selection pos. + // Ref #2742 - RHS's HMMWV + if (_wheelHitPoint == "") then { + private _wheelCenterPos = _vehicle selectionPosition _wheelCenter; + if (_wheelCenterPos isEqualTo [0, 0, 0]) exitWith {TRACE_1("no center?",_wheelCenter);}; + + + private _bestDist = 99; + private _bestIndex = -1; + { + if (_x != "") then { + // Filter out things that definitly aren't wheeels (#3759) + if ((toLowerANSI (_hitPoints select _forEachIndex)) in ["hitengine", "hitfuel", "hitbody"]) exitWith {TRACE_1("filter",_x)}; + private _xPos = _vehicle selectionPosition _x; + if (_xPos isEqualTo [0, 0, 0]) exitWith {}; + private _xDist = _wheelCenterPos distance _xPos; + if (_xDist < _bestDist) then { + _bestIndex = _forEachIndex; + _bestDist = _xDist; + }; + }; + } forEach _hitPointSelections; + + TRACE_2("closestPoint",_bestDist,_bestIndex); + if (_bestIndex != -1) then { + _wheelHitPoint = _hitPoints select _bestIndex; + _wheelHitPointSelection = _hitPointSelections select _bestIndex; + TRACE_2("wheel found [Backup]",_wheelName,_wheelHitPoint); + }; + }; + }; + + if ((_wheelHitPoint != "") && {_wheelHitPointSelection != ""}) then { + _wheelHitPoints pushBack _wheelHitPoint; + _wheelHitPointSelections pushBack _wheelHitPointSelection; + }; + } forEach _wheels; + + [_wheelHitPoints, _wheelHitPointSelections] + } else { + // Exit with nothing if the vehicle has no wheels class + TRACE_1("No Wheels",_wheels); + + [[], []] + } +}, true] // return diff --git a/addons/grenades/functions/fnc_damageEngineAndWheels.sqf b/addons/grenades/functions/fnc_damageEngineAndWheels.sqf index fa0032e87e..ab95ecbe6a 100644 --- a/addons/grenades/functions/fnc_damageEngineAndWheels.sqf +++ b/addons/grenades/functions/fnc_damageEngineAndWheels.sqf @@ -17,38 +17,22 @@ */ params ["_vehicle", "_position"]; -TRACE_1("damageWheelsAndEngine",_vehicle); +TRACE_2("damageWheelsAndEngine",_vehicle,_position); // Vehicle needs to be local and vulnerable if !(local _vehicle && {isDamageAllowed _vehicle}) exitWith {}; -// Burn tires -private _fnc_isWheelHitPoint = { - params ["_selectionName"]; - // Wheels must use a selection named "wheel_X_Y_steering" for PhysX to work - _selectionName select [0, 6] == "wheel_" && { - _selectionName select [count _selectionName - 9] == "_steering" - } // return -}; - -private _config = configOf _vehicle >> "HitPoints"; - { - private _wheelSelection = getText (_config >> _x >> "name"); - - if (_wheelSelection call _fnc_isWheelHitPoint) then { - private _wheelPosition = _vehicle modelToWorld (_vehicle selectionPosition _wheelSelection); - - if (_position distance _wheelPosition < EFFECT_SIZE * 2) then { - _vehicle setHit [_wheelSelection, 1]; - }; + // If wheel is close enough to incendiary, burn it + if (_position distance (_vehicle modelToWorld (_vehicle selectionPosition _x)) < EFFECT_SIZE * 2) then { + _vehicle setHit [_x, 1]; }; -} forEach (getAllHitPointsDamage _vehicle param [0, []]); +} forEach ((_vehicle call EFUNC(common,getWheelHitPointsWithSelections)) select 1); // Burn car engines only if (_vehicle isKindOf "Wheeled_APC_F") exitWith {}; -private _engineSelection = getText (_config >> "HitEngine" >> "name"); +private _engineSelection = getText (configOf _vehicle >> "HitPoints" >> "HitEngine" >> "name"); private _enginePosition = _vehicle modelToWorld (_vehicle selectionPosition _engineSelection); if (_position distance _enginePosition < EFFECT_SIZE * 2) then { diff --git a/addons/repair/XEH_PREP.hpp b/addons/repair/XEH_PREP.hpp index 186ec0b310..16e11b7476 100644 --- a/addons/repair/XEH_PREP.hpp +++ b/addons/repair/XEH_PREP.hpp @@ -25,7 +25,6 @@ PREP(getSelectionsToIgnore); PREP(getPatchWheelTime); PREP(getPostRepairDamage); PREP(getRepairItems); -PREP(getWheelHitPointsWithSelections); PREP(hasItems); PREP(isEngineer); PREP(isInRepairFacility); diff --git a/addons/repair/dev/draw_showRepairInfo.sqf b/addons/repair/dev/draw_showRepairInfo.sqf index 20bf748e7f..122f209739 100644 --- a/addons/repair/dev/draw_showRepairInfo.sqf +++ b/addons/repair/dev/draw_showRepairInfo.sqf @@ -4,6 +4,7 @@ #include "..\script_component.hpp" addMissionEventHandler ["Draw3D", { + if (isGamePaused) exitWith {}; if !((cursorObject isKindOf "Car") || (cursorObject isKindOf "Tank") || (cursorObject isKindOf "Air")) exitWith {}; private _config = configOf cursorObject; @@ -11,7 +12,7 @@ addMissionEventHandler ["Draw3D", { private _hitpointGroups = getArray (_config >> QGVAR(hitpointGroups)); (getAllHitPointsDamage cursorObject) params [["_hitPoints", []], ["_hitSelections", []]]; - ([cursorObject] call FUNC(getWheelHitPointsWithSelections)) params ["_wheelHitPoints", "_wheelHitSelections"]; + ([cursorObject] call EFUNC(common,getWheelHitPointsWithSelections)) params ["_wheelHitPoints", "_wheelHitSelections"]; private _output = []; diff --git a/addons/repair/functions/fnc_addRepairActions.sqf b/addons/repair/functions/fnc_addRepairActions.sqf index 9dad1ecc31..16711d7b8a 100644 --- a/addons/repair/functions/fnc_addRepairActions.sqf +++ b/addons/repair/functions/fnc_addRepairActions.sqf @@ -37,7 +37,7 @@ private _selectionsToIgnore = _vehicle call FUNC(getSelectionsToIgnore); (getAllHitPointsDamage _vehicle) params [["_hitPoints", []], ["_hitSelections", []]]; // Since 1.82 these are all lower case // get hitpoints of wheels with their selections -([_vehicle] call FUNC(getWheelHitPointsWithSelections)) params ["_wheelHitPoints", "_wheelHitSelections"]; +([_vehicle] call EFUNC(common,getWheelHitPointsWithSelections)) params ["_wheelHitPoints", "_wheelHitSelections"]; private _hitPointsAddedNames = []; private _hitPointsAddedStrings = []; diff --git a/addons/repair/functions/fnc_getSelectionsToIgnore.sqf b/addons/repair/functions/fnc_getSelectionsToIgnore.sqf index 08ca639a20..58f916185c 100644 --- a/addons/repair/functions/fnc_getSelectionsToIgnore.sqf +++ b/addons/repair/functions/fnc_getSelectionsToIgnore.sqf @@ -28,7 +28,7 @@ private _turretPaths = ((fullCrew [_vehicle, "gunner", true]) + (fullCrew [_vehi (getAllHitPointsDamage _vehicle) params [["_hitPoints", []], ["_hitSelections", []]]; // get hitpoints of wheels with their selections -([_vehicle] call FUNC(getWheelHitPointsWithSelections)) params ["_wheelHitPoints", "_wheelHitSelections"]; +([_vehicle] call EFUNC(common,getWheelHitPointsWithSelections)) params ["_wheelHitPoints", "_wheelHitSelections"]; private _indexesToIgnore = []; private _processedSelections = []; diff --git a/addons/repair/functions/fnc_getWheelHitPointsWithSelections.sqf b/addons/repair/functions/fnc_getWheelHitPointsWithSelections.sqf deleted file mode 100644 index 5d655887c6..0000000000 --- a/addons/repair/functions/fnc_getWheelHitPointsWithSelections.sqf +++ /dev/null @@ -1,97 +0,0 @@ -#include "..\script_component.hpp" -/* - * Author: commy2 - * Returns the wheel hitpoints and their selections. - * - * Arguments: - * 0: Vehicle - * - * Return Value: - * 0: Wheel hitpoints - * 1: Wheel hitpoint selections in model coordinates - * - * Example: - * [car1] call ace_repair_fnc_getWheelHitPointsWithSelections - * - * Public: No - */ - -params ["_vehicle"]; -TRACE_1("params",_vehicle); - -// get the vehicles wheel config -private _wheels = configOf _vehicle >> "Wheels"; - -// exit with nothing if the vehicle has no wheels class -if !(isClass _wheels) exitWith {TRACE_1("No Wheels",_wheels); [[],[]]}; - -// get all hitpoints and selections -(getAllHitPointsDamage _vehicle) params ["_hitPoints", "_hitPointSelections"]; - -// get all wheels and read selections from config -_wheels = "true" configClasses _wheels; - -private _wheelHitPoints = []; -private _wheelHitPointSelections = []; - -{ - private _wheelName = configName _x; - private _wheelCenter = getText (_x >> "center"); - private _wheelBone = getText (_x >> "boneName"); - private _wheelBoneNameResized = _wheelBone select [0, 9]; //ount "wheel_X_Y"; // this is a requirement for physx. Should work for all addon vehicles. - - TRACE_4("",_wheelName,_wheelCenter,_wheelBone,_wheelBoneNameResized); - - private _wheelHitPoint = ""; - private _wheelHitPointSelection = ""; - - //Commy's orginal method - { - if ((_wheelBoneNameResized != "") && {_x find _wheelBoneNameResized == 0}) exitWith { // same as above. Requirement for physx. - _wheelHitPoint = _hitPoints select _forEachIndex; - _wheelHitPointSelection = _hitPointSelections select _forEachIndex; - TRACE_2("wheel found [Orginal]",_wheelName,_wheelHitPoint); - }; - } forEach _hitPointSelections; - - - if (_vehicle isKindOf "Car") then { - //Backup method, search for the closest hitpoint to the wheel's center selection pos. - //Ref #2742 - RHS's HMMWV - if (_wheelHitPoint == "") then { - private _wheelCenterPos = _vehicle selectionPosition _wheelCenter; - if (_wheelCenterPos isEqualTo [0,0,0]) exitWith {TRACE_1("no center?",_wheelCenter);}; - - - private _bestDist = 99; - private _bestIndex = -1; - { - if (_x != "") then { - //Filter out things that definitly aren't wheeels (#3759) - if ((toLowerANSI (_hitPoints select _forEachIndex)) in ["hitengine", "hitfuel", "hitbody"]) exitWith {TRACE_1("filter",_x)}; - private _xPos = _vehicle selectionPosition _x; - if (_xPos isEqualTo [0,0,0]) exitWith {}; - private _xDist = _wheelCenterPos distance _xPos; - if (_xDist < _bestDist) then { - _bestIndex = _forEachIndex; - _bestDist = _xDist; - }; - }; - } forEach _hitPointSelections; - - TRACE_2("closestPoint",_bestDist,_bestIndex); - if (_bestIndex != -1) then { - _wheelHitPoint = _hitPoints select _bestIndex; - _wheelHitPointSelection = _hitPointSelections select _bestIndex; - TRACE_2("wheel found [Backup]",_wheelName,_wheelHitPoint); - }; - }; - }; - - if ((_wheelHitPoint != "") && {_wheelHitPointSelection != ""}) then { - _wheelHitPoints pushBack _wheelHitPoint; - _wheelHitPointSelections pushBack _wheelHitPointSelection; - }; -} forEach _wheels; - -[_wheelHitPoints, _wheelHitPointSelections] From 95b7951919389ac768893bfdd1d5fbcaf0dd060f Mon Sep 17 00:00:00 2001 From: Grim <69561145+LinkIsGrim@users.noreply.github.com> Date: Mon, 17 Jun 2024 21:07:38 -0300 Subject: [PATCH 099/290] General - Use variable for checking if medical is enabled (#10063) --- addons/advanced_fatigue/XEH_postInit.sqf | 2 +- addons/advanced_fatigue/XEH_preInit.sqf | 1 - addons/advanced_fatigue/functions/fnc_mainLoop.sqf | 2 +- addons/common/functions/fnc_setDead.sqf | 2 +- .../functions/fnc_handlePunjiTrapTrigger.sqf | 2 +- addons/dogtags/XEH_postInit.sqf | 8 +++++--- addons/dragging/functions/fnc_dropObject_carry.sqf | 2 +- addons/field_rations/XEH_postInit.sqf | 2 +- addons/field_rations/functions/fnc_handleEffects.sqf | 11 ++++++----- addons/gforces/functions/fnc_pfhUpdateGForces.sqf | 2 +- .../grenades/functions/fnc_flashbangExplosionEH.sqf | 2 +- addons/interaction/functions/fnc_canPullOutBody.sqf | 2 +- addons/killtracker/XEH_postInit.sqf | 2 +- addons/medical_blood/XEH_postInit.sqf | 2 -- addons/medical_blood/functions/fnc_isBleeding.sqf | 2 +- addons/medical_blood/functions/fnc_onBleeding.sqf | 2 +- addons/overpressure/functions/fnc_firedEHBB.sqf | 2 +- .../overpressure/functions/fnc_overpressureDamage.sqf | 2 +- addons/vehicle_damage/functions/fnc_medicalDamage.sqf | 2 +- addons/zeus/functions/fnc_moduleHeal.sqf | 2 +- addons/zeus/functions/fnc_moduleSetMedic.sqf | 2 +- .../zeus/functions/fnc_moduleSetMedicalFacility.sqf | 2 +- addons/zeus/functions/fnc_moduleSetMedicalVehicle.sqf | 2 +- 23 files changed, 30 insertions(+), 30 deletions(-) diff --git a/addons/advanced_fatigue/XEH_postInit.sqf b/addons/advanced_fatigue/XEH_postInit.sqf index f5aa7432f0..08fd827d58 100644 --- a/addons/advanced_fatigue/XEH_postInit.sqf +++ b/addons/advanced_fatigue/XEH_postInit.sqf @@ -46,7 +46,7 @@ if (!hasInterface) exitWith {}; }, true] call CBA_fnc_addPlayerEventHandler; // - Duty factors ------------------------------------------------------------- - if (GVAR(medicalLoaded)) then { + if (GETEGVAR(medical,enabled,false)) then { [QEGVAR(medical,pain), { // 0->1.0, 0.5->1.05, 1->1.1 linearConversion [0, 1, (_this getVariable [QEGVAR(medical,pain), 0]), 1, 1.1, true]; }] call FUNC(addDutyFactor); diff --git a/addons/advanced_fatigue/XEH_preInit.sqf b/addons/advanced_fatigue/XEH_preInit.sqf index 9f58e44fdf..643b7b0be0 100644 --- a/addons/advanced_fatigue/XEH_preInit.sqf +++ b/addons/advanced_fatigue/XEH_preInit.sqf @@ -13,6 +13,5 @@ GVAR(dutyList) = createHashMap; GVAR(setAnimExclusions) = []; GVAR(inertia) = 0; GVAR(inertiaCache) = createHashMap; -GVAR(medicalLoaded) = ["ace_medical"] call EFUNC(common,isModLoaded); ADDON = true; diff --git a/addons/advanced_fatigue/functions/fnc_mainLoop.sqf b/addons/advanced_fatigue/functions/fnc_mainLoop.sqf index da469b6d21..add9b6e5d8 100644 --- a/addons/advanced_fatigue/functions/fnc_mainLoop.sqf +++ b/addons/advanced_fatigue/functions/fnc_mainLoop.sqf @@ -25,7 +25,7 @@ if (!alive ACE_player) exitWith { private _oxygen = 0.9; // Default AF oxygen saturation -if (GVAR(medicalLoaded) && {EGVAR(medical_vitals,simulateSpo2)}) then { +if (GETEGVAR(medical,enabled,false) && {EGVAR(medical_vitals,simulateSpo2)}) then { _oxygen = (ACE_player getVariable [QEGVAR(medical,spo2), 97]) / 100; }; diff --git a/addons/common/functions/fnc_setDead.sqf b/addons/common/functions/fnc_setDead.sqf index 316f7346cc..f6d62abd34 100644 --- a/addons/common/functions/fnc_setDead.sqf +++ b/addons/common/functions/fnc_setDead.sqf @@ -24,7 +24,7 @@ if (!local _unit) exitWith { WARNING_1("setDead executed on non-local unit - %1",_this); }; -if (["ace_medical"] call EFUNC(common,isModLoaded)) then { +if (GETEGVAR(medical,enabled,false)) then { [_unit, _reason, _source, _instigator] call EFUNC(medical_status,setDead); } else { // From 'ace_medical_status_fnc_setDead': Kill the unit without changing visual appearance diff --git a/addons/compat_sog/functions/fnc_handlePunjiTrapTrigger.sqf b/addons/compat_sog/functions/fnc_handlePunjiTrapTrigger.sqf index d2e9abdbbc..dc51a3140c 100644 --- a/addons/compat_sog/functions/fnc_handlePunjiTrapTrigger.sqf +++ b/addons/compat_sog/functions/fnc_handlePunjiTrapTrigger.sqf @@ -15,7 +15,7 @@ * Public: No */ params ["_trap"]; -if (!(["ace_medical"] call EFUNC(common,isModLoaded))) exitWith {}; +if !(GETEGVAR(medical,enabled,false)) exitWith {}; private _radius = getNumber (configOf _trap >> "indirectHitRange"); private _affectedUnits = _trap nearEntities ["CAManBase", _radius]; diff --git a/addons/dogtags/XEH_postInit.sqf b/addons/dogtags/XEH_postInit.sqf index d9c35dc172..dae6b62247 100644 --- a/addons/dogtags/XEH_postInit.sqf +++ b/addons/dogtags/XEH_postInit.sqf @@ -5,9 +5,11 @@ [QGVAR(getDogtagItem), LINKFUNC(getDogtagItem)] call CBA_fnc_addEventHandler; [QGVAR(addDogtagItem), LINKFUNC(addDogtagItem)] call CBA_fnc_addEventHandler; -// Add actions and event handlers only if ace_medical is loaded +// Add actions and event handlers only if ace_medical is enabled // - Adding actions via config would create a dependency -if (["ace_medical"] call EFUNC(common,isModLoaded)) then { +["CBA_settingsInitialized", { + if !(GETEGVAR(medical,enabled,false)) exitWith {}; + if (hasInterface) then { private _checkTagAction = [ "ACE_CheckDogtag", @@ -44,7 +46,7 @@ if (["ace_medical"] call EFUNC(common,isModLoaded)) then { }; }] call CBA_fnc_addEventHandler; }; -}; +}] call CBA_fnc_addEventHandler; // If the arsenal is loaded, show the custom names for dog tags when in the arsenal if (["ace_arsenal"] call EFUNC(common,isModLoaded)) then { diff --git a/addons/dragging/functions/fnc_dropObject_carry.sqf b/addons/dragging/functions/fnc_dropObject_carry.sqf index 184b1755c0..7a81d94a05 100644 --- a/addons/dragging/functions/fnc_dropObject_carry.sqf +++ b/addons/dragging/functions/fnc_dropObject_carry.sqf @@ -116,7 +116,7 @@ if (_loadCargo) then { private _vehicles = [_cursorObject, 0, true] call EFUNC(common,nearestVehiclesFreeSeat); if ([_cursorObject] isEqualTo _vehicles) then { - if (["ace_medical"] call EFUNC(common,isModLoaded)) then { + if (GETEGVAR(medical,enabled,false)) then { [_unit, _target, _cursorObject] call EFUNC(medical_treatment,loadUnit); } else { [_unit, _target, _cursorObject] call EFUNC(common,loadPerson); diff --git a/addons/field_rations/XEH_postInit.sqf b/addons/field_rations/XEH_postInit.sqf index 9f64379094..9fc8406aba 100644 --- a/addons/field_rations/XEH_postInit.sqf +++ b/addons/field_rations/XEH_postInit.sqf @@ -99,7 +99,7 @@ if !(hasInterface) exitWith {}; ["ace_interactMenuOpened", LINKFUNC(addWaterSourceInteractions)] call CBA_fnc_addEventHandler; // Add status modifiers - if (["ace_medical"] call EFUNC(common,isModLoaded)) then { + if (GETEGVAR(medical,enabled,false)) then { [0, { if (_this getVariable [QEGVAR(medical,isBleeding), false]) exitWith { 0.5 diff --git a/addons/field_rations/functions/fnc_handleEffects.sqf b/addons/field_rations/functions/fnc_handleEffects.sqf index b118f6acce..ad60a743ad 100644 --- a/addons/field_rations/functions/fnc_handleEffects.sqf +++ b/addons/field_rations/functions/fnc_handleEffects.sqf @@ -28,13 +28,14 @@ if ((_thirst > 99.9 || {_hunger > 99.9}) && {random 1 < 0.5}) exitWith { if !(_player call EFUNC(common,isAwake)) exitWith {}; // Set unit unconscious (chance based on how high thirst/hunger are) -if ((_thirst > 85 || {_hunger > 85}) && {random 1 < linearConversion [85, 100, _thirst max _hunger, 0.05, 0.1, true]}) exitWith { - if (["ace_medical"] call EFUNC(common,isModLoaded)) then { - [_player, true, 5, true] call EFUNC(medical,setUnconscious); - }; +if ( + GETEGVAR(medical,enabled,false) && + {(_thirst > 85 || {_hunger > 85}) && {random 1 < linearConversion [85, 100, _thirst max _hunger, 0.05, 0.1, true]}} +) exitWith { + [_player, true, 5, true] call EFUNC(medical,setUnconscious); }; // Make unit fall if moving fast -if ((_thirst > 93 || {_hunger > 93}) && {speed _player > 1} && {vehicle _player == _player}) exitWith { +if ((_thirst > 93 || {_hunger > 93}) && {speed _player > 1} && {isNull objectParent _player}) exitWith { [_player, "down"] call EFUNC(common,doGesture); }; diff --git a/addons/gforces/functions/fnc_pfhUpdateGForces.sqf b/addons/gforces/functions/fnc_pfhUpdateGForces.sqf index 7ff3444b7d..4bb680ee47 100644 --- a/addons/gforces/functions/fnc_pfhUpdateGForces.sqf +++ b/addons/gforces/functions/fnc_pfhUpdateGForces.sqf @@ -71,7 +71,7 @@ private _suitCoef = if ((uniform ACE_player) != "") then { private _gBlackOut = MAXVIRTUALG / _classCoef + MAXVIRTUALG / _suitCoef - MAXVIRTUALG; // Unconsciousness -if ((_average > _gBlackOut) && {["ace_medical"] call EFUNC(common,isModLoaded) && {!(ACE_player getVariable ["ACE_isUnconscious", false])}}) then { +if (_average > _gBlackOut && {GETEGVAR(medical,enabled,false) && {ACE_player call EFUNC(common,isAwake)}}) then { [ACE_player, true, (10 + floor(random 5)), true] call EFUNC(medical,setUnconscious); }; diff --git a/addons/grenades/functions/fnc_flashbangExplosionEH.sqf b/addons/grenades/functions/fnc_flashbangExplosionEH.sqf index 5e8d17e50c..383c8853e3 100644 --- a/addons/grenades/functions/fnc_flashbangExplosionEH.sqf +++ b/addons/grenades/functions/fnc_flashbangExplosionEH.sqf @@ -118,7 +118,7 @@ if (hasInterface && {!isNull ACE_player} && {alive ACE_player}) then { }; // add ace_medical pain effect: - if (["ace_medical"] call EFUNC(common,isModLoaded) && {_strength > 0.1} && {isDamageAllowed _unit} && {_unit getVariable [QEGVAR(medical,allowDamage), true]}) then { + if (GETEGVAR(medical,enabled,false) && {_strength > 0.1} && {isDamageAllowed _unit} && {_unit getVariable [QEGVAR(medical,allowDamage), true]}) then { [ACE_player, _strength / 2] call EFUNC(medical,adjustPainLevel); }; diff --git a/addons/interaction/functions/fnc_canPullOutBody.sqf b/addons/interaction/functions/fnc_canPullOutBody.sqf index 167d09ecdb..2676bfc203 100644 --- a/addons/interaction/functions/fnc_canPullOutBody.sqf +++ b/addons/interaction/functions/fnc_canPullOutBody.sqf @@ -19,7 +19,7 @@ params ["_body", "_unit"]; // Defer to ACE Medical's unload patient if present -if (["ace_medical"] call EFUNC(common,isModLoaded)) exitWith {false}; +if (GETEGVAR(medical,enabled,false)) exitWith {false}; private _vehicle = objectParent _body; diff --git a/addons/killtracker/XEH_postInit.sqf b/addons/killtracker/XEH_postInit.sqf index 73ade6c94b..35145698b3 100644 --- a/addons/killtracker/XEH_postInit.sqf +++ b/addons/killtracker/XEH_postInit.sqf @@ -19,7 +19,7 @@ if ((getText (missionconfigfile >> "CfgDebriefingSections" >> QUOTE(XADDON) >> "variable")) != QXGVAR(outputText)) exitWith { TRACE_1("no mission debriefing config",_this); }; -if (!(["ace_medical"] call EFUNC(common,isModLoaded))) exitWith { +if !(GETEGVAR(medical,enabled,false)) exitWith { WARNING("No ACE-Medical"); XGVAR(outputText) = "No ACE-Medical"; }; diff --git a/addons/medical_blood/XEH_postInit.sqf b/addons/medical_blood/XEH_postInit.sqf index daf4595584..b08921b441 100644 --- a/addons/medical_blood/XEH_postInit.sqf +++ b/addons/medical_blood/XEH_postInit.sqf @@ -1,7 +1,5 @@ #include "script_component.hpp" -GVAR(useAceMedical) = ["ace_medical"] call EFUNC(common,isModLoaded); - // To support public API regardless of component settings [QGVAR(spurt), LINKFUNC(spurt)] call CBA_fnc_addEventHandler; diff --git a/addons/medical_blood/functions/fnc_isBleeding.sqf b/addons/medical_blood/functions/fnc_isBleeding.sqf index 2d57dcf73b..a21a50913a 100644 --- a/addons/medical_blood/functions/fnc_isBleeding.sqf +++ b/addons/medical_blood/functions/fnc_isBleeding.sqf @@ -17,7 +17,7 @@ params ["_unit"]; -if (GVAR(useAceMedical)) exitWith { +if (GETEGVAR(medical,enabled,false)) exitWith { IS_BLEEDING(_unit); }; diff --git a/addons/medical_blood/functions/fnc_onBleeding.sqf b/addons/medical_blood/functions/fnc_onBleeding.sqf index 02ddd93fd0..4963aaa21d 100644 --- a/addons/medical_blood/functions/fnc_onBleeding.sqf +++ b/addons/medical_blood/functions/fnc_onBleeding.sqf @@ -25,7 +25,7 @@ if !(_unit call FUNC(isBleeding)) exitWith {}; if (!isNull objectParent _unit && {!(vehicle _unit isKindOf "StaticWeapon")}) exitWith {}; if (CBA_missionTime > (_unit getVariable [QGVAR(nextTime), -10])) then { - private _bloodLoss = (if (GVAR(useAceMedical)) then {GET_BLOOD_LOSS(_unit) * 2.5} else {getDammage _unit * 2}) min 6; + private _bloodLoss = ([damage _unit * 2, GET_BLOOD_LOSS(_unit) * 2.5] select GETEGVAR(medical,enabled,false)) min 6; _unit setVariable [QGVAR(nextTime), CBA_missionTime + 8 + random 2 - _bloodLoss]; TRACE_2("Creating blood drop for bleeding unit",_unit,_bloodLoss); diff --git a/addons/overpressure/functions/fnc_firedEHBB.sqf b/addons/overpressure/functions/fnc_firedEHBB.sqf index 2ef48bf4d9..a027785940 100644 --- a/addons/overpressure/functions/fnc_firedEHBB.sqf +++ b/addons/overpressure/functions/fnc_firedEHBB.sqf @@ -53,7 +53,7 @@ if (_distance < _backblastRange) then { [_damage * 100] call BIS_fnc_bloodEffect; - if (["ace_medical"] call EFUNC(common,isModLoaded)) then { + if (GETEGVAR(medical,enabled,false)) then { [_unit, _damage, "body", "backblast", _unit] call EFUNC(medical,addDamageToUnit); } else { _unit setDamage (damage _unit + _damage); diff --git a/addons/overpressure/functions/fnc_overpressureDamage.sqf b/addons/overpressure/functions/fnc_overpressureDamage.sqf index 812a2ab7ea..12b7a820ca 100644 --- a/addons/overpressure/functions/fnc_overpressureDamage.sqf +++ b/addons/overpressure/functions/fnc_overpressureDamage.sqf @@ -57,7 +57,7 @@ TRACE_3("cache",_overpressureAngle,_overpressureRange,_overpressureDamage); [_damage * 100] call BIS_fnc_bloodEffect; }; - if (["ace_medical"] call EFUNC(common,isModLoaded)) then { + if (GETEGVAR(medical,enabled,false)) then { [_x, _damage, "body", "backblast", _firer] call EFUNC(medical,addDamageToUnit); } else { _x setDamage (damage _x + _damage); diff --git a/addons/vehicle_damage/functions/fnc_medicalDamage.sqf b/addons/vehicle_damage/functions/fnc_medicalDamage.sqf index 2aa8969644..c5234cf1c1 100644 --- a/addons/vehicle_damage/functions/fnc_medicalDamage.sqf +++ b/addons/vehicle_damage/functions/fnc_medicalDamage.sqf @@ -23,7 +23,7 @@ params ["_unit", "_source", "_instigator", ["_guaranteeDeath", false]]; // Check if unit is invulnerable if !(isDamageAllowed _unit && {_unit getVariable [QEGVAR(medical,allowDamage), true]}) exitWith {}; -if (["ace_medical"] call EFUNC(common,isModLoaded)) then { +if (GETEGVAR(medical,enabled,false)) then { for "_i" from 0 to floor (4 + random 3) do { [_unit, random [0, 0.66, 1], selectRandom ["Head", "Body", "LeftArm", "RightArm", "LeftLeg", "RightLeg"], selectRandom ["bullet", "shell", "explosive"], _instigator] call EFUNC(medical,addDamageToUnit); }; diff --git a/addons/zeus/functions/fnc_moduleHeal.sqf b/addons/zeus/functions/fnc_moduleHeal.sqf index 9a49375003..4bf0525ea7 100644 --- a/addons/zeus/functions/fnc_moduleHeal.sqf +++ b/addons/zeus/functions/fnc_moduleHeal.sqf @@ -43,7 +43,7 @@ switch (false) do { }; // Heal validated target -if (["ace_medical"] call EFUNC(common,isModLoaded)) then { +if (GETEGVAR(medical,enabled,false)) then { TRACE_1("healing with ace_medical",_unit); [QEGVAR(medical_treatment,fullHealLocal), [_unit], _unit] call CBA_fnc_targetEvent; } else { diff --git a/addons/zeus/functions/fnc_moduleSetMedic.sqf b/addons/zeus/functions/fnc_moduleSetMedic.sqf index f66ca9132d..d44dd56e59 100644 --- a/addons/zeus/functions/fnc_moduleSetMedic.sqf +++ b/addons/zeus/functions/fnc_moduleSetMedic.sqf @@ -21,7 +21,7 @@ params ["_logic"]; if !(local _logic) exitWith {}; -if !(["ace_medical"] call EFUNC(common,isModLoaded)) then { +if !(GETEGVAR(medical,enabled,false)) then { [LSTRING(RequiresAddon)] call FUNC(showMessage); } else { private _mouseOver = GETMVAR(bis_fnc_curatorObjectPlaced_mouseOver,[""]); diff --git a/addons/zeus/functions/fnc_moduleSetMedicalFacility.sqf b/addons/zeus/functions/fnc_moduleSetMedicalFacility.sqf index 1f98212935..5a23075369 100644 --- a/addons/zeus/functions/fnc_moduleSetMedicalFacility.sqf +++ b/addons/zeus/functions/fnc_moduleSetMedicalFacility.sqf @@ -21,7 +21,7 @@ params ["_logic"]; if !(local _logic) exitWith {}; -if !(["ace_medical"] call EFUNC(common,isModLoaded)) then { +if !(GETEGVAR(medical,enabled,false)) then { [LSTRING(RequiresAddon)] call FUNC(showMessage); } else { private _mouseOver = GETMVAR(bis_fnc_curatorObjectPlaced_mouseOver,[""]); diff --git a/addons/zeus/functions/fnc_moduleSetMedicalVehicle.sqf b/addons/zeus/functions/fnc_moduleSetMedicalVehicle.sqf index e8189b377e..26bb3fcfe9 100644 --- a/addons/zeus/functions/fnc_moduleSetMedicalVehicle.sqf +++ b/addons/zeus/functions/fnc_moduleSetMedicalVehicle.sqf @@ -21,7 +21,7 @@ params ["_logic"]; if !(local _logic) exitWith {}; -if !(["ace_medical"] call EFUNC(common,isModLoaded)) then { +if !(GETEGVAR(medical,enabled,false)) then { [LSTRING(RequiresAddon)] call FUNC(showMessage); } else { private _mouseOver = GETMVAR(bis_fnc_curatorObjectPlaced_mouseOver,[""]); From 8fc093de8f088cb092c8a886fb6ba5c75538d8e7 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Tue, 18 Jun 2024 10:05:01 +0200 Subject: [PATCH 100/290] Grenades - Code cleanup (#9979) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Improved various aspects of grenades * Update addons/grenades/functions/fnc_flashbangExplosionEH.sqf Co-authored-by: Jouni Järvinen * Update addons/grenades/functions/fnc_incendiary.sqf Co-authored-by: Jouni Järvinen * Update addons/grenades/functions/fnc_incendiary.sqf Co-authored-by: Jouni Järvinen * Update fnc_flashbangExplosionEH.sqf * More cleanup * Update fnc_incendiary.sqf * Update fnc_incendiary.sqf * Update fnc_flashbangThrownFuze.sqf * Update fnc_flashbangThrownFuze.sqf * Update addons/grenades/functions/fnc_nextMode.sqf Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> * Update addons/grenades/functions/fnc_flashbangExplosionEH.sqf * Update addons/grenades/functions/fnc_incendiary.sqf * Removed fix that is included in another PR * Update fnc_incendiary.sqf * Messed up merge conflict resolution --------- Co-authored-by: Jouni Järvinen Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> --- addons/grenades/CfgAmmo.hpp | 1 - addons/grenades/CfgEventHandlers.hpp | 1 - addons/grenades/CfgMagazines.hpp | 1 - addons/grenades/CfgVehicles.hpp | 1 - addons/grenades/CfgWeapons.hpp | 1 - addons/grenades/Effects.hpp | 1 - addons/grenades/XEH_PREP.hpp | 2 +- addons/grenades/XEH_postInit.sqf | 11 +- ...nc_addChangeFuseItemContextMenuOptions.sqf | 41 +-- addons/grenades/functions/fnc_flare.sqf | 3 +- .../functions/fnc_flashbangExplosionEH.sqf | 262 +++++++++--------- .../functions/fnc_flashbangThrownFuze.sqf | 23 +- addons/grenades/functions/fnc_incendiary.sqf | 73 ++--- addons/grenades/functions/fnc_nextMode.sqf | 13 +- .../grenades/functions/fnc_throwGrenade.sqf | 110 +++----- addons/grenades/initSettings.inc.sqf | 9 +- addons/grenades/script_component.hpp | 5 - 17 files changed, 267 insertions(+), 291 deletions(-) diff --git a/addons/grenades/CfgAmmo.hpp b/addons/grenades/CfgAmmo.hpp index e911e23747..2b0849d2f7 100644 --- a/addons/grenades/CfgAmmo.hpp +++ b/addons/grenades/CfgAmmo.hpp @@ -1,4 +1,3 @@ - class CfgAmmo { class Default; class Grenade: Default { diff --git a/addons/grenades/CfgEventHandlers.hpp b/addons/grenades/CfgEventHandlers.hpp index 6c29240403..f6503c2479 100644 --- a/addons/grenades/CfgEventHandlers.hpp +++ b/addons/grenades/CfgEventHandlers.hpp @@ -1,4 +1,3 @@ - class Extended_PreStart_EventHandlers { class ADDON { init = QUOTE(call COMPILE_SCRIPT(XEH_preStart)); diff --git a/addons/grenades/CfgMagazines.hpp b/addons/grenades/CfgMagazines.hpp index ea4641ab7f..2ff86c443d 100644 --- a/addons/grenades/CfgMagazines.hpp +++ b/addons/grenades/CfgMagazines.hpp @@ -1,4 +1,3 @@ - class CfgMagazines { class HandGrenade; class ACE_HandFlare_Base: HandGrenade { diff --git a/addons/grenades/CfgVehicles.hpp b/addons/grenades/CfgVehicles.hpp index f9ac60d9fe..34cf4196e6 100644 --- a/addons/grenades/CfgVehicles.hpp +++ b/addons/grenades/CfgVehicles.hpp @@ -1,4 +1,3 @@ - class CfgVehicles { class NATO_Box_Base; class Box_NATO_Grenades_F: NATO_Box_Base { diff --git a/addons/grenades/CfgWeapons.hpp b/addons/grenades/CfgWeapons.hpp index 842862f7f9..683ec7532b 100644 --- a/addons/grenades/CfgWeapons.hpp +++ b/addons/grenades/CfgWeapons.hpp @@ -1,4 +1,3 @@ - class CfgWeapons { class GrenadeLauncher; class Throw: GrenadeLauncher { diff --git a/addons/grenades/Effects.hpp b/addons/grenades/Effects.hpp index 95c3f12ba8..b4a16c6412 100644 --- a/addons/grenades/Effects.hpp +++ b/addons/grenades/Effects.hpp @@ -1,4 +1,3 @@ - class ACE_M84FlashbangEffect { // empty }; diff --git a/addons/grenades/XEH_PREP.hpp b/addons/grenades/XEH_PREP.hpp index 6feaff3a69..06ceebc6b4 100644 --- a/addons/grenades/XEH_PREP.hpp +++ b/addons/grenades/XEH_PREP.hpp @@ -1,3 +1,4 @@ +PREP(addChangeFuseItemContextMenuOptions); PREP(damageEngineAndWheels); PREP(flare); PREP(flashbangExplosionEH); @@ -5,4 +6,3 @@ PREP(flashbangThrownFuze); PREP(incendiary); PREP(nextMode); PREP(throwGrenade); -PREP(addChangeFuseItemContextMenuOptions); diff --git a/addons/grenades/XEH_postInit.sqf b/addons/grenades/XEH_postInit.sqf index 312e22fa6e..0c8e348df1 100644 --- a/addons/grenades/XEH_postInit.sqf +++ b/addons/grenades/XEH_postInit.sqf @@ -1,6 +1,7 @@ // by commy2 #include "script_component.hpp" +#include "\a3\ui_f\hpp\defineDIKCodes.inc" ["ace_flashbangExploded", LINKFUNC(flashbangExplosionEH)] call CBA_fnc_addEventHandler; [QGVAR(damageEngineAndWheels), LINKFUNC(damageEngineAndWheels)] call CBA_fnc_addEventHandler; @@ -16,21 +17,21 @@ GVAR(flashbangPPEffectCC) = ppEffectCreate ["ColorCorrections", 4265]; GVAR(flashbangPPEffectCC) ppEffectForceInNVG true; // Add keybinds -["ACE3 Weapons", QGVAR(switchGrenadeMode), localize LSTRING(SwitchGrenadeMode), { +["ACE3 Weapons", QGVAR(switchGrenadeMode), LLSTRING(SwitchGrenadeMode), { // Conditions: canInteract if !([ACE_player, objNull, ["isNotEscorting", "isNotInside"]] call EFUNC(common,canInteractWith)) exitWith {false}; // Conditions: specific - if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; + if !(ACE_player call CBA_fnc_canUseWeapon) exitWith {false}; // Don't change mode or show hint if advanced throwing is active if (ACE_player getVariable [QEGVAR(advanced_throwing,inHand), false]) exitWith {false}; // Statement - [] call FUNC(nextMode); -}, {false}, [9, [false, false, false]], false] call CBA_fnc_addKeybind; //8 Key + call FUNC(nextMode) // return +}, {}, [DIK_8, [false, false, false]], false] call CBA_fnc_addKeybind; // 8 Key ["CBA_settingsInitialized", { if (GVAR(convertExplosives)) then { - [] call FUNC(addChangeFuseItemContextMenuOptions); + call FUNC(addChangeFuseItemContextMenuOptions); }; }] call CBA_fnc_addEventHandler; diff --git a/addons/grenades/functions/fnc_addChangeFuseItemContextMenuOptions.sqf b/addons/grenades/functions/fnc_addChangeFuseItemContextMenuOptions.sqf index d778ca3349..c0b5c9dc80 100644 --- a/addons/grenades/functions/fnc_addChangeFuseItemContextMenuOptions.sqf +++ b/addons/grenades/functions/fnc_addChangeFuseItemContextMenuOptions.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: Cyruz - * Allows conversion of explosive charges in to throwable versions + * Allows conversion of explosive charges into throwable versions. * * Arguments: * None @@ -14,7 +14,8 @@ * * Public: No */ - TRACE_1("addChangeFuseItemContextMenuOptions",_this); + +LOG("addChangeFuseItemContextMenuOptions"); { _x params ["_mag", "_throwableMag"]; @@ -29,21 +30,25 @@ {true}, { params ["", "", "_item", "", "_magArr"]; - _item isEqualTo (_magArr select 0); + + _item == (_magArr select 0) } ], { params ["_unit", "", "", "_slot", "_magArr"]; - private _container = ""; - switch _slot do { + + private _container = switch (_slot) do { case "UNIFORM_CONTAINER": { - _container = "uniform"; + "uniform" }; case "VEST_CONTAINER": { - _container = "vest"; + "vest" }; case "BACKPACK_CONTAINER": { - _container = "backpack"; + "backpack" + }; + default { + "" }; }; @@ -54,7 +59,7 @@ false }, true, - [_mag,_throwableMag] + [_mag, _throwableMag] ] call CBA_fnc_addItemContextMenuOption; [ @@ -67,21 +72,25 @@ {true}, { params ["", "", "_item", "", "_magArr"]; - _item isEqualTo (_magArr select 1); + + _item == (_magArr select 1) } ], { params ["_unit", "", "", "_slot", "_magArr"]; - private _container = ""; - switch _slot do { + + private _container = switch (_slot) do { case "UNIFORM_CONTAINER": { - _container = "uniform"; + "uniform" }; case "VEST_CONTAINER": { - _container = "vest"; + "vest" }; case "BACKPACK_CONTAINER": { - _container = "backpack"; + "backpack" + }; + default { + "" }; }; @@ -92,7 +101,7 @@ false }, true, - [_mag,_throwableMag] + [_mag, _throwableMag] ] call CBA_fnc_addItemContextMenuOption; } forEach [ ["SatchelCharge_Remote_Mag", "ACE_SatchelCharge_Remote_Mag_Throwable"], diff --git a/addons/grenades/functions/fnc_flare.sqf b/addons/grenades/functions/fnc_flare.sqf index 8214a5600d..2db6335a77 100644 --- a/addons/grenades/functions/fnc_flare.sqf +++ b/addons/grenades/functions/fnc_flare.sqf @@ -4,7 +4,7 @@ * Makes flare shine. * * Arguments: - * 0: The flare + * 0: Flare * 1: Color of flare * 2: Intensity of flare * 3: Flare lifetime @@ -34,6 +34,5 @@ _light setLightFlareMaxDistance 1000; _light setLightDayLight true; _light lightAttachObject [_projectile, [0,0,0]]; -//_light attachTo [_projectile, [0,0,0]]; [{deleteVehicle _this}, _light, _timeToLive] call CBA_fnc_waitAndExecute; diff --git a/addons/grenades/functions/fnc_flashbangExplosionEH.sqf b/addons/grenades/functions/fnc_flashbangExplosionEH.sqf index 383c8853e3..33c4bdffc2 100644 --- a/addons/grenades/functions/fnc_flashbangExplosionEH.sqf +++ b/addons/grenades/functions/fnc_flashbangExplosionEH.sqf @@ -4,7 +4,7 @@ * Creates the flashbang effect and knock out AI units. * * Arguments: - * 0: The flashBang position ASL + * 0: Flashbang position ASL * * Return Value: * None @@ -18,152 +18,148 @@ params ["_grenadePosASL"]; TRACE_1("params",_grenadePosASL); -// Create flash to illuminate environment -if (hasInterface) then { - private _light = "#lightpoint" createVehicleLocal ASLtoAGL _grenadePosASL; - _light setPosASL _grenadePosASL; - - _light setLightBrightness 20; - _light setLightAmbient [1,1,1]; - _light setLightColor [1,1,1]; - _light setLightDayLight true; - _light setLightAttenuation [0, 1, 5, 1000, 0, 20]; - - // Reduce the light after 0.1 seconds - [{ - params ["_light"]; - _light setLightBrightness 5; - // Delete the light after 0.2 more seconds - [{ - params ["_light"]; - deleteVehicle _light; - }, [_light], 0.2] call CBA_fnc_waitAndExecute; - }, [_light], 0.1] call CBA_fnc_waitAndExecute; -}; - // Affect local AI (players are not local, except for ACE_player) // @todo: Affect units in static weapons, turned out, etc -private _affected = (ASLtoAGL _grenadePosASL) nearEntities ["CAManBase", 20]; -_affected = _affected - [ACE_player]; +private _affected = ((ASLtoAGL _grenadePosASL) nearEntities ["CAManBase", 20]) - [ACE_player]; + { - if (local _x && {_x call EFUNC(common,isAwake)}) then { - private _unit = _x; - private _strength = 1 - (((eyePos _unit) vectorDistance _grenadePosASL) min 20) / 20; + private _unit = _x; + private _strength = 1 - (((eyePos _unit) vectorDistance _grenadePosASL) min 20) / 20; - TRACE_3("FlashBangEffect Start",_unit,((getPosASL _unit) vectorDistance _grenadePosASL),_strength); + TRACE_3("FlashBangEffect Start",_unit,((getPosASL _unit) vectorDistance _grenadePosASL),_strength); - [_unit, true] call EFUNC(common,disableAI); + [_unit, true] call EFUNC(common,disableAI); - // Make AI try to look away - private _dirToFlash = _unit getDir _grenadePosASL; - _unit setDir (_dirToFlash + linearConversion [0.2, 1, _strength, 40, 135] * selectRandom [-1, 1]); + // Make AI try to look away + private _dirToFlash = _unit getDir _grenadePosASL; + _unit setDir (_dirToFlash + linearConversion [0.2, 1, _strength, 40, 135] * selectRandom [-1, 1]); + + private _flashReactionDebounce = _unit getVariable [QGVAR(flashReactionDebounce), 0]; + _unit setVariable [QGVAR(flashReactionDebounce), _flashReactionDebounce max (CBA_missionTime + (7 * _strength))]; + + if (_flashReactionDebounce < CBA_missionTime) then { + // Not used internally but could be useful for other mods + _unit setVariable [QGVAR(flashStrength), _strength, true]; + + [QGVAR(flashbangedAI), [_unit, _strength, _grenadePosASL]] call CBA_fnc_localEvent; + + { + _unit setSkill [_x, (_unit skill _x) / 50]; + } forEach SUBSKILLS; + + [{ + CBA_missiontime >= _this getVariable [QGVAR(flashReactionDebounce), 0] + }, { + params ["_unit"]; + + _unit setVariable [QGVAR(flashStrength), 0, true]; + + // Make sure we don't enable AI for unconscious units + if (_unit call EFUNC(common,isAwake)) then { + [_unit, false] call EFUNC(common,disableAI); + }; - private _flashReactionDebounce = _unit getVariable [QGVAR(flashReactionDebounce), 0]; - _unit setVariable [QGVAR(flashReactionDebounce), _flashReactionDebounce max (CBA_missionTime + (7 * _strength))]; - if (_flashReactionDebounce < CBA_missionTime) then { - // Not used interally but could be useful for other mods - _unit setVariable [QGVAR(flashStrength), _strength, true]; - [QGVAR(flashbangedAI), [_unit, _strength, _grenadePosASL]] call CBA_fnc_localEvent; { - _unit setSkill [_x, (_unit skill _x) / 50]; + _unit setSkill [_x, (_unit skill _x) * 50]; } forEach SUBSKILLS; - [{ - params ["_unit"]; - CBA_missiontime >= _unit getVariable [QGVAR(flashReactionDebounce), 0] - },{ - params ["_unit"]; - - _unit setVariable [QGVAR(flashStrength), 0, true]; - - // Make sure we don't enable AI for unconscious units - if !(_unit getVariable ["ace_isUnconscious", false]) then { - [_unit, false] call EFUNC(common,disableAI); - }; - { - _unit setSkill [_x, (_unit skill _x) * 50]; - } forEach SUBSKILLS; - }, [_unit]] call CBA_fnc_waitUntilAndExecute; - }; + }, _unit] call CBA_fnc_waitUntilAndExecute; }; -} forEach _affected; +} forEach (_affected select {local _x && {_x call EFUNC(common,isAwake)}}); + +if (!hasInterface) exitWith {}; + +// Create flash to illuminate environment +private _light = "#lightpoint" createVehicleLocal ASLtoAGL _grenadePosASL; +_light setPosASL _grenadePosASL; + +_light setLightBrightness 20; +_light setLightAmbient [1,1,1]; +_light setLightColor [1,1,1]; +_light setLightDayLight true; +_light setLightAttenuation [0, 1, 5, 1000, 0, 20]; + +// Reduce the light after 0.1 seconds +[{ + _this setLightBrightness 5; + + // Delete the light after 0.2 more seconds + [{deleteVehicle _this}, _this, 0.2] call CBA_fnc_waitAndExecute; +}, _light, 0.1] call CBA_fnc_waitAndExecute; + +// Ignore dead and placeable logic (zeus / spectator) +if (!alive ACE_player || {(getNumber (configOf ACE_player >> "isPlayableLogic")) == 1}) exitWith {}; // Affect local player, independently of distance -if (hasInterface && {!isNull ACE_player} && {alive ACE_player}) then { - if ((getNumber (configOf ACE_player >> "isPlayableLogic")) == 1) exitWith { - TRACE_1("skipping playable logic",typeOf ACE_player); // VirtualMan_F (placeable logic zeus / spectator) - }; - // Do effects for player - // is there line of sight to the grenade? - private _eyePos = eyePos ACE_player; //PositionASL - _grenadePosASL set [2, (_grenadePosASL select 2) + 0.2]; // compensate for grenade glitching into ground +// Check for line of sight to the grenade +private _eyePos = eyePos ACE_player; // PositionASL +_grenadePosASL set [2, (_grenadePosASL select 2) + 0.2]; // compensate for grenade glitching into ground - private _strength = 1 - ((_eyePos vectorDistance _grenadePosASL) min 20) / 20; +private _strength = 1 - ((_eyePos vectorDistance _grenadePosASL) min 20) / 20; - // Check for line of sight (check 4 points in case grenade is stuck in an object or underground) - private _losCoefficient = 1; - private _losCount = { - !lineIntersects [_grenadePosASL vectorAdd _x, _eyePos, ACE_player] - } count [[0,0,0], [0,0,0.2], [0.1, 0.1, 0.1], [-0.1, -0.1, 0.1]]; - TRACE_1("Line of sight count (out of 4)",_losCount); - if (_losCount <= 1) then { - _losCoefficient = 0.1; - }; - _strength = _strength * _losCoefficient; +// Check for line of sight (check 4 points in case grenade is stuck in an object or underground) +private _losCount = { + !lineIntersects [_grenadePosASL vectorAdd _x, _eyePos, ACE_player] +} count [[0, 0, 0], [0, 0, 0.2], [0.1, 0.1, 0.1], [-0.1, -0.1, 0.1]]; +TRACE_1("Line of sight count (out of 4)",_losCount); - // Add ace_hearing ear ringing sound effect - if (["ace_hearing"] call EFUNC(common,isModLoaded) && {_strength > 0 && {EGVAR(hearing,damageCoefficent) > 0.25}}) then { - private _earringingStrength = 40 * _strength; - [_earringingStrength] call EFUNC(hearing,earRinging); - TRACE_1("Earringing Strength",_earringingStrength); - }; +private _losCoefficient = [1, 0.1] select (_losCount <= 1); +_strength = _strength * _losCoefficient; - // add ace_medical pain effect: - if (GETEGVAR(medical,enabled,false) && {_strength > 0.1} && {isDamageAllowed _unit} && {_unit getVariable [QEGVAR(medical,allowDamage), true]}) then { - [ACE_player, _strength / 2] call EFUNC(medical,adjustPainLevel); - }; - - // Effect on vision has a wider range, with a higher falloff - _strength = 1 - (((_eyePos vectorDistance _grenadePosASL) min 25) / 25) ^ 0.4; - _strength = _strength * _losCoefficient; - // Account for people looking away by slightly reducing the effect for visual effects. - private _eyeDir = ((AGLtoASL positionCameraToWorld [0,0,1]) vectorDiff (AGLtoASL positionCameraToWorld [0,0,0])); - private _dirToUnitVector = _eyePos vectorFromTo _grenadePosASL; - private _angleDiff = acos (_eyeDir vectorDotProduct _dirToUnitVector); - TRACE_2("",_angleDiff,((1 - (_angleDiff - 45) / (120 - 45)) max 0)); - // from 0-45deg, full effect - if (_angleDiff > 45) then { - _strength = _strength * ((1 - (_angleDiff - 45) / (120 - 45)) max 0); - }; - - // Blind player - if (_strength > 0.1) then { - private _blend = [[1,1,1,0], [0.3,0.3,0.3,1]] select EGVAR(common,epilepsyFriendlyMode); - - GVAR(flashbangPPEffectCC) ppEffectEnable true; - GVAR(flashbangPPEffectCC) ppEffectAdjust [1, 1, (0.8 + _strength) min 1, _blend, [0,0,0,1], [0,0,0,0]]; - GVAR(flashbangPPEffectCC) ppEffectCommit 0.01; - - //PARTIALRECOVERY - start decreasing effect over time - [{ - params ["_strength", "_blend"]; - - GVAR(flashbangPPEffectCC) ppEffectAdjust [1, 1, 0, _blend, [0,0,0,1], [0,0,0,0]]; - GVAR(flashbangPPEffectCC) ppEffectCommit (10 * _strength); - }, [_strength, _blend], 7 * _strength] call CBA_fnc_waitAndExecute; - - //FULLRECOVERY - end effect - [{ - GVAR(flashbangPPEffectCC) ppEffectEnable false; - }, [], 17 * _strength] call CBA_fnc_waitAndExecute; - }; - - // Make player flinch - if (_strength <= 0.2) exitWith {}; - private _minFlinch = linearConversion [0.2, 1, _strength, 0, 60, true]; - private _maxFlinch = linearConversion [0.2, 1, _strength, 0, 95, true]; - private _flinch = (_minFlinch + random (_maxFlinch - _minFlinch)) * selectRandom [-1, 1]; - ACE_player setDir (getDir ACE_player + _flinch); - - [QGVAR(flashbangedPlayer), [_strength, _grenadePosASL]] call CBA_fnc_localEvent; +// Add ace_hearing ear ringing sound effect +if (["ace_hearing"] call EFUNC(common,isModLoaded) && {_strength > 0} && {EGVAR(hearing,damageCoefficent) > 0.25}) then { + private _earringingStrength = 40 * _strength; + [_earringingStrength] call EFUNC(hearing,earRinging); + TRACE_1("Earringing Strength",_earringingStrength); }; -true + +// Add ace_medical pain effect +if (GETEGVAR(medical,enabled,false) && {_strength > 0.1} && {isDamageAllowed _unit} && {_unit getVariable [QEGVAR(medical,allowDamage), true]}) then { + [ACE_player, _strength / 2] call EFUNC(medical,adjustPainLevel); +}; + +// Effect on vision has a wider range, with a higher falloff +_strength = 1 - (((_eyePos vectorDistance _grenadePosASL) min 25) / 25) ^ 0.4; +_strength = _strength * _losCoefficient; + +// Account for people looking away by slightly reducing the effect for visual effects. +private _eyeDir = ((AGLtoASL positionCameraToWorld [0, 0, 1]) vectorDiff (AGLtoASL positionCameraToWorld [0, 0, 0])); +private _dirToUnitVector = _eyePos vectorFromTo _grenadePosASL; +private _angleDiff = acos (_eyeDir vectorDotProduct _dirToUnitVector); +TRACE_2("",_angleDiff,((1 - (_angleDiff - 45) / (120 - 45)) max 0)); + +// From 0-45deg, full effect +if (_angleDiff > 45) then { + _strength = _strength * ((1 - (_angleDiff - 45) / (120 - 45)) max 0); +}; + +// Blind player +if (_strength > 0.1) then { + private _blend = [[1, 1, 1, 0], [0.3, 0.3, 0.3, 1]] select EGVAR(common,epilepsyFriendlyMode); + + GVAR(flashbangPPEffectCC) ppEffectEnable true; + GVAR(flashbangPPEffectCC) ppEffectAdjust [1, 1, (0.8 + _strength) min 1, _blend, [0, 0, 0, 1], [0, 0, 0, 0]]; + GVAR(flashbangPPEffectCC) ppEffectCommit 0.01; + + // PARTIALRECOVERY - start decreasing effect over time + [{ + params ["_strength", "_blend"]; + + GVAR(flashbangPPEffectCC) ppEffectAdjust [1, 1, 0, _blend, [0, 0, 0, 1], [0, 0, 0, 0]]; + GVAR(flashbangPPEffectCC) ppEffectCommit (10 * _strength); + }, [_strength, _blend], 7 * _strength] call CBA_fnc_waitAndExecute; + + // FULLRECOVERY - end effect + [{ + GVAR(flashbangPPEffectCC) ppEffectEnable false; + }, [], 17 * _strength] call CBA_fnc_waitAndExecute; +}; + +// Make player flinch +if (_strength <= 0.2) exitWith {}; + +private _minFlinch = linearConversion [0.2, 1, _strength, 0, 60, true]; +private _maxFlinch = linearConversion [0.2, 1, _strength, 0, 95, true]; +private _flinch = (_minFlinch + random (_maxFlinch - _minFlinch)) * selectRandom [-1, 1]; +ACE_player setDir (getDir ACE_player + _flinch); + +[QGVAR(flashbangedPlayer), [_strength, _grenadePosASL]] call CBA_fnc_localEvent; diff --git a/addons/grenades/functions/fnc_flashbangThrownFuze.sqf b/addons/grenades/functions/fnc_flashbangThrownFuze.sqf index 1c9751da37..89020842d2 100644 --- a/addons/grenades/functions/fnc_flashbangThrownFuze.sqf +++ b/addons/grenades/functions/fnc_flashbangThrownFuze.sqf @@ -4,7 +4,7 @@ * Waits for the flashbang grenade fuze to trigger and 'explode' * * Arguments: - * 0: projectile - Flashbang Grenade + * 0: Flashbang grenade * * Return Value: * None @@ -18,16 +18,17 @@ params ["_projectile"]; TRACE_1("params",_projectile); -if (alive _projectile) then { - private _sounds = getArray (_projectile call CBA_fnc_getObjectConfig >> QGVAR(flashbangExplodeSound)); +if (!alive _projectile) exitWith {}; - (if (_sounds isEqualTo []) then { - [format ["A3\Sounds_F\arsenal\explosives\grenades\Explosion_HE_grenade_0%1.wss", floor (random 4) + 1], 5, 1.2, 400] - } else { - selectRandom _sounds - }) params ["_file", "_volume", "_pitch", "_distance"]; +private _posASL = getPosASL _projectile; +private _sounds = getArray (_projectile call CBA_fnc_getObjectConfig >> QGVAR(flashbangExplodeSound)); - playSound3D [_file, _projectile, false, getPosASL _projectile, _volume, _pitch, _distance]; +(if (_sounds isEqualTo []) then { + [format ["A3\Sounds_F\arsenal\explosives\grenades\Explosion_HE_grenade_0%1.wss", floor (random 4) + 1], 5, 1.2, 400] +} else { + selectRandom _sounds +}) params ["_file", "_volume", "_pitch", "_distance"]; - ["ace_flashbangExploded", [getPosASL _projectile]] call CBA_fnc_globalEvent; -}; +playSound3D [_file, _projectile, false, _posASL, _volume, _pitch, _distance]; + +["ace_flashbangExploded", [_posASL]] call CBA_fnc_globalEvent; diff --git a/addons/grenades/functions/fnc_incendiary.sqf b/addons/grenades/functions/fnc_incendiary.sqf index f0c2effac3..f0caf82ed8 100644 --- a/addons/grenades/functions/fnc_incendiary.sqf +++ b/addons/grenades/functions/fnc_incendiary.sqf @@ -1,11 +1,12 @@ #include "..\script_component.hpp" /* * Author: commy2 - * Makes incendiary burn. + * Makes an incendiary grenade burn. * * Arguments: - * 0: The grenade + * 0: Incendiary grenade * 1: Incendiary lifetime + * 2: Instigator's side * * Return Value: * None @@ -42,16 +43,16 @@ if (isNull _projectile) exitWith {TRACE_1("null",_projectile);}; private _position = position _projectile; -// --- AI +// Alert nearby hostile AI private _nearLocalEnemies = []; { { - if (local _x && {[_center, side _x] call BIS_fnc_sideIsEnemy}) then { // WE WANT THE OBJECTS SIDE HERE! + if (local _x && {[_center, side group _x] call BIS_fnc_sideIsEnemy}) then { // WE WANT THE OBJECT'S SIDE HERE! _nearLocalEnemies pushBackUnique _x; }; } forEach crew _x; -} forEach (_position nearObjects ALERT_NEAR_ENEMY_RANGE); +} forEach (_position nearObjects ALERT_NEAR_ENEMY_RANGE); //@todo replace with nearEntities in 2.18 { if (behaviour _x in ["SAFE", "AWARE"]) then { @@ -59,7 +60,7 @@ private _nearLocalEnemies = []; }; } forEach _nearLocalEnemies; -// --- fire +// Fire particles private _fire = "#particlesource" createVehicleLocal _position; _fire setParticleParams [ @@ -99,7 +100,7 @@ _fire setParticleRandom [PARTICLE_LIFE_TIME / 4, [0.15 * EFFECT_SIZE, 0.15 * EFF _fire setParticleFire [1.2,1.0,0.1]; _fire setDropInterval (1 / PARTICLE_DENSITY); -// --- smoke +// Smoke particles private _smoke = "#particlesource" createVehicleLocal _position; _smoke setParticleParams [ @@ -137,7 +138,7 @@ _smoke setParticleParams [ _smoke setParticleRandom [PARTICLE_SMOKE_LIFE_TIME / 2, [0.5 * EFFECT_SIZE, 0.5 * EFFECT_SIZE, 0.2 * EFFECT_SIZE], [0.3,0.3,0.5], 1, 0, [0,0,0,0.06], 0, 0]; _smoke setDropInterval (1 / PARTICLE_SMOKE_DENSITY); -// --- light +// Light private _light = "#lightpoint" createVehicleLocal (_position vectorAdd [0,0,0.5]); _light setLightBrightness 1.0; @@ -150,19 +151,20 @@ _light setLightDayLight false; _light lightAttachObject [_projectile, [0,0,0]]; -// --- sound +// Sound private _sound = objNull; if (isServer) then { _sound = createSoundSource ["Sound_Fire", _position, [], 0]; private _radius = 1.5 * getNumber (configOf _projectile >> "indirectHitRange"); private _intensity = getNumber (configOf _projectile >> "hit"); + [QEGVAR(fire,addFireSource), [_projectile, _radius, _intensity, _projectile, { params ["_endTime", "_projectile"]; // If incendiary no longer exists, exit if (isNull _projectile) exitWith { - false + false // return }; // Need to get the position every time, as grenade might have been moved @@ -181,37 +183,38 @@ if (isServer) then { {deleteVehicle _x} forEach _this; }, [_fire, _smoke, _light, _sound], _timeToLive] call CBA_fnc_waitAndExecute; -// --- damage +// Damage { - if (local _x && {isDamageAllowed _x}) then { - //systemChat format ["burn: %1", _x]; + // Inflame fireplace, barrels etc. + _x inflame true; - // --- destroy nearby static weapons and ammo boxes - if (_x isKindOf "StaticWeapon" || {_x isKindOf "ACE_RepairItem_Base"}) then { + // Destroy nearby static weapons and ammo boxes + if (_x isKindOf "StaticWeapon" || {_x isKindOf "ACE_RepairItem_Base"}) then { + _x setDamage 1; + + continue; + }; + + if (_x isKindOf "ReammoBox_F") then { + if ( + (["ace_cookoff"] call EFUNC(common,isModLoaded)) && + {EGVAR(cookoff,enableAmmobox)} && + {EGVAR(cookoff,ammoCookoffDuration) != 0} && + {_x getVariable [QEGVAR(cookoff,enableAmmoCookoff), true]} + ) then { + [QEGVAR(cookOff,cookOffBoxServer), _box] call CBA_fnc_serverEvent; + } else { _x setDamage 1; }; - if (_x isKindOf "ReammoBox_F") then { - if ( - (["ace_cookoff"] call EFUNC(common,isModLoaded)) && - {EGVAR(cookoff,enableAmmobox)} && - {EGVAR(cookoff,ammoCookoffDuration) != 0} && - {_x getVariable [QEGVAR(cookoff,enableAmmoCookoff), true]} - ) then { - [QEGVAR(cookOff,cookOffBoxServer), _box] call CBA_fnc_serverEvent; - } else { - _x setDamage 1; - }; - }; - // --- delete nearby ground weapon holders - if (_x isKindOf "WeaponHolder" || {_x isKindOf "WeaponHolderSimulated"}) then { - deleteVehicle _x; - }; - - // --- inflame fireplace, barrels etc. - _x inflame true; + continue; }; -} forEach (_position nearObjects DESTRUCTION_RADIUS); + + // Delete nearby ground weapon holders + if (_x isKindOf "WeaponHolder" || {_x isKindOf "WeaponHolderSimulated"}) then { + deleteVehicle _x; + }; +} forEach ((_position nearObjects DESTRUCTION_RADIUS) select {local _x && {isDamageAllowed _x}}); { // Damage vehicles (locality is checked in FUNC(damageEngineAndWheels)) diff --git a/addons/grenades/functions/fnc_nextMode.sqf b/addons/grenades/functions/fnc_nextMode.sqf index d3d25027b1..f33fa7a5a5 100644 --- a/addons/grenades/functions/fnc_nextMode.sqf +++ b/addons/grenades/functions/fnc_nextMode.sqf @@ -7,21 +7,16 @@ * None * * Return Value: - * Handeled + * Handled * * Example: - * [] call ace_grenades_fnc_nextMode + * call ace_grenades_fnc_nextMode * * Public: No */ -private _mode = GVAR(currentThrowMode); - -if (_mode == 4) then { - _mode = 0; -} else { - _mode = _mode + 1; -}; +// _mode is 0-4, don't overflow +private _mode = (GVAR(currentThrowMode) + 1) % 5; private _currentThrowable = currentThrowable ACE_player; diff --git a/addons/grenades/functions/fnc_throwGrenade.sqf b/addons/grenades/functions/fnc_throwGrenade.sqf index 939e0755da..a440c8fd1b 100644 --- a/addons/grenades/functions/fnc_throwGrenade.sqf +++ b/addons/grenades/functions/fnc_throwGrenade.sqf @@ -27,40 +27,26 @@ if (isNull _projectile) then { private _config = configFile >> "CfgAmmo" >> _ammo; -// handle special grenades and sounds +// Handle special grenades and sounds if (local _unit) then { - // handle priming sound, if present - private _soundConfig = getArray (configFile >> "CfgAmmo" >> _ammo >> QGVAR(pullPinSound)); + // Handle priming sound, if present + private _soundConfig = getArray (_config >> QGVAR(pullPinSound)); + if (_soundConfig isNotEqualTo []) then { _soundConfig params ["_file", "_volume", "_pitch", "_distance"]; - playSound3D [_file, objNull, false, getPosASL _projectile, _volume, _pitch, _distance]; + playSound3D [_file, objNull, insideBuilding _unit >= 0.5, getPosASL _projectile, _volume, _pitch, _distance]; }; if (getNumber (_config >> QGVAR(flashbang)) == 1) then { - private _bangs = 1; - private _entry = _config >> QGVAR(flashbangBangs); - if (isNumber _entry || isText _entry) then { - _bangs = getNumber _entry; - }; - private _fuzeTimeBase = getNumber (_config >> "explosionTime"); - - private _interval = 0.5; - _entry = _config >> QGVAR(flashbangInterval); - if (isNumber _entry || isText _entry) then { - _interval = getNumber _entry; - }; - - private _maxDeviation = 0.1; - _entry = _config >> QGVAR(flashbangIntervalMaxDeviation); - if (isNumber _entry || isText _entry) then { - _maxDeviation = getNumber _entry; - }; + private _bangs = [_config >> QGVAR(flashbangBangs), "NUMBER", 1] call CBA_fnc_getConfigEntry; + private _interval = [_config >> QGVAR(flashbangInterval), "NUMBER", 0.5] call CBA_fnc_getConfigEntry; + private _maxDeviation = [_config >> QGVAR(flashbangIntervalMaxDeviation), "NUMBER", 0.1] call CBA_fnc_getConfigEntry; for "_i" from 0 to (_bangs - 1) do { - private _fuzeTime = _fuzeTimeBase + _i*_interval + random [- _maxDeviation, 0, _maxDeviation]; + private _fuzeTime = _fuzeTimeBase + _i * _interval + random [-_maxDeviation, 0, _maxDeviation]; - [FUNC(flashbangThrownFuze), [_projectile], _fuzeTime] call CBA_fnc_waitAndExecute; + [LINKFUNC(flashbangThrownFuze), _projectile, _fuzeTime] call CBA_fnc_waitAndExecute; }; }; }; @@ -71,60 +57,56 @@ if (getNumber (_config >> QGVAR(flare)) == 1) then { private _color = getArray (_config >> QGVAR(color)); private _intensity = _color deleteAt 3; - [FUNC(flare), [_projectile, _color, _intensity, _timeToLive], _fuzeTime] call CBA_fnc_waitAndExecute; + [LINKFUNC(flare), [_projectile, _color, _intensity, _timeToLive], _fuzeTime] call CBA_fnc_waitAndExecute; }; if (getNumber (_config >> QGVAR(incendiary)) == 1) then { private _fuzeTime = getNumber (_config >> "explosionTime"); private _timeToLive = getNumber (_config >> "timeToLive"); - [FUNC(incendiary), [_projectile, _timeToLive, side _unit], _fuzeTime] call CBA_fnc_waitAndExecute; // WE WANT THE OBJECTS SIDE HERE! + [LINKFUNC(incendiary), [_projectile, _timeToLive, side group _unit], _fuzeTime] call CBA_fnc_waitAndExecute; // Get the unit's real side (will return civilian if unconscious) }; -// handle throw modes +// Handle throw modes if (_unit != ACE_player) exitWith {}; if (_unit getVariable [QEGVAR(advanced_throwing,primed), false]) exitWith {LOG("advanced_throwing throw");}; -private _mode = GVAR(currentThrowMode); +if (GVAR(currentThrowMode) == 0) exitWith {}; -if (_mode != 0) then { - private _velocity = velocity _projectile; +private _velocity = velocity _projectile; - switch (_mode) do { - //high throw - case 1 : { - _velocity = [ - 0.5 * (_velocity select 0), - 0.5 * (_velocity select 1), - [0, 0, 0] distance (_velocity vectorMultiply 0.5) - ]; - }; - //precise throw - case 2 : { - _velocity = (_unit weaponDirection _weapon) vectorMultiply (vectorMagnitude _velocity); - }; - //roll grenade - case 3 : { - private _posASL = getPosASL _projectile; +switch (GVAR(currentThrowMode)) do { + // High throw + case 1: { + _velocity = _velocity vectorMultiply 0.5; - // getPos is unreliable, as surfaces in some ruins are not recognised as surfaces - private _lisPos = (lineIntersectsSurfaces [_posASL, _posASL vectorAdd [0, 0, -1e11], ACE_player, objNull, true, 1, "ROADWAY", "FIRE"]) select 0; - _projectile setPosASL ((_lisPos select 0) vectorAdd [0, 0, 0.2]); - - // Rotate throwables by 90° to the side by default, so cylindrical throwables can be rolled - private _vectorDirAndUp = getArray (_config >> QGVAR(rollVectorDirAndUp)); - _vectorDirAndUp params [["_vectorDir", [0, 1, 0], [[]], 3], ["_vectorUp", [1, 0, 0], [[]], 3]]; - - // Do as if object were facing north - _projectile setVectorDirAndUp ([[_vectorDir, _vectorUp], -(direction _projectile), 0, 0] call BIS_fnc_transformVectorDirAndUp); - - _velocity = (vectorDir _unit) vectorMultiply 10; - }; - //drop grenade - case 4 : { - _velocity = [0, 0, 0]; - }; + _velocity set [2, vectorMagnitude _velocity]; }; + // Precise throw + case 2: { + _velocity = (_unit weaponDirection _weapon) vectorMultiply (vectorMagnitude _velocity); + }; + // Roll grenade + case 3: { + private _posASL = getPosASL _projectile; - _projectile setVelocity _velocity; + // getPos is unreliable, as surfaces in some ruins are not recognised as surfaces + private _lisPos = (lineIntersectsSurfaces [_posASL, _posASL vectorAdd [0, 0, -1e11], ACE_player, objNull, true, 1, "ROADWAY", "FIRE"]) select 0; + _projectile setPosASL ((_lisPos select 0) vectorAdd [0, 0, 0.2]); + + // Rotate throwables by 90° to the side by default, so cylindrical throwables can be rolled + private _vectorDirAndUp = getArray (_config >> QGVAR(rollVectorDirAndUp)); + _vectorDirAndUp params [["_vectorDir", [0, 1, 0], [[]], 3], ["_vectorUp", [1, 0, 0], [[]], 3]]; + + // Do as if object were facing north + _projectile setVectorDirAndUp ([[_vectorDir, _vectorUp], -(direction _projectile), 0, 0] call BIS_fnc_transformVectorDirAndUp); + + _velocity = (vectorDir _unit) vectorMultiply 10; + }; + // Drop grenade + case 4: { + _velocity = [0, 0, 0]; + }; }; + +_projectile setVelocity _velocity; diff --git a/addons/grenades/initSettings.inc.sqf b/addons/grenades/initSettings.inc.sqf index b6fa36f459..6a6ceb8c37 100644 --- a/addons/grenades/initSettings.inc.sqf +++ b/addons/grenades/initSettings.inc.sqf @@ -1,9 +1,10 @@ [ - QGVAR(convertExplosives), "CHECKBOX", + QGVAR(convertExplosives), + "CHECKBOX", [LSTRING(convertExplosives_DisplayName), LSTRING(convertExplosives_Description)], LSTRING(Settings_DisplayName), true, - true, - {}, - true + 1, + {[QGVAR(convertExplosives), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart ] call CBA_fnc_addSetting; diff --git a/addons/grenades/script_component.hpp b/addons/grenades/script_component.hpp index ba673d0f33..e49fa21ca9 100644 --- a/addons/grenades/script_component.hpp +++ b/addons/grenades/script_component.hpp @@ -16,11 +16,6 @@ #include "\z\ace\addons\main\script_macros.hpp" -#define EFFECT_STAGE_RESETAI 0 -#define EFFECT_STAGE_DELETELIGHT 1 -#define EFFECT_STAGE_PARTIALRECOVERY 2 -#define EFFECT_STAGE_FULLRECOVERY 3 - #define EFFECT_SIZE 1 #define MIN_EXPLOSION_TIME_FOR_ROLL 1 From 1c6c4d6bff6fa6a5e1f8328cf3657d513fa2f808 Mon Sep 17 00:00:00 2001 From: Mike-MF Date: Tue, 18 Jun 2024 15:08:03 +0100 Subject: [PATCH 101/290] All - Fix parentheses around code (#10073) * Fix Brackets around code * Update fnc_handleFired.sqf * Shouldn't have changed this one --------- Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> --- .../functions/fnc_handleFired.sqf | 2 +- .../functions/fnc_readAmmoDataFromConfig.sqf | 2 +- addons/advanced_throwing/XEH_postInit.sqf | 2 +- .../functions/fnc_prepare.sqf | 2 +- .../advanced_throwing/functions/fnc_throw.sqf | 2 +- addons/arsenal/functions/fnc_showItem.sqf | 2 +- .../artillerytables/functions/fnc_firedEH.sqf | 2 +- .../functions/fnc_interactMenuOpened.sqf | 2 +- addons/atragmx/functions/fnc_initGunList.sqf | 2 +- .../fnc_read_gun_list_entries_from_config.sqf | 2 +- .../fnc_target_speed_assist_timer.sqf | 2 +- ...c_toggle_c1_ballistic_coefficient_data.sqf | 2 +- .../fnc_toggle_muzzle_velocity_data.sqf | 2 +- .../functions/fnc_toggle_truing_drop.sqf | 2 +- .../functions/fnc_update_zero_range.sqf | 2 +- addons/attach/functions/fnc_handleKilled.sqf | 2 +- .../functions/fnc_doEscortCaptive.sqf | 2 +- .../captives/functions/fnc_setHandcuffed.sqf | 2 +- .../captives/functions/fnc_setSurrendered.sqf | 2 +- addons/common/dev/test_cfgPatches.sqf | 4 +- .../common/functions/fnc_defineVariable.sqf | 2 +- addons/common/functions/fnc_showHud.sqf | 2 +- .../functions/fnc_handlePunjiTrapTrigger.sqf | 2 + .../functions/fnc_handleDamage.sqf | 2 +- .../fnc_reload_handleAddTurretMag.sqf | 2 +- .../fnc_reload_handleRemoveTurretMag.sqf | 2 +- .../functions/fnc_disarmDropItems.sqf | 7 +- .../functions/fnc_eventTargetStart.sqf | 2 +- .../functions/fnc_openDisarmDialog.sqf | 11 ++-- addons/dragon/XEH_postInit.sqf | 4 +- addons/dragon/functions/fnc_sightAttach.sqf | 2 +- addons/dragon/functions/fnc_sightDetach.sqf | 2 +- .../functions/fnc_addDetonateActions.sqf | 4 +- .../functions/fnc_onIncapacitated.sqf | 2 +- addons/fastroping/XEH_postInit.sqf | 6 +- addons/fire/functions/fnc_burnIndicator.sqf | 2 +- addons/fortify/functions/fnc_setupModule.sqf | 4 +- addons/frag/functions/fnc_findReflections.sqf | 4 +- addons/frag/functions/fnc_frago.sqf | 2 +- addons/frag/functions/fnc_masterPFH.sqf | 2 +- addons/grenades/XEH_postInit.sqf | 1 + .../hellfire/functions/fnc_setupVehicle.sqf | 2 +- .../interact_menu/functions/fnc_keyDown.sqf | 2 +- .../functions/fnc_renderActionPoints.sqf | 2 +- addons/killtracker/XEH_postInit.sqf | 7 +- .../functions/fnc_seekerFindLaserSpot.sqf | 4 +- .../functions/fnc_refuelUAV.sqf | 2 +- .../functions/fnc_magazineRepackFinish.sqf | 2 +- .../functions/fnc_addGroupColorMapping.sqf | 4 +- .../functions/fnc_isValidColorArray.sqf | 2 +- .../functions/fnc_moduleGroupSettings.sqf | 5 +- .../functions/fnc_moduleSettings.sqf | 4 +- .../markers/functions/fnc_removeTimestamp.sqf | 6 +- addons/medical/dev/watchVariable.sqf | 6 +- addons/medical_gui/XEH_postInit.sqf | 2 +- .../functions/fnc_checkPulseLocal.sqf | 2 +- .../functions/fnc_fullHealLocal.sqf | 4 +- .../fnc_cycleAttackProfileKeyDown.sqf | 2 +- .../missileguidance/functions/fnc_onFired.sqf | 2 +- .../mk6mortar/functions/fnc_handleFired.sqf | 2 +- .../fnc_handlePlayerVehicleChanged.sqf | 2 +- addons/nightvision/XEH_postInit.sqf | 4 +- addons/nlaw/functions/fnc_keyDown.sqf | 4 +- addons/rearm/XEH_preStart.sqf | 2 +- addons/repair/dev/draw_showRepairInfo.sqf | 2 +- addons/repair/functions/fnc_canRepair.sqf | 2 +- .../functions/fnc_getSelectionsToIgnore.sqf | 2 +- .../functions/fnc_normalizeHitPoints.sqf | 2 +- addons/repair/functions/fnc_repair.sqf | 2 +- .../repair/functions/fnc_repair_failure.sqf | 2 +- .../repair/functions/fnc_repair_success.sqf | 2 +- addons/scopes/functions/fnc_adjustScope.sqf | 2 +- addons/scopes/functions/fnc_canAdjustZero.sqf | 2 +- addons/scopes/functions/fnc_canResetZero.sqf | 2 +- addons/scopes/functions/fnc_firedEH.sqf | 2 +- .../functions/fnc_getCurrentZeroRange.sqf | 4 +- addons/scopes/functions/fnc_getOptics.sqf | 2 +- addons/scopes/initKeybinds.inc.sqf | 16 ++--- addons/sitting/functions/fnc_sit.sqf | 2 +- .../switchunits/functions/fnc_switchUnit.sqf | 2 +- .../functions/fnc_generateStencilTexture.sqf | 8 +-- .../tagging/functions/fnc_stencilVehicle.sqf | 2 +- addons/vector/functions/fnc_onKeyHold.sqf | 2 +- addons/vehicle_damage/XEH_postInit.sqf | 2 +- .../functions/fnc_addKeyForVehicle.sqf | 8 ++- addons/vehiclelock/functions/fnc_lockpick.sqf | 7 +- .../vehiclelock/functions/fnc_moduleSync.sqf | 2 +- addons/viewports/functions/fnc_eachFrame.sqf | 2 +- .../viewports/functions/fnc_getSeatInfo.sqf | 2 +- .../functions/fnc_changeCamera.sqf | 2 +- addons/weaponselect/XEH_postInit.sqf | 2 +- .../functions/fnc_calculateWindSpeed.sqf | 12 ++-- addons/xm157/functions/fnc_keyPress.sqf | 4 +- .../zeus/functions/fnc_addObjectToCurator.sqf | 2 +- .../zeus/functions/fnc_bi_moduleCurator.sqf | 64 +++++++++---------- .../functions/fnc_moduleCargoParadrop.sqf | 4 +- .../fnc_moduleCargoParadropWaypoint.sqf | 2 +- .../fnc_moduleSetMedicalFacility.sqf | 2 +- .../functions/fnc_moduleSuicideBomber.sqf | 2 +- addons/zeus/functions/fnc_showMessage.sqf | 2 +- 100 files changed, 189 insertions(+), 175 deletions(-) diff --git a/addons/advanced_ballistics/functions/fnc_handleFired.sqf b/addons/advanced_ballistics/functions/fnc_handleFired.sqf index b41fd7a7c0..ff2fe85ae4 100644 --- a/addons/advanced_ballistics/functions/fnc_handleFired.sqf +++ b/addons/advanced_ballistics/functions/fnc_handleFired.sqf @@ -19,7 +19,7 @@ //IGNORE_PRIVATE_WARNING ["_unit", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile", "_vehicle", "_gunner", "_turret"]; TRACE_10("firedEH:",_unit,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile,_vehicle,_gunner,_turret); -if (!(_ammo isKindOf "BulletBase")) exitWith {}; +if !(_ammo isKindOf "BulletBase") exitWith {}; if (!alive _projectile) exitWith {}; if (underwater _unit) exitWith {}; diff --git a/addons/advanced_ballistics/functions/fnc_readAmmoDataFromConfig.sqf b/addons/advanced_ballistics/functions/fnc_readAmmoDataFromConfig.sqf index 125c3677b8..5190786924 100644 --- a/addons/advanced_ballistics/functions/fnc_readAmmoDataFromConfig.sqf +++ b/addons/advanced_ballistics/functions/fnc_readAmmoDataFromConfig.sqf @@ -40,7 +40,7 @@ if (_transonicStabilityCoef == 0) then { _transonicStabilityCoef = 0.5; }; private _dragModel = getNumber(_ammoConfig >> "ACE_dragModel"); -if (!(_dragModel in [1, 2, 5, 6, 7, 8])) then { +if !(_dragModel in [1, 2, 5, 6, 7, 8]) then { _dragModel = 1; }; private _ballisticCoefficients = getArray(_ammoConfig >> "ACE_ballisticCoefficients"); diff --git a/addons/advanced_throwing/XEH_postInit.sqf b/addons/advanced_throwing/XEH_postInit.sqf index b732f033f9..d91129b025 100644 --- a/addons/advanced_throwing/XEH_postInit.sqf +++ b/addons/advanced_throwing/XEH_postInit.sqf @@ -13,7 +13,7 @@ GVAR(tempWindInfo) = false; // Add keybinds ["ACE3 Weapons", QGVAR(prepare), localize LSTRING(Prepare), { // Condition - if (!([ACE_player] call FUNC(canPrepare))) exitWith {false}; + if !([ACE_player] call FUNC(canPrepare)) exitWith {false}; if (EGVAR(common,isReloading)) exitWith {true}; // Statement diff --git a/addons/advanced_throwing/functions/fnc_prepare.sqf b/addons/advanced_throwing/functions/fnc_prepare.sqf index 3008b8e540..c158ad5150 100644 --- a/addons/advanced_throwing/functions/fnc_prepare.sqf +++ b/addons/advanced_throwing/functions/fnc_prepare.sqf @@ -21,7 +21,7 @@ TRACE_1("params",_unit); // Select next throwable if one already in hand if (_unit getVariable [QGVAR(inHand), false]) exitWith { TRACE_1("inHand",_unit); - if (!(_unit getVariable [QGVAR(primed), false])) then { + if !(_unit getVariable [QGVAR(primed), false]) then { TRACE_1("not primed",_unit); // Restore muzzle ammo (setAmmo 1 has no impact if no appliccable throwable in inventory) // selectNextGrenade relies on muzzles array (setAmmo 0 removes the muzzle from the array and current can't be found, cycles between 0 and 1 muzzles) diff --git a/addons/advanced_throwing/functions/fnc_throw.sqf b/addons/advanced_throwing/functions/fnc_throw.sqf index 797f18d773..d6b38a6a0c 100644 --- a/addons/advanced_throwing/functions/fnc_throw.sqf +++ b/addons/advanced_throwing/functions/fnc_throw.sqf @@ -20,7 +20,7 @@ TRACE_1("params",_unit); // Prime the throwable if it hasn't been cooking already // Next to proper simulation this also has to happen before delay for orientation of the throwable to be set -if (!(_unit getVariable [QGVAR(primed), false])) then { +if !(_unit getVariable [QGVAR(primed), false]) then { [_unit] call FUNC(prime); }; diff --git a/addons/arsenal/functions/fnc_showItem.sqf b/addons/arsenal/functions/fnc_showItem.sqf index 7ceda5f0d5..f47f12d2bf 100644 --- a/addons/arsenal/functions/fnc_showItem.sqf +++ b/addons/arsenal/functions/fnc_showItem.sqf @@ -72,6 +72,6 @@ if (_nextAction != GVAR(currentAction)) then { GVAR(currentAction) = _nextAction; }; -if (!(GVAR(currentAction) in ["Civil", "Salute"])) then { +if !(GVAR(currentAction) in ["Civil", "Salute"]) then { GVAR(center) selectWeapon ([primaryWeapon GVAR(center), secondaryWeapon GVAR(center), handgunWeapon GVAR(center), binocular GVAR(center)] select GVAR(selectedWeaponType)); // select correct weapon, prevents floating weapons }; diff --git a/addons/artillerytables/functions/fnc_firedEH.sqf b/addons/artillerytables/functions/fnc_firedEH.sqf index 01947b4ebe..f735c4c961 100644 --- a/addons/artillerytables/functions/fnc_firedEH.sqf +++ b/addons/artillerytables/functions/fnc_firedEH.sqf @@ -25,7 +25,7 @@ params ["_vehicle", "", "", "", "", "_magazine", "_projectile", "_gunner"]; TRACE_4("firedEH",_vehicle,_magazine,_projectile,_gunner); -if (!([_gunner] call EFUNC(common,isPlayer))) exitWith {}; // AI don't know how to use (this does give them more range than a player) +if !([_gunner] call EFUNC(common,isPlayer)) exitWith {}; // AI don't know how to use (this does give them more range than a player) if ((gunner _vehicle) != _gunner) exitWith {}; // check if primaryGunner diff --git a/addons/artillerytables/functions/fnc_interactMenuOpened.sqf b/addons/artillerytables/functions/fnc_interactMenuOpened.sqf index b7d6371339..4ba6342fc8 100644 --- a/addons/artillerytables/functions/fnc_interactMenuOpened.sqf +++ b/addons/artillerytables/functions/fnc_interactMenuOpened.sqf @@ -19,7 +19,7 @@ params ["_menuType"]; TRACE_1("interactMenuOpened",_menuType); if (_menuType != 1) exitWith {}; -if (!("ACE_artilleryTable" in (ace_player call EFUNC(common,uniqueItems)))) exitWith {}; +if !("ACE_artilleryTable" in (ace_player call EFUNC(common,uniqueItems))) exitWith {}; private _vehicleAdded = ace_player getVariable [QGVAR(vehiclesAdded), []]; private _rangeTablesShown = ace_player getVariable [QGVAR(rangeTablesShown), []]; diff --git a/addons/atragmx/functions/fnc_initGunList.sqf b/addons/atragmx/functions/fnc_initGunList.sqf index 2ae67bb78d..515bc9013e 100644 --- a/addons/atragmx/functions/fnc_initGunList.sqf +++ b/addons/atragmx/functions/fnc_initGunList.sqf @@ -23,7 +23,7 @@ if ((profileNamespace getVariable ["ACE_ATragMX_profileNamespaceVersion", 0]) == _resetGunList = false; { // Verify each gun has correct param type - if (!(_x isEqualTypeArray ["", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", [], [], false])) exitWith { + if !(_x isEqualTypeArray ["", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", [], [], false]) exitWith { _resetGunList = true; }; } forEach GVAR(gunList); diff --git a/addons/atragmx/functions/fnc_read_gun_list_entries_from_config.sqf b/addons/atragmx/functions/fnc_read_gun_list_entries_from_config.sqf index 31451c7ff8..cbbb4603e3 100644 --- a/addons/atragmx/functions/fnc_read_gun_list_entries_from_config.sqf +++ b/addons/atragmx/functions/fnc_read_gun_list_entries_from_config.sqf @@ -74,7 +74,7 @@ private _validate_preset = { ERROR(_errorMsg); _valid = false; }; - if (!((_this select 17) in ["ASM", "ICAO"])) then { + if !((_this select 17) in ["ASM", "ICAO"]) then { private _errorMsg = format ["Invalid atmosphere model: %1", _this select 17]; ERROR(_errorMsg); _valid = false; diff --git a/addons/atragmx/functions/fnc_target_speed_assist_timer.sqf b/addons/atragmx/functions/fnc_target_speed_assist_timer.sqf index b34dd666f2..5408edee3a 100644 --- a/addons/atragmx/functions/fnc_target_speed_assist_timer.sqf +++ b/addons/atragmx/functions/fnc_target_speed_assist_timer.sqf @@ -26,7 +26,7 @@ if !(ctrlVisible 9000) then { params ["_args"]; _args params ["_startTime"]; - if (!(GVAR(speedAssistTimer))) exitWith { + if !(GVAR(speedAssistTimer)) exitWith { GVAR(speedAssistTimer) = true; ctrlSetText [8006, Str(Round((CBA_missionTime - _startTime) * 10) / 10)]; diff --git a/addons/atragmx/functions/fnc_toggle_c1_ballistic_coefficient_data.sqf b/addons/atragmx/functions/fnc_toggle_c1_ballistic_coefficient_data.sqf index bb581ad6ea..a8cd7ce52a 100644 --- a/addons/atragmx/functions/fnc_toggle_c1_ballistic_coefficient_data.sqf +++ b/addons/atragmx/functions/fnc_toggle_c1_ballistic_coefficient_data.sqf @@ -15,7 +15,7 @@ * Public: No */ -if (!(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false])) exitWith {}; +if !(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) exitWith {}; if (ctrlVisible 17000) then { false call FUNC(show_c1_ballistic_coefficient_data); diff --git a/addons/atragmx/functions/fnc_toggle_muzzle_velocity_data.sqf b/addons/atragmx/functions/fnc_toggle_muzzle_velocity_data.sqf index 562ef30553..34326b251d 100644 --- a/addons/atragmx/functions/fnc_toggle_muzzle_velocity_data.sqf +++ b/addons/atragmx/functions/fnc_toggle_muzzle_velocity_data.sqf @@ -15,7 +15,7 @@ * Public: No */ -if (!(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false])) exitWith {}; +if !(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) exitWith {}; if (ctrlVisible 16000) then { false call FUNC(show_muzzle_velocity_data); diff --git a/addons/atragmx/functions/fnc_toggle_truing_drop.sqf b/addons/atragmx/functions/fnc_toggle_truing_drop.sqf index 2c61b1776b..2d13619de0 100644 --- a/addons/atragmx/functions/fnc_toggle_truing_drop.sqf +++ b/addons/atragmx/functions/fnc_toggle_truing_drop.sqf @@ -15,7 +15,7 @@ * Public: No */ -if (!(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false])) exitWith {}; +if !(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) exitWith {}; if (ctrlVisible 18000) then { false call FUNC(show_truing_drop); diff --git a/addons/atragmx/functions/fnc_update_zero_range.sqf b/addons/atragmx/functions/fnc_update_zero_range.sqf index 023a5a7ee2..8a3eca1344 100644 --- a/addons/atragmx/functions/fnc_update_zero_range.sqf +++ b/addons/atragmx/functions/fnc_update_zero_range.sqf @@ -35,7 +35,7 @@ if (!GVAR(atmosphereModeTBH)) then { _relativeHumidity = 0.5; }; -private _scopeBaseAngle = if (!(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false])) then { +private _scopeBaseAngle = if !(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { private _zeroAngle = "ace_advanced_ballistics" callExtension format ["calcZero:%1:%2:%3:%4", _zeroRange, _muzzleVelocity, _airFriction, _boreHeight]; (parseNumber _zeroAngle) } else { diff --git a/addons/attach/functions/fnc_handleKilled.sqf b/addons/attach/functions/fnc_handleKilled.sqf index ef08aff305..2183b05b42 100644 --- a/addons/attach/functions/fnc_handleKilled.sqf +++ b/addons/attach/functions/fnc_handleKilled.sqf @@ -28,7 +28,7 @@ if (_attachedList isEqualTo []) exitWith {}; TRACE_2("detaching",_xObject,_deadUnit); detach _xObject; //If it's a vehicle, also delete the attached - if (!(_deadUnit isKindOf "CAManBase")) then { + if !(_deadUnit isKindOf "CAManBase") then { _xObject setPos ((getPos _deadUnit) vectorAdd [0, 0, -1000]); [{deleteVehicle (_this select 0)}, [_xObject], 2] call CBA_fnc_waitAndExecute; }; diff --git a/addons/captives/functions/fnc_doEscortCaptive.sqf b/addons/captives/functions/fnc_doEscortCaptive.sqf index 817745ece3..7eb25ccc4c 100644 --- a/addons/captives/functions/fnc_doEscortCaptive.sqf +++ b/addons/captives/functions/fnc_doEscortCaptive.sqf @@ -44,7 +44,7 @@ if (_state) then { }; }; - if (!(_unit getVariable [QGVAR(isEscorting), false])) then { + if !(_unit getVariable [QGVAR(isEscorting), false]) then { [(_this select 1)] call CBA_fnc_removePerFrameHandler; [objNull, _target, false] call EFUNC(common,claim); detach _target; diff --git a/addons/captives/functions/fnc_setHandcuffed.sqf b/addons/captives/functions/fnc_setHandcuffed.sqf index c13da8f927..0c54d9a70a 100644 --- a/addons/captives/functions/fnc_setHandcuffed.sqf +++ b/addons/captives/functions/fnc_setHandcuffed.sqf @@ -58,7 +58,7 @@ if (_state) then { // fix anim on mission start (should work on dedicated servers) [{ params ["_unit"]; - if (!(_unit getVariable [QGVAR(isHandcuffed), false])) exitWith {}; + if !(_unit getVariable [QGVAR(isHandcuffed), false]) exitWith {}; if ((vehicle _unit) == _unit) then { [_unit] call EFUNC(common,fixLoweredRifleAnimation); diff --git a/addons/captives/functions/fnc_setSurrendered.sqf b/addons/captives/functions/fnc_setSurrendered.sqf index 393465e08e..4acc8529bb 100644 --- a/addons/captives/functions/fnc_setSurrendered.sqf +++ b/addons/captives/functions/fnc_setSurrendered.sqf @@ -81,7 +81,7 @@ if (_state) then { if (_unit == ACE_player) then { //only re-enable HUD if not handcuffed - if (!(_unit getVariable [QGVAR(isHandcuffed), false])) then { + if !(_unit getVariable [QGVAR(isHandcuffed), false]) then { ["captive", []] call EFUNC(common,showHud); //same as showHud true; }; }; diff --git a/addons/common/dev/test_cfgPatches.sqf b/addons/common/dev/test_cfgPatches.sqf index e2ce10b2c6..c5f3c81ef5 100644 --- a/addons/common/dev/test_cfgPatches.sqf +++ b/addons/common/dev/test_cfgPatches.sqf @@ -50,7 +50,7 @@ private _allWeapons = []; private _vics = "(configName _x) select [0,3] == 'ace'" configClasses (configFile >> "CfgVehicles"); { if (((getNumber (_x >> "scope")) == 2) || {((getNumber (_x >> "scopeCurator")) == 2)}) then { - if (!((toLowerANSI configName _x) in _allUnits)) then { + if !((toLowerANSI configName _x) in _allUnits) then { WARNING_2("Not in any units[] - %1 from %2",configName _x,configSourceMod _x); _testPass = false; }; @@ -62,7 +62,7 @@ private _weapons = "(configName _x) select [0,3] == 'ace'" configClasses (config { private _type = toLowerANSI configName _x; if (((getNumber (_x >> "scope")) == 2) || {((getNumber (_x >> "scopeCurator")) == 2)}) then { - if (!((toLowerANSI configName _x) in _allWeapons)) then { + if !((toLowerANSI configName _x) in _allWeapons) then { WARNING_2("Not in any weapons[] - %1 from %2",configName _x,configSourceMod _x); _testPass = false; }; diff --git a/addons/common/functions/fnc_defineVariable.sqf b/addons/common/functions/fnc_defineVariable.sqf index 6cf537b1f8..85eb7b447f 100644 --- a/addons/common/functions/fnc_defineVariable.sqf +++ b/addons/common/functions/fnc_defineVariable.sqf @@ -24,7 +24,7 @@ params ["_name", "_value", "_defaultGlobal", "_category", ["_code", 0], ["_persi if (isNil "_defaultGlobal") exitWith {}; -if (!(_name isEqualType "")) exitwith { +if !(_name isEqualType "") exitwith { [format ["Tried to the deinfe a variable with an invalid name: %1 Arguments: %2", _name, _this]] call FUNC(debug); }; diff --git a/addons/common/functions/fnc_showHud.sqf b/addons/common/functions/fnc_showHud.sqf index 1ca7ca8106..5bb0153772 100644 --- a/addons/common/functions/fnc_showHud.sqf +++ b/addons/common/functions/fnc_showHud.sqf @@ -56,7 +56,7 @@ private _resultMask = []; for "_index" from 0 to 9 do { private _set = true; //Default to true { - if (!(_x select _index)) exitWith { + if !(_x select _index) exitWith { _set = false; //Any false will make it false }; } forEach _masks; diff --git a/addons/compat_sog/functions/fnc_handlePunjiTrapTrigger.sqf b/addons/compat_sog/functions/fnc_handlePunjiTrapTrigger.sqf index dc51a3140c..7cac6829c5 100644 --- a/addons/compat_sog/functions/fnc_handlePunjiTrapTrigger.sqf +++ b/addons/compat_sog/functions/fnc_handlePunjiTrapTrigger.sqf @@ -14,7 +14,9 @@ * * Public: No */ + params ["_trap"]; + if !(GETEGVAR(medical,enabled,false)) exitWith {}; private _radius = getNumber (configOf _trap >> "indirectHitRange"); diff --git a/addons/concertina_wire/functions/fnc_handleDamage.sqf b/addons/concertina_wire/functions/fnc_handleDamage.sqf index 02092044ef..f5f1177df5 100644 --- a/addons/concertina_wire/functions/fnc_handleDamage.sqf +++ b/addons/concertina_wire/functions/fnc_handleDamage.sqf @@ -22,7 +22,7 @@ params ["_wire", "", "_damage", "_source", ""]; if (_damage < 0.5) exitWith { 0 }; -if (!(isNull _source)) then { +if (!isNull _source) then { _wire setVariable [QGVAR(lastDamager), _source]; }; diff --git a/addons/csw/functions/fnc_reload_handleAddTurretMag.sqf b/addons/csw/functions/fnc_reload_handleAddTurretMag.sqf index e5aa51d342..d7af22d319 100644 --- a/addons/csw/functions/fnc_reload_handleAddTurretMag.sqf +++ b/addons/csw/functions/fnc_reload_handleAddTurretMag.sqf @@ -25,7 +25,7 @@ params ["_vehicle", "_turret", "_magSource", "_carryMag", "_ammoReceived", ["_re TRACE_6("reload_handleAddTurretMag",_vehicle,_turret,_magSource,_carryMag,_ammoReceived,_returnTo); TRACE_2("",local _vehicle,_vehicle turretLocal _turret); -if (!(_vehicle turretLocal _turret)) exitWith {}; +if !(_vehicle turretLocal _turret) exitWith {}; ([_vehicle, _turret, _carryMag] call FUNC(reload_canLoadMagazine)) params ["_canAdd", "_loadedMag", "_neededAmmo", "_isBeltLinking"]; TRACE_4("canLoad",_canAdd,_loadedMag,_neededAmmo,_isBeltLinking); diff --git a/addons/csw/functions/fnc_reload_handleRemoveTurretMag.sqf b/addons/csw/functions/fnc_reload_handleRemoveTurretMag.sqf index 59d948ba27..51036b525a 100644 --- a/addons/csw/functions/fnc_reload_handleRemoveTurretMag.sqf +++ b/addons/csw/functions/fnc_reload_handleRemoveTurretMag.sqf @@ -24,7 +24,7 @@ params ["_vehicle", "_turretPath", "_carryMag", "_vehMag", "_unloadTo"]; TRACE_5("removeTurretMag EH",_vehicle,_turretPath,_carryMag,_vehMag,_unloadTo); TRACE_3("",local _vehicle,_vehicle turretLocal _turretPath,local _unloadTo); -if (!(_vehicle turretLocal _turretPath)) exitWith {}; +if !(_vehicle turretLocal _turretPath) exitWith {}; private _magsInWeapon = []; // Check how much ammo it has now: { diff --git a/addons/disarming/functions/fnc_disarmDropItems.sqf b/addons/disarming/functions/fnc_disarmDropItems.sqf index e1a4c379b4..6e842e739a 100644 --- a/addons/disarming/functions/fnc_disarmDropItems.sqf +++ b/addons/disarming/functions/fnc_disarmDropItems.sqf @@ -30,7 +30,7 @@ private _fncSumArray = { }; //Sanity Checks -if (!([_target] call FUNC(canBeDisarmed))) exitWith { +if !([_target] call FUNC(canBeDisarmed)) exitWith { [_caller, _target, "Debug: Cannot disarm target"] call FUNC(eventTargetFinish); }; if (_doNotDropAmmo && {({_x in _listOfItemsToRemove} count (magazines _target)) > 0}) exitWith { @@ -74,7 +74,6 @@ if (_holder getVariable [QGVAR(holderInUse), false]) exitWith { }; _holder setVariable [QGVAR(holderInUse), true]; - //Remove Magazines private _targetMagazinesStart = magazinesAmmo _target; private _holderMagazinesStart = magazinesAmmoCargo _holder; @@ -96,7 +95,7 @@ if (({((_x select 0) in _listOfItemsToRemove) && {(getNumber (configFile >> "Cfg [_caller, _target, "Debug: Didn't Remove Magazines"] call FUNC(eventTargetFinish); }; //Verify holder has mags unit had -if (!([_targetMagazinesStart, _targetMagazinesEnd, _holderMagazinesStart, _holderMagazinesEnd] call FUNC(verifyMagazinesMoved))) then { +if !([_targetMagazinesStart, _targetMagazinesEnd, _holderMagazinesStart, _holderMagazinesEnd] call FUNC(verifyMagazinesMoved)) then { _holder setVariable [QGVAR(holderInUse), false]; [_caller, _target, "Debug: Crate Magazines not in holder"] call FUNC(eventTargetFinish); }; @@ -238,7 +237,7 @@ if (_holderIsEmpty) then { [_caller, _target, "Debug: Drop Actions Timeout"] call FUNC(eventTargetFinish); }; //If target lost disarm status: - if (!([_target] call FUNC(canBeDisarmed))) exitWith { + if !([_target] call FUNC(canBeDisarmed)) exitWith { _holder setVariable [QGVAR(holderInUse), false]; [_caller, _target, "Debug: Target cannot be disarmed"] call FUNC(eventTargetFinish); }; diff --git a/addons/disarming/functions/fnc_eventTargetStart.sqf b/addons/disarming/functions/fnc_eventTargetStart.sqf index 7173f66a76..a7154ce2e4 100644 --- a/addons/disarming/functions/fnc_eventTargetStart.sqf +++ b/addons/disarming/functions/fnc_eventTargetStart.sqf @@ -32,7 +32,7 @@ private _itemsToAdd = []; } forEach _listOfObjectsToRemove; { - if (!(_x in _listOfObjectsToRemove)) then { + if !(_x in _listOfObjectsToRemove) then { _listOfObjectsToRemove pushBack _x; }; } forEach _itemsToAdd; diff --git a/addons/disarming/functions/fnc_openDisarmDialog.sqf b/addons/disarming/functions/fnc_openDisarmDialog.sqf index da9a860678..6cf15f4cad 100644 --- a/addons/disarming/functions/fnc_openDisarmDialog.sqf +++ b/addons/disarming/functions/fnc_openDisarmDialog.sqf @@ -16,11 +16,14 @@ * * Public: No */ + params ["_caller", "_target"]; -#define DEFUALTPATH "\A3\Ui_f\data\GUI\Cfg\Ranks\%1_gs.paa" + +#define DEFAULTPATH "\A3\Ui_f\data\GUI\Cfg\Ranks\%1_gs.paa" + //Sanity Checks if (_caller != ACE_player) exitWith {ERROR("Player isn't caller?");}; -if (!([_player, _target] call FUNC(canPlayerDisarmUnit))) exitWith {ERROR("Can't Disarm Unit");}; +if !([_player, _target] call FUNC(canPlayerDisarmUnit)) exitWith {ERROR("Can't Disarm Unit");}; if (dialog) then {ERROR("Dialog open when trying to open disarm dialog"); closeDialog 0;}; disableSerialization; @@ -74,8 +77,8 @@ GVAR(disarmTarget) = _target; private _rankPicture = _display displayCtrl 1203; //Show rank and name (just like BIS's inventory) - private _icon = format [DEFUALTPATH, toLowerANSI (rank _target)]; - if (_icon isEqualTo DEFUALTPATH) then {_icon = ""}; + private _icon = format [DEFAULTPATH, toLowerANSI (rank _target)]; + if (_icon isEqualTo DEFAULTPATH) then {_icon = ""}; _rankPicture ctrlSetText _icon; _playerName ctrlSetText ([GVAR(disarmTarget), false, true] call EFUNC(common,getName)); diff --git a/addons/dragon/XEH_postInit.sqf b/addons/dragon/XEH_postInit.sqf index 0305fe772a..2360a5bd97 100644 --- a/addons/dragon/XEH_postInit.sqf +++ b/addons/dragon/XEH_postInit.sqf @@ -6,7 +6,7 @@ ["vehicle", { params ["","_vehicle"]; TRACE_2("vehicle change",_vehicle,typeOf _vehicle); - if (!(_vehicle isKindOf QGVAR(staticBase))) exitWith {}; + if !(_vehicle isKindOf QGVAR(staticBase)) exitWith {}; _vehicle animate ["rest_rotate", 0]; @@ -14,7 +14,7 @@ [GVAR(pfID)] call CBA_fnc_removePerFrameHandler; private _lastView = cameraView; - if (!(_lastView in ["INTERNAL", "EXTERNAL"])) then { _lastView == "INTERNAL"; }; + if !(_lastView in ["INTERNAL", "EXTERNAL"]) then { _lastView == "INTERNAL"; }; GVAR(pfID) = [{ params ["_args"]; diff --git a/addons/dragon/functions/fnc_sightAttach.sqf b/addons/dragon/functions/fnc_sightAttach.sqf index 76ad9c3356..de085942b7 100644 --- a/addons/dragon/functions/fnc_sightAttach.sqf +++ b/addons/dragon/functions/fnc_sightAttach.sqf @@ -21,7 +21,7 @@ params ["_target", "_unit", ["_event", false]]; TRACE_3("sightAttach",_target,_unit,_event); if (_event isEqualTo true) then { // this is actually needed as 3rd arg may not be bool - if (!(_target turretLocal [0])) exitWith {}; + if !(_target turretLocal [0]) exitWith {}; _target setVariable [QGVAR(sightAttached), true, true]; _target animate ["optic_hide", 0]; _target addWeapon QGVAR(superStatic); diff --git a/addons/dragon/functions/fnc_sightDetach.sqf b/addons/dragon/functions/fnc_sightDetach.sqf index c9d03e22e6..a5ac159a33 100644 --- a/addons/dragon/functions/fnc_sightDetach.sqf +++ b/addons/dragon/functions/fnc_sightDetach.sqf @@ -23,7 +23,7 @@ params ["_target", "_unit", ["_event", false]]; TRACE_3("sightDetach",_target,_unit,_event); if (_event isEqualTo true) then { // this is actually needed as 3rd arg may not be bool - if (!(_target turretLocal [0])) exitWith {}; + if !(_target turretLocal [0]) exitWith {}; _target setVariable [QGVAR(sightAttached), false, true]; _target animate ["optic_hide", 1]; _target removeWeapon QGVAR(superStatic); diff --git a/addons/explosives/functions/fnc_addDetonateActions.sqf b/addons/explosives/functions/fnc_addDetonateActions.sqf index ea4b87128a..d950278c35 100644 --- a/addons/explosives/functions/fnc_addDetonateActions.sqf +++ b/addons/explosives/functions/fnc_addDetonateActions.sqf @@ -53,7 +53,7 @@ private _explosivesList = []; // If the detonator is not active, is a clacker and has assigned explosives, generate an interaction to make it the active detonator for use with the "trigger all" keybind if ( _detonator != GVAR(activeTrigger) && - {_detonator != "Cellphone"} && + {_detonator != "Cellphone"} && { _explosivesList isNotEqualTo [] || {_detonator == "ACE_DeadManSwitch" && {_unit getVariable [QGVAR(deadmanInvExplosive), ""] != ""}} @@ -144,7 +144,7 @@ if (_detonator != "ACE_DeadManSwitch") then { private _procressedMags = []; { private _mag = _x; - if (!(_mag in _procressedMags)) then { + if !(_mag in _procressedMags) then { _procressedMags pushBack _x; private _magConfig = configFile >> "CfgMagazines" >> _mag; private _supportedTriggers = getArray (_magConfig >> "ACE_Triggers" >> "SupportedTriggers"); diff --git a/addons/explosives/functions/fnc_onIncapacitated.sqf b/addons/explosives/functions/fnc_onIncapacitated.sqf index 09d1d7b21f..5e7b8797e1 100644 --- a/addons/explosives/functions/fnc_onIncapacitated.sqf +++ b/addons/explosives/functions/fnc_onIncapacitated.sqf @@ -37,7 +37,7 @@ TRACE_2("placed",_deadman,_range); //Handle deadman connected to explosive in inventory private _connectedInventoryExplosive = _unit getVariable [QGVAR(deadmanInvExplosive), ""]; if (_connectedInventoryExplosive != "") then { - if (!(_connectedInventoryExplosive in (magazines _unit))) exitWith {}; + if !(_connectedInventoryExplosive in (magazines _unit)) exitWith {}; //Remove mag and reset variable _unit removeMagazine _connectedInventoryExplosive; diff --git a/addons/fastroping/XEH_postInit.sqf b/addons/fastroping/XEH_postInit.sqf index 650b277dbf..0ba9231215 100644 --- a/addons/fastroping/XEH_postInit.sqf +++ b/addons/fastroping/XEH_postInit.sqf @@ -9,7 +9,7 @@ // Keybinds ["ACE3 Vehicles", QGVAR(fastRope), localize LSTRING(Interaction_fastRope), { if ((vehicle ACE_player) == ACE_player) exitWith {false}; - if (!([ACE_player, vehicle ACE_player, []] call EFUNC(common,canInteractWith))) exitWith {false}; + if !([ACE_player, vehicle ACE_player, []] call EFUNC(common,canInteractWith)) exitWith {false}; if ([ACE_player, vehicle ACE_player] call FUNC(canFastRope)) then { [ACE_player, vehicle ACE_player] call FUNC(fastRope); true @@ -20,7 +20,7 @@ ["ACE3 Vehicles", QGVAR(cutRopes), localize LSTRING(Interaction_cutRopes), { if ((vehicle ACE_player) == ACE_player) exitWith {false}; - if (!([ACE_player, vehicle ACE_player, []] call EFUNC(common,canInteractWith))) exitWith {false}; + if !([ACE_player, vehicle ACE_player, []] call EFUNC(common,canInteractWith)) exitWith {false}; if ([vehicle ACE_player] call FUNC(canCutRopes)) then { [vehicle ACE_player] call FUNC(cutRopes); true @@ -43,7 +43,7 @@ if (isServer) then { #ifdef DRAW_FASTROPE_INFO addMissionEventHandler ["Draw3D", { - if (!(cursorObject isKindOf "Helicopter")) exitWith {}; + if !(cursorObject isKindOf "Helicopter") 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/fire/functions/fnc_burnIndicator.sqf b/addons/fire/functions/fnc_burnIndicator.sqf index 13db8862c9..d876d18a07 100644 --- a/addons/fire/functions/fnc_burnIndicator.sqf +++ b/addons/fire/functions/fnc_burnIndicator.sqf @@ -30,7 +30,7 @@ if !(IS_UNCONSCIOUS(_unit)) then { _unit setVariable [QGVAR(indicatorIteration), _iteration]; }; -if (!([_unit] call FUNC(isBurning)) || { !alive _unit }) then { +if (!([_unit] call FUNC(isBurning)) || {!alive _unit}) then { [_pfhHandle] call CBA_fnc_removePerFrameHandler; _unit setVariable [QGVAR(burnUIPFH), -1]; }; diff --git a/addons/fortify/functions/fnc_setupModule.sqf b/addons/fortify/functions/fnc_setupModule.sqf index f032d98ebe..1215393a46 100644 --- a/addons/fortify/functions/fnc_setupModule.sqf +++ b/addons/fortify/functions/fnc_setupModule.sqf @@ -48,10 +48,10 @@ if IS_NUMBER(_preset) then { // Legacy support }; private _budget = _logic getVariable ["Budget", -1]; -if (!(_budget isEqualType 0)) then {_budget = -1}; +if !(_budget isEqualType 0) then {_budget = -1}; private _addToolItem = _logic getVariable ["AddToolItem", false]; -if (!(_addToolItem isEqualType false)) then {_addToolItem = false}; +if !(_addToolItem isEqualType false) then {_addToolItem = false}; private _objects = [_preset] call FUNC(getPlaceableSet); diff --git a/addons/frag/functions/fnc_findReflections.sqf b/addons/frag/functions/fnc_findReflections.sqf index 53931c3fda..a753934fe8 100644 --- a/addons/frag/functions/fnc_findReflections.sqf +++ b/addons/frag/functions/fnc_findReflections.sqf @@ -65,7 +65,7 @@ if (_zIndex < 5) then { while {count _nlos != count _excludes && {_c < (count _nlos)}} do { scopeName "mainSearch"; { - if (!(_forEachIndex in _excludes)) then { + if !(_forEachIndex in _excludes) then { private _index = _buckets pushBack [_x, [_x]]; _excludes pushBack _forEachIndex; _bucketPos = _x; @@ -74,7 +74,7 @@ if (_zIndex < 5) then { }; } forEach _nlos; { - if (!(_forEachIndex in _excludes)) then { + if !(_forEachIndex in _excludes) then { _testPos = _x; if (_testPos vectorDistanceSqr _bucketPos <= 30) then { _bucketList pushBack _x; diff --git a/addons/frag/functions/fnc_frago.sqf b/addons/frag/functions/fnc_frago.sqf index 87fabc4fc5..8fd77dbc73 100644 --- a/addons/frag/functions/fnc_frago.sqf +++ b/addons/frag/functions/fnc_frago.sqf @@ -127,7 +127,7 @@ if (_objects isNotEqualTo []) then { if (_currentCount < 10) then { private _count = ceil (random (sqrt (_m / 1000))); private _vecVar = FRAG_VEC_VAR; - if (!(_target isKindOf "Man")) then { + if !(_target isKindOf "Man") then { ADD(_vecVar,(sqrt _cubic) / 2000); if ((crew _target) isEqualTo [] && {_count > 0}) then { _count = 0 max (_count / 2); diff --git a/addons/frag/functions/fnc_masterPFH.sqf b/addons/frag/functions/fnc_masterPFH.sqf index ef0fbc3eda..004af9a9ce 100644 --- a/addons/frag/functions/fnc_masterPFH.sqf +++ b/addons/frag/functions/fnc_masterPFH.sqf @@ -34,7 +34,7 @@ while {_objectCount > 0 && {_iter < (GVAR(maxTrackPerFrame) min _objectCount)}} if (!isNil "_object") then { private _args = GVAR(arguments) select GVAR(lastIterationIndex); - if (!(_args call FUNC(pfhRound))) then { + if !(_args call FUNC(pfhRound)) then { _gcIndex pushBack GVAR(lastIterationIndex); // Add it to the GC if it returns false }; }; diff --git a/addons/grenades/XEH_postInit.sqf b/addons/grenades/XEH_postInit.sqf index 0c8e348df1..c13bc81b43 100644 --- a/addons/grenades/XEH_postInit.sqf +++ b/addons/grenades/XEH_postInit.sqf @@ -22,6 +22,7 @@ GVAR(flashbangPPEffectCC) ppEffectForceInNVG true; if !([ACE_player, objNull, ["isNotEscorting", "isNotInside"]] call EFUNC(common,canInteractWith)) exitWith {false}; // Conditions: specific if !(ACE_player call CBA_fnc_canUseWeapon) exitWith {false}; + // Don't change mode or show hint if advanced throwing is active if (ACE_player getVariable [QEGVAR(advanced_throwing,inHand), false]) exitWith {false}; diff --git a/addons/hellfire/functions/fnc_setupVehicle.sqf b/addons/hellfire/functions/fnc_setupVehicle.sqf index 49eefd8274..ce3961d77a 100644 --- a/addons/hellfire/functions/fnc_setupVehicle.sqf +++ b/addons/hellfire/functions/fnc_setupVehicle.sqf @@ -46,7 +46,7 @@ if ((getNumber (configOf _vehicle >> QGVAR(addLaserDesignator))) == 1) then { params ["_vehicle", "_turretPath"]; TRACE_3("checking for laser",_vehicle,_turretPath,_vehicle turretLocal _turretPath); if (!alive _vehicle) exitWith {}; - if (!(_vehicle turretLocal _turretPath)) then {WARNING("Turret not local");}; + if !(_vehicle turretLocal _turretPath) then {WARNING("Turret not local");}; private _hasLaser = false; { // Most addons just use "Laserdesignator_mounted", but this should cover custom ones diff --git a/addons/interact_menu/functions/fnc_keyDown.sqf b/addons/interact_menu/functions/fnc_keyDown.sqf index 5bce40d0a8..9cb638bcea 100644 --- a/addons/interact_menu/functions/fnc_keyDown.sqf +++ b/addons/interact_menu/functions/fnc_keyDown.sqf @@ -116,7 +116,7 @@ GVAR(selfMenuOffset) = (AGLtoASL (positionCameraToWorld [0, 0, 2])) vectorDiff ( //Auto expand the first level when self, mounted vehicle or zeus (skips the first animation as there is only one choice) if (GVAR(openedMenuType) == 0) then { if (isNull curatorCamera) then { - if (!(isNull (ACE_controlledUAV select 0))) then { + if !(isNull (ACE_controlledUAV select 0)) then { GVAR(menuDepthPath) = [["ACE_SelfActions", (ACE_controlledUAV select 0)]]; GVAR(expanded) = true; GVAR(expandedTime) = diag_tickTime; diff --git a/addons/interact_menu/functions/fnc_renderActionPoints.sqf b/addons/interact_menu/functions/fnc_renderActionPoints.sqf index 4ce37aa66b..62d29be91f 100644 --- a/addons/interact_menu/functions/fnc_renderActionPoints.sqf +++ b/addons/interact_menu/functions/fnc_renderActionPoints.sqf @@ -123,7 +123,7 @@ GVAR(collectedActionPoints) resize 0; // Render nearby actions, unit self actions or vehicle self actions as appropiate if (GVAR(openedMenuType) == 0) then { if (isNull curatorCamera) then { - if (!(isNull (ACE_controlledUAV select 0))) then { + if !(isNull (ACE_controlledUAV select 0)) then { // Render UAV self actions when in control of UAV AI (ACE_controlledUAV select 0) call _fnc_renderSelfActions; } else { diff --git a/addons/killtracker/XEH_postInit.sqf b/addons/killtracker/XEH_postInit.sqf index 35145698b3..35050d1dc3 100644 --- a/addons/killtracker/XEH_postInit.sqf +++ b/addons/killtracker/XEH_postInit.sqf @@ -19,6 +19,7 @@ if ((getText (missionconfigfile >> "CfgDebriefingSections" >> QUOTE(XADDON) >> "variable")) != QXGVAR(outputText)) exitWith { TRACE_1("no mission debriefing config",_this); }; + if !(GETEGVAR(medical,enabled,false)) exitWith { WARNING("No ACE-Medical"); XGVAR(outputText) = "No ACE-Medical"; @@ -64,7 +65,7 @@ GVAR(killCount) = 0; private _killInfo = []; if (!isNull _killer) then { - if (!(_killer isKindof "CAManBase")) then { // If killer is a vehicle log the vehicle type + if !(_killer isKindof "CAManBase") then { // If killer is a vehicle log the vehicle type _killInfo pushBack format [LLSTRING(Vehicle), getText ((configOf _killer) >> "displayName")]; }; if (isNull _instigator) then { @@ -77,7 +78,7 @@ GVAR(killCount) = 0; TRACE_2("",_unitIsPlayer,_instigatorIsPlayer); // Don't do anything if neither are players - if (!(_unitIsPlayer || _instigatorIsPlayer)) exitWith {}; + if !(_unitIsPlayer || _instigatorIsPlayer) exitWith {}; // Log firendly fire private _fnc_getSideFromConfig = { @@ -89,7 +90,7 @@ GVAR(killCount) = 0; default {civilian}; }; }; - if ((!isNull _instigator) && {_unit != _instigator} && {_instigator isKindOf "CAManBase"}) then { + if (!isNull _instigator && {_unit != _instigator} && {_instigator isKindOf "CAManBase"}) then { // Because of unconscious group switching/captives it's probably best to just use unit's config side private _unitSide = [_unit] call _fnc_getSideFromConfig; private _killerSide = [_instigator] call _fnc_getSideFromConfig; diff --git a/addons/laser/functions/fnc_seekerFindLaserSpot.sqf b/addons/laser/functions/fnc_seekerFindLaserSpot.sqf index aa3e43d35a..4ceb15d814 100644 --- a/addons/laser/functions/fnc_seekerFindLaserSpot.sqf +++ b/addons/laser/functions/fnc_seekerFindLaserSpot.sqf @@ -115,7 +115,7 @@ if (_spots isNotEqualTo []) then { while { count(_spots) != count(_excludes) && _c < (count _spots) } do { scopeName "mainSearch"; { - if (!(_forEachIndex in _excludes)) then { + if !(_forEachIndex in _excludes) then { private _index = _buckets pushBack [_x, [_x]]; _excludes pushBack _forEachIndex; _bucketPos = _x select 0; @@ -124,7 +124,7 @@ if (_spots isNotEqualTo []) then { }; } forEach _spots; { - if (!(_forEachIndex in _excludes)) then { + if !(_forEachIndex in _excludes) then { private _testPos = (_x select 0); if ((_testPos vectorDistanceSqr _bucketPos) <= 100) then { _bucketList pushBack _x; diff --git a/addons/logistics_uavbattery/functions/fnc_refuelUAV.sqf b/addons/logistics_uavbattery/functions/fnc_refuelUAV.sqf index 8c73052c45..a471e82cbf 100644 --- a/addons/logistics_uavbattery/functions/fnc_refuelUAV.sqf +++ b/addons/logistics_uavbattery/functions/fnc_refuelUAV.sqf @@ -17,7 +17,7 @@ */ params ["_caller", "_target"]; -if (!(_this call FUNC(canRefuelUAV))) exitWith {}; +if !(_this call FUNC(canRefuelUAV)) exitWith {}; private _onFinish = { (_this select 0) params ["_caller", "_target"]; diff --git a/addons/magazinerepack/functions/fnc_magazineRepackFinish.sqf b/addons/magazinerepack/functions/fnc_magazineRepackFinish.sqf index 9383089d28..c2785c5fad 100644 --- a/addons/magazinerepack/functions/fnc_magazineRepackFinish.sqf +++ b/addons/magazinerepack/functions/fnc_magazineRepackFinish.sqf @@ -25,7 +25,7 @@ _args params ["_magazineClassname", "_lastAmmoCount"]; private _fullMagazineCount = getNumber (configFile >> "CfgMagazines" >> _magazineClassname >> "count"); // Don't show anything if player can't interact -if (!([ACE_player, objNull, ["isNotInside", "isNotSitting", "isNotSwimming"]] call EFUNC(common,canInteractWith))) exitWith {}; +if !([ACE_player, objNull, ["isNotInside", "isNotSitting", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {}; // Count mags private _fullMags = 0; diff --git a/addons/map_gestures/functions/fnc_addGroupColorMapping.sqf b/addons/map_gestures/functions/fnc_addGroupColorMapping.sqf index d7d1bd3305..f533f9df34 100644 --- a/addons/map_gestures/functions/fnc_addGroupColorMapping.sqf +++ b/addons/map_gestures/functions/fnc_addGroupColorMapping.sqf @@ -25,7 +25,7 @@ TRACE_3("params",_group,_leadColor,_unitColor); if (_group isEqualType grpNull) then {_group = groupID _group}; if (_group == "") exitWith {ERROR("Group ID is blank, which is not valid.")}; -if (!([_leadColor] call FUNC(isValidColorArray))) exitWith {ERROR("leadColor is not a valid color array.")}; -if (!([_unitColor] call FUNC(isValidColorArray))) exitWith {ERROR("color is not a valid color array.")}; +if !([_leadColor] call FUNC(isValidColorArray)) exitWith {ERROR("leadColor is not a valid color array.")}; +if !([_unitColor] call FUNC(isValidColorArray)) exitWith {ERROR("color is not a valid color array.")}; GVAR(GroupColorCfgMappingNew) set [toLower _group, [_leadColor, _unitColor]]; diff --git a/addons/map_gestures/functions/fnc_isValidColorArray.sqf b/addons/map_gestures/functions/fnc_isValidColorArray.sqf index 7cc9335800..bcd5fea38c 100644 --- a/addons/map_gestures/functions/fnc_isValidColorArray.sqf +++ b/addons/map_gestures/functions/fnc_isValidColorArray.sqf @@ -20,7 +20,7 @@ scopeName "main"; params ["_colorArray"]; if (isNil "_colorArray") exitWith {false}; -if (!(_colorArray isEqualType [])) exitWith {false}; +if !(_colorArray isEqualType []) exitWith {false}; if (count _colorArray != 4) exitWith {false}; { diff --git a/addons/map_gestures/functions/fnc_moduleGroupSettings.sqf b/addons/map_gestures/functions/fnc_moduleGroupSettings.sqf index 07be21fc90..36bef695d5 100644 --- a/addons/map_gestures/functions/fnc_moduleGroupSettings.sqf +++ b/addons/map_gestures/functions/fnc_moduleGroupSettings.sqf @@ -24,9 +24,10 @@ if (!_activated) exitWith {}; // Transcode string setting into usable array. Example: "1,1,1,1" -> [1, 1, 1, 1] private _leadColor = call compile ("[" + (_logic getVariable ["leadColor", ""]) + "]"); -if (!([_leadColor] call FUNC(isValidColorArray))) exitWith {ERROR("leadColor is not a valid color array.")}; +if !([_leadColor] call FUNC(isValidColorArray)) exitWith {ERROR("leadColor is not a valid color array.")}; + private _color = call compile ("[" + (_logic getVariable ["color", ""]) + "]"); -if (!([_color] call FUNC(isValidColorArray))) exitWith {ERROR("color is not a valid color array.")}; +if !([_color] call FUNC(isValidColorArray)) exitWith {ERROR("color is not a valid color array.")}; // Add all synchronized groups and reference custom configuration for them { diff --git a/addons/map_gestures/functions/fnc_moduleSettings.sqf b/addons/map_gestures/functions/fnc_moduleSettings.sqf index b637997af7..22913dceef 100644 --- a/addons/map_gestures/functions/fnc_moduleSettings.sqf +++ b/addons/map_gestures/functions/fnc_moduleSettings.sqf @@ -29,14 +29,14 @@ if (!_activated) exitWith {}; private _defaultLeadColor = _logic getVariable ["defaultLeadColor", ""]; if (_defaultLeadColor != "") then { _defaultLeadColor = call compile ("[" + _defaultLeadColor + "]"); - if (!([_defaultLeadColor] call FUNC(isValidColorArray))) exitWith {ERROR("defaultLeadColor is not a valid color array.")}; + if !([_defaultLeadColor] call FUNC(isValidColorArray)) exitWith {ERROR("defaultLeadColor is not a valid color array.")}; ["CBA_settings_setSettingMission", [QGVAR(defaultLeadColor), _defaultLeadColor, true]] call CBA_fnc_localEvent; }; private _defaultColor = _logic getVariable ["defaultColor", ""]; if (_defaultColor != "") then { _defaultColor = call compile ("[" + _defaultColor + "]"); - if (!([_defaultColor] call FUNC(isValidColorArray))) exitWith {ERROR("defaultColor is not a valid color array.")}; + if !([_defaultColor] call FUNC(isValidColorArray)) exitWith {ERROR("defaultColor is not a valid color array.")}; ["CBA_settings_setSettingMission", [QGVAR(defaultColor), _defaultColor, true]] call CBA_fnc_localEvent; }; diff --git a/addons/markers/functions/fnc_removeTimestamp.sqf b/addons/markers/functions/fnc_removeTimestamp.sqf index 073d9ce613..5d2c7c3c1f 100644 --- a/addons/markers/functions/fnc_removeTimestamp.sqf +++ b/addons/markers/functions/fnc_removeTimestamp.sqf @@ -43,8 +43,8 @@ private _index = 1; private _keepCheckingDigits = true; private _validTimestamp = true; while {_keepCheckingDigits} do { - if (!(_string select [_index, 1] in DIGITS)) exitWith { _validTimestamp = false; }; - if (!(_string select [_index+1, 1] in DIGITS)) exitWith { _validTimestamp = false; }; + if !(_string select [_index, 1] in DIGITS) exitWith { _validTimestamp = false; }; + if !(_string select [_index+1, 1] in DIGITS) exitWith { _validTimestamp = false; }; switch (_string select [_index+2, 1]) do { case (":"): { _index = _index + 3; @@ -54,7 +54,7 @@ while {_keepCheckingDigits} do { }; case (" "): { _keepCheckingDigits = false; - if (!(_string select [_index+3, 3] in ["am]", "pm]"])) then {_validTimestamp = false; }; + if !(_string select [_index+3, 3] in ["am]", "pm]"]) then {_validTimestamp = false; }; }; default { _keepCheckingDigits = false; diff --git a/addons/medical/dev/watchVariable.sqf b/addons/medical/dev/watchVariable.sqf index 05cb094ba8..a0e064595a 100644 --- a/addons/medical/dev/watchVariable.sqf +++ b/addons/medical/dev/watchVariable.sqf @@ -10,10 +10,10 @@ GVAR(dev_watchVariableRunning) = true; if (!isNull _display) exitWith {"Paused"}; private _unit = cursorTarget; - if (!(_unit isKindOf "CAManBase")) then {_unit = cursorObject}; - if (!(_unit isKindOf "CAManBase")) then {_unit = ACE_player}; + if !(_unit isKindOf "CAManBase") then {_unit = cursorObject}; + if !(_unit isKindOf "CAManBase") then {_unit = ACE_player}; if ((_unit != ACE_player) && {IS_UNCONSCIOUS(ACE_player)}) then {_unit = ACE_player}; - if (!(_unit isKindOf "CAManBase")) exitWith {"No Unit?"}; + if !(_unit isKindOf "CAManBase") exitWith {"No Unit?"}; private _return = []; diff --git a/addons/medical_gui/XEH_postInit.sqf b/addons/medical_gui/XEH_postInit.sqf index 5ff49d2167..2b7fb8ce52 100644 --- a/addons/medical_gui/XEH_postInit.sqf +++ b/addons/medical_gui/XEH_postInit.sqf @@ -21,7 +21,7 @@ GVAR(selfInteractionActions) = []; [QEGVAR(interact_menu,newControllableObject), { params ["_type"]; // string of the object's classname - if (!(_type isKindOf "CAManBase")) exitWith {}; + if !(_type isKindOf "CAManBase") exitWith {}; { _x set [0, _type]; _x call EFUNC(interact_menu,addActionToClass); diff --git a/addons/medical_treatment/functions/fnc_checkPulseLocal.sqf b/addons/medical_treatment/functions/fnc_checkPulseLocal.sqf index 3798e64eb4..bb3efedc22 100644 --- a/addons/medical_treatment/functions/fnc_checkPulseLocal.sqf +++ b/addons/medical_treatment/functions/fnc_checkPulseLocal.sqf @@ -21,7 +21,7 @@ params ["_medic", "_patient", "_bodyPart"]; private _heartRate = 0; -if (!([_patient, _bodyPart] call FUNC(hasTourniquetAppliedTo))) then { +if !([_patient, _bodyPart] call FUNC(hasTourniquetAppliedTo)) then { _heartRate = switch (true) do { case (alive _patient): { GET_HEART_RATE(_patient) diff --git a/addons/medical_treatment/functions/fnc_fullHealLocal.sqf b/addons/medical_treatment/functions/fnc_fullHealLocal.sqf index dc95c44185..42c5866a9a 100644 --- a/addons/medical_treatment/functions/fnc_fullHealLocal.sqf +++ b/addons/medical_treatment/functions/fnc_fullHealLocal.sqf @@ -77,12 +77,12 @@ _patient setVariable [QEGVAR(medical,bodyPartDamage), [0,0,0,0,0,0], true]; // wakeup needs to be done after achieving stable vitals, but before manually reseting unconc var if IS_UNCONSCIOUS(_patient) then { - if (!([_patient] call EFUNC(medical_status,hasStableVitals))) then { ERROR_2("fullheal [unit %1][state %2] did not restore stable vitals",_patient,_state); }; + if !([_patient] call EFUNC(medical_status,hasStableVitals)) then {ERROR_2("fullheal [unit %1][state %2] did not restore stable vitals",_patient,_state);}; TRACE_1("Waking up",_patient); [QEGVAR(medical,WakeUp), _patient] call CBA_fnc_localEvent; _state = GET_SM_STATE(_patient); TRACE_1("after WakeUp",_state); - if IS_UNCONSCIOUS(_patient) then { ERROR_2("fullheal [unit %1][state %2] failed to wake up patient",_patient,_state); }; + if IS_UNCONSCIOUS(_patient) then {ERROR_2("fullheal [unit %1][state %2] failed to wake up patient",_patient,_state);}; }; // Generic medical admin diff --git a/addons/missileguidance/functions/fnc_cycleAttackProfileKeyDown.sqf b/addons/missileguidance/functions/fnc_cycleAttackProfileKeyDown.sqf index d25d2bc2b7..2263716724 100644 --- a/addons/missileguidance/functions/fnc_cycleAttackProfileKeyDown.sqf +++ b/addons/missileguidance/functions/fnc_cycleAttackProfileKeyDown.sqf @@ -18,7 +18,7 @@ TRACE_1("cycle fire mode",_this); if (!alive ACE_player) exitWith {}; -if (!([ACE_player, objNull, ["isNotInside"]] call EFUNC(common,canInteractWith))) exitWith {}; +if !([ACE_player, objNull, ["isNotInside"]] call EFUNC(common,canInteractWith)) exitWith {}; private _currentShooter = objNull; diff --git a/addons/missileguidance/functions/fnc_onFired.sqf b/addons/missileguidance/functions/fnc_onFired.sqf index 18eaf2a7c7..1d63d120a9 100644 --- a/addons/missileguidance/functions/fnc_onFired.sqf +++ b/addons/missileguidance/functions/fnc_onFired.sqf @@ -20,7 +20,7 @@ params ["_shooter","_weapon","","_mode","_ammo","","_projectile"]; // Bail on not missile -if (!(_ammo isKindOf "MissileBase")) exitWith {}; +if !(_ammo isKindOf "MissileBase") exitWith {}; // Bail if guidance is disabled for this ammo if ((getNumber (configFile >> "CfgAmmo" >> _ammo >> QUOTE(ADDON) >> "enabled")) != 1) exitWith {}; diff --git a/addons/mk6mortar/functions/fnc_handleFired.sqf b/addons/mk6mortar/functions/fnc_handleFired.sqf index f2979d0e4e..8ea2984b79 100644 --- a/addons/mk6mortar/functions/fnc_handleFired.sqf +++ b/addons/mk6mortar/functions/fnc_handleFired.sqf @@ -28,7 +28,7 @@ if (_vehicle distance ACE_player > 8000) exitWith {}; //AI will have no clue how to use: private _shooterMan = gunner _vehicle; -if (!([_shooterMan] call EFUNC(common,isPlayer))) exitWith {}; +if !([_shooterMan] call EFUNC(common,isPlayer)) exitWith {}; //Calculate air density: private _altitude = (getPosASL _vehicle) select 2; diff --git a/addons/mk6mortar/functions/fnc_handlePlayerVehicleChanged.sqf b/addons/mk6mortar/functions/fnc_handlePlayerVehicleChanged.sqf index 216bab43bc..d721b0e4ae 100644 --- a/addons/mk6mortar/functions/fnc_handlePlayerVehicleChanged.sqf +++ b/addons/mk6mortar/functions/fnc_handlePlayerVehicleChanged.sqf @@ -19,7 +19,7 @@ params ["_player", "_newVehicle"]; if (isNull _newVehicle) exitWith {}; -if (!(_newVehicle isKindOf "Mortar_01_base_F")) exitWith {}; +if !(_newVehicle isKindOf "Mortar_01_base_F") exitWith {}; private _tubeWeaponName = (weapons _newVehicle) select 0; private _fireModes = getArray (configFile >> "CfgWeapons" >> _tubeWeaponName >> "modes"); diff --git a/addons/nightvision/XEH_postInit.sqf b/addons/nightvision/XEH_postInit.sqf index 9bfee4d166..5a1aa19b82 100644 --- a/addons/nightvision/XEH_postInit.sqf +++ b/addons/nightvision/XEH_postInit.sqf @@ -61,7 +61,7 @@ if (!isNil QGVAR(serverPriorFog)) then {[] call FUNC(nonDedicatedFix);}; // If v if !([ACE_player, objNull, ["isNotEscorting", "isNotInside", "isNotSitting", "isNotRefueling"]] call EFUNC(common,canInteractWith)) exitWith {false}; // Conditions: specific if ((currentVisionMode ACE_player != 1)) exitWith {false}; - if (!(missionNamespace getVariable [QGVAR(allowBrightnessControl), true])) exitWith {false}; // just a mission setVar (not ace_setting) + if !(missionNamespace getVariable [QGVAR(allowBrightnessControl), true]) exitWith {false}; // just a mission setVar (not ace_setting) // Statement [ACE_player, 1] call FUNC(changeNVGBrightness); @@ -73,7 +73,7 @@ if (!isNil QGVAR(serverPriorFog)) then {[] call FUNC(nonDedicatedFix);}; // If v if !([ACE_player, objNull, ["isNotEscorting", "isNotInside", "isNotSitting", "isNotRefueling"]] call EFUNC(common,canInteractWith)) exitWith {false}; // Conditions: specific if ((currentVisionMode ACE_player != 1)) exitWith {false}; - if (!(missionNamespace getVariable [QGVAR(allowBrightnessControl), true])) exitWith {false}; // just a mission setVar (not ace_setting) + if !(missionNamespace getVariable [QGVAR(allowBrightnessControl), true]) exitWith {false}; // just a mission setVar (not ace_setting) // Statement [ACE_player, -1] call FUNC(changeNVGBrightness); diff --git a/addons/nlaw/functions/fnc_keyDown.sqf b/addons/nlaw/functions/fnc_keyDown.sqf index 60ac4bf3d8..5b75c72140 100644 --- a/addons/nlaw/functions/fnc_keyDown.sqf +++ b/addons/nlaw/functions/fnc_keyDown.sqf @@ -19,8 +19,8 @@ TRACE_1("lock key down",GVAR(isLockKeyDown)); if (!alive ACE_player) exitWith {}; -if (!([ACE_player, objNull, ["isNotInside"]] call EFUNC(common,canInteractWith))) exitWith {}; -if (!(ACE_player call CBA_fnc_canUseWeapon)) exitWith {}; +if !([ACE_player, objNull, ["isNotInside"]] call EFUNC(common,canInteractWith)) exitWith {}; +if !(ACE_player call CBA_fnc_canUseWeapon) exitWith {}; if ((getNumber (configFile >> "CfgWeapons" >> (currentWeapon ACE_player) >> QGVAR(enabled))) == 0) exitWith {}; if (GVAR(isLockKeyDown)) exitWith {ERROR("already running?");}; diff --git a/addons/rearm/XEH_preStart.sqf b/addons/rearm/XEH_preStart.sqf index b092699f9b..b013b04b86 100644 --- a/addons/rearm/XEH_preStart.sqf +++ b/addons/rearm/XEH_preStart.sqf @@ -4,6 +4,6 @@ // Test binarization one time at startup - ref https://github.com/acemod/ACE3/pull/8093 private _test = getText (configFile >> "Cfg3DEN" >> "Object" >> "AttributeCategories" >> "ace_attributes" >> "Attributes" >> "ace_rearm_rearmCargo" >> "defaultValue"); -if (!("else {" in _test)) then { +if !("else {" in _test) then { ERROR("3den attribute has ERROR [check binarization]"); }; diff --git a/addons/repair/dev/draw_showRepairInfo.sqf b/addons/repair/dev/draw_showRepairInfo.sqf index 122f209739..182b2f7a08 100644 --- a/addons/repair/dev/draw_showRepairInfo.sqf +++ b/addons/repair/dev/draw_showRepairInfo.sqf @@ -29,7 +29,7 @@ addMissionEventHandler ["Draw3D", { _info = _info + "[Wheel]"; _color = [0,1,0,1]; }; - if (!((getText (_config>> "HitPoints" >> _hitpoint >> "depends")) in ["", "0"])) then { + if !((getText (_config>> "HitPoints" >> _hitpoint >> "depends")) in ["", "0"]) then { _info = _info + format ["[depends: %1]", getText (_config>> "HitPoints" >> _hitpoint >> "depends")]; _color = [0,0,1,1] }; diff --git a/addons/repair/functions/fnc_canRepair.sqf b/addons/repair/functions/fnc_canRepair.sqf index f1f4aa7b7c..ff61450b12 100644 --- a/addons/repair/functions/fnc_canRepair.sqf +++ b/addons/repair/functions/fnc_canRepair.sqf @@ -65,7 +65,7 @@ if (!_return) exitWith {false}; // if (_vehicleStateCondition == 1 && {!([_target] call FUNC(isInStableCondition))}) exitWith {false}; private _repairLocations = getArray (_config >> "repairLocations"); -if (!("All" in _repairLocations)) then { +if !("All" in _repairLocations) then { private _repairFacility = {([_caller] call FUNC(isInRepairFacility)) || ([_target] call FUNC(isInRepairFacility))}; private _repairVeh = {([_caller] call FUNC(isNearRepairVehicle)) || ([_target] call FUNC(isNearRepairVehicle))}; { diff --git a/addons/repair/functions/fnc_getSelectionsToIgnore.sqf b/addons/repair/functions/fnc_getSelectionsToIgnore.sqf index 58f916185c..455b58c040 100644 --- a/addons/repair/functions/fnc_getSelectionsToIgnore.sqf +++ b/addons/repair/functions/fnc_getSelectionsToIgnore.sqf @@ -117,7 +117,7 @@ private _processedSelections = []; continue }; - if (!(getText (_vehCfg >> "HitPoints" >> _hitpoint >> "depends") in ["", "0"])) then { // skip depends hitpoints, should be normalized by engine + 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]; diff --git a/addons/repair/functions/fnc_normalizeHitPoints.sqf b/addons/repair/functions/fnc_normalizeHitPoints.sqf index 5e61ef8c88..97f34c22db 100644 --- a/addons/repair/functions/fnc_normalizeHitPoints.sqf +++ b/addons/repair/functions/fnc_normalizeHitPoints.sqf @@ -33,7 +33,7 @@ private _dependentHitPointScripts = []; { if ((_x != "") && {isClass (_config >> _x)} && {!(_x in _realHitPoints)}) then { _realHitPoints pushBack _x; - if (!((getText (_config >> _x >> "depends")) in ["", "0"])) then { + if !((getText (_config >> _x >> "depends")) in ["", "0"]) then { _dependentHitPoints pushBack _x; _dependentHitPointScripts pushBack compile getText (_config >> _x >> "depends"); }; diff --git a/addons/repair/functions/fnc_repair.sqf b/addons/repair/functions/fnc_repair.sqf index 86ff191000..526b2d506b 100644 --- a/addons/repair/functions/fnc_repair.sqf +++ b/addons/repair/functions/fnc_repair.sqf @@ -70,7 +70,7 @@ if (!_return) exitWith {false}; // if (_vehicleStateCondition == 1 && {!([_target] call FUNC(isInStableCondition))}) exitWith {false}; private _repairLocations = getArray (_config >> "repairLocations"); -if (!("All" in _repairLocations)) then { +if !("All" in _repairLocations) then { private _repairFacility = {([_caller] call FUNC(isInRepairFacility)) || ([_target] call FUNC(isInRepairFacility))}; private _repairVeh = {([_caller] call FUNC(isNearRepairVehicle)) || ([_target] call FUNC(isNearRepairVehicle))}; { diff --git a/addons/repair/functions/fnc_repair_failure.sqf b/addons/repair/functions/fnc_repair_failure.sqf index c305c90b6b..f9de2a8ae6 100644 --- a/addons/repair/functions/fnc_repair_failure.sqf +++ b/addons/repair/functions/fnc_repair_failure.sqf @@ -65,7 +65,7 @@ if (isNil _callback) then { } else { _callback = missionNamespace getVariable _callback; }; -if (!(_callback isEqualType {})) then {_callback = {TRACE_1("callback was NOT code",_callback)};}; +if !(_callback isEqualType {}) then {_callback = {TRACE_1("callback was NOT code",_callback)};}; _args call _callback; diff --git a/addons/repair/functions/fnc_repair_success.sqf b/addons/repair/functions/fnc_repair_success.sqf index 271d662cd4..6248082779 100644 --- a/addons/repair/functions/fnc_repair_success.sqf +++ b/addons/repair/functions/fnc_repair_success.sqf @@ -60,7 +60,7 @@ if (isNil _callback) then { } else { _callback = missionNamespace getVariable _callback; }; -if (!(_callback isEqualType {})) then {_callback = {TRACE_1("callback was NOT code",_callback)};}; +if !(_callback isEqualType {}) then {_callback = {TRACE_1("callback was NOT code",_callback)};}; _args call _callback; diff --git a/addons/scopes/functions/fnc_adjustScope.sqf b/addons/scopes/functions/fnc_adjustScope.sqf index 0a9d7bd089..a760065cde 100644 --- a/addons/scopes/functions/fnc_adjustScope.sqf +++ b/addons/scopes/functions/fnc_adjustScope.sqf @@ -22,7 +22,7 @@ if (!GVAR(enabled)) exitWith {false}; params ["_unit", "_turretAndDirection", "_majorStep"]; TRACE_3("adjustScope",_unit,_turretAndDirection,_majorStep); -if (!(_unit isKindOf "Man")) exitWith {false}; +if !(_unit isKindOf "Man") exitWith {false}; if (currentMuzzle _unit != currentWeapon _unit) exitWith {false}; private _weaponIndex = [_unit, currentWeapon _unit] call EFUNC(common,getWeaponIndex); diff --git a/addons/scopes/functions/fnc_canAdjustZero.sqf b/addons/scopes/functions/fnc_canAdjustZero.sqf index ca03ab4123..1461d91d20 100644 --- a/addons/scopes/functions/fnc_canAdjustZero.sqf +++ b/addons/scopes/functions/fnc_canAdjustZero.sqf @@ -20,7 +20,7 @@ params ["_unit"]; if (cameraView == "GUNNER") exitWith {false}; if (!isNull objectParent _unit) exitWith {false}; if (GVAR(simplifiedZeroing)) exitWith {false}; -if (!(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false])) exitWith {false}; +if !(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) exitWith {false}; private _weaponIndex = [_unit, currentWeapon _unit] call EFUNC(common,getWeaponIndex); if (_weaponIndex < 0) exitWith {false}; diff --git a/addons/scopes/functions/fnc_canResetZero.sqf b/addons/scopes/functions/fnc_canResetZero.sqf index 79dae44be9..92bbda1a4d 100644 --- a/addons/scopes/functions/fnc_canResetZero.sqf +++ b/addons/scopes/functions/fnc_canResetZero.sqf @@ -19,7 +19,7 @@ params ["_unit"]; if (cameraView == "GUNNER") exitWith {false}; if (!isNull objectParent _unit) exitWith {false}; -if (!(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false])) exitWith {false}; +if !(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) exitWith {false}; private _weaponIndex = [_unit, currentWeapon _unit] call EFUNC(common,getWeaponIndex); if (_weaponIndex < 0) exitWith {false}; diff --git a/addons/scopes/functions/fnc_firedEH.sqf b/addons/scopes/functions/fnc_firedEH.sqf index f1b8e91bf4..5ff78a44b7 100644 --- a/addons/scopes/functions/fnc_firedEH.sqf +++ b/addons/scopes/functions/fnc_firedEH.sqf @@ -18,7 +18,7 @@ //IGNORE_PRIVATE_WARNING ["_unit", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile", "_vehicle", "_gunner", "_turret"]; TRACE_10("firedEH:",_unit,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile,_vehicle,_gunner,_turret); -if (!(_ammo isKindOf "BulletBase")) exitWith {}; +if !(_ammo isKindOf "BulletBase") exitWith {}; private _weaponIndex = [_unit, currentWeapon _unit] call EFUNC(common,getWeaponIndex); if (_weaponIndex < 0) exitWith {}; diff --git a/addons/scopes/functions/fnc_getCurrentZeroRange.sqf b/addons/scopes/functions/fnc_getCurrentZeroRange.sqf index 001e5e8b79..d1bc3b7790 100644 --- a/addons/scopes/functions/fnc_getCurrentZeroRange.sqf +++ b/addons/scopes/functions/fnc_getCurrentZeroRange.sqf @@ -17,12 +17,12 @@ params ["_unit"]; -if (!GVAR(enabled)) exitWith { currentZeroing _unit }; +if (!GVAR(enabled)) exitWith {currentZeroing _unit}; private _weaponIndex = [_unit, currentWeapon _unit] call EFUNC(common,getWeaponIndex); if (_weaponIndex < 0) exitWith { currentZeroing _unit }; if (GVAR(simplifiedZeroing)) exitWith { - if (!(GVAR(canAdjustElevation) select _weaponIndex)) exitWith { currentZeroing _unit }; + if !(GVAR(canAdjustElevation) select _weaponIndex) exitWith {currentZeroing _unit}; private _adjustment = _unit getVariable [QGVAR(Adjustment), [[0, 0, 0], [0, 0, 0], [0, 0, 0]]]; ((_adjustment select _weaponIndex) select 0) }; diff --git a/addons/scopes/functions/fnc_getOptics.sqf b/addons/scopes/functions/fnc_getOptics.sqf index 6be1952b6f..d419d8d7f0 100644 --- a/addons/scopes/functions/fnc_getOptics.sqf +++ b/addons/scopes/functions/fnc_getOptics.sqf @@ -21,7 +21,7 @@ params ["_unit"]; private _optics = ["", "", ""]; -if (!(_unit isKindOf "CAManBase")) exitWith {_optics}; +if !(_unit isKindOf "CAManBase") exitWith {_optics}; { if (count _x >= 2) then { diff --git a/addons/scopes/initKeybinds.inc.sqf b/addons/scopes/initKeybinds.inc.sqf index a147b1b215..0e8db97238 100644 --- a/addons/scopes/initKeybinds.inc.sqf +++ b/addons/scopes/initKeybinds.inc.sqf @@ -2,7 +2,7 @@ // Conditions: canInteract if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; // Conditions: specific - if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; + if !([ACE_player] call CBA_fnc_canUseWeapon) exitWith {false}; [ACE_player] call FUNC(inventoryCheck); @@ -14,7 +14,7 @@ // Conditions: canInteract if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; // Conditions: specific - if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; + if !([ACE_player] call CBA_fnc_canUseWeapon) exitWith {false}; [ACE_player] call FUNC(inventoryCheck); @@ -26,7 +26,7 @@ // Conditions: canInteract if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; // Conditions: specific - if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; + if !([ACE_player] call CBA_fnc_canUseWeapon) exitWith {false}; [ACE_player] call FUNC(inventoryCheck); @@ -38,7 +38,7 @@ // Conditions: canInteract if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; // Conditions: specific - if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; + if !([ACE_player] call CBA_fnc_canUseWeapon) exitWith {false}; [ACE_player] call FUNC(inventoryCheck); @@ -50,7 +50,7 @@ // Conditions: canInteract if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; // Conditions: specific - if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; + if !([ACE_player] call CBA_fnc_canUseWeapon) exitWith {false}; [ACE_player] call FUNC(inventoryCheck); @@ -62,7 +62,7 @@ // Conditions: canInteract if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; // Conditions: specific - if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; + if !([ACE_player] call CBA_fnc_canUseWeapon) exitWith {false}; [ACE_player] call FUNC(inventoryCheck); @@ -74,7 +74,7 @@ // Conditions: canInteract if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; // Conditions: specific - if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; + if !([ACE_player] call CBA_fnc_canUseWeapon) exitWith {false}; [ACE_player] call FUNC(inventoryCheck); @@ -86,7 +86,7 @@ // Conditions: canInteract if !([ACE_player, objNull, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; // Conditions: specific - if (!([ACE_player] call CBA_fnc_canUseWeapon)) exitWith {false}; + if !([ACE_player] call CBA_fnc_canUseWeapon) exitWith {false}; [ACE_player] call FUNC(inventoryCheck); diff --git a/addons/sitting/functions/fnc_sit.sqf b/addons/sitting/functions/fnc_sit.sqf index 2d7cc999da..70e028719b 100644 --- a/addons/sitting/functions/fnc_sit.sqf +++ b/addons/sitting/functions/fnc_sit.sqf @@ -78,7 +78,7 @@ if (_seatsClaimed isEqualTo []) then { _seat setVariable [QGVAR(seatsClaimed), _seatsClaimed, true]; // Also prevent dragging/carrying -if (!([_seat] call EFUNC(common,owned))) then { +if !([_seat] call EFUNC(common,owned)) then { [_player, _seat] call EFUNC(common,claim); }; diff --git a/addons/switchunits/functions/fnc_switchUnit.sqf b/addons/switchunits/functions/fnc_switchUnit.sqf index 135088d243..9ce074eecb 100644 --- a/addons/switchunits/functions/fnc_switchUnit.sqf +++ b/addons/switchunits/functions/fnc_switchUnit.sqf @@ -18,7 +18,7 @@ params ["_unit"]; // don't switch to original player units -if (!([_unit] call FUNC(isValidAi))) exitWith {}; +if !([_unit] call FUNC(isValidAi)) exitWith {}; // exit var private _leave = false; diff --git a/addons/tagging/functions/fnc_generateStencilTexture.sqf b/addons/tagging/functions/fnc_generateStencilTexture.sqf index 1870d67114..6d8dffdc55 100644 --- a/addons/tagging/functions/fnc_generateStencilTexture.sqf +++ b/addons/tagging/functions/fnc_generateStencilTexture.sqf @@ -29,10 +29,10 @@ params [ ["_dimension", 512, [0]] ]; -if (_textColor select [0, 1] == "#") then { _textColor = _textColor select [1]; }; -if (_backgroundColor select [0, 1] == "#") then { _backgroundColor = _backgroundColor select [1]; }; -if (!((count _textColor) in [6,8])) exitWith { ERROR_1("bad Tcolor %1",_textColor); "" }; -if (!((count _backgroundColor) in [6,8])) exitWith { ERROR_1("bad Bcolor %1",_textColor); "" }; +if (_textColor select [0, 1] == "#") then {_textColor = _textColor select [1];}; +if (_backgroundColor select [0, 1] == "#") then {_backgroundColor = _backgroundColor select [1];}; +if !((count _textColor) in [6,8]) exitWith {ERROR_1("bad Tcolor %1",_textColor); ""}; +if !((count _backgroundColor) in [6,8]) exitWith {ERROR_1("bad Bcolor %1",_textColor); ""}; if (_autoMultiline) then { private _magicWidth = 0.75; diff --git a/addons/tagging/functions/fnc_stencilVehicle.sqf b/addons/tagging/functions/fnc_stencilVehicle.sqf index b2ee99c241..1dfd86a2f9 100644 --- a/addons/tagging/functions/fnc_stencilVehicle.sqf +++ b/addons/tagging/functions/fnc_stencilVehicle.sqf @@ -29,7 +29,7 @@ TRACE_2("",_vehicle,_text); if (!isServer) exitWith {}; if (_text == "") exitWith {}; private _clanSel = getText (configOf _vehicle >> "selectionClan"); -if (!(_clanSel in selectionNames _vehicle)) exitWith { TRACE_1("no tag",_clanSel); }; +if !(_clanSel in selectionNames _vehicle) exitWith {TRACE_1("no tag",_clanSel);}; private _texture = [_text, _textSize, _textColor, "00000000", true] call FUNC(generateStencilTexture); TRACE_1("",_texture); diff --git a/addons/vector/functions/fnc_onKeyHold.sqf b/addons/vector/functions/fnc_onKeyHold.sqf index 60a38ba96d..f19039851b 100644 --- a/addons/vector/functions/fnc_onKeyHold.sqf +++ b/addons/vector/functions/fnc_onKeyHold.sqf @@ -16,7 +16,7 @@ * Public: No */ -if (!((currentWeapon ACE_player) isKindOf ["ACE_Vector", configFile >> "CfgWeapons"])) exitWith { +if !((currentWeapon ACE_player) isKindOf ["ACE_Vector", configFile >> "CfgWeapons"]) exitWith { [_this select 1] call CBA_fnc_removePerFrameHandler; GVAR(currentMode) = ""; diff --git a/addons/vehicle_damage/XEH_postInit.sqf b/addons/vehicle_damage/XEH_postInit.sqf index d14770dea0..43050086d8 100644 --- a/addons/vehicle_damage/XEH_postInit.sqf +++ b/addons/vehicle_damage/XEH_postInit.sqf @@ -10,7 +10,7 @@ TRACE_3("bailOut",_center,_crewman,_vehicle); if (isPlayer _crewman) exitWith {}; - if (!alive _crewman || { !( [_crewman] call EFUNC(common,isAwake))} ) exitWith {}; + if (!alive _crewman || {!([_crewman] call EFUNC(common,isAwake))}) exitWith {}; unassignVehicle _crewman; _crewman leaveVehicle _vehicle; diff --git a/addons/vehiclelock/functions/fnc_addKeyForVehicle.sqf b/addons/vehiclelock/functions/fnc_addKeyForVehicle.sqf index 6461e7fca2..4d0f065c06 100644 --- a/addons/vehiclelock/functions/fnc_addKeyForVehicle.sqf +++ b/addons/vehiclelock/functions/fnc_addKeyForVehicle.sqf @@ -23,8 +23,12 @@ if (!params [["_unit", objNull, [objNull]], ["_veh", objNull, [objNull]], ["_use }; TRACE_3("params",_unit,_veh,_useCustom); -if (isNull _unit) exitWith {ERROR("null unit");}; -if (isNull _veh) exitWith {ERROR("null vehicle");}; +if (isNull _unit) exitWith { + ERROR("null unit"); +}; +if (isNull _veh) exitWith { + ERROR("null vehicle"); +}; if (_useCustom) then { private _previousMags = magazinesDetail _unit; diff --git a/addons/vehiclelock/functions/fnc_lockpick.sqf b/addons/vehiclelock/functions/fnc_lockpick.sqf index 4ef3289b45..7bb29395f0 100644 --- a/addons/vehiclelock/functions/fnc_lockpick.sqf +++ b/addons/vehiclelock/functions/fnc_lockpick.sqf @@ -33,7 +33,10 @@ if ((locked _veh) == 0) exitWith {false}; if !("ACE_key_lockpick" in (_unit call EFUNC(common,uniqueItems))) exitWith {false}; private _vehLockpickStrength = _veh getVariable[QGVAR(lockpickStrength), GVAR(DefaultLockpickStrength)]; -if (!(_vehLockpickStrength isEqualType 0)) exitWith {ERROR("ACE_vehicleLock_LockpickStrength invalid"); false}; +if !(_vehLockpickStrength isEqualType 0) exitWith { + ERROR("ACE_vehicleLock_LockpickStrength invalid"); + false +}; //-1 indicates unpickable lock if (_vehLockpickStrength < 0) exitWith {false}; @@ -45,7 +48,7 @@ private _condition = { ((_unit distance _veh) < 5) && {(speed _veh) < 0.1} }; -if (!([[_unit, _veh]] call _condition)) exitWith {false}; +if !([[_unit, _veh]] call _condition) exitWith {false}; private _returnValue = _funcType in ["canLockpick", "startLockpick", "finishLockpick"]; switch (_funcType) do { diff --git a/addons/vehiclelock/functions/fnc_moduleSync.sqf b/addons/vehiclelock/functions/fnc_moduleSync.sqf index c29c7a06d2..a269fbd6e5 100644 --- a/addons/vehiclelock/functions/fnc_moduleSync.sqf +++ b/addons/vehiclelock/functions/fnc_moduleSync.sqf @@ -22,7 +22,7 @@ if (!isServer) exitWith {}; params ["_logic", "_syncedObjects", "_activated"]; TRACE_3("params",_logic,_syncedObjects,_activated); -if !(_activated) exitWith {WARNING("Vehicle Lock Sync Module - placed but not active");}; +if (!_activated) exitWith {WARNING("Vehicle Lock Sync Module - placed but not active");}; [{ params ["_syncedObjects"]; diff --git a/addons/viewports/functions/fnc_eachFrame.sqf b/addons/viewports/functions/fnc_eachFrame.sqf index 068a5edcf5..21f2f09dc8 100644 --- a/addons/viewports/functions/fnc_eachFrame.sqf +++ b/addons/viewports/functions/fnc_eachFrame.sqf @@ -27,7 +27,7 @@ private _newIndex = -1; if (cba_events_control) then { if (cameraView != "INTERNAL") exitWith {}; if (isTurnedOut _player) exitWith {}; - if (!([_player, _vehicle, []] call EFUNC(common,canInteractWith))) exitWith {}; + if !([_player, _vehicle, []] call EFUNC(common,canInteractWith)) exitWith {}; BEGIN_COUNTER(newIndex); if ((_shownIndex > -1) && {currentVisionMode _player != _lastVisionMode}) then { diff --git a/addons/viewports/functions/fnc_getSeatInfo.sqf b/addons/viewports/functions/fnc_getSeatInfo.sqf index 86dccebdd1..01c71c3cfe 100644 --- a/addons/viewports/functions/fnc_getSeatInfo.sqf +++ b/addons/viewports/functions/fnc_getSeatInfo.sqf @@ -41,6 +41,6 @@ private _compartment = switch (_role) do { }; }; -if (!(_compartment isEqualType "")) then { _compartment = format ["Compartment%1",_compartment] }; +if !(_compartment isEqualType "") then {_compartment = format ["Compartment%1",_compartment]}; [_role, _cargoIndex, _turretPath, _compartment] diff --git a/addons/viewrestriction/functions/fnc_changeCamera.sqf b/addons/viewrestriction/functions/fnc_changeCamera.sqf index 6a1f7d03ff..eb6907386a 100644 --- a/addons/viewrestriction/functions/fnc_changeCamera.sqf +++ b/addons/viewrestriction/functions/fnc_changeCamera.sqf @@ -18,7 +18,7 @@ params ["_newCameraView", "_cameraOn"]; -if (! ([_newCameraView, _cameraOn] call FUNC(canChangeCamera))) exitWith {}; +if !([_newCameraView, _cameraOn] call FUNC(canChangeCamera)) exitWith {}; TRACE_1("View Restricted",XGVAR(mode)); diff --git a/addons/weaponselect/XEH_postInit.sqf b/addons/weaponselect/XEH_postInit.sqf index 77a2fc673b..e9f05de8bb 100644 --- a/addons/weaponselect/XEH_postInit.sqf +++ b/addons/weaponselect/XEH_postInit.sqf @@ -198,7 +198,7 @@ if (!hasInterface) exitWith {}; ["ACE3 Vehicles", QGVAR(CollisionLights), localize LSTRING(CollisionLights), { // Conditions: canInteract - if (!([ACE_player, vehicle ACE_player, []] call EFUNC(common,canInteractWith))) exitWith {false}; + if !([ACE_player, vehicle ACE_player, []] call EFUNC(common,canInteractWith)) exitWith {false}; // Conditions: specific if ((ACE_player isEqualTo (vehicle ACE_player)) || {ACE_player != (driver (vehicle ACE_player))}) exitWith {false}; diff --git a/addons/weather/functions/fnc_calculateWindSpeed.sqf b/addons/weather/functions/fnc_calculateWindSpeed.sqf index cd73fac358..d24322bef0 100644 --- a/addons/weather/functions/fnc_calculateWindSpeed.sqf +++ b/addons/weather/functions/fnc_calculateWindSpeed.sqf @@ -47,15 +47,15 @@ if (_terrainEffectEnabled) then { private _newWindSpeed = 0; { private _windSource = [100, _windDirAdjusted, _x] call _fnc_polar2vect; - if (!(terrainIntersectASL [_position, _position vectorAdd _windSource])) exitWith { + if !(terrainIntersectASL [_position, _position vectorAdd _windSource]) exitWith { _newWindSpeed = cos(_x * 9) * _windSpeed; }; _windSource = [100, _windDirAdjusted + _x, 0] call _fnc_polar2vect; - if (!(terrainIntersectASL [_position, _position vectorAdd _windSource])) exitWith { + if !(terrainIntersectASL [_position, _position vectorAdd _windSource]) exitWith { _newWindSpeed = cos(_x * 9) * _windSpeed; }; _windSource = [100, _windDirAdjusted - _x, 0] call _fnc_polar2vect; - if (!(terrainIntersectASL [_position, _position vectorAdd _windSource])) exitWith { + if !(terrainIntersectASL [_position, _position vectorAdd _windSource]) exitWith { _newWindSpeed = cos(_x * 9) * _windSpeed; }; } forEach [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; @@ -69,15 +69,15 @@ if (_obstacleEffectEnabled) then { private _newWindSpeed = 0; { private _windSource = [20, _windDirAdjusted, _x] call _fnc_polar2vect; - if (!(lineIntersects [_position, _position vectorAdd _windSource])) exitWith { + if !(lineIntersects [_position, _position vectorAdd _windSource]) exitWith { _newWindSpeed = cos(_x * 2) * _windSpeed; }; _windSource = [20, _windDirAdjusted + _x, 0] call _fnc_polar2vect; - if (!(lineIntersects [_position, _position vectorAdd _windSource])) exitWith { + if !(lineIntersects [_position, _position vectorAdd _windSource]) exitWith { _newWindSpeed = cos(_x * 2) * _windSpeed; }; _windSource = [20, _windDirAdjusted - _x, 0] call _fnc_polar2vect; - if (!(lineIntersects [_position, _position vectorAdd _windSource])) exitWith { + if !(lineIntersects [_position, _position vectorAdd _windSource]) exitWith { _newWindSpeed = cos(_x * 2) * _windSpeed; }; } forEach [0, 5, 10, 15, 20, 25, 30, 35, 40, 45]; diff --git a/addons/xm157/functions/fnc_keyPress.sqf b/addons/xm157/functions/fnc_keyPress.sqf index c5e4760563..3a9dd53a26 100644 --- a/addons/xm157/functions/fnc_keyPress.sqf +++ b/addons/xm157/functions/fnc_keyPress.sqf @@ -19,8 +19,8 @@ params ["_func", "_keyDown"]; if (!GVAR(shown)) exitWith { false }; // fast exit if not shown -if (!([ACE_player, objNull, ["isNotInside"]] call EFUNC(common,canInteractWith))) exitWith { false }; -if (!(ACE_player call CBA_fnc_canUseWeapon)) exitWith { false }; +if !([ACE_player, objNull, ["isNotInside"]] call EFUNC(common,canInteractWith)) exitWith { false }; +if !(ACE_player call CBA_fnc_canUseWeapon) exitWith { false }; if (currentMuzzle ACE_player != currentWeapon ACE_player) exitWith { false }; private _display = uinamespace getVariable [QGVAR(display), displayNull]; diff --git a/addons/zeus/functions/fnc_addObjectToCurator.sqf b/addons/zeus/functions/fnc_addObjectToCurator.sqf index 9651630ccc..4b87904d0f 100644 --- a/addons/zeus/functions/fnc_addObjectToCurator.sqf +++ b/addons/zeus/functions/fnc_addObjectToCurator.sqf @@ -17,7 +17,7 @@ params ["_object"]; -if (!(_object getVariable [QGVAR(addObject), GVAR(autoAddObjects)])) exitWith {}; +if !(_object getVariable [QGVAR(addObject), GVAR(autoAddObjects)]) exitWith {}; [{ TRACE_1("Delayed addCuratorEditableObjects",_this); diff --git a/addons/zeus/functions/fnc_bi_moduleCurator.sqf b/addons/zeus/functions/fnc_bi_moduleCurator.sqf index ec04a12d24..cdc4d35b64 100644 --- a/addons/zeus/functions/fnc_bi_moduleCurator.sqf +++ b/addons/zeus/functions/fnc_bi_moduleCurator.sqf @@ -23,13 +23,13 @@ params ["_logic", "_units", "_activated"]; if (_activated) then { - //--- Terminate when not created on the server - if (!isserver && local _logic && isnull (getassignedcuratorunit _logic)) exitwith { + // Terminate when not created on the server + if (!isServer && local _logic && isnull (getassignedcuratorunit _logic)) exitwith { [format ["%1 is trying to create curator logic ModuleCurator_F",profilename],"bis_fnc_error",false] call bis_fnc_mp; deletevehicle _logic; }; - //--- Get curator owner + // Get curator owner _ownerVar = _logic getvariable ["owner",""]; _ownerUID = parsenumber _ownerVar; if (cheatsenabled) then { @@ -46,13 +46,13 @@ if (_activated) then { }; _isAdmin = _ownerVar == "#adminLogged" || _ownerVar == "#adminVoted"; - //--- Wipe out the variable so clients can't access it + // Wipe out the variable so clients can't access it _logic setvariable ["owner",nil]; - //--- Server + // Server if (isserver) then { - //--- Prepare admin variable + // Prepare admin variable _adminVar = ""; if (_isAdmin) then { _letters = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]; @@ -61,12 +61,12 @@ if (_activated) then { _logic setvariable ["adminVar",_adminVar,true]; }; - //--- Get allowed addons + // Get allowed addons _addonsType = _logic getvariable ["Addons",2]; _addons = []; switch _addonsType do { - //--- All (including unofficial ones) + // All (including unofficial ones) case 3: { _cfgPatches = configfile >> "cfgpatches"; for "_i" from 0 to (count _cfgPatches - 1) do { @@ -79,10 +79,10 @@ if (_activated) then { _logic addcuratoraddons _addons; }; - //--- All active + // All active case 2: {}; - //--- All mission + // All mission case 1: { _addonsList = []; { @@ -92,13 +92,13 @@ if (_activated) then { _logic addcuratoraddons _addonsList; }; - //--- None + // None case 0: { removeallcuratoraddons _logic; }; }; - //--- Handle ownership + // Handle ownership [_logic,_ownerVar,_ownerUID,_adminVar] spawn { scriptname "BIS_fnc_moduleCurator: Owner"; @@ -110,16 +110,16 @@ if (_activated) then { _name = _logic getvariable ["name",""]; if (_name == "") then {_name = localize "STR_A3_curator";}; - //--- Wait until mission starts + // Wait until mission starts waitUntil {time > 0}; // NOTE: DO NOT CHANGE TO CBA_missionTime, IT BREAKS THE MODULE - //--- Refresh addon list, so it's broadcasted to clients + // Refresh addon list, so it's broadcasted to clients _addons = curatoraddons _logic; removeAllCuratorAddons _logic; _logic addcuratoraddons _addons; while {true} do { - //--- Wait for player to become Zeus + // Wait for player to become Zeus switch true do { case (_ownerUID > 0): { waituntil { @@ -133,7 +133,7 @@ if (_activated) then { }; if (isnull _logic) exitwith {}; - //--- Assign + // Assign _player = objnull; switch true do { case (_ownerUID > 0): { @@ -150,7 +150,7 @@ if (_activated) then { waituntil {_player assignCurator _logic; getassignedcuratorunit _logic == _player || isnull _logic}; if (isnull _logic) exitwith {}; - //--- Add radio channels + // Add radio channels { _x radiochanneladd [_player]; } foreach (_logic getvariable ["channels",[]]); @@ -159,7 +159,7 @@ if (_activated) then { private _msgCode = { params ["_logic","_player"]; - //--- Sent notification to all assigned players + // Sent notification to all assigned players if ((_logic getVariable ["showNotification",true]) && GVAR(zeusAscension)) then { { if (isplayer _x) then { @@ -181,7 +181,7 @@ if (_activated) then { // Added by ace_zeus [QGVAR(zeusUnitAssigned), [_logic,_player]] call CBA_fnc_globalEvent; - //--- Wait for player to stop being Zeus + // Wait for player to stop being Zeus switch true do { case (_ownerUID > 0): { waituntil { @@ -195,12 +195,12 @@ if (_activated) then { }; if (isnull _logic) exitwith {}; - //--- Add radio channels + // Add radio channels { _x radiochannelremove [_player]; } foreach (_logic getvariable ["channels",[]]); - //--- Unassign + // Unassign waituntil {unassigncurator _logic; isnull (getassignedcuratorunit _logic) || isnull _logic}; if (isnull _logic) exitwith {}; }; @@ -211,14 +211,14 @@ if (_activated) then { params ["_logic"]; if (GVAR(zeusBird)) then { - //--- Create bird + // Create bird _birdType = _logic getVariable ["birdType","eagle_f"]; if (_birdType != "") then { _bird = createvehicle [_birdType,[100,100,100],[],0,"none"]; _logic setVariable ["bird",_bird,true]; }; - //--- Locality changed + // Locality changed _logic addeventhandler [ "local", { @@ -237,7 +237,7 @@ if (_activated) then { [_logic] call _birdCode; }; - //--- Activated all future addons + // Activated all future addons _addons = []; { if (typeof _x == "ModuleCuratorAddAddons_F") then { @@ -254,12 +254,12 @@ if (_activated) then { if (time <= 0) then { _addons call bis_fnc_activateaddons; }; }; - //--- Player + // Player if (hasinterface) then { waituntil {local player}; _serverCommand = ["#kick", "#shutdown"] select (_ownerVar == "#adminLogged"); - //--- Black effect until the interface is open + // Black effect until the interface is open _forced = _logic getvariable ["forced",0] > 0; if (_forced) then { _isCurator = switch true do { @@ -279,15 +279,15 @@ if (_activated) then { }; }; - //--- Check if player is server admin + // Check if player is server admin if (_isAdmin) then { _adminVar = _logic getvariable ["adminVar",""]; _logic setvariable ["adminVar",nil]; if (isserver) then { - //--- Host + // Host missionnamespace setvariable [_adminVar,player]; } else { - //--- Client + // Client [_logic,_adminVar,_serverCommand] spawn { scriptname "BIS_fnc_moduleCurator: Admin check"; @@ -314,7 +314,7 @@ if (_activated) then { sleep 1; waituntil {alive player}; - //--- Show warning when Zeus key is not assigned + // Show warning when Zeus key is not assigned if (count (actionkeys "curatorInterface") == 0) then { [ format [ @@ -324,7 +324,7 @@ if (_activated) then { ] call bis_fnc_guiMessage; }; - //--- Show hint about pinging for players + // Show hint about pinging for players if ( isnil {profilenamespace getvariable "bis_fnc_curatorPinged_done"} && @@ -339,7 +339,7 @@ if (_activated) then { }; }; - //--- Add local event handlers + // Add local event handlers _logic addeventhandler ["curatorFeedbackMessage",{_this call bis_fnc_showCuratorFeedbackMessage;}]; _logic addeventhandler ["curatorPinged",{_this call bis_fnc_curatorPinged;}]; _logic addeventhandler ["curatorObjectPlaced",{_this call bis_fnc_curatorObjectPlaced;}]; diff --git a/addons/zeus/functions/fnc_moduleCargoParadrop.sqf b/addons/zeus/functions/fnc_moduleCargoParadrop.sqf index 69d90d310d..2aaffb3796 100644 --- a/addons/zeus/functions/fnc_moduleCargoParadrop.sqf +++ b/addons/zeus/functions/fnc_moduleCargoParadrop.sqf @@ -30,13 +30,13 @@ TRACE_4("moduleCargoParadrop placed",_logic,typeOf _vehicle,_pilot,typeOf _pilot deleteVehicle _logic; // cleanup logic now, we just needed it to get the attached vehicle -if (!(missionNamespace getVariable [QEGVAR(cargo,enable), false])) exitWith { +if !(missionNamespace getVariable [QEGVAR(cargo,enable), false]) exitWith { [LSTRING(RequiresAddon)] call FUNC(showMessage); }; if (isNull _vehicle) exitWith { [LSTRING(NothingSelected)] call FUNC(showMessage); }; -if (!(_vehicle isKindOf "Air")) exitWith { +if !(_vehicle isKindOf "Air") exitWith { [format ["%1 %2", localize "str_dn_aircraft", localize "str_msg_no_veh_select"]] call FUNC(showMessage); }; if ((!alive _vehicle) || {!alive _pilot}) exitWith { diff --git a/addons/zeus/functions/fnc_moduleCargoParadropWaypoint.sqf b/addons/zeus/functions/fnc_moduleCargoParadropWaypoint.sqf index dded460710..6570648499 100644 --- a/addons/zeus/functions/fnc_moduleCargoParadropWaypoint.sqf +++ b/addons/zeus/functions/fnc_moduleCargoParadropWaypoint.sqf @@ -22,7 +22,7 @@ TRACE_2("moduleCargoParadropWaypoint",_vehicleGroup,_wpPos); private _vehicle = vehicle leader _vehicleGroup; private _commander = driver _vehicle; private _cargo = _vehicle getVariable [QEGVAR(cargo,loaded), []]; -if (!(_vehicle isKindOf "Air")) exitWith {WARNING_1("not in a air vehicle",typeOf _vehicle); true}; +if !(_vehicle isKindOf "Air") exitWith {WARNING_1("not in a air vehicle",typeOf _vehicle); true}; if (_cargo isEqualTo []) exitWith {WARNING_1("no cargo",_cargo); true}; private _previousSpeedMode = speedMode _vehicleGroup; diff --git a/addons/zeus/functions/fnc_moduleSetMedicalFacility.sqf b/addons/zeus/functions/fnc_moduleSetMedicalFacility.sqf index 5a23075369..b6742a25a4 100644 --- a/addons/zeus/functions/fnc_moduleSetMedicalFacility.sqf +++ b/addons/zeus/functions/fnc_moduleSetMedicalFacility.sqf @@ -40,7 +40,7 @@ if !(GETEGVAR(medical,enabled,false)) then { if (GETVAR(_unit,EGVAR(captives,isHandcuffed),false)) then { [LSTRING(OnlyNonCaptive)] call FUNC(showMessage); } else { - if (!(GETVAR(_unit,EGVAR(medical,isMedicalFacility),false))) then { + if !(GETVAR(_unit,EGVAR(medical,isMedicalFacility),false)) then { _unit setVariable [QEGVAR(medical,isMedicalFacility), true, true]; }; }; diff --git a/addons/zeus/functions/fnc_moduleSuicideBomber.sqf b/addons/zeus/functions/fnc_moduleSuicideBomber.sqf index 8346eb4266..8425ff1548 100644 --- a/addons/zeus/functions/fnc_moduleSuicideBomber.sqf +++ b/addons/zeus/functions/fnc_moduleSuicideBomber.sqf @@ -57,7 +57,7 @@ if (_autoSeek) then { LOG("Unit deleted or killed, PFH removed"); }; - if (!([_unit] call EFUNC(common,isAwake))) exitWith {}; + if !([_unit] call EFUNC(common,isAwake)) exitWith {}; // Detonation private _nearObjects = (_unit nearObjects _activationRadius) select {side _x == _activationSide && {_x != _unit} && {alive _x}}; diff --git a/addons/zeus/functions/fnc_showMessage.sqf b/addons/zeus/functions/fnc_showMessage.sqf index 8bbd7d510d..53094dbfb3 100644 --- a/addons/zeus/functions/fnc_showMessage.sqf +++ b/addons/zeus/functions/fnc_showMessage.sqf @@ -18,7 +18,7 @@ * Public: Yes */ -if (!(_this isEqualTypeParams [""])) exitWith {ERROR_1("First arg must be string [%1]",_this);}; +if !(_this isEqualTypeParams [""]) exitWith {ERROR_1("First arg must be string [%1]",_this);}; private _message = _this apply {if ((_x isEqualType "") && {isLocalized _x}) then {localize _x} else {_x}}; [objNull, format _message] call BIS_fnc_showCuratorFeedbackMessage; From c8be3a4e05c8957e099c8921bfcbfd93bb512285 Mon Sep 17 00:00:00 2001 From: Grim <69561145+LinkIsGrim@users.noreply.github.com> Date: Tue, 18 Jun 2024 12:26:24 -0300 Subject: [PATCH 102/290] Docs - Clarifiy `!` operator usage in Coding Guidelines (#10080) coding guidelines brackets --- docs/wiki/development/coding-guidelines.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/wiki/development/coding-guidelines.md b/docs/wiki/development/coding-guidelines.md index fcecbfbce4..fe9f0bfdf0 100644 --- a/docs/wiki/development/coding-guidelines.md +++ b/docs/wiki/development/coding-guidelines.md @@ -381,11 +381,19 @@ However the following is allowed: _value = (_array select 0) select 1; ``` -Any conditions in statements shall always be wrapped around brackets. +Any conditions in statements shall always be wrapped around brackets. Both uses of the `!` operator below are allowed. ```sqf -if (!_value) then {}; if (_value) then {}; +if (!_value) then {}; +if !(_value) then {}; +``` + +Use of the `!` operator on the lefthand-side of brackets can be more readable, particularly for more complex conditions or macros: + +```sqf +if !(_value && _otherValue && {_thirdValue call _something}) then {}; +if !(GETEGVAR(addon,globalVariableName,defaultValue)) then {}; ``` ### 5.6 Magic Numbers From 5ea202ce25a2ec95c923b59df7965d63bd10d647 Mon Sep 17 00:00:00 2001 From: Apricot <50947830+Apricot-ale@users.noreply.github.com> Date: Fri, 21 Jun 2024 03:01:28 +0900 Subject: [PATCH 103/290] Compat RF - Improve/Change RF Realistic Name (#10071) * Update RF Realname Stringtables Add HEMMT Fire Truck Change Puma family naming and add missing variation * typo fix * Tab to space I hate this * Update stringtable.xml Import HEMTT Fire Truck localization from RF Add "Container" to AMOS. cuz that is not just AMOS... * Uppercase and add rifle the HERA H6 * add space start of comment * Add "ASW" to Wildcat AH-11F For distinction with WY-55(Vanilla Wildcat) and AH-11F (RF Wildcat) * Remove "Rifle" from H6 Does it really need? Probably not. --- .../compat_rf_realisticnames/CfgVehicles.hpp | 48 +++++++--- .../compat_rf_realisticnames/stringtable.xml | 91 ++++++++++++------- 2 files changed, 90 insertions(+), 49 deletions(-) diff --git a/addons/compat_rf/compat_rf_realisticnames/CfgVehicles.hpp b/addons/compat_rf/compat_rf_realisticnames/CfgVehicles.hpp index 016a569c50..2983525ec8 100644 --- a/addons/compat_rf/compat_rf_realisticnames/CfgVehicles.hpp +++ b/addons/compat_rf/compat_rf_realisticnames/CfgVehicles.hpp @@ -19,36 +19,54 @@ class CfgVehicles { displayName = SUBCSTRING(heli_light_03_unarmed_Name); }; - class Heli_EC_01A_base_RF; - class Heli_EC_01A_military_base_RF: Heli_EC_01A_base_RF { - displayName = SUBCSTRING(ec_01a_military_Name); - }; - + // H240 Transport, Gendarmerie/ION Transport class Helicopter_Base_H; class Heli_EC_01_base_RF: Helicopter_Base_H { displayName = SUBCSTRING(ec_01_base_Name); }; - + // H240C Transport, CIV Transport class Heli_EC_01_civ_base_RF: Heli_EC_01_base_RF { - displayName = SUBCSTRING(ec_01_Name); + displayName = SUBCSTRING(ec_01_civ_base_Name); }; - + // H235 Transport, CIV Transport Float-less (not used) + class Heli_EC_01A_base_RF: Heli_EC_01_base_RF { + displayName = SUBCSTRING(ec_01a_base_Name); + }; + // H235C Transport, CIV Transport Float-less class Heli_EC_01A_civ_base_RF: Heli_EC_01A_base_RF { - displayName = SUBCSTRING(ec_01a_Name); + displayName = SUBCSTRING(ec_01a_civ_base_Name); }; - + // RAI-350M Cougar (Unarmed), IND/UNA Transport Float-less + class Heli_EC_01A_military_base_RF: Heli_EC_01A_base_RF { + displayName = SUBCSTRING(ec_01a_military_base_Name); + }; + // RAI-360M Cougar, IND/OPF SOCAT Float-less class Heli_EC_02_base_RF: Heli_EC_01_base_RF { - displayName = SUBCSTRING(ec_02_Name); + displayName = SUBCSTRING(ec_02_base_Name); }; - + // MH-360M Cougar, NATO SOCAT (not used) Float-less + class B_Heli_EC_02_RF: Heli_EC_02_base_RF { + displayName = SUBCSTRING(ec_02_nato_Name); + }; + // MH-245 Cougar, NATO Combat Type class Heli_EC_03_base_RF: Heli_EC_01_base_RF { - displayName = SUBCSTRING(ec_03_Name); + displayName = SUBCSTRING(ec_03_base_Name); }; - + // H245 SAR, CIV SAR Type class Heli_EC_04_base_RF: Heli_EC_01_base_RF { - displayName = SUBCSTRING(ec_04_Name); + displayName = SUBCSTRING(ec_04_base_Name); + }; + // MH-245 Cougar (Unarmed), NATO Transport Type (Maybe SAR?) + class Heli_EC_04_military_base_RF: Heli_EC_04_base_RF { + displayName = SUBCSTRING(ec_04_military_base_Name); }; + // HEMTT + class B_Truck_01_fuel_F; + class C_Truck_01_water_rf: B_Truck_01_fuel_F { + displayName = SUBCSTRING(truck_01_water_Name); + }; + // Typhoon class O_Truck_03_fuel_F; class C_Truck_03_water_rf: O_Truck_03_fuel_F { diff --git a/addons/compat_rf/compat_rf_realisticnames/stringtable.xml b/addons/compat_rf/compat_rf_realisticnames/stringtable.xml index a31221294c..e2ccac3c30 100644 --- a/addons/compat_rf/compat_rf_realisticnames/stringtable.xml +++ b/addons/compat_rf/compat_rf_realisticnames/stringtable.xml @@ -90,24 +90,24 @@ デザートイーグル Mark XIX L5 (ゴールド) - Hera H6 (Tan) - ヘラ H6 (タン) + HERA H6 (Tan) + HERA H6 (タン) - Hera H6 (Olive) - ヘラ H6 (オリーブ) + HERA H6 (Olive) + HERA H6 (オリーブ) - Hera H6 (Black) - ヘラ H6 (ブラック) + HERA H6 (Black) + HERA H6 (ブラック) - Hera H6 (Digital) - ヘラ H6 (AAF迷彩) + HERA H6 (Digital) + HERA H6 (AAF迷彩) - Hera H6 (Gold) - ヘラ H6 (ゴールド) + HERA H6 (Gold) + HERA H6 (ゴールド) VS-121 (Black) @@ -170,40 +170,63 @@ ASh-12 LR (森林迷彩) - AW159 Wildcat - AW159 ワイルドキャット + AW159 Wildcat ASW + AW159 ワイルドキャット ASW - AW159 Wildcat (Unarmed) - AW159 ワイルドキャット (非武装) - - - H225M Super Cougar HADR - H225M シュペル クーガー HADR + AW159 Wildcat ASW (Unarmed) + AW159 ワイルドキャット ASW (非武装) - H225M Super Cougar Transport - H225M シュペル クーガー 輸送 + H225 Super Puma (Transport) + H225 シュペル ピューマ (輸送型) - - H225 Super Puma Transport - H225 シュペル ピューマ 輸送 + + H225 Super Puma (Civilian) + H225 シュペル ピューマ (民生型) - - H225 Super Puma VIP - H225 シュペル ピューマ VIP + + H215 Super Puma (Transport) + H215 シュペル ピューマ (輸送型) - + + H215 Super Puma (Civilian) + H215 シュペル ピューマ (民生型) + + + H215 Super Puma (Unarmed) + H215 シュペル ピューマ (非武装) + + H225M Super Cougar SOCAT H225M シュペル クーガー SOCAT - - H225M Super Cougar CSAR - H225M シュペル クーガー CSAR + + H225M Super Cougar SOCAT + H225M シュペル クーガー SOCAT - + + H225M Super Cougar + H225M シュペル クーガー + + H225 Super Puma SAR - H225 シュペル ピューマ SAR + H225 シュペル ピューマ 捜索救難型 + + + H225M Super Cougar (Unarmed) + H225M シュペル クーガー (非武装) + + + HEMTT Fire Truck + HEMTT anti-incendie + HEMTT (wersja pożarnicza) + HEMTT-Löschfahrzeug + HEMTT (camión de bomberos) + Пожарная машина HEMTT + HEMTT 消防卡车 + HEMTT contra incêndio + HEMTT 消防車 Typhoon Water @@ -258,8 +281,8 @@ RSG60 - AMOS - AMOS + AMOS Container + AMOS コンテナ Drone40 From c4fb858c1d179376040c245f81d2d78f07483c24 Mon Sep 17 00:00:00 2001 From: Kex Date: Thu, 20 Jun 2024 20:19:14 +0200 Subject: [PATCH 104/290] Medical - Refactor target blood pressure (#10081) Refactor target blood pressure --- addons/medical_vitals/functions/fnc_updateHeartRate.sqf | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/addons/medical_vitals/functions/fnc_updateHeartRate.sqf b/addons/medical_vitals/functions/fnc_updateHeartRate.sqf index 187a8ffe58..0390a9ad07 100644 --- a/addons/medical_vitals/functions/fnc_updateHeartRate.sqf +++ b/addons/medical_vitals/functions/fnc_updateHeartRate.sqf @@ -40,13 +40,9 @@ if IN_CRDC_ARRST(_unit) then { private _spo2 = GET_SPO2(_unit); private _painLevel = GET_PAIN_PERCEIVED(_unit); - private _targetBP = 107; - if (_bloodVolume < BLOOD_VOLUME_CLASS_2_HEMORRHAGE) then { - _targetBP = _targetBP * (_bloodVolume / DEFAULT_BLOOD_VOLUME); - }; - _targetHR = DEFAULT_HEART_RATE; if (_bloodVolume < BLOOD_VOLUME_CLASS_3_HEMORRHAGE) then { + private _targetBP = 107 * (_bloodVolume / DEFAULT_BLOOD_VOLUME); _targetHR = _heartRate * (_targetBP / (45 max _meanBP)); }; if (_painLevel > 0.2) then { From 143968079526cce88e62b6d5523b5b906432238a Mon Sep 17 00:00:00 2001 From: bluefield <59333909+bluefieldcreator@users.noreply.github.com> Date: Thu, 20 Jun 2024 22:30:33 +0200 Subject: [PATCH 105/290] Overpressure - Separate backblast and overpressure range coefficient (#10070) * feat: separate overpressure and backblast configurations * documentation: remove undefined return * typo: trace macro padding * refactor: add range return * refactor: reuse return values for overpressure coef * refactor: reuse return values for backblast coef * whitespace Co-authored-by: Drofseh * headers Co-authored-by: Drofseh Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * feat: change backblast limit to 0 Co-authored-by: PabstMirror * remove: deleted ACE_Settings.hpp * fix: update postInit.sqf event handler to register new GVARs * fix: remove `ACE_Settings.hpp` * typo: add spacing Co-authored-by: Drofseh * typo: fix spacing Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * feat: switch distanceCoef minimun value to 0 Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * typo: update the slider checks with new minimuns temporary solution until i figure out the EH Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * feat: new stringable elements * Update stringtable.xml * Added translations * Switched order of settings to match age of settings * setting require restart, split adding firedEH * Added notifications about mission restart --------- Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> Co-authored-by: Drofseh Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> Co-authored-by: PabstMirror --- addons/overpressure/ACE_Settings.hpp | 5 --- addons/overpressure/XEH_postInit.sqf | 13 ++++--- addons/overpressure/config.cpp | 1 - .../overpressure/functions/fnc_firedEHBB.sqf | 2 ++ .../overpressure/functions/fnc_firedEHOP.sqf | 2 ++ .../functions/fnc_getOverPressureValues.sqf | 2 +- addons/overpressure/initSettings.inc.sqf | 20 +++++++++-- addons/overpressure/stringtable.xml | 34 +++++++++++-------- 8 files changed, 50 insertions(+), 29 deletions(-) delete mode 100644 addons/overpressure/ACE_Settings.hpp diff --git a/addons/overpressure/ACE_Settings.hpp b/addons/overpressure/ACE_Settings.hpp deleted file mode 100644 index d46cae7498..0000000000 --- a/addons/overpressure/ACE_Settings.hpp +++ /dev/null @@ -1,5 +0,0 @@ -class ACE_Settings { - class GVAR(distanceCoefficient) { - movedToSQF = 1; - }; -}; diff --git a/addons/overpressure/XEH_postInit.sqf b/addons/overpressure/XEH_postInit.sqf index 46fe460268..4b014e89e2 100644 --- a/addons/overpressure/XEH_postInit.sqf +++ b/addons/overpressure/XEH_postInit.sqf @@ -1,14 +1,17 @@ #include "script_component.hpp" ["CBA_settingsInitialized", { - TRACE_1("settingsInit eh",GVAR(distanceCoefficient)); - if (GVAR(distanceCoefficient) <= 0) exitWith {}; + TRACE_2("settingsInit eh",GVAR(backblastDistanceCoefficient),GVAR(overpressureDistanceCoefficient)); ["ace_overpressure", LINKFUNC(overpressureDamage)] call CBA_fnc_addEventHandler; - // Register fire event handler - ["ace_firedPlayer", LINKFUNC(firedEHBB)] call CBA_fnc_addEventHandler; - ["ace_firedPlayerVehicle", LINKFUNC(firedEHOP)] call CBA_fnc_addEventHandler; + // Register fire event handlers + if (GVAR(backblastDistanceCoefficient) > 0) then { + ["ace_firedPlayer", LINKFUNC(firedEHBB)] call CBA_fnc_addEventHandler; + }; + if (GVAR(overpressureDistanceCoefficient) > 0) then { + ["ace_firedPlayerVehicle", LINKFUNC(firedEHOP)] call CBA_fnc_addEventHandler; + }; GVAR(cacheHash) = createHashMap; }] call CBA_fnc_addEventHandler; diff --git a/addons/overpressure/config.cpp b/addons/overpressure/config.cpp index 3815cc831f..7274cd5059 100644 --- a/addons/overpressure/config.cpp +++ b/addons/overpressure/config.cpp @@ -14,7 +14,6 @@ class CfgPatches { }; }; -#include "ACE_Settings.hpp" #include "CfgEventHandlers.hpp" #include "CfgWeapons.hpp" #include "ACE_Arsenal_Stats.hpp" diff --git a/addons/overpressure/functions/fnc_firedEHBB.sqf b/addons/overpressure/functions/fnc_firedEHBB.sqf index a027785940..05a761bf06 100644 --- a/addons/overpressure/functions/fnc_firedEHBB.sqf +++ b/addons/overpressure/functions/fnc_firedEHBB.sqf @@ -22,6 +22,8 @@ TRACE_10("firedEH:",_unit,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile,_veh private _bbValues = [_weapon, _ammo, _magazine] call FUNC(getOverPressureValues); _bbValues params ["_backblastAngle", "_backblastRange", "_backblastDamage", "_offset"]; +_backblastRange = _backblastRange * GVAR(backblastDistanceCoefficient); + TRACE_4("cache",_backblastAngle,_backblastRange,_backblastDamage,_offset); if (_backblastDamage <= 0) exitWith {}; diff --git a/addons/overpressure/functions/fnc_firedEHOP.sqf b/addons/overpressure/functions/fnc_firedEHOP.sqf index 2345d09327..e011098b59 100644 --- a/addons/overpressure/functions/fnc_firedEHOP.sqf +++ b/addons/overpressure/functions/fnc_firedEHOP.sqf @@ -22,6 +22,8 @@ TRACE_10("firedEH:",_unit,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile,_veh private _opValues = [_weapon, _ammo, _magazine] call FUNC(getOverPressureValues); _opValues params ["_dangerZoneAngle", "_dangerZoneRange", "_dangerZoneDamage"]; +_dangerZoneRange = _dangerZoneRange * GVAR(overpressureDistanceCoefficient); + TRACE_3("cache",_dangerZoneAngle,_dangerZoneRange,_dangerZoneDamage); if (_dangerZoneDamage <= 0) exitWith {}; diff --git a/addons/overpressure/functions/fnc_getOverPressureValues.sqf b/addons/overpressure/functions/fnc_getOverPressureValues.sqf index 4372d4c8e6..374e9de9d6 100644 --- a/addons/overpressure/functions/fnc_getOverPressureValues.sqf +++ b/addons/overpressure/functions/fnc_getOverPressureValues.sqf @@ -54,7 +54,7 @@ TRACE_1("ConfigPath",_config); // get the Variables out of the Configs and populate return array with them _return = [ (getNumber (_config >> QGVAR(angle))), - (getNumber (_config >> QGVAR(range))) * GVAR(distanceCoefficient), + (getNumber (_config >> QGVAR(range))), (getNumber (_config >> QGVAR(damage))), (getNumber (_config >> QGVAR(offset))) ]; diff --git a/addons/overpressure/initSettings.inc.sqf b/addons/overpressure/initSettings.inc.sqf index 7fe6401131..ece1230dcc 100644 --- a/addons/overpressure/initSettings.inc.sqf +++ b/addons/overpressure/initSettings.inc.sqf @@ -1,9 +1,23 @@ private _category = [LELSTRING(common,categoryUncategorized), LLSTRING(DisplayName)]; [ - QGVAR(distanceCoefficient), "SLIDER", + QGVAR(overpressureDistanceCoefficient), + "SLIDER", [LSTRING(distanceCoefficient_displayName), LSTRING(distanceCoefficient_toolTip)], _category, - [-1, 10, 1, 1], - 1 + [0, 10, 1, 1], + 1, + {[QGVAR(overpressureDistanceCoefficient), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart +] call CBA_fnc_addSetting; + +[ + QGVAR(backblastDistanceCoefficient), + "SLIDER", + [LSTRING(backblastDistanceCoefficient_displayName), LSTRING(backblastDistanceCoefficient_toolTip)], + _category, + [0, 10, 1, 1], + 1, + {[QGVAR(backblastDistanceCoefficient), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart ] call CBA_fnc_addSetting; diff --git a/addons/overpressure/stringtable.xml b/addons/overpressure/stringtable.xml index caade38c3d..d8b9ad12f4 100644 --- a/addons/overpressure/stringtable.xml +++ b/addons/overpressure/stringtable.xml @@ -30,20 +30,26 @@ Coeficiente de distancia de sobrepresión - Scales the overpressure effect [Default: 1] - Stellt den Koeffizient für die Überdruckentfernung ein [Standard: 1] - 過圧効果の範囲 [デフォルト: 1] - 과중압력의 효과 크기 [기본설정: 1] - Skaluje efekt nadciśnienia [Domyślne: 1] - Ajuste l'effet de surpression. Valeur par défaut : 1. - Scala l'effetto di sovrapressione [Predefinito: 1] - 超压影响的范围 [预设:1] - 高壓影響的範圍 [預設: 1] - Степень зависимости избыточного давления от расстояния [По умолчанию: 1] - Escala o efeito de sobrepressão [Padrão: 1] - Állítja a túlnyomás hatását [Alapértelmezett: 1] - Nastavuje jak velký je efekt přetlaku [Standard: 1] - Escala el efecto de sobrepresión [Predeterminado: 1] + Scales the overpressure effect + Stellt den Koeffizient für die Überdruckentfernung ein + 過圧効果の範囲 + 과중압력의 효과 크기 + Skaluje efekt nadciśnienia + Ajuste l'effet de surpression + Scala l'effetto di sovrapressione + 超压影响的范围 + 高壓影響的範圍 + Степень зависимости избыточного давления от расстояния + Escala o efeito de sobrepressão + Állítja a túlnyomás hatását + Nastavuje jak velký je efekt přetlaku + Escala el efecto de sobrepresión + + + Backblast Distance Coefficient + + + Scales the backblast effect Backblast range From db6c4a72a6d58e1da496311f49c987d68630f31e Mon Sep 17 00:00:00 2001 From: Cyruz Date: Fri, 21 Jun 2024 16:06:44 +0100 Subject: [PATCH 106/290] Cookoff - Fix incorrect parent class in cookoff sounds (#10083) Fix incorrect parent Co-authored-by: Cyruz143 --- addons/cookoff/CfgSounds.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/cookoff/CfgSounds.hpp b/addons/cookoff/CfgSounds.hpp index 742fb589d9..70d752d613 100644 --- a/addons/cookoff/CfgSounds.hpp +++ b/addons/cookoff/CfgSounds.hpp @@ -45,7 +45,7 @@ class CfgSounds { class GVAR(shotsubmunitions_close_3): GVAR(shotbullet_close_3) { sound[] = {QPATHTOF(sounds\shotbullet\close_3.wss), VOLUME, PITCH, 1600}; }; - class GVAR(shotsubmunitions_mid_1): GVAR(shotbullet_far_1) { + class GVAR(shotsubmunitions_mid_1): GVAR(shotbullet_mid_1) { sound[] = {QPATHTOF(sounds\shotbullet\mid_1.wss), VOLUME, PITCH, 1600}; }; class GVAR(shotsubmunitions_mid_2): GVAR(shotbullet_mid_2) { From 7ea2aab2c90def4ed57b6fdcc31299125d52c483 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 22 Jun 2024 15:52:59 +0200 Subject: [PATCH 107/290] Common - Improve PBO checking (#9266) * Update PBO checking * Added kicking of clients without ACE loaded * Update fnc_errorMessage.sqf * Update fnc_checkVersionNumber.sqf * More compatibility for #9568 * Cleanup * Minor cleanup + added server source * update outdated/not present error message * check version number fixes * Update fnc_errorMessage.sqf * Changed error names Server is always right, client has either older or newer versions, or missing or additional addons * Improved ACE detection method * Tweaks and fixes * Try another approach * Update events-framework.md * Update XEH_postInit.sqf * Update fnc_checkVersionNumber.sqf * Removed check for non-ACE clients * Update XEH_postInit.sqf * Cleanup * Remove rogue change * Improved message display in systemChat * Update fnc_checkPBOs.sqf * Removed loop variable initialisers * Fixed header * Updated headers --------- Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> Co-authored-by: LinkIsGrim --- addons/common/XEH_PREP.hpp | 1 + addons/common/functions/fnc_checkFiles.sqf | 119 ++++++----- .../functions/fnc_checkFiles_diagnoseACE.sqf | 48 +++-- addons/common/functions/fnc_checkPBOs.sqf | 102 +++++----- .../functions/fnc_checkVersionNumber.sqf | 161 +++++++++++++++ addons/common/functions/fnc_errorMessage.sqf | 188 +++++++++--------- addons/common/scripts/checkVersionNumber.sqf | 160 --------------- docs/wiki/framework/events-framework.md | 2 + 8 files changed, 408 insertions(+), 373 deletions(-) create mode 100644 addons/common/functions/fnc_checkVersionNumber.sqf delete mode 100644 addons/common/scripts/checkVersionNumber.sqf diff --git a/addons/common/XEH_PREP.hpp b/addons/common/XEH_PREP.hpp index f46d1689f9..3a5838a230 100644 --- a/addons/common/XEH_PREP.hpp +++ b/addons/common/XEH_PREP.hpp @@ -30,6 +30,7 @@ PREP(changeProjectileDirection); PREP(checkFiles); PREP(checkFiles_diagnoseACE); PREP(checkPBOs); +PREP(checkVersionNumber); PREP(claim); PREP(claimSafeServer); PREP(codeToString); diff --git a/addons/common/functions/fnc_checkFiles.sqf b/addons/common/functions/fnc_checkFiles.sqf index 39e2bac3ac..7b90a1b0a8 100644 --- a/addons/common/functions/fnc_checkFiles.sqf +++ b/addons/common/functions/fnc_checkFiles.sqf @@ -15,15 +15,20 @@ * Public: No */ -/////////////// -// check addons -/////////////// -private _mainCfg = configFile >> "CfgPatches" >> "ace_main"; -private _mainVersion = getText (_mainCfg >> "versionStr"); -private _mainSource = configSourceMod _mainCfg; +// Don't execute in scheduled environment +if (canSuspend) exitWith { + [FUNC(checkFiles), nil] call CBA_fnc_directCall; +}; -//CBA Versioning check - close main display if using incompatible version -private _cbaVersionAr = getArray (configFile >> "CfgPatches" >> "cba_main" >> "versionAr"); +/////////////// +// Check addons +/////////////// +private _cfgPatches = configFile >> "CfgPatches"; +private _mainVersion = getText (_cfgPatches >> "ace_main" >> "versionStr"); +private _mainSource = configSourceMod (_cfgPatches >> "ace_main"); + +// CBA Versioning check - close main display if using incompatible version +private _cbaVersionAr = getArray (_cfgPatches >> "cba_main" >> "versionAr"); private _cbaRequiredAr = getArray (configFile >> "CfgSettings" >> "CBA" >> "Versioning" >> "ACE" >> "dependencies" >> "CBA") select 1; private _cbaVersionStr = _cbaVersionAr joinString "."; @@ -31,53 +36,62 @@ private _cbaRequiredStr = _cbaRequiredAr joinString "."; INFO_3("ACE is version %1 - CBA is version %2 (min required %3)",_mainVersion,_cbaVersionStr,_cbaRequiredStr); -if ([_cbaRequiredAr, _cbaVersionAr] call cba_versioning_fnc_version_compare) then { +if ([_cbaRequiredAr, _cbaVersionAr] call CBA_versioning_fnc_version_compare) then { private _errorMsg = format ["CBA version %1 is outdated (required %2)", _cbaVersionStr, _cbaRequiredStr]; ERROR(_errorMsg); + if (hasInterface) then { - ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg] call FUNC(errorMessage); }; }; -//private _addons = activatedAddons; // broken with High-Command module, see #2134 -private _addons = (cba_common_addons select {(_x select [0,4]) == "ace_"}) apply {toLowerANSI _x}; +//private _addons = activatedAddons; // Broken with High-Command module, see #2134 +private _addons = (CBA_common_addons select {(_x select [0, 4]) == "ace_"}) apply {toLowerANSI _x}; + private _oldAddons = []; private _oldSources = []; private _oldCompats = []; + { private _addonCfg = configFile >> "CfgPatches" >> _x; private _addonVersion = getText (_addonCfg >> "versionStr"); + if (_addonVersion != _mainVersion) then { private _addonSource = configSourceMod _addonCfg; + _oldSources pushBackUnique _addonSource; + + // Check ACE install call FUNC(checkFiles_diagnoseACE); + // Don't block game if it's just an old compat pbo if ((_x select [0, 10]) != "ace_compat") then { - if (hasInterface) then { - _oldAddons pushBack _x; - }; + _oldAddons pushBack _x; } else { - _oldCompats pushBack [_x, _addonVersion]; // Don't block game if it's just an old compat pbo + _oldCompats pushBack [_x, _addonVersion]; }; }; } forEach _addons; if (_oldAddons isNotEqualTo []) then { - _oldAddons = _oldAddons apply { format ["%1.pbo", _x] }; - private _errorMsg = ""; - if (count _oldAddons > 3) then { - _errorMsg = format ["The following files are outdated: %1, and %2 more.
ACE Main version is %3 from %4.
Loaded mods with outdated ACE files: %5", (_oldAddons select [0, 3]) joinString ", ", (count _oldAddons) -3, _mainVersion, _mainSource, (_oldSources joinString ", ")]; + _oldAddons = _oldAddons apply {format ["%1.pbo", _x]}; + + private _errorMsg = if (count _oldAddons > 3) then { + format ["The following files are outdated: %1, and %2 more.
ACE Main version is %3 from %4.
Loaded mods with outdated ACE files: %5", (_oldAddons select [0, 3]) joinString ", ", (count _oldAddons) - 3, _mainVersion, _mainSource, _oldSources joinString ", "]; } else { - _errorMsg = format ["The following files are outdated: %1.
ACE Main version is %2 from %3.
Loaded mods with outdated ACE files: %4", (_oldAddons) joinString ", ", _mainVersion, _mainSource, (_oldSources) joinString ", "]; + format ["The following files are outdated: %1.
ACE Main version is %2 from %3.
Loaded mods with outdated ACE files: %4", _oldAddons joinString ", ", _mainVersion, _mainSource, _oldSources joinString ", "]; }; + if (hasInterface) then { - ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg] call FUNC(errorMessage); }; + ERROR(_errorMsg); }; if (_oldCompats isNotEqualTo []) then { _oldCompats = _oldCompats apply {format ["%1 (%2)", _x select 0, _x select 1]}; + [{ // Lasts for ~10 seconds ERROR_WITH_TITLE_3("The following ACE compatiblity PBOs are outdated","%1. ACE Main version is %2 from %3.",_this select 0,_this select 1,_this select 2); @@ -85,9 +99,10 @@ if (_oldCompats isNotEqualTo []) then { }; /////////////// -// check extensions +// Check extensions /////////////// private _platform = toLowerANSI (productVersion select 6); + if (!isServer && {_platform in ["linux", "osx"]}) then { // Linux and OSX client ports do not support extensions at all INFO("Operating system does not support extensions"); @@ -101,8 +116,10 @@ if (!isServer && {_platform in ["linux", "osx"]}) then { if ((_isWindows || _isLinux) && {_isClient || _isServer}) then { private _versionEx = _extension callExtension "version"; + if (_versionEx == "") then { private _extensionFile = _extension; + if (productVersion select 7 == "x64") then { _extensionFile = format ["%1_x64", _extensionFile]; }; @@ -114,7 +131,7 @@ if (!isServer && {_platform in ["linux", "osx"]}) then { ERROR(_errorMsg); if (hasInterface) then { - ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg] call FUNC(errorMessage); }; } else { // Print the current extension version @@ -123,54 +140,66 @@ if (!isServer && {_platform in ["linux", "osx"]}) then { }; } forEach ("true" configClasses (configFile >> "ACE_Extensions")); }; + if (isArray (configFile >> "ACE_Extensions" >> "extensions")) then { WARNING("extensions[] array no longer supported"); }; /////////////// -// check server version/addons +// Check server version/addons /////////////// if (isMultiplayer) then { - // don't check optional addons - _addons = _addons select {getNumber (configFile >> "CfgPatches" >> _x >> "ACE_isOptional") != 1}; + // Don't check optional addons + _addons = _addons select {getNumber (_cfgPatches >> _x >> "ACE_isOptional") != 1}; if (isServer) then { - // send servers version of ACE to all clients - GVAR(ServerVersion) = _mainVersion; - GVAR(ServerAddons) = _addons; - publicVariable QGVAR(ServerVersion); - publicVariable QGVAR(ServerAddons); + // Send server's version of ACE to all clients + GVAR(serverVersion) = _mainVersion; + GVAR(serverAddons) = _addons; + GVAR(serverSource) = _mainSource; + + publicVariable QGVAR(serverVersion); + publicVariable QGVAR(serverAddons); + publicVariable QGVAR(serverSource); } else { - // clients have to wait for the variables - [{ - if (isNil QGVAR(ServerVersion) || isNil QGVAR(ServerAddons)) exitWith {}; + GVAR(clientVersion) = _version; + GVAR(clientAddons) = _addons; - (_this select 0) params ["_mainVersion", "_addons"]; - - if (_mainVersion != GVAR(ServerVersion)) then { - private _errorMsg = format ["Client/Server Version Mismatch. Server: %1, Client: %2.", GVAR(ServerVersion), _mainVersion]; + private _fnc_check = { + if (GVAR(clientVersion) != GVAR(serverVersion)) then { + private _errorMsg = format ["Client/Server Version Mismatch. Server: %1, Client: %2. Server modDir: %3", GVAR(serverVersion), GVAR(clientVersion), GVAR(serverSource)]; + // Check ACE install call FUNC(checkFiles_diagnoseACE); + ERROR(_errorMsg); if (hasInterface) then { - ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg] call FUNC(errorMessage); }; }; - _addons = _addons - GVAR(ServerAddons); + private _addons = GVAR(clientAddons) - GVAR(serverAddons); + if (_addons isNotEqualTo []) then { - private _errorMsg = format ["Client/Server Addon Mismatch. Client has extra addons: %1.",_addons]; + private _errorMsg = format ["Client/Server Addon Mismatch. Client has additional addons: %1. Server modDir: %2", _addons, GVAR(serverSource)]; + // Check ACE install call FUNC(checkFiles_diagnoseACE); + ERROR(_errorMsg); if (hasInterface) then { - ["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage); + ["[ACE] ERROR", _errorMsg] call FUNC(errorMessage); }; }; + }; - [_this select 1] call CBA_fnc_removePerFrameHandler; - }, 1, [_mainVersion,_addons]] call CBA_fnc_addPerFrameHandler; + // Clients have to wait for the variables + if (isNil QGVAR(serverVersion) || isNil QGVAR(serverAddons)) then { + GVAR(serverVersion) addPublicVariableEventHandler _fnc_check; + } else { + call _fnc_check; + }; }; }; diff --git a/addons/common/functions/fnc_checkFiles_diagnoseACE.sqf b/addons/common/functions/fnc_checkFiles_diagnoseACE.sqf index 5b7f80198b..f9271ca213 100644 --- a/addons/common/functions/fnc_checkFiles_diagnoseACE.sqf +++ b/addons/common/functions/fnc_checkFiles_diagnoseACE.sqf @@ -1,13 +1,13 @@ #include "..\script_component.hpp" /* * Author: PabstMirror - * Diagnose ACE install problems, this will only be called if there is a known problem + * Diagnoses ACE install problems, this will only be called if there is a known problem. * * Arguments: * None * * Return Value: - * None + * ACE addons' WS IDs * * Example: * [] call ace_common_fnc_checkFiles_diagnoseACE @@ -16,43 +16,59 @@ */ // Only run once -if (missionNameSpace getVariable [QGVAR(checkFiles_diagnoseACE), false]) exitWith {}; +if (missionNameSpace getVariable [QGVAR(checkFiles_diagnoseACE), false]) exitWith { + createHashMap // return +}; + GVAR(checkFiles_diagnoseACE) = true; -private _addons = cba_common_addons select {(_x select [0,4]) == "ace_"}; +private _addons = CBA_common_addons select {(_x select [0, 4]) == "ace_"}; private _cfgPatches = configFile >> "CfgPatches"; private _allMods = createHashMap; +private _getLoadedModsInfo = getLoadedModsInfo; -// Check ACE_ADDONs are in expected mod DIR +// Check if ACE_ADDONs are in expected mod DIR { - private _cfg = (_cfgPatches >> _x); + private _cfg = _cfgPatches >> _x; private _actualModDir = configSourceMod _cfg; private _expectedModDir = getText (_cfg >> "ACE_expectedModDir"); - if (_expectedModDir == "") then { _expectedModDir = "@ace" }; + + if (_expectedModDir == "") then { + _expectedModDir = "@ace"; + }; + private _expectedSteamID = getText (_cfg >> "ACE_expectedSteamID"); - if (_expectedSteamID == "") then { _expectedSteamID = "463939057" }; + + if (_expectedSteamID == "") then { + _expectedSteamID = "463939057" + }; (_allMods getOrDefault [_actualModDir, [], true]) pushBackUnique _expectedSteamID; + if (_actualModDir != _expectedModDir) then { - private _errorMsg = format ["%1 loading from unexpected modDir [%2]",_x,_actualModDir]; + private _errorMsg = format ["%1 loading from unexpected modDir [%2]", _x, _actualModDir]; systemChat _errorMsg; WARNING_1("%1",_errorMsg); }; } forEach _addons; -// Check all ACE ModDirs have expected steam WS ID +// Check if all ACE ModDirs have expected steam WS ID { private _modDir = _x; - if ((count _y) != 1) then { ERROR_2("Unexpected multiple steamIDs %1 - %2",_modDir,_y) }; - private _expectedSteamID = _y # 0; - private _index = getLoadedModsInfo findIf {_x#1 == _modDir}; - (getLoadedModsInfo param [_index, []]) params [["_modName", "$Error$"], "", "", "", "", "", "", ["_actualID", ""]]; + + if (count _y != 1) then { + ERROR_2("Unexpected multiple steamIDs %1 - %2",_modDir,_y); + }; + + private _expectedSteamID = _y select 0; + private _index = _getLoadedModsInfo findIf {_x select 1 == _modDir}; + (_getLoadedModsInfo param [_index, []]) params [["_modName", "$Error$"], "", "", "", "", "", "", ["_actualID", ""]]; if (_actualID != _expectedSteamID) then { - private _errorMsg = format ["%1 [%2] unexpected workshopID [%3]",_modDir,_modName,_actualID]; + private _errorMsg = format ["%1 [%2] unexpected workshopID [%3]", _modDir, _modName, _actualID]; systemChat _errorMsg; WARNING_1("%1",_errorMsg); }; } forEach _allMods; -_allMods +_allMods // return diff --git a/addons/common/functions/fnc_checkPBOs.sqf b/addons/common/functions/fnc_checkPBOs.sqf index cb192c6667..4f2e3f4fa6 100644 --- a/addons/common/functions/fnc_checkPBOs.sqf +++ b/addons/common/functions/fnc_checkPBOs.sqf @@ -1,6 +1,6 @@ #include "..\script_component.hpp" /* - * Author: commy2 + * Author: commy2, johnb43 * Used to execute the checkPBOs module without placing the module. Don't use this together with the module. * Checks PBO versions and compares to the one running on server. * @@ -9,8 +9,8 @@ * 0 = Warn once * 1 = Warn permanently * 2 = Kick - * 1: Check all PBOs? (default: false) - * 2: Whitelist (default: "") + * 1: Check all PBOs? (default: false) + * 2: Whitelist (default: "") * * Return Value: * None @@ -24,7 +24,7 @@ params ["_mode", ["_checkAll", false], ["_whitelist", "", [""]]]; TRACE_3("params",_mode,_checkAll,_whitelist); -//lowercase and convert whiteList String into array of strings: +// Lowercase and convert whiteList string into array of strings _whitelist = toLowerANSI _whitelist; _whitelist = _whitelist splitString "[,""']"; TRACE_1("Array",_whitelist); @@ -32,75 +32,67 @@ TRACE_1("Array",_whitelist); ACE_Version_CheckAll = _checkAll; ACE_Version_Whitelist = _whitelist; -if (!_checkAll) exitWith {}; //ACE is checked by FUNC(checkFiles) +// ACE is checked by FUNC(checkFiles) +if (!_checkAll) exitWith {}; if (!isServer) then { - [{ - if (isNil "ACE_Version_ClientErrors") exitWith {}; + ["ace_versioning_clientCheckDone", { + // Don't let this event get triggered again + [_thisType, _thisId] call CBA_fnc_removeEventHandler; - ACE_Version_ClientErrors params ["_missingAddon", "_missingAddonServer", "_oldVersionClient", "_oldVersionServer"]; + params ["_clientErrors"]; + _clientErrors params ["_missingAddonClient", "_additionalAddonClient", "_olderVersionClient", "_newerVersionClient"]; + _thisArgs params ["_mode"]; - (_this select 0) params ["_mode", "_checkAll", "_whitelist"]; + // Display error message(s) + if (_missingAddonClient || {_additionalAddonClient} || {_olderVersionClient} || {_newerVersionClient}) then { + private _errorMsg = "[ACE] Version mismatch:

"; + private _error = []; - // Display error message. - if (_missingAddon || {_missingAddonServer} || {_oldVersionClient} || {_oldVersionServer}) then { - private _text = "[ACE] Version mismatch:

"; - private _error = format ["ACE version mismatch: %1: ", profileName]; - - if (_missingAddon) then { - _text = _text + "Detected missing addon on client
"; - _error = _error + "Missing file(s); "; - }; - if (_missingAddonServer) then { - _text = _text + "Detected missing addon on server
"; - _error = _error + "Additional file(s); "; - }; - if (_oldVersionClient) then { - _text = _text + "Detected old client version
"; - _error = _error + "Older version; "; - }; - if (_oldVersionServer) then { - _text = _text + "Detected old server version
"; - _error = _error + "Newer version; "; + if (_missingAddonClient) then { + _errorMsg = _errorMsg + "Detected missing addon on client
"; + _error pushBack "Missing file(s)"; }; - //[QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; + if (_additionalAddonClient) then { + _errorMsg = _errorMsg + "Detected additional addon on client
"; + _error pushBack "Additional file(s)"; + }; - ERROR(_error); + if (_olderVersionClient) then { + _errorMsg = _errorMsg + "Detected older client version
"; + _error pushBack "Older version"; + }; + if (_newerVersionClient) then { + _errorMsg = _errorMsg + "Detected newer client version
"; + _error pushBack "Newer version"; + }; + + ERROR_2("[ACE] Version mismatch: %1: %2",profileName,_error joinString ", "); + + _errorMsg = parseText format ["%1", _errorMsg]; + + // Warn if (_mode < 2) then { - _text = composeText [lineBreak, parseText format ["%1", _text]]; - private _rscLayer = "ACE_RscErrorHint" call BIS_fnc_rscLayer; _rscLayer cutRsc ["ACE_RscErrorHint", "PLAIN", 0, true]; - disableSerialization; - private _ctrlHint = uiNamespace getVariable "ACE_ctrlErrorHint"; - _ctrlHint ctrlSetStructuredText _text; + (uiNamespace getVariable "ACE_ctrlErrorHint") ctrlSetStructuredText composeText [lineBreak, _errorMsg]; if (_mode == 0) then { [{ - params ["_rscLayer"]; - TRACE_2("Hiding Error message after 10 seconds",time,_rscLayer); - _rscLayer cutFadeOut 0.2; - }, [_rscLayer], 10] call CBA_fnc_waitAndExecute; + TRACE_2("Hiding Error message after 10 seconds",time,_this); + _this cutFadeOut 0.2; + }, _rscLayer, 10] call CBA_fnc_waitAndExecute; }; - }; - - if (_mode == 2) then { - [{alive player}, { // To be able to show list if using checkAll - params ["_text"]; - TRACE_2("Player is alive, showing msg and exiting",time,_text); - _text = composeText [parseText format ["%1", _text]]; - ["[ACE] ERROR", _text, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage); - }, [_text]] call CBA_fnc_waitUntilAndExecute; + } else { + // Kick + ["[ACE] ERROR", composeText [_errorMsg]] call FUNC(errorMessage); }; }; - - [_this select 1] call CBA_fnc_removePerFrameHandler; - }, 1, [_mode, _checkAll, _whitelist]] call CBA_fnc_addPerFrameHandler; + }, [_mode]] call CBA_fnc_addEventHandlerArgs; }; -if (_checkAll) then { - 0 spawn COMPILE_FILE(scripts\checkVersionNumber); // @todo -}; +// Check file version numbers +[_whitelist] call FUNC(checkVersionNumber); diff --git a/addons/common/functions/fnc_checkVersionNumber.sqf b/addons/common/functions/fnc_checkVersionNumber.sqf new file mode 100644 index 0000000000..a286129917 --- /dev/null +++ b/addons/common/functions/fnc_checkVersionNumber.sqf @@ -0,0 +1,161 @@ +#include "..\script_component.hpp" +/* + * Author: commy2, johnb43 + * Compares version numbers from loaded addons. + * + * Arguments: + * 0: Lowercase addon whitelist (default: missionNamespace getVariable ["ACE_Version_Whitelist", []]) + * + * Return Value: + * None + * + * Example: + * call ace_common_fnc_checkVersionNumber + * + * Public: No + */ + +// Don't execute in scheduled environment +if (canSuspend) exitWith { + [FUNC(checkVersionNumber), _this] call CBA_fnc_directCall; +}; + +params [["_whitelist", missionNamespace getVariable ["ACE_Version_Whitelist", []]]]; + +private _files = CBA_common_addons select { + (_x select [0, 3] != "a3_") && + {_x select [0, 4] != "ace_"} && + {!((toLowerANSI _x) in _whitelist)} +}; + +private _cfgPatches = configFile >> "CfgPatches"; +private _versions = []; + +{ + (getText (_cfgPatches >> _x >> "version") splitString ".") params [["_major", "0"], ["_minor", "0"]]; + private _version = parseNumber _major + parseNumber _minor / 100; + _versions pushBack _version; +} forEach _files; + +if (isServer) exitWith { + ACE_Version_ServerVersions = [_files, _versions]; + publicVariable "ACE_Version_ServerVersions"; + + // Raise event when done + ["ace_versioning_serverCheckDone", [+ACE_Version_ServerVersions]] call CBA_fnc_localEvent; +}; + +// Begin client version check +ACE_Version_ClientVersions = [_files, _versions]; + +private _fnc_check = { + ACE_Version_ClientVersions params [["_files", []], ["_versions", []]]; + ACE_Version_ServerVersions params [["_serverFiles", []], ["_serverVersions", []]]; + + // Compare client and server files and versions + private _client = profileName; + private _missingAddonsClient = []; + private _olderVersionsClient = []; + private _newerVersionsClient = []; + + { + private _serverVersion = _serverVersions select _forEachIndex; + + private _index = _files find _x; + + if (_index == -1) then { + if (_x != "ace_server") then { + _missingAddonsClient pushBack _x; + }; + } else { + private _clientVersion = _versions select _index; + + if (_clientVersion < _serverVersion) then { + _olderVersionsClient pushBack [_x, _clientVersion, _serverVersion]; + }; + + if (_clientVersion > _serverVersion) then { + _newerVersionsClient pushBack [_x, _clientVersion, _serverVersion]; + }; + }; + } forEach _serverFiles; + + // Find client files which the server doesn't have + private _additionalAddonsClient = _files select {!(_x in _serverFiles)}; + + // Check for client missing addons, server missing addons, client outdated addons and server outdated addons + private _clientErrors = []; + + #define DISPLAY_NUMBER_ADDONS (10 + 1) // +1 to account for header + + { + _x params ["_items", "_string"]; + + // Check if something is either missing or outdated + private _isMissingItems = _items isNotEqualTo []; + + if (_isMissingItems) then { + // Generate error message + private _errorLog = +_items; + private _header = format ["[ACE] %1: ERROR %2 addon(s): ", _client, _string]; + + // Don't display all missing items, as they are logged + private _errorMsg = _header + ((_errorLog select [0, DISPLAY_NUMBER_ADDONS]) joinString ", "); + _errorLog = _header + (_errorLog joinString ", "); + + private _count = count _items; + + if (_count > DISPLAY_NUMBER_ADDONS) then { + _errorMsg = _errorMsg + format [", and %1 more.", _count - DISPLAY_NUMBER_ADDONS]; + }; + + // Wait until in briefing screen + [{ + getClientStateNumber >= 9 // "BRIEFING SHOWN" + }, { + params ["_errorLog", "_errorMsg"]; + + // Log and display error messages + diag_log text _errorLog; + [QGVAR(serverLog), _errorLog] call CBA_fnc_serverEvent; + [QGVAR(systemChatGlobal), _errorMsg] call CBA_fnc_globalEvent; + + // Wait until after map screen + [{ + !isNull (call BIS_fnc_displayMission) + }, { + params ["_errorMsg", "_timeOut"]; + + // If the briefing screen was shown for less than 5 seconds, display the error message again, but locally + if (_timeOut < CBA_missionTime) exitWith {}; + + // Make sure systemChat is ready by waiting a bit + [{ + systemChat _this; + }, _errorMsg, 1] call CBA_fnc_waitAndExecute; + }, [_errorMsg, CBA_missionTime + 5]] call CBA_fnc_waitUntilAndExecute; + }, [_errorLog, _errorMsg]] call CBA_fnc_waitUntilAndExecute; + }; + + _clientErrors pushBack _isMissingItems; + } forEach [ + [_missingAddonsClient, "client missing"], + [_additionalAddonsClient, "client additional"], + [_olderVersionsClient, "older client"], + [_newerVersionsClient, "newer client"] + ]; + + TRACE_4("",_missingAddonsClient,_additionalAddonsClient,_olderVersionsClient,_newerVersionsClient); + + ACE_Version_ClientErrors = _clientErrors; + + // Raise event when done + ["ace_versioning_clientCheckDone", [+ACE_Version_ClientErrors]] call CBA_fnc_localEvent; +}; + +// Wait for server to send the servers files and version numbers +if (isNil "ACE_Version_ServerVersions") then { + ACE_Version_ServerVersions addPublicVariableEventHandler _fnc_check; +} else { + call _fnc_check; +}; diff --git a/addons/common/functions/fnc_errorMessage.sqf b/addons/common/functions/fnc_errorMessage.sqf index 72344299f3..e98a5baf8f 100644 --- a/addons/common/functions/fnc_errorMessage.sqf +++ b/addons/common/functions/fnc_errorMessage.sqf @@ -1,147 +1,141 @@ #include "..\script_component.hpp" +#include "\a3\ui_f\hpp\defineResincl.inc" +#include "\a3\ui_f\hpp\defineDIKCodes.inc" /* - * Author: commy2, based on BIS_fnc_errorMsg and BIS_fnc_guiMessage by Karel Moricky (BI) - * Stops simulation and opens a textbox with error message. + * Author: commy2, johnb43, based on BIS_fnc_errorMsg and BIS_fnc_guiMessage by Karel Moricky (BI) + * Opens a textbox with an error message, used for PBO checking. * * Arguments: - * ? + * 0: Header + * 1: Text * * Return Value: * None * * Example: - * call ace_common_fnc_errorMessage + * ["[ACE] ERROR", "Test"] call ace_common_fnc_errorMessage * * Public: No */ -disableSerialization; +// Force stop any loading screens endLoadingScreen; -// no message without player possible +// No message without interface possible if (!hasInterface) exitWith {}; -// wait for display -if (isNull (call BIS_fnc_displayMission)) exitWith { - [{ - if (isNull (call BIS_fnc_displayMission)) exitWith {}; +[{ + !isNull (call BIS_fnc_displayMission) +}, { + params ["_textHeader", "_textMessage"]; - (_this select 0) call FUNC(errorMessage); - [_this select 1] call CBA_fnc_removePerFrameHandler; + disableSerialization; - }, 1, _this] call CBA_fnc_addPerFrameHandler; -}; + // Use curator display if present + private _curatorDisplay = findDisplay 312; -params ["_textHeader", "_textMessage", ["_onOK", {}], ["_onCancel", {}]]; + private _mainDisplay = if (!isNull _curatorDisplay) then { + _curatorDisplay + } else { + call BIS_fnc_displayMission + }; -if (_textMessage isEqualType "") then { - _textMessage = parseText _textMessage; -}; + if (_textMessage isEqualType "") then { + _textMessage = parseText _textMessage; + }; -ARR_SELECT(_this,4,call BIS_fnc_displayMission) createDisplay "RscDisplayCommonMessagePause"; + private _display = _mainDisplay createDisplay "RscDisplayCommonMessagePause"; -private _display = uiNamespace getVariable "RscDisplayCommonMessage_display"; -private _ctrlRscMessageBox = _display displayCtrl 2351; -private _ctrlBcgCommonTop = _display displayCtrl 235100; -private _ctrlBcgCommon = _display displayCtrl 235101; -private _ctrlText = _display displayCtrl 235102; -private _ctrlBackgroundButtonOK = _display displayCtrl 235103; -private _ctrlBackgroundButtonMiddle = _display displayCtrl 235104; -private _ctrlBackgroundButtonCancel = _display displayCtrl 235105; -private _ctrlButtonOK = _display displayCtrl 235106; -private _ctrlButtonCancel = _display displayCtrl 235107; + if (isNull _display) exitWith {}; -_ctrlBcgCommonTop ctrlSetText _textHeader; + private _ctrlRscMessageBox = _display displayCtrl 2351; + private _ctrlBcgCommonTop = _display displayCtrl 235100; + private _ctrlBcgCommon = _display displayCtrl 235101; + private _ctrlText = _display displayCtrl 235102; + private _ctrlBackgroundButtonOK = _display displayCtrl 235103; + private _ctrlBackgroundButtonMiddle = _display displayCtrl 235104; + private _ctrlBackgroundButtonCancel = _display displayCtrl 235105; + private _ctrlButtonOK = _display displayCtrl 235106; + private _ctrlButtonCancel = _display displayCtrl 235107; -private _ctrlButtonOKPos = ctrlPosition _ctrlButtonOK; -private _ctrlBcgCommonPos = ctrlPosition _ctrlBcgCommon; -private _bottomSpaceY = (_ctrlButtonOKPos select 1) - ((_ctrlBcgCommonPos select 1) + (_ctrlBcgCommonPos select 3)); + _ctrlBcgCommonTop ctrlSetText _textHeader; -private _ctrlTextPos = ctrlPosition _ctrlText; -private _marginX = (_ctrlTextPos select 0) - (_ctrlBcgCommonPos select 0); -private _marginY = (_ctrlTextPos select 1) - (_ctrlBcgCommonPos select 1); + private _ctrlButtonOKPos = ctrlPosition _ctrlButtonOK; + private _ctrlBcgCommonPos = ctrlPosition _ctrlBcgCommon; + private _bottomSpaceY = (_ctrlButtonOKPos select 1) - ((_ctrlBcgCommonPos select 1) + (_ctrlBcgCommonPos select 3)); -_ctrlText ctrlSetStructuredText _textMessage; -private _ctrlTextPosH = ctrlTextHeight _ctrlText; + private _ctrlTextPos = ctrlPosition _ctrlText; + private _marginX = (_ctrlTextPos select 0) - (_ctrlBcgCommonPos select 0); + private _marginY = (_ctrlTextPos select 1) - (_ctrlBcgCommonPos select 1); -_ctrlBcgCommon ctrlSetPosition [ - _ctrlBcgCommonPos select 0, - _ctrlBcgCommonPos select 1, - _ctrlBcgCommonPos select 2, - _ctrlTextPosH + _marginY * 2 -]; -_ctrlBcgCommon ctrlCommit 0; + _ctrlText ctrlSetStructuredText _textMessage; + private _ctrlTextPosH = ctrlTextHeight _ctrlText; -_ctrlText ctrlSetPosition [ - (_ctrlBcgCommonPos select 0) + _marginX, - (_ctrlBcgCommonPos select 1) + _marginY, - (_ctrlBcgCommonPos select 2) - _marginX * 2, - _ctrlTextPosH -]; -_ctrlText ctrlCommit 0; + _ctrlBcgCommon ctrlSetPosition [ + _ctrlBcgCommonPos select 0, + _ctrlBcgCommonPos select 1, + _ctrlBcgCommonPos select 2, + _ctrlTextPosH + _marginY * 2 + ]; + _ctrlBcgCommon ctrlCommit 0; -private _bottomPosY = (_ctrlBcgCommonPos select 1) + _ctrlTextPosH + (_marginY * 2) + _bottomSpaceY; + _ctrlText ctrlSetPosition [ + (_ctrlBcgCommonPos select 0) + _marginX, + (_ctrlBcgCommonPos select 1) + _marginY, + (_ctrlBcgCommonPos select 2) - _marginX * 2, + _ctrlTextPosH + ]; + _ctrlText ctrlCommit 0; -{ - private _xPos = ctrlPosition _x; + private _bottomPosY = (_ctrlBcgCommonPos select 1) + _ctrlTextPosH + (_marginY * 2) + _bottomSpaceY; - _xPos set [1, _bottomPosY]; - _x ctrlSetPosition _xPos; - _x ctrlCommit 0; -} forEach [ - _ctrlBackgroundButtonOK, - _ctrlBackgroundButtonMiddle, - _ctrlBackgroundButtonCancel, - _ctrlButtonOK, - _ctrlButtonCancel -]; + { + private _xPos = ctrlPosition _x; -private _ctrlRscMessageBoxPos = ctrlPosition _ctrlRscMessageBox; -private _ctrlRscMessageBoxPosH = _bottomPosY + (_ctrlButtonOKPos select 3); + _xPos set [1, _bottomPosY]; + _x ctrlSetPosition _xPos; + _x ctrlCommit 0; + } forEach [ + _ctrlBackgroundButtonOK, + _ctrlBackgroundButtonMiddle, + _ctrlBackgroundButtonCancel, + _ctrlButtonOK, + _ctrlButtonCancel + ]; -_ctrlRscMessageBox ctrlSetPosition [ - 0.5 - (_ctrlBcgCommonPos select 2) / 2, - 0.5 - _ctrlRscMessageBoxPosH / 2, - (_ctrlBcgCommonPos select 2) + 0.5, - _ctrlRscMessageBoxPosH -]; + private _ctrlRscMessageBoxPos = ctrlPosition _ctrlRscMessageBox; + private _ctrlRscMessageBoxPosH = _bottomPosY + (_ctrlButtonOKPos select 3); -_ctrlRscMessageBox ctrlEnable true; -_ctrlRscMessageBox ctrlCommit 0; + _ctrlRscMessageBox ctrlSetPosition [ + 0.5 - (_ctrlBcgCommonPos select 2) / 2, + 0.5 - _ctrlRscMessageBoxPosH / 2, + (_ctrlBcgCommonPos select 2) + 0.5, + _ctrlRscMessageBoxPosH + ]; -if (_onOK isEqualTo {}) then { - _ctrlButtonOK ctrlEnable false; - _ctrlButtonOK ctrlSetFade 0; - _ctrlButtonOK ctrlSetText ""; - _ctrlButtonOK ctrlCommit 0; -} else { + _ctrlRscMessageBox ctrlEnable true; + _ctrlRscMessageBox ctrlCommit 0; + + // Enable ok button _ctrlButtonOK ctrlEnable true; _ctrlButtonOK ctrlSetFade 0; _ctrlButtonOK ctrlSetText localize "STR_DISP_OK"; _ctrlButtonOK ctrlCommit 0; ctrlSetFocus _ctrlButtonOK; -}; -if (_onCancel isEqualTo {}) then { + // Disable cancel button _ctrlButtonCancel ctrlEnable false; _ctrlButtonCancel ctrlSetFade 0; _ctrlButtonCancel ctrlSetText ""; _ctrlButtonCancel ctrlCommit 0; -} else { - _ctrlButtonCancel ctrlEnable true; - _ctrlButtonCancel ctrlSetFade 0; - _ctrlButtonCancel ctrlSetText localize "STR_DISP_CANCEL"; - _ctrlButtonCancel ctrlCommit 0; - ctrlSetFocus _ctrlButtonCancel; -}; + _ctrlButtonOK ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay IDC_OK; true}]; -_ctrlButtonOK ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay 1; true}]; -_ctrlButtonCancel ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay 2; true}]; + // Intercept all keystrokes except the enter keys + _display displayAddEventHandler ["KeyDown", {!((_this select 1) in [DIK_RETURN, DIK_NUMPADENTER])}]; -GVAR(errorOnOK) = _onOK; -GVAR(errorOnCancel) = _onCancel; - -_display displayAddEventHandler ["Unload", {call ([{}, GVAR(errorOnOK), GVAR(errorOnCancel)] select (_this select 1))}]; -_display displayAddEventHandler ["KeyDown", {_this select 1 == 1}]; + // Close curator and mission displays (because of the message display, it doesn't quit the mission yet) + findDisplay 312 closeDisplay 0; + findDisplay 46 closeDisplay 0; +}, _this] call CBA_fnc_waitUntilAndExecute; diff --git a/addons/common/scripts/checkVersionNumber.sqf b/addons/common/scripts/checkVersionNumber.sqf deleted file mode 100644 index 3ed51120b6..0000000000 --- a/addons/common/scripts/checkVersionNumber.sqf +++ /dev/null @@ -1,160 +0,0 @@ -// by commy2 -#include "..\script_component.hpp" - -private _aceWhitelist = missionNamespace getVariable ["ACE_Version_Whitelist", []]; -private _files = CBA_common_addons select { - (_x select [0,3] != "a3_") && - {_x select [0,4] != "ace_"} && - {!((toLowerANSI _x) in _aceWhitelist)} -}; - -private _versions = []; -{ - getText (configFile >> "CfgPatches" >> _x >> "version") splitString "." params [["_major", "0"], ["_minor", "0"]]; - private _version = parseNumber _major + parseNumber _minor/100; - _versions set [_forEachIndex, _version]; -} forEach _files; - -if (isServer) then { - ACE_Version_ServerVersions = [_files, _versions]; - publicVariable "ACE_Version_ServerVersions"; -} else { - ACE_Version_ClientVersions = [_files, _versions]; -}; - -// Begin client version check -if (!isServer) then { - // Wait for server to send the servers files and version numbers - waitUntil { - sleep 1; - !isNil "ACE_Version_ClientVersions" && {!isNil "ACE_Version_ServerVersions"} - }; - - private _client = profileName; - - _files = ACE_Version_ClientVersions select 0; - _versions = ACE_Version_ClientVersions select 1; - - private _serverFiles = ACE_Version_ServerVersions select 0; - private _serverVersions = ACE_Version_ServerVersions select 1; - - // Compare client and server files and versions - private _missingAddons = []; - private _oldVersionsClient = []; - private _oldVersionsServer = []; - { - private _serverVersion = _serverVersions select _forEachIndex; - - private _index = _files find _x; - if (_index == -1) then { - if (_x != "ace_server") then {_missingAddons pushBack _x;}; - } else { - - private _clientVersion = _versions select _index; - - if (_clientVersion < _serverVersion) then { - _oldVersionsClient pushBack [_x, _clientVersion, _serverVersion]; - }; - - if (_clientVersion > _serverVersion) then { - _oldVersionsServer pushBack [_x, _clientVersion, _serverVersion]; - }; - }; - } forEach _serverFiles; - - // find client files which the server doesn't have - private _missingAddonsServer = []; - { - private _index = _serverFiles find _x; - if (_index == -1) then { - _missingAddonsServer pushBack _x; - } - } forEach _files; - - // display and log error messages - private _fnc_cutComma = { - private _string = _this; - _string = toArray _string; - - private _count = count _string; - _string set [_count - 2, toArray "." select 0]; - _string set [_count - 1, -1]; - _string = _string - [-1]; - - toString _string; - }; - - private _missingAddon = false; - if (count _missingAddons > 0) then { - _missingAddon = true; - - private _error = format ["[ACE] %1: ERROR client missing addon(s): ", _client]; - { - _error = _error + format ["%1, ", _x]; - - if (_forEachIndex > 9) exitWith {}; - } forEach _missingAddons; - - _error = _error call _fnc_cutComma; - - diag_log text _error; - [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; - [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; - }; - - private _missingAddonServer = false; - if (count _missingAddonsServer > 0) then { - _missingAddonServer = true; - - private _error = format ["[ACE] %1: ERROR server missing addon(s): ", _client]; - { - _error = _error + format ["%1, ", _x]; - - if (_forEachIndex > 9) exitWith {}; - } forEach _missingAddonsServer; - - _error = _error call _fnc_cutComma; - - diag_log text _error; - [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; - [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; - }; - - private _oldVersionClient = false; - if (count _oldVersionsClient > 0) then { - _oldVersionClient = true; - - private _error = format ["[ACE] %1: ERROR outdated client addon(s): ", _client]; - { - _error = _error + format ["%1 (client: %2, server: %3), ", _x select 0, _x select 1, _x select 2]; - - if (_forEachIndex > 9) exitWith {}; - } forEach _oldVersionsClient; - - _error = _error call _fnc_cutComma; - - diag_log text _error; - [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; - [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; - }; - - private _oldVersionServer = false; - if (count _oldVersionsServer > 0) then { - _oldVersionServer = true; - - private _error = format ["[ACE] %1: ERROR outdated server addon(s): ", _client]; - { - _error = _error + format ["%1 (client: %2, server: %3), ", _x select 0, _x select 1, _x select 2]; - - if (_forEachIndex > 9) exitWith {}; - } forEach _oldVersionsServer; - - _error = _error call _fnc_cutComma; - - diag_log text _error; - [QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent; - [QGVAR(serverLog), _error] call CBA_fnc_serverEvent; - }; - - ACE_Version_ClientErrors = [_missingAddon, _missingAddonServer, _oldVersionClient, _oldVersionServer]; -}; diff --git a/docs/wiki/framework/events-framework.md b/docs/wiki/framework/events-framework.md index 860cd90068..5155cf7593 100644 --- a/docs/wiki/framework/events-framework.md +++ b/docs/wiki/framework/events-framework.md @@ -30,6 +30,8 @@ The vehicle events will also have the following local variables available `_gunn |`ace_firedPlayerVehicle` | [_vehicle, _weapon, _muzzle, _mode, _ammo, _magazine, _projectile] | Local | Listen | ACE_player turret fires | |`ace_firedPlayerVehicleNonLocal` | [_vehicle, _weapon, _muzzle, _mode, _ammo, _magazine, _projectile] | Local | Listen | Any other player turret fires | |`ace_firedNonPlayerVehicle` | [_vehicle, _weapon, _muzzle, _mode, _ammo, _magazine, _projectile] | Local | Listen | AI turret fires | +|`ace_versioning_clientCheckDone` | [[_missingAddonsClient, _additionalAddonsClient, _olderVersionsClient, _newerVersionsClient]] | Local | Listen | When PBO checking has finished on a client | +|`ace_versioning_serverCheckDone` | [[_serverFiles, _serverVersions]] | Local | Listen | When PBO checking has finished on the server | ### 2.2 Medical (`ace_medical`) From 18ea360b1ea2403443da7f4cf00e55389cb0b34d Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 22 Jun 2024 17:18:28 +0200 Subject: [PATCH 108/290] Cargo - Add check for invoking `ace_cargoAdded` EH only if cargo was actually added (#10084) Only invoke cargoAdded EH if cargo was actually added --- addons/cargo/functions/fnc_addCargoItem.sqf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/cargo/functions/fnc_addCargoItem.sqf b/addons/cargo/functions/fnc_addCargoItem.sqf index de262bdcfb..d5c7925a6f 100644 --- a/addons/cargo/functions/fnc_addCargoItem.sqf +++ b/addons/cargo/functions/fnc_addCargoItem.sqf @@ -41,6 +41,8 @@ if (_item isEqualType "") then { TRACE_1("loaded",_loaded); // Invoke listenable event -["ace_cargoAdded", [_item, _vehicle, _loaded]] call CBA_fnc_globalEvent; +if (_loaded > 0) then { + ["ace_cargoAdded", [_item, _vehicle, _loaded]] call CBA_fnc_globalEvent; +}; _loaded // return From 1f5044aabdb7f1521c3a239a1284e6913e8a8405 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 22 Jun 2024 19:03:32 +0200 Subject: [PATCH 109/290] CSW - Improved weapon attachments handling (#9904) --- .../functions/fnc_assemble_deployTripod.sqf | 50 +++++++++++----- .../functions/fnc_assemble_deployWeapon.sqf | 58 +++++++++++++++---- .../fnc_staticWeaponInit_unloadExtraMags.sqf | 40 ++++++++++--- 3 files changed, 114 insertions(+), 34 deletions(-) diff --git a/addons/csw/functions/fnc_assemble_deployTripod.sqf b/addons/csw/functions/fnc_assemble_deployTripod.sqf index da2ed56c04..29cc4b5876 100644 --- a/addons/csw/functions/fnc_assemble_deployTripod.sqf +++ b/addons/csw/functions/fnc_assemble_deployTripod.sqf @@ -19,16 +19,20 @@ params ["_player"]; TRACE_1("assemble_deployTripod",_player); + // Save magazines and attachments (handle loaded launchers which can become csw like CUP Metis) + private _secondaryWeaponInfo = (getUnitLoadout _player) select 1; + private _secondaryWeaponClassname = _secondaryWeaponInfo deleteAt 0; + + // Remove empty entries + _secondaryWeaponInfo = _secondaryWeaponInfo select {_x isNotEqualTo "" && {_x isNotEqualTo []}}; + // Remove the tripod from the launcher slot - private _secondaryWeaponClassname = secondaryWeapon _player; - // handle loaded launchers which can become csw like CUP Metis - private _secondaryWeaponMagazine = secondaryWeaponMagazine _player param [0, ""]; _player removeWeaponGlobal _secondaryWeaponClassname; private _onFinish = { params ["_args"]; - _args params ["_player", "_secondaryWeaponClassname", "_secondaryWeaponMagazine"]; - TRACE_3("deployTripod finish",_player,_secondaryWeaponClassname,_secondaryWeaponMagazine); + _args params ["_player", "_secondaryWeaponClassname", "_secondaryWeaponInfo"]; + TRACE_3("deployTripod finish",_player,_secondaryWeaponClassname,_secondaryWeaponInfo); private _tripodClassname = getText(configFile >> "CfgWeapons" >> _secondaryWeaponClassname >> QUOTE(ADDON) >> "deploy"); @@ -36,9 +40,24 @@ private _cswTripod = createVehicle [_tripodClassname, [0, 0, 0], [], 0, "NONE"]; // Because the tripod can be a "full weapon" we disable any data that will allow it to be loaded _cswTripod setVariable [QGVAR(assemblyMode), 2, true]; // Explicitly set enabled&unload assembly mode and broadcast - if (_secondaryWeaponMagazine isNotEqualTo "") then { - _cswTripod setVariable [QGVAR(secondaryWeaponMagazine), _secondaryWeaponMagazine]; + + private _secondaryWeaponMagazines = []; + + { + // Magazines + if (_x isEqualType []) then { + _secondaryWeaponMagazines pushBack _x; + } else { + // Items + [_player, _x, true] call CBA_fnc_addItem; + }; + } forEach _secondaryWeaponInfo; + + // Only add magazines once the weapon is fully ready + if (_secondaryWeaponMagazines isNotEqualTo []) then { + _cswTripod setVariable [QGVAR(secondaryWeaponMagazines), _secondaryWeaponMagazines, true]; }; + if (!GVAR(defaultAssemblyMode)) then { [_cswTripod, "disableWeaponAssembly", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); }; @@ -65,15 +84,18 @@ private _onFailure = { params ["_args"]; - _args params ["_player", "_secondaryWeaponClassname", "_secondaryWeaponMagazine"]; - TRACE_3("deployTripod failure",_player,_secondaryWeaponClassname,_secondaryWeaponMagazine); + _args params ["_player", "_secondaryWeaponClassname", "_secondaryWeaponInfo"]; + TRACE_3("deployTripod failure",_player,_secondaryWeaponClassname,_secondaryWeaponInfo); - _player addWeaponGlobal _secondaryWeaponClassname; - if (_secondaryWeaponMagazine isNotEqualTo "") then { - _player addWeaponItem [_secondaryWeaponClassname, _secondaryWeaponMagazine, true]; - }; + // Add tripod back + [_player, _secondaryWeaponClassname] call CBA_fnc_addWeaponWithoutItems; + + // Add all attachments back + { + _player addWeaponItem [_secondaryWeaponClassname, _x, true]; + } forEach _secondaryWeaponInfo; }; private _deployTime = getNumber(configFile >> "CfgWeapons" >> _secondaryWeaponClassname >> QUOTE(ADDON) >> "deployTime"); - [TIME_PROGRESSBAR(_deployTime), [_player, _secondaryWeaponClassname, _secondaryWeaponMagazine], _onFinish, _onFailure, LLSTRING(PlaceTripod_progressBar)] call EFUNC(common,progressBar); + [TIME_PROGRESSBAR(_deployTime), [_player, _secondaryWeaponClassname, _secondaryWeaponInfo], _onFinish, _onFailure, LLSTRING(PlaceTripod_progressBar)] call EFUNC(common,progressBar); }, _this] call CBA_fnc_execNextFrame; diff --git a/addons/csw/functions/fnc_assemble_deployWeapon.sqf b/addons/csw/functions/fnc_assemble_deployWeapon.sqf index b9f8029bc2..ca45d64615 100644 --- a/addons/csw/functions/fnc_assemble_deployWeapon.sqf +++ b/addons/csw/functions/fnc_assemble_deployWeapon.sqf @@ -4,39 +4,51 @@ * Deploys the current CSW * * Arguments: - * 0: Unit + * 0: Target + * 1: Unit + * 2: Args + * 3: Action Data * * Return Value: * None * * Example: - * [player] call ace_csw_fnc_assemble_deployWeapon + * [cursorObject, player] call ace_csw_fnc_assemble_deployWeapon * * Public: No */ [{ - params ["_tripod", "_player", "", "_carryWeaponClassname"]; - if (isNil "_carryWeaponClassname") then { _carryWeaponClassname = secondaryWeapon _player }; + params ["_tripod", "_player"]; + + // Save magazines and attachments (handle loaded launchers which can become csw like CUP Metis) + private _carryWeaponInfo = (getUnitLoadout _player) select 1; + private _carryWeaponClassname = _carryWeaponInfo deleteAt 0; + + // Remove empty entries + _carryWeaponInfo = _carryWeaponInfo select {_x isNotEqualTo "" && {_x isNotEqualTo []}}; + TRACE_3("assemble_deployWeapon_carryWeaponClassname",_tripod,_player,_carryWeaponClassname); private _tripodClassname = typeOf _tripod; - _player removeWeaponGlobal _carryWeaponClassname; - private _weaponConfig = configfile >> "CfgWeapons" >> _carryWeaponClassname >> QUOTE(ADDON); private _assembledClassname = getText (_weaponConfig >> "assembleTo" >> _tripodClassname); if (!isClass (configFile >> "CfgVehicles" >> _assembledClassname)) exitWith {ERROR_1("bad static classname [%1]",_assembledClassname);}; + _player removeWeaponGlobal _carryWeaponClassname; + private _deployTime = getNumber (_weaponConfig >> "deployTime"); TRACE_4("",_carryWeaponClassname,_tripodClassname,_assembledClassname,_deployTime); private _onFinish = { params ["_args"]; - _args params ["_tripod", "_player", "_assembledClassname"]; + _args params ["_tripod", "_player", "_assembledClassname", "", "_carryWeaponInfo"]; TRACE_3("deployWeapon finish",_tripod,_player,_assembledClassname); + private _secondaryWeaponMagazines = _tripod getVariable [QGVAR(secondaryWeaponMagazines), []]; + private _tripodPos = getPosATL _tripod; private _tripodDir = getDir _tripod; deleteVehicle _tripod; @@ -44,10 +56,26 @@ _tripodPos set [2, (_tripodPos select 2) + 0.1]; // Delay a frame so tripod has a chance to be deleted [{ - params ["_assembledClassname", "_tripodDir", "_tripodPos"]; + params ["_assembledClassname", "_tripodDir", "_tripodPos", "_player", "_carryWeaponInfo", "_secondaryWeaponMagazines"]; private _csw = createVehicle [_assembledClassname, [0, 0, 0], [], 0, "NONE"]; // Assembly mode: [0=disabled, 1=enabled, 2=enabled&unload, 3=default] _csw setVariable [QGVAR(assemblyMode), 2, true]; // Explicitly set advanced assembly mode + unload, and broadcast + + { + // Magazines + if (_x isEqualType []) then { + _secondaryWeaponMagazines pushBack _x; + } else { + // Items + [_player, _x, true] call CBA_fnc_addItem; + }; + } forEach _carryWeaponInfo; + + // Only add magazines once the weapon is fully ready + if (_secondaryWeaponMagazines isNotEqualTo []) then { + _csw setVariable [QGVAR(secondaryWeaponMagazines), _secondaryWeaponMagazines, true]; + }; + if (!GVAR(defaultAssemblyMode)) then { [_csw, "disableWeaponAssembly", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); }; @@ -58,15 +86,21 @@ }; [QGVAR(deployWeaponSucceeded), [_csw]] call CBA_fnc_localEvent; TRACE_2("csw placed",_csw,_assembledClassname); - }, [_assembledClassname, _tripodDir, _tripodPos]] call CBA_fnc_execNextFrame; + }, [_assembledClassname, _tripodDir, _tripodPos, _player, _carryWeaponInfo, _secondaryWeaponMagazines]] call CBA_fnc_execNextFrame; }; private _onFailure = { params ["_args"]; - _args params ["", "_player", "", "_carryWeaponClassname"]; + _args params ["", "_player", "", "_carryWeaponClassname", "_carryWeaponInfo"]; TRACE_2("deployWeapon failure",_player,_carryWeaponClassname); - _player addWeaponGlobal _carryWeaponClassname; + // Add weapon back + [_player, _carryWeaponClassname] call CBA_fnc_addWeaponWithoutItems; + + // Add all attachments back + { + _player addWeaponItem [_carryWeaponClassname, _x, true]; + } forEach _carryWeaponInfo; }; private _codeCheck = { @@ -76,5 +110,5 @@ alive _tripod }; - [TIME_PROGRESSBAR(_deployTime), [_tripod, _player, _assembledClassname, _carryWeaponClassname], _onFinish, _onFailure, LLSTRING(AssembleCSW_progressBar), _codeCheck] call EFUNC(common,progressBar); + [TIME_PROGRESSBAR(_deployTime), [_tripod, _player, _assembledClassname, _carryWeaponClassname, _carryWeaponInfo], _onFinish, _onFailure, LLSTRING(AssembleCSW_progressBar), _codeCheck] call EFUNC(common,progressBar); }, _this] call CBA_fnc_execNextFrame; diff --git a/addons/csw/functions/fnc_staticWeaponInit_unloadExtraMags.sqf b/addons/csw/functions/fnc_staticWeaponInit_unloadExtraMags.sqf index 23155ead0b..98200840a3 100644 --- a/addons/csw/functions/fnc_staticWeaponInit_unloadExtraMags.sqf +++ b/addons/csw/functions/fnc_staticWeaponInit_unloadExtraMags.sqf @@ -68,14 +68,38 @@ TRACE_1("Remove all loaded magazines",_magsToRemove); }; } forEach _magsToRemove; -if (_staticWeapon getVariable [QGVAR(secondaryWeaponMagazine), ""] isNotEqualTo "") then { - private _secondaryWeaponMagazine = _staticWeapon getVariable QGVAR(secondaryWeaponMagazine); - private _turret = allTurrets _staticWeapon param [0, []]; - private _vehicleMag = [_staticWeapon, _turret, _secondaryWeaponMagazine] call FUNC(reload_getVehicleMagazine); - TRACE_3("Re-add previous mag",_secondaryWeaponMagazine,_turret,_vehicleMag); - if (!isClass (configFile >> "CfgMagazines" >> _vehicleMag)) exitWith {}; - _staticWeapon addMagazineTurret [_vehicleMag, _turret, 1]; - _staticWeapon setVariable [QGVAR(secondaryWeaponMagazine), nil]; +private _secondaryWeaponMagazines = _staticWeapon getVariable [QGVAR(secondaryWeaponMagazines), []]; + +if (_secondaryWeaponMagazines isNotEqualTo []) then { + // Check if the static weapon can take magazines + private _turret = (allTurrets _staticWeapon) param [0, []]; + private _compatibleMagazinesTurret = flatten ((_staticWeapon weaponsTurret _turret) apply {compatibleMagazines _x}); + private _container = objNull; + + { + private _vehicleMag = [_staticWeapon, _turret, _x select 0] call FUNC(reload_getVehicleMagazine); + TRACE_3("Re-add previous mag",_x select 0,_turret,_vehicleMag); + + // If the magazine can be added to the static weapon, do it now + if (_vehicleMag in _compatibleMagazinesTurret) then { + _staticWeapon addMagazineTurret [_vehicleMag, _turret, _x select 1]; + } else { + // Find a suitable container to place items in if necessary + if (isNull _container) then { + _container = (nearestObjects [_staticWeapon, ["GroundWeaponHolder"], 10]) param [0, objNull]; + + // Create ammo storage container + if (isNull _container) then { + _container = createVehicle ["GroundWeaponHolder", getPosATL _staticWeapon, [], 0, "NONE"]; + }; + }; + + // If the mag can't be added to the static weapon, add it to the ground holder + _container addMagazineAmmoCargo [_x select 0, 1, _x select 1]; + }; + } forEach _secondaryWeaponMagazines; + + _staticWeapon setVariable [QGVAR(secondaryWeaponMagazines), nil, true]; }; if (_storeExtraMagazines) then { From cd66f495adc7fa9f579bcb1d0d9f1666474e5f11 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 22 Jun 2024 19:39:36 +0200 Subject: [PATCH 110/290] CSW - Improve tripod and weapon disassembly (#9915) * Add disassembly for tripods when players have occupied launcher slots * Update fnc_assemble_canDeployWeapon.sqf * Update fnc_assemble_canPickupWeapon.sqf * Revert file renaming (see #9777) * Correct headers * Update fnc_canPickupTripod.sqf * Fixed checks and eject dead bodies * Invert checks --- .../fnc_assemble_canDeployWeapon.sqf | 7 ++- .../fnc_assemble_canPickupWeapon.sqf | 4 +- .../functions/fnc_assemble_deployWeapon.sqf | 4 +- .../functions/fnc_assemble_pickupTripod.sqf | 37 +++++++++++-- .../functions/fnc_assemble_pickupWeapon.sqf | 54 ++++++++++++------- addons/csw/functions/fnc_canPickupTripod.sqf | 6 +-- 6 files changed, 77 insertions(+), 35 deletions(-) diff --git a/addons/csw/functions/fnc_assemble_canDeployWeapon.sqf b/addons/csw/functions/fnc_assemble_canDeployWeapon.sqf index 57f2ce2bc8..65dd81cc41 100644 --- a/addons/csw/functions/fnc_assemble_canDeployWeapon.sqf +++ b/addons/csw/functions/fnc_assemble_canDeployWeapon.sqf @@ -5,7 +5,7 @@ * * Arguments: * 0: Target Tripod - * 0: Player + * 1: Player * * Return Value: * Wether or not you can deploy the weapon @@ -16,9 +16,8 @@ * Public: No */ -params ["_target", "_player", "", "_carryWeaponClassname"]; -if (isNil "_carryWeaponClassname") then { _carryWeaponClassname = secondaryWeapon _player }; +params ["_target", "_player"]; // If the current launcher has a config-value that defines the tripod, it is a CSW (alive _target) && -{(getText(configFile >> "CfgWeapons" >> _carryWeaponClassname >> QUOTE(ADDON) >> "assembleTo" >> (typeOf _target))) != ""} +{(getText (configFile >> "CfgWeapons" >> secondaryWeapon _player >> QUOTE(ADDON) >> "assembleTo" >> typeOf _target)) != ""} diff --git a/addons/csw/functions/fnc_assemble_canPickupWeapon.sqf b/addons/csw/functions/fnc_assemble_canPickupWeapon.sqf index 6217d769dd..0d508bfa89 100644 --- a/addons/csw/functions/fnc_assemble_canPickupWeapon.sqf +++ b/addons/csw/functions/fnc_assemble_canPickupWeapon.sqf @@ -19,7 +19,5 @@ params ["_staticWeapon"]; // Assembly mode: [0=disabled, 1=enabled, 2=enabled&unload, 3=default] private _assemblyMode = [false, true, true, GVAR(defaultAssemblyMode)] select (_staticWeapon getVariable [QGVAR(assemblyMode), 3]); -private _notCrewed = (crew _staticWeapon) isEqualTo []; -private _deadCrew = !(alive (gunner _staticWeapon)); // need to eject body??? -_assemblyMode && {alive _staticWeapon} && {_notCrewed || _deadCrew} +_assemblyMode && {alive _staticWeapon} && {((crew _staticWeapon) findIf {alive _x && {!unitIsUAV _x}}) == -1} // return diff --git a/addons/csw/functions/fnc_assemble_deployWeapon.sqf b/addons/csw/functions/fnc_assemble_deployWeapon.sqf index ca45d64615..974bf03431 100644 --- a/addons/csw/functions/fnc_assemble_deployWeapon.sqf +++ b/addons/csw/functions/fnc_assemble_deployWeapon.sqf @@ -103,12 +103,12 @@ } forEach _carryWeaponInfo; }; - private _codeCheck = { + private _condition = { params ["_args"]; _args params ["_tripod"]; alive _tripod }; - [TIME_PROGRESSBAR(_deployTime), [_tripod, _player, _assembledClassname, _carryWeaponClassname, _carryWeaponInfo], _onFinish, _onFailure, LLSTRING(AssembleCSW_progressBar), _codeCheck] call EFUNC(common,progressBar); + [TIME_PROGRESSBAR(_deployTime), [_tripod, _player, _assembledClassname, _carryWeaponClassname, _carryWeaponInfo], _onFinish, _onFailure, LLSTRING(AssembleCSW_progressBar), _condition] call EFUNC(common,progressBar); }, _this] call CBA_fnc_execNextFrame; diff --git a/addons/csw/functions/fnc_assemble_pickupTripod.sqf b/addons/csw/functions/fnc_assemble_pickupTripod.sqf index 176718f015..0996c0f3d3 100644 --- a/addons/csw/functions/fnc_assemble_pickupTripod.sqf +++ b/addons/csw/functions/fnc_assemble_pickupTripod.sqf @@ -11,7 +11,7 @@ * None * * Example: - * [tripod, player] call ace_csw_fnc_assemble_pickupTripod + * [cursorObject, player] call ace_csw_fnc_assemble_pickupTripod * * Public: No */ @@ -28,16 +28,45 @@ _args params ["_tripod", "_player", "_tripodClassname"]; TRACE_3("assemble_pickupTripod finish",_tripod,_player,_tripodClassname); + // Save tripod position before it's deleted + private _tripodPos = getPosATL _tripod; + + // Eject dead units (all crew are dead at this point, otherwise condition would have failed), but ignore UAV units + { + if (unitIsUAV _x) then { + _tripod deleteVehicleCrew _x; + } else { + moveOut _x; + }; + } forEach (crew _tripod); + deleteVehicle _tripod; - _player addWeaponGlobal _tripodClassname; + [_player, "PutDown"] call EFUNC(common,doGesture); + + // If the player has space, give it to him + if ((alive _player) && {(secondaryWeapon _player) == ""}) exitWith { + [_player, _tripodClassname] call CBA_fnc_addWeaponWithoutItems; + }; + + // Try to find existing weapon holders + private _weaponHolder = nearestObject [_tripodPos, "WeaponHolder"]; + + // If there are none or too far away, make a new one + if (isNull _weaponHolder || {_tripodPos distance _weaponHolder > 2}) then { + _weaponHolder = createVehicle ["GroundWeaponHolder", [0, 0, 0], [], 0, "CAN_COLLIDE"]; + _weaponHolder setDir random [0, 180, 360]; + _weaponHolder setVehiclePosition [_tripodPos, [], 0, "CAN_COLLIDE"]; // places object on surface below + }; + + _weaponHolder addWeaponCargoGlobal [_tripodClassname, 1]; }; private _condition = { params ["_args"]; - _args params ["_tripod", "_player"]; + _args params ["_tripod"]; - (alive _tripod) && {secondaryWeapon _player == ""} + _tripod call FUNC(canPickupTripod) }; TRACE_3("",_pickupTime,typeOf _tripod,_tripodClassname); diff --git a/addons/csw/functions/fnc_assemble_pickupWeapon.sqf b/addons/csw/functions/fnc_assemble_pickupWeapon.sqf index 3034e2260c..468f385efa 100644 --- a/addons/csw/functions/fnc_assemble_pickupWeapon.sqf +++ b/addons/csw/functions/fnc_assemble_pickupWeapon.sqf @@ -5,12 +5,13 @@ * * Arguments: * 0: Static Weapon + * 1: Unit * * Return Value: * None * * Example: - * [weapon] call ace_csw_fnc_assemble_pickupWeapon + * [cursorObject, player] call ace_csw_fnc_assemble_pickupWeapon * * Public: No */ @@ -43,11 +44,10 @@ _args params ["_staticWeapon", "_player", "_carryWeaponClassname", "_turretClassname", "_onDisassembleFunc"]; TRACE_4("disassemble finish",_staticWeapon,_player,_carryWeaponClassname,_turretClassname); - private _weaponPos = getPosATL _staticWeapon; - _weaponPos set [2, (_weaponPos select 2) + 0.1]; + private _weaponPos = (getPosATL _staticWeapon) vectorAdd [0, 0, 0.1]; private _weaponDir = getDir _staticWeapon; - private _carryWeaponMag = ""; + private _carryWeaponMag = []; private _carryWeaponMags = compatibleMagazines _carryWeaponClassname; LOG("remove ammo"); { @@ -55,9 +55,9 @@ if (_xAmmo == 0) then {continue}; private _carryMag = _xMag call FUNC(getCarryMagazine); - if (_carryWeaponMag == "" && {_carryMag in _carryWeaponMags}) then { + if (_carryWeaponMag isEqualTo [] && {_carryMag in _carryWeaponMags}) then { TRACE_3("Adding mag to secondary weapon",_xMag,_xAmmo,_carryMag); - _carryWeaponMag = _carryMag; + _carryWeaponMag = [_carryMag, _xAmmo]; DEC(_xAmmo); }; if ((_xAmmo > 0) && {_carryMag != ""}) then { @@ -80,25 +80,40 @@ }; [{ - params ["_player", "_weaponPos", "_carryWeaponClassname", "_carryWeaponMag"]; + params ["_player", "_weaponPos", "_carryWeaponClassname", "_carryWeaponMag", "_turretClassname"]; + + // Give the weapon to the player if possible if ((alive _player) && {(secondaryWeapon _player) == ""}) exitWith { - _player addWeapon _carryWeaponClassname; - if (_carryWeaponMag isNotEqualTo "") then { + [_player, _carryWeaponClassname] call CBA_fnc_addWeaponWithoutItems; + + if (_carryWeaponMag isNotEqualTo []) then { _player addWeaponItem [_carryWeaponClassname, _carryWeaponMag, true]; }; }; - private _weaponRelPos = _weaponPos getPos RELATIVE_DIRECTION(90); - private _weaponHolder = createVehicle ["groundWeaponHolder", [0, 0, 0], [], 0, "NONE"]; - _weaponHolder setDir random [0, 180, 360]; - _weaponHolder setPosATL [_weaponRelPos select 0, _weaponRelPos select 1, _weaponPos select 2]; - if (_carryWeaponMag isEqualTo "") then { - _weaponHolder addWeaponCargoGlobal [_carryWeaponClassname, 1]; - } else { - _weaponHolder addWeaponWithAttachmentsCargoGlobal [[_carryWeaponClassname, "", "", "", [_carryWeaponMag, 1], [], ""], 1]; + + // If there is no turret, place the ground holder where the turret was + if (_turretClassname != "") then { + _weaponPos = _weaponPos getPos RELATIVE_DIRECTION(90); }; - }, [_player, _weaponPos, _carryWeaponClassname, _carryWeaponMag]] call CBA_fnc_execNextFrame; + + // Create a new weapon holder (don't try to get an existing one, as no guarantee where it could be) + private _weaponHolder = createVehicle ["GroundWeaponHolder", [0, 0, 0], [], 0, "CAN_COLLIDE"]; + _weaponHolder setDir random [0, 180, 360]; + _weaponHolder setVehiclePosition [_weaponPos, [], 0, "CAN_COLLIDE"]; // places object on surface below + _weaponHolder addWeaponWithAttachmentsCargoGlobal [[_carryWeaponClassname, "", "", "", _carryWeaponMag, [], ""], 1]; + }, [_player, _weaponPos, _carryWeaponClassname, _carryWeaponMag, _turretClassname]] call CBA_fnc_execNextFrame; LOG("delete weapon"); + + // Eject dead units (all crew are dead or UAV at this point, otherwise condition would have failed), but ignore UAV units + { + if (unitIsUAV _x) then { + _staticWeapon deleteVehicleCrew _x; + } else { + moveOut _x; + }; + } forEach (crew _staticWeapon); + deleteVehicle _staticWeapon; LOG("end"); @@ -107,7 +122,8 @@ private _condition = { params ["_args"]; _args params ["_staticWeapon"]; - ((crew _staticWeapon) isEqualTo []) && (alive _staticWeapon) + + _staticWeapon call FUNC(assemble_canPickupWeapon) }; [TIME_PROGRESSBAR(_pickupTime), [_staticWeapon, _player, _carryWeaponClassname, _turretClassname, _onDisassembleFunc], _onFinish, {}, LLSTRING(DisassembleCSW_progressBar), _condition] call EFUNC(common,progressBar); diff --git a/addons/csw/functions/fnc_canPickupTripod.sqf b/addons/csw/functions/fnc_canPickupTripod.sqf index 0a9f0f5f90..2ec3b065da 100644 --- a/addons/csw/functions/fnc_canPickupTripod.sqf +++ b/addons/csw/functions/fnc_canPickupTripod.sqf @@ -5,7 +5,7 @@ * * Arguments: * 0: Tripod - * 1: Unit + * 1: Unit (not used) * * Return Value: * Can pickup @@ -16,6 +16,6 @@ * Public: No */ -params ["_tripod", "_unit"]; +params ["_tripod"]; -((secondaryWeapon _unit) == "") && {alive _tripod} // return +alive _tripod && {((crew _tripod) findIf {alive _x && {!unitIsUAV _x}}) == -1} // return From f86e882b18e5aa5aeab4fece7468247180678474 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 22 Jun 2024 19:53:08 +0200 Subject: [PATCH 111/290] Advanced Fatigue - Various improvements (continuation of #5723) (#9714) Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> Co-authored-by: ulteq Co-authored-by: LinkIsGrim --- addons/advanced_fatigue/XEH_PREP.hpp | 1 + addons/advanced_fatigue/XEH_postInit.sqf | 18 +-- .../functions/fnc_getAnimDuty.sqf | 2 +- .../functions/fnc_getMetabolicCosts.sqf | 78 +++++++---- .../functions/fnc_handleEffects.sqf | 50 +++---- .../functions/fnc_handlePlayerChanged.sqf | 30 +++-- .../functions/fnc_mainLoop.sqf | 124 +++++++++++++----- .../functions/fnc_renderDebugLines.sqf | 40 ++++++ addons/advanced_fatigue/initSettings.inc.sqf | 32 +++-- addons/advanced_fatigue/script_component.hpp | 26 +++- .../framework/advanced-fatigue-framework.md | 14 +- 11 files changed, 290 insertions(+), 125 deletions(-) create mode 100644 addons/advanced_fatigue/functions/fnc_renderDebugLines.sqf diff --git a/addons/advanced_fatigue/XEH_PREP.hpp b/addons/advanced_fatigue/XEH_PREP.hpp index 4ee00e3ce4..22bb99617a 100644 --- a/addons/advanced_fatigue/XEH_PREP.hpp +++ b/addons/advanced_fatigue/XEH_PREP.hpp @@ -9,3 +9,4 @@ PREP(handleStaminaBar); PREP(mainLoop); PREP(moduleSettings); PREP(removeDutyFactor); +PREP(renderDebugLines); diff --git a/addons/advanced_fatigue/XEH_postInit.sqf b/addons/advanced_fatigue/XEH_postInit.sqf index 08fd827d58..519d218b8c 100644 --- a/addons/advanced_fatigue/XEH_postInit.sqf +++ b/addons/advanced_fatigue/XEH_postInit.sqf @@ -2,6 +2,10 @@ if (!hasInterface) exitWith {}; +#ifdef DEBUG_MODE_FULL +call FUNC(renderDebugLines); +#endif + // recheck weapon inertia after weapon swap, change of attachments or switching unit ["weapon", {[ACE_player] call FUNC(getWeaponInertia)}, true] call CBA_fnc_addPlayerEventHandler; ["loadout", {[ACE_player] call FUNC(getWeaponInertia)}, true] call CBA_fnc_addPlayerEventHandler; @@ -33,25 +37,23 @@ if (!hasInterface) exitWith {}; GVAR(ppeBlackout) ppEffectCommit 0.4; // - GVAR updating and initialization ----------------------------------------- - ["unit", LINKFUNC(handlePlayerChanged), true] call CBA_fnc_addPlayerEventHandler; + ["unit", LINKFUNC(handlePlayerChanged)] call CBA_fnc_addPlayerEventHandler; ["visibleMap", { params ["", "_visibleMap"]; // command visibleMap is updated one frame later - private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull]; - _staminaBarContainer ctrlShow ((!_visibleMap) && {(vehicle ACE_player) == ACE_player}); + (uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull]) ctrlShow (!_visibleMap && isNull objectParent ACE_player); }, true] call CBA_fnc_addPlayerEventHandler; ["vehicle", { - private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull]; - _staminaBarContainer ctrlShow ((!visibleMap) && {(vehicle ACE_player) == ACE_player}); + (uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull]) ctrlShow (!visibleMap && isNull objectParent ACE_player); }, true] call CBA_fnc_addPlayerEventHandler; // - Duty factors ------------------------------------------------------------- if (GETEGVAR(medical,enabled,false)) then { [QEGVAR(medical,pain), { // 0->1.0, 0.5->1.05, 1->1.1 - linearConversion [0, 1, (_this getVariable [QEGVAR(medical,pain), 0]), 1, 1.1, true]; + linearConversion [0, 1, _this getVariable [QEGVAR(medical,pain), 0], 1, 1.1, true]; }] call FUNC(addDutyFactor); [QEGVAR(medical,bloodVolume), { // 6->1.0, 5->1.167, 4->1.33 - linearConversion [6, 0, (_this getVariable [QEGVAR(medical,bloodVolume), 6]), 1, 2, true]; + linearConversion [6, 0, _this getVariable [QEGVAR(medical,bloodVolume), 6], 1, 2, true]; }] call FUNC(addDutyFactor); }; if (["ace_dragging"] call EFUNC(common,isModLoaded)) then { @@ -62,7 +64,7 @@ if (!hasInterface) exitWith {}; // Weather has an off switch, Dragging & Medical don't. if (missionNamespace getVariable [QEGVAR(weather,enabled), false]) then { [QEGVAR(weather,temperature), { // 35->1, 45->2 - linearConversion [35, 45, (missionNamespace getVariable [QEGVAR(weather,currentTemperature), 25]), 1, 2, true]; + linearConversion [35, 45, missionNamespace getVariable [QEGVAR(weather,currentTemperature), 25], 1, 2, true]; }] call FUNC(addDutyFactor); }; diff --git a/addons/advanced_fatigue/functions/fnc_getAnimDuty.sqf b/addons/advanced_fatigue/functions/fnc_getAnimDuty.sqf index e992816e9b..50e052d5f8 100644 --- a/addons/advanced_fatigue/functions/fnc_getAnimDuty.sqf +++ b/addons/advanced_fatigue/functions/fnc_getAnimDuty.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: BaerMitUmlaut - * Calculates the duty of the current animation. + * Calculates the duty ('postureWeight') of the current animation. * * Arguments: * 0: Unit diff --git a/addons/advanced_fatigue/functions/fnc_getMetabolicCosts.sqf b/addons/advanced_fatigue/functions/fnc_getMetabolicCosts.sqf index cc07d9e004..36048cee04 100644 --- a/addons/advanced_fatigue/functions/fnc_getMetabolicCosts.sqf +++ b/addons/advanced_fatigue/functions/fnc_getMetabolicCosts.sqf @@ -1,54 +1,74 @@ #include "..\script_component.hpp" /* - * Author: BaerMitUmlaut - * Calculates the current metabolic costs for a unit. + * Author: BaerMitUmlaut, ulteq + * Calculates the current metabolic costs. * Calculation is done according to the Pandolf/Wojtowicz formulas. * * Arguments: - * 0: Unit - * 1: Speed + * 0: Duty of animation + * 1: Mass of unit + * 2: Terrain gradient + * 3: Terrain factor + * 4: Speed * * Return Value: * Metabolic cost * * Example: - * [player, 3.3] call ace_advanced_fatigue_fnc_getMetabolicCosts + * [1, 840, 20, 1, 4] call ace_advanced_fatigue_fnc_getMetabolicCosts * * Public: No */ -params ["_unit", "_velocity"]; -private _gearMass = ((_unit getVariable [QEGVAR(movement,totalLoad), loadAbs _unit]) / 22.046) * GVAR(loadFactor); - -private _terrainAngle = asin (1 - ((surfaceNormal getPosASL _unit) select 2)); -private _terrainGradient = (_terrainAngle / 45 min 1) * 5 * GVAR(terrainGradientFactor); -private _duty = GVAR(animDuty); - -{ - if (_x isEqualType 0) then { - _duty = _duty * _x; - } else { - _duty = _duty * (_unit call _x); - }; -} forEach (values GVAR(dutyList)); - -if (GVAR(isSwimming)) then { - _terrainGradient = 0; -}; +params ["_duty", "_gearMass", "_terrainGradient", "_terrainFactor", "_speed"]; // Metabolic cost for walking and running is different -if (_velocity > 2) then { +if (_speed > 2) then { // Running + #ifdef DEBUG_MODE_FULL + private _baseline = 2.1 * SIM_BODYMASS + 4 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + (SIM_BODYMASS + _gearMass) * 0.9 * (_speed ^ 2); + private _graded = 2.1 * SIM_BODYMASS + 4 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + _terrainFactor * (SIM_BODYMASS + _gearMass) * (0.9 * (_speed ^ 2) + 0.66 * _speed * _terrainGradient); + private _terrainImpact = abs ((_graded / _baseline) - 1); + hintSilent format ["FwdAngle: %1 | SideAngle: %2 \n TerrainFactor: %3 | TerrainGradient: %4 \n TerrainImpact: %5 \n Speed: %6 | CarriedLoad: %7 \n Duty: %8 | Work: %9", + _fwdAngle toFixed 1, + _sideAngle toFixed 1, + _terrainFactor toFixed 2, + _terrainGradient toFixed 1, + _terrainImpact toFixed 2, + _speed toFixed 2, + _gearMass toFixed 1, + _duty toFixed 2, + round (_graded * BIOMECH_EFFICIENCY * _duty) + ]; + #endif + ( - 2.10 * SIM_BODYMASS + 2.1 * SIM_BODYMASS + 4 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) - + (SIM_BODYMASS + _gearMass) * (0.9 * (_velocity ^ 2) + 0.66 * _velocity * _terrainGradient) - ) * 0.23 * _duty + + _terrainFactor * (SIM_BODYMASS + _gearMass) * (0.9 * (_speed ^ 2) + 0.66 * _speed * _terrainGradient) + ) * BIOMECH_EFFICIENCY * _duty } else { // Walking + #ifdef DEBUG_MODE_FULL + private _baseline = 1.05 * SIM_BODYMASS + 2 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + (SIM_BODYMASS + _gearMass) * 1.15 * (_speed ^ 2); + private _graded = 1.05 * SIM_BODYMASS + 2 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + _terrainFactor * (SIM_BODYMASS + _gearMass) * (1.15 * (_speed ^ 2) + 0.66 * _speed * _terrainGradient); + private _terrainImpact = abs ((_graded / _baseline) - 1); + hintSilent format ["FwdAngle: %1 | SideAngle: %2 \n TerrainFactor: %3 | TerrainGradient: %4 \n TerrainImpact: %5 \n Speed: %6 | CarriedLoad: %7 \n Duty: %8 | Work: %9", + _fwdAngle toFixed 1, + _sideAngle toFixed 1, + _terrainFactor toFixed 2, + _terrainGradient toFixed 1, + _terrainImpact toFixed 2, + _speed toFixed 2, + _gearMass toFixed 1, + _duty toFixed 2, + round (_graded * BIOMECH_EFFICIENCY * _duty) + ]; + #endif + ( 1.05 * SIM_BODYMASS + 2 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) - + (SIM_BODYMASS + _gearMass) * (1.15 * (_velocity ^ 2) + 0.66 * _velocity * _terrainGradient) - ) * 0.23 * _duty + + _terrainFactor * (SIM_BODYMASS + _gearMass) * (1.15 * (_speed ^ 2) + 0.66 * _speed * _terrainGradient) + ) * BIOMECH_EFFICIENCY * _duty }; diff --git a/addons/advanced_fatigue/functions/fnc_handleEffects.sqf b/addons/advanced_fatigue/functions/fnc_handleEffects.sqf index 13c1fefc62..d948823354 100644 --- a/addons/advanced_fatigue/functions/fnc_handleEffects.sqf +++ b/addons/advanced_fatigue/functions/fnc_handleEffects.sqf @@ -1,44 +1,44 @@ #include "..\script_component.hpp" /* - * Author: BaerMitUmlaut + * Author: BaerMitUmlaut, ulteq * Handles any audible, visual and physical effects of fatigue. * * Arguments: * 0: Unit * 1: Fatigue - * 2: Speed - * 3: Overexhausted + * 2: Overexhausted + * 3: Forward Angle + * 4: Side Angle * * Return Value: * None * * Example: - * [_player, 0.5, 3.3, true] call ace_advanced_fatigue_fnc_handleEffects + * [_player, 0.5, 3.3, true, 0, 0] call ace_advanced_fatigue_fnc_handleEffects * * Public: No */ -params ["_unit", "_fatigue", "_speed", "_overexhausted"]; -#ifdef DEBUG_MODE_FULL - systemChat str _fatigue; - systemChat str vectorMagnitude velocity _unit; -#endif +params ["_unit", "_fatigue", "_overexhausted", "_fwdAngle", "_sideAngle"]; // - Audible effects ---------------------------------------------------------- GVAR(lastBreath) = GVAR(lastBreath) + 1; + if (_fatigue > 0.4 && {GVAR(lastBreath) > (_fatigue * -10 + 9)} && {!underwater _unit}) then { if (!isGameFocused) exitWith {}; + switch (true) do { case (_fatigue < 0.6): { - playSound (QGVAR(breathLow) + str(floor random 6)); + playSound (QGVAR(breathLow) + str (floor random 6)); }; case (_fatigue < 0.85): { - playSound (QGVAR(breathMid) + str(floor random 6)); + playSound (QGVAR(breathMid) + str (floor random 6)); }; default { - playSound (QGVAR(breathMax) + str(floor random 6)); + playSound (QGVAR(breathMax) + str (floor random 6)); }; }; + GVAR(lastBreath) = 0; }; @@ -62,31 +62,35 @@ if (GVAR(isSwimming)) exitWith { if (GVAR(setAnimExclusions) isEqualTo []) then { _unit setAnimSpeedCoef linearConversion [0.7, 0.9, _fatigue, 1, 0.5, true]; }; - if ((isSprintAllowed _unit) && {_fatigue > 0.7}) then { + + if (isSprintAllowed _unit && _fatigue > 0.7) then { // small checks like these are faster without lazy eval [_unit, "blockSprint", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); } else { - if ((!isSprintAllowed _unit) && {_fatigue < 0.7}) then { + if (!isSprintAllowed _unit && _fatigue < 0.7) then { [_unit, "blockSprint", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); }; }; }; -if ((getAnimSpeedCoef _unit) != 1) then { - if (GVAR(setAnimExclusions) isEqualTo []) then { - TRACE_1("reset",getAnimSpeedCoef _unit); - _unit setAnimSpeedCoef 1; - }; + +// If other components are setting setAnimSpeedCoef, do not change animSpeedCoef +if (getAnimSpeedCoef _unit != 1 && {GVAR(setAnimExclusions) isEqualTo []}) then { + TRACE_1("reset",getAnimSpeedCoef _unit); + _unit setAnimSpeedCoef 1; }; -if (_overexhausted) then { +if (!isForcedWalk _unit && _fatigue >= 1) then { // small checks like these are faster without lazy eval [_unit, "forceWalk", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); + [_unit, "blockSprint", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); } else { - if (isForcedWalk _unit && {_fatigue < 0.7}) then { + if (isForcedWalk _unit && _fatigue < 0.7) then { [_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); + [_unit, "blockSprint", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); } else { - if ((isSprintAllowed _unit) && {_fatigue > 0.7}) then { + // Forward angle is the slope of the terrain, side angle simulates the unevenness/roughness of the terrain + if (isSprintAllowed _unit && {_fatigue > 0.7 || abs _fwdAngle > 20 || abs _sideAngle > 20}) then { [_unit, "blockSprint", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); } else { - if ((!isSprintAllowed _unit) && {_fatigue < 0.6}) then { + if (!isSprintAllowed _unit && _fatigue < 0.6 && abs _fwdAngle < 20 && abs _sideAngle < 20) then { [_unit, "blockSprint", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); }; }; diff --git a/addons/advanced_fatigue/functions/fnc_handlePlayerChanged.sqf b/addons/advanced_fatigue/functions/fnc_handlePlayerChanged.sqf index a119b35862..82c9c90a56 100644 --- a/addons/advanced_fatigue/functions/fnc_handlePlayerChanged.sqf +++ b/addons/advanced_fatigue/functions/fnc_handlePlayerChanged.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* - * Author: BaerMitUmlaut - * Handles switching units (once on init and afterwards via Zeus). + * Author: BaerMitUmlaut, ulteq + * Handles switching units (once on init and afterwards via Zeus). Also handles CBA setting change for performance factor. * * Arguments: * 0: New Unit @@ -15,20 +15,24 @@ * * Public: No */ + params ["_newUnit", "_oldUnit"]; + TRACE_2("unit changed",_newUnit,_oldUnit); -if !(isNull _oldUnit) then { +if (!isNull _oldUnit) then { + TRACE_1("remove old",_oldUnit getVariable QGVAR(animHandler)); + _oldUnit enableStamina true; _oldUnit removeEventHandler ["AnimChanged", _oldUnit getVariable [QGVAR(animHandler), -1]]; _oldUnit setVariable [QGVAR(animHandler), nil]; - TRACE_1("remove old",_oldUnit getVariable QGVAR(animHandler)); _oldUnit setVariable [QGVAR(ae1Reserve), GVAR(ae1Reserve)]; _oldUnit setVariable [QGVAR(ae2Reserve), GVAR(ae2Reserve)]; _oldUnit setVariable [QGVAR(anReserve), GVAR(anReserve)]; _oldUnit setVariable [QGVAR(anFatigue), GVAR(anFatigue)]; _oldUnit setVariable [QGVAR(muscleDamage), GVAR(muscleDamage)]; + _oldUnit setVariable [QGVAR(respiratoryRate), GVAR(respiratoryRate)]; }; _newUnit enableStamina false; @@ -38,6 +42,7 @@ if (_newUnit getVariable [QGVAR(animHandler), -1] == -1) then { private _animHandler = _newUnit addEventHandler ["AnimChanged", { GVAR(animDuty) = _this call FUNC(getAnimDuty); }]; + TRACE_1("add new",_animHandler); _newUnit setVariable [QGVAR(animHandler), _animHandler]; }; @@ -47,18 +52,27 @@ GVAR(ae2Reserve) = _newUnit getVariable [QGVAR(ae2Reserve), AE2_MAXRESERVE] GVAR(anReserve) = _newUnit getVariable [QGVAR(anReserve), AN_MAXRESERVE]; GVAR(anFatigue) = _newUnit getVariable [QGVAR(anFatigue), 0]; GVAR(muscleDamage) = _newUnit getVariable [QGVAR(muscleDamage), 0]; +GVAR(respiratoryRate) = _newUnit getVariable [QGVAR(respiratoryRate), 0]; // Clean variables for respawning units { _newUnit setVariable [_x, nil]; -} forEach [QGVAR(ae1Reserve), QGVAR(ae2Reserve), QGVAR(anReserve), QGVAR(anFatigue), QGVAR(muscleDamage)]; +} forEach [QGVAR(ae1Reserve), QGVAR(ae2Reserve), QGVAR(anReserve), QGVAR(anFatigue), QGVAR(muscleDamage), QGVAR(respiratoryRate)]; GVAR(VO2Max) = 35 + 20 * (_newUnit getVariable [QGVAR(performanceFactor), GVAR(performanceFactor)]); -GVAR(VO2MaxPower) = GVAR(VO2Max) * SIM_BODYMASS * 0.23 * JOULES_PER_ML_O2 / 60; +GVAR(VO2MaxPower) = GVAR(VO2Max) * SIM_BODYMASS * BIOMECH_EFFICIENCY * JOULES_PER_ML_O2 / 60; GVAR(peakPower) = VO2MAX_STRENGTH * GVAR(VO2MaxPower); -GVAR(ae1PathwayPower) = GVAR(peakPower) / (13.3 + 16.7 + 113.3) * 13.3 * ANTPERCENT ^ 1.28 * 1.362; -GVAR(ae2PathwayPower) = GVAR(peakPower) / (13.3 + 16.7 + 113.3) * 16.7 * ANTPERCENT ^ 1.28 * 1.362; +GVAR(ae1PathwayPower) = GVAR(peakPower) / (AE1_ATP_RELEASE_RATE + AE2_ATP_RELEASE_RATE + AN_ATP_RELEASE_RATE) * AE1_ATP_RELEASE_RATE * ANTPERCENT ^ 1.28 * 1.362; +GVAR(ae2PathwayPower) = GVAR(peakPower) / (AE1_ATP_RELEASE_RATE + AE2_ATP_RELEASE_RATE + AN_ATP_RELEASE_RATE) * AE2_ATP_RELEASE_RATE * ANTPERCENT ^ 1.28 * 1.362; +GVAR(aePathwayPower) = GVAR(ae1PathwayPower) + GVAR(ae2PathwayPower); +GVAR(anPathwayPower) = GVAR(peakPower) - GVAR(aePathwayPower); + +GVAR(aeWattsPerATP) = GVAR(ae1PathwayPower) / AE1_ATP_RELEASE_RATE; +GVAR(anWattsPerATP) = GVAR(anPathwayPower) / AN_ATP_RELEASE_RATE; + +GVAR(respiratoryBufferDivisor) = (RESPIRATORY_BUFFER - 1) / RESPIRATORY_BUFFER; +GVAR(maxPowerFatigueRatio) = 0.057 / GVAR(peakPower); GVAR(ppeBlackoutLast) = 100; GVAR(lastBreath) = 0; diff --git a/addons/advanced_fatigue/functions/fnc_mainLoop.sqf b/addons/advanced_fatigue/functions/fnc_mainLoop.sqf index add9b6e5d8..a07abae794 100644 --- a/addons/advanced_fatigue/functions/fnc_mainLoop.sqf +++ b/addons/advanced_fatigue/functions/fnc_mainLoop.sqf @@ -1,6 +1,6 @@ #include "..\script_component.hpp" /* - * Author: BaerMitUmlaut + * Author: BaerMitUmlaut, ulteq * Main looping function that updates fatigue values. * * Arguments: @@ -17,73 +17,131 @@ // Dead people don't breathe, will also handle null (map intros) if (!alive ACE_player) exitWith { - [FUNC(mainLoop), [], 1] call CBA_fnc_waitAndExecute; + [LINKFUNC(mainLoop), [], 1] call CBA_fnc_waitAndExecute; + private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull]; _staminaBarContainer ctrlSetFade 1; _staminaBarContainer ctrlCommit 1; }; - -private _oxygen = 0.9; // Default AF oxygen saturation -if (GETEGVAR(medical,enabled,false) && {EGVAR(medical_vitals,simulateSpo2)}) then { - _oxygen = (ACE_player getVariable [QEGVAR(medical,spo2), 97]) / 100; -}; +private _velocity = velocity ACE_player; +private _normal = surfaceNormal (getPosWorld ACE_player); +private _movementVector = vectorNormalized _velocity; +private _sideVector = vectorNormalized (_movementVector vectorCrossProduct _normal); +private _fwdAngle = asin (_movementVector select 2); +private _sideAngle = asin (_sideVector select 2); private _currentWork = REE; -private _currentSpeed = (vectorMagnitude (velocity ACE_player)) min 6; +private _currentSpeed = (vectorMagnitude _velocity) min 6; // fix #4481. Diving to the ground is recorded as PRONE stance with running speed velocity. Cap maximum speed to fix. if (GVAR(isProne)) then { _currentSpeed = _currentSpeed min 1.5; }; -if ((vehicle ACE_player == ACE_player) && {_currentSpeed > 0.1} && {isTouchingGround ACE_player || {underwater ACE_player}}) then { - _currentWork = [ACE_player, _currentSpeed] call FUNC(getMetabolicCosts); +// Get the current duty +private _duty = GVAR(animDuty); + +{ + if (_x isEqualType 0) then { + _duty = _duty * _x; + } else { + _duty = _duty * (ACE_player call _x); + }; +} forEach (values GVAR(dutyList)); + +private _terrainGradient = abs _fwdAngle; +private _terrainFactor = 1; +private _gearMass = 0 max (((ACE_player getVariable [QEGVAR(movement,totalLoad), loadAbs ACE_player]) / 22.046 - UNDERWEAR_WEIGHT) * GVAR(loadFactor)); + +if (isNull objectParent ACE_player && {_currentSpeed > 0.1} && {isTouchingGround ACE_player || {underwater ACE_player}}) then { + if (!GVAR(isSwimming)) then { + // If the unit is going downhill, it's much less demanding + if (_fwdAngle < 0) then { + _terrainGradient = 0.15 * _terrainGradient; + }; + + // Used to simulate the unevenness/roughness of the terrain + if ((getPosATL ACE_player) select 2 < 0.01) then { + private _sideGradient = abs (_sideAngle / 45) min 1; + + _terrainFactor = 1 + _sideGradient ^ 4; + }; + }; + + _currentWork = [_duty, _gearMass, _terrainGradient * GVAR(terrainGradientFactor), _terrainFactor, _currentSpeed] call FUNC(getMetabolicCosts); _currentWork = _currentWork max REE; }; +// Oxygen calculation +private _oxygen = if (GETEGVAR(medical,enabled,false) && {EGVAR(medical_vitals,simulateSpo2)}) then { // Defer to medical + (ACE_player getVariable [QEGVAR(medical,spo2), 97]) / 100 +} else { + 1 - 0.131 * GVAR(respiratoryRate) ^ 2 // Default AF oxygen saturation +}; // Calculate muscle damage increase -// Note: Muscle damage recovery is ignored as it takes multiple days -GVAR(muscleDamage) = (GVAR(muscleDamage) + (_currentWork / GVAR(peakPower)) ^ 3.2 * 0.00004) min 1; -private _muscleIntegritySqrt = sqrt (1 - GVAR(muscleDamage)); +GVAR(muscleDamage) = GVAR(muscleDamage) + (_currentWork / GVAR(peakPower)) ^ 3.2 * MUSCLE_TEAR_RATE; + +// Calculate muscle damage recovery +GVAR(muscleDamage) = 0 max (GVAR(muscleDamage) - MUSCLE_RECOVERY * GVAR(recoveryFactor)) min 1; +private _muscleIntegrity = 1 - GVAR(muscleDamage); +private _muscleFactor = sqrt _muscleIntegrity; // Calculate available power -private _ae1PathwayPowerFatigued = GVAR(ae1PathwayPower) * sqrt (GVAR(ae1Reserve) / AE1_MAXRESERVE) * _oxygen * _muscleIntegritySqrt; -private _ae2PathwayPowerFatigued = GVAR(ae2PathwayPower) * sqrt (GVAR(ae2Reserve) / AE2_MAXRESERVE) * _oxygen * _muscleIntegritySqrt; +private _ae1PathwayPowerFatigued = GVAR(ae1PathwayPower) * sqrt (GVAR(ae1Reserve) / AE1_MAXRESERVE) * _oxygen * _muscleFactor; +private _ae2PathwayPowerFatigued = GVAR(ae2PathwayPower) * sqrt (GVAR(ae2Reserve) / AE2_MAXRESERVE) * _oxygen * _muscleFactor; +private _aePathwayPowerFatigued = _ae1PathwayPowerFatigued + _ae2PathwayPowerFatigued; +private _anPathwayPowerFatigued = GVAR(anPathwayPower) * sqrt (GVAR(anReserve) / AN_MAXRESERVE) * _oxygen * _muscleIntegrity; // Calculate how much power is consumed from each reserve private _ae1Power = _currentWork min _ae1PathwayPowerFatigued; -private _ae2Power = ((_currentWork - _ae1Power) max 0) min _ae2PathwayPowerFatigued; -private _anPower = (_currentWork - _ae1Power - _ae2Power) max 0; +private _ae2Power = (_currentWork - _ae1Power) min _ae2PathwayPowerFatigued; +private _anPower = 0 max (_currentWork - _ae1Power - _ae2Power); // Remove ATP from reserves for current work -GVAR(ae1Reserve) = GVAR(ae1Reserve) - _ae1Power / WATTSPERATP; -GVAR(ae2Reserve) = GVAR(ae2Reserve) - _ae2Power / WATTSPERATP; -GVAR(anReserve) = GVAR(anReserve) - _anPower / WATTSPERATP; -// Increase anearobic fatigue -GVAR(anFatigue) = GVAR(anFatigue) + _anPower * (0.057 / GVAR(peakPower)) * 1.1; +GVAR(ae1Reserve) = 0 max (GVAR(ae1Reserve) - _ae1Power / GVAR(aeWattsPerATP)); +GVAR(ae2Reserve) = 0 max (GVAR(ae2Reserve) - _ae2Power / GVAR(aeWattsPerATP)); +GVAR(anReserve) = 0 max (GVAR(anReserve) - _anPower / GVAR(anWattsPerATP)); + +// Acidosis accumulation +GVAR(anFatigue) = GVAR(anFatigue) + _anPower * GVAR(maxPowerFatigueRatio) * 1.1; // Aerobic ATP reserve recovery -GVAR(ae1Reserve) = ((GVAR(ae1Reserve) + _oxygen * 6.60 * (GVAR(ae1PathwayPower) - _ae1Power) / GVAR(ae1PathwayPower) * GVAR(recoveryFactor)) min AE1_MAXRESERVE) max 0; -GVAR(ae2Reserve) = ((GVAR(ae2Reserve) + _oxygen * 5.83 * (GVAR(ae2PathwayPower) - _ae2Power) / GVAR(ae2PathwayPower) * GVAR(recoveryFactor)) min AE2_MAXRESERVE) max 0; +GVAR(ae1Reserve) = (GVAR(ae1Reserve) + _oxygen * GVAR(recoveryFactor) * AE1_ATP_RECOVERY * (GVAR(ae1PathwayPower) - _ae1Power) / GVAR(ae1PathwayPower)) min AE1_MAXRESERVE; +GVAR(ae2Reserve) = (GVAR(ae2Reserve) + _oxygen * GVAR(recoveryFactor) * AE2_ATP_RECOVERY * (GVAR(ae2PathwayPower) - _ae2Power) / GVAR(ae2PathwayPower)) min AE2_MAXRESERVE; -// Anaerobic ATP reserver and fatigue recovery -GVAR(anReserve) = ((GVAR(anReserve) - + (_ae1PathwayPowerFatigued + _ae2PathwayPowerFatigued - _ae1Power - _ae2Power) / GVAR(VO2MaxPower) * 56.7 * GVAR(anFatigue) ^ 2 * GVAR(recoveryFactor) -) min AN_MAXRESERVE) max 0; +private _aeSurplus = _ae1PathwayPowerFatigued + _ae2PathwayPowerFatigued - _ae1Power - _ae2Power; -GVAR(anFatigue) = ((GVAR(anFatigue) - - (_ae1PathwayPowerFatigued + _ae2PathwayPowerFatigued - _ae1Power - _ae2Power) * (0.057 / GVAR(peakPower)) * GVAR(anFatigue) ^ 2 * GVAR(recoveryFactor) -) min 1) max 0; +// Anaerobic ATP reserve recovery +GVAR(anReserve) = 0 max (GVAR(anReserve) + _aeSurplus / GVAR(VO2MaxPower) * AN_ATP_RECOVERY * GVAR(recoveryFactor) * (GVAR(anFatigue) max linearConversion [AN_MAXRESERVE, 0, GVAR(anReserve), 0, 0.75, true]) ^ 2) min AN_MAXRESERVE; // max linearConversion ensures that if GVAR(anFatigue) is very low, it will still regenerate reserves +// Acidosis recovery +GVAR(anFatigue) = 0 max (GVAR(anFatigue) - _aeSurplus * GVAR(maxPowerFatigueRatio) * GVAR(recoveryFactor) * GVAR(anFatigue) ^ 2) min 1; +// Respiratory rate decrease +GVAR(respiratoryRate) = GVAR(respiratoryRate) * GVAR(respiratoryBufferDivisor); + +// Respiratory rate increase +private _aePowerRatio = (GVAR(aePathwayPower) / _aePathwayPowerFatigued) min 2; +private _respiratorySampleDivisor = 1 / (RESPIRATORY_BUFFER * 4.72 * GVAR(VO2Max)); +GVAR(respiratoryRate) = (GVAR(respiratoryRate) + _currentWork * _respiratorySampleDivisor * _aePowerRatio) min 1; + +// Calculate a pseudo-perceived fatigue, which is used for effects GVAR(aeReservePercentage) = (GVAR(ae1Reserve) / AE1_MAXRESERVE + GVAR(ae2Reserve) / AE2_MAXRESERVE) / 2; GVAR(anReservePercentage) = GVAR(anReserve) / AN_MAXRESERVE; private _perceivedFatigue = 1 - (GVAR(anReservePercentage) min GVAR(aeReservePercentage)); -[ACE_player, _perceivedFatigue, _currentSpeed, GVAR(anReserve) == 0] call FUNC(handleEffects); +#ifdef DEBUG_MODE_FULL +systemChat format ["---- muscleDamage: %1 ----", GVAR(muscleDamage) toFixed 8]; +systemChat format ["---- ae2: %1 - an: %2 ----", (GVAR(ae2Reserve) / AE2_MAXRESERVE) toFixed 2, (GVAR(anReserve) / AN_MAXRESERVE) toFixed 2]; +systemChat format ["---- anFatigue: %1 - perceivedFatigue: %2 ----", GVAR(anFatigue) toFixed 2, _perceivedFatigue toFixed 2]; +systemChat format ["---- velocity %1 - respiratoryRate: %2 ----", (vectorMagnitude _velocity) toFixed 2, GVAR(respiratoryRate) toFixed 2]; +// systemChat format ["---- aePower: %1 ----", _aePathwayPowerFatigued toFixed 1]; +#endif + +[ACE_player, _perceivedFatigue, GVAR(anReserve) == 0, _fwdAngle, _sideAngle] call FUNC(handleEffects); if (GVAR(enableStaminaBar)) then { [GVAR(anReserve) / AN_MAXRESERVE] call FUNC(handleStaminaBar); }; -[FUNC(mainLoop), [], 1] call CBA_fnc_waitAndExecute; +[LINKFUNC(mainLoop), [], 1] call CBA_fnc_waitAndExecute; diff --git a/addons/advanced_fatigue/functions/fnc_renderDebugLines.sqf b/addons/advanced_fatigue/functions/fnc_renderDebugLines.sqf new file mode 100644 index 0000000000..3826637b9e --- /dev/null +++ b/addons/advanced_fatigue/functions/fnc_renderDebugLines.sqf @@ -0,0 +1,40 @@ +#include "..\script_component.hpp" +/* + * Author: ulteq + * Draw lines for debugging. + * + * Arguments: + * None + * + * Return Value: + * None + * + * Example: + * call ace_advanced_fatigue_fnc_renderDebugLines + * + * Public: No + */ + +addMissionEventHandler ["Draw3D", { + private _normal = surfaceNormal (getPosWorld ACE_player); + private _beg = (getPosWorld ACE_player) vectorAdd (_normal vectorMultiply 0.5); + private _end = _beg vectorAdd (_normal vectorMultiply 2); + drawLine3D [ASLToATL _beg, ASLToATL _end, [0, 1, 0, 1]]; + + private _side = vectorNormalized (_normal vectorCrossProduct [0, 0, 1]); + private _end = _beg vectorAdd (_side vectorMultiply 2); + drawLine3D [ASLToATL _beg, ASLToATL _end, [0, 0, 1, 1]]; + + private _up = vectorNormalized (_normal vectorCrossProduct _side); + private _end = _beg vectorAdd (_up vectorMultiply 2); + drawLine3D [ASLToATL _beg, ASLToATL _end, [1, 0, 0, 1]]; + + private _movementVector = vectorNormalized (velocity ACE_player); + private _end = _beg vectorAdd (_movementVector vectorMultiply 2); + drawLine3D [ASLToATL _beg, ASLToATL _end, [1, 1, 0, 1]]; + + private _sideVector = vectorNormalized (_movementVector vectorCrossProduct _normal); + _sideVector set [2, 0]; + private _end = _beg vectorAdd (_sideVector vectorMultiply 2); + drawLine3D [ASLToATL _beg, ASLToATL _end, [0, 1, 1, 1]]; +}]; diff --git a/addons/advanced_fatigue/initSettings.inc.sqf b/addons/advanced_fatigue/initSettings.inc.sqf index 9952a51d23..01eba8652d 100644 --- a/addons/advanced_fatigue/initSettings.inc.sqf +++ b/addons/advanced_fatigue/initSettings.inc.sqf @@ -4,12 +4,14 @@ [LSTRING(Enabled), LSTRING(Enabled_Description)], LSTRING(DisplayName), true, - true, { + 1, + { if (!_this) then { private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull]; _staminaBarContainer ctrlSetFade 1; _staminaBarContainer ctrlCommit 0; }; + [QGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged) }, true // Needs mission restart @@ -21,7 +23,8 @@ [LSTRING(EnableStaminaBar), LSTRING(EnableStaminaBar_Description)], LSTRING(DisplayName), true, - true, { + 1, + { if (!_this) then { private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull]; _staminaBarContainer ctrlSetFade 1; @@ -36,7 +39,8 @@ [LSTRING(FadeStaminaBar), LSTRING(FadeStaminaBar_Description)], LSTRING(DisplayName), true, - false, { + 0, + { if (!_this && GVAR(enabled) && GVAR(enableStaminaBar)) then { private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull]; _staminaBarContainer ctrlSetFade 0; @@ -50,8 +54,14 @@ "SLIDER", [LSTRING(PerformanceFactor), LSTRING(PerformanceFactor_Description)], LSTRING(DisplayName), - [0, 5, 1, 1], - true + [0, 10, 1, 2], + 1, + { + // Recalculate values if the setting is changed mid-mission + if (GVAR(enabled) && hasInterface && !isNull ACE_player) then { + [ACE_player, ACE_player] call FUNC(handlePlayerChanged); + }; + } ] call CBA_fnc_addSetting; [ @@ -59,8 +69,8 @@ "SLIDER", [LSTRING(RecoveryFactor), LSTRING(RecoveryFactor_Description)], LSTRING(DisplayName), - [0, 5, 1, 1], - true + [0, 10, 1, 2], + 1 ] call CBA_fnc_addSetting; [ @@ -68,8 +78,8 @@ "SLIDER", [LSTRING(LoadFactor), LSTRING(LoadFactor_Description)], LSTRING(DisplayName), - [0, 5, 1, 1], - true + [0, 5, 1, 2], + 1 ] call CBA_fnc_addSetting; [ @@ -77,6 +87,6 @@ "SLIDER", [LSTRING(TerrainGradientFactor), LSTRING(TerrainGradientFactor_Description)], LSTRING(DisplayName), - [0, 5, 1, 1], - true + [0, 5, 1, 2], + 1 ] call CBA_fnc_addSetting; diff --git a/addons/advanced_fatigue/script_component.hpp b/addons/advanced_fatigue/script_component.hpp index fcc8abd3c0..7e3255439f 100644 --- a/addons/advanced_fatigue/script_component.hpp +++ b/addons/advanced_fatigue/script_component.hpp @@ -16,14 +16,28 @@ #include "\z\ace\addons\main\script_macros.hpp" +#define UNDERWEAR_WEIGHT 3.5 + #define ANTPERCENT 0.8 #define SIM_BODYMASS 70 #define JOULES_PER_ML_O2 20.9 #define VO2MAX_STRENGTH 4.1 -#define REE 18.83 //((0.5617 * SIM_BODYMASS + 42.57) * 0.23) -#define OXYGEN 0.9 -#define WATTSPERATP 7 +#define BIOMECH_EFFICIENCY 0.23 +#define REE 18.83 // ((0.5617 * SIM_BODYMASS + 42.57) * BIOMECH_EFFICIENCY) -#define AE1_MAXRESERVE 4000000 -#define AE2_MAXRESERVE 84000 -#define AN_MAXRESERVE 2300 +#define RESPIRATORY_BUFFER 60 + +#define MUSCLE_TEAR_RATE 0.00004 +#define MUSCLE_RECOVERY 0.00000386 + +#define AE1_ATP_RELEASE_RATE 13.3 // mmol +#define AE2_ATP_RELEASE_RATE 16.7 // mmol +#define AN_ATP_RELEASE_RATE 113.3 // mmol + +#define AE1_ATP_RECOVERY 6.60 // mmol +#define AE2_ATP_RECOVERY 5.83 // mmol +#define AN_ATP_RECOVERY 56.70 // mmol + +#define AE1_MAXRESERVE 4000000 // mmol +#define AE2_MAXRESERVE 84000 // mmol +#define AN_MAXRESERVE 2300 // mmol diff --git a/docs/wiki/framework/advanced-fatigue-framework.md b/docs/wiki/framework/advanced-fatigue-framework.md index 93c9aa9b77..9afd9891d7 100644 --- a/docs/wiki/framework/advanced-fatigue-framework.md +++ b/docs/wiki/framework/advanced-fatigue-framework.md @@ -13,16 +13,18 @@ version: ## 1. Global Settings -ACE provides four settings to tweak Advanced Fatigue. Adjust these factors depending on how hard you want your experience to be. +ACE provides multiple settings to tweak Advanced Fatigue. Adjust these settings depending on how hard you want your experience to be. +- **Enabled:** This allow you to toggle Advanced Fatigue on or off. Mission needs to be restarted if this setting is changed. +- **Show stamina bar:** Shows/hides the stamina bar. +- **Fade Stamina bar automatically:** Adjusts transparency of the bar based on stamina status. - **Performance factor:** This influences the overall performance of players, malnourished or super soldiers, everything is possible. - **Recovery factor:** Do you like looking at the landscape or think breaks are boring? Whatever the case, this influences the length of your stamina breaks. - **Load factor:** If you believe a Javelin is the perfect companion for your .50 BMG sniper rifle you probably should tweak this setting. -- **Terrain factor**: Not everyone is used to mountainous terrain. Tweak this until you feel more at home. -- **Sway factor**: Influences the amount of weapon sway. Higher means more sway. - -Note that while there currently is no restriction on the value of these settings, it's generally recommended to keep them between 0 and 2. - +- **Terrain factor:** Not everyone is used to mountainous terrain. Tweak this until you feel more at home. +- **Sway factor:** Influences the amount of weapon sway. Higher means more sway. +- **Rested sway factor:** Influences the amount of weapon sway while rested is deployed. Higher means more sway. +- **Deployed sway factor:** Influences the amount of weapon sway while weapon is deployed. Higher means more sway. ## 2. Unit Specific Settings From f45dff8a094ff41a68f53b69ff6c40d3058296e3 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 22 Jun 2024 20:07:36 +0200 Subject: [PATCH 112/290] Fire - Mini-Rewrite (#9757) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jouni Järvinen Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> --- .../functions/fnc_woundsHandlerIncendiary.sqf | 8 +- .../functions/fnc_woundsHandlerIncendiary.sqf | 8 +- .../cookoff/functions/fnc_cookOffServer.sqf | 2 +- addons/fire/CfgSounds.hpp | 8 +- addons/fire/CfgVehicles.hpp | 7 + addons/fire/XEH_PREP.hpp | 7 +- addons/fire/XEH_postInit.sqf | 92 ++++- addons/fire/config.cpp | 1 + addons/fire/functions/fnc_burn.sqf | 361 +++--------------- addons/fire/functions/fnc_burnEffects.sqf | 191 +++++++++ addons/fire/functions/fnc_burnIndicator.sqf | 34 +- addons/fire/functions/fnc_burnReaction.sqf | 19 +- addons/fire/functions/fnc_burnSimulation.sqf | 167 ++++++++ addons/fire/functions/fnc_fireManagerPFH.sqf | 53 +-- addons/fire/functions/fnc_isBurning.sqf | 8 +- .../fire/functions/fnc_medical_canPatDown.sqf | 2 +- .../fire/functions/fnc_medical_progress.sqf | 8 +- addons/fire/functions/fnc_medical_success.sqf | 29 +- addons/fire/initSettings.inc.sqf | 32 +- addons/fire/script_component.hpp | 7 +- addons/zeus/functions/fnc_moduleBurn.sqf | 12 +- docs/wiki/framework/fire-framework.md | 7 +- 22 files changed, 612 insertions(+), 451 deletions(-) create mode 100644 addons/fire/CfgVehicles.hpp create mode 100644 addons/fire/functions/fnc_burnEffects.sqf create mode 100644 addons/fire/functions/fnc_burnSimulation.sqf diff --git a/addons/compat_sog/functions/fnc_woundsHandlerIncendiary.sqf b/addons/compat_sog/functions/fnc_woundsHandlerIncendiary.sqf index 75ee243f08..6d3b7a8678 100644 --- a/addons/compat_sog/functions/fnc_woundsHandlerIncendiary.sqf +++ b/addons/compat_sog/functions/fnc_woundsHandlerIncendiary.sqf @@ -18,8 +18,6 @@ * Public: No */ -#define BURN_THRESHOLD 1 - params ["_unit", "_damages"]; TRACE_2("woundsHandlerIncendiary",_unit,_damages); @@ -32,9 +30,7 @@ private _fireDamage = 0; private _intensity = linearConversion [0, 20, _fireDamage, 0, 10, true]; TRACE_2("",_intensity,_fireDamage); -if (_intensity > BURN_THRESHOLD) then { - TRACE_2("Setting unit ablaze",_intensity,BURN_THRESHOLD); - ["ace_fire_burn", [_unit, _intensity]] call CBA_fnc_globalEvent; -}; +// Let fire handle if unit is set ablaze or not +[QEGVAR(fire,burn), [_unit, _intensity]] call CBA_fnc_localEvent; _this // return diff --git a/addons/compat_spe/functions/fnc_woundsHandlerIncendiary.sqf b/addons/compat_spe/functions/fnc_woundsHandlerIncendiary.sqf index aa282e9be8..d2b0cb165c 100644 --- a/addons/compat_spe/functions/fnc_woundsHandlerIncendiary.sqf +++ b/addons/compat_spe/functions/fnc_woundsHandlerIncendiary.sqf @@ -18,8 +18,6 @@ * Public: No */ -#define BURN_THRESHOLD 1 - params ["_unit", "_damages"]; TRACE_2("woundsHandlerIncendiary",_unit,_damages); @@ -32,9 +30,7 @@ private _fireDamage = 0; private _intensity = linearConversion [0, 20, _fireDamage, 0, 10, true]; TRACE_2("",_intensity,_fireDamage); -if (_intensity > BURN_THRESHOLD) then { - TRACE_2("Setting unit ablaze",_intensity,BURN_THRESHOLD); - ["ace_fire_burn", [_unit, _intensity]] call CBA_fnc_globalEvent; -}; +// Let fire handle if unit is set ablaze or not +[QEGVAR(fire,burn), [_unit, _intensity]] call CBA_fnc_localEvent; _this // return diff --git a/addons/cookoff/functions/fnc_cookOffServer.sqf b/addons/cookoff/functions/fnc_cookOffServer.sqf index 303555ba28..05111d7e69 100644 --- a/addons/cookoff/functions/fnc_cookOffServer.sqf +++ b/addons/cookoff/functions/fnc_cookOffServer.sqf @@ -175,7 +175,7 @@ if (_delayBetweenSmokeAndFire) then { if (["ace_fire"] call EFUNC(common,isModLoaded)) then { // Use current intensity, in case GVAR(cookoffDuration) is very large and only 1 flameout stage happens { - [QEGVAR(fire,burn), [_x, _intensity * 1.5, _instigator]] call CBA_fnc_globalEvent; + [QEGVAR(fire,burn), [_x, _intensity * 1.5, _instigator], _x] call CBA_fnc_targetEvent; } forEach (crew _vehicle); }; diff --git a/addons/fire/CfgSounds.hpp b/addons/fire/CfgSounds.hpp index b83ce9b91a..76fb0e64f7 100644 --- a/addons/fire/CfgSounds.hpp +++ b/addons/fire/CfgSounds.hpp @@ -1,10 +1,10 @@ // weird ass concatenation syntax. PBO Project complains otherwise... #define CONCAT(a,b) a####b #define CREATE_SCREAM(no)\ -class GVAR(DOUBLES(scream,no)) { \ - name = QUOTE(GVAR(CONCAT(scream,no)));\ - sound[] = {QUOTE(PATHTOF(CONCAT(sounds\scream,no).ogg)), QUOTE(db+8), 1};\ - titles[] = {}; \ +class GVAR(DOUBLES(scream,no)) {\ + name = QGVAR(CONCAT(scream,no));\ + sound[] = {QPATHTOF(CONCAT(sounds\scream,no).ogg), QUOTE(db+8), 1};\ + titles[] = {};\ } class CfgSounds { diff --git a/addons/fire/CfgVehicles.hpp b/addons/fire/CfgVehicles.hpp new file mode 100644 index 0000000000..0ed16faff7 --- /dev/null +++ b/addons/fire/CfgVehicles.hpp @@ -0,0 +1,7 @@ +class CfgVehicles { + class Static; + class GVAR(logic): Static { + scope = 1; + displayName = ""; + }; +}; diff --git a/addons/fire/XEH_PREP.hpp b/addons/fire/XEH_PREP.hpp index 8b2e8f6bd1..a352cdf2aa 100644 --- a/addons/fire/XEH_PREP.hpp +++ b/addons/fire/XEH_PREP.hpp @@ -1,9 +1,10 @@ PREP(burn); -PREP(isBurning); +PREP(burnEffects); PREP(burnIndicator); PREP(burnReaction); +PREP(burnSimulation); PREP(fireManagerPFH); - +PREP(isBurning); +PREP(medical_canPatDown); PREP(medical_progress); PREP(medical_success); -PREP(medical_canPatDown); diff --git a/addons/fire/XEH_postInit.sqf b/addons/fire/XEH_postInit.sqf index 571c0033d9..641b74fffe 100644 --- a/addons/fire/XEH_postInit.sqf +++ b/addons/fire/XEH_postInit.sqf @@ -1,37 +1,89 @@ #include "script_component.hpp" [QGVAR(burn), LINKFUNC(burn)] call CBA_fnc_addEventHandler; +[QGVAR(burnEffects), LINKFUNC(burnEffects)] call CBA_fnc_addEventHandler; +[QGVAR(burnSimulation), LINKFUNC(burnSimulation)] call CBA_fnc_addEventHandler; + [QGVAR(playScream), { params ["_scream", "_source"]; - // only play sound if enabled in settings and enabled for the unit + + // Only play sound if enabled in settings and enabled for the unit if (GVAR(enableScreams) && {_source getVariable [QGVAR(enableScreams), true]}) then { _source say3D _scream; }; }] call CBA_fnc_addEventHandler; -["ace_settingsInitialized", { +if (!isServer) exitWith {}; + +["CBA_settingsInitialized", { TRACE_1("settingsInit",GVAR(enabled)); + if (!GVAR(enabled)) exitWith {}; - if (isServer) then { - [QGVAR(addFireSource), { - params ["_source", "_radius", "_intensity", "_key", ["_condition", { true }], ["_conditionArgs", []]]; - private _fireLogic = createVehicle ["ACE_LogicDummy", [0, 0, 0], [], 0, "NONE"]; - if (_source isEqualType objNull) then { - _fireLogic attachTo [_source]; - } else { - _fireLogic setPosASL _source; - }; + GVAR(fireSources) = createHashMap; - [GVAR(fireSources), _key, [_fireLogic, _radius, _intensity, _condition, _conditionArgs]] call CBA_fnc_hashSet; - }] call CBA_fnc_addEventHandler; + [QGVAR(addFireSource), { + params [ + ["_source", objNull, [objNull, []]], + ["_radius", 0, [0]], + ["_intensity", 0, [0]], + ["_key", ""], + ["_condition", {true}, [{}]], + ["_conditionArgs", []] + ]; - [QGVAR(removeFireSource), { - params ["_key"]; - [GVAR(fireSources), _key] call CBA_fnc_hashRem; - }] call CBA_fnc_addEventHandler; + private _isObject = _source isEqualType objNull; - [LINKFUNC(fireManagerPFH), FIRE_MANAGER_PFH_DELAY, []] call CBA_fnc_addPerFrameHandler; - GVAR(fireSources) = [[], nil] call CBA_fnc_hashCreate; - }; + // Check if the source is valid + if !(_isObject || {_source isEqualTypeParams [0, 0, 0]}) exitWith {}; + + if (_isObject && {isNull _source}) exitWith {}; + if (_radius == 0 || _intensity == 0) exitWith {}; + if (_key isEqualTo "") exitWith {}; // key can be many types + + // hashValue supports more types than hashmaps do by default, but not all (e.g. locations) + private _hashedKey = hashValue _key; + + if (isNil "_hashedKey") exitWith { + ERROR_2("Unsupported key type used: %1 - %2",_key,typeName _key); + }; + + // If a position is passed, create a static object at said position + private _sourcePos = if (_isObject) then { + getPosATL _source + } else { + ASLToATL _source + }; + + private _fireLogic = createVehicle [QGVAR(logic), _sourcePos, [], 0, "CAN_COLLIDE"]; + + // If an object was passed, attach logic to the object + if (_isObject) then { + _fireLogic attachTo [_source]; + }; + + // To avoid issues, remove existing entries first before overwriting + if (_hashedKey in GVAR(fireSources)) then { + [QGVAR(removeFireSource), _key] call CBA_fnc_localEvent; + }; + + GVAR(fireSources) set [_hashedKey, [_fireLogic, _radius, _intensity, _condition, _conditionArgs]]; + }] call CBA_fnc_addEventHandler; + + [QGVAR(removeFireSource), { + params ["_key"]; + + private _hashedKey = hashValue _key; + + if (isNil "_hashedKey") exitWith { + ERROR_2("Unsupported key type used: %1 - %2",_key,typeName _key); + }; + + (GVAR(fireSources) deleteAt _hashedKey) params [["_fireLogic", objNull]]; + + detach _fireLogic; + deleteVehicle _fireLogic; + }] call CBA_fnc_addEventHandler; + + [LINKFUNC(fireManagerPFH), FIRE_MANAGER_PFH_DELAY, []] call CBA_fnc_addPerFrameHandler; }] call CBA_fnc_addEventHandler; diff --git a/addons/fire/config.cpp b/addons/fire/config.cpp index da8cd0091c..df2eb5cb79 100644 --- a/addons/fire/config.cpp +++ b/addons/fire/config.cpp @@ -24,6 +24,7 @@ class CfgPatches { #include "CfgEventHandlers.hpp" #include "CfgSounds.hpp" +#include "CfgVehicles.hpp" #include "ACE_Medical_Treatment_Actions.hpp" #include "RscTitles.hpp" diff --git a/addons/fire/functions/fnc_burn.sqf b/addons/fire/functions/fnc_burn.sqf index 1d829dfc45..1cf0fc6759 100644 --- a/addons/fire/functions/fnc_burn.sqf +++ b/addons/fire/functions/fnc_burn.sqf @@ -1,13 +1,12 @@ #include "..\script_component.hpp" /* - * Author: tcvm - * Makes object catch fire. Only call from events. Local effects only. - * Arbitrary values to ignite people. Assumed maximum is "10". + * Author: johnb43 + * Makes a unit catch fire. Only call from targeted events, is applied globally. * * Arguments: - * 0: Vehicle - * 1: Intensity of fire - * 2: Instigator of fire (default: objNull) + * 0: Unit + * 1: Fire intensity + * 2: Fire instigator (default: objNull) * * Return Value: * None @@ -18,322 +17,62 @@ * Public: No */ -#define INTENSITY_LOSS 0.03 -#define INTENSITY_UPDATE 3 -#define BURN_PROPOGATE_UPDATE 1 -#define BURN_PROPOGATE_DISTANCE 2 -#define BURN_PROPOGATE_COUNTER_MAX 5 - -params ["_unit", "_intensity", ["_instigator", objNull]]; +if (!EGVAR(common,settingsInitFinished)) exitWith { + EGVAR(common,runAtSettingsInitialized) pushBack [LINKFUNC(burn), _this]; +}; if (!GVAR(enabled)) exitWith {}; -private _isBurning = [_unit] call FUNC(isBurning); -if (_isBurning) exitWith {}; +params ["_unit", "_intensity", ["_instigator", objNull]]; +TRACE_3("burn",_unit,_intensity,_instigator); -[{ - // looped function - (_this getVariable "params") params ["_unit", "", "_instigator"]; - private _unitPos = getPosASL _unit; +if (BURN_MIN_INTENSITY > _intensity) exitWith { + TRACE_3("intensity is too low",_unit,_intensity,BURN_MIN_INTENSITY); +}; - _intensity = _unit getVariable [QGVAR(intensity), 0]; +// Check if unit is remote (objNull is remote) +if (!local _unit) exitWith { + TRACE_1("unit is null or not local",_unit); +}; - if (surfaceIsWater _unitPos && {(_unitPos#2) < 1}) then { - _intensity = 0; +// Check if the unit can burn (takes care of spectators and curators) +if (getNumber (configOf _unit >> "isPlayableLogic") == 1 || {!(_unit isKindOf "CAManBase")}) exitWith { + TRACE_1("unit is virtual or not a man",_unit); +}; + +// If unit is invulnerable, don't burn the unit +if !(isDamageAllowed _unit && {_unit getVariable [QEGVAR(medical,allowDamage), true]}) exitWith { + TRACE_1("unit is invulnerable",_unit); +}; + +private _eyePos = eyePos _unit; + +// Check if unit is mostly submerged in water +if (surfaceIsWater _eyePos && {(_eyePos select 2) < 0.1}) exitWith { + TRACE_1("unit is in water",_unit); +}; + +// If unit is already burning, update intensity, but don't add another PFH +if (_unit call FUNC(isBurning)) exitWith { + // Only allow intensity to be increased + if (_intensity <= (_unit getVariable [QGVAR(intensity), 0])) exitWith { + TRACE_2("unit already burning, no intensity update",_unit,_intensity); }; - _fireParticle setDropInterval (0.01 max linearConversion [BURN_MAX_INTENSITY, BURN_MIN_INTENSITY, _intensity, 0.03, 0.1, false]); - _fireParticle setParticleParams [ - ["\A3\data_f\ParticleEffects\Universal\Universal", 16, 10, 32], // sprite sheet values - "", // animation name - "Billboard", // particle type - 1, // timer period - 0.7, // lifetime - "destructionEffect2", // position - [0, 0, 1], // move velocity - 0, // rotation velocity - 10, // weight - 7.9, // volume - 1, // rubbing - [0.3, 0.3], // size - [ - [1, 1, 1, -0], - [1, 1, 1, -1], - [1, 1, 1, -1], - [1, 1, 1, -1], - [1, 1, 1, -0] - ], // colour - [0.5, 1], // animation speed - 1, // random dir period - 0, // random dir intensity - "", // on timer script - "", // before destroy script - _unit, // particle source - 0, - false, - 0, - [[0.8, 0.6, 0.2, 1]] // emissive color - ]; - _fireParticle setParticleRandom [ - 0.04 * _intensity, // life time - [0.05, 0.05, 2], // position - [0.05 * _intensity, 0.05 * _intensity, 0.05 * _intensity], // move velocity - 0, // rotation velocity - 0.06 * _intensity, // size - [0, 0, 0, 0], // color - 0, // random direction period - 0 // random direction intensity - ]; + TRACE_2("unit already burning, updating intensity",_unit,_intensity); - _smokeParticle setParticleCircle [0, [0, 0, 0]]; - _smokeParticle setParticleRandom [ - 0, // life time - [0.25, 0.25, 0], // position - [0.2, 0.2, 0], // move velocity - 0, // rotation velocity - 0.25, // size - [0, 0, 0, 0.1], // color - 0, // random direction period - 0 // random direction intensity - ]; - _smokeParticle setParticleParams [ - ["\A3\data_f\ParticleEffects\Universal\Universal", 16, 7, 48], // sprite sheet values - "", // animation name - "Billboard", // particle type - 1, // timer period - 8, // lifetime - [0, 0, 1.1], // position - [0, 0, 1], // move velocity - 0, // rotation velocity - 10, // weight - 7.9, // volume - 0.066, // rubbing - [1, 3, 6], // size - [ - [0.5, 0.5, 0.5, 0.15], - [0.75, 0.75, 0.75, 0.075], - [1, 1, 1, 0] - ], // colour - [0.125], // animation speed - 1, // random dir period - 0, // random dir intensity - "", // on timer script - "", // before destroy script - _unit // particle source - ]; - _smokeParticle setDropInterval 0.15; + _unit setVariable [QGVAR(intensity), _intensity, true]; +}; - _fireLight setLightBrightness ((_intensity * 3) / 10); - _lightFlare setLightBrightness (_intensity / 30); +TRACE_2("setting unit ablaze",_unit,_intensity); - private _distanceToUnit = (_unit distance ace_player); - _fireLight setLightAttenuation [1, 10 max (5 min (10 - _intensity)), 0, 15]; - _lightFlare setLightFlareSize (_intensity * (3 / 4)) * FLARE_SIZE_MODIFIER; +_unit setVariable [QGVAR(intensity), _intensity, true]; - if (!GVAR(enableFlare)) then { - _lightFlare setLightFlareSize 0; - }; +// Fire simulation (fire sources are handled differently) +[QGVAR(burnSimulation), [_unit, _instigator], _unit] call CBA_fnc_targetEvent; - // always keep flare visible to perceiving unit as long as it isnt the player - if (_unit isNotEqualTo ace_player) then { - private _relativeAttachPoint = [0, 0, 0.3]; - if (_distanceToUnit > 1.5) then { - _relativeAttachPoint = (vectorNormalized (_unit worldToModelVisual (getPos ace_player))) vectorMultiply linearConversion [5, 30, _distanceToUnit, 0.5, 1.5]; - _relativeAttachPoint set [2, 0.3 + ((_unit selectionPosition "pelvis") select 2)]; - }; - _lightFlare attachTo [_unit, _relativeAttachPoint]; - }; +// Spawn effects for unit +private _burnEffectsJipID = [QGVAR(burnEffects), _unit] call CBA_fnc_globalEventJIP; +[_burnEffectsJipID, _unit] call CBA_fnc_removeGlobalEventJIP; - if (!isGamePaused) then { - // If the unit goes to spectator alive _unit == true and they will be on fire and still take damage - // Only workaround I could think of, kinda clunky - if (_isThisUnitAlive) then { - _isThisUnitAlive = (alive _unit) && { getNumber ((configOf _unit) >> "isPlayableLogic") != 1 }; - }; - - // propagate fire - if ((CBA_missionTime - _lastPropogateUpdate) >= BURN_PROPOGATE_UPDATE) then { - _lastPropogateUpdate = CBA_missionTime; - if !([ace_player] call FUNC(isBurning)) then { - if ((vehicle _unit) isEqualTo (vehicle ace_player)) then { - if (0.5 > random 1) then { - [QGVAR(burn), [ace_player, _intensity * (7 / 8), _instigator]] call CBA_fnc_globalEvent; - }; - } else { - if ((ace_player isKindOf "Man") && {_unit isNotEqualTo ace_player} && {isDamageAllowed ace_player && {ace_player getVariable [QEGVAR(medical,allowDamage), true]}}) then { - private _burnCounter = _unit getVariable [QGVAR(burnCounter), 0]; - if (_distanceToUnit < BURN_PROPOGATE_DISTANCE) then { - if (_burnCounter < BURN_PROPOGATE_COUNTER_MAX) then { - _burnCounter = _burnCounter + 1; - } else { - [QGVAR(burn), [ace_player, _intensity * (3 / 4), _instigator]] call CBA_fnc_globalEvent; - }; - } else { - _burnCounter = 0; - }; - _unit setVariable [QGVAR(burnCounter), _burnCounter]; - }; - }; - }; - }; - - // update intensity/fire reactions - if ((CBA_missionTime - _lastIntensityUpdate) >= INTENSITY_UPDATE) then { - _lastIntensityUpdate = CBA_missionTime; - _intensity = _intensity - INTENSITY_LOSS - (rain / 10); - if (local _unit) then { - if (_isThisUnitAlive) then { - if !(IS_UNCONSCIOUS(_unit)) then { - if !(isPlayer _unit) then { - private _sdr = _unit getVariable [QGVAR(stopDropRoll), false]; - if ((_unit isEqualTo vehicle _unit) && (_sdr || ({ 0.05 > random 1 }))) then { - _unit setVariable [QGVAR(stopDropRoll), true]; - if !(_sdr) then { - TRACE_1("stop,drop,roll!",_unit); - _unit setUnitPos "DOWN"; - doStop _unit; - }; - // queue up a bunch of animations - for "_i" from 0 to 2 do { - [_unit, selectRandom ["amovppnemstpsnonwnondnon_amovppnemevasnonwnondl", "amovppnemstpsnonwnondnon_amovppnemevasnonwnondr"], 0] call EFUNC(common,doAnimation); - }; - _intensity = _intensity - (1 / _intensity); - } else { - private _group = (group _unit); - private _vehicle = vehicle _unit; - - if (_vehicle != _unit) then { - TRACE_1("Ejecting",_unit); - _unit leaveVehicle _vehicle; - unassignVehicle _unit; - _unit action ["eject",_vehicle]; - }; - _unit disableAI "TARGET"; - _unit disableAI "AUTOTARGET"; - - // Run away - if (leader _group != _unit) then { - [_unit] join grpNull; - }; - _unit doMove ((getPosATL _unit) getPos [20 + random 35, floor (random 360)]); - _unit setSpeedMode "FULL"; - _unit setSuppression 1; - }; - } else { - if ((animationState _unit) in PRONE_ROLLING_ANIMS) then { - // decrease intensity of burn - _intensity = _intensity * INTENSITY_DECREASE_MULT_ROLLING; - }; - }; - - [_unit] call FUNC(burnReaction); - }; - - // Common burn areas are the hands and face https://www.ncbi.nlm.nih.gov/pubmed/16899341/ - private _woundSelection = ["Head", "Body", "LeftArm", "RightArm", "LeftLeg", "RightLeg"] selectRandomWeighted [0.77, 0.5, 0.8, 0.8, 0.3, 0.3]; - if (GET_PAIN_PERCEIVED(_unit) < (PAIN_UNCONSCIOUS + random 0.2)) then { - // keep pain around unconciousness limit to allow for more fun interactions - [_unit, _intensity / BURN_MAX_INTENSITY, _woundSelection, "burn", _instigator] call EFUNC(medical,addDamageToUnit); - } else { - [_unit, 0.15, _woundSelection, "burn", _instigator] call EFUNC(medical,addDamageToUnit); - }; - }; - _unit setVariable [QGVAR(intensity), _intensity, true]; // globally sync intensity across all clients to make sure simulation is deterministic - }; - }; - - private _burnIndicatorPFH = _unit getVariable [QGVAR(burnUIPFH), -1]; - if (_unit isEqualTo ace_player && { _isThisUnitAlive } && { _burnIndicatorPFH < 0 }) then { - _burnIndicatorPFH = [LINKFUNC(burnIndicator), 1, _unit] call CBA_fnc_addPerFrameHandler; - _unit setVariable [QGVAR(burnUIPFH), _burnIndicatorPFH]; - }; - }; -}, 0, [_unit, _intensity, _instigator], { - TRACE_1("burn init",GVAR(enableFlare)); - // init function - private _params = _this getVariable "params"; - _params params ["_unit", "_startingIntensity"]; - - _intensity = _startingIntensity; - private _unitPos = getPos _unit; - - _fireParticle = "#particlesource" createVehicleLocal _unitPos; - _fireParticle attachTo [_unit, [0, 0, 0]]; - _fireParticle setDropInterval 0.03; - - _smokeParticle = "#particlesource" createVehicleLocal _unitPos; - - _fireLight = "#lightpoint" createVehicleLocal _unitPos; - _fireLight setLightIntensity 0; - _fireLight setLightAmbient [0.8, 0.6, 0.2]; - _fireLight setLightColor [1, 0.5, 0.4]; - _fireLight attachTo [_unit, [0, 0, 0]]; - _fireLight setLightDayLight false; - - _lightFlare = "#lightpoint" createVehicleLocal _unitPos; - _lightFlare setLightIntensity 0; - _lightFlare setLightColor [1, 0.8, 0.8]; - _lightFlare setLightUseFlare true; - _lightFlare setLightFlareMaxDistance 100; - _lightFlare setLightFlareSize 0; - - if (_unit isNotEqualTo ace_player) then { - private _relativeAttachPoint = (vectorNormalized (_unit worldToModelVisual (getPos ace_player))) vectorMultiply 1; - _relativeAttachPoint set [2, 0.5]; - _lightFlare attachTo [_unit, _relativeAttachPoint]; - } else { - _lightFlare attachTo [_unit, [0, 0, 0.3]]; - }; - - if (isServer) then { - _fireSound = createSoundSource ["Sound_Fire", _unitPos, [], 0]; - _fireSound attachTo [_unit, [0, 0, 0], "Head"]; - }; - - _unit setVariable [QGVAR(burning), true]; - _unit setVariable [QGVAR(intensity), _intensity]; - _unit setVariable [QGVAR(burnUIPFH), -1]; - - if (local _unit) then { - if (_unit isEqualTo ace_player) then { - private _burnIndicatorPFH = [LINKFUNC(burnIndicator), 1, _unit] call CBA_fnc_addPerFrameHandler; - _unit setVariable [QGVAR(burnUIPFH), _burnIndicatorPFH]; - }; - - [_unit, false] call FUNC(burnReaction); - }; - - _lastIntensityUpdate = 0; - _lastPropogateUpdate = 0; - - _isThisUnitAlive = true; -}, { - (_this getVariable "params") params ["_unit"]; - - // deinit function - deleteVehicle _fireParticle; - deleteVehicle _smokeParticle; - deleteVehicle _fireLight; - deleteVehicle _lightFlare; - deleteVehicle _fireSound; - - if (local _unit) then { - if (!isPlayer _unit) then { - _unit setUnitPos "AUTO"; - _unit setVariable [QGVAR(stopDropRoll), false]; - }; - }; - _unit setVariable [QGVAR(burning), false]; - _unit setVariable [QGVAR(burnCounter), 0]; -}, { - // run condition - true -}, { - // exit condition - (_this getVariable "params") params ["_unit"]; - - private _unitAlive = (alive _unit) && { getNumber ((configOf _unit) >> "isPlayableLogic") != 1 }; - private _unitIsUnit = { (_unit != vehicle _unit) && { isNull vehicle _unit } }; - - !_unitAlive || _unitIsUnit || { _intensity <= BURN_MIN_INTENSITY } || { !([_unit] call FUNC(isBurning)) } -}, ["_intensity", "_fireParticle", "_smokeParticle", "_fireLight", "_fireSound", "_lightFlare", "_lastIntensityUpdate", "_lastPropogateUpdate", "_isThisUnitAlive"]] call CBA_fnc_createPerFrameHandlerObject; +_unit setVariable [QGVAR(jipID), _burnEffectsJipID, true]; diff --git a/addons/fire/functions/fnc_burnEffects.sqf b/addons/fire/functions/fnc_burnEffects.sqf new file mode 100644 index 0000000000..4dadda8526 --- /dev/null +++ b/addons/fire/functions/fnc_burnEffects.sqf @@ -0,0 +1,191 @@ +#include "..\script_component.hpp" +/* + * Author: tcvm, johnb43 + * Spawns particle effects for a burning unit. + * + * Arguments: + * 0: Unit + * + * Return Value: + * None + * + * Example: + * player call ace_fire_fnc_burnEffects + * + * Public: No + */ + +params ["_unit"]; + +// Spawn particles +private _unitPos = getPos _unit; +private _fireParticle = objNull; +private _smokeParticle = objNull; +private _fireLight = objNull; +private _lightFlare = objNull; + +if (hasInterface) then { + _fireParticle = createVehicleLocal ["#particlesource", _unitPos, [], 0, "CAN_COLLIDE"]; + _fireParticle attachTo [_unit]; + _fireParticle setDropInterval 0.03; + + _smokeParticle = createVehicleLocal ["#particlesource", _unitPos, [], 0, "CAN_COLLIDE"]; + + _fireLight = createVehicleLocal ["#lightpoint", _unitPos, [], 0, "CAN_COLLIDE"]; + _fireLight setLightIntensity 0; + _fireLight setLightAmbient [0.8, 0.6, 0.2]; + _fireLight setLightColor [1, 0.5, 0.4]; + _fireLight attachTo [_unit]; + _fireLight setLightDayLight false; + + _lightFlare = createVehicleLocal ["#lightpoint", _unitPos, [], 0, "CAN_COLLIDE"]; + _lightFlare setLightIntensity 0; + _lightFlare setLightColor [1, 0.8, 0.8]; + _lightFlare setLightUseFlare true; + _lightFlare setLightFlareMaxDistance 100; + _lightFlare setLightFlareSize 0; + + if (_unit != ACE_player) then { + private _relativeAttachPoint = vectorNormalized (_unit worldToModelVisual (getPos ACE_player)); + _relativeAttachPoint set [2, 0.5]; + _lightFlare attachTo [_unit, _relativeAttachPoint]; + } else { + _lightFlare attachTo [_unit, [0, 0, 0.3]]; + }; +}; + +private _fireSound = objNull; + +if (isServer) then { + _fireSound = createSoundSource ["Sound_Fire", _unitPos, [], 0]; + _fireSound attachTo [_unit, [0, 0, 0], "Head"]; +}; + +[{ + params ["_args", "_pfhID"]; + _args params ["_unit", "_fireParticle", "_smokeParticle", "_fireLight", "_lightFlare", "_fireSound"]; + + if (isNull _unit || {!(_unit call FUNC(isBurning))}) exitWith { + _pfhID call CBA_fnc_removePerFrameHandler; + + deleteVehicle _fireParticle; + deleteVehicle _smokeParticle; + deleteVehicle _fireLight; + deleteVehicle _lightFlare; + deleteVehicle _fireSound; + }; + + // Display burn indicators + if (_unit == ACE_player && {alive _unit} && {isNil {_unit getVariable QGVAR(burnUIPFH)}}) then { // This accounts for player remote controlled a new unit + private _burnIndicatorPFH = [LINKFUNC(burnIndicator), 1, _unit] call CBA_fnc_addPerFrameHandler; + _unit setVariable [QGVAR(burnUIPFH), _burnIndicatorPFH]; + }; + + if (!hasInterface) exitWith {}; + + private _intensity = _unit getVariable [QGVAR(intensity), 0]; + + _fireParticle setDropInterval (0.01 max linearConversion [BURN_MAX_INTENSITY, BURN_MIN_INTENSITY, _intensity, 0.03, 0.1, false]); + _fireParticle setParticleParams [ + ["\A3\data_f\ParticleEffects\Universal\Universal", 16, 10, 32], // sprite sheet values + "", // animation name + "Billboard", // particle type + 1, // timer period + 0.7, // lifetime + "destructionEffect2", // position + [0, 0, 1], // move velocity + 0, // rotation velocity + 10, // weight + 7.9, // volume + 1, // rubbing + [0.3, 0.3], // size + [ + [1, 1, 1, -0], + [1, 1, 1, -1], + [1, 1, 1, -1], + [1, 1, 1, -1], + [1, 1, 1, -0] + ], // colour + [0.5, 1], // animation speed + 1, // random dir period + 0, // random dir intensity + "", // on timer script + "", // before destroy script + _unit, // particle source + 0, + false, + 0, + [[0.8, 0.6, 0.2, 1]] // emissive color + ]; + _fireParticle setParticleRandom [ + 0.04 * _intensity, // life time + [0.05, 0.05, 2], // position + [0.05, 0.05, 0.05] vectorMultiply _intensity, // move velocity + 0, // rotation velocity + 0.06 * _intensity, // size + [0, 0, 0, 0], // color + 0, // random direction period + 0 // random direction intensity + ]; + + _smokeParticle setDropInterval 0.15; + _smokeParticle setParticleCircle [0, [0, 0, 0]]; + _smokeParticle setParticleParams [ + ["\A3\data_f\ParticleEffects\Universal\Universal", 16, 7, 48], // sprite sheet values + "", // animation name + "Billboard", // particle type + 1, // timer period + 8, // lifetime + [0, 0, 1.1], // position + [0, 0, 1], // move velocity + 0, // rotation velocity + 10, // weight + 7.9, // volume + 0.066, // rubbing + [1, 3, 6], // size + [ + [0.5, 0.5, 0.5, 0.15], + [0.75, 0.75, 0.75, 0.075], + [1, 1, 1, 0] + ], // colour + [0.125], // animation speed + 1, // random dir period + 0, // random dir intensity + "", // on timer script + "", // before destroy script + _unit // particle source + ]; + _smokeParticle setParticleRandom [ + 0, // life time + [0.25, 0.25, 0], // position + [0.2, 0.2, 0], // move velocity + 0, // rotation velocity + 0.25, // size + [0, 0, 0, 0.1], // color + 0, // random direction period + 0 // random direction intensity + ]; + + _fireLight setLightBrightness ((_intensity * 3) / 10); + _fireLight setLightAttenuation [1, 10 max (5 min (10 - _intensity)), 0, 15]; + + _lightFlare setLightBrightness (_intensity / 30); + _lightFlare setLightFlareSize (_intensity * (3 / 4)) * FLARE_SIZE_MODIFIER; + + if (!GVAR(enableFlare)) then { + _lightFlare setLightFlareSize 0; + }; + + // Always keep flare visible to perceiving unit as long as it isn't the player + if (_unit != ACE_player) then { + private _distanceToUnit = _unit distance ACE_player; + private _relativeAttachPoint = [0, 0, 0.3]; + + if (_distanceToUnit > 1.5) then { + _relativeAttachPoint = (vectorNormalized (_unit worldToModelVisual (getPos ACE_player))) vectorMultiply linearConversion [5, 30, _distanceToUnit, 0.5, 1.5]; + _relativeAttachPoint set [2, 0.3 + ((_unit selectionPosition "pelvis") select 2)]; + }; + + _lightFlare attachTo [_unit, _relativeAttachPoint]; + }; +}, 0, [_unit, _fireParticle, _smokeParticle, _fireLight, _lightFlare, _fireSound]] call CBA_fnc_addPerFrameHandler; diff --git a/addons/fire/functions/fnc_burnIndicator.sqf b/addons/fire/functions/fnc_burnIndicator.sqf index d876d18a07..5dbc1a8cbf 100644 --- a/addons/fire/functions/fnc_burnIndicator.sqf +++ b/addons/fire/functions/fnc_burnIndicator.sqf @@ -11,26 +11,30 @@ * None * * Example: - * [player, 4] call ace_fire_fnc_burnIndicator + * [player, _pfhID] call ace_fire_fnc_burnIndicator * * Public: No */ -params ["_unit", "_pfhHandle"]; +params ["_unit", "_pfhID"]; -if !(IS_UNCONSCIOUS(_unit)) then { - private _iteration = _unit getVariable [QGVAR(indicatorIteration), 0]; - if (_iteration == 0) then { - QGVAR(indicatorLayer) cutRsc [QGVAR(onFire1), "PLAIN"]; - _iteration = 1; - } else { - QGVAR(indicatorLayer) cutRsc [QGVAR(onFire2), "PLAIN"]; - _iteration = 0; - }; - _unit setVariable [QGVAR(indicatorIteration), _iteration]; +if (!alive _unit || {!(_unit call FUNC(isBurning))}) exitWith { + _pfhID call CBA_fnc_removePerFrameHandler; + + _unit setVariable [QGVAR(burnUIPFH), nil]; }; -if (!([_unit] call FUNC(isBurning)) || {!alive _unit}) then { - [_pfhHandle] call CBA_fnc_removePerFrameHandler; - _unit setVariable [QGVAR(burnUIPFH), -1]; +// Don't show burn overlay if unconscious or dead +if !(_unit call EFUNC(common,isAwake)) exitWith {}; + +private _iteration = _unit getVariable [QGVAR(indicatorIteration), 0]; + +if (_iteration == 0) then { + QGVAR(indicatorLayer) cutRsc [QGVAR(onFire1), "PLAIN"]; + _iteration = 1; +} else { + QGVAR(indicatorLayer) cutRsc [QGVAR(onFire2), "PLAIN"]; + _iteration = 0; }; + +_unit setVariable [QGVAR(indicatorIteration), _iteration]; diff --git a/addons/fire/functions/fnc_burnReaction.sqf b/addons/fire/functions/fnc_burnReaction.sqf index 748fbbd60e..5a9b75d48c 100644 --- a/addons/fire/functions/fnc_burnReaction.sqf +++ b/addons/fire/functions/fnc_burnReaction.sqf @@ -5,7 +5,6 @@ * * Arguments: * 0: Unit - * 1: Should unit throw its current weapon * * Return Value: * None @@ -13,19 +12,15 @@ * Public: No */ -params ["_unit", ["_throwWeapon", true]]; +params ["_unit"]; if ( - _throwWeapon - && {GVAR(dropWeapon) > 0} - && {_unit in _unit && {(currentWeapon _unit) isNotEqualTo ""}} - && {!isPlayer _unit || GVAR(dropWeapon) >= 2} + GVAR(dropWeapon) > 0 && + {isNull objectParent _unit} && + {(currentWeapon _unit) != ""} && + {!isPlayer _unit || GVAR(dropWeapon) == 2} ) then { - [_unit] call EFUNC(common,throwWeapon); + _unit call EFUNC(common,throwWeapon); }; -if (_unit isKindOf "CAManBase") then { - private _soundID = floor (1 + random 15); - private _sound = format [QGVAR(scream_%1), _soundID]; - [QGVAR(playScream), [_sound, _unit]] call CBA_fnc_globalEvent; -}; +[QGVAR(playScream), [format [QGVAR(scream_%1), floor (1 + random 15)], _unit]] call CBA_fnc_globalEvent; diff --git a/addons/fire/functions/fnc_burnSimulation.sqf b/addons/fire/functions/fnc_burnSimulation.sqf new file mode 100644 index 0000000000..b50afab5dc --- /dev/null +++ b/addons/fire/functions/fnc_burnSimulation.sqf @@ -0,0 +1,167 @@ +#include "..\script_component.hpp" +/* + * Author: tcvm, johnb43 + * Simulates fire intensity over time on burning units. + * Arbitrary values to ignite people. Assumed maximum is "10". + * + * Arguments: + * 0: Unit + * 1: Instigator + * + * Return Value: + * None + * + * Example: + * [player, player] call ace_fire_fnc_burnSimulation + * + * Public: No + */ + +params ["_unit", "_instigator"]; + +[{ + params ["_args", "_pfhID"]; + _args params ["_unit", "_instigator"]; + + if (isNull _unit) exitWith { + TRACE_1("unit is null",_unit); + + _pfhID call CBA_fnc_removePerFrameHandler; + }; + + // Locality has changed + if (!local _unit) exitWith { + TRACE_1("unit is no longer local",_unit); + + _pfhID call CBA_fnc_removePerFrameHandler; + + [QGVAR(burnSimulation), [_unit, _instigator], _unit] call CBA_fnc_targetEvent; + }; + + // If the unit is invulnerable, in water or if the fire has died out, stop burning the unit + if ( + !(_unit call FUNC(isBurning)) || + {!(isDamageAllowed _unit && {_unit getVariable [QEGVAR(medical,allowDamage), true]})} || + {private _eyePos = eyePos _unit; surfaceIsWater _eyePos && {(_eyePos select 2) < 0.1}} + ) exitWith { + TRACE_3("unit is no longer burning, invulnerable or in water",_unit,_unit call FUNC(isBurning),isDamageAllowed _unit && {_unit getVariable [ARR_2(QEGVAR(medical,allowDamage),true)]}); + + // Remove global effects + (_unit getVariable [QGVAR(jipID), ""]) call CBA_fnc_removeGlobalEventJIP; + + // Update globally that the unit isn't burning anymore + _unit setVariable [QGVAR(intensity), nil, true]; + + _pfhID call CBA_fnc_removePerFrameHandler; + + if (!isNil {_unit getVariable QGVAR(stopDropRoll)} && {!isPlayer _unit}) then { + _unit setUnitPos "AUTO"; + + _unit setVariable [QGVAR(stopDropRoll), nil, true]; + }; + }; + + if (isGamePaused) exitWith {}; + + private _intensity = _unit getVariable [QGVAR(intensity), 0]; + + // Propagate fire to other units (alive or dead) if it's intense + if (_intensity >= BURN_THRESHOLD_INTENSE) then { + TRACE_2("check for other units",_unit,_intensity); + + { + private _distancePercent = 1 - ((_unit distance _x) / BURN_PROPAGATE_DISTANCE); + private _adjustedIntensity = _intensity * _distancePercent; + + // Don't burn if intensity is too low or already burning with higher intensity + if (BURN_MIN_INTENSITY > _adjustedIntensity || {(_x getVariable [QGVAR(intensity), 0]) > _adjustedIntensity}) then { + continue; + }; + + [QGVAR(burn), [_x, _adjustedIntensity, _instigator], _x] call CBA_fnc_targetEvent; + + TRACE_3("propagate fire",_x,_intensity,_adjustedIntensity); + } forEach nearestObjects [_unit, ["CAManBase"], BURN_PROPAGATE_DISTANCE]; + }; + + // Update intensity/fire reactions + if (CBA_missionTime >= _unit getVariable [QGVAR(intensityUpdate), 0]) then { + TRACE_2("update intensity",_unit,_intensity); + + _unit setVariable [QGVAR(intensityUpdate), CBA_missionTime + INTENSITY_UPDATE]; + + _intensity = _intensity - INTENSITY_LOSS - (rain / 10); + + if (_unit call EFUNC(common,isAwake)) then { + if (_unit call EFUNC(common,isPlayer)) then { + // Decrease intensity of burn if rolling around + if ((animationState _unit) in PRONE_ROLLING_ANIMS) then { + _intensity = _intensity * INTENSITY_DECREASE_MULT_ROLLING; + }; + } else { + private _sdr = _unit getVariable [QGVAR(stopDropRoll), false]; + + private _vehicle = objectParent _unit; + + if (isNull _vehicle && {_sdr || {0.05 > random 1}}) then { + _unit setVariable [QGVAR(stopDropRoll), true, true]; + + if (!_sdr) then { + TRACE_1("stop, drop, roll!",_unit); + + _unit setUnitPos "DOWN"; + doStop _unit; + }; + + // Queue up a bunch of animations + for "_i" from 0 to 2 do { + [_unit, selectRandom ["amovppnemstpsnonwnondnon_amovppnemevasnonwnondl", "amovppnemstpsnonwnondnon_amovppnemevasnonwnondr"], 0] call EFUNC(common,doAnimation); + }; + + _intensity = _intensity - (1 / _intensity); + } else { + // Make the unit leave the vehicle + if (_vehicle != _unit) then { + TRACE_1("Ejecting",_unit); + + _unit leaveVehicle _vehicle; + unassignVehicle _unit; + + _unit action ["Eject", _vehicle]; + }; + + _unit disableAI "TARGET"; + _unit disableAI "AUTOTARGET"; + + // Run away, erraticly + if (leader group _unit != _unit) then { + [_unit] join grpNull; + }; + + _unit doMove ((getPosATL _unit) getPos [20 + random 35, floor (random 360)]); + _unit setSpeedMode "FULL"; + _unit setSuppression 1; + }; + }; + + // Play screams and throw weapon (if enabled) + _unit call FUNC(burnReaction); + }; + + if (!isNull _instigator) then { + _unit setVariable [QEGVAR(medical,lastDamageSource), _instigator]; + _unit setVariable [QEGVAR(medical,lastInstigator), _instigator]; + }; + + // Common burn areas are the hands and face https://www.ncbi.nlm.nih.gov/pubmed/16899341/ + private _bodyPart = ["Head", "Body", "LeftArm", "RightArm", "LeftLeg", "RightLeg"] selectRandomWeighted [0.77, 0.5, 0.8, 0.8, 0.3, 0.3]; + + // Keep pain around unconciousness limit to allow for more fun interactions + private _damageToAdd = [0.15, _intensity / BURN_MAX_INTENSITY] select (!alive _unit || {GET_PAIN_PERCEIVED(_unit) < (PAIN_UNCONSCIOUS + random 0.2)}); + + // Use event directly, as ace_medical_fnc_addDamageToUnit requires unit to be alive + [QEGVAR(medical,woundReceived), [_unit, [[_damageToAdd, _bodyPart, _damageToAdd]], _instigator, "burn"]] call CBA_fnc_localEvent; + + _unit setVariable [QGVAR(intensity), _intensity, true]; // Globally sync intensity across all clients to make sure simulation is deterministic + }; +}, BURN_PROPAGATE_UPDATE, [_unit, _instigator]] call CBA_fnc_addPerFrameHandler; diff --git a/addons/fire/functions/fnc_fireManagerPFH.sqf b/addons/fire/functions/fnc_fireManagerPFH.sqf index fa8e7fb789..924279e3c8 100644 --- a/addons/fire/functions/fnc_fireManagerPFH.sqf +++ b/addons/fire/functions/fnc_fireManagerPFH.sqf @@ -1,43 +1,48 @@ #include "..\script_component.hpp" /* - * Author: tcvm - * Handles various fire objects and determines if local units deserves to get burned. - * Used to handle external burning objects, not used internally because internal methods are more performant. + * Author: tcvm, johnb43 + * Handles various objects on fire and determines if units close to objects deserve to get burned. * * Arguments: - * 0: Unit on fire - * 1: PFH Handle + * None * * Return Value: * None * * Example: - * [ace_fire_fnc_fireManagerPFH, 0.25, [_unit]] call CBA_fnc_addPerFrameHandler + * ace_fire_fnc_fireManagerPFH call CBA_fnc_addPerFrameHandler * * Public: No */ -params ["_args", "_handle"]; +{ + _y params ["_fireLogic", "_radius", "_intensity", "_condition", "_conditionArgs"]; + TRACE_2("fireManagerPFH loop",_x,_y); -[GVAR(fireSources), { - _value params ["", "", "", "_condition", "_conditionArgs"]; - _conditionArgs call _condition; -}] call CBA_fnc_hashFilter; + // Remove when condition is no longer valid + if !(_conditionArgs call _condition) then { + TRACE_2("condition no longer valid, deleting",_x,_y); -[GVAR(fireSources), { - _value params ["_source", "_radius", "_intensity"]; - private _attachedObject = attachedTo _source; - private _sourcePos = getPosATL _source; - if (_attachedObject isNotEqualTo objNull) then { - _sourcePos = getPosATL _attachedObject; + detach _fireLogic; + deleteVehicle _fireLogic; + + GVAR(fireSources) deleteAt _x; + + continue; }; - private _nearEntities = _sourcePos nearEntities ["Man", _radius]; + // Burn units (alive or dead) close to the fire { - private _burning = [_x] call FUNC(isBurning); - if !(_burning) then { - private _distancePercent = 1 - ((_sourcePos distance _x) / _radius); - [QGVAR(burn), [_x, _intensity * _distancePercent]] call CBA_fnc_globalEvent; + private _distancePercent = 1 - ((_fireLogic distance _x) / _radius); + private _adjustedIntensity = _intensity * _distancePercent; + + // Don't burn if intensity is too low or already burning with higher intensity + if (BURN_MIN_INTENSITY > _adjustedIntensity || {(_x getVariable [QGVAR(intensity), 0]) > _adjustedIntensity}) then { + continue; }; - } forEach _nearEntities; -}] call CBA_fnc_hashEachPair; + + [QGVAR(burn), [_x, _adjustedIntensity], _x] call CBA_fnc_targetEvent; + + TRACE_3("propagate fire",_x,_intensity,_adjustedIntensity); + } forEach nearestObjects [_fireLogic, ["CAManBase"], _radius]; +} forEach GVAR(fireSources); diff --git a/addons/fire/functions/fnc_isBurning.sqf b/addons/fire/functions/fnc_isBurning.sqf index 7cc06dc01d..04a57c29e6 100644 --- a/addons/fire/functions/fnc_isBurning.sqf +++ b/addons/fire/functions/fnc_isBurning.sqf @@ -1,10 +1,10 @@ #include "..\script_component.hpp" /* * Author: commy2 - * Check if object is burning. + * Check if an object is burning. * * Arguments: - * 0: Vehicle + * 0: Object * * Return Value: * None @@ -15,6 +15,6 @@ * Public: Yes */ -params [["_unit", objNull, [objNull]]]; +params [["_object", objNull, [objNull]]]; -_unit getVariable [QGVAR(burning), false] +(_object getVariable [QGVAR(intensity), 0]) > BURN_MIN_INTENSITY diff --git a/addons/fire/functions/fnc_medical_canPatDown.sqf b/addons/fire/functions/fnc_medical_canPatDown.sqf index b7efc262b2..758b83b922 100644 --- a/addons/fire/functions/fnc_medical_canPatDown.sqf +++ b/addons/fire/functions/fnc_medical_canPatDown.sqf @@ -18,4 +18,4 @@ params ["", "_patient"]; -[_patient] call FUNC(isBurning) +_patient call FUNC(isBurning) diff --git a/addons/fire/functions/fnc_medical_progress.sqf b/addons/fire/functions/fnc_medical_progress.sqf index 07d99958d6..fd64b5c27d 100644 --- a/addons/fire/functions/fnc_medical_progress.sqf +++ b/addons/fire/functions/fnc_medical_progress.sqf @@ -5,8 +5,8 @@ * * Arguments: * 0: Arguments - * 0: Medic - * 1: Patient + * - 0: Medic (not used) + * - 1: Patient * * Return Value: * Continue pat down @@ -18,6 +18,6 @@ */ params ["_args"]; -_args params ["_medic", "_patient"]; +_args params ["", "_patient"]; -[_patient] call FUNC(isBurning) +_patient call FUNC(isBurning) diff --git a/addons/fire/functions/fnc_medical_success.sqf b/addons/fire/functions/fnc_medical_success.sqf index 78e119a8fa..ca569e1280 100644 --- a/addons/fire/functions/fnc_medical_success.sqf +++ b/addons/fire/functions/fnc_medical_success.sqf @@ -2,10 +2,13 @@ /* * Author: tcvm * Decreases burning intensity on successful medical action. + * The medical action is looped until the user stops the interaction or the unit is no longer burning. * * Arguments: * 0: Medic * 1: Patient + * 2: Body Part + * 3: Treatment * * Return Value: * None @@ -20,17 +23,21 @@ params ["_medic", "_patient", "_bodyPart", "_classname"]; private _intensity = _patient getVariable [QGVAR(intensity), 0]; _intensity = _intensity * INTENSITY_DECREASE_MULT_PAT_DOWN; + _patient setVariable [QGVAR(intensity), _intensity, true]; -if (_intensity > BURN_MIN_INTENSITY) then { - TRACE_1("patient still burning, looping",_this); - - if (EGVAR(medical_gui,pendingReopen)) then { - LOG("temporarily blocking medical menu reopen"); - - EGVAR(medical_gui,pendingReopen) = false; - [{EGVAR(medical_gui,pendingReopen) = true}] call CBA_fnc_execNextFrame; - }; - - [_medic, _patient, _bodyPart, _classname] call EFUNC(medical_treatment,treatment); +// If the unit is still burning, loop the medical action +if !(_patient call FUNC(isBurning)) exitWith { + TRACE_1("patient no longer burning, quitting",_this); }; + +TRACE_1("patient still burning, looping",_this); + +if (EGVAR(medical_gui,pendingReopen)) then { + TRACE_1("temporarily blocking medical menu reopen",_this); + + EGVAR(medical_gui,pendingReopen) = false; + [{EGVAR(medical_gui,pendingReopen) = true}] call CBA_fnc_execNextFrame; +}; + +[_medic, _patient, _bodyPart, _classname] call EFUNC(medical_treatment,treatment); diff --git a/addons/fire/initSettings.inc.sqf b/addons/fire/initSettings.inc.sqf index 97963f3e32..edcd51a8a7 100644 --- a/addons/fire/initSettings.inc.sqf +++ b/addons/fire/initSettings.inc.sqf @@ -1,40 +1,40 @@ [ - QGVAR(enabled), "CHECKBOX", + QGVAR(enabled), + "CHECKBOX", [ELSTRING(common,Enabled), LSTRING(Setting_Description)], LSTRING(Category_DisplayName), - true, // default value - true, // isGlobal + true, + 1, {[QGVAR(fireEnabled), _this] call EFUNC(common,cbaSettings_settingChanged)}, true // Needs mission restart ] call CBA_fnc_addSetting; [ - QGVAR(enableFlare), "CHECKBOX", + QGVAR(enableFlare), + "CHECKBOX", [LSTRING(Setting_FlareEnable), LSTRING(Setting_FlareDescription)], LSTRING(Category_DisplayName), - false, // default value - true, // isGlobal - {[QGVAR(flareEnabled), _this] call EFUNC(common,cbaSettings_settingChanged)}, - true // Needs mission restart + false, + 1 ] call CBA_fnc_addSetting; [ - QGVAR(dropWeapon), "LIST", + QGVAR(dropWeapon), + "LIST", [LSTRING(Setting_DropWeapon), LSTRING(Setting_DropWeapon_Description)], LSTRING(Category_DisplayName), [ - [0,1,2], - [localize "STR_A3_OPTIONS_DISABLED", ELSTRING(common,aiOnly), ELSTRING(common,playersAndAI)], + [0, 1, 2], + ["STR_A3_OPTIONS_DISABLED", ELSTRING(common,aiOnly), ELSTRING(common,playersAndAI)], 1 ], - true // isGlobal + 1 ] call CBA_fnc_addSetting; [ - QGVAR(enableScreams), "CHECKBOX", + QGVAR(enableScreams), + "CHECKBOX", [LSTRING(Setting_EnableScreams), LSTRING(Setting_EnableScreams_Description)], LSTRING(Category_DisplayName), - true, - false // isGlobal + true ] call CBA_fnc_addSetting; - diff --git a/addons/fire/script_component.hpp b/addons/fire/script_component.hpp index 86ef159aae..ebb0002ff6 100644 --- a/addons/fire/script_component.hpp +++ b/addons/fire/script_component.hpp @@ -31,9 +31,14 @@ "amovppnemstpsoptwbindnon_amovppnemevasoptwbindr"\ ] - #define BURN_MAX_INTENSITY 10 #define BURN_MIN_INTENSITY 1 #define INTENSITY_DECREASE_MULT_PAT_DOWN 0.8 #define INTENSITY_DECREASE_MULT_ROLLING INTENSITY_DECREASE_MULT_PAT_DOWN + +#define INTENSITY_LOSS 0.02 +#define INTENSITY_UPDATE 2 +#define BURN_PROPAGATE_UPDATE 1 +#define BURN_PROPAGATE_DISTANCE 2 +#define BURN_THRESHOLD_INTENSE 3 diff --git a/addons/zeus/functions/fnc_moduleBurn.sqf b/addons/zeus/functions/fnc_moduleBurn.sqf index 4cf2017b67..9fb3b085af 100644 --- a/addons/zeus/functions/fnc_moduleBurn.sqf +++ b/addons/zeus/functions/fnc_moduleBurn.sqf @@ -17,26 +17,22 @@ params ["_logic"]; -if !(local _logic) exitWith {}; +if (!local _logic) exitWith {}; private _unit = attachedTo _logic; deleteVehicle _logic; switch (false) do { - case !(isNull _unit): { + case (!isNull _unit): { [LSTRING(NothingSelected)] call FUNC(showMessage); }; - case (_unit isKindOf "CAManBase"): { + case (_unit isKindOf "CAManBase" && {getNumber (configOf _unit >> "isPlayableLogic") == 0}): { [LSTRING(OnlyInfantry)] call FUNC(showMessage); }; - case (alive _unit): { - [LSTRING(OnlyAlive)] call FUNC(showMessage); - }; case (["ace_fire"] call EFUNC(common,isModLoaded)): { [LSTRING(RequiresAddon)] call FUNC(showMessage); }; default { - [QEGVAR(fire,burn), [_unit, 5]] call CBA_fnc_globalEvent; + [QEGVAR(fire,burn), [_unit, 5], _unit] call CBA_fnc_targetEvent; }; }; - diff --git a/docs/wiki/framework/fire-framework.md b/docs/wiki/framework/fire-framework.md index 7994036ece..147710384c 100644 --- a/docs/wiki/framework/fire-framework.md +++ b/docs/wiki/framework/fire-framework.md @@ -26,8 +26,8 @@ Use `CBA_fnc_serverEvent` to use the following features. Events are defined only | 0 | Source of flame | Object/Position ASL | Required | | 1 | Radius of fire | Number | Required | | 2 | Intensity of fire (1, 10] | Number | Required | -| 3 | Fire source ID | Any | Required | -| 4 | Condition to stop fire | Code | Optional (default: `{ true }`) | +| 3 | Fire source ID | Array/Boolean/Code/Config/Group/Namespace/NaN/Number/Object/Side/String | Required | +| 4 | Condition to stop fire | Code | Optional (default: `{true}`) | | 5 | Arguments to pass to condition | Any | Optional (default: `[]`) | ### 1.2 Removing fire source @@ -36,8 +36,7 @@ Use `CBA_fnc_serverEvent` to use the following features. Events are defined only | | Arguments | Type | Optional (default value) | |----| --------- | ---- | ------------------------ | -| 0 | Fire source ID | Any | Required | - +| 0 | Fire source ID | Array/Boolean/Code/Config/Group/Namespace/NaN/Number/Object/Side/String | Required | ## 2. Variables From 56016a48165f76262231fa9a564a8da392865741 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 22 Jun 2024 20:08:43 +0200 Subject: [PATCH 113/290] Vehicle Damage - Add turret tossing again (#9989) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jouni Järvinen --- addons/vehicle_damage/XEH_postInit.sqf | 24 +++++-------------- .../functions/fnc_blowOffTurret.sqf | 15 ++++++------ 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/addons/vehicle_damage/XEH_postInit.sqf b/addons/vehicle_damage/XEH_postInit.sqf index 43050086d8..9784d335ed 100644 --- a/addons/vehicle_damage/XEH_postInit.sqf +++ b/addons/vehicle_damage/XEH_postInit.sqf @@ -31,26 +31,14 @@ ["Car", "init", LINKFUNC(addEventHandler), true, [], true] call CBA_fnc_addClassEventHandler; }; - // blow off turret effect - /* - Disabled temporarily due to issues with being able to repair tanks after death. Needs work - */ - /*["Tank", "killed", { - if (random 1 < 0.15) then { + // Blow off turret effect + // TODO: Add blowing-off-turret effect to vehicles that cook-off but aren't destroyed (no catastrophic explosion) + // The problem is that vehicles are repairable if they haven't been destroyed. So if the turret is gone and vehicle is repaired, how do we handle that? + ["Tank", "Killed", { + if (_this select 3 && random 1 < 0.15) then { (_this select 0) call FUNC(blowOffTurret); }; - }, true, [], true] call CBA_fnc_addClassEventHandler;*/ - - // event to add a turret to a curator if the vehicle already belonged to that curator - if (isServer) then { - [QGVAR(addTurretToEditable), { - params ["_vehicle", "_turret"]; - - { - _x addCuratorEditableObjects [[_turret], false]; - } forEach (objectCurators _vehicle); - }] call CBA_fnc_addEventHandler; - }; + }, true, [], true] call CBA_fnc_addClassEventHandler; }; // init eject from destroyed vehicle diff --git a/addons/vehicle_damage/functions/fnc_blowOffTurret.sqf b/addons/vehicle_damage/functions/fnc_blowOffTurret.sqf index a036f0045b..818fe6f6ef 100644 --- a/addons/vehicle_damage/functions/fnc_blowOffTurret.sqf +++ b/addons/vehicle_damage/functions/fnc_blowOffTurret.sqf @@ -4,7 +4,7 @@ * Blow off turret effect. * * Arguments: - * 0: Vehicle + * 0: Vehicle * * Return Value: * None @@ -15,13 +15,12 @@ * Public: No */ -// delayed so the object is spawned after the model changes to a wreck -// the sudden change in the model would cause nearby physx objects to get stuck +// Delayed so the object is spawned after the model changes to a wreck +// The sudden change in the model would cause nearby PhysX objects to get stuck [{ params ["_vehicle"]; - private _config = _vehicle call CBA_fnc_getObjectConfig; - getArray (_config >> QGVAR(turret)) params [["_model", "", [""]], ["_offset", [0,0,0], [[]], 3]]; + (getArray (configOf _vehicle >> QGVAR(turret))) params [["_model", "", [""]], ["_offset", [0, 0, 0], [[]], 3]]; if (_model isEqualTo "") exitWith {}; @@ -31,6 +30,8 @@ _turret setVectorUp [random 1, random 1, 1]; _turret setVelocity [random 7, random 7, 8 + random 5]; - // add turret to all curators that already own the wreck - [QGVAR(addTurretToEditable), [_vehicle, _turret]] call CBA_fnc_serverEvent; + // Add turret to all curators that already own the wreck + if (["ace_zeus"] call EFUNC(common,isModLoaded)) then { + [QEGVAR(zeus,addObjects), [[_turret], objectCurators _vehicle]] call CBA_fnc_serverEvent; + }; }, _this, 1] call CBA_fnc_waitAndExecute; From c9e82afff7be06e1429577812b93dbea710999d2 Mon Sep 17 00:00:00 2001 From: Psycool <104776717+Psycool3695@users.noreply.github.com> Date: Sun, 23 Jun 2024 04:47:23 +0900 Subject: [PATCH 114/290] Korean translation updated (#10077) * KoreanTranslation Someone has returned all the translations in Korean to English. there is no need to return them. * koreantranslation * Korean Typo Fix * Korean Translation * Update stringtable.xml * Korean Translation Added Added Korean translation related to Cargo Refuel * Merge branch 'master' of https://github.com/Psycool3695/ACE3 * Korean translation Add/Updated * Fixed wrong strings * Korean translation improved * Korean translation updated * Korean translation updated * Fix Merge * Update stringtable.xml * Update stringtable.xml * Korean translation updated * Korean translation minor fix * Korean translation fixed * Korean translation updated * Update stringtable.xml * Spacing fixed * Korean translation updated * Spacing fixed * Korean translation updated * Korean translation updated --------- Co-authored-by: PabstMirror --- .../compat_rf_realisticnames/stringtable.xml | 75 +++++++++++++++++++ .../compat_ws_realisticnames/stringtable.xml | 40 ++++++++++ addons/cookoff/stringtable.xml | 22 ++++-- addons/grenades/stringtable.xml | 3 +- addons/hearing/stringtable.xml | 1 + addons/hitreactions/stringtable.xml | 2 + addons/medical_treatment/stringtable.xml | 16 ++-- addons/realisticnames/stringtable.xml | 9 +++ addons/zeus/stringtable.xml | 7 ++ 9 files changed, 163 insertions(+), 12 deletions(-) diff --git a/addons/compat_rf/compat_rf_realisticnames/stringtable.xml b/addons/compat_rf/compat_rf_realisticnames/stringtable.xml index e2ccac3c30..6d77333cda 100644 --- a/addons/compat_rf/compat_rf_realisticnames/stringtable.xml +++ b/addons/compat_rf/compat_rf_realisticnames/stringtable.xml @@ -4,214 +4,267 @@ EOTech MRDS (Khaki) EOTech MRDS (カーキ) + 이오텍 MRDS (카키) EOTech MRDS (Tan) EOTech MRDS (タン) + 이오텍 MRDS (황갈) C-More Railway (Green, Desert) C-More レイルウェイ (グリーン、砂漠迷彩) + 씨모어 레일웨이 (녹색, 사막) C-More Railway (Green, Woodland) C-More レイルウェイ (グリーン、森林迷彩) + 씨모어 레일웨이 (녹색, 수풀 위장) C-More Railway (Red, Desert) C-More レイルウェイ (グリーン、砂漠迷彩) + 씨모어 레일웨이 (빨강, 사막) C-More Railway (Red, Woodland) C-More レイルウェイ (グリーン、森林迷彩) + 씨모어 레일웨이 (빨강, 수풀) Aimpoint Micro R-1 Aimpoint マイクロ R-1 + 에임포인트 마이크로 R-1 Vortex Spitfire Prism Vortex スピットファイア プリズム + 버텍스 스핏파이어 프리즘 Vortex Spitfire Prism (Tan) Vortex スピットファイア プリズム (タン) + 버텍스 스핏파이어 프리즘 (황갈) Vortex Spitfire Prism (Khaki) Vortex スピットファイア プリズム (カーキ) + 버텍스 스핏파이어 프리즘 (카키) Vortex Spitfire Prism (Pistol) Vortex スピットファイア プリズム (ピストル用) + 버텍스 스핏파이어 프리즘 (권총용) Glock 19X グロック 19X + 글록 19X Glock 19X (Khaki) グロック 19X (カーキ) + 글록 19X (카키) Glock 19X (Tan) グロック 19X (タン) + 글록 19X (황갈) Glock 19X Auto グロック 19X オート + 글록 19X 기관권총 Glock 19X Auto (Khaki) グロック 19X オート (カーキ) + 글록 19X 기관권총 (카키) Glock 19X Auto (Tan) グロック 19X オート (タン) + 글록 19X 기관권총 (황갈) Desert Eagle Mark XIX L5 デザートイーグル Mark XIX L5 + 데저트 이글 마크 XIX L5 Desert Eagle Mark XIX L5 (Classic) デザートイーグル Mark XIX L5 (クラシック) + 데저트 이글 마크 XIX L5 (클래식) Desert Eagle Mark XIX L5 (Bronze) デザートイーグル Mark XIX L5 (ブロンズ) + 데저트 이글 마크 XIX L5 (브론즈) Desert Eagle Mark XIX L5 (Copper) デザートイーグル Mark XIX L5 (カッパー) + 데저트 이글 마크 XIX L5 (구리) Desert Eagle Mark XIX L5 (Gold) デザートイーグル Mark XIX L5 (ゴールド) + 데저트 이글 마크 XIX L5 (금색) HERA H6 (Tan) HERA H6 (タン) + 헤라 H6 (황갈) HERA H6 (Olive) HERA H6 (オリーブ) + 헤라 H6 (올리브) HERA H6 (Black) HERA H6 (ブラック) + 헤라 H6 (검정) HERA H6 (Digital) HERA H6 (AAF迷彩) + 헤라 H6 (AAF 디지털) HERA H6 (Gold) HERA H6 (ゴールド) + 헤라 H6 (금색) VS-121 (Black) VS-121 (ブラック) + VS-121 (검정) VS-121 (Tan) VS-121 (タン) + VS-121 (황갈) Vector SMG (Black) ベクター SMG (ブラック) + 벡터 SMG (검정) ASh-12 (Black) ASh-12 (ブラック) + ASh-12 (검정) ASh-12 (Desert) ASh-12 (砂漠迷彩) + ASh-12 (사막) ASh-12 (Urban) ASh-12 (市街地迷彩) + ASh-12 (도심) ASh-12 (Woodland) ASh-12 (森林迷彩) + ASh-12 (수풀) ASh-12 GL (Black) ASh-12 GL (ブラック) + ASh-12 GL (검정) ASh-12 GL (Desert) ASh-12 GL (砂漠迷彩) + ASh-12 GL (사막) ASh-12 GL (Urban) ASh-12 GL (市街地迷彩) + ASh-12 GL (도심) ASh-12 GL (Woodland) ASh-12 GL (森林迷彩) + ASh-12 GL (수풀) ASh-12 LR (Black) ASh-12 LR (ブラック) + ASh-12 LR (검정) ASh-12 LR (Desert) ASh-12 LR (砂漠迷彩) + ASh-12 LR (사막) ASh-12 LR (Urban) ASh-12 LR (市街地迷彩) + ASh-12 LR (도심) ASh-12 LR (Woodland) ASh-12 LR (森林迷彩) + ASh-12 LR (수풀) AW159 Wildcat ASW AW159 ワイルドキャット ASW + AW159 와일드캣 ASW AW159 Wildcat ASW (Unarmed) AW159 ワイルドキャット ASW (非武装) + AW159 와일드캣 ASW (비무장) H225 Super Puma (Transport) H225 シュペル ピューマ (輸送型) + H225 슈퍼 퓨마 (비무장) H225 Super Puma (Civilian) H225 シュペル ピューマ (民生型) + H225 슈퍼 퓨마 (비무장) H215 Super Puma (Transport) H215 シュペル ピューマ (輸送型) + H215 슈퍼 퓨마 (비무장) H215 Super Puma (Civilian) H215 シュペル ピューマ (民生型) + H215 슈퍼 퓨마 (비무장) H215 Super Puma (Unarmed) H215 シュペル ピューマ (非武装) + H215 슈퍼 퓨마 (비무장) H225M Super Cougar SOCAT H225M シュペル クーガー SOCAT + H225M 슈퍼 쿠거 SOCAT H225M Super Cougar SOCAT H225M シュペル クーガー SOCAT + H225M 슈퍼 쿠거 SOCAT H225M Super Cougar H225M シュペル クーガー + H225M 슈퍼 쿠거 H225 Super Puma SAR H225 シュペル ピューマ 捜索救難型 + H225 슈퍼 퓨마 SAR H225M Super Cougar (Unarmed) @@ -231,90 +284,112 @@ Typhoon Water タイフーン 給水 + 타이푼 급수 Ram 1500 ラム 1500 + 램 1500 Ram 1500 (Fuel) ラム 1500 (燃料) + 램 1500 (연료) Ram 1500 (Services) ラム 1500 (サービス) + 램 1500 (서비스) Ram 1500 (Repair) ラム 1500 (修理) + 램 1500 (정비) Ram 1500 (Comms) ラム 1500 (通信) + 램 1500 (통신) Ram 1500 (HMG) ラム 1500 (HMG) + 램 1500 (중기관총) Ram 1500 (MMG) ラム 1500 (MMG) + 램 1500 (중형기관총) Ram 1500 (MRL) ラム 1500 (MRL) + 램 1500 (다연장로켓) Ram 1500 (AA) ラム 1500 (対空) + 램 1500 (대공) Ram 1500 (Covered) ラム 1500 (カバー) + 램 1500 (커버) Ram 1500 (Water) ラム 1500 (給水) + 램 1500 (급수) RSG60 RSG60 + RSG60 AMOS Container AMOS コンテナ + AMOS 컨테이너 Drone40 ドローン40 + 드론40 Drone40 Scout ドローン40 偵察型 + 드론40 정찰 Drone40 HE ドローン40 榴弾 + 드론40 고폭 Drone40 Smoke (White) ドローン40 発煙弾 (白) + 드론40 연막 (백색) Drone40 Smoke (Blue) ドローン40 発煙弾 (青) + 드론40 연막 (청색) Drone40 Smoke (Red) ドローン40 発煙弾 (赤) + 드론40 연막 (적색) Drone40 Smoke (Green) ドローン40 発煙弾 (緑) + 드론40 연막 (녹색) Drone40 Smoke (Orange) ドローン40 発煙弾 (橙) + 드론40 연막 (주황색) diff --git a/addons/compat_ws/compat_ws_realisticnames/stringtable.xml b/addons/compat_ws/compat_ws_realisticnames/stringtable.xml index 30b53b7926..82efb554d9 100644 --- a/addons/compat_ws/compat_ws_realisticnames/stringtable.xml +++ b/addons/compat_ws/compat_ws_realisticnames/stringtable.xml @@ -259,10 +259,12 @@ FN FAL OSW Para FN FAL OSW パラ + FN FAL OSW 파라 FN FAL OSW Para (Snake) FN FAL OSW パラ (ヘビ柄迷彩) + FN FAL OSW 파라 (뱀 위장) Vektor R4 @@ -459,154 +461,192 @@ GM6 Lynx (Snake) GM6 リンクス (ヘビ柄迷彩) + GM6 링스 (뱀 위장) RPG-32 (Sand) RPG-32 (サンド) + RPG-32 (모래) ELCAN SpecterOS (Hex) ELCAN SpecterOS (六角形迷彩) + 엘칸 스펙터OS (육각) EOTech XPS3 (Snake) EOTech XPS3 (ヘビ柄迷彩) + 이오텍 XPS3 (뱀 위장) EOTech XPS3 SMG (Snake) EOTech XPS3 SMG (ヘビ柄迷彩) + 이오텍 XPS3 SMG (뱀 위장) Leupold Mark 4 HAMR (Arid) Leupold Mark 4 HAMR (乾燥地帯迷彩) + 류폴드 마크 4 HAMR (건조) Leupold Mark 4 HAMR (Lush) Leupold Mark 4 HAMR (緑地迷彩) + 류폴드 마크 4 HAMR (초목) Leupold Mark 4 HAMR (Sand) Leupold Mark 4 HAMR (サンド) + 류폴드 마크 4 HAMR (모래) Leupold Mark 4 HAMR (Snake) Leupold Mark 4 HAMR (ヘビ柄迷彩) + 류폴드 마크 4 HAMR (뱀 위장) Aimpoint Micro R-1 (High, Black) Aimpoint マイクロ R-1 (ハイマウント、ブラック) + 에임포인트 마이크로 R-1 (높음, 검정) Aimpoint Micro R-1 (High, Khaki) Aimpoint マイクロ R-1 (ハイマウント、カーキ) + 에임포인트 마이크로 R-1 (높음, 카키) Aimpoint Micro R-1 (High, Sand) Aimpoint マイクロ R-1 (ハイマウント、サンド) + 에임포인트 마이크로 R-1 (높음, 모래) Aimpoint Micro R-1 (High, Snake) Aimpoint マイクロ R-1 (ハイマウント、ヘビ柄迷彩) + 에임포인트 마이크로 R-1 (높음, 뱀 위장) Aimpoint Micro R-1 (High, Arid) Aimpoint マイクロ R-1 (ハイマウント、乾燥地帯迷彩) + 에임포인트 마이크로 R-1 (높음, 건조) Aimpoint Micro R-1 (High, Lush) Aimpoint マイクロ R-1 (ハイマウント、緑地迷彩) + 에임포인트 마이크로 R-1 (높음, 초목) Aimpoint Micro R-1 (High, Black/Sand) Aimpoint マイクロ R-1 (ハイマウント、ブラック/サンド) + 에임포인트 마이크로 R-1 (높음, 검정/모래) Aimpoint Micro R-1 (Low, Black) Aimpoint マイクロ R-1 (ローマウント、ブラック) + 에임포인트 마이크로 R-1 (낮음, 검정) Aimpoint Micro R-1 (Low, Khaki) Aimpoint マイクロ R-1 (ローマウント、カーキ) + 에임포인트 마이크로 R-1 (낮음, 카키) Aimpoint Micro R-1 (Low, Sand) Aimpoint マイクロ R-1 (ローマウント、サンド) + 에임포인트 마이크로 R-1 (낮음, 모래) Aimpoint Micro R-1 (Low, Snake) Aimpoint マイクロ R-1 (ローマウント、ヘビ柄迷彩) + 에임포인트 마이크로 R-1 (낮음, 뱀 위장) Aimpoint Micro R-1 (Low, Arid) Aimpoint マイクロ R-1 (ローマウント、乾燥地帯迷彩) + 에임포인트 마이크로 R-1 (낮음, 건조) Aimpoint Micro R-1 (Low, Lush) Aimpoint マイクロ R-1 (ローマウント、緑地迷彩) + 에임포인트 마이크로 R-1 (낮음, 초목) Burris XTR II (Snake) Burris XTR II (ヘビ柄迷彩) + 버리스 XTR II (뱀 위장) Badger IFV (ATGM) バジャー IFV (ATGM) + 뱃져 보병전투차 (대전차미사일) Badger IFV (Command) バジャー IFV (指揮) + 뱃져 보병전투차 (지휘) Badger IFV (Mortar) バジャー IFV (迫撃砲) + 뱃져 보병전투차 (자주박격포) KamAZ (Zu-23-2) KamAZ (Zu-23-2) + 카마즈 (ZU-23-2) KamAZ Cargo KamAZ 貨物 + 카마즈 화물 KamAZ Repair KamAZ 修理 + 카마즈 정비 KamAZ Racing KamAZ レース仕様 + 카마즈 경주용 KamAZ Ammo KamAZ 弾薬 + 카마즈 탄약 KamAZ Flatbed KamAZ フラットベッド + 카마즈 플랫베드 AW101 Merlin AW101 マーリン + AW101 멀린 BM-2T Stalker (Bumerang-BM) BM-2T ストーカー (ブーメランク-BM) + BM-2T 스토커 (부메랑-BM) Otokar ARMA (HMG) オトカ アルマ (HMG) + 오토카르 아르마 APC (중기관총) Otokar ARMA (Unarmed) オトカ アルマ (非武装) + 오토카르 아르마 APC (비무장) Ka-60 Kasatka (UP) Ka-60 カサートカ (UP) + Ka-60 카사트카 (UP) Ka-60 Kasatka (UP, Unarmed) Ka-60 カサートカ (UP、非武装) + Ka-60 카사트카 (UP, 비무장)) diff --git a/addons/cookoff/stringtable.xml b/addons/cookoff/stringtable.xml index 205b8d2b4d..745b686b8a 100644 --- a/addons/cookoff/stringtable.xml +++ b/addons/cookoff/stringtable.xml @@ -8,7 +8,7 @@ ACE 殉爆效果 ACE 殉爆效果 ACE 誘爆 - ACE 쿡오프 + ACE 유폭 ACE Durchzündung ACE Auto-inflammation ACE Samozapłon @@ -20,35 +20,41 @@ Enable vehicle cook-off fire 車両の誘爆火災を有効化 Вкл. возгорание техники + 차량 유폭 화재를 활성화합니다 Enables vehicle cook-off fire effects.\nThis doesn't include ammunition detonations. 車両の誘爆火災エフェクトを有効化します。\nこれには弾薬の爆発は含まれません。 Вкл. эффект горения техники. \nНе включает детонацию боекомплекта + 차량 유폭 효과를 활성화합니다.\n여기엔 탄약 유폭이 포함되지 않습니다. Vehicle cook-off fire duration multiplier 車両の誘爆火災の持続時間倍率 Увел. продолжительности горения техники + 차량 유폭 화재 지속 시간 계수 Multiplier for how long vehicle cook-off fire lasts.\nSetting to 0 will disable vehicle cook-off fire. 車両の誘爆火災の持続時間をどのくらいの長さにするかの倍率。\n0に設定すると車両の誘爆火災が無効化されます。 Увел. продолжительности горения техники. \nУстановка значения на 0 выключает возгорание техники. + 차량 유폭 화재가 지속되는 시간에 대한 계수입니다.\n0으로 설정하면 차량 쿸오프 화재가 비활성화됩니다. Vehicle cook-off fire probability multiplier 車両の誘爆火災の可能性倍率 Возможность усиления пожара при детонации техники + 차량 유폭 화재 확률 계수 Multiplier for vehicle cook-off fire probability. Higher value results in higher cook-off probability.\nSetting to 0 will disable vehicle cook-off fire. 車両の誘爆火災がどのくらいの可能性で発生するかの倍率。高い数値は高い誘爆の可能性につながります。\n0に設定すると車両の誘爆火災が無効化されます。 Увел. вероятности возникновения возгорания техники. Большое значение указывает на высокую вероятность детонации. \nУстановка значения 0 предотвращает возгорание техники. + 차량 유폭 화재 확률에 대한 계수입니다. 값이 높을 수록 유폭 확률이 높아집니다.\n0으로 설정하면 차량 유폭 화재가 비활성화됩니다. Destroy vehicles after cook-off - 쿡오프 후 차량 파괴 + 유폭 후 차량 파괴 殉爆发生后摧毁载具 Уничтожать технику после детонации Destruir vehículos tras la detonación inducida por calor @@ -65,7 +71,7 @@ Kontroluje, czy pojazdy będą zawsze niszczone po samozapłonie. Steuert, ob Fahrzeuge nach dem Durchzünden immer zerstört werden. Determina se veicoli saranno sempre distrutti dall'esplosione delle munizioni. - 쿡오프 후 차량이 항상 파괴되는지 여부를 조정합니다. + 유폭 후 차량이 항상 파괴되는지 여부를 조정합니다. Contrôle si les véhicules seront toujours détruits après l'auto-inflammation. Define se os veículos serão sempre destruídos após cozinhamento. Определяет, всегда ли транспортные средства будут уничтожаться после детонации. @@ -75,18 +81,20 @@ Enable vehicle ammo cook-off 車両弾薬の誘爆を有効化 Вкл. детонацию боеприпасов в технике. + 차량 내 탄약 유폭 활성화 Enables cooking off of vehicle ammunition. Fires ammunition projectiles while vehicle has ammunition remaining.\nThis doesn't include fire effects. 車両弾薬の誘爆を有効化します。車両に積載されたままの弾薬と弾頭が発射されます。\nこれには火災エフェクトは含まれません。 Вкл. детонацию боеприпасов на технике. Боеприпасы и боеголовки, которые остаются заряженными на транспортном средстве, будут приведены в действие. \nЭто не включает эффекты пожара. + 차량 내 탄약 유폭을 활성화합니다. 차량에 탄약이 남아 있는 동안 탄약 발사체를 발사합니다.\n여기엔 화재 효과가 포함되지 않습니다. Enable ammo box cook-off Habilitar detonación inducida por calor en las cajas de munición 弾薬箱の誘爆を有効化 Durchzündung für Munitionskisten ermöglichen - 탄약 상자 쿡오프 현상 활성화 + 탄약 상자 유폭 현상 활성화 Aktywuj samozapłon skrzyń z amunicją Auto-inflammation des caisses de munitions Abilita esplosione casse munizioni @@ -100,16 +108,19 @@ Enables cooking off of ammo boxes.\nThis doesn't include fire effects. 弾薬箱の誘爆を有効化します。\nこれには火災エフェクトは含まれません。 Вкл. детонацию ящика с боеприпасами. \nЭто не включает эффекты огня. + 탄약 상자 유폭을 활성화합니다.\n여기엔 화재 효과가 포함되지 않습니다. Ammo cook-off duration multiplier 弾薬の誘爆の持続時間倍率 Увеличение продолжительности детонации боеприпасов. + 탄약 유폭 시간 계수 Multiplier for how long ammunition cook-off lasts, for both vehicles and ammo boxes.\nSetting to 0 will disable ammo cook-off for both vehicles and ammo boxes. 弾薬の誘爆の持続時間をどのくらいの長さにするかの倍率。車両弾薬と弾薬箱どちらにも影響します。\n0に設定すると弾薬の誘爆が無効化されます。 Увеличение продолжительности детонации боеприпасов. Это влияет как на боеприпасы в технике, так и на ящики с боеприпасами. \nУстановка значения 0 отключает детонацию боеприпасов. + 차량과 탄약 상자 모두에 대해 탄약 유폭이 지속되는 시간에 대한 계수입니다.\n0으로 설정하면 차량과 탄약 상자 모두에 대해 탄약 유폭이 비활성화됩니다. Enable ammo removal during cook-off @@ -119,7 +130,7 @@ Abilita rimozione munizioni dopo l'esplosione Włącz/Wyłącz usuwanie amunicji podczas samozapłonu 启用/禁用殉爆过程中的弹药移除功能 - 쿡오프시 탄약 제거 활성화/비활성화 + 유폭 시 탄약 제거 활성화/비활성화 Вкл. удаление боеприпасов из-за детонации Habilita/Deshabilita ka eliminación de munición durante la detonación inducida por calor @@ -129,6 +140,7 @@ Entfernt Munition während dem Durchzünden der Munition eines Fahrzeuges. 誘爆によって全ての弾薬を除去します。 Все боеприпасы уничтожаются путем подрыва. + 유폭 중 모든 탄약을 제거합니다. diff --git a/addons/grenades/stringtable.xml b/addons/grenades/stringtable.xml index 1a571093f8..04cc6d20e2 100644 --- a/addons/grenades/stringtable.xml +++ b/addons/grenades/stringtable.xml @@ -107,6 +107,7 @@ Can't roll this grenade, switched to %1 この手榴弾は転がせません、 %1 に切り替えます Эта граната не может быть брошена, переключитесь на %1 + 이 수류탄은 굴릴 수 없습니다. %1(으)로 전환되었습니다. M84 Stun Grenade @@ -154,7 +155,7 @@ Anche conosciuta come flashbang. Causa accecamento immediato, sensazioni di sposatezza, mancanza d'equilibrio e disturbi al timpano. Também conhecida como flashbang. Causa uma clarão imediato, cegueira, surdez, zumbido e distúrbio no tímpano. フラッシュバンとも知られています。即時に失明と難聴、耳鳴り、内耳障害を引き起こします。 - 플래시뱅이라고도 알려져있습니다. 사용 즉시 섬광으로 인한 시력장애, 청각장애, 이명, 내이기관방해를 유발합니다. + 플래시뱅이라고도 알려져 있습니다. 사용 즉시 섬광으로 인한 시력장애, 청각장애, 이명, 내이기관방해를 유발합니다. 也被称为闪光弹,会造成暂时性失明,耳聋,耳鸣等效果。 也被稱為閃光彈,會造成暫時性失明,耳聾,耳鳴等效果 Flashbang olarak da bilinir. Ani flaş körlüğü, sağırlık, kulak çınlaması ve iç kulak rahatsızlığına neden olur. diff --git a/addons/hearing/stringtable.xml b/addons/hearing/stringtable.xml index 5b7c3da063..9aba1ab56b 100644 --- a/addons/hearing/stringtable.xml +++ b/addons/hearing/stringtable.xml @@ -381,6 +381,7 @@ 重火器を装備したユニットのみ Sólo unidades con armas pesadas Solo a unità con armi pesanti + 중화기를 가진 유닛만 해당 diff --git a/addons/hitreactions/stringtable.xml b/addons/hitreactions/stringtable.xml index 421f806e32..8cc25a53a5 100644 --- a/addons/hitreactions/stringtable.xml +++ b/addons/hitreactions/stringtable.xml @@ -21,11 +21,13 @@ Player Weapon Drop Chance (Arm Hit) プレイヤーが武器を落とす確率 (腕部への被弾) Шанс выпадения оружия у игрока (попадание в руку) + 플레이어가 무기를 떨굴 확률 (팔 피격) AI Weapon Drop Chance (Arm Hit) AIが武器を落とす確率 (腕部への被弾) Шанс выпадения оружия у ИИ (попадание в руку) + 인공지능이 무기를 떨굴 확률 (팔 피격) diff --git a/addons/medical_treatment/stringtable.xml b/addons/medical_treatment/stringtable.xml index 8b8cc640eb..e7217260ac 100644 --- a/addons/medical_treatment/stringtable.xml +++ b/addons/medical_treatment/stringtable.xml @@ -73,13 +73,14 @@ Включено и может диагностировать смерть/остановку сердца Aktiviert & kann Tod/Herzstillstand diagnostizieren 已启用 & 可以诊断死亡/心搏骤停 - 활성화 및 사망/심정지 진찰가능 + 활성화 및 사망/심정지 진찰 가능 Habilitado y poder diagnosticar Muerte/Parada cardíaca Abilitato e può diagnosticare Morte/Arresto Cardiaco Enabled & Can Diagnose Death/Cardiac Arrest [Directly] 有効 & 死亡/心停止状態を診断可能 [直接的に] + 활성화 및 사망/심정지 진찰 가능 [직접] Advanced Medication @@ -3682,7 +3683,7 @@ %1 zkontroloval krevní tlak: %2 %1 verificou pressão arterial: %2 %1 が血圧を確認: %2 - %1 (이)가 혈압을 측정했습니다: %2 + %1(이)가 혈압을 측정했습니다: %2 %1 测得血压为 %2 已由%1確認血壓: %2 @@ -3935,7 +3936,7 @@ %1 zkontroloval srdeční tep: %2 %1 verificou a frequência cardíaca: %2 %1 が心拍を確認: %2 - %1 (이)가 맥박을 측정했습니다: %2 + %1(이)가 맥박을 측정했습니다: %2 %1 测得心率为 %2 已由%1確認心跳: %2 @@ -4019,7 +4020,7 @@ A Frequência Cardíaca é de %2 Nahmatal jsi srdeční tep u %2 計測した心拍数は %2 でした - 맥박이 %2 입니다 + 맥박은 %2 입니다 心率为 %2 心跳為%2 @@ -4135,7 +4136,7 @@ %1 está respondendo %1 odpovídá %1 は反応している - %1 은 반응이 있습니다 + %1은(는) 반응이 있습니다 %1 有反应 %1 有反應 %1 tepki veriyor @@ -4152,7 +4153,7 @@ %1 não está respondendo %1 neodpovídá %1 は反応していない - %1 은 반응이 없습니다 + %1은(는) 반응이 없습니다 %1 没有反应 %1 沒有反應 %1 tepki vermiyor @@ -4161,6 +4162,7 @@ %1 is unconscious %1 は意識がない %1 находится без сознания + %1은(는) 의식불명입니다 %1 is not responsive, taking shallow gasps and convulsing @@ -4178,6 +4180,7 @@ %1 is in cardiac arrest %1 は心停止している У %1 произошла остановка сердца + %1은(는) 심정지 상태입니다 %1 is not responsive, motionless and cold @@ -4195,6 +4198,7 @@ %1 is dead %1 は死亡している %1 мертв + %1은(는) 사망했습니다 You checked %1 diff --git a/addons/realisticnames/stringtable.xml b/addons/realisticnames/stringtable.xml index 833c83db94..5fc19bb9bf 100644 --- a/addons/realisticnames/stringtable.xml +++ b/addons/realisticnames/stringtable.xml @@ -703,6 +703,7 @@ KamAZ Água KamAZ 給水 КамАЗ (водоноситель) + 카마즈 급수 KamAZ MRL @@ -1666,12 +1667,14 @@ CZ 581 CZ 581 CZ 581 + CZ 581 CZ 581 (Sawed-Off) CZ 581 (Cano serrado) CZ 581 (ソードオフ) CZ 581 (Sawed-Off) + CZ 581 (소드오프) FNX-45 Tactical (Green) @@ -3079,18 +3082,21 @@ Type 115 (Preto) Type 115 (ブラック) Type 115 (чёрный) + 115식 보총 (검정) Type 115 (Green Hex) Type 115 (Verde Hex) Type 115 (緑六角形迷彩) Type 115 (зелёный гекс) + 115식 보총 (초록육각) Type 115 (Hex) Type 115 (Hex) Type 115 (六角形迷彩) Type 115 (гекс) + 115식 보총 (육각) QBZ-95-1 (Black) @@ -3881,18 +3887,21 @@ UTG Defender 126 UTG ディフェンダー 126 UTG Defender 126 + UTG 디펜더 126 EOTech MRDS EOTech MRDS EOTech MRDS EOTech MRDS + 이오텍 MRDS EOTech MRDS (Black) EOTech MRDS (Preto) EOTech MRDS (ブラック) EOTech MRDS (чёрный) + 이오텍 MRDS (검정) Leupold Mark 4 HAMR diff --git a/addons/zeus/stringtable.xml b/addons/zeus/stringtable.xml index e871ef85ef..59597da0b4 100644 --- a/addons/zeus/stringtable.xml +++ b/addons/zeus/stringtable.xml @@ -2013,36 +2013,43 @@ Forces the spectator interface preventing the player from closing it with the Escape key 観戦インターフェイスを強制し、ユーザーがEscキーでも閉じられないようにします。 Активирует интерфейс spectator, не позволяя игроку закрыть его с помощью клавиши Escape. + 플레이어가 Esc 키로 관전자 인터페이스를 닫지 못하도록 강제로 관전자 인터페이스를 설정합니다. Hide player プレイヤーを隠す Скрыть игрока + 플레이어 숨기기 Hides the player by making them invisible, invulnerable, muted, and removing them from their group 透明化、無敵化、ミュート、グループからの除外を行いプレーヤーを隠します Скрывает игрока, делая его невидимым, неуязвимым, отключая звук и удаляя из группы. + 플레이어를 투명, 무적, 음소거화하고 그룹에서 제거하여 숨깁니다. Sets the sides that are available to spectate 指定の陣営を観戦可能に設定します Устанавливает стороны, доступные для режима spectator + 관전 가능한 진영을 설정합니다. White Hot 白=熱源 Белый + 백색 열원 Black Hot 黒=熱源 Чёрный + 흑색 열원 Toggle All 全てを切り替え Выключить все + 전부 토글 From 05d6327e5e1d7af445f659761e56d9fad7e8a6af Mon Sep 17 00:00:00 2001 From: V1nsyara Date: Sun, 23 Jun 2024 04:24:00 +0300 Subject: [PATCH 115/290] Translation - Update Russian for small features (#10085) * Translation - Update Russian for new features * Up to date translate RU --- addons/killtracker/stringtable.xml | 2 ++ addons/medical_treatment/stringtable.xml | 1 + addons/overpressure/stringtable.xml | 2 ++ 3 files changed, 5 insertions(+) diff --git a/addons/killtracker/stringtable.xml b/addons/killtracker/stringtable.xml index 916dac6877..64fedfe320 100644 --- a/addons/killtracker/stringtable.xml +++ b/addons/killtracker/stringtable.xml @@ -121,9 +121,11 @@ Show vehicle kills to other crew members + Показать уничтоженные машины другим членам экипажа Show kills from a vehicle to driver, gunner and commander + Показать уничтоженную технику водителю, стрелку и командиру diff --git a/addons/medical_treatment/stringtable.xml b/addons/medical_treatment/stringtable.xml index e7217260ac..6593042d2a 100644 --- a/addons/medical_treatment/stringtable.xml +++ b/addons/medical_treatment/stringtable.xml @@ -80,6 +80,7 @@ Enabled & Can Diagnose Death/Cardiac Arrest [Directly] 有効 & 死亡/心停止状態を診断可能 [直接的に] + Включено и может диагностировать смерть/остановку сердца [Напрямую] 활성화 및 사망/심정지 진찰 가능 [직접] diff --git a/addons/overpressure/stringtable.xml b/addons/overpressure/stringtable.xml index d8b9ad12f4..f981fbc009 100644 --- a/addons/overpressure/stringtable.xml +++ b/addons/overpressure/stringtable.xml @@ -47,9 +47,11 @@ Backblast Distance Coefficient + Коэффициент расстояния рекативной струи Scales the backblast effect + Масштабирует эффект реактивной струи Backblast range From aed2222b8159dbfbea00526169fd8fa85870ee6b Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Sat, 22 Jun 2024 22:34:34 -0500 Subject: [PATCH 116/290] Artillery Tables - Support for ammo that has native `airFriction` (#10059) * Artillery Tables - Support for ammo that has native `airFriction` * fix comment Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * Update addons/artillerytables/functions/fnc_rangeTableOpen.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * replace if block with select const Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --------- Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- .../artillerytables/functions/fnc_firedEH.sqf | 3 +- .../functions/fnc_rangeTableOpen.sqf | 11 +++++- .../framework/artillery-tables-framework.md | 38 +++++++++++++++++++ 3 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 docs/wiki/framework/artillery-tables-framework.md diff --git a/addons/artillerytables/functions/fnc_firedEH.sqf b/addons/artillerytables/functions/fnc_firedEH.sqf index f735c4c961..5aa46c6969 100644 --- a/addons/artillerytables/functions/fnc_firedEH.sqf +++ b/addons/artillerytables/functions/fnc_firedEH.sqf @@ -35,7 +35,7 @@ if (isNumber (configFile >> "CfgMagazines" >> _magazine >> QGVAR(airFriction))) _airFriction = getNumber (configFile >> "CfgMagazines" >> _magazine >> QGVAR(airFriction)); }; TRACE_1("",_airFriction); -if (_airFriction >= 0) exitWith {}; // 0 disables everything, >0 makes no sense +if (_airFriction == 0) exitWith {}; // 0 disables everything BEGIN_COUNTER(adjustmentsCalc); @@ -60,6 +60,7 @@ if (_newMuzzleVelocityCoefficent != 1) then { _projectile setVelocity _bulletVelocity; }; +if (_airFriction > 0) exitWith {}; // positive value indicates it has vanilla airFriction, so we can just exit [{ params ["_projectile", "_kFactor", "_time"]; diff --git a/addons/artillerytables/functions/fnc_rangeTableOpen.sqf b/addons/artillerytables/functions/fnc_rangeTableOpen.sqf index 327a2903a0..508b8c894c 100644 --- a/addons/artillerytables/functions/fnc_rangeTableOpen.sqf +++ b/addons/artillerytables/functions/fnc_rangeTableOpen.sqf @@ -41,8 +41,15 @@ _mags = _mags apply { private _initSpeed = getNumber (_magCfg >> _x >> "initSpeed"); _magParamsArray pushBackUnique _initSpeed; private _airFriction = 0; - if (_advCorrection) then { - _airFriction = if (isNumber (_magCfg >> _x >> QGVAR(airFriction))) then { getNumber (_magCfg >> _x >> QGVAR(airFriction)) } else { DEFAULT_AIR_FRICTION }; + private _magAirFriction = getNumber (_magCfg >> _x >> QGVAR(airFriction)); + if (_magAirFriction <= 0) then { + if (_advCorrection) then { + _airFriction = [DEFAULT_AIR_FRICTION, _magAirFriction] select (isNumber (_magCfg >> _x >> QGVAR(airFriction))); + }; + } else { + // positive value, use ammo's airFriction (regardless of setting) + private _ammo = getText (_magCfg >> _x >> "ammo"); + _airFriction = getNumber (configFile >> "CfgAmmo" >> _ammo >> "airFriction"); }; _magParamsArray pushBackUnique _airFriction; [getText (_magCfg >> _x >> "displayNameShort"), getText (_magCfg >> _x >> "displayName"), _initSpeed, _airFriction] diff --git a/docs/wiki/framework/artillery-tables-framework.md b/docs/wiki/framework/artillery-tables-framework.md new file mode 100644 index 0000000000..be2adb3331 --- /dev/null +++ b/docs/wiki/framework/artillery-tables-framework.md @@ -0,0 +1,38 @@ +--- +layout: wiki +title: Artillery Tables +description: Explains the configs for artillery tables. +group: framework +parent: wiki +mod: ace +version: + major: 3 + minor: 13 + patch: 0 +--- + +## 1. Magazine Configs + +```cpp +class CfgMagazines { + class yourMag { + ace_artillerytables_airFriction = -0.00006; // default value + // drag coefficent (when Air Resistance setting is enabled) + // can set to 0 to disable all muzzle effects and airFriction + // can set to +1 to use the ammo's native airFriction (not common, as most artillery ammo will have none) +``` + +## 2. Vehicle Configs + +```cpp +class CfgVehicles { + class yourVic { + ace_artillerytables_showRangetable = 1; // [0 disabled, 1 enabled] falls back to artilleryScanner + // Show rangetable for this vehicle + + ace_artillerytables_showGunLaying = 1; // [0 disabled, 1 enabled, 2 enabled w/ alt elevationMode] falls back to artilleryScanner + // Shows gun laying info (elev/azimuth) + + ace_artillerytables_applyCorrections = 1; // [0 disabled, 1 enabled] falls back to artilleryScanner + // Apply advanced corrections (when setting enabled) +``` From bdb6c7c69c09ad481ce8d5ece79757ffcf482df3 Mon Sep 17 00:00:00 2001 From: Fabio Schick <58027418+mrschick@users.noreply.github.com> Date: Sun, 23 Jun 2024 05:36:41 +0200 Subject: [PATCH 117/290] Compat RHS/Hellfire - Use RHS models when loaded (#10076) Co-authored-by: PabstMirror --- addons/compat_rhs_usf3/CfgMagazineWells.hpp | 11 ------ addons/compat_rhs_usf3/CfgMagazines.hpp | 17 --------- .../compat_rhs_usf3_hellfire/CfgAmmo.hpp | 8 ++++ .../CfgMagazineWells.hpp | 11 ++++++ .../compat_rhs_usf3_hellfire/CfgMagazines.hpp | 37 +++++++++++++++++++ .../compat_rhs_usf3_hellfire/config.cpp | 25 +++++++++++++ .../script_component.hpp | 3 ++ addons/compat_rhs_usf3/config.cpp | 1 - addons/hellfire/CfgMagazines.hpp | 4 +- 9 files changed, 86 insertions(+), 31 deletions(-) delete mode 100644 addons/compat_rhs_usf3/CfgMagazineWells.hpp create mode 100644 addons/compat_rhs_usf3/compat_rhs_usf3_hellfire/CfgAmmo.hpp create mode 100644 addons/compat_rhs_usf3/compat_rhs_usf3_hellfire/CfgMagazineWells.hpp create mode 100644 addons/compat_rhs_usf3/compat_rhs_usf3_hellfire/CfgMagazines.hpp create mode 100644 addons/compat_rhs_usf3/compat_rhs_usf3_hellfire/config.cpp create mode 100644 addons/compat_rhs_usf3/compat_rhs_usf3_hellfire/script_component.hpp diff --git a/addons/compat_rhs_usf3/CfgMagazineWells.hpp b/addons/compat_rhs_usf3/CfgMagazineWells.hpp deleted file mode 100644 index 01223ec141..0000000000 --- a/addons/compat_rhs_usf3/CfgMagazineWells.hpp +++ /dev/null @@ -1,11 +0,0 @@ -class CfgMagazineWells { - class ace_hellfire_K { - ADDON[] = {QGVAR(pylon_mag_2rnd_hellfire_k)}; - }; - class ace_hellfire_N { - ADDON[] = {QGVAR(pylon_mag_2rnd_hellfire_n)}; - }; - class ace_hellfire_L { - ADDON[] = {QGVAR(pylon_mag_2rnd_hellfire_l)}; - }; -}; diff --git a/addons/compat_rhs_usf3/CfgMagazines.hpp b/addons/compat_rhs_usf3/CfgMagazines.hpp index f11dad081c..471b345dcd 100644 --- a/addons/compat_rhs_usf3/CfgMagazines.hpp +++ b/addons/compat_rhs_usf3/CfgMagazines.hpp @@ -38,21 +38,4 @@ class cfgMagazines { EGVAR(overpressure,range) = 0; EGVAR(overpressure,damage) = 0; }; - - class rhs_mag_AGM114K_2; - class GVAR(pylon_mag_2rnd_hellfire_k): rhs_mag_AGM114K_2 { - displayName = "2x AGM-114K [ACE]"; - pylonWeapon = "ace_hellfire_launcher"; - ammo = "ACE_Hellfire_AGM114K"; - }; - class GVAR(pylon_mag_2rnd_hellfire_n): rhs_mag_AGM114K_2 { - displayName = "2x AGM-114N [ACE]"; - pylonWeapon = "ace_hellfire_launcher_N"; - ammo = "ACE_Hellfire_AGM114N"; - }; - class GVAR(pylon_mag_2rnd_hellfire_l): rhs_mag_AGM114K_2 { - displayName = "2x AGM-114L [ACE]"; - pylonWeapon = "ace_hellfire_launcher_L"; - ammo = "ACE_Hellfire_AGM114L"; - }; }; diff --git a/addons/compat_rhs_usf3/compat_rhs_usf3_hellfire/CfgAmmo.hpp b/addons/compat_rhs_usf3/compat_rhs_usf3_hellfire/CfgAmmo.hpp new file mode 100644 index 0000000000..16a0628d1f --- /dev/null +++ b/addons/compat_rhs_usf3/compat_rhs_usf3_hellfire/CfgAmmo.hpp @@ -0,0 +1,8 @@ +class CfgAmmo { + // Use RHS Hellfire 3D Model on ACE Hellfires + class M_Scalpel_AT; + class ACE_Hellfire_AGM114K: M_Scalpel_AT { + model = "\rhsusf\addons\rhsusf_airweapons\proxyammo\rhsusf_m_AGM114K_fly"; + proxyShape = "\rhsusf\addons\rhsusf_airweapons\proxyammo\rhsusf_m_AGM114K"; + }; +}; diff --git a/addons/compat_rhs_usf3/compat_rhs_usf3_hellfire/CfgMagazineWells.hpp b/addons/compat_rhs_usf3/compat_rhs_usf3_hellfire/CfgMagazineWells.hpp new file mode 100644 index 0000000000..e574b123a2 --- /dev/null +++ b/addons/compat_rhs_usf3/compat_rhs_usf3_hellfire/CfgMagazineWells.hpp @@ -0,0 +1,11 @@ +class CfgMagazineWells { + class ace_hellfire_K { + ADDON[] = {QGVAR(pylon_mag_2rnd_hellfire_k), QGVAR(pylon_mag_4rnd_hellfire_k)}; + }; + class ace_hellfire_N { + ADDON[] = {QGVAR(pylon_mag_2rnd_hellfire_n), QGVAR(pylon_mag_4rnd_hellfire_n)}; + }; + class ace_hellfire_L { + ADDON[] = {QGVAR(pylon_mag_2rnd_hellfire_l), QGVAR(pylon_mag_4rnd_hellfire_l)}; + }; +}; diff --git a/addons/compat_rhs_usf3/compat_rhs_usf3_hellfire/CfgMagazines.hpp b/addons/compat_rhs_usf3/compat_rhs_usf3_hellfire/CfgMagazines.hpp new file mode 100644 index 0000000000..9d96974ab8 --- /dev/null +++ b/addons/compat_rhs_usf3/compat_rhs_usf3_hellfire/CfgMagazines.hpp @@ -0,0 +1,37 @@ +class CfgMagazines { + // 2x ACE Hellfire racks + class rhs_mag_AGM114K_2; + class GVAR(pylon_mag_2rnd_hellfire_k): rhs_mag_AGM114K_2 { + displayName = "2x AGM-114K [ACE]"; + pylonWeapon = "ace_hellfire_launcher"; + ammo = "ACE_Hellfire_AGM114K"; + }; + class GVAR(pylon_mag_2rnd_hellfire_n): rhs_mag_AGM114K_2 { + displayName = "2x AGM-114N [ACE]"; + pylonWeapon = "ace_hellfire_launcher_N"; + ammo = "ACE_Hellfire_AGM114N"; + }; + class GVAR(pylon_mag_2rnd_hellfire_l): rhs_mag_AGM114K_2 { + displayName = "2x AGM-114L [ACE]"; + pylonWeapon = "ace_hellfire_launcher_L"; + ammo = "ACE_Hellfire_AGM114L"; + }; + + // 4x ACE Hellfire racks that align better on RHS Apaches and Blackhawks than the standard ACE 4x racks + class rhs_mag_AGM114K_4; + class GVAR(pylon_mag_4rnd_hellfire_k): rhs_mag_AGM114K_4 { + displayName = "4x AGM-114K [ACE]"; + pylonWeapon = "ace_hellfire_launcher"; + ammo = "ACE_Hellfire_AGM114K"; + }; + class GVAR(pylon_mag_4rnd_hellfire_n): rhs_mag_AGM114K_4 { + displayName = "4x AGM-114N [ACE]"; + pylonWeapon = "ace_hellfire_launcher_N"; + ammo = "ACE_Hellfire_AGM114N"; + }; + class GVAR(pylon_mag_4rnd_hellfire_l): rhs_mag_AGM114K_4 { + displayName = "4x AGM-114L [ACE]"; + pylonWeapon = "ace_hellfire_launcher_L"; + ammo = "ACE_Hellfire_AGM114L"; + }; +}; diff --git a/addons/compat_rhs_usf3/compat_rhs_usf3_hellfire/config.cpp b/addons/compat_rhs_usf3/compat_rhs_usf3_hellfire/config.cpp new file mode 100644 index 0000000000..f460508a18 --- /dev/null +++ b/addons/compat_rhs_usf3/compat_rhs_usf3_hellfire/config.cpp @@ -0,0 +1,25 @@ +#include "script_component.hpp" + +class CfgPatches { + class SUBADDON { + name = COMPONENT_NAME; + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = { + "rhsusf_main_loadorder", + "ace_hellfire" + }; + skipWhenMissingDependencies = 1; + author = ECSTRING(common,ACETeam); + authors[] = {}; + url = ECSTRING(main,URL); + VERSION_CONFIG; + + addonRootClass = QUOTE(ADDON); + }; +}; + +#include "CfgAmmo.hpp" +#include "CfgMagazines.hpp" +#include "CfgMagazineWells.hpp" diff --git a/addons/compat_rhs_usf3/compat_rhs_usf3_hellfire/script_component.hpp b/addons/compat_rhs_usf3/compat_rhs_usf3_hellfire/script_component.hpp new file mode 100644 index 0000000000..387de2d3ad --- /dev/null +++ b/addons/compat_rhs_usf3/compat_rhs_usf3_hellfire/script_component.hpp @@ -0,0 +1,3 @@ +#define SUBCOMPONENT hellfire +#define SUBCOMPONENT_BEAUTIFIED Hellfire +#include "..\script_component.hpp" diff --git a/addons/compat_rhs_usf3/config.cpp b/addons/compat_rhs_usf3/config.cpp index 1e67b1e007..73b4723b2c 100644 --- a/addons/compat_rhs_usf3/config.cpp +++ b/addons/compat_rhs_usf3/config.cpp @@ -19,7 +19,6 @@ class CfgPatches { #include "CfgAmmo.hpp" #include "CfgEventHandlers.hpp" #include "CfgMagazines.hpp" -#include "CfgMagazineWells.hpp" #include "CfgWeapons.hpp" #include "CfgVehicles.hpp" #include "CfgGlasses.hpp" diff --git a/addons/hellfire/CfgMagazines.hpp b/addons/hellfire/CfgMagazines.hpp index 8abf2529b5..d025afadde 100644 --- a/addons/hellfire/CfgMagazines.hpp +++ b/addons/hellfire/CfgMagazines.hpp @@ -32,7 +32,7 @@ class CfgMagazines { count = 3; mass = 250; pylonWeapon = QGVAR(launcher); - hardpoints[] = {"B_MISSILE_PYLON", "UNI_SCALPEL", "CUP_NATO_HELO_LARGE", "RHS_HP_LONGBOW_RACK"}; + hardpoints[] = {"B_MISSILE_PYLON", "UNI_SCALPEL", "CUP_NATO_HELO_LARGE"}; model = "\A3\Weapons_F\DynamicLoadout\PylonPod_3x_Missile_LG_scalpel_F.p3d"; mirrorMissilesIndexes[] = {2, 1, 3}; }; @@ -41,7 +41,7 @@ class CfgMagazines { count = 4; mass = 340; pylonWeapon = QGVAR(launcher); - hardpoints[] = {"UNI_SCALPEL", "CUP_NATO_HELO_LARGE", "RHS_HP_HELLFIRE_RACK", "RHS_HP_LONGBOW_RACK"}; + hardpoints[] = {"UNI_SCALPEL", "CUP_NATO_HELO_LARGE"}; model = "\A3\Weapons_F\DynamicLoadout\PylonPod_4x_Missile_LG_scalpel_F.p3d"; mirrorMissilesIndexes[] = {2, 1, 4, 3}; }; From 5c8ea65f7cd0a290e7ff6f8d0c44347617e77955 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Sun, 23 Jun 2024 18:12:30 -0500 Subject: [PATCH 118/290] Common - Update header for addPlayerEH (#10086) --- addons/common/functions/fnc_addPlayerEH.sqf | 8 +++++--- addons/ui/XEH_clientInit.sqf | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/addons/common/functions/fnc_addPlayerEH.sqf b/addons/common/functions/fnc_addPlayerEH.sqf index 81d030fb62..c20fde9da1 100644 --- a/addons/common/functions/fnc_addPlayerEH.sqf +++ b/addons/common/functions/fnc_addPlayerEH.sqf @@ -2,12 +2,14 @@ /* * Author: PabstMirror * Adds event handler just to ACE_player + * Can be removed after cba 3.18 is released for CBA_fnc_addBISPlayerEventHandler + * This never was public in a release * * Arguments: * 0: Key * 1: Event Type * 2: Event Code - * 3: Ignore Virtual Units (spectators, virtual zeus, uav RC) (default: false) + * 3: Ignore Virtual Units (spectators, virtual zeus, uav RC) (default: true) * * Return Value: * None @@ -15,9 +17,9 @@ * Example: * ["example", "FiredNear", {systemChat str _this}] call ace_common_fnc_addPlayerEH * - * Public: Yes + * Public: No */ -params [["_key", "", [""]], ["_type", "", [""]], ["_code", {}, [{}]], ["_ignoreVirtual", false, [false]]]; +params [["_key", "", [""]], ["_type", "", [""]], ["_code", {}, [{}]], ["_ignoreVirtual", true, [true]]]; TRACE_3("addPlayerEH",_key,_type,_ignoreVirtual); if (isNil QGVAR(playerEventsHash)) then { // first-run init diff --git a/addons/ui/XEH_clientInit.sqf b/addons/ui/XEH_clientInit.sqf index 2c8cd3e4b4..d9d3fa5717 100644 --- a/addons/ui/XEH_clientInit.sqf +++ b/addons/ui/XEH_clientInit.sqf @@ -47,4 +47,4 @@ GVAR(elementsSet) = createHashMap; }] call CBA_fnc_addEventHandler; }] call CBA_fnc_addEventHandler; -[QUOTE(ADDON), "AnimChanged", LINKFUNC(onAnimChanged)] call EFUNC(common,addPlayerEH); +[QUOTE(ADDON), "AnimChanged", LINKFUNC(onAnimChanged), true] call EFUNC(common,addPlayerEH); From b013ab81d585dc0482e96d1a8babdcbe80e88ecb Mon Sep 17 00:00:00 2001 From: Fabio Schick <58027418+mrschick@users.noreply.github.com> Date: Mon, 24 Jun 2024 23:44:41 +0200 Subject: [PATCH 119/290] Translations - Italian and German (#10087) * Grenades italian+german translation * Fix english typo in MicroDAGR * Medical Treatment italian+german translations * Realisticnames italian+german translations * Hitreactions italian+german translations * Fix italian typo in 3 addons * Cookoff italian+german translations * Killtracker italian+german translations * Zeus italian+german translations * Overpressure italian+german translations * Compat RF italian+german translations * Realisticnames Fix italian+german oversight * Compat WS italian+german translations * Compat CUP-CSW italian translations * Compat CUP-NVG italian translations * Fixup overpressure --- addons/cargo/stringtable.xml | 2 +- .../compat_cup_weapons_csw/stringtable.xml | 17 ++ .../stringtable.xml | 6 +- .../compat_rf_realisticnames/stringtable.xml | 153 ++++++++++++++++++ .../compat_ws_realisticnames/stringtable.xml | 80 +++++++++ addons/cookoff/stringtable.xml | 25 ++- addons/csw/stringtable.xml | 2 +- addons/grenades/stringtable.xml | 2 + addons/hitreactions/stringtable.xml | 4 + addons/killtracker/stringtable.xml | 4 + addons/medical_treatment/stringtable.xml | 8 + addons/microdagr/stringtable.xml | 2 +- addons/overpressure/stringtable.xml | 6 +- addons/realisticnames/stringtable.xml | 18 +++ addons/zeus/stringtable.xml | 16 +- 15 files changed, 337 insertions(+), 8 deletions(-) diff --git a/addons/cargo/stringtable.xml b/addons/cargo/stringtable.xml index 4e8d707f61..8e16f50090 100644 --- a/addons/cargo/stringtable.xml +++ b/addons/cargo/stringtable.xml @@ -506,7 +506,7 @@ Ladezeitmultiplikator 積載の所要時間係数 Współczynnik czasu załadowania - Coefficente Tempo Caricamento + Coefficiente Tempo Caricamento Коэф. времени погрузки Fator de tempo para carregar Coefficient du temps de chargement diff --git a/addons/compat_cup_weapons/compat_cup_weapons_csw/stringtable.xml b/addons/compat_cup_weapons/compat_cup_weapons_csw/stringtable.xml index 112c335638..ea16be2905 100644 --- a/addons/compat_cup_weapons/compat_cup_weapons_csw/stringtable.xml +++ b/addons/compat_cup_weapons/compat_cup_weapons_csw/stringtable.xml @@ -8,6 +8,7 @@ [CSW] AGS-30 벨트 [CSW] AGS30 Gurt [CSW] Cinta de AGS30 + [CSW] Nastro AGS30 [CSW] MK19 Belt @@ -16,6 +17,7 @@ [CSW] Mk.19 벨트 [CSW] MK19 Gurt [CSW] Cinta de MK19 + [CSW] Nastro MK19 [CSW] TOW Tube @@ -24,6 +26,7 @@ [CSW] TOW 튜브 [CSW] TOW Rohr [CSW] Tubo de TOW + [CSW] Tubo TOW [CSW] TOW2 Tube @@ -32,6 +35,7 @@ [CSW] TOW2 튜브 [CSW] TOW2 Rohr [CSW] Tubo de TOW2 + [CSW] Tubo TOW2 [CSW] PG-9 Round @@ -40,6 +44,7 @@ [CSW] PG-9 대전차고폭탄 [CSW] PG-9 Rakete [CSW] Carga de PG-9 + [CSW] Razzo PG-9 [CSW] OG-9 Round @@ -48,6 +53,7 @@ [CSW] OG-9 고폭파편탄 [CSW] OG-9 Rakete [CSW] Carga de OG-9 + [CSW] Razzo OG-9 [CSW] M1 HE @@ -57,6 +63,7 @@ [CSW] M1 HE [CSW] M1 HE [CSW] HE de M1 + [CSW] M1 HE [CSW] M84 Smoke @@ -66,6 +73,7 @@ [CSW] M84 Fumigène [CSW] M84 Rauch [CSW] Humo M84 + [CSW] M84 Fumogeno [CSW] M60A2 WP @@ -75,6 +83,7 @@ [CSW] M60A2 WP [CSW] M60A2 WP [CSW] M60A2 WP + [CSW] M60A2 WP [CSW] M67 AT Laser Guided @@ -84,6 +93,7 @@ [CSW] M67 AT Guidé laser [CSW] M67 AT Lasergelenkt [CSW] AT Guiado por Láser M67 + [CSW] M67 AT Laserguidato [CSW] M314 Illumination @@ -93,6 +103,7 @@ [CSW] M314 Illumination [CSW] M314 Beleuchtung [CSW] Iluminación M314 + [CSW] M314 Illuminante [CSW] 3OF56 HE @@ -102,6 +113,7 @@ [CSW] 3OF56 HE [CSW] 3OF56 HE [CSW] HE de 3OF56 + [CSW] 3OF56 HE [CSW] 3OF69M Laser Guided @@ -111,6 +123,7 @@ [CSW] 3OF69M Guidé laser [CSW] 3OF69M Lasergelenkt [CSW] 3OF69M Guiado por Láser + [CSW] 3OF69M Laserguidato [CSW] 122mm WP @@ -120,6 +133,7 @@ [CSW] 122mm WP [CSW] 122mm WP [CSW] WP de 122mm + [CSW] 122mm WP [CSW] D-462 Smoke @@ -129,6 +143,7 @@ [CSW] D-462 Fumigène [CSW] D-462 Rauch [CSW] Humo D-462 + [CSW] D-462 Fumogeno [CSW] S-463 Illumination @@ -138,6 +153,7 @@ [CSW] S-463 Eclairante [CSW] S-463 Beleuchtung [CSW] Iluminación S-463 + [CSW] S-463 Illuminante [CSW] BK-6M HEAT @@ -147,6 +163,7 @@ [CSW] BK-6M HEAT [CSW] BK-6M HEAT [CSW] BK-6M HEAT + [CSW] BK-6M HEAT diff --git a/addons/compat_cup_weapons/compat_cup_weapons_nightvision/stringtable.xml b/addons/compat_cup_weapons/compat_cup_weapons_nightvision/stringtable.xml index e1afbe21c8..5e31f93caf 100644 --- a/addons/compat_cup_weapons/compat_cup_weapons_nightvision/stringtable.xml +++ b/addons/compat_cup_weapons/compat_cup_weapons_nightvision/stringtable.xml @@ -37,7 +37,7 @@ AN/PVS-15 (Tan, WP) AN/PVS-15 (タン, 白色蛍光) - AN/PVS-15 (Marroncina, FB) + AN/PVS-15 (Marroncino, FB) AN/PVS-15 (Jasnobrązowa, WP) AN/PVS-15 (Hellbraun, WP) AN/PVS-15 (황갈색, 백색광) @@ -48,6 +48,7 @@ AN/PVS-15 (Winter, WP) AN/PVS-15 (冬季迷彩, WP) + AN/PVS-15 (Invernale, FB) AN/PVS-15 (설상, 백색광) AN/PVS-15 (Белый, БФ) AN/PVS-15 (Blanc, WP) @@ -68,7 +69,7 @@ GPNVG (Tan, WP) GPNVG (タン, 白色蛍光) - GPNVG (Marroncina, FB) + GPNVG (Marroncino, FB) GPNVG (Jasnobrązowa, WP) GPNVG (Hellbraun, WP) GPNVG (황갈색, 백색광) @@ -90,6 +91,7 @@ GPNVG (Winter, WP) GPNVG (冬季迷彩, WP) + GPNVG (Invernale, FB) GPNVG (설상, 백색광) AN/PVS-15 (Белый, БФ) GPNVG (Blanc, WP) diff --git a/addons/compat_rf/compat_rf_realisticnames/stringtable.xml b/addons/compat_rf/compat_rf_realisticnames/stringtable.xml index 6d77333cda..c65a8fd4ad 100644 --- a/addons/compat_rf/compat_rf_realisticnames/stringtable.xml +++ b/addons/compat_rf/compat_rf_realisticnames/stringtable.xml @@ -5,270 +5,378 @@ EOTech MRDS (Khaki) EOTech MRDS (カーキ) 이오텍 MRDS (카키) + EOTech MRDS (Khaki) + EOTech MRDS (Cachi) EOTech MRDS (Tan) EOTech MRDS (タン) 이오텍 MRDS (황갈) + EOTech MRDS (Hellbraun) + EOTech MRDS (Marroncino) C-More Railway (Green, Desert) C-More レイルウェイ (グリーン、砂漠迷彩) 씨모어 레일웨이 (녹색, 사막) + C-More Railway (Grün, Wüste) + C-More Railway (Verde, Deserto) C-More Railway (Green, Woodland) C-More レイルウェイ (グリーン、森林迷彩) 씨모어 레일웨이 (녹색, 수풀 위장) + C-More Railway (Grün, Grünes Tarnmuster) + C-More Railway (Verde, Boschivo) C-More Railway (Red, Desert) C-More レイルウェイ (グリーン、砂漠迷彩) 씨모어 레일웨이 (빨강, 사막) + C-More Railway (Rot, Wüste) + C-More Railway (Rosso, Desert) C-More Railway (Red, Woodland) C-More レイルウェイ (グリーン、森林迷彩) 씨모어 레일웨이 (빨강, 수풀) + C-More Railway (Rot, Grünes Tarnmuster) + C-More Railway (Rosso, Boschivo) Aimpoint Micro R-1 Aimpoint マイクロ R-1 에임포인트 마이크로 R-1 + Aimpoint Micro R-1 + Aimpoint Micro R-1 Vortex Spitfire Prism Vortex スピットファイア プリズム 버텍스 스핏파이어 프리즘 + Vortex Spitfire Prism + Vortex Spitfire Prism Vortex Spitfire Prism (Tan) Vortex スピットファイア プリズム (タン) 버텍스 스핏파이어 프리즘 (황갈) + Vortex Spitfire Prism (Hellbraun) + Vortex Spitfire Prism (Marroncino) Vortex Spitfire Prism (Khaki) Vortex スピットファイア プリズム (カーキ) 버텍스 스핏파이어 프리즘 (카키) + Vortex Spitfire Prism (Khaki) + Vortex Spitfire Prism (Cachi) Vortex Spitfire Prism (Pistol) Vortex スピットファイア プリズム (ピストル用) 버텍스 스핏파이어 프리즘 (권총용) + Vortex Spitfire Prism (Pistole) + Vortex Spitfire Prism (Pistola) Glock 19X グロック 19X 글록 19X + Glock 19X + Glock 19X Glock 19X (Khaki) グロック 19X (カーキ) 글록 19X (카키) + Glock 19X (Khaki) + Glock 19X (Cachi) Glock 19X (Tan) グロック 19X (タン) 글록 19X (황갈) + Glock 19X (Hellbraun) + Glock 19X (Marroncino) Glock 19X Auto グロック 19X オート 글록 19X 기관권총 + Glock 19X Auto + Glock 19X Auto Glock 19X Auto (Khaki) グロック 19X オート (カーキ) 글록 19X 기관권총 (카키) + Glock 19X Auto (Khaki) + Glock 19X Auto (Cachi) Glock 19X Auto (Tan) グロック 19X オート (タン) 글록 19X 기관권총 (황갈) + Glock 19X Auto (Hellbraun) + Glock 19X Auto (Marroncino) Desert Eagle Mark XIX L5 デザートイーグル Mark XIX L5 데저트 이글 마크 XIX L5 + Desert Eagle Mark XIX L5 + Desert Eagle Mark XIX L5 Desert Eagle Mark XIX L5 (Classic) デザートイーグル Mark XIX L5 (クラシック) 데저트 이글 마크 XIX L5 (클래식) + Desert Eagle Mark XIX L5 (Klassisch) + Desert Eagle Mark XIX L5 (Classico) Desert Eagle Mark XIX L5 (Bronze) デザートイーグル Mark XIX L5 (ブロンズ) 데저트 이글 마크 XIX L5 (브론즈) + Desert Eagle Mark XIX L5 (Bronze) + Desert Eagle Mark XIX L5 (Bronzo) Desert Eagle Mark XIX L5 (Copper) デザートイーグル Mark XIX L5 (カッパー) 데저트 이글 마크 XIX L5 (구리) + Desert Eagle Mark XIX L5 (Kupfer) + Desert Eagle Mark XIX L5 (Rame) Desert Eagle Mark XIX L5 (Gold) デザートイーグル Mark XIX L5 (ゴールド) 데저트 이글 마크 XIX L5 (금색) + Desert Eagle Mark XIX L5 (Gold) + Desert Eagle Mark XIX L5 (Oro) HERA H6 (Tan) HERA H6 (タン) 헤라 H6 (황갈) + HERA H6 (Hellbraun) + HERA H6 (Marroncino) HERA H6 (Olive) HERA H6 (オリーブ) 헤라 H6 (올리브) + HERA H6 (Olivgrün) + HERA H6 (Oliva) HERA H6 (Black) HERA H6 (ブラック) 헤라 H6 (검정) + HERA H6 (Schwarz) + HERA H6 (Nero) HERA H6 (Digital) HERA H6 (AAF迷彩) 헤라 H6 (AAF 디지털) + HERA H6 (Digital) + HERA H6 (Digitale) HERA H6 (Gold) HERA H6 (ゴールド) 헤라 H6 (금색) + HERA H6 (Gold) + HERA H6 (Oro) VS-121 (Black) VS-121 (ブラック) VS-121 (검정) + VS-121 (Schwarz) + VS-121 (Nero) VS-121 (Tan) VS-121 (タン) VS-121 (황갈) + VS-121 (Hellbraun) + VS-121 (Marroncino) Vector SMG (Black) ベクター SMG (ブラック) 벡터 SMG (검정) + Vector SMG (Schwarz) + Vector SMG (Nero) ASh-12 (Black) ASh-12 (ブラック) ASh-12 (검정) + ASh-12 (Schwarz) + ASh-12 (Nero) ASh-12 (Desert) ASh-12 (砂漠迷彩) ASh-12 (사막) + ASh-12 (Wüste) + ASh-12 (Deserto) ASh-12 (Urban) ASh-12 (市街地迷彩) ASh-12 (도심) + ASh-12 (Urban) + ASh-12 (Urbano) ASh-12 (Woodland) ASh-12 (森林迷彩) ASh-12 (수풀) + ASh-12 (Grünes Tarnmuster) + ASh-12 (Boschivo) ASh-12 GL (Black) ASh-12 GL (ブラック) ASh-12 GL (검정) + ASh-12 GL (Schwarz) + ASh-12 GL (Nero) ASh-12 GL (Desert) ASh-12 GL (砂漠迷彩) ASh-12 GL (사막) + ASh-12 GL (Wüste) + ASh-12 GL (Deserto) ASh-12 GL (Urban) ASh-12 GL (市街地迷彩) ASh-12 GL (도심) + ASh-12 GL (Urban) + ASh-12 GL (Urbano) ASh-12 GL (Woodland) ASh-12 GL (森林迷彩) ASh-12 GL (수풀) + ASh-12 GL (Grünes Tarnmuster) + ASh-12 GL (Boschivo) ASh-12 LR (Black) ASh-12 LR (ブラック) ASh-12 LR (검정) + ASh-12 LR (Schwarz) + ASh-12 LR (Nero) ASh-12 LR (Desert) ASh-12 LR (砂漠迷彩) ASh-12 LR (사막) + ASh-12 LR (Wüste) + ASh-12 LR (Deserto) ASh-12 LR (Urban) ASh-12 LR (市街地迷彩) ASh-12 LR (도심) + ASh-12 LR (Urban) + ASh-12 LR (Urbano) ASh-12 LR (Woodland) ASh-12 LR (森林迷彩) ASh-12 LR (수풀) + ASh-12 LR (Grünes Tarnmuster) + ASh-12 LR (Boschivo) AW159 Wildcat ASW AW159 ワイルドキャット ASW AW159 와일드캣 ASW + AW159 Wildcat ASW + AW159 Wildcat ASW AW159 Wildcat ASW (Unarmed) AW159 ワイルドキャット ASW (非武装) AW159 와일드캣 ASW (비무장) + AW159 Wildcat ASW (Unbewaffnet) + AW159 Wildcat ASW (Disarmato) H225 Super Puma (Transport) H225 シュペル ピューマ (輸送型) H225 슈퍼 퓨마 (비무장) + H225 Super Puma (Transport) + H225 Super Puma (Trasporto) H225 Super Puma (Civilian) H225 シュペル ピューマ (民生型) H225 슈퍼 퓨마 (비무장) + H225 Super Puma (Zivil) + H225 Super Puma (Civile) H215 Super Puma (Transport) H215 シュペル ピューマ (輸送型) H215 슈퍼 퓨마 (비무장) + H215 Super Puma (Transport) + H215 Super Puma (Trasporto) H215 Super Puma (Civilian) H215 シュペル ピューマ (民生型) H215 슈퍼 퓨마 (비무장) + H215 Super Puma (Zivil) + H215 Super Puma (Civile) H215 Super Puma (Unarmed) H215 シュペル ピューマ (非武装) H215 슈퍼 퓨마 (비무장) + H215 Super Puma (Unbewaffnet) + H215 Super Puma (Disarmato) H225M Super Cougar SOCAT H225M シュペル クーガー SOCAT H225M 슈퍼 쿠거 SOCAT + H225M Super Cougar SOCAT + H225M Super Cougar SOCAT H225M Super Cougar SOCAT H225M シュペル クーガー SOCAT H225M 슈퍼 쿠거 SOCAT + H225M Super Cougar SOCAT + H225M Super Cougar SOCAT H225M Super Cougar H225M シュペル クーガー H225M 슈퍼 쿠거 + H225M Super Cougar + H225M Super Cougar H225 Super Puma SAR H225 シュペル ピューマ 捜索救難型 H225 슈퍼 퓨마 SAR + H225 Super Puma SAR + H225 Super Puma SAR H225M Super Cougar (Unarmed) H225M シュペル クーガー (非武装) + H225M Super Cougar (Unbewaffnet) + H225M Super Cougar (Disarmato) HEMTT Fire Truck @@ -280,116 +388,161 @@ HEMTT 消防卡车 HEMTT contra incêndio HEMTT 消防車 + HEMTT Autobotte Typhoon Water タイフーン 給水 타이푼 급수 + Typhoon Water + Typhoon Acqua Ram 1500 ラム 1500 램 1500 + Ram 1500 + Ram 1500 Ram 1500 (Fuel) ラム 1500 (燃料) 램 1500 (연료) + Ram 1500 (Treibstoff) + Ram 1500 (Carburante) Ram 1500 (Services) ラム 1500 (サービス) 램 1500 (서비스) + Ram 1500 (Pannenhilfe) + Ram 1500 (Servizi) Ram 1500 (Repair) ラム 1500 (修理) 램 1500 (정비) + Ram 1500 (Instandsetzung) + Ram 1500 (Riparazioni) Ram 1500 (Comms) ラム 1500 (通信) 램 1500 (통신) + Ram 1500 (Kommunikation) + Ram 1500 (Comunicazioni) Ram 1500 (HMG) ラム 1500 (HMG) 램 1500 (중기관총) + Ram 1500 (HMG) + Ram 1500 (HMG) Ram 1500 (MMG) ラム 1500 (MMG) 램 1500 (중형기관총) + Ram 1500 (MMG) + Ram 1500 (MMG) Ram 1500 (MRL) ラム 1500 (MRL) 램 1500 (다연장로켓) + Ram 1500 (MRL) + Ram 1500 (MRL) Ram 1500 (AA) ラム 1500 (対空) 램 1500 (대공) + Ram 1500 (AA) + Ram 1500 (AA) Ram 1500 (Covered) ラム 1500 (カバー) 램 1500 (커버) + Ram 1500 (Abgedeckt) + Ram 1500 (Coperto) Ram 1500 (Water) ラム 1500 (給水) 램 1500 (급수) + Ram 1500 (Wasser) + Ram 1500 (Acqua) RSG60 RSG60 RSG60 + RSG60 + RSG60 AMOS Container AMOS コンテナ AMOS 컨테이너 + AMOS Container + AMOS Container Drone40 ドローン40 드론40 + Drone40 + Drone40 Drone40 Scout ドローン40 偵察型 드론40 정찰 + Drone40 Scout + Drone40 Scout Drone40 HE ドローン40 榴弾 드론40 고폭 + Drone40 HE + Drone40 HE Drone40 Smoke (White) ドローン40 発煙弾 (白) 드론40 연막 (백색) + Drone40 Smoke (Weiß) + Drone40 Smoke (Bianco) Drone40 Smoke (Blue) ドローン40 発煙弾 (青) 드론40 연막 (청색) + Drone40 Smoke (Blau) + Drone40 Smoke (Blu) Drone40 Smoke (Red) ドローン40 発煙弾 (赤) 드론40 연막 (적색) + Drone40 Smoke (Rot) + Drone40 Smoke (Rosso) Drone40 Smoke (Green) ドローン40 発煙弾 (緑) 드론40 연막 (녹색) + Drone40 Smoke (Grün) + Drone40 Smoke (Verde) Drone40 Smoke (Orange) ドローン40 発煙弾 (橙) 드론40 연막 (주황색) + Drone40 Smoke (Orange) + Drone40 Smoke (Arancione) diff --git a/addons/compat_ws/compat_ws_realisticnames/stringtable.xml b/addons/compat_ws/compat_ws_realisticnames/stringtable.xml index 82efb554d9..606bbb7932 100644 --- a/addons/compat_ws/compat_ws_realisticnames/stringtable.xml +++ b/addons/compat_ws/compat_ws_realisticnames/stringtable.xml @@ -260,11 +260,15 @@ FN FAL OSW Para FN FAL OSW パラ FN FAL OSW 파라 + FN FAL OSW Fallschirmjäger + FN FAL OSW Para FN FAL OSW Para (Snake) FN FAL OSW パラ (ヘビ柄迷彩) FN FAL OSW 파라 (뱀 위장) + FN FAL OSW Fallschirmjäger (Schlange) + FN FAL OSW Para (Serpe) Vektor R4 @@ -462,191 +466,267 @@ GM6 Lynx (Snake) GM6 リンクス (ヘビ柄迷彩) GM6 링스 (뱀 위장) + GM6 Lynx (Schlange) + GM6 Lynx (Serpe) RPG-32 (Sand) RPG-32 (サンド) RPG-32 (모래) + RPG-32 (Sand) + RPG-32 (Sabbia) ELCAN SpecterOS (Hex) ELCAN SpecterOS (六角形迷彩) 엘칸 스펙터OS (육각) + ELCAN SpecterOS (Hex) + ELCAN SpecterOS (Hex) EOTech XPS3 (Snake) EOTech XPS3 (ヘビ柄迷彩) 이오텍 XPS3 (뱀 위장) + EOTech XPS3 (Schlange) + EOTech XPS3 (Serpe) EOTech XPS3 SMG (Snake) EOTech XPS3 SMG (ヘビ柄迷彩) 이오텍 XPS3 SMG (뱀 위장) + EOTech XPS3 SMG (Schlange) + EOTech XPS3 SMG (Serpe) Leupold Mark 4 HAMR (Arid) Leupold Mark 4 HAMR (乾燥地帯迷彩) 류폴드 마크 4 HAMR (건조) + Leupold Mark 4 HAMR (Trocken) + Leupold Mark 4 HAMR (Arido) Leupold Mark 4 HAMR (Lush) Leupold Mark 4 HAMR (緑地迷彩) 류폴드 마크 4 HAMR (초목) + Leupold Mark 4 HAMR (Grün) + Leupold Mark 4 HAMR (Verdeggiante) Leupold Mark 4 HAMR (Sand) Leupold Mark 4 HAMR (サンド) 류폴드 마크 4 HAMR (모래) + Leupold Mark 4 HAMR (Sand) + Leupold Mark 4 HAMR (Sabbia) Leupold Mark 4 HAMR (Snake) Leupold Mark 4 HAMR (ヘビ柄迷彩) 류폴드 마크 4 HAMR (뱀 위장) + Leupold Mark 4 HAMR (Schlange) + Leupold Mark 4 HAMR (Serpe) Aimpoint Micro R-1 (High, Black) Aimpoint マイクロ R-1 (ハイマウント、ブラック) 에임포인트 마이크로 R-1 (높음, 검정) + Aimpoint Micro R-1 (Hoch, Schwarz) + Aimpoint Micro R-1 (Alto, Nero) Aimpoint Micro R-1 (High, Khaki) Aimpoint マイクロ R-1 (ハイマウント、カーキ) 에임포인트 마이크로 R-1 (높음, 카키) + Aimpoint Micro R-1 (Hoch, Khaki) + Aimpoint Micro R-1 (Alto, Cachi) Aimpoint Micro R-1 (High, Sand) Aimpoint マイクロ R-1 (ハイマウント、サンド) 에임포인트 마이크로 R-1 (높음, 모래) + Aimpoint Micro R-1 (Hoch, Sand) + Aimpoint Micro R-1 (Alto, Sabbia) Aimpoint Micro R-1 (High, Snake) Aimpoint マイクロ R-1 (ハイマウント、ヘビ柄迷彩) 에임포인트 마이크로 R-1 (높음, 뱀 위장) + Aimpoint Micro R-1 (Hoch, Schlange) + Aimpoint Micro R-1 (Alto, Serpe) Aimpoint Micro R-1 (High, Arid) Aimpoint マイクロ R-1 (ハイマウント、乾燥地帯迷彩) 에임포인트 마이크로 R-1 (높음, 건조) + Aimpoint Micro R-1 (Hoch, Trocken) + Aimpoint Micro R-1 (Alto, Arido) Aimpoint Micro R-1 (High, Lush) Aimpoint マイクロ R-1 (ハイマウント、緑地迷彩) 에임포인트 마이크로 R-1 (높음, 초목) + Aimpoint Micro R-1 (Hoch, Grün) + Aimpoint Micro R-1 (Alto, Verdeggiante) Aimpoint Micro R-1 (High, Black/Sand) Aimpoint マイクロ R-1 (ハイマウント、ブラック/サンド) 에임포인트 마이크로 R-1 (높음, 검정/모래) + Aimpoint Micro R-1 (Hoch, Schwarz/Sand) + Aimpoint Micro R-1 (Alto, Nero/Sabbia) Aimpoint Micro R-1 (Low, Black) Aimpoint マイクロ R-1 (ローマウント、ブラック) 에임포인트 마이크로 R-1 (낮음, 검정) + Aimpoint Micro R-1 (Tief, Schwarz) + Aimpoint Micro R-1 (Basso, Nero) Aimpoint Micro R-1 (Low, Khaki) Aimpoint マイクロ R-1 (ローマウント、カーキ) 에임포인트 마이크로 R-1 (낮음, 카키) + Aimpoint Micro R-1 (Tief, Khaki) + Aimpoint Micro R-1 (Basso, Cachi) Aimpoint Micro R-1 (Low, Sand) Aimpoint マイクロ R-1 (ローマウント、サンド) 에임포인트 마이크로 R-1 (낮음, 모래) + Aimpoint Micro R-1 (Tief, Sand) + Aimpoint Micro R-1 (Basso, Sabbia) Aimpoint Micro R-1 (Low, Snake) Aimpoint マイクロ R-1 (ローマウント、ヘビ柄迷彩) 에임포인트 마이크로 R-1 (낮음, 뱀 위장) + Aimpoint Micro R-1 (Tief, Schlange) + Aimpoint Micro R-1 (Basso, Serpe) Aimpoint Micro R-1 (Low, Arid) Aimpoint マイクロ R-1 (ローマウント、乾燥地帯迷彩) 에임포인트 마이크로 R-1 (낮음, 건조) + Aimpoint Micro R-1 (Tief, Trocken) + Aimpoint Micro R-1 (Basso, Arido) Aimpoint Micro R-1 (Low, Lush) Aimpoint マイクロ R-1 (ローマウント、緑地迷彩) 에임포인트 마이크로 R-1 (낮음, 초목) + Aimpoint Micro R-1 (Tief, Grün) + Aimpoint Micro R-1 (Basso, Verdeggiante) Burris XTR II (Snake) Burris XTR II (ヘビ柄迷彩) 버리스 XTR II (뱀 위장) + Burris XTR II (Schlange) + Burris XTR II (Serpe) Badger IFV (ATGM) バジャー IFV (ATGM) 뱃져 보병전투차 (대전차미사일) + Badger IFV (PzAbw) + Badger IFV (ATGM) Badger IFV (Command) バジャー IFV (指揮) 뱃져 보병전투차 (지휘) + Badger IFV (Kommando) + Badger IFV (Comando) Badger IFV (Mortar) バジャー IFV (迫撃砲) 뱃져 보병전투차 (자주박격포) + Badger IFV (Mörser) + Badger IFV (Mortaio) KamAZ (Zu-23-2) KamAZ (Zu-23-2) 카마즈 (ZU-23-2) + KamAZ (Zu-23-2) + KamAZ (Zu-23-2) KamAZ Cargo KamAZ 貨物 카마즈 화물 + KamAZ Fracht + KamAZ Carico KamAZ Repair KamAZ 修理 카마즈 정비 + KamAZ Instandsetzung + KamAZ Riparazione KamAZ Racing KamAZ レース仕様 카마즈 경주용 + KamAZ Rennlaster + KamAZ da corsa KamAZ Ammo KamAZ 弾薬 카마즈 탄약 + KamAZ Munition + KamAZ Munizioni KamAZ Flatbed KamAZ フラットベッド 카마즈 플랫베드 + KamAZ Flachbett + KamAZ Pianale AW101 Merlin AW101 マーリン AW101 멀린 + AW101 Merlin + AW101 Merlin BM-2T Stalker (Bumerang-BM) BM-2T ストーカー (ブーメランク-BM) BM-2T 스토커 (부메랑-BM) + BM-2T Stalker (Bumerang-BM) + BM-2T Stalker (Bumerang-BM) Otokar ARMA (HMG) オトカ アルマ (HMG) 오토카르 아르마 APC (중기관총) + Otokar ARMA (HMG) + Otokar ARMA (HMG) Otokar ARMA (Unarmed) オトカ アルマ (非武装) 오토카르 아르마 APC (비무장) + Otokar ARMA (Unbewaffnet) + Otokar ARMA (Disarmato) Ka-60 Kasatka (UP) Ka-60 カサートカ (UP) Ka-60 카사트카 (UP) + Ka-60 Kasatka (UP) + Ka-60 Kasatka (UP) Ka-60 Kasatka (UP, Unarmed) Ka-60 カサートカ (UP、非武装) Ka-60 카사트카 (UP, 비무장)) + Ka-60 Kasatka (UP, Unbewaffnet) + Ka-60 Kasatka (UP, Disarmato) diff --git a/addons/cookoff/stringtable.xml b/addons/cookoff/stringtable.xml index 745b686b8a..15d2d2adec 100644 --- a/addons/cookoff/stringtable.xml +++ b/addons/cookoff/stringtable.xml @@ -4,7 +4,7 @@ ACE Cook-off ACE Detonación inducida por calor - ACE Detonazione Munizioni + ACE Esplosioni di Munizioni ACE 殉爆效果 ACE 殉爆效果 ACE 誘爆 @@ -21,36 +21,48 @@ 車両の誘爆火災を有効化 Вкл. возгорание техники 차량 유폭 화재를 활성화합니다 + Abilita incendio dei veicoli + Aktiviert Fahrzeug Munitionsbrand Enables vehicle cook-off fire effects.\nThis doesn't include ammunition detonations. 車両の誘爆火災エフェクトを有効化します。\nこれには弾薬の爆発は含まれません。 Вкл. эффект горения техники. \nНе включает детонацию боекомплекта 차량 유폭 효과를 활성화합니다.\n여기엔 탄약 유폭이 포함되지 않습니다. + Abilita effetti di incendio del veicolo dovuto all'esplosione delle munizioni.\nQuesto non include gli effetti di esplosione. + Aktiviert Fahrzeug Brandeffekte durch Durchzündung.\nExplosionseffekte sind nicht mit einbegriffen. Vehicle cook-off fire duration multiplier 車両の誘爆火災の持続時間倍率 Увел. продолжительности горения техники 차량 유폭 화재 지속 시간 계수 + Coefficiente di durata incendio dei veicoli + Fahrzeugbrand Dauer-Multiplikator Multiplier for how long vehicle cook-off fire lasts.\nSetting to 0 will disable vehicle cook-off fire. 車両の誘爆火災の持続時間をどのくらいの長さにするかの倍率。\n0に設定すると車両の誘爆火災が無効化されます。 Увел. продолжительности горения техники. \nУстановка значения на 0 выключает возгорание техники. 차량 유폭 화재가 지속되는 시간에 대한 계수입니다.\n0으로 설정하면 차량 쿸오프 화재가 비활성화됩니다. + Coefficiente di durata degli incendi dei veicoli.\nImpostarlo su 0 disabilita incendi dei veicoli. + Multiplikator der Fahrzeugbrand Dauer.\nIhn auf 0 zu setzen wird Munitionsbrände deaktivieren. Vehicle cook-off fire probability multiplier 車両の誘爆火災の可能性倍率 Возможность усиления пожара при детонации техники 차량 유폭 화재 확률 계수 + Probabilità di incendio dei veicoli + Fahrzeug Munitionsbrand Wahrscheinlichkeit-Multiplikator Multiplier for vehicle cook-off fire probability. Higher value results in higher cook-off probability.\nSetting to 0 will disable vehicle cook-off fire. 車両の誘爆火災がどのくらいの可能性で発生するかの倍率。高い数値は高い誘爆の可能性につながります。\n0に設定すると車両の誘爆火災が無効化されます。 Увел. вероятности возникновения возгорания техники. Большое значение указывает на высокую вероятность детонации. \nУстановка значения 0 предотвращает возгорание техники. 차량 유폭 화재 확률에 대한 계수입니다. 값이 높을 수록 유폭 확률이 높아집니다.\n0으로 설정하면 차량 유폭 화재가 비활성화됩니다. + Coefficiente di probabilità degli incendi dei veicoli.\nValori maggiori aumentano la probabilità di incendi.\nImpostarlo su 0 disabilita incendi dei veicoli. + Multiplikator der Fahrzeugbrand Wahrscheinlichkeit.\nHöhere Werte erhöhen die Wahrscheinlichkeit.\nEin Null-Wert wird Munitionsbrände deaktivieren. Destroy vehicles after cook-off @@ -82,12 +94,16 @@ 車両弾薬の誘爆を有効化 Вкл. детонацию боеприпасов в технике. 차량 내 탄약 유폭 활성화 + Abilita esplosioni delle munizioni dei veicoli + Aktiviert Fahrzeug Munitionsdurchzündung Enables cooking off of vehicle ammunition. Fires ammunition projectiles while vehicle has ammunition remaining.\nThis doesn't include fire effects. 車両弾薬の誘爆を有効化します。車両に積載されたままの弾薬と弾頭が発射されます。\nこれには火災エフェクトは含まれません。 Вкл. детонацию боеприпасов на технике. Боеприпасы и боеголовки, которые остаются заряженными на транспортном средстве, будут приведены в действие. \nЭто не включает эффекты пожара. 차량 내 탄약 유폭을 활성화합니다. 차량에 탄약이 남아 있는 동안 탄약 발사체를 발사합니다.\n여기엔 화재 효과가 포함되지 않습니다. + Abilita l'esplosione delle munizioni dei veicoli. Spara via pezzi di munizioni se il veicolo ha ancora munizioni rimanenti.\nNon include gli effetti di fuoco. + Aktiviert Durchzündung von Fahrzeugmunition. Schleudert Munitionsfragmente umher wenn das Fahrzeug noch Munition an Bord hat.\nBrandeffekte sind nicht mit einbegriffen. Enable ammo box cook-off @@ -109,18 +125,24 @@ 弾薬箱の誘爆を有効化します。\nこれには火災エフェクトは含まれません。 Вкл. детонацию ящика с боеприпасами. \nЭто не включает эффекты огня. 탄약 상자 유폭을 활성화합니다.\n여기엔 화재 효과가 포함되지 않습니다. + Abilita esplosioni delle casse di munizioni.\nNon include effetti di fuoco. + Aktiviert Munitionskisten Durchzündung.\nBrandeffekte sind nicht mit einbegriffen. Ammo cook-off duration multiplier 弾薬の誘爆の持続時間倍率 Увеличение продолжительности детонации боеприпасов. 탄약 유폭 시간 계수 + Coefficiente di durata esplisioni di munizioni + Fahrzeug Munitionsdurchzündung Dauer-Multiplikator Multiplier for how long ammunition cook-off lasts, for both vehicles and ammo boxes.\nSetting to 0 will disable ammo cook-off for both vehicles and ammo boxes. 弾薬の誘爆の持続時間をどのくらいの長さにするかの倍率。車両弾薬と弾薬箱どちらにも影響します。\n0に設定すると弾薬の誘爆が無効化されます。 Увеличение продолжительности детонации боеприпасов. Это влияет как на боеприпасы в технике, так и на ящики с боеприпасами. \nУстановка значения 0 отключает детонацию боеприпасов. 차량과 탄약 상자 모두에 대해 탄약 유폭이 지속되는 시간에 대한 계수입니다.\n0으로 설정하면 차량과 탄약 상자 모두에 대해 탄약 유폭이 비활성화됩니다. + Coefficiente della durata di esplosioni delle munizioni, sia per veicoli che casse.\nImpostarlo su 0 disabilita esplosioni di veicoli e casse. + Multiplikator der Munitionsdurchzündungs-Dauer, gilt für Fahrzeuge und Munitionskisten.\nIhn auf 0 zu setzen wird Durchzünden deaktivieren. Enable ammo removal during cook-off @@ -141,6 +163,7 @@ 誘爆によって全ての弾薬を除去します。 Все боеприпасы уничтожаются путем подрыва. 유폭 중 모든 탄약을 제거합니다. + Rimuovi le munizioni dal veicolo durante le esplosioni. diff --git a/addons/csw/stringtable.xml b/addons/csw/stringtable.xml index 7c241a8a51..da794376ab 100644 --- a/addons/csw/stringtable.xml +++ b/addons/csw/stringtable.xml @@ -263,7 +263,7 @@ インタラクションの所要時間係数 互動時間係數 交互时间系数 - Coefficente per il tempo di interazione + Coefficiente per il tempo di interazione Koeficient času interakce Współczynnik czasu interakcji Coeficiente de tiempo de interacción diff --git a/addons/grenades/stringtable.xml b/addons/grenades/stringtable.xml index 04cc6d20e2..b0630e3a43 100644 --- a/addons/grenades/stringtable.xml +++ b/addons/grenades/stringtable.xml @@ -108,6 +108,8 @@ この手榴弾は転がせません、 %1 に切り替えます Эта граната не может быть брошена, переключитесь на %1 이 수류탄은 굴릴 수 없습니다. %1(으)로 전환되었습니다. + Granate kann nicht rollen, zu %1 gewechselt + Granata non può rotolare, cambiato a %1 M84 Stun Grenade diff --git a/addons/hitreactions/stringtable.xml b/addons/hitreactions/stringtable.xml index 8cc25a53a5..ff541ad6a3 100644 --- a/addons/hitreactions/stringtable.xml +++ b/addons/hitreactions/stringtable.xml @@ -22,12 +22,16 @@ プレイヤーが武器を落とす確率 (腕部への被弾) Шанс выпадения оружия у игрока (попадание в руку) 플레이어가 무기를 떨굴 확률 (팔 피격) + Spieler Wahrscheinlichkeit, die Waffe fallen zu lassen (Arm Treffer) + Probabilità dei giocatori di far cadere l'arma (colpo al braccio) AI Weapon Drop Chance (Arm Hit) AIが武器を落とす確率 (腕部への被弾) Шанс выпадения оружия у ИИ (попадание в руку) 인공지능이 무기를 떨굴 확률 (팔 피격) + KI-Wahrscheinlichkeit, die Waffe fallen zu lassen (Arm Treffer) + Probabilità dell'IA di far cadere l'arma (colpo al braccio) diff --git a/addons/killtracker/stringtable.xml b/addons/killtracker/stringtable.xml index 64fedfe320..61db7afab5 100644 --- a/addons/killtracker/stringtable.xml +++ b/addons/killtracker/stringtable.xml @@ -122,10 +122,14 @@ Show vehicle kills to other crew members Показать уничтоженные машины другим членам экипажа + Zeige der Fahrzeugbesatzung die Abschüsse des Fahrzeugs + Mostra uccisioni del veicolo a membri dell'equipaggio Show kills from a vehicle to driver, gunner and commander Показать уничтоженную технику водителю, стрелку и командиру + Zeige Abschüsse des Fahrzeugs dem Fahrer, Richtschützen und Kommandanten an + Mostra uccisioni del veicolo al pilota, artigliere e comandante diff --git a/addons/medical_treatment/stringtable.xml b/addons/medical_treatment/stringtable.xml index 6593042d2a..930562434f 100644 --- a/addons/medical_treatment/stringtable.xml +++ b/addons/medical_treatment/stringtable.xml @@ -82,6 +82,8 @@ 有効 & 死亡/心停止状態を診断可能 [直接的に] Включено и может диагностировать смерть/остановку сердца [Напрямую] 활성화 및 사망/심정지 진찰 가능 [직접] + Aktiviert & kann Tod/Herzstillstand diagnostizieren [Direkt] + Abilitato e può diagnosticare Morte/Arresto Cardiaco [Esplicito] Advanced Medication @@ -4164,6 +4166,8 @@ %1 は意識がない %1 находится без сознания %1은(는) 의식불명입니다 + %1 ist bewusstlos + %1 è privo di sensi %1 is not responsive, taking shallow gasps and convulsing @@ -4182,6 +4186,8 @@ %1 は心停止している У %1 произошла остановка сердца %1은(는) 심정지 상태입니다 + %1 ist im Herzstillstand + %1 è in arresto cardiaco %1 is not responsive, motionless and cold @@ -4200,6 +4206,8 @@ %1 は死亡している %1 мертв %1은(는) 사망했습니다 + %1 ist tod + %1 è morto You checked %1 diff --git a/addons/microdagr/stringtable.xml b/addons/microdagr/stringtable.xml index 786cb15b95..c9bd546afc 100644 --- a/addons/microdagr/stringtable.xml +++ b/addons/microdagr/stringtable.xml @@ -357,7 +357,7 @@ 切換微型軍用GPS接收器顯示模式 - Show MicoDAGR + Show MicroDAGR Zeige MicroDAGR Mostrar MicroDAGR Показать MicroDAGR diff --git a/addons/overpressure/stringtable.xml b/addons/overpressure/stringtable.xml index f981fbc009..74a6b3a54e 100644 --- a/addons/overpressure/stringtable.xml +++ b/addons/overpressure/stringtable.xml @@ -20,7 +20,7 @@ 과중압력 거리 계수 Mnożnik dystansu nadciśnienia Coefficient de distance pour la surpression - Coefficente Distanza Sovrapressione + Coefficiente Distanza Sovrapressione 超压影响距离系数 高壓影響距離係數 Коэф. избыточного давления @@ -48,10 +48,14 @@ Backblast Distance Coefficient Коэффициент расстояния рекативной струи + Rückstrahl-Entfernung Multiplikator + Coefficiente distanza di svampata Scales the backblast effect Масштабирует эффект реактивной струи + Skaliert den Rückstrahl-Effekt + Scala l'effetto delle svampate dei lanciarazzi Backblast range diff --git a/addons/realisticnames/stringtable.xml b/addons/realisticnames/stringtable.xml index 5fc19bb9bf..70b78e6d25 100644 --- a/addons/realisticnames/stringtable.xml +++ b/addons/realisticnames/stringtable.xml @@ -704,6 +704,8 @@ KamAZ 給水 КамАЗ (водоноситель) 카마즈 급수 + KamAS Wasser + KamAZ Acqua KamAZ MRL @@ -1668,6 +1670,8 @@ CZ 581 CZ 581 CZ 581 + CZ 581 + CZ 581 CZ 581 (Sawed-Off) @@ -1675,6 +1679,8 @@ CZ 581 (ソードオフ) CZ 581 (Sawed-Off) CZ 581 (소드오프) + CZ 581 (Abgesägt) + CZ 581 (Canne mozze) FNX-45 Tactical (Green) @@ -3083,6 +3089,8 @@ Type 115 (ブラック) Type 115 (чёрный) 115식 보총 (검정) + Type 115 (Schwarz) + Type 115 (Nero) Type 115 (Green Hex) @@ -3090,6 +3098,8 @@ Type 115 (緑六角形迷彩) Type 115 (зелёный гекс) 115식 보총 (초록육각) + Type 115 (Hex Grün) + Type 115 (Hex Verde) Type 115 (Hex) @@ -3097,6 +3107,8 @@ Type 115 (六角形迷彩) Type 115 (гекс) 115식 보총 (육각) + Type 115 (Hex) + Type 115 (Hex) QBZ-95-1 (Black) @@ -3888,6 +3900,8 @@ UTG ディフェンダー 126 UTG Defender 126 UTG 디펜더 126 + UTG Defender 126 + UTG Defender 126 EOTech MRDS @@ -3895,6 +3909,8 @@ EOTech MRDS EOTech MRDS 이오텍 MRDS + EOTech MRDS + EOTech MRDS EOTech MRDS (Black) @@ -3902,6 +3918,8 @@ EOTech MRDS (ブラック) EOTech MRDS (чёрный) 이오텍 MRDS (검정) + EOTech MRDS (Schwarz) + EOTech MRDS (Nero) Leupold Mark 4 HAMR diff --git a/addons/zeus/stringtable.xml b/addons/zeus/stringtable.xml index 59597da0b4..28a73213ca 100644 --- a/addons/zeus/stringtable.xml +++ b/addons/zeus/stringtable.xml @@ -2004,7 +2004,7 @@ + Shift 키로 강제하기 (동서남북 방향으로만 깔 수 있음) +MAJ pour forcer (Disponible uniquement sur les alignements N/S ou E/O) +SHIFT zum Erzwingen (Kann nur nach N/S oder E/W legen) - +SHIFT per forzare (Può piazzare solo N/S o E/O + +SHIFT per forzare (Può piazzare solo N/S o E/O) +SHIFTキー で強制的に敷設 (北/南または東/西方向にのみ配置可能) +SHIFT на принудительное (может укладываться только на Север/Юг или Восток/Запад) +SHIFT para forzar (Puede solo colocar en N/S or E/O) @@ -2014,42 +2014,56 @@ 観戦インターフェイスを強制し、ユーザーがEscキーでも閉じられないようにします。 Активирует интерфейс spectator, не позволяя игроку закрыть его с помощью клавиши Escape. 플레이어가 Esc 키로 관전자 인터페이스를 닫지 못하도록 강제로 관전자 인터페이스를 설정합니다. + Erzwingt die Zuschauer-Ansicht und verhindert dass der Spieler sie mit der Esc-Taste schließen kann + Forza l'interfaccia di spettatore, impedendo al giocatore di chiuderla con il tasto Esc Hide player プレイヤーを隠す Скрыть игрока 플레이어 숨기기 + Spieler ausblenden + Nascondi giocatore Hides the player by making them invisible, invulnerable, muted, and removing them from their group 透明化、無敵化、ミュート、グループからの除外を行いプレーヤーを隠します Скрывает игрока, делая его невидимым, неуязвимым, отключая звук и удаляя из группы. 플레이어를 투명, 무적, 음소거화하고 그룹에서 제거하여 숨깁니다. + Blendet den Spieler aus, macht ihn unsichtbar, unverwundbar, stumm und entfernt ihn von seiner Gruppe + Nasconde il giocatore, rendendolo invisibile, invulnerabile, muto e lo rimuove dal proprio gruppo Sets the sides that are available to spectate 指定の陣営を観戦可能に設定します Устанавливает стороны, доступные для режима spectator 관전 가능한 진영을 설정합니다. + Bestimmt die Seiten denen man zuschauen kann + Imposta le fazioni che lo spettatore può osservare White Hot 白=熱源 Белый 백색 열원 + Weiß-Schwarz + Bianco-caldo Black Hot 黒=熱源 Чёрный 흑색 열원 + Schwarz-Weiß + Nero-caldo Toggle All 全てを切り替え Выключить все 전부 토글 + Alle wechseln + Cambia tutti From ad4af0d5537504ce287776b3b3c00d112d74930a Mon Sep 17 00:00:00 2001 From: Apricot <50947830+Apricot-ale@users.noreply.github.com> Date: Wed, 26 Jun 2024 11:43:24 +0900 Subject: [PATCH 120/290] Translations - Improve Japanese (killtracker/overpressure) (#10088) killtracker/overpressure --- addons/killtracker/stringtable.xml | 14 ++++++++------ addons/overpressure/stringtable.xml | 12 +++++++----- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/addons/killtracker/stringtable.xml b/addons/killtracker/stringtable.xml index 61db7afab5..b7a97df15a 100644 --- a/addons/killtracker/stringtable.xml +++ b/addons/killtracker/stringtable.xml @@ -6,7 +6,7 @@ ACE Tracciatore di Uccisioni ACE Kill Tracker ACE Отслеживание убийств - ACE キルトラッカー + ACE キル追跡 ACE 킬트래커 ACE Suivi des morts ACE Abschüsse @@ -30,7 +30,7 @@ Всего убийств: Liczba zabójstw: Toplam Öldürme: - 総キル: + 合計キル数: Gesammte Abschüsse: Uccisioni Totali: 总击杀数: @@ -44,7 +44,7 @@ Убил: %1 %2 Zabójstwo: %1 %2 Öldürülen: %1 %2 - キル: %1 %2 + 殺害: %1 %2 Abschuss: %1 %2 Uccisione: %1 %2 击杀:%1 %2 @@ -58,7 +58,7 @@ Убийца: %1 %2 Zabójca: %1 %2 Öldüren: %1 %2 - キラー: %1 %2 + 殺害者: %1 %2 Täter: %1 %2 Uccisore: %1 %2 击杀者:%1 %2 @@ -102,7 +102,7 @@ Traccia IA uccise da giocatori Sledovat AI zabité hráči Отслеживание юнитов ИИ, убитых игроком - プレイヤーに殺害されたAIユニットを追跡 + プレイヤーがキルしたAIユニットを追跡 플레이어가 죽인 AI 트래킹 Suivi de l'IA tuée par les joueurs Zähle vom Spieler getöteten KI-Einheiten @@ -113,7 +113,7 @@ Determina se IA uccise verranno visualizzate nel tracciatore durante il debriefing della missione. Udává zdali se zabité AI budou ukazovat v kill trackeru v průběhu debriefingu po misi. Определяет, будут ли убитые ИИ отображаться в трекере убийств во время дебрифинга миссии. - ミッションデブリーフィングのキルトラッカーに殺害されたAIが表示されるかどうかを定義します。 + キルしたAIをミッション終了デブリーフィング画面に表示させるかどうかを定義します。 사후강평 중 살해된 AI가 킬트래킹에 표시되는지 여부를 정의합니다. Définit si les IA tuées seront affichées dans le tracker pendant le débriefing de la mission. Legt fest, ob getötete KIs während des Endbildschirms der Mission in den Abschüssen angezeigt werden. @@ -124,12 +124,14 @@ Показать уничтоженные машины другим членам экипажа Zeige der Fahrzeugbesatzung die Abschüsse des Fahrzeugs Mostra uccisioni del veicolo a membri dell'equipaggio + 車両でのキルを乗員全員に表示する Show kills from a vehicle to driver, gunner and commander Показать уничтоженную технику водителю, стрелку и командиру Zeige Abschüsse des Fahrzeugs dem Fahrer, Richtschützen und Kommandanten an Mostra uccisioni del veicolo al pilota, artigliere e comandante + 車両でのキルを操縦手、砲手、車長で共有して表示する diff --git a/addons/overpressure/stringtable.xml b/addons/overpressure/stringtable.xml index 74a6b3a54e..0d43f01825 100644 --- a/addons/overpressure/stringtable.xml +++ b/addons/overpressure/stringtable.xml @@ -8,7 +8,7 @@ Sovrapressione 과중압력 Nadciśnienie - 過圧 + 超過圧力 Перегрузка Sobrepresiòn Surpression @@ -16,7 +16,7 @@ Overpressure Distance Coefficient Überdruckentfernungskoeffizient - 過圧の距離係数 + 超過圧力の距離係数 과중압력 거리 계수 Mnożnik dystansu nadciśnienia Coefficient de distance pour la surpression @@ -32,7 +32,7 @@ Scales the overpressure effect Stellt den Koeffizient für die Überdruckentfernung ein - 過圧効果の範囲 + 火砲による超過圧力の影響範囲の大きさ 과중압력의 효과 크기 Skaluje efekt nadciśnienia Ajuste l'effet de surpression @@ -50,17 +50,19 @@ Коэффициент расстояния рекативной струи Rückstrahl-Entfernung Multiplikator Coefficiente distanza di svampata + 後方噴射の距離係数 Scales the backblast effect Масштабирует эффект реактивной струи Skaliert den Rückstrahl-Effekt Scala l'effetto delle svampate dei lanciarazzi + 無反動砲による後方噴射の影響範囲の大きさ Backblast range Rückstrahlzone - 後方噴射の範囲 + 後方噴射範囲 向后喷射的范围 後方尾焰的範圍 Raggio della fiammata [lanciarazzi] @@ -76,7 +78,7 @@ Backblast angle Rückstrahlwinkel - 後方噴射の角度 + 後方噴射角度 向后喷射的角度 後方尾焰的角度 Angolo della fiammata [lanciarazzi] From bfa23f01db9a9f70918b2768ea0dfd259b7f3c8e Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 26 Jun 2024 14:02:19 +0200 Subject: [PATCH 121/290] Refuel - Remove unused variable (#10089) Update XEH_postInit.sqf --- addons/refuel/XEH_postInit.sqf | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/refuel/XEH_postInit.sqf b/addons/refuel/XEH_postInit.sqf index f6f5a7d7b3..d007266e5f 100644 --- a/addons/refuel/XEH_postInit.sqf +++ b/addons/refuel/XEH_postInit.sqf @@ -49,7 +49,6 @@ private _halfWorldSize = worldSize / 2; private _worldCenter = [_halfWorldSize, _halfWorldSize]; _halfWorldSize = _halfWorldSize * sqrt 2; - private _refuelMissionObjects = allMissionObjects "" select {getFuelCargo _x > 0}; private _baseStaticClasses = keys (uiNamespace getVariable QGVAR(cacheRefuelClassesBaseStatic)); { From a30afe69b71d6c13fd0c977e50755f194ee60973 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Fri, 28 Jun 2024 14:41:04 +0200 Subject: [PATCH 122/290] Interaction - Disable magazine passing to dead and unconscious units (#10091) * Disable magazine passing to dead units * Disable for unconscious units as well --- addons/interaction/functions/fnc_canPassMagazine.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/interaction/functions/fnc_canPassMagazine.sqf b/addons/interaction/functions/fnc_canPassMagazine.sqf index 9d0bed083d..97478bffa7 100644 --- a/addons/interaction/functions/fnc_canPassMagazine.sqf +++ b/addons/interaction/functions/fnc_canPassMagazine.sqf @@ -19,7 +19,7 @@ params ["_player", "_target", "_weapon"]; if (!GVAR(enableMagazinePassing)) exitWith {false}; -if (_weapon isEqualTo "") exitWith {false}; +if (_weapon isEqualTo "" || {!(_target call EFUNC(common,isAwake))}) exitWith {false}; if (((vehicle _target) != _target) && {(vehicle _target) != (vehicle _player)}) exitWith {false}; private _compatibleMags = [_weapon] call CBA_fnc_compatibleMagazines; From cb40c8ec5dfd81c210c394eb67f237de590aac0c Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Fri, 28 Jun 2024 19:43:13 +0200 Subject: [PATCH 123/290] Vehicle damage - Add missing documentation (#10093) Update vehicledamage-framework.md --- docs/wiki/framework/vehicledamage-framework.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/wiki/framework/vehicledamage-framework.md b/docs/wiki/framework/vehicledamage-framework.md index 0d4268bf5e..04137e9c73 100644 --- a/docs/wiki/framework/vehicledamage-framework.md +++ b/docs/wiki/framework/vehicledamage-framework.md @@ -65,23 +65,29 @@ Default: 0.2 #### 1.1.8 `ace_vehicle_damage_canHaveFireRing` -Whether or not this vehicle can spawn `ring-of-fire` effect (Boolean value: 0 or 1) +Whether or not this vehicle can spawn a `ring-of-fire` effect (Boolean value: 0 or 1) Default: 0 -#### 1.1.9 `ace_vehicle_damage_slatHitpoints` +#### 1.1.9 `ace_cookoff_canHaveFireJet` + +Whether or not this vehicle can spawn a `jet` effect (Boolean value: 0 or 1) + +Default: 0 + +#### 1.1.10 `ace_vehicle_damage_slatHitpoints` An array of all hitpoints that are defined to be SLAT. String array Default: {} -#### 1.1.10 `ace_vehicle_damage_eraHitpoints` +#### 1.1.11 `ace_vehicle_damage_eraHitpoints` An array of all hitpoints that are defined to be ERA. String array Default: {} -#### 1.1.11 `ace_vehicle_damage_turret` +#### 1.1.12 `ace_vehicle_damage_turret` String for turret classname to spawn when catastrophically destroyed. Turret will pop-off and this is the class spawned From 71afce53c1bde666369344652a30a71ec8ad751a Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 1 Jul 2024 18:56:00 +0200 Subject: [PATCH 124/290] Dogtags - Make "Dog Tag" consistent (#10099) Make Dog Tag consistent --- addons/dogtags/stringtable.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/dogtags/stringtable.xml b/addons/dogtags/stringtable.xml index d19c61f505..73d2d07e56 100644 --- a/addons/dogtags/stringtable.xml +++ b/addons/dogtags/stringtable.xml @@ -66,7 +66,7 @@ Al - Dogtag taken from %1... + Dog Tag taken from %1... Zabrałeś nieśmiertelnik %1... Жетон снят с %1... Sebral jsem známku od %1... @@ -82,7 +82,7 @@ Künye %1 kişisinden alındı - Somebody else has already taken the dogtag... + Somebody else has already taken the Dog Tag... Ktoś już zabrał ten nieśmiertelnik... Кто-то уже забрал жетон... Někdo jiný už vzal identifikační známku... @@ -98,7 +98,7 @@ Başka biri zaten künyeyi almış - Onscreen display for checking dogtags + Onscreen display for checking Dog Tags Anzeige um Erkennungsmarke zu überprüfen 在畫面中顯示檢查兵籍牌 在画面中显示检查兵籍牌 From ba47c12a974200262d07f70057e1c6a9bdd0d7e8 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Tue, 2 Jul 2024 11:16:27 +0200 Subject: [PATCH 125/290] Dogtags - Drop dogtag on ground if unit doesn't have inventory space (#10094) * Drop dogtag on ground if unit doesn't have inventory space * Only allow taking of dogtags if unit has space --- addons/dogtags/functions/fnc_addDogtagItem.sqf | 3 ++- addons/dogtags/functions/fnc_canTakeDogtag.sqf | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/dogtags/functions/fnc_addDogtagItem.sqf b/addons/dogtags/functions/fnc_addDogtagItem.sqf index 970bb1926e..803c54d82f 100644 --- a/addons/dogtags/functions/fnc_addDogtagItem.sqf +++ b/addons/dogtags/functions/fnc_addDogtagItem.sqf @@ -20,7 +20,8 @@ params ["_item", "_dogtagData"]; if (_item == "") exitWith {}; -[ace_player, _item] call CBA_fnc_addItem; +// Verify that the unit has inventory space, otherwise drop the dogtag on the ground +[ace_player, _item, true] call CBA_fnc_addItem; _dogtagData params ["_nickName"]; private _displayText = format [localize LSTRING(takeDogtagSuccess), _nickName]; diff --git a/addons/dogtags/functions/fnc_canTakeDogtag.sqf b/addons/dogtags/functions/fnc_canTakeDogtag.sqf index c482d74c1c..815aeb7a79 100644 --- a/addons/dogtags/functions/fnc_canTakeDogtag.sqf +++ b/addons/dogtags/functions/fnc_canTakeDogtag.sqf @@ -23,4 +23,4 @@ if (isNull _target) exitWith {false}; // check if disabled for faction if ((faction _target) in GVAR(disabledFactions)) exitWith {false}; -(!alive _target) || {_target getVariable ["ACE_isUnconscious", false]} +((!alive _target) || {_target getVariable ["ACE_isUnconscious", false]}) && {_player canAdd ["ACE_dogtag", 1/*, true*/]} // Todo: Uncomment in 2.18 From aecafe673bc7020857fad7aaa2941a182be6c935 Mon Sep 17 00:00:00 2001 From: Fabio Schick <58027418+mrschick@users.noreply.github.com> Date: Tue, 2 Jul 2024 11:16:48 +0200 Subject: [PATCH 126/290] Aircraft - Drone "Follow Unit" Waypoint Action (#9889) * Fix "Recharge" interaction showing on destroyed drone * Add "Follow Unit" action * Improve condition check * UGV Following via PFH that updates WP Pos * Use HOLD WP for all Follow Actions Since FOLLOW WP would stop working on AI Soldiers after some time. * Allow selecting a follow distance * Follow Distance under separate interaction, just like Loiter Alt Only visible when a HOLD waypoint is selected, which is pretty much always going to have been created by the "Follow" interaction. * Localize "Follow" Interaction * Show structuredText Hint when following/changing distance * Variable for cursorTarget Reuse * Better isKindOf condition use * Make "Ship"-kind vehicles followable * Clean up Comments and systemChat Debugs * Comment explanation for custom PFH solution over vanilla "Follow"-WP * Trim excess brackets from setWaypointPosition argument Co-Authored-By: johnb432 <58661205+johnb432@users.noreply.github.com> * Broader determination for UGV follow distances Co-Authored-By: PabstMirror * Prevent infinite PFH loop if follow target is deleted Co-Authored-By: PabstMirror * Delete Follow WP when PFH terminates * The ternary rules Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * Various requested changes Co-Authored-By: johnb432 <58661205+johnb432@users.noreply.github.com> --------- Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> Co-authored-by: PabstMirror --- .../functions/fnc_droneAddActions.sqf | 61 +++++++++++++++++-- .../functions/fnc_droneSetWaypoint.sqf | 32 +++++++++- addons/aircraft/stringtable.xml | 10 +++ .../functions/fnc_canRefuelUAV.sqf | 2 +- 4 files changed, 95 insertions(+), 10 deletions(-) diff --git a/addons/aircraft/functions/fnc_droneAddActions.sqf b/addons/aircraft/functions/fnc_droneAddActions.sqf index 38ca53e4c6..895004f0e9 100644 --- a/addons/aircraft/functions/fnc_droneAddActions.sqf +++ b/addons/aircraft/functions/fnc_droneAddActions.sqf @@ -22,7 +22,7 @@ if (!alive _vehicle) exitWith {}; if (_vehicle getVariable [QGVAR(droneActionsAdded), false]) exitWith {}; _vehicle setVariable [QGVAR(droneActionsAdded), true]; -// move to location +// Move to location private _condition = { params ["_vehicle"]; (missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]} @@ -37,14 +37,63 @@ private _action = [QGVAR(droneSetWaypointMove), localize "$STR_AC_MOVE", "\a3\3DEN\Data\CfgWaypoints\Move_ca.paa", _statement, _condition] call EFUNC(interact_menu,createAction); [_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject); +// Follow unit/vehicle at turret location +_condition = { + params ["_vehicle"]; + private _target = cursorTarget; + (missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]} && {!isNull _target} && {["CAManBase", "LandVehicle", "Ship"] findIf {_target isKindOf _x} != -1} +}; +_statement = { + params ["_vehicle"]; + private _group = group driver _vehicle; + private _pos = ([_vehicle, [0]] call FUNC(droneGetTurretTargetPos)) select 0; + [QGVAR(droneSetWaypoint), [_vehicle, _group, _pos, "FOLLOW", cursorTarget], _group] call CBA_fnc_targetEvent; + private _followDistance = _vehicle getVariable [QGVAR(wpFollowDistance), 0]; + [[LLSTRING(DroneFollowHint), _followDistance], 3] call EFUNC(common,displayTextStructured); +}; +_action = [QGVAR(droneSetWaypointFollow), localize "$STR_AC_FOLLOW", "\a3\3DEN\Data\CfgWaypoints\Follow_ca.paa", _statement, _condition] call EFUNC(interact_menu,createAction); +[_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject); + +// Set drone follow distance +_condition = { + params ["_vehicle"]; + private _group = group driver _vehicle; + private _index = (currentWaypoint _group) min count waypoints _group; + private _waypoint = [_group, _index]; + (missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]} && {(waypointType _waypoint) == "HOLD"} +}; +_statement = { + params ["_vehicle", "", "_value"]; + _vehicle setVariable [QGVAR(wpFollowDistance), _value]; + [[LLSTRING(DroneFollowHint), _value], 3] call EFUNC(common,displayTextStructured); +}; +_action = [QGVAR(droneSetFollowDistance), LLSTRING(DroneFollowDistance), "", {}, _condition] call EFUNC(interact_menu,createAction); +private _base = [_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject); +private _followDistances = if (_vehicle isKindOf "Car_F") then { + [0, 25, 50, 100, 200] +} else { + [0, 100, 200, 300, 400, 500] +}; +{ + _action = [ + QGVAR(droneSetFollowDistance_) + str _x, + str _x, + "", + _statement, + {true}, + {}, + _x + ] call EFUNC(interact_menu,createAction); + [_vehicle, 1, _base, _action] call EFUNC(interact_menu,addActionToObject); +} forEach _followDistances; if (_vehicle isKindOf "Air") then { - // loiter at location + // Loiter at location _condition = { params ["_vehicle"]; (missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]} }; - _statement = { + _statement = { params ["_vehicle"]; private _group = group driver _vehicle; private _pos = ([_vehicle, [0]] call FUNC(droneGetTurretTargetPos)) select 0; @@ -55,7 +104,7 @@ if (_vehicle isKindOf "Air") then { [_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject); - // set height + // Set height _condition = { params ["_vehicle"]; (missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]} @@ -74,7 +123,7 @@ if (_vehicle isKindOf "Air") then { } forEach [20, 50, 200, 500, 2000]; - // set loiter radius + // Set loiter radius _condition = { params ["_vehicle"]; private _group = group driver _vehicle; @@ -97,7 +146,7 @@ if (_vehicle isKindOf "Air") then { } forEach [500, 750, 1000, 1250, 1500]; - // set loiter direction + // Set loiter direction _condition = { params ["_vehicle", "", "_args"]; private _group = group driver _vehicle; diff --git a/addons/aircraft/functions/fnc_droneSetWaypoint.sqf b/addons/aircraft/functions/fnc_droneSetWaypoint.sqf index 5ffbbae825..953b99a357 100644 --- a/addons/aircraft/functions/fnc_droneSetWaypoint.sqf +++ b/addons/aircraft/functions/fnc_droneSetWaypoint.sqf @@ -8,6 +8,7 @@ * 1: Group * 2: Pos 2D * 3: Type + * 4: Target to follow (default: objNull) * * Return Value: * None @@ -18,7 +19,7 @@ * Public: No */ -params ["_vehicle", "_group", "_pos", "_type"]; +params ["_vehicle", "_group", "_pos", "_type", ["_target", objNull]]; TRACE_4("droneSetWaypoint",_vehicle,_group,_pos,_type); private _index = (currentWaypoint _group) min count waypoints _group; @@ -34,9 +35,34 @@ _pos set [ [0, _currentHeight] select (_currentHeight >= 50) ]; -// [_group] call CBA_fnc_clearWaypoints; _waypoint = _group addWaypoint [_pos, 0]; -_waypoint setWaypointType _type; +// The Vanilla "FOLLOW"-type waypoint is not used directly, due to 2 main issues (as of v2.16): +// - It does not work at all for UGVs, which is a known issue https://feedback.bistudio.com/T126283; +// - No clear scripting way was found to mimic the UAV Terminal's "Follow Distance" functionality; +// Instead, the solution for both UAV and UGV following consists of a CBA PFH that moves a "HOLD"-type Waypoint every 3 seconds. +// Either on the target itself, or on the Drone's current position if the target is within the desired follow distance. +if (_type == "FOLLOW" && {["CAManBase", "LandVehicle", "Ship"] findIf {_target isKindOf _x} != -1}) then { + _waypoint setWaypointType "HOLD"; + [{ + params ["_args", "_handle"]; + _args params ["_vehicle", "_group", "_waypoint", "_target"]; + + if ( // Abort PFH if a new waypoint is created via UAV Terminal or ACE Interaction + _waypoint select 1 != currentWaypoint _group || + {!alive _vehicle} || {isNull _target} + ) exitWith { + deleteWaypoint _waypoint; + [_handle] call CBA_fnc_removePerFrameHandler; + }; + + private _followDistance = _vehicle getVariable [QGVAR(wpFollowDistance), 0]; + if ((_vehicle distance2D _target) < _followDistance) then { + _waypoint setWaypointPosition [getPosASL _vehicle, -1]; + } else { + _waypoint setWaypointPosition [getPosASL _target, -1]; + }; + }, 3, [_vehicle, _group, _waypoint, _target]] call CBA_fnc_addPerFrameHandler; +}; TRACE_3("",_currentHeight,_currentLoiterRadius,_currentLoiterType); if (_currentHeight > 1) then { _vehicle flyInHeight _currentHeight; }; diff --git a/addons/aircraft/stringtable.xml b/addons/aircraft/stringtable.xml index c0cef87756..a60706aad3 100644 --- a/addons/aircraft/stringtable.xml +++ b/addons/aircraft/stringtable.xml @@ -177,5 +177,15 @@ 30мм СБ 5:1 30mm CM 5:1 + + Follow Distance + Distanza di seguimento + Folge-Entfernung + + + Following unit within %1m + Seguendo unità entro %1m + Folgt Einheit bis zu %1m + diff --git a/addons/logistics_uavbattery/functions/fnc_canRefuelUAV.sqf b/addons/logistics_uavbattery/functions/fnc_canRefuelUAV.sqf index 3e7ce4f15c..925178d642 100644 --- a/addons/logistics_uavbattery/functions/fnc_canRefuelUAV.sqf +++ b/addons/logistics_uavbattery/functions/fnc_canRefuelUAV.sqf @@ -18,4 +18,4 @@ params ["_caller", "_target"]; -("ACE_UAVBattery" in (_caller call EFUNC(common,uniqueItems))) && {(fuel _target) < 1} && {(speed _target) < 1} && {!(isEngineOn _target)} && {(_target distance _caller) <= 4} +(alive _target) && {"ACE_UAVBattery" in (_caller call EFUNC(common,uniqueItems))} && {(fuel _target) < 1} && {(speed _target) < 1} && {!(isEngineOn _target)} && {(_target distance _caller) <= 4} From 45f9301019e31e04c46154b3fc7fe81f15903407 Mon Sep 17 00:00:00 2001 From: Psycool <104776717+Psycool3695@users.noreply.github.com> Date: Wed, 3 Jul 2024 03:14:19 +0900 Subject: [PATCH 127/290] Korean translation updated (#10104) * KoreanTranslation Someone has returned all the translations in Korean to English. there is no need to return them. * koreantranslation * Korean Typo Fix * Korean Translation * Update stringtable.xml * Korean Translation Added Added Korean translation related to Cargo Refuel * Merge branch 'master' of https://github.com/Psycool3695/ACE3 * Korean translation Add/Updated * Fixed wrong strings * Korean translation improved * Korean translation updated * Korean translation updated * Fix Merge * Update stringtable.xml * Update stringtable.xml * Korean translation updated * Korean translation minor fix * Korean translation fixed * Korean translation updated * Update stringtable.xml * Spacing fixed * Korean translation updated * Spacing fixed * Korean translation updated * Korean translation updated * Korean translation updated --------- Co-authored-by: PabstMirror --- addons/aircraft/stringtable.xml | 10 ++++--- addons/ballistics/stringtable.xml | 16 ++++++------ .../compat_rf_realisticnames/stringtable.xml | 2 ++ addons/concertina_wire/stringtable.xml | 2 +- addons/killtracker/stringtable.xml | 2 ++ addons/overpressure/stringtable.xml | 2 ++ addons/realisticnames/stringtable.xml | 26 +++++++++---------- 7 files changed, 34 insertions(+), 26 deletions(-) diff --git a/addons/aircraft/stringtable.xml b/addons/aircraft/stringtable.xml index a60706aad3..01c5b41e36 100644 --- a/addons/aircraft/stringtable.xml +++ b/addons/aircraft/stringtable.xml @@ -129,7 +129,7 @@ 30mm コンバット ミックス 4:1 劣化ウラン徹甲弾:焼夷榴弾 30mm Bojový Mix 4:1 DU:HEI 30мм Смешанное боепитание 4:1 ОУ:ОФЗ - 30mm 4:1 열화:고폭소이 + 30mm 열화우라늄:고폭소이 4:1 혼합 30mm Mix de Combate 4:1 DU:AEI @@ -145,7 +145,7 @@ 30mm CM 4:1 30mm BM 4:1 30мм СБ 4:1 - 30mm CM 4:1 + 30mm 4:1 혼합 30mm Combat Mix 5:1 DU:HEI @@ -160,7 +160,7 @@ 30mm コンバット ミックス 5:1 劣化ウラン徹甲弾:焼夷榴弾 30mm Bojový Mix 5:1 DU:HEI 30мм Смешанное боепитание 5:1 ОУ:ОФЗ - 30mm 5:1 열화:고폭소이 + 30mm 열화우라늄:고폭소이 5:1 혼합 30mm CM 5:1 @@ -175,17 +175,19 @@ 30mm CM 5:1 30mm BM 5:1 30мм СБ 5:1 - 30mm CM 5:1 + 30mm 5:1 혼합 Follow Distance Distanza di seguimento Folge-Entfernung + 따라가는 거리 Following unit within %1m Seguendo unità entro %1m Folgt Einheit bis zu %1m + %1m 이내로 유닛을 따라갑니다 diff --git a/addons/ballistics/stringtable.xml b/addons/ballistics/stringtable.xml index a4c67c68d5..7137735233 100644 --- a/addons/ballistics/stringtable.xml +++ b/addons/ballistics/stringtable.xml @@ -1505,7 +1505,7 @@ Carregador de 10 cartuchos 9.3 mm traçantes IR-DIM 9,3 mm 10-lövedékes infravörös nyomkövető tár 9.3mm 10Rnd IR-DIM トレーサー マガジン - 10발들이 9.3mm IR-DIM 예광탄 탄창 + 10발 들이 9.3mm IR-DIM 예광탄 탄창 9.3毫米 10發 低視度紅外線曳光彈 彈匣 9.3 mm 10发 弹匣(红外曳光) 9.3 mm 10Rnd Tracer IR-DIM Mag @@ -1608,7 +1608,7 @@ Cinto de munição traçante 9.3 mm IR-DIM com 150 cartuchos 9,3 mm 150-lövedékes infravörös nyomkövető heveder 9.3mm 150Rnd IR-DIM トレーサー ベルト - 150발들이 9.3mm IR-DIM 예광탄 벨트 + 150발 들이 9.3mm IR-DIM 예광탄 벨트 9.3毫米 150發 低視度紅外線曳光彈 彈鏈 9.3 mm 150发 弹链(红外曳光) 9.3 mm 150Rnd Tracer IR-DIM Belt @@ -1659,7 +1659,7 @@ Cinto de munição 9.3 mm AP com 150 cartuchos 9,3 mm 150-lövedékes páncéltörő heveder 9.3mm 150Rnd 徹甲弾 ベルト - 150발들이 9.3mm 철갑탄 벨트 + 150발 들이 9.3mm 철갑탄 벨트 9.3毫米 150發 穿甲彈 彈鏈 9.3 mm 150发 弹链(穿甲) 9.3 mm 150Rnd AP Belt @@ -1710,7 +1710,7 @@ Carregador de 16 cartuchos 9x19 mm 9x19 mm 16-lövedékes tár 9x19 mm 16Rnd マガジン - 17발들이 9x19mm 탄창 + 16발 들이 9x19mm 탄창 9x19毫米 16發 彈匣 9x19 mm 16发 弹匣 9x19 mm 16Rnd Mag @@ -2016,7 +2016,7 @@ Carregador 5.56 mm com 30 cartuchos (Mk318) 5,56 mm 30-lövedékes tár (Mk318) 5.56mm 30Rnd マガジン (Mk318) - 30발들이 5.56mm 탄창 (Mk.318) + 30발 들이 5.56mm 탄창 (Mk.318) 5.56毫米 30發 彈匣 (Mk318 特戰專用彈) 5.56 mm 30发 弹匣(Mk318) 5.56 mm 30Rnd Mag (Mk318) @@ -2322,7 +2322,7 @@ Carregador 7.62 mm com 10 cartuchos (Mk319 Mod 0) 7,62 mm 10-lövedékes tár (Mk319 Mod 0) 7.62mm 10Rnd マガジン (Mk319 Mod 0) - 10발들이 7.62mm 탄창 (Mk.319 Mod 0) + 10발 들이 7.62mm 탄창 (Mk.319 Mod 0) 7.62毫米 10發 彈匣 (Mk319 Mod 0 特戰專用彈) 7.62 mm 10发 弹匣(Mk319 Mod 0) 7.62 mm 10Rnd Mag (Mk319 Mod 0) @@ -3344,7 +3344,7 @@ Carregador 12.7x99 mm (AMAX) com 5 cartuchos 12,7x99 mm 5-lövedékes tár (AMAX) 12.7x99mm 5Rnd マガジン (AMAX) - 5발들이 12.7x99mm 탄창 (AMAX) + 5발 들이 12.7x99mm 탄창 (AMAX) 12.7x99毫米 5發 彈匣 (AMAX 比賽專用彈) 12.7x99 mm 5发 弹匣(AMAX) 12.7x99 mm 5Rnd Şarjör (AMAX) @@ -3378,7 +3378,7 @@ Carregador 12.7x99 mm (AMAX) com 10 cartuchos 12,7x99 mm 10-lövedékes tár (AMAX) 12.7x99mm 10Rnd マガジン (AMAX) - 10발들이 12.7x99mm 탄창 (AMAX) + 10발 들이 12.7x99mm 탄창 (AMAX) 12.7x99毫米 10發 彈匣 (AMAX 比賽專用彈) 12.7x99 mm 10发 弹匣(AMAX) 12.7x99 mm 10Rnd Şarjör (AMAX) diff --git a/addons/compat_rf/compat_rf_realisticnames/stringtable.xml b/addons/compat_rf/compat_rf_realisticnames/stringtable.xml index c65a8fd4ad..03d5003a62 100644 --- a/addons/compat_rf/compat_rf_realisticnames/stringtable.xml +++ b/addons/compat_rf/compat_rf_realisticnames/stringtable.xml @@ -377,6 +377,7 @@ H225M シュペル クーガー (非武装) H225M Super Cougar (Unbewaffnet) H225M Super Cougar (Disarmato) + H225M 슈퍼 쿠거 (비무장) HEMTT Fire Truck @@ -389,6 +390,7 @@ HEMTT contra incêndio HEMTT 消防車 HEMTT Autobotte + HEMTT 소방트럭 Typhoon Water diff --git a/addons/concertina_wire/stringtable.xml b/addons/concertina_wire/stringtable.xml index 0ea44fc063..603cc5a7a8 100644 --- a/addons/concertina_wire/stringtable.xml +++ b/addons/concertina_wire/stringtable.xml @@ -30,7 +30,7 @@ Concertina wire coil Bobina de arame farpado 鉄条網コイル - 코일형 철조망 + 윤형철조망 鐵絲網捲 铁丝网卷 Bıçaklı Tel Rulo diff --git a/addons/killtracker/stringtable.xml b/addons/killtracker/stringtable.xml index b7a97df15a..64b9ee764d 100644 --- a/addons/killtracker/stringtable.xml +++ b/addons/killtracker/stringtable.xml @@ -125,6 +125,7 @@ Zeige der Fahrzeugbesatzung die Abschüsse des Fahrzeugs Mostra uccisioni del veicolo a membri dell'equipaggio 車両でのキルを乗員全員に表示する + 다른 승무원에게 차량 처치 표시 Show kills from a vehicle to driver, gunner and commander @@ -132,6 +133,7 @@ Zeige Abschüsse des Fahrzeugs dem Fahrer, Richtschützen und Kommandanten an Mostra uccisioni del veicolo al pilota, artigliere e comandante 車両でのキルを操縦手、砲手、車長で共有して表示する + 차량 처치를 운전수, 사수, 지휘관에게 보여줍니다 diff --git a/addons/overpressure/stringtable.xml b/addons/overpressure/stringtable.xml index 0d43f01825..2ce7615ad4 100644 --- a/addons/overpressure/stringtable.xml +++ b/addons/overpressure/stringtable.xml @@ -51,6 +51,7 @@ Rückstrahl-Entfernung Multiplikator Coefficiente distanza di svampata 後方噴射の距離係数 + 후폭풍 거리 계수 Scales the backblast effect @@ -58,6 +59,7 @@ Skaliert den Rückstrahl-Effekt Scala l'effetto delle svampate dei lanciarazzi 無反動砲による後方噴射の影響範囲の大きさ + 후폭풍 효과의 스케일을 조정합니다 Backblast range diff --git a/addons/realisticnames/stringtable.xml b/addons/realisticnames/stringtable.xml index 70b78e6d25..af864f64df 100644 --- a/addons/realisticnames/stringtable.xml +++ b/addons/realisticnames/stringtable.xml @@ -13,7 +13,7 @@ XM312 XM312 XM312 - XM312 + XM312 중기관총 XM312重機槍 XM312 XM312 @@ -30,7 +30,7 @@ XM312A XM312A XM312A - XM312A + XM312A 무인중기관총 XM312A重機槍 XM312A XM312A @@ -47,7 +47,7 @@ XM312 (Magasított) XM312 (Alto) XM312 (ハイマウント) - XM312 (높음) + XM312 중기관총 (높음) XM312重機槍 (高射腳架) XM312(高) XM312 (Yüksek) @@ -64,7 +64,7 @@ XM307 XM307 XM307 - XM307 + XM307 유탄기관총 XM307榴彈機槍 XM307 XM307 @@ -81,7 +81,7 @@ XM307A XM307A XM307A - XM307A + XM307A 무인유탄기관총 XM307A榴彈機槍 XM307A XM307A @@ -98,7 +98,7 @@ XM307 (Magasított) XM307 (Alto) XM307 (ハイマウント) - XM307 (높음) + XM307 유탄기관총 (높음) XM307榴彈機槍 (高射腳架) XM307(高) XM307 (Yüksek) @@ -149,7 +149,7 @@ YABHON-R3 YABHON-R3 YABHON-R3 - YABHON-R3 + YABHON-R3 무인기 "亞伯罕-R3型"空中無人載具 "联合"-R3 YABHON-R3 @@ -166,7 +166,7 @@ YABHON-R3 (CAS) YABHON-R3 (CAS) YABHON-R3 (CAS) - YABHON-R3 (근접지원) + YABHON-R3 무인기 (근접지원) "亞伯罕-R3型"空中無人載具 (近空支援) "联合"-R3(近空支援) YABHON-R3 (CAS) @@ -3668,7 +3668,7 @@ Polaris DAGOR (XM312) Polaris DAGOR (XM312) Polaris DAGOR (XM312) - 폴라리스 DAGOR (XM312) + 폴라리스 DAGOR (XM312 중기관총) Polaris DAGOR (Mini-Spike AT) @@ -3684,7 +3684,7 @@ Polaris DAGOR (Mini-Spike AT) Polaris DAGOR (Mini-Spike AT) Polaris DAGOR (Mini-Spike AT) - 폴라리스 DAGOR (스파이크 미사일 대전차) + 폴라리스 DAGOR (스파이크 대전차미사일) Polaris DAGOR @@ -3732,7 +3732,7 @@ LSV Mk. II (M134) LSV Mk. II (M134) LSV Mk. II (M134) - LSV Mk.II (M134) + LSV Mk.II (M134 미니건) LSV Mk. II (Metis-M) @@ -3844,7 +3844,7 @@ Wiesel 2 Ozelot (AA) Wiesel 2 Ozelot (AA) Wiesel 2 Ozelot (AA) - 비젤 2 오셀롯 (대공) + 비젤 2 오젤롯 (대공) Wiesel 2 (ATGM) @@ -3860,7 +3860,7 @@ Wiesel 2 (ATGM) Wiesel 2 (ATGM) Wiesel 2 (ATGM) - 비젤 2 (대전차유도) + 비젤 2 (대전차미사일) Wiesel 2 (MK20) From 516eb48c93a21d77db5e2a51aa08f81cee9a91c1 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Tue, 2 Jul 2024 20:16:28 +0200 Subject: [PATCH 128/290] Dogtags - Stop throwing error when trying to take dog tags (#10103) Stop throwing error --- addons/dogtags/functions/fnc_canTakeDogtag.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/dogtags/functions/fnc_canTakeDogtag.sqf b/addons/dogtags/functions/fnc_canTakeDogtag.sqf index 815aeb7a79..796f219f56 100644 --- a/addons/dogtags/functions/fnc_canTakeDogtag.sqf +++ b/addons/dogtags/functions/fnc_canTakeDogtag.sqf @@ -23,4 +23,4 @@ if (isNull _target) exitWith {false}; // check if disabled for faction if ((faction _target) in GVAR(disabledFactions)) exitWith {false}; -((!alive _target) || {_target getVariable ["ACE_isUnconscious", false]}) && {_player canAdd ["ACE_dogtag", 1/*, true*/]} // Todo: Uncomment in 2.18 +((!alive _target) || {_target getVariable ["ACE_isUnconscious", false]}) && {_player canAdd ["ACE_dogtag_1", 1/*, true*/]} // Todo: Uncomment in 2.18 From ee0e947611d72378580099019153c51e67da838c Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Tue, 2 Jul 2024 21:38:14 +0200 Subject: [PATCH 129/290] General - Use `ace_common_fnc_isAwake` where possible (#10098) * Use `ace_common_fnc_isAwake` where possible * Revert bad change --- addons/captives/functions/fnc_canEscortCaptive.sqf | 3 +-- addons/captives/functions/fnc_canLoadCaptive.sqf | 2 +- addons/captives/functions/fnc_doEscortCaptive.sqf | 2 +- .../captives/functions/fnc_handleAnimChangedHandcuffed.sqf | 2 +- .../captives/functions/fnc_handleAnimChangedSurrendered.sqf | 2 +- addons/captives/functions/fnc_setHandcuffed.sqf | 2 +- addons/captives/functions/fnc_setSurrendered.sqf | 5 ++--- addons/common/functions/fnc_disableAI.sqf | 2 +- addons/common/functions/fnc_nearestVehiclesFreeSeat.sqf | 2 +- addons/dogtags/functions/fnc_canCheckDogtag.sqf | 2 +- addons/dogtags/functions/fnc_canTakeDogtag.sqf | 2 +- addons/dragging/functions/fnc_dropObject.sqf | 2 +- addons/dragging/functions/fnc_dropObject_carry.sqf | 2 +- addons/gforces/functions/fnc_pfhUpdateGForces.sqf | 2 +- addons/goggles/functions/fnc_canWipeGlasses.sqf | 2 +- addons/interaction/functions/fnc_canJoinGroup.sqf | 3 +-- addons/interaction/functions/fnc_canJoinTeam.sqf | 3 +-- addons/interaction/functions/fnc_canTapShoulder.sqf | 5 ++--- addons/towing/functions/fnc_towStateMachinePFH.sqf | 5 ++--- 19 files changed, 22 insertions(+), 28 deletions(-) diff --git a/addons/captives/functions/fnc_canEscortCaptive.sqf b/addons/captives/functions/fnc_canEscortCaptive.sqf index f39ff2ac5f..204206e506 100644 --- a/addons/captives/functions/fnc_canEscortCaptive.sqf +++ b/addons/captives/functions/fnc_canEscortCaptive.sqf @@ -21,7 +21,6 @@ params ["_unit", "_target"]; (_target getVariable [QGVAR(isHandcuffed), false]) && {isNull (attachedTo _target)} && -{alive _target} && -{!(_target getVariable ["ACE_isUnconscious", false])} && +{_target call EFUNC(common,isAwake)} && {(vehicle _unit) == _unit} && {(vehicle _target) == _target} diff --git a/addons/captives/functions/fnc_canLoadCaptive.sqf b/addons/captives/functions/fnc_canLoadCaptive.sqf index 982e4025a2..46da188238 100644 --- a/addons/captives/functions/fnc_canLoadCaptive.sqf +++ b/addons/captives/functions/fnc_canLoadCaptive.sqf @@ -20,7 +20,7 @@ params ["_unit", "_target", "_vehicle"]; // Don't show "Load Captive" if unit is unconscious (already has "Load Patient") -if (_target getVariable ["ACE_isUnconscious", false]) exitWith {false}; +if !(_target call EFUNC(common,isAwake)) exitWith {false}; if ((isNull _target) && {_unit getVariable [QGVAR(isEscorting), false]}) then { //Looking at a vehicle while escorting, get target from attached objects: diff --git a/addons/captives/functions/fnc_doEscortCaptive.sqf b/addons/captives/functions/fnc_doEscortCaptive.sqf index 7eb25ccc4c..86cc52cb9c 100644 --- a/addons/captives/functions/fnc_doEscortCaptive.sqf +++ b/addons/captives/functions/fnc_doEscortCaptive.sqf @@ -39,7 +39,7 @@ if (_state) then { _args params ["_unit", "_target", "_actionID"]; if (_unit getVariable [QGVAR(isEscorting), false]) then { - if (!alive _target || {!alive _unit} || {!canStand _target} || {!canStand _unit} || {_target getVariable ["ACE_isUnconscious", false]} || {_unit getVariable ["ACE_isUnconscious", false]} || {!isNull (attachedTo _unit)}) then { + if (!canStand _target || {!canStand _unit} || {!(_target call EFUNC(common,isAwake))} || {!(_unit call EFUNC(common,isAwake))} || {!isNull (attachedTo _unit)}) then { _unit setVariable [QGVAR(isEscorting), false, true]; }; }; diff --git a/addons/captives/functions/fnc_handleAnimChangedHandcuffed.sqf b/addons/captives/functions/fnc_handleAnimChangedHandcuffed.sqf index 3363ca923e..8ce4391783 100644 --- a/addons/captives/functions/fnc_handleAnimChangedHandcuffed.sqf +++ b/addons/captives/functions/fnc_handleAnimChangedHandcuffed.sqf @@ -19,7 +19,7 @@ params ["_unit", "_newAnimation"]; TRACE_2("AnimChanged",_unit,_newAnimation); if (_unit == (vehicle _unit)) then { - if ((_newAnimation != "ACE_AmovPercMstpSsurWnonDnon") && {!(_unit getVariable ["ACE_isUnconscious", false])}) then { + if ((_newAnimation != "ACE_AmovPercMstpSsurWnonDnon") && {_unit call EFUNC(common,isAwake)}) then { TRACE_1("Handcuff animation interrupted",_newAnimation); [_unit, "ACE_AmovPercMstpScapWnonDnon", 1] call EFUNC(common,doAnimation); }; diff --git a/addons/captives/functions/fnc_handleAnimChangedSurrendered.sqf b/addons/captives/functions/fnc_handleAnimChangedSurrendered.sqf index b9164ddbe5..7d69c8c7fa 100644 --- a/addons/captives/functions/fnc_handleAnimChangedSurrendered.sqf +++ b/addons/captives/functions/fnc_handleAnimChangedSurrendered.sqf @@ -19,7 +19,7 @@ params ["_unit", "_newAnimation"]; TRACE_2("AnimChanged",_unit,_newAnimation); -if ((_newAnimation != "ACE_AmovPercMstpSsurWnonDnon") && {!(_unit getVariable ["ACE_isUnconscious", false])}) then { +if ((_newAnimation != "ACE_AmovPercMstpSsurWnonDnon") && {_unit call EFUNC(common,isAwake)}) then { TRACE_1("Surrender animation interrupted",_newAnimation); [_unit, "ACE_AmovPercMstpSsurWnonDnon", 1] call EFUNC(common,doAnimation); }; diff --git a/addons/captives/functions/fnc_setHandcuffed.sqf b/addons/captives/functions/fnc_setHandcuffed.sqf index 0c54d9a70a..d3d9fa4e6b 100644 --- a/addons/captives/functions/fnc_setHandcuffed.sqf +++ b/addons/captives/functions/fnc_setHandcuffed.sqf @@ -91,7 +91,7 @@ if (_state) then { _unit removeEventHandler ["AnimChanged", _animChangedEHID]; _unit setVariable [QGVAR(handcuffAnimEHID), -1]; - if (((vehicle _unit) == _unit) && {!(_unit getVariable ["ACE_isUnconscious", false])}) then { + if (((vehicle _unit) == _unit) && {_unit call EFUNC(common,isAwake)}) then { //Break out of hands up animation loop [_unit, "ACE_AmovPercMstpScapWnonDnon_AmovPercMstpSnonWnonDnon", 2] call EFUNC(common,doAnimation); }; diff --git a/addons/captives/functions/fnc_setSurrendered.sqf b/addons/captives/functions/fnc_setSurrendered.sqf index 4acc8529bb..887bfb2680 100644 --- a/addons/captives/functions/fnc_setSurrendered.sqf +++ b/addons/captives/functions/fnc_setSurrendered.sqf @@ -86,8 +86,7 @@ if (_state) then { }; }; - if (!alive _unit) exitWith {}; - if (_unit getVariable ["ACE_isUnconscious", false]) exitWith {}; //don't touch animations if unconscious + if !(_unit call EFUNC(common,isAwake)) exitWith {}; //don't touch animations if unconscious //if we are in "hands up" animationState, crack it now if (((vehicle _unit) == _unit) && {(animationState _unit) == "ACE_AmovPercMstpSsurWnonDnon"}) then { @@ -99,7 +98,7 @@ if (_state) then { params ["_args", "_pfID"]; _args params ["_unit", "_maxTime"]; //If waited long enough or they re-surrendered or they are unconscious, exit loop - if ((CBA_missionTime > _maxTime) || {_unit getVariable [QGVAR(isSurrendering), false]} || {_unit getVariable ["ACE_isUnconscious", false]}) exitWith { + if ((CBA_missionTime > _maxTime) || {_unit getVariable [QGVAR(isSurrendering), false]} || {!(_unit call EFUNC(common,isAwake))}) exitWith { [_pfID] call CBA_fnc_removePerFrameHandler; }; //Only break animation if they are actualy the "hands up" animation (because we are using switchmove there won't be an transition) diff --git a/addons/common/functions/fnc_disableAI.sqf b/addons/common/functions/fnc_disableAI.sqf index 52f1ed37c3..a0c725c7db 100644 --- a/addons/common/functions/fnc_disableAI.sqf +++ b/addons/common/functions/fnc_disableAI.sqf @@ -29,7 +29,7 @@ if !([_unit] call EFUNC(common,isPlayer)) then { _unit disableConversation true; } else { //Sanity check to make sure we don't enable unconsious AI - if (_unit getVariable ["ace_isunconscious", false] && alive _unit) exitWith { + if (_unit getVariable ["ACE_isUnconscious", false] && alive _unit) exitWith { ERROR("Enabling AI for unconsious unit"); }; diff --git a/addons/common/functions/fnc_nearestVehiclesFreeSeat.sqf b/addons/common/functions/fnc_nearestVehiclesFreeSeat.sqf index 71f62959b9..2108751066 100644 --- a/addons/common/functions/fnc_nearestVehiclesFreeSeat.sqf +++ b/addons/common/functions/fnc_nearestVehiclesFreeSeat.sqf @@ -22,7 +22,7 @@ params ["_unit", ["_distance", 10], ["_cargoOnly", false]]; private _nearVehicles = nearestObjects [_unit, ["Car", "Air", "Tank", "Ship_F", "Pod_Heli_Transport_04_crewed_base_F"], _distance]; _nearVehicles select { // Filter cargo seats that will eject unconscious units (e.g. quad bike) - private _canSitInCargo = (!(_unit getVariable ['ACE_isUnconscious', false])) || {(getNumber (configOf _x >> "ejectDeadCargo")) == 0}; + private _canSitInCargo = (_unit call EFUNC(common,isAwake)) || {(getNumber (configOf _x >> "ejectDeadCargo")) == 0}; ((fullCrew [_x, "", true]) findIf { _x params ["_body", "_role", "_cargoIndex"]; (isNull _body) // seat empty diff --git a/addons/dogtags/functions/fnc_canCheckDogtag.sqf b/addons/dogtags/functions/fnc_canCheckDogtag.sqf index bec3ef0dfa..98d437cbac 100644 --- a/addons/dogtags/functions/fnc_canCheckDogtag.sqf +++ b/addons/dogtags/functions/fnc_canCheckDogtag.sqf @@ -23,4 +23,4 @@ if (isNull _target) exitWith {false}; // check if disabled for faction if ((faction _target) in GVAR(disabledFactions)) exitWith {false}; -(!alive _target) || {_target getVariable ["ACE_isUnconscious", false]} +!(_target call EFUNC(common,isAwake)) diff --git a/addons/dogtags/functions/fnc_canTakeDogtag.sqf b/addons/dogtags/functions/fnc_canTakeDogtag.sqf index 796f219f56..5f0a6d1afe 100644 --- a/addons/dogtags/functions/fnc_canTakeDogtag.sqf +++ b/addons/dogtags/functions/fnc_canTakeDogtag.sqf @@ -23,4 +23,4 @@ if (isNull _target) exitWith {false}; // check if disabled for faction if ((faction _target) in GVAR(disabledFactions)) exitWith {false}; -((!alive _target) || {_target getVariable ["ACE_isUnconscious", false]}) && {_player canAdd ["ACE_dogtag_1", 1/*, true*/]} // Todo: Uncomment in 2.18 +!(_target call EFUNC(common,isAwake)) && {_player canAdd ["ACE_dogtag_1", 1/*, true*/]} // Todo: Uncomment in 2.18 diff --git a/addons/dragging/functions/fnc_dropObject.sqf b/addons/dragging/functions/fnc_dropObject.sqf index 10cfda1703..4115f28820 100644 --- a/addons/dragging/functions/fnc_dropObject.sqf +++ b/addons/dragging/functions/fnc_dropObject.sqf @@ -33,7 +33,7 @@ if (!GVAR(dragAndFire)) then { private _inBuilding = _unit call FUNC(isObjectOnObject); // Play release animation -if !(_unit getVariable ["ACE_isUnconscious", false]) then { +if (_unit call EFUNC(common,isAwake)) then { [_unit, "released"] call EFUNC(common,doGesture); }; diff --git a/addons/dragging/functions/fnc_dropObject_carry.sqf b/addons/dragging/functions/fnc_dropObject_carry.sqf index 7a81d94a05..ff6324e0f3 100644 --- a/addons/dragging/functions/fnc_dropObject_carry.sqf +++ b/addons/dragging/functions/fnc_dropObject_carry.sqf @@ -44,7 +44,7 @@ if (_tryLoad && {!(_target isKindOf "CAManBase")} && {["ace_cargo"] call EFUNC(c // Fix anim when aborting carrying persons if (_target isKindOf "CAManBase" || {animationState _unit in CARRY_ANIMATIONS}) then { - if (isNull objectParent _unit && {!(_unit getVariable ["ACE_isUnconscious", false])}) then { + if (isNull objectParent _unit && {_unit call EFUNC(common,isAwake)}) then { [_unit, "", 2] call EFUNC(common,doAnimation); }; diff --git a/addons/gforces/functions/fnc_pfhUpdateGForces.sqf b/addons/gforces/functions/fnc_pfhUpdateGForces.sqf index 4bb680ee47..487ba15b2a 100644 --- a/addons/gforces/functions/fnc_pfhUpdateGForces.sqf +++ b/addons/gforces/functions/fnc_pfhUpdateGForces.sqf @@ -77,7 +77,7 @@ if (_average > _gBlackOut && {GETEGVAR(medical,enabled,false) && {ACE_player cal GVAR(GForces_CC) ppEffectAdjust [1,1,0,[0,0,0,1],[0,0,0,0],[1,1,1,1],[10,10,0,0,0,0.1,0.5]]; -if !(ACE_player getVariable ["ACE_isUnconscious", false]) then { +if (ACE_player call EFUNC(common,isAwake)) then { if (_average > 0.30 * _gBlackOut) then { private _strength = ((_average - 0.30 * _gBlackOut) / (0.70 * _gBlackOut)) max 0; GVAR(GForces_CC) ppEffectAdjust [1,1,0,[0,0,0,1],[0,0,0,0],[1,1,1,1],[2 * (1 - _strength),2 * (1 - _strength),0,0,0,0.1,0.5]]; diff --git a/addons/goggles/functions/fnc_canWipeGlasses.sqf b/addons/goggles/functions/fnc_canWipeGlasses.sqf index ef9d961bc1..cb24b4137a 100644 --- a/addons/goggles/functions/fnc_canWipeGlasses.sqf +++ b/addons/goggles/functions/fnc_canWipeGlasses.sqf @@ -15,4 +15,4 @@ * Public: No */ -GVAR(effects) in [2, 3] && {!GETVAR(ACE_player,ACE_isUnconscious,false)} // return +GVAR(effects) in [2, 3] && {ACE_player call EFUNC(common,isAwake)} // return diff --git a/addons/interaction/functions/fnc_canJoinGroup.sqf b/addons/interaction/functions/fnc_canJoinGroup.sqf index facc3376ee..ec2feb8240 100644 --- a/addons/interaction/functions/fnc_canJoinGroup.sqf +++ b/addons/interaction/functions/fnc_canJoinGroup.sqf @@ -18,7 +18,6 @@ params ["_unit", "_target"]; -alive _target -&& {!(_target getVariable ["ACE_isUnconscious", false])} +_target call EFUNC(common,isAwake) && {side group _unit == side group _target} && {group _unit != group _target} // return diff --git a/addons/interaction/functions/fnc_canJoinTeam.sqf b/addons/interaction/functions/fnc_canJoinTeam.sqf index 09d0281dca..e0e3684ce9 100644 --- a/addons/interaction/functions/fnc_canJoinTeam.sqf +++ b/addons/interaction/functions/fnc_canJoinTeam.sqf @@ -18,7 +18,6 @@ params ["_unit", "_target"]; -alive _target -&& {!(_target getVariable ["ACE_isUnconscious", false])} +_target call EFUNC(common,isAwake) && {!([_target] call EFUNC(common,isPlayer))} && {_target in units group _unit} diff --git a/addons/interaction/functions/fnc_canTapShoulder.sqf b/addons/interaction/functions/fnc_canTapShoulder.sqf index 049c178152..51f271fb4c 100644 --- a/addons/interaction/functions/fnc_canTapShoulder.sqf +++ b/addons/interaction/functions/fnc_canTapShoulder.sqf @@ -19,6 +19,5 @@ params ["_unit", "_target"]; _target isKindOf "CAManBase" && -{alive _target} && -{_unit distance _target < 4} && -{!(_target getVariable ["ACE_isUnconscious", false])} // return +{_target call EFUNC(common,isAwake)} && +{_unit distance _target < 4} // return diff --git a/addons/towing/functions/fnc_towStateMachinePFH.sqf b/addons/towing/functions/fnc_towStateMachinePFH.sqf index 50afdeb153..7b295754fa 100644 --- a/addons/towing/functions/fnc_towStateMachinePFH.sqf +++ b/addons/towing/functions/fnc_towStateMachinePFH.sqf @@ -44,15 +44,14 @@ if (GVAR(isSwimming) && {currentWeapon _unit isNotEqualTo ""}) then { private _exitCondition = !( (alive GVAR(attachHelper)) && { alive _parent } && - { alive _unit } && + { _unit call EFUNC(common,isAwake) } && { currentWeapon _unit isEqualTo "" || {_unit call EFUNC(common,isSwimming)} // swimming in wetsuit forces weapon in hands || {getPosASLW _unit select 2 < -1.5} // walking-to-swimming animation in wetsuit lasts for 3 seconds } && { [_unit, objNull, [INTERACTION_EXCEPTIONS]] call EFUNC(common,canInteractWith) } && - { "unconscious" isNotEqualTo toLowerANSI animationState _unit } && - { !(_unit getVariable ["ACE_isUnconscious", false]) } && + { "unconscious" != animationState _unit } && { ACE_player == _unit } ); From b714c8bce2628ff8d4795da8a7f2fc05bb82f474 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 3 Jul 2024 11:02:43 +0200 Subject: [PATCH 130/290] Nametags - Only display talking waves when unit is alive and conscious (#10106) Only display waves when unit is alive and conscious --- addons/nametags/functions/fnc_initIsSpeaking.sqf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/nametags/functions/fnc_initIsSpeaking.sqf b/addons/nametags/functions/fnc_initIsSpeaking.sqf index 5bae931e60..db2bf30ac3 100644 --- a/addons/nametags/functions/fnc_initIsSpeaking.sqf +++ b/addons/nametags/functions/fnc_initIsSpeaking.sqf @@ -41,14 +41,14 @@ switch (true) do { INFO("ACRE Detected."); DFUNC(isSpeaking) = { params ["_unit"]; - ([_unit] call acre_api_fnc_isSpeaking) && {!(_unit getVariable ["ACE_isUnconscious", false])} + ([_unit] call acre_api_fnc_isSpeaking) && {_unit call EFUNC(common,isAwake)} }; }; case (["task_force_radio"] call EFUNC(common,isModLoaded)): { INFO("TFAR Detected."); DFUNC(isSpeaking) = { params ["_unit"]; - (_unit getVariable ["tf_isSpeaking", false]) && {!(_unit getVariable ["ACE_isUnconscious", false])} + (_unit getVariable ["tf_isSpeaking", false]) && {_unit call EFUNC(common,isAwake)} }; }; default { @@ -65,7 +65,7 @@ switch (true) do { DFUNC(isSpeaking) = { params ["_unit"]; - (_unit getVariable [QGVAR(isSpeakingInGame), false]) && {!(_unit getVariable ["ACE_isUnconscious", false])} + (_unit getVariable [QGVAR(isSpeakingInGame), false]) && {_unit call EFUNC(common,isAwake)} }; }; }; From 7b0e5b64169e01bc2f35ae69750b25564b2ccfb4 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 3 Jul 2024 17:30:41 +0200 Subject: [PATCH 131/290] Common - Fix `ace_common_fnc_uniqueItems` (#10107) Fix `ace_common_fnc_uniqueItems` --- addons/common/functions/fnc_uniqueItems.sqf | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/addons/common/functions/fnc_uniqueItems.sqf b/addons/common/functions/fnc_uniqueItems.sqf index 204501ca3f..5b2177a376 100644 --- a/addons/common/functions/fnc_uniqueItems.sqf +++ b/addons/common/functions/fnc_uniqueItems.sqf @@ -28,10 +28,12 @@ private _fnc_getItems = { _inventoryItems append ((getItemCargo vestContainer _target) select 0); _inventoryItems append ((getItemCargo backpackContainer _target) select 0); - _items set [0, _inventoryItems]; - _items set [1, magazines _target]; + private _magazines = magazines _target; - _items arrayIntersect _items + _items set [0, _inventoryItems arrayIntersect _inventoryItems]; + _items set [1, _magazines arrayIntersect _magazines]; + + _items }; // Cache items list if unit is ACE_player From dae2c5b465c12e4c320e7ef117e0b899fd3373c2 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 3 Jul 2024 17:39:04 +0200 Subject: [PATCH 132/290] Common - Clean up `ace_common_fnc_hasItem` & `ace_common_fnc_hasMagazine` functions (#10108) * Clean up hasItem & hasMagazine functions * Replace EFUNC * Update fnc_hasItem.sqf --- addons/common/functions/fnc_hasItem.sqf | 10 +++++----- addons/common/functions/fnc_hasMagazine.sqf | 12 +++++------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/addons/common/functions/fnc_hasItem.sqf b/addons/common/functions/fnc_hasItem.sqf index f446c5dac0..ac0be8b10e 100644 --- a/addons/common/functions/fnc_hasItem.sqf +++ b/addons/common/functions/fnc_hasItem.sqf @@ -1,21 +1,21 @@ #include "..\script_component.hpp" /* * Author: Glowbal - * Check if unit has item. Note: case-sensitive. + * Check if given unit has an item of given classname. Note: Case sensitive. * * Arguments: * 0: Unit - * 1: Item Classname + * 1: Item classname * * Return Value: - * Unit has Item + * Unit has item * * Example: - * [bob, "item"] call ace_common_fnc_hasItem + * [player, "ACE_Banana"] call ace_common_fnc_hasItem * * Public: Yes */ params [["_unit", objNull, [objNull]], ["_item", "", [""]]]; -_item in (_unit call EFUNC(common,uniqueItems)) +_item in (_unit call FUNC(uniqueItems)) // return diff --git a/addons/common/functions/fnc_hasMagazine.sqf b/addons/common/functions/fnc_hasMagazine.sqf index 7874bcbd16..9f35aafdba 100644 --- a/addons/common/functions/fnc_hasMagazine.sqf +++ b/addons/common/functions/fnc_hasMagazine.sqf @@ -1,23 +1,21 @@ #include "..\script_component.hpp" /* * Author: Glowbal - * Check if given unit has a magazine of given classname + * Check if given unit has a magazine of given classname. Note: Case sensitive. * * Arguments: * 0: Unit - * 1: Magazine Classname + * 1: Magazine classname * * Return Value: - * has Magazine + * Unit has magazine * * Example: - * [bob, "magazine"] call ace_common_fnc_hasMagazine + * [player, "30Rnd_65x39_caseless_mag"] call ace_common_fnc_hasMagazine * * Public: yes - * - * Note: Case sensitive */ params [["_unit", objNull, [objNull]], ["_magazine", "", [""]]]; -_magazine in magazines _unit // return +_magazine in ([_unit, 2] call FUNC(uniqueItems)) // return From 4d0641abb829bfb6945dea1ca5a5597f9c66a52d Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 3 Jul 2024 18:50:08 +0200 Subject: [PATCH 133/290] Dogtags - Improve displaying dogtags from bodies with no name (#10096) Improve displaying dogtags from bodies with no name --- addons/dogtags/XEH_postInit.sqf | 10 +++++++--- addons/dogtags/functions/fnc_addDogtagItem.sqf | 10 ++++++++-- addons/dogtags/functions/fnc_showDogtag.sqf | 10 ++++++++-- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/addons/dogtags/XEH_postInit.sqf b/addons/dogtags/XEH_postInit.sqf index dae6b62247..1633aace3c 100644 --- a/addons/dogtags/XEH_postInit.sqf +++ b/addons/dogtags/XEH_postInit.sqf @@ -66,10 +66,14 @@ if (["ace_arsenal"] call EFUNC(common,isModLoaded)) then { _item = _rightPanel lnbData [_i, 0]; if (_item isKindOf ["ACE_dogtag", _cfgWeapons]) then { - _dogtagData = _allDogtagsData param [_allDogtags find _item, []]; + private _name = (_allDogtagsData param [_allDogtags find _item, []]) param [0, ""]; - // If data doesn't exist, put name as "unknown" - _rightPanel lnbSetText [[_i, 1], [LLSTRING(itemName), ": ", _dogtagData param [0, LELSTRING(common,unknown)]] joinString ""]; + // If data doesn't exist or body has no name, set name as "unknown" + if (_name == "") then { + _name = LELSTRING(common,unknown); + }; + + _rightPanel lnbSetText [[_i, 1], [LLSTRING(itemName), ": ", _name] joinString ""]; }; }; }; diff --git a/addons/dogtags/functions/fnc_addDogtagItem.sqf b/addons/dogtags/functions/fnc_addDogtagItem.sqf index 803c54d82f..6979299db3 100644 --- a/addons/dogtags/functions/fnc_addDogtagItem.sqf +++ b/addons/dogtags/functions/fnc_addDogtagItem.sqf @@ -23,8 +23,14 @@ if (_item == "") exitWith {}; // Verify that the unit has inventory space, otherwise drop the dogtag on the ground [ace_player, _item, true] call CBA_fnc_addItem; -_dogtagData params ["_nickName"]; -private _displayText = format [localize LSTRING(takeDogtagSuccess), _nickName]; +_dogtagData params ["_name"]; + +// If data doesn't exist or body has no name, set name as "unknown" +if (_name == "") then { + _name = LELSTRING(common,unknown); +}; + +private _displayText = format [localize LSTRING(takeDogtagSuccess), _name]; // display message [{ diff --git a/addons/dogtags/functions/fnc_showDogtag.sqf b/addons/dogtags/functions/fnc_showDogtag.sqf index 4865ff7de2..9e01bfc3cd 100644 --- a/addons/dogtags/functions/fnc_showDogtag.sqf +++ b/addons/dogtags/functions/fnc_showDogtag.sqf @@ -31,5 +31,11 @@ private _display = uiNamespace getvariable [QGVAR(tag), displayNull]; if(isNull _display) exitWith {}; private _control = _display displayCtrl 1001; -_dogtagData params ["_nickName", "_code", "_bloodType"]; -_control ctrlSetStructuredText parseText format ["%1
%2
%3", toUpper _nickName, _code, _bloodType]; +_dogtagData params ["_name", "_code", "_bloodType"]; + +// If data doesn't exist or body has no name, set name as "unknown" +if (_name == "") then { + _name = LELSTRING(common,unknown); +}; + +_control ctrlSetStructuredText parseText format ["%1
%2
%3", toUpper _name, _code, _bloodType]; From 374530532352b3be05c56a7db0fed1c63c863d5e Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 4 Jul 2024 09:32:37 +0200 Subject: [PATCH 134/290] Dogtags - Fix arsenal not showing dogtag info in multiplayer (#10095) * Broadcast dogtag info globally so that arsenal can use it * Broadcast changes incrementally * Update addons/dogtags/XEH_postInit.sqf Co-authored-by: PabstMirror * Update addons/dogtags/functions/fnc_getDogtagItem.sqf Co-authored-by: PabstMirror * Add EH only on necessary machines --------- Co-authored-by: PabstMirror --- addons/dogtags/XEH_PREP.hpp | 2 -- addons/dogtags/XEH_postInit.sqf | 25 +++++++++++--- addons/dogtags/XEH_preInit.sqf | 8 +++++ .../functions/fnc_addDogtagActions.sqf | 4 ++- .../dogtags/functions/fnc_checkDogtagItem.sqf | 22 ------------- .../dogtags/functions/fnc_getDogtagItem.sqf | 16 ++++----- .../dogtags/functions/fnc_sendDogtagData.sqf | 33 ------------------- 7 files changed, 38 insertions(+), 72 deletions(-) delete mode 100644 addons/dogtags/functions/fnc_checkDogtagItem.sqf delete mode 100644 addons/dogtags/functions/fnc_sendDogtagData.sqf diff --git a/addons/dogtags/XEH_PREP.hpp b/addons/dogtags/XEH_PREP.hpp index 5917600139..a34a04a982 100644 --- a/addons/dogtags/XEH_PREP.hpp +++ b/addons/dogtags/XEH_PREP.hpp @@ -5,10 +5,8 @@ PREP(bloodType); PREP(canCheckDogtag); PREP(canTakeDogtag); PREP(checkDogtag); -PREP(checkDogtagItem); PREP(getDogtagData); PREP(getDogtagItem); -PREP(sendDogtagData); PREP(showDogtag); PREP(ssn); PREP(takeDogtag); diff --git a/addons/dogtags/XEH_postInit.sqf b/addons/dogtags/XEH_postInit.sqf index 1633aace3c..9f9fad0f81 100644 --- a/addons/dogtags/XEH_postInit.sqf +++ b/addons/dogtags/XEH_postInit.sqf @@ -1,10 +1,29 @@ #include "script_component.hpp" [QGVAR(showDogtag), LINKFUNC(showDogtag)] call CBA_fnc_addEventHandler; -[QGVAR(sendDogtagData), LINKFUNC(sendDogtagData)] call CBA_fnc_addEventHandler; [QGVAR(getDogtagItem), LINKFUNC(getDogtagItem)] call CBA_fnc_addEventHandler; [QGVAR(addDogtagItem), LINKFUNC(addDogtagItem)] call CBA_fnc_addEventHandler; +if (hasInterface || isServer) then { + [QGVAR(broadcastDogtagInfo), { + GVAR(dogtagsData) set _this; + }] call CBA_fnc_addEventHandler; + + if (isServer) then { + // Sync dogtag data from server to client + [QGVAR(requestSyncDogtagDataJIP), { + params ["_clientOwner"]; + + { + [QGVAR(broadcastDogtagInfo), [_x, _y], _clientOwner] call CBA_fnc_ownerEvent; + } forEach GVAR(dogtagsData); + }] call CBA_fnc_addEventHandler; + } else { + // To be here, hasInterface must be true + [QGVAR(requestSyncDogtagDataJIP), clientOwner] call CBA_fnc_serverEvent; + }; +}; + // Add actions and event handlers only if ace_medical is enabled // - Adding actions via config would create a dependency ["CBA_settingsInitialized", { @@ -56,8 +75,6 @@ if (["ace_arsenal"] call EFUNC(common,isModLoaded)) then { if (_leftPanelIDC in [2010, 2012, 2014] && {_rightPanelIDC == 38}) then { LOG("passed"); private _rightPanel = _display displayCtrl 15; - private _allDogtags = missionNamespace getVariable [QGVAR(allDogtags), []]; - private _allDogtagsData = missionNamespace getVariable [QGVAR(allDogtagDatas), []]; private _cfgWeapons = configFile >> "CfgWeapons"; private _item = ""; private _dogtagData = []; @@ -66,7 +83,7 @@ if (["ace_arsenal"] call EFUNC(common,isModLoaded)) then { _item = _rightPanel lnbData [_i, 0]; if (_item isKindOf ["ACE_dogtag", _cfgWeapons]) then { - private _name = (_allDogtagsData param [_allDogtags find _item, []]) param [0, ""]; + private _name = (GVAR(dogtagsData) getOrDefault [_item, []]) param [0, ""]; // If data doesn't exist or body has no name, set name as "unknown" if (_name == "") then { diff --git a/addons/dogtags/XEH_preInit.sqf b/addons/dogtags/XEH_preInit.sqf index f5fcb406b1..482551de0a 100644 --- a/addons/dogtags/XEH_preInit.sqf +++ b/addons/dogtags/XEH_preInit.sqf @@ -8,4 +8,12 @@ PREP_RECOMPILE_END; GVAR(disabledFactions) = createHashMap; +if (hasInterface || isServer) then { + GVAR(dogtagsData) = createHashMap; + + if (!isServer) exitWith {}; + + GVAR(idCounter) = 0; +}; + ADDON = true; diff --git a/addons/dogtags/functions/fnc_addDogtagActions.sqf b/addons/dogtags/functions/fnc_addDogtagActions.sqf index 7c7a2e5e8f..b41cce1be8 100644 --- a/addons/dogtags/functions/fnc_addDogtagActions.sqf +++ b/addons/dogtags/functions/fnc_addDogtagActions.sqf @@ -27,7 +27,9 @@ private _fnc_getActions = { private _displayName = getText (_config >> "displayName"); private _picture = getText (_config >> "picture"); - private _action = [_x, _displayName, _picture, FUNC(checkDogtagItem), {true}, {}, _x] call EFUNC(interact_menu,createAction); + private _action = [_x, _displayName, _picture, { + [GVAR(dogtagsData) getOrDefault [_this select 2, []]] call FUNC(showDogtag); + }, {true}, {}, _x] call EFUNC(interact_menu,createAction); _actions pushBack [_action, [], _player]; }; } forEach (_player call EFUNC(common,uniqueItems)); diff --git a/addons/dogtags/functions/fnc_checkDogtagItem.sqf b/addons/dogtags/functions/fnc_checkDogtagItem.sqf deleted file mode 100644 index 09526d83ed..0000000000 --- a/addons/dogtags/functions/fnc_checkDogtagItem.sqf +++ /dev/null @@ -1,22 +0,0 @@ -#include "..\script_component.hpp" -/* - * Author: SzwedzikPL - * Check dogtag self menu action. - * - * Arguments: - * 0: Player - * 1: Target - * 2: Item class - * - * Return Value: - * None - * - * Example: - * [player, unit, "itemClass"] call ace_dogtags_fnc_checkDogtagItem - * - * Public: No - */ - -params ["_player", "_target", "_item"]; - -[QGVAR(sendDogtagData), [_player, _item]] call CBA_fnc_serverEvent; diff --git a/addons/dogtags/functions/fnc_getDogtagItem.sqf b/addons/dogtags/functions/fnc_getDogtagItem.sqf index 04112bcc94..41cfc4deb7 100644 --- a/addons/dogtags/functions/fnc_getDogtagItem.sqf +++ b/addons/dogtags/functions/fnc_getDogtagItem.sqf @@ -21,19 +21,15 @@ if(!isServer) exitWith {}; params ["_player", "_target"]; TRACE_2("getDogtagItem",_player,_target); -private _allDogtags = missionNamespace getVariable [QGVAR(allDogtags), []]; -private _allDogtagDatas = missionNamespace getVariable [QGVAR(allDogtagDatas), []]; +GVAR(idCounter) = GVAR(idCounter) + 1; -private _nextID = count _allDogtags + 1; - -if (_nextID > 999) exitWith {ERROR("Ran out of IDs");}; +if (GVAR(idCounter) > 999) exitWith {ERROR("Ran out of IDs");}; private _dogTagData = [_target] call FUNC(getDogTagData); -private _item = format ["ACE_dogtag_%1", _nextID]; -_allDogtags pushBack _item; -_allDogtagDatas pushBack _dogTagData; +private _item = format ["ACE_dogtag_%1", GVAR(idCounter)]; -missionNamespace setVariable [QGVAR(allDogtags), _allDogtags]; -missionNamespace setVariable [QGVAR(allDogtagDatas), _allDogtagDatas]; [QGVAR(addDogtagItem), [_item, _dogTagData], [_player]] call CBA_fnc_targetEvent; + +// Broadcast data globally, so that clients can use it where needed +[QGVAR(broadcastDogtagInfo), [_item, _dogTagData]] call CBA_fnc_globalEvent; diff --git a/addons/dogtags/functions/fnc_sendDogtagData.sqf b/addons/dogtags/functions/fnc_sendDogtagData.sqf deleted file mode 100644 index 2351e61166..0000000000 --- a/addons/dogtags/functions/fnc_sendDogtagData.sqf +++ /dev/null @@ -1,33 +0,0 @@ -#include "..\script_component.hpp" -/* - * Author: SzwedzikPL - * Server: returns to client data on given dogtag. - * - * Arguments: - * 0: Player - * 1: Target - * - * Return Value: - * None - * - * Example: - * [player, unit] call ace_dogtags_fnc_sendDogtagData - * - * Public: No - */ - -if (!isServer) exitWith {}; - -params ["_target", "_item"]; -TRACE_2("sendDogtagData",_target,_item); - -private _allDogtags = missionNameSpace getVariable [QGVAR(allDogtags), []]; -private _allDogtagDatas = missionNameSpace getVariable [QGVAR(allDogtagDatas), []]; - -private _dogtagData = []; -private _index = _allDogtags find _item; -if (_index >= 0) then { - _dogtagData = _allDogtagDatas select _index; -}; - -[QGVAR(showDogtag), [_dogtagData], [_target]] call CBA_fnc_targetEvent; From edc7e9af3e5bbb6a3feaee0f3bec2dc625e4becc Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 4 Jul 2024 09:39:08 +0200 Subject: [PATCH 135/290] Dogtags - Add context menu action to check dog tag (#10101) * Broadcast dogtag info globally so that arsenal can use it * Broadcast changes incrementally * Add context menu option for dogtags --- addons/dogtags/XEH_postInit.sqf | 18 ++++++++++++++++++ addons/dogtags/functions/fnc_getDogtagItem.sqf | 1 - 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/addons/dogtags/XEH_postInit.sqf b/addons/dogtags/XEH_postInit.sqf index 9f9fad0f81..6e676671ae 100644 --- a/addons/dogtags/XEH_postInit.sqf +++ b/addons/dogtags/XEH_postInit.sqf @@ -97,5 +97,23 @@ if (["ace_arsenal"] call EFUNC(common,isModLoaded)) then { }] call CBA_fnc_addEventHandler; }; +// Add context menu option +[ + "ACE_dogtag", + ["GROUND", "CARGO", "CONTAINER"], + LLSTRING(checkItem), + nil, + QPATHTOF(data\dogtag_icon_ca.paa), + [ + {true}, + {true} + ], + { + [GVAR(dogtagsData) getOrDefault [_this select 2, []]] call FUNC(showDogtag); + + false + } +] call CBA_fnc_addItemContextMenuOption; + // Disable dogtags for civilians "CIV_F" call FUNC(disableFactionDogtags); diff --git a/addons/dogtags/functions/fnc_getDogtagItem.sqf b/addons/dogtags/functions/fnc_getDogtagItem.sqf index 41cfc4deb7..e5f05eb19b 100644 --- a/addons/dogtags/functions/fnc_getDogtagItem.sqf +++ b/addons/dogtags/functions/fnc_getDogtagItem.sqf @@ -28,7 +28,6 @@ if (GVAR(idCounter) > 999) exitWith {ERROR("Ran out of IDs");}; private _dogTagData = [_target] call FUNC(getDogTagData); private _item = format ["ACE_dogtag_%1", GVAR(idCounter)]; - [QGVAR(addDogtagItem), [_item, _dogTagData], [_player]] call CBA_fnc_targetEvent; // Broadcast data globally, so that clients can use it where needed From f65138f65e14f6e8afe72fec14ce491a5acbd465 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sun, 7 Jul 2024 16:41:10 +0200 Subject: [PATCH 136/290] Casings - Fix settings (#10110) --- addons/casings/XEH_postInit.sqf | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/addons/casings/XEH_postInit.sqf b/addons/casings/XEH_postInit.sqf index c1baad68e9..47737c4e04 100644 --- a/addons/casings/XEH_postInit.sqf +++ b/addons/casings/XEH_postInit.sqf @@ -1,7 +1,12 @@ #include "script_component.hpp" -if (!hasInterface || !GVAR(enabled)) exitWith {}; +if (!hasInterface) exitWith {}; -GVAR(cachedCasings) = createHashMap; -GVAR(casings) = []; -["CAManBase", "FiredMan", LINKFUNC(createCasing)] call CBA_fnc_addClassEventHandler; +["CBA_settingsInitialized", { + if (!GVAR(enabled)) exitWith {}; + + GVAR(cachedCasings) = createHashMap; + GVAR(casings) = []; + + ["CAManBase", "FiredMan", LINKFUNC(createCasing)] call CBA_fnc_addClassEventHandler; +}] call CBA_fnc_addEventHandler; From 63d1ab82a730b4d052cd3d635801331c10f6fcbe Mon Sep 17 00:00:00 2001 From: Apricot <50947830+Apricot-ale@users.noreply.github.com> Date: Sun, 14 Jul 2024 09:22:06 +0900 Subject: [PATCH 137/290] Translations - Improve Japanese (#10112) * Improve Japanese * Tweaks * bit tweak * even more tweak * Update stringtable.xml * Update stringtable.xml --- addons/advanced_throwing/stringtable.xml | 6 ++-- addons/aircraft/stringtable.xml | 2 ++ addons/arsenal/stringtable.xml | 2 +- addons/common/stringtable.xml | 20 +++++------ addons/fieldmanual/stringtable.xml | 8 ++--- addons/fortify/stringtable.xml | 26 +++++++------- addons/gestures/stringtable.xml | 12 +++---- addons/goggles/stringtable.xml | 2 +- addons/interact_menu/stringtable.xml | 46 ++++++++++++------------ addons/interaction/stringtable.xml | 10 +++--- addons/map_gestures/stringtable.xml | 24 ++++++------- addons/medical/stringtable.xml | 2 +- addons/medical_gui/stringtable.xml | 8 ++--- addons/mk6mortar/stringtable.xml | 2 +- addons/optionsmenu/stringtable.xml | 2 +- addons/overheating/stringtable.xml | 2 +- addons/rangecard/stringtable.xml | 2 +- addons/reload/stringtable.xml | 4 +-- addons/respawn/stringtable.xml | 18 +++++----- addons/scopes/stringtable.xml | 24 ++++++------- addons/switchunits/stringtable.xml | 8 ++--- addons/ui/stringtable.xml | 4 +-- addons/vehiclelock/stringtable.xml | 6 ++-- addons/weather/stringtable.xml | 4 +-- addons/zeus/stringtable.xml | 4 +-- 25 files changed, 125 insertions(+), 123 deletions(-) diff --git a/addons/advanced_throwing/stringtable.xml b/addons/advanced_throwing/stringtable.xml index e0e526e12e..fc9cf2705a 100644 --- a/addons/advanced_throwing/stringtable.xml +++ b/addons/advanced_throwing/stringtable.xml @@ -144,7 +144,7 @@ Enables ability to pick up throwables from the ground. Activa la habilidad de coger objetos lanzados del suelo Включает возможность подбирать гранаты с земли. - 地面に落ちている投擲物を拾い上げる機能を有効化します。 + 地面に落ちている投擲物を拾う機能を有効化します。 Umożliwia podnoszenie obiektów miotanych z ziemi. Aktiviert die Möglichkeit, geworfene Objekte wieder vom Boden aufzuheben. 땅에 떨어진 투척물을 주울 수 있게 해줍니다. @@ -174,7 +174,7 @@ Enables ability to pick up throwables from attached objects. Activa la habilidad de lanzar objetos enganchados Включает возможность подбирать гранаты, прикрепленные к объектам. - オブジェクトに装着された投擲可能物を拾い上げる機能を有効化します。 + オブジェクトに装着された投擲物を拾う機能を有効化します。 Umożliwia podnoszenie obiektów miotanych przyczepionych do innych obiektów. Aktiviert die Möglichkeit, befestigte Wurfobjekte erneut aufzunehmen. 부착된 투척물을 주울 수 있게 해줍니다. @@ -254,7 +254,7 @@ Primed Preparado Подготовлена - 点火 + を点火した Odbezpieczony Scharf gemacht 뇌관 작동 diff --git a/addons/aircraft/stringtable.xml b/addons/aircraft/stringtable.xml index 01c5b41e36..041653fe2b 100644 --- a/addons/aircraft/stringtable.xml +++ b/addons/aircraft/stringtable.xml @@ -182,12 +182,14 @@ Distanza di seguimento Folge-Entfernung 따라가는 거리 + 追跡距離 Following unit within %1m Seguendo unità entro %1m Folgt Einheit bis zu %1m %1m 이내로 유닛을 따라갑니다 + %1m 間隔で 目標を追跡します diff --git a/addons/arsenal/stringtable.xml b/addons/arsenal/stringtable.xml index cf858ec24d..38f41ef4a6 100644 --- a/addons/arsenal/stringtable.xml +++ b/addons/arsenal/stringtable.xml @@ -23,7 +23,7 @@ Masque l'interface Oberfläche verstecken Ukryj interfejs - インターフェースを隠す + インタフェースを隠す Nascondi interfaccia 인터페이스 숨기기 隱藏介面 diff --git a/addons/common/stringtable.xml b/addons/common/stringtable.xml index 96ad037cc1..4b015fe9d4 100644 --- a/addons/common/stringtable.xml +++ b/addons/common/stringtable.xml @@ -402,7 +402,7 @@ [ACE] Itens diversos [ACE] Egyéb tárgyak [ACE] Oggetti vari - [ACE] その他アイテム + [ACE] その他のアイテム [ACE] 기타 물품. [ACE] 雜項 [ACE] 杂项 @@ -726,7 +726,7 @@ Enable gunlight after weapon switch or vehicle enter/exit if it was previously enabled. Включать ЛЦУ/тактический фонарь после смены оружия или входа/выхода из машины, если он был до этого включен. - 銃のライト等を点けていると武器を切り替えた後や車両を乗り降りしても、ライト等を点けたままにします。 + 銃のライトをつけていた場合、武器の切り替え後または車両の出入り後にライトを再度点灯します。 Abilita la torcia/laser dopo il cambio dell'arma o l'entrata/uscita del veicolo se precedentemente attiva. 이전에 무기의 손전등/레이저를 켠 경우 무기 전환이나 차량 승하차시 켠 상태를 유지합니다. Aktiviert Laserpointer/Taktisches Licht nach einem Waffenwechsel oder dem Auf-/Absitzen, falls es zuvor aktiv war. @@ -1360,7 +1360,7 @@ Non hai più spazio Nincs több hely В инвентаре нет места - インベントリに空きがない + インベントリに空きがありません 넣을 공간이 없습니다 無可用空間 无可用空间 @@ -1406,7 +1406,7 @@ 음악 끄기 허용 允許調低音樂音量 允许调低音乐音量 - 音楽の音量低下を許可 + 音楽音量の低減を許可 Permesso di abbassare la musica Zezwól na przyciszanie muzyki Разрешить приглушение музыки @@ -1422,7 +1422,7 @@ ACE 스크립트가 음악을 끌 수 있습니다. 允許ACE腳本去控制音樂的音量 允许 ACE 脚本去控制音乐的音量。 - ACEのスクリプトに音量低下を許可します。 + ACEのスクリプトに音楽音量の低減を許可します。 Permetti agli script di ACEdi abbassare la musica. Zezwól skrypty ACE na przyciszanie muzyki. Позволить скриптам ACE приглушать музыку @@ -1435,7 +1435,7 @@ Epilepsy friendly mode Epilepsiefreundlicher Modus - けいれん回避モード + てんかん対応モード Tryb dla epileptyków Mode adapté à l'épilepsie Modalità per Epilettici @@ -1448,7 +1448,7 @@ Disables some flashing light effects to reduce seizure risk. Deaktiviert einige Lichtflackereffekte um das Risiko von Epilepsieanfällen zu reduzieren. - いくつかの光点滅エフェクトを無効化し、けいれんの恐れを低下させます。 + てんかん発作のリスクを軽減するために、一部の点滅する光の効果を無効にします。 Wyłącz część migających efektów w celu zredukowania ryzyka napadu epilepsji Désactive certains effets de lumière clignotante afin de réduire les risques de crise d'épilepsie. Disattiva alcuni effetti di luci intermittenti per ridurre il rischio di crisi epilettiche. @@ -1464,7 +1464,7 @@ 旗帜(ACE-黑色): 旗幟(ACE-黑色) Bandiera (ACE - Nera) - 旗 (ACE - 黒) + 旗 (ACE - 黒色) Flaga (ACE - Czarna) Флаг (ACE - Черный) Bandeira (ACE - Preto) @@ -1480,7 +1480,7 @@ 旗帜(ACE-白色): 旗幟(ACE-白色) Bandiera (ACE - Bianca) - 旗 (ACE - 白) + 旗 (ACE - 白色) Flaga (ACE - Biała) Флаг (ACE - Белый) Bandeira (ACE - Branco) @@ -1544,7 +1544,7 @@ 在自我互动菜单内显示动作 Pokaż akcje w menu interakcji własnej Mostra a ação no menu de auto-interação - セルフ インタラクションにアクションを表示 + セルフ・インタラクションにアクションを表示します Mostra le azioni nel menu di interazione con se stessi Mostrar la acción en el menú de interacción propio Zobrazit akci v menu vlastních interakcí diff --git a/addons/fieldmanual/stringtable.xml b/addons/fieldmanual/stringtable.xml index 78b7ad6fe8..12e34d0e34 100644 --- a/addons/fieldmanual/stringtable.xml +++ b/addons/fieldmanual/stringtable.xml @@ -312,7 +312,7 @@ %3의료 메뉴%4는 %3의료%4를 용이하게 사용하기 위한 전용 %3인터페이스%4입니다. %3우%4 및 %3좌%4 문자는 치료 중인 환자의 신체 측면을 나타냅니다.<br/><br/>%3사용 방법:%4<br/>%2환자를 보고 [%3%13%4]를 사용하여 의료 메뉴를 여십시오. 환자 없이 메뉴를 열면 자가 치료가 됩니다.<br/>%2아니면 [%3%12%4] 또는 [%3%13%4]를 사용하고 %3의료 메뉴%4를 선택하십시오.<br/><br/>%3키 설정%4<br/>%2[%3W, A, S, D, X와 Z%4]를 사용하여 신체 부위를 선택하십시오.<br/>%2%3번호판 키%4를 사용하여 치료 카테고리를 선택하십시오. O %3Menu Médico%4 é uma %3interface%4 dedicada a facilitar o %3tratamento médico%4. As letras %3R%4 e %3L%4 indicam o lado do corpo do paciente que está recebendo o tratamento.<br/><br/>%3Uso:%4<br/>%2Utilize [%3%14%4] enquanto olha o paciente para abrir o Menu Médico. Se não houver paciente, o menu será de auto-tratamento.<br/>%2Alternativamente, utilize [%3%12%4] ou [%3%13%4] e selecione %3Menu Médico%4.<br/><br/>%3Atalhos de teclado:%4<br/>%2Utilize [%3W, A, S, D, X, e Z%4] para selecionar partes do corpo.<br/>%2Utilize as %3teclas numéricas%4 para selecionar as categorias de tratamento. Il %3Menù Medico%4 è un'%3interfaccia%4 dedicata a facilitare %3trattamenti medici%4. Le lettere %3Dx%4 e %3Sx%4 contrassegnano i lati del corpo del paziente che si stanno medicando.<br/><br/>%3Utilizzo:%4<br/>%2Usa [%3%14%4] guardando il paziente per aprire il Menù Medico. Aprire il menù senza paziente di fronte permette l'automedicazione.<br/>%2In alternativa, usa [%3%12%4] o [%3%13%4] e seleziona %3Menù Medico%4.<br/><br/>%3Comandi:%4<br/>%2Usa [%3W, A, S, D, X, and Z%4] per selezionare parti del corpo.<br/>%2Usa %3tasti numerici%4 per selezionare categorie di cure. - %3医療メニュー%4は%3治療%4をしやすくするための専用%3インターフェース%4です。%3右%4と%3左%4の文字は治療を受ける患者の向きを表しています。<br/><br/>%3使用方法:%4<br/>%2[%3%14%4] を患者に視点を合わせながら押すことで患者の医療メニューを開けます。視点を合わせないで押すと、自分の医療メニューを開くことが出来ます。<br/>%2もしくは [%3%12%4] または [%3%13%4] を使って%3医療メニュー%4を選択します。<br/><br/>%3キーバインド:%4<br/>%2[%3W, A, S, D, X, と Zキー%4] を使って身体の部位を選択できます。<br/>%2%3数字キー%4を使って治療項目を選択できます。 + %3医療メニュー%4は%3治療%4をしやすくするための専用%3インタフェース%4です。%3右%4と%3左%4の文字は治療を受ける患者の向きを表しています。<br/><br/>%3使用方法:%4<br/>%2[%3%14%4] を患者に視点を合わせながら押すことで患者の医療メニューを開けます。視点を合わせないで押すと、自分の医療メニューを開くことが出来ます。<br/>%2もしくは [%3%12%4] または [%3%13%4] を使って%3医療メニュー%4を選択します。<br/><br/>%3キーバインド:%4<br/>%2[%3W, A, S, D, X, と Zキー%4] を使って身体の部位を選択できます。<br/>%2%3数字キー%4を使って治療項目を選択できます。 El %3Menú Médico%4 es una %3interfaz%4 dedicada para facilitar el %3tratamiento médico%4. Las letras %3R%4 and %3L%4 indican el lado del paciente siendo tratado.<br/><br/>%3Uso:%4<br/>%2Usar [%3%14%4] mientras se mira al paciente para abrir el Menú Médico. Abrir el menú sin mirar a un paciente permite el tratamiento a uno mismo. <br/>%2Alternativamente, usar [%3%12%4] o [%3%13%4] y seleccionar %3Menú Médico%4.<br/><br/>%3Teclas asociadas:%4<br/>%2Usar [%3W, A, S, D, X, and Z%4] para seleccionar las partes del cuerpo.<br/>%2Usar las %3teclas numéricas%4 para seleccionar las categorías de tratamiento. @@ -388,7 +388,7 @@ %3휴대전화%4는 기능적으로는 %3격발기%4입니다. 폭발물 장치를 연결하여 폭발물을 터뜨릴 때 사용합니다. 여러 장치를 휴대전화와 연결하여 전화번호부 내에서 호출할 수 있습니다.<br/><br/>%3사용 방법:%4<br/>%2폭발물을 놓으십시오.<br/>%2[%3%13%4]를 사용하고, %3폭발물%4을 선택하고, %3휴대전화%4를 선택하십시오.<br/%2[%3%12%4]로 휴대전화 인터페이스를 여십시오.<br/>%2기폭시킬 전화번호를 선택하십시오. O %3Celular%4 serve como dispositivo de detonação ao explosivo. Utilize-o para conectar e detonar dispositivos explosivos. Múltiplos dispositivos podem estar conectados ao celular e aparecerão na lista telefônica.<br/><br/>%3Uso:%4<br/>%2Plante o explosivo.<br/>%2Utilize [%3%13%4], selecione %3Explosivos%4, e selecione %3Celular%4.<br/>%2Abra a interface do celular com [%3%12%4].<br/>%2Navegue pela lista telefônica utilizando as setas e selecione o número desejado.<br/>%2Ligue para o número para detonar. Il %3Cellulare%4 è essenzialmente una %3spoletta%4. Usalo per collegare e detonare esplosivi. Molteplici esplosivi possono essere collegati ad un cellulare e detonati chiamando numeri nella rubrica.<br/><br/>%3Utilizzo:%4<br/>%2Piazza un esplosivo.<br/>%2Usa [%3%13%4], seleziona %3Esplosivi%4, seleziona %3Cellulare%4.<br/>%2Apri l'interfaccia del telefono con [%3%12%4].<br/>%2Naviga la rubrica con le freccette e seleziona il numero da chiamare.<br/>%2Chiama il numero del dispositivo da detonare. - %3携帯電話%4は%3点火装置%4として機能します。爆破装置を接続して起爆するために使用します。複数のデバイスを携帯電話に繋ぎ、電話帳から呼び出すことができます。<br/><br/>%3使用方法:%4<br/>%2爆発物を設置。<br/>%2[%3%13%4] を使い、%3爆発物%4を選択して、%3携帯電話%4を選択します。<br/>%2[%3%12%4] を使って携帯電話インターフェースを開きます。<br/>%2矢印ボタンで電話帳に移動し、発信番号を選択します。<br/>%2電話を掛けることで起爆します。 + %3携帯電話%4は%3点火装置%4として機能します。爆破装置を接続して起爆するために使用します。複数のデバイスを携帯電話に繋ぎ、電話帳から呼び出すことができます。<br/><br/>%3使用方法:%4<br/>%2爆発物を設置。<br/>%2[%3%13%4] を使い、%3爆発物%4を選択して、%3携帯電話%4を選択します。<br/>%2[%3%12%4] を使って携帯電話インタフェースを開きます。<br/>%2矢印ボタンで電話帳に移動し、発信番号を選択します。<br/>%2電話を掛けることで起爆します。 El %3Teléfono%4 es funcionalmente un %3Detonador%4. Úsalo para conectarlo y detonar un dispositivo explosivo. Múltiples dispositivos pueden ser conectados al teléfono y llamados desde la agenda de contactos.<br/><br/>%3Uso:%4<br/>%2Colocar un explosivo.<br/>%2Usar [%3%13%4], seleccionar %3Explosivos%4, y seleccionar %3Teléfono%4.<br/>%2Abrir la interfaz del teléfono con [%3%12%4].<br/>%2Navegar por la agenda de contactos con las flechas y selecciona el número a llamar.<br/>%2Llamar al número para detonarlo. @@ -425,7 +425,7 @@ Użyj%3Detonatora%4 do podłączenia i wysadzenia ładunku. Do jednego ładunku może być podłączonych wiele ładunków na różnych kanałach.<br/><br/>%3Użycie:%4<br/>%2Połóż ładunek wybuchowy.<br/>%2Użyj [%3%13%4], wybierz%3Mat. Wybuchowe%4, i wybierz %3Detonator%4, do którego chcesz go podłączyć.<br/>%2Otwórz menu interakcji ACE [%3%12%4].<br/>%2Wybierz %3Mat. Wybuchowe%4 i wybierz %3Detonator%4.<br/>%2Wybierz %3Ładunek%4 który chcesz wysadzić. %3격발기%4를 사용하여 폭발물을 연결하고 폭발시킬 수 있습니다. 여러 폭발물을 다른 채널에 연결하여 폭발시킬 수도 있습니다.<br/><br/>%3사용 방법:%4<br/>%2폭발물을 설치합니다.<br/>%2[%3%13%4]를 사용하여 %3폭발물%4을 선택하고 연결할 %3격발기%4를 선택하십시오.<br/>%2[%3%12%4] 키로 ACE 인터페이스를 여십시오.<br/>%2%3폭발물%4을 선택하고 %3격발기%4를 선택하십시오.<br/>%2%3폭발물%4을 선택하면 폭발합니다. Usa %3Spolette%4 per collegare e detonare dispositivi esplosivi. Molteplici dispositivi possono essere collagati a una spoletta e detonati individualmente come vari canali.<br/><br/>%3Utilizzo:%4<br/>%2Piazza esplosivo.<br/>%2Usa [%3%13%4], seleziona %3Esplosivo%4, seleziona la %3Spoletta%4 a cui intendi collegarlo.<br/>%2Apri l'interfaccia ACE con [%3%12%4].<br/>%2Seleziona %3Esplosivi%4 e scegli una %3Spoletta%4.<br/>%2Seleziona un %3Explosivo%4 da detonare. - %3点火装置%4を爆破装置に接続し使用することで起爆することが出来ます。複数の爆破装置を接続しそれぞれ違うチャンネルから起爆することもできます。<br/><br/>%3使用方法:%4<br/>%2爆発物を設置。<br/>%2[%3%13%4] を使い、%3爆発物%4を選択して、接続したい%3点火装置%4を選択します。<br/>%2ACEインターフェースを [%3%12%4] で開きます。<br/>%2%3爆発物%4を選択し、%3点火装置%4を選びます。<br/>%2起爆したい%3爆破装置%4を選択します。 + %3点火装置%4を爆破装置に接続し使用することで起爆することが出来ます。複数の爆破装置を接続しそれぞれ違うチャンネルから起爆することもできます。<br/><br/>%3使用方法:%4<br/>%2爆発物を設置。<br/>%2[%3%13%4] を使い、%3爆発物%4を選択して、接続したい%3点火装置%4を選択します。<br/>%2ACEインタフェースを [%3%12%4] で開きます。<br/>%2%3爆発物%4を選択し、%3点火装置%4を選びます。<br/>%2起爆したい%3爆破装置%4を選択します。 Utiliza los %3Detonadores%4 para conectar y detonar un explosivo. Múltiple dispositivos pueden ser conectados a un detonador y detonados en diferentes canales.<br/><br/>%3Uso:%4<br/>%2 Coloca un explosivo.<br/>%2Usar [%3%13%4], seleccionar %3Explosivos%4, y selecciona el %3Detonador%4 al que quieres conectarlo.<br/>%2Abre la interfaz de ACE con [%3%12%4].<br/>%2Selecciona %3Explosivos%4 y selecciona un %3Detonador%4.<br/>%2Selecciona el %3Explosivo%4 que quieres detonar. @@ -860,7 +860,7 @@ %3Narzędzie do fortyfikowania%4 pozwala żołnierzom budować fortyfikacje wybrane przez twórcę misji.<br/><br/>%3Użycie:%4<br/>%2Podnieś %3Narzędzie do fortyfikowania%4.<br/>%2Użyj [%3%12%4] i wybierz %3Fortyfikuj%4.<br/>%2Wybierz dostępną fortyfikację i postępuj zgodnie ze wskazówkami na ekranie. L'%3Attrezzo di Fortificazione%4 permette ai soldati di costruire fortificazioni permesse dal creatore della missione.<br/><br/>%3Utilizzo:%4<br/>%2Raccogli un %3Attrezzo di Fortificazione%4.<br/>%2Usa [%3%12%4] e seleziona %3Fortifica%4.<br/>%2Seleziona una fortificazione disponibile e segui le indicazioni di piazzamento sullo schermo. %3요새화 도구%4를 사용하면 병사들이 임무 생성자가 제공한 요새를 구축할 수 있습니다.<br/><br/>%3사용 방법:%4<br/>%2%3요새화 도구%4를 가지십시오.<br/>%2[%3%12%4]를 사용하고 %3요새화%4를 선택하십시오.<br/>%2사용 가능한 요새를 선택하고 화면의 지시에 따라 배치하십시오. - %3要塞ツール%4を使用すると、兵士はミッション作成者が提供した要塞を構築できます。<br/><br/>%3使用方法:%4<br/>%2%3要塞ツール%4を持つ。<br/>%2[%3%12%4] を使って%3要塞%4を選択します。<br/>%2利用可能な構造物を選択し、画面上の指示に従って配置します。 + %3築城ツール%4を使用すると、兵士はミッション作成者が提供した要塞を構築できます。<br/><br/>%3使用方法:%4<br/>%2%3築城ツール%4を持つ。<br/>%2[%3%12%4] を使って%3野戦築城%4を選択します。<br/>%2利用可能な構造物を選択し、画面上の指示に従って配置します。 La %3Herramienta de Fortificación%4 permite a los soldados construir fortificaciones provistas por su creador de mision.<br/><br/>%3Uso:%4<br/>%2Coge una %3Herramienta de Fortificación%4.<br/>%2Usar [%3%12%4] y seleccionar %3Fortificar%4.<br/>%2Selecciona una fortificación disponible y sigue las instrucciones en pantalla para su colocación. diff --git a/addons/fortify/stringtable.xml b/addons/fortify/stringtable.xml index 15150d6685..028cfbd9b2 100644 --- a/addons/fortify/stringtable.xml +++ b/addons/fortify/stringtable.xml @@ -4,7 +4,7 @@ Fortify Verstärken - 要塞 + 野戦築城 요새화 Fortifica 要塞 @@ -20,7 +20,7 @@ Fortify Tool Bauwerkzeug Attrezzo di Fortificazione - 要塞ツール + 築城ツール 요새화 도구 要塞工具 设防工具 @@ -49,7 +49,7 @@ Auto add fortify item Füge das Bauwerkzeug automatisch hinzu - 自動的に要塞ツールを追加 + 自動的に築城ツールを追加 Auto-aggiungi attrezzo di fortificazione 요새화 도구 자동으로 추가 自動增加要塞物品 @@ -67,7 +67,7 @@ Inizializza il sistema di fortificazione con alcuni parametri di base.<br/>Preset vengono presi da configFile and missionConfigFile, leggi la wiki per il formato richiesto. Инициализирует систему фортификации с некоторыми базовыми параметрами.<br/>Предустановки взяты из configFile и missionConfigFile, формат смотри на wiki. Inşa etme sistemini bazı temel parametrelerle başlatır. <br/> Ön ayarlar configFile ve missionConfigFile'dan alınır, format için wiki'ye bakın. - 要塞システムを初期設定に戻します。<br/>プリセットは configfile と missionConfigFile から参照されます。詳細は wiki を参照してください。 + 野戦築城システムを初期設定に戻します。<br/>プリセットは configfile と missionConfigFile から参照されます。詳細は wiki を参照してください。 Initialisiert das Verstärken-System, mit grundlegenden Einstellungen <br/>Vorseinstellungen werden aus der configFile und der missionConfigFile gezogen, für mehr Informationen: siehe das ACE Wiki. 使用一些基本参数初始化设防系统。<br/>预设从 configFile 和 missionConfigFile 中提取,参见 wiki 的格式。 기본 파라미터와 함께 요새화 시스템을 활성화합니다<br/>configFile 과 missionConfigFile에서 프리셋을 뽑아옵니다, 포맷은 위키를 참조하십시오. @@ -103,7 +103,7 @@ Conferma Posizionamento Lerak Confirmar implantação - ここで作る + 配置を確定 설치 확인 确认部署 確認佈署 @@ -112,7 +112,7 @@ Fortify: Limit Build Area Verstärken: Beschränke Baubereich - 要塞: 構築制限エリア + 野戦築城: 構築制限エリア 要塞: 限制建造區 Fortificazione: Limita Area 设防:限制建造区 @@ -130,7 +130,7 @@ ACE Fortificazione ACE 要塞 ACE 设防 - ACE 要塞 + ACE 野戦築城 ACE Fortyfikowanie ACE Фортификация ACE Inşa Etme @@ -190,7 +190,7 @@ Ha l'attrezzo di fortificazione 有要塞工具 有设防工具 - 要塞ツール所持時 + 築城ツール所持時 Posiada narzędzie do fortyfikowania Если имеется инструмент Insa Etme Aleti Olanlara Göster @@ -233,7 +233,7 @@ 건축물을 지을 때 걸리는 시간을 계수를 적용하여 계산합니다. Koeffizient zur Bestimmung der Bauzeit \nA in Ax + b, wobei x die Kosten des Objekts sind. Il coefficiente 'C' che determina il tempo di costruzione.\nTempo Totale = Costo * C + Tempo Minimo - 建造する時間を定義するために使用される係数。\n計算式はAx + bです。この係数はAであり、xは建造物のコストです。 + 構築する時間を定義するために使用される係数。\n計算式はAx + bです。この係数はAであり、xは構築物のコストです。 Współczynnik używany do określenia czasu budowy konstrukcji.\nA w Ax + b gdzie x jest kosztem obiektu Коэффициент используемый для указания времени необходимого для возведения постройки.\nA в формуле Ax + b, где x - это цена объекта Coeficiente usado para determinar el tiempo de construcción de una estructura.\nA en Ax + b donde x es el coste del objeto @@ -246,7 +246,7 @@ 최소 건축 시간 Minimale Bauzeit Tempo di costruzione minimo - 最短建造時間 + 最短構築時間 Minimalny czas budowy Мин. время возведения Tiempo mínimo de construcción @@ -259,7 +259,7 @@ 건축물을 지을 때 걸리는 최소 시간을 계수를 적용하여 계산합니다. Mindestzeit für den Bau eines beliebigen Bauwerks.\nb in Ax + b, wobei x die Kosten des Objekts sind. Tempo minimo necessario per costruire una qualsiasi fortificazione.\nTempo Totale = Costo * CoefT/C + Tempo Minimo - 建造に掛かる最短時間。\n計算式はAx + bです。この時間はbであり、xは建造物のコストです。 + 構築に掛かる最短時間。\n計算式はAx + bです。この時間はbであり、xは構築物のコストです。 Minimalny czas do zbudowania dowolenj konstrukcji.\nb w Ax + b gdzie x jest kosztem obiektu Минимальное время для возведения любой постройки.\nb в формуле Ax + b, где x - это цена объекта Tiempo mínimo para construir una estructura.\nb en Ax + b donde x es el coste del objeto @@ -272,7 +272,7 @@ 건설 중 Bauwerk Costruendo - 建造 + 構築中 Budowanie Возведение Construyendo @@ -298,7 +298,7 @@ 건축물을 건설하고 나서 지도에 마커를 생성합니다 Erstellen von Kartenmarkierungen, die wie Gebäude im Gelände aussehen, wenn statische Befestigungen platziert werden Crea marker che appaiono come edifici sulla mappa lì dove vengono costruite fortificazioni - 静的な建築物が配置されたときに地形の建物のように見えるマップマーカーを生成します + 静的な構築物が配置されたときに地形の建物のように見えるマップマーカーを生成します Utwórz znaczniki mapy, które wyglądają jak obiekty terenu, gdy umieszczane są statyczne fortyfikacje Создавать маркера от статических фортификаций как от зданий на карте Crear marcadores de mapa que tienen la apariencia de edificios del terreno cuando las fortificaciones estáticas son colocadas diff --git a/addons/gestures/stringtable.xml b/addons/gestures/stringtable.xml index 33b73290c3..0f483e17a2 100644 --- a/addons/gestures/stringtable.xml +++ b/addons/gestures/stringtable.xml @@ -12,7 +12,7 @@ ACE Gestos ACE Жесты ACE Gestos - ACE ジェスチャー + ACE ジェスチャ ACE 수신호 ACE 手势 ACE 手勢 @@ -29,7 +29,7 @@ ACE Gestos ACE Жесты ACE Gestos - ACE ジェスチャー + ACE ジェスチャ ACE 수신호 ACE 手势 ACE 手勢 @@ -46,7 +46,7 @@ Kézjelek Gestos Gesti - ジェスチャー + ジェスチャ 수신호 手势 手勢 @@ -293,7 +293,7 @@ Afficher les gestes dans le menu d'interaction Mostrar gestos no menu de interação Показать жесты в меню взаимодействия - インタラクションメニュー上でジェスチャー表示 + ジェスチャのアクションを表示 수신호를 상호작용 메뉴에서 보여줍니다 显示手势互动菜单 顯示手勢互動選單 @@ -309,7 +309,7 @@ Afficher les gestes dans le menu d'interaction personnel, ou utiliser uniquement les touches, ou désactiver complètement. Mostra gestos no menu de interação, ou utilize um dos atalhos de teclado ou desative completamente Показать жесты в меню взамиодейтсвия с собой или только использовать горячие клавиши, или полностью отключить - セルフ インタラクションメニューでジェスチャーを表示するか、キーバインドのみを使用するか、完全に無効にします + セルフ・インタラクション メニューにジェスチャのアクションを表示するか、キーバインドのみを使用するか、完全に無効にします 수신호를 상호작용 메뉴에서 보여주거나 혹은 단축키를 지정하거나 아니면 아예 사용하지 않습니다. 显示手势选项在自己的互动菜单上,或只利用键盘来使用手势,或完全禁用 顯示手勢選項在自己的互動選單上,或只利用鍵盤來使用手勢,或完全禁用 @@ -341,7 +341,7 @@ Touches + menu d'interaction Atalhos + Menu de Interação Клавиши + Меню взаимодействия - キー操作とインタラクションメニュー + キー操作とメニュー 단축키 및 상호작용 메뉴 键盘 + 互动菜单 鍵盤 + 互動選單 diff --git a/addons/goggles/stringtable.xml b/addons/goggles/stringtable.xml index f02b95bf5c..233ac3e6ca 100644 --- a/addons/goggles/stringtable.xml +++ b/addons/goggles/stringtable.xml @@ -137,7 +137,7 @@ Pokaż interakcję Wyczyść Gogle Mostra interazione automatica per la pulizia degli occhiali Ukaž Vyčistit brýle v menu Interakce (vlastní) - ゴーグル拭き取りをセルフ インタラクションに表示 + ゴーグル拭き取りのアクションを表示 在自我互動中顯示擦拭護目鏡的動作 在自我互动中显示擦拭护目镜的动作 Afficher l'interaction "Essuyer les lunettes" diff --git a/addons/interact_menu/stringtable.xml b/addons/interact_menu/stringtable.xml index ce4da0c506..cb05331633 100644 --- a/addons/interact_menu/stringtable.xml +++ b/addons/interact_menu/stringtable.xml @@ -12,7 +12,7 @@ Mindig legyen a saját cselekvés kurzorja látható Mostra sempre il cursore per le autointerazioni Sempre mostrar cursor para interação pessoal - セルフ インタラクションへ常にカーソルを表示 + カーソルを常に表示 자기상호작용 시 항상 커서를 보이기 自我互动时永远显示光标 自我互動時永遠顯示游標 @@ -29,7 +29,7 @@ Immer den Mauszeiger für Fremd-Interaktionen anzeigen Mindig legyen a cselekvés kurzorja látható Sempre mostrar cursor para interação - インタラクションへ常にカーソルを表示 + カーソルを常に表示 상호작용 시 항상 커서를 보이기 互动时永远显示光标 互動時永遠顯示游標 @@ -46,7 +46,7 @@ Interaktionsmenü in Listen anzeigen Cselekvő menük listaként való megjelenítése Mostrar menu de interação como listas - インタラクションメニューを一覧表示 + メニューをリストで表示 상호작용메뉴를 리스트화 해서 보이기 以列表方式显示互动表单 以列表方式顯示互動表單 @@ -80,7 +80,7 @@ Saját cselekvő gomb Tasto autointerazioni Tecla de Interação Pessoal - セルフ インタラクション キー + セルフ・インタラクション キー 자기상호작용 키 自我互动键 自我互動鍵 @@ -131,7 +131,7 @@ Ações do Zeus Действия Зевса Interazioni Zeus - Zeusでのアクション + Zeusのアクション 제우스 동작 宙斯操作 宙斯操作 @@ -148,7 +148,7 @@ Interacción - Texto al max. Cselekvés - Szöveg max. Interação - Max. de Texto - インタラクション - 文字の色 + インタラクション - 文字の表示色の最大値 상호작용 - 문자색깔 互动—文字颜色最大值 互動 - 文字最大化 @@ -165,7 +165,7 @@ Interacción - Texto al min. Cselekvés - Szöveg min. Interação - Min. de Texto - インタラクション - 文字の背景色 + インタラクション - 文字の表示色の最低値 상호작용 - 문자배경색 互动—文字颜色最小值 互動 - 文字最小化 @@ -182,7 +182,7 @@ Interacción - Sombras al max. Cselekvés - Árnyék max. Interação - Max. de Sombra - インタラクション - 文字への影の色 + インタラクション - 文字の影色の最大値 상호작용 - 문자그림자색 互动—阴影最大值 互動 - 陰影最大化 @@ -199,7 +199,7 @@ Interacción - Sombras al min. Cselekvés - Árnyék min. Interação - Min. de Sombra - インタラクション - 文字への影の最低色 + インタラクション - 文字の影色の最低値 상호작용 - 문자그림자배경색 互动—阴影最小值 互動 - 陰影最小化 @@ -216,7 +216,7 @@ Udržuj kurzor na středu Manter o cursor centralizado Mantieni il cursore centrato - 常にカーソルを中央にする + カーソルを常に中心にする 커서를 항상 가운데에 둡니다 保持光标在中心点 保持游標在中心點 @@ -233,7 +233,7 @@ Mantiene el cursor centrado y despliega los menús alrededor. Útil si el tamaño de la pantalla es limitado. Manter o cursor centralizado e mover o menu de opções. Útil caso o tamanho da tela seja limitado. Mantieni il cursore centrato e sposta il menù intorno. Utile se lo schermo è piccolo. - 常にカーソルを中央へ表示させ、オプション メニューが移動します。画面の大きさが制限されている時に使いやすくなります。 + カーソルを常に中心に表示し、オプション メニューを移動させます。画面の大きさが制限されている時に便利です。 커서를 항상 가운데에 두고 메뉴를 움직입니다. 화면의 크기가 제한되있을 때 유용합니다. 保持光标在中心点并平移周遭的选项菜单。这对在屏幕尺寸有限的玩家很有用! 保持游標在中心點並平移周遭的選項選單。這對在螢幕尺寸有限的玩家很有用! @@ -250,7 +250,7 @@ Execute a ação quando soltar a tecla de menu Cselekvés végrehajtása a menügomb elengedésekor Esegui l'azione quando rilasci il tasto menu - メニュー キーを離した時にアクションを実行 + キーを離した時にアクションを実行 메뉴 키를 놓을 때 행동하기 当放开菜单键后就执行动作 當放開選單鍵後就執行動作 @@ -267,7 +267,7 @@ Tamanho do texto de interação Cselekvő szöveg mérete Dimensione del testo d'interazione - インタラクション文字の大きさ + 文字の大きさ 상호작용 - 문자크기 互动菜单文字大小 互動選單文字大小 @@ -284,7 +284,7 @@ Sombra do texto de interação Cselekvő szöveg árnyéka Ombra del testo d'interazione - インタラクション文字へ影 + 文字の影表示 상호작용 - 문자그림자 互动菜单文字阴影 互動選單文字陰影 @@ -301,7 +301,7 @@ Permite controlar a sombra do texto. Contorno ignora sombras com cores customizadas. Hozzáférést biztosít a szöveg árnyékának kezeléséhez. A körvonal nem veszi figyelembe az egyedi árnyékszíneket. Permette di controllare l'ombra del testo. L'impostazione "Contorno" ignora il colore dell'ombra. - 文字への影を設定します。縁取りは設定された影の色を無視します。 + 文字に影を表示します。縁取りは設定された影の色を無視します。 문자의 그림자를 조절하는 것을 가능케 합니다. 외곽선은 임의의 그림자색을 무시합니다. 允许控制文字阴影。轮廓部分则会忽略自定义的阴影颜色。 允許控制文字陰影。輪廓部分則會忽略自定義的陰影顏色 @@ -335,7 +335,7 @@ Cselekvő menü háttere Фон меню взаимодействия Sfondo Menù Interazioni - インタラクションメニューの背景 + メニューの背景 상호작용 메뉴 배경 互动菜单背景 互動選單背景 @@ -352,7 +352,7 @@ A háttér elmosása a cselekvő menü használata alatt. Размыть фон, пока открыто меню взаимодействия. Sfoca lo sfondo mentre il Menù Interazioni è aperto. - インタラクションメニューを開いたとき、背景をぼかします。 + インタラクション メニューを開いたときに背景をぼかします。 상호작용 메뉴가 열릴 시 배경을 흐릿하게 처리합니다. 当互动菜单开启时,模糊背景画面。 當互動選單開啟時,模糊背景畫面 @@ -386,7 +386,7 @@ Fekete Черный Nero - 背景を黒くする + 背景を暗くする 까맣게 黑色 黑色 @@ -436,7 +436,7 @@ Menú de interacción Menù Interazioni Menu d'interaction - インタラクションメニュー + インタラクション メニュー 상호작용 메뉴 互动菜单 互動選單 @@ -452,7 +452,7 @@ Velocità di Animazione delle Interazioni Velocidad de animación del menú de interacción Vitesse de l'animation d'interaction - インタラクションのアニメーション速度 + アニメーション速度 상호작용 움직임 속도 互动菜单动画速度 互動選單動畫速度 @@ -468,7 +468,7 @@ Rende le animazioni del Menù più veloci e diminuisce il tempo richiesto per mostrare sotto-azioni Hace la animación del menú más rápida, reduciendo el tiempo necesario para abrir sub-acciones. Rend les animations du menu plus rapide, et réduit le temps nécessaire à l'affichage des sous menus d'action. - メニューのアニメーションを高速化し、サブアクションを表示するためのホバーに必要な時間を短縮します。 + メニューのアニメーションを高速化し、サブアクションを表示するために必要なホバーにかかる時間を短縮します。 使菜单的动画速度更快,并减少子选项显现出来的时间 使選單的動畫速度更快,並減少子選項顯現出來的時間 상호작용을 표시하기 위해 메뉴 애니메이션을 빠르게 만들고 마우스를 가져오는 데 필요한 시간을 줄입니다. @@ -493,7 +493,7 @@ Consolidate single child actions Объединять ед. дочерные действия - 子アクションを統合 + 1個のみの子アクションを統合 Consolidar acciones hijo únicas Combiner les sous-actions uniques Untergeordnete Aktionen zusammenfassen @@ -506,7 +506,7 @@ Combines parent action with only one child action together. Объединять родительское действие с единственным дочерним действием в одно. - 親アクションと子アクションの一つを統合して表示します。 + アクションが1個のみの子アクションを親アクションと結合し表示を整理します。 Combina acciones padre con una única accion hijo de forma conjunta Lorsqu'un menu ne contient qu'une seule sous-action, elle est combinée avec son menu parent. Combina interazioni con una sola sotto-azione in una singola interazione. diff --git a/addons/interaction/stringtable.xml b/addons/interaction/stringtable.xml index 41861dcb31..38c86f5f99 100644 --- a/addons/interaction/stringtable.xml +++ b/addons/interaction/stringtable.xml @@ -164,7 +164,7 @@ Cselekvő menü Menu de Interação Menù Interazioni - インタラクションメニュー + インタラクション メニュー 상호작용 메뉴 互动菜单 互動選單 @@ -181,7 +181,7 @@ Cselekvő menü (saját) Menu de Interação (Individual) Menù Interazioni (su se stesso) - インタラクションメニュー (セルフ) + インタラクション メニュー (セルフ) 상호작용 메뉴(자신) 互动菜单(自我) 互動選單 (自我) @@ -458,7 +458,7 @@ Вас похлопали по ПРАВОМУ плечу Você foi tocado no ombro Ti è stato dato un colpetto sulla spalla destra - 右肩を叩かれました + 右肩を叩かれた 누군가 오른쪽 어깨를 쳤다 你的右肩膀被轻拍了一下 你的右肩膀被輕拍了一下 @@ -475,7 +475,7 @@ Вас похлопали по ЛЕВОМУ плечу Você foi tocado no ombro. Ti è stato dato un colpetto sulla spalla sinistra - 左肩を叩かれました + 左肩を叩かれた 누군가 왼쪽 어깨를 쳤다 你的左肩膀被轻拍了一下 你的左肩膀被輕拍了一下 @@ -848,7 +848,7 @@ Perdão Perdona Megbocsátás - 許す + 赦免する 허용 原谅 原諒 diff --git a/addons/map_gestures/stringtable.xml b/addons/map_gestures/stringtable.xml index 91f07c7cdf..cff2d15f4f 100644 --- a/addons/map_gestures/stringtable.xml +++ b/addons/map_gestures/stringtable.xml @@ -11,7 +11,7 @@ Kartenzeichen Gestos en mapa Pointage sur carte - マップ ジェスチャー + マップ ジェスチャ 지도 신호 地图指示 地圖指示器 @@ -43,7 +43,7 @@ Aktiviert die Kartenzeichen. Activar Gestos en Mapa Active le pointage sur carte. - マップ ジェスチャーを有効化 + マップ ジェスチャを有効化 지도 신호 활성화 启用地图指示 啟用地圖指示器 @@ -59,7 +59,7 @@ Maximale Reichweite der Kartenzeichen Máx. dist. para gestos en mapa Portée du pointage sur carte - マップ ジェスチャーの最大範囲 + マップ ジェスチャの最大範囲 지도 신호 최대 거리 地图指示最大范围 地圖指示器最大範圍 @@ -75,7 +75,7 @@ Maximale Reichweite zwischen Spielern um Kartenzeichen anzuzeigen Máxima distancia a la cual pueden verse el indicador de gestos Définit le rayon au-delà duquel un joueur ne verra plus l'indicateur de pointage des autres joueurs. - マップ ジェスチャーのインジケーターを表示可能なプレーヤー間の最大距離 + マップ ジェスチャのインジケータを表示可能なプレーヤー間の最大距離 플레이어간에 지도 신호 표시거리를 설정합니다. 设定地图指示显示的最大范围距离 設定地圖指示器顯示的最大範圍距離 @@ -137,7 +137,7 @@ Farbe der Namenstexte neben der Kartenzeichen-Markierung. Color de los nombres dibujados al lado del marcados de gestos. Définit la couleur du texte pour le nom à côté du marqueur de pointage sur carte. - マップ ジェスチャーに添えて表示される名前の文字色。 + マップ ジェスチャに添えて表示される名前の文字色。 지도 색상에 표시되는 이름의 색상을 결정합니다. 定义名称文字颜色。使其与地图指示颜色有所区别。 定義名稱文字顏色。使其與地圖指示器顏色有所區別 @@ -270,7 +270,7 @@ Показывать только союзные жесты Pokazuj jedynie sojusznicze gesty Afficher uniquement le pointage des alliés - 友軍のジェスチャーのみ表示 + 友軍のジェスチャのみ表示 Mostrar sólo gestos de aliados Nur Gesten befreundeter Einheiten zeigen Mostra solo gesti di alleati @@ -283,7 +283,7 @@ Показывать жесты только от игроков союзной стороны. Affiche uniquement les pointages effectués par des unités qui sont du même camp, ou d'un camp allié. Mostra solo gesti effettuati da unità che sono della stessa fazione o una fazione alleata. - 同じ陣営または味方陣営のユニットからのジェスチャーのみを表示します。 + 同じ陣営または味方陣営のユニットからのジェスチャのみを表示します。 Muestra únicamente gestos de las unidades que son del mismo bando o de un bando aliado Pokazuj tylko Gesty od jednostek z tej samej lub sojuszniczej strony Nur Gesten von Einheiten der selben oder einer verbündeten Seite zeigen. @@ -308,7 +308,7 @@ Max range between a Camera and players to show the map gesture indicator Устанавливает макс. дальность между игроком и камерой для отображения жестов на карте Définit le rayon au-delà duquel une caméra ne verra plus l'indicateur de pointage des autres joueurs. - 観戦カメラから確認可能なマップ ジェスチャーのインジケーターを表示するカメラとプレーヤー間の最大距離 + 観戦カメラから確認可能なマップ ジェスチャのインジケータを表示するカメラとプレーヤー間の最大距離 Máxima distancia entre una cámara y los jugadores para mostrar el indicador de gestos en mapa Distanza massima da cui videocamere (spettatore/zeus) può vedere i gesti di giocatori. Maksymalny zasięg pomiędzy kamerą a graczami do pokazania gestów na mapie @@ -334,7 +334,7 @@ Allows Spectator to See Map Gestures Позволяет наблюдателю видеть жесты на карте Permet aux spectateurs de voir le pointage des autres joueurs. - 観戦者からマップ ジェスチャーを表示できるようにします。 + 観戦者からマップ ジェスチャを表示できるようにします。 Permetti agli spettatori di vedere gesti in mappa Permitir al espectador ver los gestos de mapa Zezwól Obserwatorowi widzieć Gesty na mapie @@ -360,7 +360,7 @@ Allows Curator to See Map Gestures Позволяет куратору видеть жесты на карте Permet aux curateurs de voir le pointage des autres joueurs. - キュレーターからマップ ジェスチャーを表示できるようにします。 + キュレーターからマップ ジェスチャを表示できるようにします。 Permitir al Curador ver los gestos de mapa Permetti agli Zeus di vedere gesti in mappa Zezwól Zeusowi widzieć gesty na mapie @@ -473,7 +473,7 @@ Kartenzeichen - Gruppeneinstellungen Gestos en mapas - Configuración de grupos Pointage sur carte - réglages de groupe - マップ ジェスチャー - グループ設定 + マップ ジェスチャ - グループ設定 지도 신호 - 그룹 설정 地图指示—队伍设定 地圖指示器 - 隊伍設定 @@ -488,7 +488,7 @@ ACE Kartenzeichen ACE Gestos en mapa ACE Pointage sur carte - ACE マップ ジェスチャー + ACE マップ ジェスチャ ACE 지도 신호 ACE 地图指示 ACE 地圖指示器 diff --git a/addons/medical/stringtable.xml b/addons/medical/stringtable.xml index 6a081fa648..1a6cb07dbb 100644 --- a/addons/medical/stringtable.xml +++ b/addons/medical/stringtable.xml @@ -32,7 +32,7 @@ ACE 医疗 界面 ACE 醫療系統 介面 ACE Medikal Arayüz - ACE 医療 インターフェース + ACE 医療 インタフェース Unconscious Wake Up Chance diff --git a/addons/medical_gui/stringtable.xml b/addons/medical_gui/stringtable.xml index b88d9cbbf1..a03bc0bad8 100644 --- a/addons/medical_gui/stringtable.xml +++ b/addons/medical_gui/stringtable.xml @@ -36,7 +36,7 @@ Enables medical actions for the Interaction Menu and selects their style. Aktiviert die Sanitätsaktionen für das Interaktionsmenü und legt das Aussehen fest - インタラクションメニューから選択した表示方式で医療行為をできるようになります。 + インタラクション メニューから選択した表示方式で医療行為をできるようになります。 Включает медицинские действия для меню взаимодействия и выбирает их стиль. Permet d'afficher les actions médicales dans le menu d'interaction, et de définir leur style visuel. Ativa as ações médicas para o menu de interação e seleciona seus estilos. @@ -86,7 +86,7 @@ Enable Medical Self Actions Medizinische Selbst-Interaktionen anzeigen - 医療セルフインタラクションの有効化 + 医療セルフ・インタラクションの有効化 Разрешить Медицинские действия на себе Activer les actions médicales sur soi-même Ativar ações médicas em si mesmo @@ -102,7 +102,7 @@ Enables medical actions for the Self Interaction Menu. Medizinische Interaktionen bei Selbst-Interaktionen anzeigen - セルフインタラクションメニューで医療行為をできるようになります。 + セルフ・インタラクション メニューで医療行為をできるようになります。 Включает медицинские действия для меню взаимодействия с собой. Active les actions médicales du menu d'interaction personnel. Ativa as ações médicas do menu de interação pessoal. @@ -134,7 +134,7 @@ Enables the use of the Medical Menu through the keybind or interaction menu. Aktiviere die Nutzung des Sanitätsmenüs durch eine Tastenkombination oder durch das Interaktionsmenü - 割り当てられたキーかインタラクションメニューから医療メニューを使えるようになります。 + 割り当てられたキーかインタラクション メニューから医療メニューを使えるようになります。 Позволяет использовать Медицинское меню через связку клавиш или меню взаимодействия. Permet l'utilisation du menu médical via le menu d'interaction ou l'appui d'une touche. Ativa o uso do Menu Médico através da Tecla ou Menu de Interação. diff --git a/addons/mk6mortar/stringtable.xml b/addons/mk6mortar/stringtable.xml index 4195579998..c6f29a037d 100644 --- a/addons/mk6mortar/stringtable.xml +++ b/addons/mk6mortar/stringtable.xml @@ -46,7 +46,7 @@ Abrir tabela de distâncias para 82mm Otevřít 82mm Rangetable Apri la tavola di tiro 82mm - 82mm用射表を開く + 82mm用 射表 を開く 82mm 사거리표 열기 开启82 mm 迫击炮射表 開啟82毫米迫擊炮射表 diff --git a/addons/optionsmenu/stringtable.xml b/addons/optionsmenu/stringtable.xml index 4cd7f7d2f7..674ea3eb49 100644 --- a/addons/optionsmenu/stringtable.xml +++ b/addons/optionsmenu/stringtable.xml @@ -12,7 +12,7 @@ Debug a vágólapra Отладка в буфер обмена Debug negli Appunti - クリップボードにデバッグ + デバッグ情報をコピー 클립보드를 디버그하기 复制调试信息至剪贴板 複製除錯訊息至剪貼簿 diff --git a/addons/overheating/stringtable.xml b/addons/overheating/stringtable.xml index ef20ae9e81..d5e8ad7ca8 100644 --- a/addons/overheating/stringtable.xml +++ b/addons/overheating/stringtable.xml @@ -714,7 +714,7 @@ Cool weapon with... - 武器を・・・で冷却 + 武器をアイテムで冷却 Refroidir l'arme avec... Охладить оружие с... Waffe mit... kühlen diff --git a/addons/rangecard/stringtable.xml b/addons/rangecard/stringtable.xml index 859bb2e048..3e79eac985 100644 --- a/addons/rangecard/stringtable.xml +++ b/addons/rangecard/stringtable.xml @@ -12,7 +12,7 @@ Távolsági kártya Таблица поправок Tavola Balistica - レンジカード (射表) + レンジカード (弾道射表) 사거리표 射表 彈道射表 diff --git a/addons/reload/stringtable.xml b/addons/reload/stringtable.xml index 2c4bbcab76..2f0c6c60c1 100644 --- a/addons/reload/stringtable.xml +++ b/addons/reload/stringtable.xml @@ -38,7 +38,7 @@ Zawsze pokazuj interakcję od sprawdzania amunicji Mostra sempre l'autointerazione di controllo delle munizioni Vždy zobrazit kontrolu munice v menu vlastní interakce - セルフ インタラクションへ弾薬確認を常に表示 + 弾薬確認アクションを常に表示 總是在自我互動中顯示檢查彈藥動作 总是在自我互动中显示检查弹药动作 Toujours afficher l'action de vérification des munitions @@ -53,7 +53,7 @@ Pokazuje interakcję od sprawdzania amunicji poza bronią statyczną. Mostra l'autointerazione di controllo delle munizioni anche quando non si è in un'arma statica. Zobrazuje kontrolu munice v menu vlastní interakce i pokud hráč nepoužívá statickou zbraň. - 設置型火器を使っていなくても、セルフ インタラクションへ弾薬確認を常に表示します。 + 設置型火器以外でも常にセルフ・インタラクションに弾薬確認アクションを表示します。 即使不是固定式支援武器也依然在自我互動中顯示檢查彈藥動作 即使不是固定式支援武器也依然在自我互动中显示检查弹药动作 Permet d'afficher l'action de vérification des munitions du menu d'interaction personnel, même si le joueur n'utilise pas d'arme statique. diff --git a/addons/respawn/stringtable.xml b/addons/respawn/stringtable.xml index 6db9f12913..1de77a45d3 100644 --- a/addons/respawn/stringtable.xml +++ b/addons/respawn/stringtable.xml @@ -28,7 +28,7 @@ Kihelyezés 5 másodperc múlva... Dispiegamento in 5 secondi... Será posicionado em 5 segundos... - 5秒後に設置します・・・ + 5秒後に設置が完了します・・・ 5초 후 재투입... 5秒后完成部署... 5秒後完成佈署... @@ -126,7 +126,7 @@ Gyülekezőpont, Nyugat (Bázis) Bod shromáždění Západ (Základna) Ponto de encontro Oeste (Base) - ラリーポイント 同盟軍 (ベース) + ラリーポイント BLUFOR軍 (ベース) 蓝方集合点(基地) 藍方集合點 (基地) 청군 집결지 (기지) @@ -158,7 +158,7 @@ Gyülekezőpont, Független (Bázis) Bod shromáždění Nezávislý (Základna) Ponto de encontro Independente (Base) - ラリーポイント 独立軍 (ベース) + ラリーポイント INDEPENDENT軍 (ベース) 独立方集合点(基地) 獨立方集合點 (基地) 무소속군 집결지 (기지) @@ -174,7 +174,7 @@ Gyülekezőpont, Nyugat Bod shromáždění Západ Ponto de encontro Oeste - ラリーポイント 同盟軍 + ラリーポイント BLUFOR軍 蓝方集合点 藍方集合點 청군 집결지 @@ -206,7 +206,7 @@ Gyülekezőpont, Független Bod shromáždění Nezávislý Ponto de encontro Independente - ラリーポイント 独立軍 + ラリーポイント INDEPENDENT軍 独立方集合点 獨立方集合點 무소속군 집결지 @@ -319,7 +319,7 @@ Ce module vous permet de configurer les fonctionnalités ACE spécifiques à la réapparition des joueurs. Questo modulo ti permette di configurare le funzionalità ACE specifiche dei respawn. Este módulo permite configurar parámetros relacionados con la reaparición - 有効化するとリスポーンへ ACE 機能を設定できます。 + このモジュールを使用すると、リスポーンに ACE 固有の機能を設定できます。 이 모듈은 ACE 재투입의 자세한 설정을 변경할 수 있게 해줍니다. 该模块使您可以设定 ACE 的重生功能 該模塊使您可以設定ACE的重生功能 @@ -335,7 +335,7 @@ Baráti tűz üzenetek Сообщения об огне по своим Messaggi Fuoco Amico - 友軍誤射の布告 + フレンドリーファイア通知 아군 오인사격 메시지 友军误击信息 友軍誤擊訊息 @@ -350,7 +350,7 @@ L'utilisation de ce module fait en sorte qu'à chaque joueur mort par un tir ami, un rapport sera affiché dans le chat, indiquant qui a tué qui. Usando questo modulo nella tua missione farà in modo che ogni uccisione per fuoco amico venga mostrata in forma di messaggio in chat. El usar este módulo, todas las muertes por fuego amigo serán indicadas en el chat. - もし友軍誤射による死者が出た場合は、チャットにてその旨を表示します。 + ミッションでこのモジュールを使用すると、誤射による友軍キルがチャット上のメッセージとして表示されるようになります。 이 모듈은 미션 중 아군 오인사격으로 인한 사망자 발생 시 채팅창에 메시지를 표시해줍니다. 摆放此模块后,当有发生友军误击致死的事件,会显示提示信息在聊天视窗中。 擺放此模塊後,當有發生友軍誤擊致死的事件,會顯示提示訊息在聊天視窗中 @@ -381,7 +381,7 @@ Questo modulo ti consente di usare Rallypoint in missione, a cui ti puoi teleportare rapidamente dalla bandiera in base. Richiede il piazzamento di oggetti speciali in mappa - base e bandiera. Entrambi disponibili nella categoria Vuoto -> ACE Riapparizione Este módulo permite usar puntos de reunión en la misión, a los que pueden teletransportarse las unidades desde la bandera de base. Requiere colocar objetos especiales en el mapa: las banderas de base y de reunión, ambas disponibles en la categoría Vacio-> Reaparición ACE Ce module vous permet d'utiliser des points de ralliement dans les missions, vers lesquels vous pouvez vous téléporter rapidement depuis le drapeau de la base.\nNécessite de placer des objets spéciaux sur la carte - base et drapeau, tous deux disponibles dans la catégorie "Vide -> ACE Réapparition". - ミッションでベースから素早く移動できるラリーポイントを使えるようにします。ゲーム内に専用オブジェクトとなるベースとフラッグを設置している必要があります。両オブジェクトは Empty 下の ACE リスポーンから設置できます。 + このモジュールを使用すると、ミッションでラリーポイントを使用できるようになります。ラリーポイントには、ベース旗からすばやくテレポートできます。マップ上に特別なラリー/ベース旗オブジェクトを配置する必要があります。両オブジェクトは道具カテゴリ下の看板サブカテゴリ内、旗から設置できます。 이 모듈은 미션 중에 기지 깃발에서 집결지로 빠르게 텔레포트 시켜주는 역할을 합니다. 지도 상에 기지 및 깃발이 필요합니다. 두 가지 모두 비어 있음->ACE 재투입 카테고리에서 찾을 수 있습니다. 摆放此模块后,你将能在任务中部署集合点,使你可以快速往返基地与前线。要使用本功能,请记得放上空物体->ACE 重生里面的基地与旗帜。 擺放此模塊後,你將能在任務中佈署集合點,使你可以快速往返基地與前線。要使用本功能,請記得放上空物件->ACE 重生裡面的基地與旗幟 diff --git a/addons/scopes/stringtable.xml b/addons/scopes/stringtable.xml index b69d59e3c8..9a47f657cc 100644 --- a/addons/scopes/stringtable.xml +++ b/addons/scopes/stringtable.xml @@ -35,7 +35,7 @@ Enable adjustment turrets on high powered scopes Aktiviere Absehenverstellungen für Waffen mit Zielfernrohren - 高倍率スコープでACE スコープ調節を有効化 + 高倍率スコープでのタレット調整を有効化します 고성능 조준경 조절 나사 활성화 Włącz pokrętła regulacyjne Active les tourelles de réglage des lunettes de visée à fort grossissement. @@ -50,7 +50,7 @@ Force adjustment turrets Erzwinge Absehenverstellungen - ACE スコープ調節を有効化 + タレット調整を強制 조절 나사 강제 Wymuś użycie pokręteł regulacyjnych Forcer les tourelles de réglage @@ -65,7 +65,7 @@ Force usage of adjustment turrets on high powered scopes Erzwinge Absehenverstellungen für Waffen mit Zielfernrohren - 高倍率スコープで調整の使用を強制させます + 高倍率スコープでタレット調整の使用を強制させます 고성능 조준경의 조절 나사 사용을 강제합니다 Wymuś użycie pokręteł regulacyjnych dla celowników o dużym powiększeniu Force l'utilisation des tourelles de réglage sur les lunettes de visée à fort grossissement. @@ -80,7 +80,7 @@ Correct zeroing Nullungsanpassung - ゼロイン調節 + ゼロイン規整 영점 고치기 Poprawka zerowania Corriger le zérotage @@ -95,7 +95,7 @@ Corrects the zeroing of all small arms sights Korrigiert alle Nullungen von Handfeuerwaffen - 全ての小口径用照準器のゼロインを調節します + 全ての小火器用照準器のゼロインを規整します 모든 소화기의 영점을 고칩니다 Poprawia zerowanie wszystkich celowników broni ręcznej Corrige le zérotage de tous les viseurs d'armes légères. @@ -125,7 +125,7 @@ Uses the 'defaultZeroRange' setting to overwrite the zero range of high power scopes Nutzt die Einstellung 'defaultZeroRange' um Zielfernrohre anzupassen - 'defaultZeroRange'設定を使う高倍率スコープのゼロイン距離を上書きします + '標準のゼロイン距離'設定を使用して、高倍率スコープのゼロイン距離を上書きします。 기존 고성능 조준경의 영점거리에 'defaultZeroRange'를 덮어씌웁니다 Używa 'defaultZeroRange' zamiast ustawionej odległości zerowania dla celowników o duzym przybliżeniu Utilise le paramètre "Distance de zérotage par défaut" pour remplacer la distance de zérotage des lunettes de visée à fort grossissement. @@ -155,7 +155,7 @@ High powered scopes will be zeroed at this distance Zielfernrohre werden auf diese Entfernung genullt - 高倍率スコープのゼロイン距離はこの設定になります + 高倍率スコープのゼロイン位置はこの設定になります 고성능 조준경이 정해진 수만큼 영점거리를 맞추게 됩니다. Celowniki o dużym powiększeniu będą zerowane dla tej odległości Distance de zérotage des lunettes de visée à fort grossissement. @@ -308,7 +308,7 @@ Visualizza Alzo e Deriva con numeri firmati 使用帶著標籤的數字顯示歸零遠近與風偏程度 使用带着标签的数字显示归零远近与风偏程度 - 印付きの数字で仰角と横風を表示 + ウィンデージとエレベーションを符号付き数字で表示します 기존의 부호가 있는 숫자로 표고와 폭을 표시합니다. Wyświetla elewację i tarcie powietrza poprzez podpisane liczby Отображает горизонтальные и вертикальные поправки с подписанными числами @@ -320,7 +320,7 @@ Simplified zeroing Vereinfachte Nullung - 簡略なゼロイン + 簡素化ゼロイン Azzeramento semplificato 단순화된 영점 조정 簡單歸零 @@ -335,7 +335,7 @@ Replicates the vanilla zeroing system for riflescopes. Repliziert das Vanilla-Zeroing-System für Zielfernrohre. - バニラ(ゲーム標準)のライフルスコープ用ゼロイン調整システムを複製します。 + バニラ(ゲーム標準)のライフルスコープ用ゼロイン調整システムを再現します。 Replica il sistema di azzeramento vanilla per le ottiche. 라이플 스코프용 바닐라 영점조정 시스템을 복제합니다. 使用原版的歸零系統來取代ACE複雜的歸零模擬。 @@ -486,7 +486,7 @@ Állítások nullázása Zerar ajuste Vynulovat korekci - ゼロインを調節 + ゼロイン調節をセット 영점 초기화 设定归零 設定歸零 @@ -509,7 +509,7 @@ This module adds windage and elevation adjustment turrets on high power rifle scopes. Dieses Modul fügt Absehenverstellung (horizontal und vertikal) zu Zielfernrohren hinzu. - このモジュールは高倍率ライフル スコープにおいて横風と仰角の調節ができます。 + このモジュールは高倍率ライフル スコープにおいてウィンデージとエレベーションの調節ができます。 이 모듈은 고성능 조준경에 조준 나사를 이용한 편차 및 고도 조절 기능을 더해줍니다. Ten moduł włącza pokrętła kalibracyjne poprawki na wiatr oraz poprawki wysokości dla celowników o dużym powiększeniu. Ce module ajoute les tourelles de correction de hausse et de dérive sur les lunettes de visée à fort grossissement. diff --git a/addons/switchunits/stringtable.xml b/addons/switchunits/stringtable.xml index c772b40867..11e54342aa 100644 --- a/addons/switchunits/stringtable.xml +++ b/addons/switchunits/stringtable.xml @@ -92,7 +92,7 @@ Átváltás BLUFOR-ra? На синих? Cambia per BLUFOR? - 同盟軍へ切り替える? + BLUFOR軍へ切り替える? 切换至蓝方? 切換至藍方? 청군으로 변경합니까? @@ -109,7 +109,7 @@ Nyugat-fakciós egységekre való váltás engedélyezése? Разрешить переключаться на синих юнитов? Consenti passaggio ad unità BLUFOR? - 同盟軍ユニットへの切り替えを許可しますか? + BLUFOR軍ユニットへの切り替えを許可しますか? 允许切换至蓝方? 允許切換至藍方? 청군 인원으로 변경하는 것을 허락합니까? @@ -158,7 +158,7 @@ Átváltás INDFOR-ra? На независимых? Cambia per INDFOR? - 独立軍へ切り替える? + INDEPENDENT軍へ切り替える? 切换至独立方? 切換至獨立方? 무소속군으로 전환합니까? @@ -175,7 +175,7 @@ Független egységekre való váltás engedélyezése? Разрешить переключаться на независимых юнитов? Consenti passaggio ad unità INDFOR? - 独立軍ユニットへの切り替えを許可しますか? + INDEPENDENT軍ユニットへの切り替えを許可しますか? 允许切换至独立方? 允許切換至獨立方? 무소속군 인원으로 변경하는 것을 허락합니까? diff --git a/addons/ui/stringtable.xml b/addons/ui/stringtable.xml index 562abe2765..2578f58c6d 100644 --- a/addons/ui/stringtable.xml +++ b/addons/ui/stringtable.xml @@ -645,7 +645,7 @@ A modificação da interface do usuário está desabilitada. La personnalisation de l'Interface Utilisateur est désactivée. Изменение пользовательского интерфейса запрещено. - ユーザ インターフェースの変更は無効化されています。 + ユーザ インタフェースの変更は無効化されています。 Modyfikacja interfejsu użytkownika jest wyłączona. Die Modifizierung des UI ist deaktiviert. 사용자 인터페이스 변경이 비활성화 되어 있습니다. @@ -659,7 +659,7 @@ Não é possível modificar um elemento forçado da interface do usuário. Impossible de modifier un élément forcé de l'Interface Utilisateur. Невозможно изменить зафиксированный элемент пользовательского интерфейса. - ユーザ インターフェース要素の強制はできません。 + ユーザ インタフェース要素の強制はできません。 Nie można modyfikować wymuszonego elementu interfejsu użytkownika. Gesperrte UI-Elemente können nicht modifiziert werden. 강제 사용자 인터페이스는 변경하실 수 없습니다. diff --git a/addons/vehiclelock/stringtable.xml b/addons/vehiclelock/stringtable.xml index 7cfa58d07a..b247967fe1 100644 --- a/addons/vehiclelock/stringtable.xml +++ b/addons/vehiclelock/stringtable.xml @@ -79,7 +79,7 @@ Взламываем замок... Scassinando il veicolo... Usando Mixa... - 鍵をこじ開けている・・・ + 鍵をこじ開けています・・・ 문따는 중... 正在开锁... 解鎖中... @@ -144,7 +144,7 @@ Ключ для открытия большинства машин Красных. Una chiave che apre la maggior parte dei veicoli occidentali Uma chave que abre a maioria dos veículos ocidentais - このキーは多くの同盟軍車両を開けられます。 + このキーは多くのBLUFOR軍車両を開けられます。 거의 모든 청군 진영 차량을 여는 열쇠입니다. 一组解锁钥匙(可解锁大部份蓝方载具) 一組解鎖鑰匙 (可解鎖大部份藍方載具) @@ -176,7 +176,7 @@ Ключ для открытия большинства машин Независимых. Una chiave che apre la maggior parte dei veicoli degli indipendenti. Uma chave que abre a maioria dos veículos independentes - このキーは多くの独立軍車両を開けられます。 + このキーは多くのINDEPENDENT軍車両を開けられます。 거의 모든 무소속군 진영 차량을 여는 열쇠입니다. 一组解锁钥匙(可解锁大部份独立方载具) 一組解鎖鑰匙 (可解鎖大部份獨立方載具) diff --git a/addons/weather/stringtable.xml b/addons/weather/stringtable.xml index bb815b8d06..ece79abe4a 100644 --- a/addons/weather/stringtable.xml +++ b/addons/weather/stringtable.xml @@ -142,7 +142,7 @@ Simulazione del Vento (basato sulla mappa) 風力模擬(基於地圖) 风力模拟(基于地图) - 風シミュレーション (マップを基に) + 風シミュレーション (マップに基づく) 바람 시뮬레이션 (지도 기반) Symulacja Wiatru (bazowana na mapie) Симуляция ветра (на основе местности) @@ -158,7 +158,7 @@ Abilita la simulazione del vento basato sulla mappa (sovrascrive il vento vanilla) 啟用後將遵照地圖特色進行風力模擬(覆蓋掉官方原版的風力模擬) 启用后将遵照地图特色进行风力模拟(覆盖掉官方原版的风力模拟) - マップを基にした風シミュレーションを有効化 (ゲーム標準の風を上書き) + マップに基づいた風シミュレーションを有効化 (ゲーム標準の風を上書き) 지도 기반의 바람 시뮬레이션을 활성화합니다. (바닐라 바람을 덮어 씀) Aktywuje symulację wiatru bazującą na mapie (nadpisuje wind z domyślnej wersji gry) Включает симуляцию ветра на основе текущей местности (переписывает ванильный ветер) diff --git a/addons/zeus/stringtable.xml b/addons/zeus/stringtable.xml index 28a73213ca..a6eaaac158 100644 --- a/addons/zeus/stringtable.xml +++ b/addons/zeus/stringtable.xml @@ -61,7 +61,7 @@ Felemelkedési üzenetek Сообщения о вознесении Messaggi di Ascesa - 転生の布告 + Zeus転生通知 재림 메세지 宙斯上任信息 宙斯上任訊息 @@ -2011,7 +2011,7 @@ Forces the spectator interface preventing the player from closing it with the Escape key - 観戦インターフェイスを強制し、ユーザーがEscキーでも閉じられないようにします。 + 観戦インターフェイスを強制し、ユーザがEscキーでも閉じられないようにします。 Активирует интерфейс spectator, не позволяя игроку закрыть его с помощью клавиши Escape. 플레이어가 Esc 키로 관전자 인터페이스를 닫지 못하도록 강제로 관전자 인터페이스를 설정합니다. Erzwingt die Zuschauer-Ansicht und verhindert dass der Spieler sie mit der Esc-Taste schließen kann From ec5b84c27813cf586fc88eb6e47118be7dc21a7f Mon Sep 17 00:00:00 2001 From: V1nsyara Date: Mon, 15 Jul 2024 05:46:14 +0300 Subject: [PATCH 138/290] Translation - Small update Russian (#10115) * Translation - Update Russian for new features * Up to date translate RU * Small update medical treatment * resolve problem * i`m cry i hate this conflict --- addons/common/stringtable.xml | 4 ++-- addons/medical_blood/stringtable.xml | 4 ++-- addons/medical_damage/stringtable.xml | 2 +- addons/medical_gui/stringtable.xml | 10 ++++----- addons/medical_treatment/stringtable.xml | 28 ++++++++++++------------ addons/repair/stringtable.xml | 2 +- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/addons/common/stringtable.xml b/addons/common/stringtable.xml index 4b015fe9d4..8c59d06516 100644 --- a/addons/common/stringtable.xml +++ b/addons/common/stringtable.xml @@ -1896,7 +1896,7 @@ Verwacklungsfaktor, wenn aufgelegt Fattore di Oscillazione Appoggiato 静止依託時の手ぶれ係数 - Коэффициент колебания прицела в состоянии покоя + Коэф. колебания прицела в состоянии покоя Factor de oscilación apoyado @@ -1918,7 +1918,7 @@ Verwacklungsfaktor, wenn Zweibein aufgestellt ist. Fattore di Oscillazione su Bipode 接地展開時の手ぶれ係数 - Коэффициент колебания прицела при развертывании + Коэф. колебания прицела при развертывании Factor de oscilación desplegado diff --git a/addons/medical_blood/stringtable.xml b/addons/medical_blood/stringtable.xml index a63de99ea0..3167b38ef2 100644 --- a/addons/medical_blood/stringtable.xml +++ b/addons/medical_blood/stringtable.xml @@ -27,7 +27,7 @@ Abilita Chiazze di Sangue 开启血液滴落效果 開啟血液滴落效果 - Разрешить капли крови + Вкл. капли крови Permitir gotas de sangue Povolit kapky krve Habilitar manchas de sangre @@ -37,7 +37,7 @@ Enables the creation of blood drops when units are bleeding or take damage. ユニットが出血や負傷した時に、血痕を残すようにします。 Si une unité saigne, elle laissera des traces de sang derrière elle. - Разрешает создание капель крови при кровотечении или получении урона + Включает создание капель крови при кровотечении или получении урона Permitir a criação de gotas de sangue quando as unidades recebem ferimentos ou estão sangrando. 当单位失血或受伤的时,启用出血效果。 啟用出血效果當單位失血或受傷的時候。 diff --git a/addons/medical_damage/stringtable.xml b/addons/medical_damage/stringtable.xml index 3f274dd37a..fa4e1c4ae4 100644 --- a/addons/medical_damage/stringtable.xml +++ b/addons/medical_damage/stringtable.xml @@ -36,7 +36,7 @@ AI Critical Damage Threshold AIのクリティカルダメージしきい値 Seuil de dégât critique de l'IA - Порог критического урона AI + Порог критического урона ИИ Limite de Dano Crítico da IA AI重擊承受量 AI 临界伤害阈值 diff --git a/addons/medical_gui/stringtable.xml b/addons/medical_gui/stringtable.xml index a03bc0bad8..3f816aa39b 100644 --- a/addons/medical_gui/stringtable.xml +++ b/addons/medical_gui/stringtable.xml @@ -21,7 +21,7 @@ Enable Medical Actions Aktiviere Sanitätsaktionen 医療インタラクションの有効化 - Разрешить Медицинские действия + Вкл. медицинские действия Activer les actions médicales Ativar Ações Médicas 啟用醫療行為 @@ -119,7 +119,7 @@ Enable Medical Menu Aktiviere das Sanitätsmenü 医療メニューを有効化 - Разрешить Медицинское меню + Вкл. медицинское меню Activer le menu médical Ativar Menu Médico 啟用醫療選單 @@ -151,7 +151,7 @@ Reopen Medical Menu Sanitätsmenü wieder öffnen 医療メニューの再表示 - Открывать меню после лечения + Медицинское меню после лечения Rouvrir le menu médical Reabrir Menu Médico 醫療選單二度開啟 @@ -167,7 +167,7 @@ Reopen the Medical Menu after successful treatment. Öffne das Sanitätsmenü nach einer Behandlung 治療の完了後に、再度医療メニューを開きます。 - Открывает Медицинское меню после успешного лечения + Открывает медицинское меню после успешного лечения Réouvre le menu médical suite à l'application d'un soin. Reabrir Menu Médico após um tratamento com sucesso 當治療完成後二度打開醫療選單 @@ -217,7 +217,7 @@ Mostra livello di Triage nel Menù d'Interazione インタラクションにトリアージ レベルを表示 Mostrar nivel de triado en menú de interacción - Показать уровень триажа в меню взаимодействия + Уровень триажа в меню взаимодействия Pokaż poziom Triażu w menu interakcji Zeige Triage-Einstufung im Interaktionsmenü 在交互式菜单中显示分诊级别 diff --git a/addons/medical_treatment/stringtable.xml b/addons/medical_treatment/stringtable.xml index 930562434f..383048626a 100644 --- a/addons/medical_treatment/stringtable.xml +++ b/addons/medical_treatment/stringtable.xml @@ -373,7 +373,7 @@ Tempo di inserimento EV 点滴の所要時間 Tiempo de tratamiento de bolsa de IV - Время применения пакета внутривенного переливания + Время внутривенного переливания Czas aplikacji IV 静脉输液袋治疗时间 수액용기 사용 시간 @@ -469,7 +469,7 @@ Permetti Epinefrina Povolit epinefrin Permitir Epinefrina - Разрешить Адреналин + Доступ к Адреналину アドレナリンの許可 에피네프린 사용 허가 允许使用肾上腺素 @@ -526,7 +526,7 @@ Allow PAK - Использование Аптечки + Доступ к Аптечке Ograniczenia użycia apteczek osobistych Permitir EPA Erlaube Erste-Hilfe-Set @@ -688,7 +688,7 @@ Allow Surgical Kit 手術キットを許可 Trousse chirurgicale autorisée pour - Разрешить Хирургический набор + Доступ к Хирургическому набору Permitir Kit Cirúrgico 允許使用手術包 允许使用手术包 @@ -772,7 +772,7 @@ Co powinno zostać zużyte po zastosowaniu. 봉합키트를 1회성 소모품으로 설정할 지 여부를 결정합니다. Ce qui doit être consommé après l'utilisation. - Решите, следует ли использовать набор для наложения швов в качестве одноразового расходного материала. + Контролирует, следует ли израсходовать Хирургический набор или нить после использования Self Stitching @@ -863,7 +863,7 @@ Housse mortuaire - Autoriser patients inconscients 無意識者の遺体袋への収容許可 Permitir bolsa para cuerpos inconsciente - Разрешить упаковывать пациентов без сознания в мешки для трупов + Упаковка без сознания в мешки для трупов Nieprzytomni w worku na ciało Erlaube Benutzung des Leichensackes mit bewusstlosen Personen Permetti di insaccare un paziente svenuto @@ -891,7 +891,7 @@ Permitir cavar tumbas Autoriser le creusement de tombes 墓掘りを許可 - Разрешить рытье могил + Рытье могил Enables digging graves to dispose of corpses. @@ -924,7 +924,7 @@ 무덤 마커 생성 Créer des pierres tombales 墓標を作成 - Создайте надгробные знаки + Надгробные знаки Enables the creation of grave markers when digging graves. @@ -947,7 +947,7 @@ 允许静脉输液 IV 輸液の制限 Povolit IV transfuzi - Разрешить внутривенное переливание + Доступ к внутривенному переливанию Permitir transfusión de IV 수액용기 사용 허가 @@ -970,7 +970,7 @@ IV輸液の可能な場所 Ubicación para transfusiones IV Lieux perfusions IV - Места введения пакетов внутривенного переливания + Места внутривенного переливания Miejsca do transfuzji IV Orte an denen IV-Transfusionen angelegt werden können Luoghi Fleboclisi EV @@ -982,7 +982,7 @@ IV 輸液を行える場所を制御します。 Controla dónde pueden ser realizadas las transfusiones IV. Définit les lieux où la pose de perfusions est autorisée. - Определяет к каким частям тела разрешено применять пакеты внутренного переливания. + Контролирует, где можно использовать внутревенное переливание. Kontroluje w jakich miejscach można robić transfuzje IV. Kontrolliert, wo IV-Transfusionen durchgeführt werden können. Luoghi in cui è possibile applicare Fleboclisi Endovenose. @@ -4989,7 +4989,7 @@ Coefficient d'efficacité des bandages Coefficiente di efficacia bendaggi 包帯有効性係数 - Коэффициент эффективности повязки + Коэф. эффективности повязки Coeficiente de Efectividad de Vendado @@ -5023,7 +5023,7 @@ Zeit-Koeffizient für Zeus Behandlungen Zeus治療時間係数 제우스 치료 시간 계수 - Коэффициент времени обработки Zeus + Коэф. времени обработки Zeus Coeff. de temps Coeficiente de Tiempo del Tratamiento de Zeus @@ -5056,7 +5056,7 @@ Administer Painkillers Somministra Antidolorifici - Испол-ть обезболивающие + Ввести обезболивающие 鎮痛剤を投与 진통제 투여 Administrer des analgésiques diff --git a/addons/repair/stringtable.xml b/addons/repair/stringtable.xml index 850f9dee7f..6f16e91e09 100644 --- a/addons/repair/stringtable.xml +++ b/addons/repair/stringtable.xml @@ -280,7 +280,7 @@ Coefficiente di riparazione completa 전체 수리 시간 계수 Coefficient du temps de réparation complète - Коэффициент времени полного ремонта + Коэф. времени полного ремонта Coeficiente de Tiempo de Reparación Completa From 66c31928ab5c4da457767232e02b026358940ba2 Mon Sep 17 00:00:00 2001 From: Dart <59131299+DartRuffian@users.noreply.github.com> Date: Wed, 17 Jul 2024 01:12:01 -0500 Subject: [PATCH 139/290] General - Fix case in event handler commands (#10121) --- addons/frag/functions/fnc_doSpall.sqf | 2 +- addons/frag/functions/fnc_pfhRound.sqf | 2 +- addons/frag/functions/fnc_spallTrack.sqf | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/frag/functions/fnc_doSpall.sqf b/addons/frag/functions/fnc_doSpall.sqf index 8b5a06d812..b206c701b2 100644 --- a/addons/frag/functions/fnc_doSpall.sqf +++ b/addons/frag/functions/fnc_doSpall.sqf @@ -25,7 +25,7 @@ private _hpData = (_hitData select 1) select _hitPartDataIndex; private _objectHit = _hpData param [0, objNull]; TRACE_1("",_objectHit); if ((isNil "_objectHit") || {isNull _objectHit}) exitWith {WARNING_1("Problem with hitPart data - bad object [%1]",_objectHit);}; -_objectHit removeEventHandler ["hitPart", _hpId]; +_objectHit removeEventHandler ["HitPart", _hpId]; private _caliber = getNumber (configFile >> "CfgAmmo" >> _roundType >> "caliber"); private _explosive = getNumber (configFile >> "CfgAmmo" >> _roundType >> "explosive"); diff --git a/addons/frag/functions/fnc_pfhRound.sqf b/addons/frag/functions/fnc_pfhRound.sqf index ce734a08e3..0c261dcffb 100644 --- a/addons/frag/functions/fnc_pfhRound.sqf +++ b/addons/frag/functions/fnc_pfhRound.sqf @@ -41,7 +41,7 @@ if (!alive _round) exitWith { TRACE_1("doSpall",_foundObjectHPIds); { if (!isNil "_x") then { - _x removeEventHandler ["hitPart", _foundObjectHPIds select _forEachIndex]; + _x removeEventHandler ["HitPart", _foundObjectHPIds select _forEachIndex]; }; } forEach _spallTrack; }; diff --git a/addons/frag/functions/fnc_spallTrack.sqf b/addons/frag/functions/fnc_spallTrack.sqf index 43dae8afcb..50ca64b6ec 100644 --- a/addons/frag/functions/fnc_spallTrack.sqf +++ b/addons/frag/functions/fnc_spallTrack.sqf @@ -31,7 +31,7 @@ if (_intersectsWith isEqualTo []) exitWith {}; { // diag_log text format ["Adding HP: %1", _x]; private _index = count GVAR(spallHPData); - private _hpId = _x addEventHandler ["hitPart", compile format ["[%1, _this] call " + QFUNC(spallHP), _index]]; + private _hpId = _x addEventHandler ["HitPart", compile format ["[%1, _this] call " + QFUNC(spallHP), _index]]; _foundObjects pushBack _x; _foundObjectHPIds pushBack _hpId; private _data = [_hpId, _x, typeOf _round, _round, _curPos, _velocity, 0, _foundObjects, _foundObjectHPIds]; From f4272f0e3613d1c3963acc535d47fca5835e6eed Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 17 Jul 2024 10:42:37 +0200 Subject: [PATCH 140/290] Spectator - Remove spectator lights when exiting spectator (#10114) Remove spectator lights when exiting spectator --- addons/spectator/functions/fnc_cam.sqf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/spectator/functions/fnc_cam.sqf b/addons/spectator/functions/fnc_cam.sqf index d63a3c24a8..a9f8e97522 100644 --- a/addons/spectator/functions/fnc_cam.sqf +++ b/addons/spectator/functions/fnc_cam.sqf @@ -132,6 +132,9 @@ if (_init) then { GVAR(camDummy) = nil; // Stop tracking everything + { deleteVehicle _x; } forEach GVAR(camLights); + GVAR(camLights) = nil; + GVAR(camMode) = nil; GVAR(camVision) = nil; GVAR(camFocus) = nil; @@ -144,6 +147,5 @@ if (_init) then { GVAR(camYaw) = nil; GVAR(camPitch) = nil; GVAR(camSlow) = nil; - GVAR(camLights) = nil; GVAR(camLight) = nil; }; From 8f84df77d0bccc0404b2158c8123b60ab2283742 Mon Sep 17 00:00:00 2001 From: Dart <59131299+DartRuffian@users.noreply.github.com> Date: Thu, 18 Jul 2024 16:53:34 -0500 Subject: [PATCH 141/290] Sitting - Add config overwrite for random animation pool (#10120) * Add config property animation overwrite * Update addons/sitting/functions/fnc_getRandomAnimation.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * Fix header * Update addons/sitting/functions/fnc_getRandomAnimation.sqf * Update function call --------- Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- .../functions/fnc_getRandomAnimation.sqf | 66 +++++++++++-------- addons/sitting/functions/fnc_sit.sqf | 2 +- docs/wiki/framework/sitting-framework.md | 1 + 3 files changed, 41 insertions(+), 28 deletions(-) diff --git a/addons/sitting/functions/fnc_getRandomAnimation.sqf b/addons/sitting/functions/fnc_getRandomAnimation.sqf index ac8bd9e68d..b0aa2ba270 100644 --- a/addons/sitting/functions/fnc_getRandomAnimation.sqf +++ b/addons/sitting/functions/fnc_getRandomAnimation.sqf @@ -4,7 +4,7 @@ * Gets a random animations from the list. * * Arguments: - * None + * 0: Object to get animation pool from (default: objNull) * * Return Value: * Random Animation @@ -15,30 +15,42 @@ * Public: No */ +params [["_object", objNull, [objNull]]]; + +private _animations = []; + +if (!isNull _object) then { + _animations = getArray (configOf _object >> QGVAR(animations)); +}; + +if (_animations isEqualTo []) then { + _animations = [ + QGVAR(HubSittingChairA_idle1), + QGVAR(HubSittingChairA_idle2), + QGVAR(HubSittingChairA_idle3), + QGVAR(HubSittingChairA_move1), + QGVAR(HubSittingChairB_idle1), + QGVAR(HubSittingChairB_idle2), + QGVAR(HubSittingChairB_idle3), + QGVAR(HubSittingChairB_move1), + QGVAR(HubSittingChairC_idle1), + QGVAR(HubSittingChairC_idle2), + QGVAR(HubSittingChairC_idle3), + QGVAR(HubSittingChairC_move1), + QGVAR(HubSittingChairUA_idle1), + QGVAR(HubSittingChairUA_idle2), + QGVAR(HubSittingChairUA_idle3), + QGVAR(HubSittingChairUA_move1), + QGVAR(HubSittingChairUB_idle1), + QGVAR(HubSittingChairUB_idle2), + QGVAR(HubSittingChairUB_idle3), + QGVAR(HubSittingChairUB_move1), + QGVAR(HubSittingChairUC_idle1), + QGVAR(HubSittingChairUC_idle2), + QGVAR(HubSittingChairUC_idle3), + QGVAR(HubSittingChairUC_move1) + ]; +}; + // Select random animation from Animations Pool -selectRandom [ - QGVAR(HubSittingChairA_idle1), - QGVAR(HubSittingChairA_idle2), - QGVAR(HubSittingChairA_idle3), - QGVAR(HubSittingChairA_move1), - QGVAR(HubSittingChairB_idle1), - QGVAR(HubSittingChairB_idle2), - QGVAR(HubSittingChairB_idle3), - QGVAR(HubSittingChairB_move1), - QGVAR(HubSittingChairC_idle1), - QGVAR(HubSittingChairC_idle2), - QGVAR(HubSittingChairC_idle3), - QGVAR(HubSittingChairC_move1), - QGVAR(HubSittingChairUA_idle1), - QGVAR(HubSittingChairUA_idle2), - QGVAR(HubSittingChairUA_idle3), - QGVAR(HubSittingChairUA_move1), - QGVAR(HubSittingChairUB_idle1), - QGVAR(HubSittingChairUB_idle2), - QGVAR(HubSittingChairUB_idle3), - QGVAR(HubSittingChairUB_move1), - QGVAR(HubSittingChairUC_idle1), - QGVAR(HubSittingChairUC_idle2), - QGVAR(HubSittingChairUC_idle3), - QGVAR(HubSittingChairUC_move1) -] +selectRandom _animations diff --git a/addons/sitting/functions/fnc_sit.sqf b/addons/sitting/functions/fnc_sit.sqf index 70e028719b..033a1f4d2c 100644 --- a/addons/sitting/functions/fnc_sit.sqf +++ b/addons/sitting/functions/fnc_sit.sqf @@ -48,7 +48,7 @@ if (_multiSitting) then { }; // Get random animation and perform it (before moving player to ensure correct placement) -[_player, call FUNC(getRandomAnimation), 2] call EFUNC(common,doAnimation); // Correctly places when using non-transitional animations +[_player, [_seat] call FUNC(getRandomAnimation), 2] call EFUNC(common,doAnimation); // Correctly places when using non-transitional animations [_player, "", 1] call EFUNC(common,doAnimation); // Correctly applies animation's config values (such as disallow throwing of grenades, intercept keybinds... etc). TRACE_2("Sit pos and dir",_sitPosition,_sitDirection); diff --git a/docs/wiki/framework/sitting-framework.md b/docs/wiki/framework/sitting-framework.md index 09f59a9df4..b8f8ff37b0 100644 --- a/docs/wiki/framework/sitting-framework.md +++ b/docs/wiki/framework/sitting-framework.md @@ -29,6 +29,7 @@ class CfgVehicles { acex_sitting_sitDirection = 180; // Direction relative to object acex_sitting_sitPosition[] = {0, -0.1, -0.45}; // Position relative to object (may behave weird with certain objects) acex_sitting_interactPosition[] = {0, -0.1, -0.45}; + ace_sitting_animations[] = {"ace_sitting_HubSittingChairA_idle1"}; // Overwrite random animation pool XEH_ENABLED; // Enable XEH (only necessary if XEH is not yet enabled for this class or the one this inherits from) }; }; From 2c3396a4e87bcf0dd0a49ab3ee114fc0fdbeaec3 Mon Sep 17 00:00:00 2001 From: OverlordZorn <56258612+OverlordZorn@users.noreply.github.com> Date: Fri, 19 Jul 2024 14:36:37 +0200 Subject: [PATCH 142/290] Documentation - Add `ACE_suture` entry to list of classnames (#10125) Update class-names.md --- docs/wiki/class-names.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/wiki/class-names.md b/docs/wiki/class-names.md index d8537f0645..4a4f9b032f 100644 --- a/docs/wiki/class-names.md +++ b/docs/wiki/class-names.md @@ -240,6 +240,7 @@ ACE_plasmaIV_250 | Plasma IV (250ml) | ACE_ItemCore | ACE_salineIV | Saline IV (1000ml) | ACE_ItemCore | ACE_salineIV_500 | Saline IV (500ml) | ACE_ItemCore | ACE_salineIV_250 | Saline IV (250ml) | ACE_ItemCore | +ACE_suture | Suture | ACE_ItemCore | ACE_surgicalKit | Surgical Kit | ACE_ItemCore | ACE_tourniquet | Tourniquet (CAT) | ACE_ItemCore | ACE_medicalSupplyCrate | Simple ACE Medical Supply Crate | ammo box | From 37d7c4c544fde849ff0c5533a2ee8df388d4febb Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Fri, 19 Jul 2024 18:26:14 +0200 Subject: [PATCH 143/290] Interaction - Hide push interaction if target is in ViV cargo (#10127) Hide push interaction for ViV cargo --- addons/interaction/functions/fnc_canPush.sqf | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/interaction/functions/fnc_canPush.sqf b/addons/interaction/functions/fnc_canPush.sqf index 28197d12cd..ff339d5952 100644 --- a/addons/interaction/functions/fnc_canPush.sqf +++ b/addons/interaction/functions/fnc_canPush.sqf @@ -10,7 +10,7 @@ * Can Push * * Example: - * [target] call ace_interaction_fnc_canPush + * cursorObject call ace_interaction_fnc_canPush * * Public: No */ @@ -19,4 +19,5 @@ params ["_target"]; alive _target && {getMass _target <= 2600 || getNumber (configOf _target >> QGVAR(canPush)) == 1} && -{vectorMagnitude velocity _target < 3} +{vectorMagnitude velocity _target < 3} && +{isNull isVehicleCargo _target} // Check if vehicle is loaded as ViV cargo From 68738316c291feed25905e999afb3ae5a5d01179 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Fri, 19 Jul 2024 19:13:44 +0200 Subject: [PATCH 144/290] Dragging - Remove weight calculation workaround (#10117) * loadAbs has been fixed * Update fnc_getWeight.sqf --- addons/dragging/functions/fnc_getWeight.sqf | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/addons/dragging/functions/fnc_getWeight.sqf b/addons/dragging/functions/fnc_getWeight.sqf index f6b93feca0..f6cb466165 100644 --- a/addons/dragging/functions/fnc_getWeight.sqf +++ b/addons/dragging/functions/fnc_getWeight.sqf @@ -11,7 +11,7 @@ * Weight * * Example: - * [cursorTarget] call ace_dragging_fnc_getWeight + * cursorTarget call ace_dragging_fnc_getWeight * * Public: No */ @@ -23,19 +23,20 @@ if (GVAR(weightCoefficient) == 0) exitWith {0}; private _weight = loadAbs _object; -if !(GVAR(skipContainerWeight)) then { +if (!GVAR(skipContainerWeight)) then { // Add the mass of the object itself // getMass handles PhysX mass, this should be 0 for SupplyX containers and WeaponHolders // Use originalMass in case we're checking weight for a carried object - _weight = _weight + ((_object getVariable [QGVAR(originalMass), getMass _object])); + _weight = _weight + (_object getVariable [QGVAR(originalMass), getMass _object]); }; -// Contents of backpacks get counted twice (https://github.com/acemod/ACE3/pull/8457#issuecomment-1062522447 and https://feedback.bistudio.com/T167469) -// This is a workaround until that is fixed on BI's end -{ - _x params ["", "_container"]; - _weight = _weight - (loadAbs _container); -} forEach (everyContainer _object); +// Fixed in https://feedback.bistudio.com/T167469 on 2.16 profiling branch and for 2.18 stable +if ((productVersion select 3) < 152017) then { + { + _x params ["", "_container"]; + _weight = _weight - (loadAbs _container); + } forEach (everyContainer _object); +}; // Mass in Arma isn't an exact amount but rather a volume/weight value // This attempts to work around that by making it a usable value (sort of) From 5cada7d3971ce1327ee5191207fed65ae24038a6 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 20 Jul 2024 08:13:42 +0200 Subject: [PATCH 145/290] General - Remove "SwitchWeapon" spam (#10113) * Remove "switchWeapon" spam * Update fnc_startDragLocal.sqf * Don't add invalid fire modes * Tweaks & fix --- .../common/functions/fnc_getWeaponModes.sqf | 29 ++-- .../functions/fnc_dropObject_carry.sqf | 9 +- .../functions/fnc_startCarryLocal.sqf | 9 +- .../dragging/functions/fnc_startDragLocal.sqf | 5 +- .../fnc_handlePlayerVehicleChanged.sqf | 137 +++++++++--------- addons/rearm/script_component.hpp | 4 +- addons/repair/functions/fnc_repair.sqf | 9 +- .../repair/functions/fnc_repair_failure.sqf | 6 +- .../repair/functions/fnc_repair_success.sqf | 6 +- addons/respawn/functions/fnc_handleKilled.sqf | 2 +- addons/respawn/functions/fnc_restoreGear.sqf | 33 +---- .../functions/fnc_playChangeFiremodeSound.sqf | 2 + .../functions/fnc_selectWeaponMode.sqf | 30 ++-- .../functions/fnc_selectWeaponMuzzle.sqf | 30 ++-- 14 files changed, 145 insertions(+), 166 deletions(-) diff --git a/addons/common/functions/fnc_getWeaponModes.sqf b/addons/common/functions/fnc_getWeaponModes.sqf index c1ca241cab..42a29681f2 100644 --- a/addons/common/functions/fnc_getWeaponModes.sqf +++ b/addons/common/functions/fnc_getWeaponModes.sqf @@ -1,34 +1,45 @@ #include "..\script_component.hpp" /* - * Author: commy2 + * Author: commy2, johnb43 * Get the available firing modes of a weapon. Will ignore the AI helper modes. * * Arguments: * 0: Weapon + * 1: Muzzle (default: weapon) * * Return Value: * Firing Modes * * Example: - * ["gun"] call ace_common_fnc_getWeaponModes + * "arifle_AK12_F" call ace_common_fnc_getWeaponModes * * Public: Yes */ -params [["_weapon", "", [""]]]; +params [["_weapon", "", [""]], ["_muzzle", nil, [""]]]; private _config = configFile >> "CfgWeapons" >> _weapon; +if (!isNil "_muzzle") then { + _config = _config >> _muzzle +}; + +if (!isClass _config) exitWith { + [] // return +}; + private _modes = []; { if (getNumber (_config >> _x >> "showToPlayer") == 1) then { - _modes pushBack _x; - }; - - if (_x == "this") then { - _modes pushBack _weapon; + if (_x == "this") then { + _modes pushBack (configName _config); + } else { + if (isClass (_config >> _x)) then { + _modes pushBack (configName (_config >> _x)); + }; + }; }; } forEach getArray (_config >> "modes"); -_modes +_modes // return diff --git a/addons/dragging/functions/fnc_dropObject_carry.sqf b/addons/dragging/functions/fnc_dropObject_carry.sqf index ff6324e0f3..32e8adcbe6 100644 --- a/addons/dragging/functions/fnc_dropObject_carry.sqf +++ b/addons/dragging/functions/fnc_dropObject_carry.sqf @@ -59,11 +59,12 @@ if (_target isKindOf "CAManBase" || {animationState _unit in CARRY_ANIMATIONS}) _unit removeWeapon "ACE_FakePrimaryWeapon"; // Reselect weapon and re-enable sprint -private _previousWeaponIndex = _unit getVariable [QGVAR(previousWeapon), -1]; -_unit setVariable [QGVAR(previousWeapon), nil, true]; +private _previousWeaponState = _unit getVariable QGVAR(previousWeapon); -if (_previousWeaponIndex != -1) then { - _unit action ["SwitchWeapon", _unit, _unit, _previousWeaponIndex]; +if (!isNil "_previousWeaponState") then { + _unit selectWeapon _previousWeaponState; + + _unit setVariable [QGVAR(previousWeapon), nil, true]; }; [_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); diff --git a/addons/dragging/functions/fnc_startCarryLocal.sqf b/addons/dragging/functions/fnc_startCarryLocal.sqf index 6ba2c68934..743a56e1f4 100644 --- a/addons/dragging/functions/fnc_startCarryLocal.sqf +++ b/addons/dragging/functions/fnc_startCarryLocal.sqf @@ -50,7 +50,7 @@ if (_target isKindOf "CAManBase") then { }; // Select primary, otherwise the carry animation actions don't work - _unit selectWeapon _primaryWeapon; + _unit selectWeapon _primaryWeapon; // This turns off lasers/lights // Move a bit closer and adjust direction when trying to pick up a person [QEGVAR(common,setDir), [_target, getDir _unit + 180], _target] call CBA_fnc_targetEvent; @@ -62,10 +62,11 @@ if (_target isKindOf "CAManBase") then { _timer = CBA_missionTime + 10; } else { // Select no weapon and stop sprinting - private _previousWeaponIndex = [_unit] call EFUNC(common,getFiremodeIndex); - _unit setVariable [QGVAR(previousWeapon), _previousWeaponIndex, true]; + if (currentWeapon _unit != "") then { + _unit setVariable [QGVAR(previousWeapon), (weaponState _unit) select [0, 3], true]; - _unit action ["SwitchWeapon", _unit, _unit, 299]; + _unit action ["SwitchWeapon", _unit, _unit, 299]; + }; [_unit, "AmovPercMstpSnonWnonDnon", 0] call EFUNC(common,doAnimation); diff --git a/addons/dragging/functions/fnc_startDragLocal.sqf b/addons/dragging/functions/fnc_startDragLocal.sqf index 22c7cecd24..de41d712a4 100644 --- a/addons/dragging/functions/fnc_startDragLocal.sqf +++ b/addons/dragging/functions/fnc_startDragLocal.sqf @@ -46,7 +46,10 @@ if (!GVAR(dragAndFire)) then { _primaryWeapon = "ACE_FakePrimaryWeapon"; }; - _unit selectWeapon _primaryWeapon; + // Keep the laser/light on if the weapon is already selected + if (currentWeapon _unit != _primaryWeapon) then { + _unit selectWeapon _primaryWeapon; + }; } else { // Making sure the unit is holding a primary weapon or handgun private _handgunWeapon = handgunWeapon _unit; diff --git a/addons/mk6mortar/functions/fnc_handlePlayerVehicleChanged.sqf b/addons/mk6mortar/functions/fnc_handlePlayerVehicleChanged.sqf index d721b0e4ae..c3dcc2cfe4 100644 --- a/addons/mk6mortar/functions/fnc_handlePlayerVehicleChanged.sqf +++ b/addons/mk6mortar/functions/fnc_handlePlayerVehicleChanged.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: PabstMirror - * Handles player getting into new vehicle. Loads PFEG for mortar display if it is a mortar. + * Handles player getting into new vehicle. Loads PFEG for mortar display if it is a mortar. * * Arguments: * 0: Player @@ -11,7 +11,7 @@ * None * * Example: - * [bob, mortar] call ace_mk6mortar_fnc_handlePlayerVehicleChanged; + * [player, cursorObject] call ace_mk6mortar_fnc_handlePlayerVehicleChanged * * Public: No */ @@ -24,83 +24,78 @@ if !(_newVehicle isKindOf "Mortar_01_base_F") exitWith {}; private _tubeWeaponName = (weapons _newVehicle) select 0; private _fireModes = getArray (configFile >> "CfgWeapons" >> _tubeWeaponName >> "modes"); -//Restore last firemode: -private _lastFireMode = _newVehicle getVariable [QGVAR(lastFireMode), -1]; -if (_lastFireMode != -1) then { - _player action ["SwitchWeapon", _newVehicle, _player, _lastFireMode]; +// Restore last firemode +private _lastSavedWeaponsInfo = _newVehicle getVariable QGVAR(lastFireMode); + +if (!isNil "_lastSavedWeaponsInfo") then { + _newVehicle selectWeaponTurret [_lastSavedWeaponsInfo select 0, [0], _lastSavedWeaponsInfo select 1, _lastSavedWeaponsInfo select 2]; }; [{ - params ["_args", "_pfID"]; - _args params ["_mortarVeh", "_fireModes"]; + params ["_mortarVeh", "_pfhID"]; - if ((vehicle ACE_player) != _mortarVeh) then { - [_pfID] call CBA_fnc_removePerFrameHandler; + if ((vehicle ACE_player) != _mortarVeh) exitWith { + _pfhID call CBA_fnc_removePerFrameHandler; + }; + + // Save firemode ('charge' from weaponstate) on vehicle + _mortarVeh setVariable [QGVAR(lastFireMode), (weaponState [_mortarVeh, [0]]) select [0, 3]]; + + if (shownArtilleryComputer && {!GVAR(allowComputerRangefinder)}) then { + // Don't like this solution, but it works + closeDialog 0; + [parseText "Computer Disabled"] call EFUNC(common,displayTextStructured); + }; + + private _display = uiNamespace getVariable ["ACE_Mk6_RscWeaponRangeArtillery", displayNull]; + + if (isNull _display) exitWith {}; // It may be null for the first frame + + // Hud should hidden in 3rd person + private _notGunnerView = cameraView != "GUNNER"; + private _useMils = _mortarVeh getVariable [QGVAR(useMils), true]; + + // Get aiming values from ace_artillerytables + // Note: it also handles displaying the "charge" level + private _realAzimuth = missionNamespace getVariable [QEGVAR(artillerytables,predictedAzimuth), -1]; + private _realElevation = missionNamespace getVariable [QEGVAR(artillerytables,predictedElevation), -1]; + + // Update Heading Display + if (_notGunnerView || !GVAR(allowCompass)) then { + (_display displayCtrl 80156) ctrlSetText ""; } else { - - private _useMils = _mortarVeh getVariable [QGVAR(useMils), true]; - - //Compute: 'charge' from weaponstate - private _currentFireMode = (weaponState [_mortarVeh, [0]]) select 2; - private _currentChargeMode = _fireModes find _currentFireMode; - - //Save firemode on vehicle: - _mortarVeh setVariable [QGVAR(lastFireMode), _currentChargeMode]; - - if (shownArtilleryComputer && {!GVAR(allowComputerRangefinder)}) then { - //Don't like this solution, but it works - closeDialog 0; - [parseText "Computer Disabled"] call EFUNC(common,displayTextStructured); - }; - - private _display = uiNamespace getVariable ["ACE_Mk6_RscWeaponRangeArtillery", displayNull]; - if (isNull _display) exitWith {}; //It may be null for the first frame - - //Hud should hidden in 3rd person - private _notGunnerView = cameraView != "GUNNER"; - - // Get aiming values from ace_artillerytables - // Note: it also handles displaying the "charge" level - private _realAzimuth = missionNamespace getVariable [QEGVAR(artillerytables,predictedAzimuth), -1]; - private _realElevation = missionNamespace getVariable [QEGVAR(artillerytables,predictedElevation), -1]; - - //Update Heading Display: - if (_notGunnerView || (!GVAR(allowCompass))) then { - (_display displayCtrl 80156) ctrlSetText ""; + if (_useMils) then { + (_display displayCtrl 80156) ctrlSetText str (((round (_realAzimuth * 6400 / 360)) + 6400) % 6400); } else { + (_display displayCtrl 80156) ctrlSetText str ((round (_realAzimuth + 360)) % 360); + }; + }; + + // Update CurrentElevation Display + if (_notGunnerView) then { + (_display displayCtrl 80175) ctrlSetText ""; + } else { + if (_useMils) then { + (_display displayCtrl 80175) ctrlSetText str ((round (_realElevation * 6400 / 360)) % 6400); + } else { + (_display displayCtrl 80175) ctrlSetText str (((round (_realElevation * 100)) / 100) % 360); + }; + }; + + // Update ElevationNeeded Display + if (_notGunnerView || !GVAR(allowComputerRangefinder)) then { + (_display displayCtrl 80176) ctrlSetText ""; + } else { + private _elevDeg = parseNumber ctrlText (_display displayCtrl 176); + if (_elevDeg <= 0) then { // Bad data means "----" out of range + (_display displayCtrl 80176) ctrlSetText (ctrlText (_display displayCtrl 176)); + } else { + _elevDeg = _elevDeg + (_realElevation - (parseNumber ctrlText (_display displayCtrl 175))); if (_useMils) then { - (_display displayCtrl 80156) ctrlSetText str (((round (_realAzimuth * 6400 / 360)) + 6400) % 6400); + (_display displayCtrl 80176) ctrlSetText str round ((round (_elevDeg * 6400 / 360)) % 6400); } else { - (_display displayCtrl 80156) ctrlSetText str ((round (_realAzimuth + 360)) % 360); - }; - }; - - //Update CurrentElevation Display - if (_notGunnerView) then { - (_display displayCtrl 80175) ctrlSetText ""; - } else { - if (_useMils) then { - (_display displayCtrl 80175) ctrlSetText str ((round (_realElevation * 6400 / 360)) % 6400); - } else { - (_display displayCtrl 80175) ctrlSetText str (((round (_realElevation * 100)) / 100) % 360); - }; - }; - - //Update ElevationNeeded Display: - if (_notGunnerView || (!GVAR(allowComputerRangefinder))) then { - (_display displayCtrl 80176) ctrlSetText ""; - } else { - private _elevDeg = parseNumber ctrlText (_display displayCtrl 176); - if (_elevDeg <= 0) then { //Bad data means "----" out of range - (_display displayCtrl 80176) ctrlSetText (ctrlText (_display displayCtrl 176)); - } else { - _elevDeg = _elevDeg + (_realElevation - (parseNumber ctrlText (_display displayCtrl 175))); - if (_useMils) then { - (_display displayCtrl 80176) ctrlSetText str round ((round (_elevDeg * 6400 / 360)) % 6400); - } else { - (_display displayCtrl 80176) ctrlSetText str (((round (_elevDeg * 100)) / 100) % 360); - }; + (_display displayCtrl 80176) ctrlSetText str (((round (_elevDeg * 100)) / 100) % 360); }; }; }; -}, 0, [_newVehicle, _fireModes]] call CBA_fnc_addPerFrameHandler; +}, 0, _newVehicle] call CBA_fnc_addPerFrameHandler; diff --git a/addons/rearm/script_component.hpp b/addons/rearm/script_component.hpp index 83d495bc38..1cc6379ff7 100644 --- a/addons/rearm/script_component.hpp +++ b/addons/rearm/script_component.hpp @@ -28,7 +28,9 @@ #define REARM_HOLSTER_WEAPON \ - _unit setVariable [QGVAR(selectedWeaponOnRearm), currentWeapon _unit]; \ + if (currentWeapon _unit != "") then { \ + _unit setVariable [QGVAR(selectedWeaponOnRearm), (weaponState _unit) select [0, 3]]; \ + }; \ TRACE_2("REARM_HOLSTER_WEAPON",_unit,currentWeapon _unit); \ _unit action ["SwitchWeapon", _unit, _unit, 299]; diff --git a/addons/repair/functions/fnc_repair.sqf b/addons/repair/functions/fnc_repair.sqf index 526b2d506b..ccb2e42dfd 100644 --- a/addons/repair/functions/fnc_repair.sqf +++ b/addons/repair/functions/fnc_repair.sqf @@ -149,10 +149,15 @@ 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]; + +private _currentWeapon = currentWeapon _caller; + +if (_currentWeapon != "") then { + _caller setVariable [QGVAR(selectedWeaponOnrepair), (weaponState _caller) select [0, 3]]; +}; // Cannot use secondairy weapon for animation -if (currentWeapon _caller == secondaryWeapon _caller) then { +if (_currentWeapon == secondaryWeapon _caller) then { _caller selectWeapon (primaryWeapon _caller); }; diff --git a/addons/repair/functions/fnc_repair_failure.sqf b/addons/repair/functions/fnc_repair_failure.sqf index f9de2a8ae6..37b2c50447 100644 --- a/addons/repair/functions/fnc_repair_failure.sqf +++ b/addons/repair/functions/fnc_repair_failure.sqf @@ -38,9 +38,11 @@ if (vehicle _caller == _caller && {!(_caller call EFUNC(common,isSwimming))}) th _caller setVariable [QGVAR(repairCurrentAnimCaller), nil]; _caller setVariable [QGVAR(repairPrevAnimCaller), nil]; -private _weaponSelect = (_caller getVariable [QGVAR(selectedWeaponOnrepair), ""]); -if (_weaponSelect != "") then { +private _weaponSelect = _caller getVariable QGVAR(selectedWeaponOnrepair); + +if (!isNil "_weaponSelect") then { _caller selectWeapon _weaponSelect; + _caller setVariable [QGVAR(selectedWeaponOnrepair), nil]; } else { _caller action ["SwitchWeapon", _caller, _caller, 299]; }; diff --git a/addons/repair/functions/fnc_repair_success.sqf b/addons/repair/functions/fnc_repair_success.sqf index 6248082779..9da2b0c403 100644 --- a/addons/repair/functions/fnc_repair_success.sqf +++ b/addons/repair/functions/fnc_repair_success.sqf @@ -38,9 +38,11 @@ if (vehicle _caller == _caller && {!(_caller call EFUNC(common,isSwimming))}) th _caller setVariable [QGVAR(repairCurrentAnimCaller), nil]; _caller setVariable [QGVAR(repairPrevAnimCaller), nil]; -private _weaponSelect = (_caller getVariable [QGVAR(selectedWeaponOnrepair), ""]); -if (_weaponSelect != "") then { +private _weaponSelect = _caller getVariable QGVAR(selectedWeaponOnrepair); + +if (!isNil "_weaponSelect") then { _caller selectWeapon _weaponSelect; + _caller setVariable [QGVAR(selectedWeaponOnrepair), nil]; } else { _caller action ["SwitchWeapon", _caller, _caller, 299]; }; diff --git a/addons/respawn/functions/fnc_handleKilled.sqf b/addons/respawn/functions/fnc_handleKilled.sqf index 1383561f2c..eeca8f96e5 100644 --- a/addons/respawn/functions/fnc_handleKilled.sqf +++ b/addons/respawn/functions/fnc_handleKilled.sqf @@ -21,7 +21,7 @@ params ["_unit"]; // Saves the gear when the player! (and only him) is killed if (ACE_player == _unit && {GVAR(SavePreDeathGear)}) then { _unit setVariable [QGVAR(unitGear), [_unit] call CBA_fnc_getLoadout]; - _unit setVariable [QGVAR(activeWeaponAndMuzzle), [currentWeapon _unit, currentMuzzle _unit, currentWeaponMode _unit]]; + _unit setVariable [QGVAR(activeWeaponAndMuzzle), (weaponState _unit) select [0, 3]]; [QGVAR(saveGear), _unit] call CBA_fnc_localEvent; }; diff --git a/addons/respawn/functions/fnc_restoreGear.sqf b/addons/respawn/functions/fnc_restoreGear.sqf index afbc7def86..34c5918383 100644 --- a/addons/respawn/functions/fnc_restoreGear.sqf +++ b/addons/respawn/functions/fnc_restoreGear.sqf @@ -5,7 +5,8 @@ * * Arguments: * 0: Unit - * 1: All Gear based on return value of ACE_common_fnc_getAllGear + * 1: All Gear based on return value of ace_common_fnc_getAllGear + * 2: All weapon info needed for restoring previous weapon status * * Return Value: * None @@ -19,36 +20,12 @@ params ["_unit", "_allGear", "_activeWeaponAndMuzzle"]; TRACE_3("restoreGear",_unit,count _allGear,_activeWeaponAndMuzzle); -// restore all gear +// Restore all gear if (!isNil "_allGear") then { [_unit, _allGear] call CBA_fnc_setLoadout; }; -// restore the last active weapon, muzzle and weaponMode +// Restore the last active weapon, muzzle and weapon mode if (!isNil "_activeWeaponAndMuzzle") then { - // @todo, replace this with CBA_fnc_selectWeapon after next CBA update - _activeWeaponAndMuzzle params ["_activeWeapon", "_activeMuzzle", "_activeWeaponMode"]; - - if ( - (_activeMuzzle != "") && - {_activeMuzzle != _activeWeapon} && - {_activeMuzzle in getArray (configFile >> "CfgWeapons" >> _activeWeapon >> "muzzles")} - ) then { - _unit selectWeapon _activeMuzzle; - } else { - if (_activeWeapon != "") then { - _unit selectWeapon _activeWeapon; - }; - }; - - if (currentWeapon _unit != "") then { - private _index = 0; - - while { - _index < 299 && {currentWeaponMode _unit != _activeWeaponMode} - } do { - _unit action ["SwitchWeapon", _unit, _unit, _index]; - _index = _index + 1; - }; - }; + _unit selectWeapon _activeWeaponAndMuzzle; }; diff --git a/addons/weaponselect/functions/fnc_playChangeFiremodeSound.sqf b/addons/weaponselect/functions/fnc_playChangeFiremodeSound.sqf index fc55b54b5f..641787a394 100644 --- a/addons/weaponselect/functions/fnc_playChangeFiremodeSound.sqf +++ b/addons/weaponselect/functions/fnc_playChangeFiremodeSound.sqf @@ -35,3 +35,5 @@ if !(toLowerANSI (_filename select [count _filename - 4]) in [".wav", ".ogg", ". }; playSound3D [_filename, objNull, false, _position, _volume, _soundPitch, _distance]; + +nil // return diff --git a/addons/weaponselect/functions/fnc_selectWeaponMode.sqf b/addons/weaponselect/functions/fnc_selectWeaponMode.sqf index f2810bb512..fd22bd4462 100644 --- a/addons/weaponselect/functions/fnc_selectWeaponMode.sqf +++ b/addons/weaponselect/functions/fnc_selectWeaponMode.sqf @@ -18,35 +18,23 @@ params ["_unit", "_weapon"]; -if (_weapon == "") exitWith {}; +if (_weapon == "" || {!(_unit hasWeapon _weapon)}) exitWith {}; + +private _currentWeaponMode = (_unit weaponState _weapon) select 2; +private _muzzle = (_weapon call EFUNC(common,getWeaponMuzzles)) select 0; if (currentWeapon _unit != _weapon) exitWith { - _unit selectWeapon _weapon; + _unit selectWeapon [_weapon, _muzzle, _currentWeaponMode]; }; -// unlock safety +// Unlock safety if (_weapon in (_unit getVariable [QEGVAR(safemode,safedWeapons), []])) exitWith { [_unit, _weapon, _weapon] call EFUNC(safemode,unlockSafety); }; -private _muzzles = [_weapon] call EFUNC(common,getWeaponMuzzles); -private _modes = [_weapon] call EFUNC(common,getWeaponModes); +private _modes = _weapon call EFUNC(common,getWeaponModes); -private _index = (_modes find currentWeaponMode _unit) + 1; +_unit selectWeapon [_weapon, _muzzle, _modes select (((_modes find _currentWeaponMode) + 1) % (count _modes))]; -if (_index > count _modes - 1) then {_index = 0}; - -private _muzzle = _muzzles select 0; -private _mode = _modes select _index; - -_index = 0; - -while { - _index < 299 && {currentMuzzle _unit != _muzzle || {currentWeaponMode _unit != _mode}} -} do { - _unit action ["SwitchWeapon", _unit, _unit, _index]; - _index = _index + 1; -}; - -// play fire mode selector sound +// Play fire mode selector sound [_unit, _weapon] call FUNC(playChangeFiremodeSound); diff --git a/addons/weaponselect/functions/fnc_selectWeaponMuzzle.sqf b/addons/weaponselect/functions/fnc_selectWeaponMuzzle.sqf index 9a27a515ad..3882253573 100644 --- a/addons/weaponselect/functions/fnc_selectWeaponMuzzle.sqf +++ b/addons/weaponselect/functions/fnc_selectWeaponMuzzle.sqf @@ -18,32 +18,22 @@ params ["_unit", "_weapon"]; -if (_weapon == "") exitWith {}; +if (_weapon == "" || {!(_unit hasWeapon _weapon)}) exitWith {}; private _muzzles = _weapon call EFUNC(common,getWeaponMuzzles); -if (currentWeapon _unit != _weapon) exitWith { - if (count _muzzles > 1) then { +if (count _muzzles <= 1) exitWith {}; - // unlock safety - /*if (_weapon in (_unit getVariable [QEGVAR(safemode,safedWeapons), []])) exitWith { - [_unit, _weapon, _muzzles select 1] call EFUNC(safemode,unlockSafety); - };*/ +private _muzzle = (_unit weaponState _weapon) select 1; - _unit selectWeapon (_muzzles select 1); - }; +private _index = if (currentWeapon _unit == _weapon) then { + (((_muzzles find currentMuzzle _unit) + 1) % (count _muzzles)) max 1 +} else { + 1 }; -private _index = (_muzzles find currentMuzzle _unit) + 1; - -if (_index > count _muzzles - 1) then {_index = 1}; - private _muzzle = _muzzles select _index; -_index = 0; -while { - _index < 299 && {currentMuzzle _unit != _muzzle} -} do { - _unit action ["SwitchWeapon", _unit, _unit, _index]; - _index = _index + 1; -}; +_unit selectWeapon [_weapon, _muzzle, ([_weapon, _muzzle] call EFUNC(common,getWeaponModes)) select 0]; + +nil // return From 8ab36f64ffa5e07cf8f636a4402db8526f8c597e Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 20 Jul 2024 08:15:15 +0200 Subject: [PATCH 146/290] Quickmount - Fix quickmount for vehicle interactions (#10126) * Fix quickmount for vehicle interactions * Update addons/quickmount/functions/fnc_getInNearest.sqf --- addons/quickmount/XEH_postInitClient.sqf | 5 +- .../quickmount/functions/fnc_getInNearest.sqf | 174 +++++++++--------- 2 files changed, 86 insertions(+), 93 deletions(-) diff --git a/addons/quickmount/XEH_postInitClient.sqf b/addons/quickmount/XEH_postInitClient.sqf index 23c225f583..6dbd38742b 100644 --- a/addons/quickmount/XEH_postInitClient.sqf +++ b/addons/quickmount/XEH_postInitClient.sqf @@ -2,9 +2,8 @@ if (!hasInterface) exitWith {}; -["ACE3 Movement", QGVAR(mount), [localize LSTRING(KeybindName), localize LSTRING(KeybindDescription)], "", { +["ACE3 Movement", QGVAR(mount), [LLSTRING(KeybindName), LLSTRING(KeybindDescription)], "", { if (!dialog) then { - [] call FUNC(getInNearest); + call FUNC(getInNearest); }; - false }] call CBA_fnc_addKeybind; diff --git a/addons/quickmount/functions/fnc_getInNearest.sqf b/addons/quickmount/functions/fnc_getInNearest.sqf index 5e6c21eb36..52bc8cd220 100644 --- a/addons/quickmount/functions/fnc_getInNearest.sqf +++ b/addons/quickmount/functions/fnc_getInNearest.sqf @@ -1,131 +1,125 @@ #include "..\script_component.hpp" /* * Author: Kingsley - * Mount the player in the vehicle they are directly looking at based on their distance. + * Mounts the player in the vehicle they are directly looking at based on their distance. * * Arguments: - * 0: Target (Optional) + * 0: Target (default: objNull) * * Return Value: * None * * Example: - * [] call ace_quickmount_fnc_getInNearest; + * call ace_quickmount_fnc_getInNearest * * Public: No */ -if (!GVAR(enabled) || +if ( + !GVAR(enabled) || {isNull ACE_player} || - {vehicle ACE_player != ACE_player} || - {!alive ACE_player} || - {ACE_player getVariable ["ace_unconscious", false]} + {!isNull objectParent ACE_player} || + {!(ACE_player call EFUNC(common,isAwake))} ) exitWith {}; -params [["_interactionTarget", objNull, [objNull]]]; -TRACE_1("getInNearest",_interactionTarget); +params [["_target", objNull, [objNull]]]; +TRACE_1("getInNearest",_target); -private _start = ACE_player modelToWorldVisualWorld (ACE_player selectionPosition "pilot"); -private _end = (_start vectorAdd (getCameraViewDirection ACE_player vectorMultiply GVAR(distance))); -private _objects = lineIntersectsSurfaces [_start, _end, ACE_player]; -private _target = (_objects param [0, []]) param [2, objNull]; - -if ((isNull _target) && {alive _interactionTarget}) then { - _end = _start vectorAdd ((_start vectorFromTo (aimPos _interactionTarget)) vectorMultiply GVAR(distance)); - _objects = lineIntersectsSurfaces [_start, _end, ACE_player]; - TRACE_1("2nd ray attempt at interaction target aim pos",_objects); +// If target is not defined (e.g. keybind was used), search for valid target +if (isNull _target) then { + private _start = ACE_player modelToWorldVisualWorld (ACE_player selectionPosition "pilot"); + private _end = (_start vectorAdd (getCameraViewDirection ACE_player vectorMultiply GVAR(distance))); + private _objects = lineIntersectsSurfaces [_start, _end, ACE_player]; _target = (_objects param [0, []]) param [2, objNull]; }; -if (locked _target in [2,3] || {!simulationEnabled _target}) exitWith { - [localize LSTRING(VehicleLocked)] call EFUNC(common,displayTextStructured); - true +if (!alive _target) exitWith {}; + +if (locked _target >= 2 || {!simulationEnabled _target}) exitWith { + [LLSTRING(VehicleLocked)] call EFUNC(common,displayTextStructured); }; TRACE_2("",_target,typeOf _target); -if (!isNull _target && - {alive _target} && - {{_target isKindOf _x} count ["Air","LandVehicle","Ship","StaticMortar"] > 0} && - {([ACE_player, _target, ["isNotSwimming"]] call EFUNC(common,canInteractWith))} && - {speed _target <= GVAR(speed)} - ) then { +if ( + (speed _target > GVAR(speed)) || + {["Air", "LandVehicle", "Ship", "StaticMortar"] findIf {_target isKindOf _x} == -1} || + {!([ACE_player, _target, ["isNotSwimming"]] call EFUNC(common,canInteractWith))} +) exitWith {}; +private _seats = ["driver", "gunner", "commander", "cargo"]; +private _sortedSeats = [_seats select GVAR(priority)]; +_seats deleteAt GVAR(priority); +_sortedSeats append _seats; - if (GVAR(priority) > 3 || GVAR(priority) < 0) then { - GVAR(priority) = 0; - }; +private _fullCrew = fullCrew [_target, "", true]; - private _seats = ["Driver", "Gunner", "Commander", "Cargo"]; - private _sortedSeats = [_seats select GVAR(priority)]; - _seats deleteAt GVAR(priority); - _sortedSeats append _seats; +private _hasAction = false; +scopeName "SearchForSeat"; +{ + private _desiredRole = _x; - private _hasAction = false; - scopeName "SearchForSeat"; { - private _desiredRole = _x; - { - _x params ["_unit", "_role", "_cargoIndex", "_turretPath"]; - if ((isNull _unit) || {!alive _unit}) then { - private _effectiveRole = toLowerANSI _role; + _x params ["_unit", "_role", "_cargoIndex", "_turretPath"]; - if ((_effectiveRole in ["driver", "gunner"]) && {unitIsUAV _target}) exitWith {}; // Ignoring UAV Driver/Gunner - if ((_effectiveRole == "driver") && {(getNumber (configOf _target >> "hasDriver")) == 0}) exitWith {}; // Ignoring Non Driver (static weapons) + if (!alive _unit) then { + private _effectiveRole = _role; - // Seats can be locked independently of the main vehicle - if ((_role == "driver") && {lockedDriver _target}) exitWith {TRACE_1("lockedDriver",_x);}; - if ((_cargoIndex >= 0) && {_target lockedCargo _cargoIndex}) exitWith {TRACE_1("lockedCargo",_x);}; - if ((_turretPath isNotEqualTo []) && {_target lockedTurret _turretPath}) exitWith {TRACE_1("lockedTurret",_x);}; + if ((_effectiveRole in ["driver", "gunner"]) && {unitIsUAV _target}) exitWith {}; // Ignoring UAV Driver/Gunner + if ((_effectiveRole == "driver") && {(getNumber (configOf _target >> "hasDriver")) == 0}) exitWith {}; // Ignoring Non Driver (static weapons) - if (_effectiveRole == "turret") then { - private _turretConfig = [_target, _turretPath] call CBA_fnc_getTurret; - if (getNumber (_turretConfig >> "isCopilot") == 1) exitWith { - _effectiveRole = "driver"; - }; - if ( - _cargoIndex >= 0 // FFV - || {"" isEqualTo getText (_turretConfig >> "gun")} // turret without weapon - ) exitWith { - _effectiveRole = "cargo"; - }; - _effectiveRole = "gunner"; // door gunners / 2nd turret - }; - TRACE_2("",_effectiveRole,_x); - if (_effectiveRole != _desiredRole) exitWith {}; + // Seats can be locked independently of the main vehicle + if ((_effectiveRole == "driver") && {lockedDriver _target}) exitWith {TRACE_1("lockedDriver",_x);}; + if ((_cargoIndex >= 0) && {_target lockedCargo _cargoIndex}) exitWith {TRACE_1("lockedCargo",_x);}; + if ((_turretPath isNotEqualTo []) && {_target lockedTurret _turretPath}) exitWith {TRACE_1("lockedTurret",_x);}; - if (_turretPath isNotEqualTo []) then { - // Using GetInTurret seems to solve problems with incorrect GetInEH params when gunner/commander - ACE_player action ["GetInTurret", _target, _turretPath]; - TRACE_3("Geting In Turret",_x,_role,_turretPath); - } else { - if (_cargoIndex > -1) then { - // GetInCargo expects the index of the seat in the "cargo" array from fullCrew - // See description: https://community.bistudio.com/wiki/fullCrew - private _cargoActionIndex = -1; - { - if ((_x select 2) == _cargoIndex) exitWith {_cargoActionIndex = _forEachIndex}; - } forEach (fullCrew [_target, "cargo", true]); + if (_effectiveRole == "turret") then { + private _turretConfig = [_target, _turretPath] call CBA_fnc_getTurret; - ACE_player action ["GetInCargo", _target, _cargoActionIndex]; - TRACE_4("Geting In Cargo",_x,_role,_cargoActionIndex,_cargoIndex); - } else { - ACE_player action ["GetIn" + _role, _target]; - TRACE_2("Geting In",_x,_role); - }; + if (getNumber (_turretConfig >> "isCopilot") == 1) exitWith { + _effectiveRole = "driver"; }; - _hasAction = true; - breakTo "SearchForSeat"; + if ( + _cargoIndex >= 0 || // FFV + {getText (_turretConfig >> "gun") == ""} // Turret without weapon + ) exitWith { + _effectiveRole = "cargo"; + }; + + _effectiveRole = "gunner"; // Door gunners / 2nd turret }; - } forEach (fullCrew [_target, "", true]); - } forEach _sortedSeats; - if (!_hasAction) then { - TRACE_1("no empty seats",_hasAction); - [localize LSTRING(VehicleFull)] call EFUNC(common,displayTextStructured); - }; + TRACE_2("",_effectiveRole,_x); + + if (_effectiveRole != _desiredRole) exitWith {}; + + if (_turretPath isNotEqualTo []) then { + // Using GetInTurret seems to solve problems with incorrect GetInEH params when gunner/commander + ACE_player action ["GetInTurret", _target, _turretPath]; + TRACE_3("Getting In Turret",_x,_role,_turretPath); + } else { + if (_cargoIndex > -1) then { + // GetInCargo expects the index of the seat in the "cargo" array from fullCrew + // See description: https://community.bistudio.com/wiki/fullCrew + private _cargoActionIndex = (fullCrew [_target, "cargo", true]) findIf {(_x select 2) == _cargoIndex}; + + ACE_player action ["GetInCargo", _target, _cargoActionIndex]; + TRACE_4("Getting In Cargo",_x,_role,_cargoActionIndex,_cargoIndex); + } else { + ACE_player action ["GetIn" + _role, _target]; + TRACE_2("Getting In",_x,_role); + }; + }; + + _hasAction = true; + breakTo "SearchForSeat"; + }; + } forEach _fullCrew; +} forEach _sortedSeats; + +if (!_hasAction) then { + TRACE_1("no empty seats",_hasAction); + [LLSTRING(VehicleFull)] call EFUNC(common,displayTextStructured); }; - -true From 05ab1bbe99750faafc7dec9b55db9c2cf3e272a3 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 20 Jul 2024 08:26:53 +0200 Subject: [PATCH 147/290] Dragging - Fix dragging/carrying failing for items in ViV (#10128) * Unload ViV before dragging/carrying * Update addons/dragging/functions/fnc_carryObject.sqf Co-authored-by: PabstMirror * Use lazy eval to check if item was unloaded --------- Co-authored-by: PabstMirror --- addons/dragging/functions/fnc_carryObject.sqf | 6 ++++++ addons/dragging/functions/fnc_dragObject.sqf | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/addons/dragging/functions/fnc_carryObject.sqf b/addons/dragging/functions/fnc_carryObject.sqf index 4d5ac8b61b..a6b38c4ea5 100644 --- a/addons/dragging/functions/fnc_carryObject.sqf +++ b/addons/dragging/functions/fnc_carryObject.sqf @@ -19,6 +19,12 @@ params ["_unit", "_target"]; TRACE_2("params",_unit,_target); +// If in ViV cargo, unload it first +// Warn user if it failed to unload (shouldn't happen) +if (!isNull isVehicleCargo _target && {!(objNull setVehicleCargo _target)}) then { + WARNING_1("ViV Unload Failed %1",_target); +}; + // Get attachTo offset and direction private _position = _target getVariable [QGVAR(carryPosition), [0, 0, 0]]; private _direction = _target getVariable [QGVAR(carryDirection), 0]; diff --git a/addons/dragging/functions/fnc_dragObject.sqf b/addons/dragging/functions/fnc_dragObject.sqf index 5116f440b3..6420ff56df 100644 --- a/addons/dragging/functions/fnc_dragObject.sqf +++ b/addons/dragging/functions/fnc_dragObject.sqf @@ -19,6 +19,12 @@ params ["_unit", "_target"]; TRACE_2("params",_unit,_target); +// If in ViV cargo, unload it first +// Warn user if it failed to unload (shouldn't happen) +if (!isNull isVehicleCargo _target && {!(objNull setVehicleCargo _target)}) then { + WARNING_1("ViV Unload Failed %1",_target); +}; + // Get attachTo offset and direction. private _position = _target getVariable [QGVAR(dragPosition), [0, 0, 0]]; private _direction = _target getVariable [QGVAR(dragDirection), 0]; From 5d133bd793444b75eaa7afaff840c16293cb3a15 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 20 Jul 2024 08:29:17 +0200 Subject: [PATCH 148/290] Dogtags - Code cleanup (#10097) * Clean up dogtags * Only allow taking of dogtags if unit has space * Fixed upper case T * Stop throwing error * Reverted to case insensitive method of checking * Remove unused files * More cleanup & fixes - Better check for taking dog tags until 2.18 comes - Changed parent condition from `canTakeDogtag` to `canCheckDogtag` - Register EH only where necessary * Update CfgEventHandlers.hpp * More header cleanup --- addons/dogtags/CfgEventHandlers.hpp | 2 + addons/dogtags/CfgVehicles.hpp | 2 +- addons/dogtags/CfgWeapons.hpp | 4 +- addons/dogtags/XEH_PREP.hpp | 4 +- addons/dogtags/XEH_postInit.sqf | 148 +++++++++--------- .../functions/fnc_addDogtagActions.sqf | 25 +-- .../dogtags/functions/fnc_addDogtagItem.sqf | 38 ----- addons/dogtags/functions/fnc_bloodType.sqf | 6 +- .../dogtags/functions/fnc_canCheckDogtag.sqf | 12 +- .../dogtags/functions/fnc_canTakeDogtag.sqf | 13 +- addons/dogtags/functions/fnc_checkDogtag.sqf | 16 +- .../functions/fnc_disableFactionDogtags.sqf | 2 +- .../dogtags/functions/fnc_getDogtagData.sqf | 19 ++- .../dogtags/functions/fnc_getDogtagItem.sqf | 24 ++- addons/dogtags/functions/fnc_showDogtag.sqf | 10 +- addons/dogtags/functions/fnc_ssn.sqf | 15 +- addons/dogtags/functions/fnc_takeDogtag.sqf | 17 +- 17 files changed, 173 insertions(+), 184 deletions(-) delete mode 100644 addons/dogtags/functions/fnc_addDogtagItem.sqf diff --git a/addons/dogtags/CfgEventHandlers.hpp b/addons/dogtags/CfgEventHandlers.hpp index 2a3f71f852..f6503c2479 100644 --- a/addons/dogtags/CfgEventHandlers.hpp +++ b/addons/dogtags/CfgEventHandlers.hpp @@ -3,11 +3,13 @@ class Extended_PreStart_EventHandlers { init = QUOTE(call COMPILE_SCRIPT(XEH_preStart)); }; }; + class Extended_PreInit_EventHandlers { class ADDON { init = QUOTE(call COMPILE_SCRIPT(XEH_preInit)); }; }; + class Extended_PostInit_EventHandlers { class ADDON { init = QUOTE(call COMPILE_SCRIPT(XEH_postInit)); diff --git a/addons/dogtags/CfgVehicles.hpp b/addons/dogtags/CfgVehicles.hpp index cc56410699..56be52b53e 100644 --- a/addons/dogtags/CfgVehicles.hpp +++ b/addons/dogtags/CfgVehicles.hpp @@ -4,7 +4,7 @@ class CfgVehicles { class ACE_Actions { class ACE_Dogtag { displayName = CSTRING(itemName); - condition = QUOTE([ARR_2(_player,_target)] call FUNC(canTakeDogtag)); + condition = QUOTE([ARR_2(_player,_target)] call FUNC(canCheckDogtag)); statement = ""; exceptions[] = {"isNotSwimming", "isNotInside"}; showDisabled = 0; diff --git a/addons/dogtags/CfgWeapons.hpp b/addons/dogtags/CfgWeapons.hpp index 0f795d8d08..ac73ee68f7 100644 --- a/addons/dogtags/CfgWeapons.hpp +++ b/addons/dogtags/CfgWeapons.hpp @@ -16,8 +16,8 @@ class CfgWeapons { author = ECSTRING(common,ACETeam); scope = 0; displayName = CSTRING(itemName); - model = QUOTE(PATHTOF(data\ace_dogtag.p3d)); - picture = QUOTE(PATHTOF(data\dogtagSingle.paa)); + model = QPATHTOF(data\ace_dogtag.p3d); + picture = QPATHTOF(data\dogtagSingle.paa); class ItemInfo: CBA_MiscItem_ItemInfo { mass = 0; //too small to for 1 ? }; diff --git a/addons/dogtags/XEH_PREP.hpp b/addons/dogtags/XEH_PREP.hpp index a34a04a982..9ff33a26a2 100644 --- a/addons/dogtags/XEH_PREP.hpp +++ b/addons/dogtags/XEH_PREP.hpp @@ -1,13 +1,11 @@ - PREP(addDogtagActions); -PREP(addDogtagItem); PREP(bloodType); PREP(canCheckDogtag); PREP(canTakeDogtag); PREP(checkDogtag); +PREP(disableFactionDogtags); PREP(getDogtagData); PREP(getDogtagItem); PREP(showDogtag); PREP(ssn); PREP(takeDogtag); -PREP(disableFactionDogtags); diff --git a/addons/dogtags/XEH_postInit.sqf b/addons/dogtags/XEH_postInit.sqf index 6e676671ae..3ced843f47 100644 --- a/addons/dogtags/XEH_postInit.sqf +++ b/addons/dogtags/XEH_postInit.sqf @@ -1,9 +1,5 @@ #include "script_component.hpp" -[QGVAR(showDogtag), LINKFUNC(showDogtag)] call CBA_fnc_addEventHandler; -[QGVAR(getDogtagItem), LINKFUNC(getDogtagItem)] call CBA_fnc_addEventHandler; -[QGVAR(addDogtagItem), LINKFUNC(addDogtagItem)] call CBA_fnc_addEventHandler; - if (hasInterface || isServer) then { [QGVAR(broadcastDogtagInfo), { GVAR(dogtagsData) set _this; @@ -18,69 +14,29 @@ if (hasInterface || isServer) then { [QGVAR(broadcastDogtagInfo), [_x, _y], _clientOwner] call CBA_fnc_ownerEvent; } forEach GVAR(dogtagsData); }] call CBA_fnc_addEventHandler; + + [QGVAR(getDogtagItem), LINKFUNC(getDogtagItem)] call CBA_fnc_addEventHandler; } else { // To be here, hasInterface must be true [QGVAR(requestSyncDogtagDataJIP), clientOwner] call CBA_fnc_serverEvent; }; }; -// Add actions and event handlers only if ace_medical is enabled -// - Adding actions via config would create a dependency -["CBA_settingsInitialized", { - if !(GETEGVAR(medical,enabled,false)) exitWith {}; +if (hasInterface) then { + // If the arsenal is loaded, show the custom names for dog tags when in the arsenal + if (["ace_arsenal"] call EFUNC(common,isModLoaded)) then { + [QEGVAR(arsenal,rightPanelFilled), { + params ["_display", "_leftPanelIDC", "_rightPanelIDC"]; - if (hasInterface) then { - private _checkTagAction = [ - "ACE_CheckDogtag", - format ["%1: %2", localize LSTRING(itemName), localize LSTRING(checkDogtag)], - QPATHTOF(data\dogtag_icon_ca.paa), - {[_player,_target] call FUNC(checkDogtag)}, - {!isNil {_target getVariable QGVAR(dogtagData)}} - ] call EFUNC(interact_menu,createAction); + if !(_leftPanelIDC in [2010, 2012, 2014] && {_rightPanelIDC == 38}) exitWith {}; - ["ACE_bodyBagObject", 0, ["ACE_MainActions"], _checkTagAction, true] call EFUNC(interact_menu,addActionToClass); - - private _takeTagAction = [ - "ACE_TakeDogtag", - format ["%1: %2", localize LSTRING(itemName), localize LSTRING(takeDogtag)], - QPATHTOF(data\dogtag_icon_ca.paa), - {[_player,_target] call FUNC(takeDogtag)}, - {(!isNil {_target getVariable QGVAR(dogtagData)}) && {((_target getVariable [QGVAR(dogtagTaken), objNull]) != _target)}} - ] call EFUNC(interact_menu,createAction); - - ["ACE_bodyBagObject", 0, ["ACE_MainActions"], _takeTagAction, true] call EFUNC(interact_menu,addActionToClass); - }; - - if (isServer) then { - ["ace_placedInBodyBag", { - params ["_target", "_bodyBag", "_isGrave"]; - if (_isGrave) exitWith {}; - TRACE_2("ace_placedInBodyBag eh",_target,_bodyBag); - - private _dogTagData = [_target] call FUNC(getDogtagData); - _bodyBag setVariable [QGVAR(dogtagData), _dogTagData, true]; - - if ((_target getVariable [QGVAR(dogtagTaken), objNull]) == _target) then { - _bodyBag setVariable [QGVAR(dogtagTaken), _bodyBag, true]; - }; - }] call CBA_fnc_addEventHandler; - }; -}] call CBA_fnc_addEventHandler; - -// If the arsenal is loaded, show the custom names for dog tags when in the arsenal -if (["ace_arsenal"] call EFUNC(common,isModLoaded)) then { - [QEGVAR(arsenal,rightPanelFilled), { - params ["_display", "_leftPanelIDC", "_rightPanelIDC"]; - - if (_leftPanelIDC in [2010, 2012, 2014] && {_rightPanelIDC == 38}) then { - LOG("passed"); private _rightPanel = _display displayCtrl 15; private _cfgWeapons = configFile >> "CfgWeapons"; - private _item = ""; - private _dogtagData = []; + + TRACE_1("passed",_rightPanel); for "_i" from 0 to (lnbSize _rightPanel select 0) - 1 do { - _item = _rightPanel lnbData [_i, 0]; + private _item = _rightPanel lnbData [_i, 0]; if (_item isKindOf ["ACE_dogtag", _cfgWeapons]) then { private _name = (GVAR(dogtagsData) getOrDefault [_item, []]) param [0, ""]; @@ -93,27 +49,71 @@ if (["ace_arsenal"] call EFUNC(common,isModLoaded)) then { _rightPanel lnbSetText [[_i, 1], [LLSTRING(itemName), ": ", _name] joinString ""]; }; }; - }; - }] call CBA_fnc_addEventHandler; + }] call CBA_fnc_addEventHandler; + }; + + // Add context menu option + [ + "ACE_dogtag", + ["GROUND", "CARGO", "CONTAINER"], + LLSTRING(checkItem), + nil, + QPATHTOF(data\dogtag_icon_ca.paa), + [ + {true}, + {true} + ], + { + [GVAR(dogtagsData) getOrDefault [_this select 2, []]] call FUNC(showDogtag); + + false + } + ] call CBA_fnc_addItemContextMenuOption; }; -// Add context menu option -[ - "ACE_dogtag", - ["GROUND", "CARGO", "CONTAINER"], - LLSTRING(checkItem), - nil, - QPATHTOF(data\dogtag_icon_ca.paa), - [ - {true}, - {true} - ], - { - [GVAR(dogtagsData) getOrDefault [_this select 2, []]] call FUNC(showDogtag); +// Add actions and event handlers only if ace_medical is enabled +// - Adding actions via config would create a dependency +["CBA_settingsInitialized", { + if !(GETEGVAR(medical,enabled,false)) exitWith {}; - false - } -] call CBA_fnc_addItemContextMenuOption; + if (hasInterface) then { + private _checkTagAction = [ + "ACE_CheckDogtag", + format ["%1: %2", LLSTRING(itemName), LLSTRING(checkDogtag)], + QPATHTOF(data\dogtag_icon_ca.paa), + {[_player, _target] call FUNC(checkDogtag)}, + {!isNil {_target getVariable QGVAR(dogtagData)}} + ] call EFUNC(interact_menu,createAction); -// Disable dogtags for civilians + ["ACE_bodyBagObject", 0, ["ACE_MainActions"], _checkTagAction, true] call EFUNC(interact_menu,addActionToClass); + + private _takeTagAction = [ + "ACE_TakeDogtag", + format ["%1: %2", LLSTRING(itemName), LLSTRING(takeDogtag)], + QPATHTOF(data\dogtag_icon_ca.paa), + {[_player, _target] call FUNC(takeDogtag)}, + {(!isNil {_target getVariable QGVAR(dogtagData)}) && {((_target getVariable [QGVAR(dogtagTaken), objNull]) != _target)}} + ] call EFUNC(interact_menu,createAction); + + ["ACE_bodyBagObject", 0, ["ACE_MainActions"], _takeTagAction, true] call EFUNC(interact_menu,addActionToClass); + }; + + if (isServer) then { + ["ace_placedInBodyBag", { + params ["_target", "_bodyBag", "_isGrave"]; + + if (_isGrave) exitWith {}; + TRACE_2("ace_placedInBodyBag eh",_target,_bodyBag); + + private _dogtagData = _target call FUNC(getDogtagData); + _bodyBag setVariable [QGVAR(dogtagData), _dogtagData, true]; + + if ((_target getVariable [QGVAR(dogtagTaken), objNull]) == _target) then { + _bodyBag setVariable [QGVAR(dogtagTaken), _bodyBag, true]; + }; + }] call CBA_fnc_addEventHandler; + }; +}] call CBA_fnc_addEventHandler; + +// Disable dog tags for civilians "CIV_F" call FUNC(disableFactionDogtags); diff --git a/addons/dogtags/functions/fnc_addDogtagActions.sqf b/addons/dogtags/functions/fnc_addDogtagActions.sqf index b41cce1be8..9b2f3147b5 100644 --- a/addons/dogtags/functions/fnc_addDogtagActions.sqf +++ b/addons/dogtags/functions/fnc_addDogtagActions.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: SzwedzikPL, mharis001 - * Returns children actions for checking dogtags in player's inventory. + * Returns children actions for checking dog tags in the player's inventory. * * Arguments: * 0: Player @@ -10,7 +10,7 @@ * Actions * * Example: - * [_player] call ace_dogtags_fnc_addDogtagActions + * player call ace_dogtags_fnc_addDogtagActions * * Public: No */ @@ -23,14 +23,21 @@ private _fnc_getActions = { { private _config = _cfgWeapons >> _x; - if (getNumber (_config >> QGVAR(tagID)) > 0) then { - private _displayName = getText (_config >> "displayName"); - private _picture = getText (_config >> "picture"); - private _action = [_x, _displayName, _picture, { - [GVAR(dogtagsData) getOrDefault [_this select 2, []]] call FUNC(showDogtag); - }, {true}, {}, _x] call EFUNC(interact_menu,createAction); - _actions pushBack [_action, [], _player]; + if (getNumber (_config >> QGVAR(tagID)) > 0) then { + _actions pushBack [ + [ + _x, + getText (_config >> "displayName"), + getText (_config >> "picture"), + {[GVAR(dogtagsData) getOrDefault [_this select 2, []]] call FUNC(showDogtag)}, + {true}, + {}, + _x + ] call EFUNC(interact_menu,createAction), + [], + _player + ]; }; } forEach (_player call EFUNC(common,uniqueItems)); diff --git a/addons/dogtags/functions/fnc_addDogtagItem.sqf b/addons/dogtags/functions/fnc_addDogtagItem.sqf deleted file mode 100644 index 6979299db3..0000000000 --- a/addons/dogtags/functions/fnc_addDogtagItem.sqf +++ /dev/null @@ -1,38 +0,0 @@ -#include "..\script_component.hpp" -/* - * Author: SzwedzikPL - * Adds dogtag item to unit (triggered by server). - * - * Arguments: - * 0: Item class - * 1: Dogtag data - * - * Return Value: - * None - * - * Example: - * ["itemClass", ["name", "610-27-5955", "A POS"]] call ace_dogtags_fnc_addDogtagItem - * - * Public: No - */ - -params ["_item", "_dogtagData"]; - -if (_item == "") exitWith {}; - -// Verify that the unit has inventory space, otherwise drop the dogtag on the ground -[ace_player, _item, true] call CBA_fnc_addItem; - -_dogtagData params ["_name"]; - -// If data doesn't exist or body has no name, set name as "unknown" -if (_name == "") then { - _name = LELSTRING(common,unknown); -}; - -private _displayText = format [localize LSTRING(takeDogtagSuccess), _name]; - -// display message -[{ - [_this, 2.5] call EFUNC(common,displayTextStructured); -}, _displayText, DOGTAG_SHOW_DELAY] call CBA_fnc_waitAndExecute; diff --git a/addons/dogtags/functions/fnc_bloodType.sqf b/addons/dogtags/functions/fnc_bloodType.sqf index 5e03c586fa..53b6007370 100644 --- a/addons/dogtags/functions/fnc_bloodType.sqf +++ b/addons/dogtags/functions/fnc_bloodType.sqf @@ -1,16 +1,16 @@ #include "..\script_component.hpp" /* * Author: commy2 - * Reports a blood type depending on the units name. + * Reports a blood type depending on the unit's name. * * Arguments: - * 0: Name of a unit + * 0: Unit name * * Return Value: * A random blood type * * Example: - * _bloodType = ["name"] call ace_dogtags_fnc_bloodType + * "name" call ace_dogtags_fnc_bloodType * * Public: No */ diff --git a/addons/dogtags/functions/fnc_canCheckDogtag.sqf b/addons/dogtags/functions/fnc_canCheckDogtag.sqf index 98d437cbac..a5ed987fc0 100644 --- a/addons/dogtags/functions/fnc_canCheckDogtag.sqf +++ b/addons/dogtags/functions/fnc_canCheckDogtag.sqf @@ -1,26 +1,26 @@ #include "..\script_component.hpp" /* * Author: SzwedzikPL - * Checks if dogtag can be checked. + * Checks if the target's dog tag can be checked by the unit. * * Arguments: - * 0: Player + * 0: Player (not used) * 1: Target * * Return Value: - * True if dogtag can be checked + * If dog tag can be checked * * Example: - * _canCheck = [player, unit] call ace_dogtags_fnc_canCheckDogtag + * [player, cursorObject] call ace_dogtags_fnc_canCheckDogtag * * Public: No */ -params ["_player", "_target"]; +params ["", "_target"]; if (isNull _target) exitWith {false}; -// check if disabled for faction +// Check if disabled for faction if ((faction _target) in GVAR(disabledFactions)) exitWith {false}; !(_target call EFUNC(common,isAwake)) diff --git a/addons/dogtags/functions/fnc_canTakeDogtag.sqf b/addons/dogtags/functions/fnc_canTakeDogtag.sqf index 5f0a6d1afe..c56db0b893 100644 --- a/addons/dogtags/functions/fnc_canTakeDogtag.sqf +++ b/addons/dogtags/functions/fnc_canTakeDogtag.sqf @@ -1,17 +1,17 @@ #include "..\script_component.hpp" /* * Author: SzwedzikPL - * Checks if dogtag can be taken. + * Checks if the target's dog tag can be taken by the unit. * * Arguments: * 0: Player * 1: Target * * Return Value: - * True if dogtag can be taken + * If dog tag can be taken * * Example: - * _canTake = [player, unit] call ace_dogtags_fnc_canTakeDogtag + * [player, cursorObject] call ace_dogtags_fnc_canTakeDogtag * * Public: No */ @@ -20,7 +20,10 @@ params ["_player", "_target"]; if (isNull _target) exitWith {false}; -// check if disabled for faction +// Check if disabled for faction if ((faction _target) in GVAR(disabledFactions)) exitWith {false}; -!(_target call EFUNC(common,isAwake)) && {_player canAdd ["ACE_dogtag_1", 1/*, true*/]} // Todo: Uncomment in 2.18 +// CBA_fnc_canAddItem doesn't account for mass 0 items and unit not having any containers +!(_target call EFUNC(common,isAwake)) && {(uniform _player + vest _player + backpack _player) != ""} && {[_player, "ACE_dogtag_1"] call CBA_fnc_canAddItem} +// Todo: Use code below in 2.18 +// _player canAdd ["ACE_dogtag_1", 1, true] diff --git a/addons/dogtags/functions/fnc_checkDogtag.sqf b/addons/dogtags/functions/fnc_checkDogtag.sqf index dcceb8c2c0..4b2f2d533f 100644 --- a/addons/dogtags/functions/fnc_checkDogtag.sqf +++ b/addons/dogtags/functions/fnc_checkDogtag.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: SzwedzikPL - * Checks unit dogtag. + * Checks the unit's dog tag. * * Arguments: * 0: Player @@ -11,17 +11,17 @@ * None * * Example: - * [player, unit] call ace_dogtags_fnc_checkDogtag + * [player, cursorObject] call ace_dogtags_fnc_checkDogtag * * Public: No */ params ["_player", "_target"]; -// animation +// Animation _player call EFUNC(common,goKneeling); -// sound +// Sound private _position = _target modelToWorldWorld (_target selectionPosition "neck"); playSound3D [ @@ -34,10 +34,8 @@ playSound3D [ 50 ]; -// display dogtag +// Display dog tag private _doubleTags = (_target getVariable [QGVAR(dogtagTaken), objNull]) != _target; -private _dogTagData = [_target] call FUNC(getDogTagData); +private _dogtagData = _target call FUNC(getDogtagData); -[{ - [QGVAR(showDogtag), _this] call CBA_fnc_localEvent; -}, [_dogTagData, _doubleTags], DOGTAG_SHOW_DELAY] call CBA_fnc_waitAndExecute; +[LINKFUNC(showDogtag), [_dogtagData, _doubleTags], DOGTAG_SHOW_DELAY] call CBA_fnc_waitAndExecute; diff --git a/addons/dogtags/functions/fnc_disableFactionDogtags.sqf b/addons/dogtags/functions/fnc_disableFactionDogtags.sqf index c4642ef4b5..b1ac145d9a 100644 --- a/addons/dogtags/functions/fnc_disableFactionDogtags.sqf +++ b/addons/dogtags/functions/fnc_disableFactionDogtags.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: commy2 - * Disable this faction from using dogtags. + * Disables this faction from using dog tags. * * Arguments: * 0: Faction diff --git a/addons/dogtags/functions/fnc_getDogtagData.sqf b/addons/dogtags/functions/fnc_getDogtagData.sqf index 6a850543fc..4aaf930fa2 100644 --- a/addons/dogtags/functions/fnc_getDogtagData.sqf +++ b/addons/dogtags/functions/fnc_getDogtagData.sqf @@ -1,19 +1,19 @@ #include "..\script_component.hpp" /* * Author: esteldunedain - * Get unit dogtag data. + * Gets unit's dog tag data. * * Arguments: * 0: Target * * Return Value: - * Dogtag Data + * Dog tag Data * 0: Name * 1: SSN * 2: Blood Type * * Example: - * _dogtagData = [unit, player] call ace_dogtags_fnc_getDogtagData + * player call ace_dogtags_fnc_getDogtagData * * Public: No */ @@ -21,17 +21,20 @@ params ["_target"]; // Check if the data was already created -private _dogTagData = _target getVariable QGVAR(dogtagData); -if (!isNil "_dogTagData") exitWith {_dogTagData}; +private _dogtagData = _target getVariable QGVAR(dogtagData); + +if (!isNil "_dogtagData") exitWith {_dogtagData}; // Create dog tag data once for the unit: nickname, code (eg. 135-13-900) and blood type private _targetName = [_target, false, true] call EFUNC(common,getName); -private _dogTagData = [ +private _dogtagData = [ _targetName, _targetName call FUNC(ssn), _targetName call FUNC(bloodType) ]; + // Store it -_target setVariable [QGVAR(dogtagData), _dogTagData, true]; -_dogTagData +_target setVariable [QGVAR(dogtagData), _dogtagData, true]; + +_dogtagData diff --git a/addons/dogtags/functions/fnc_getDogtagItem.sqf b/addons/dogtags/functions/fnc_getDogtagItem.sqf index e5f05eb19b..6a01d8c36f 100644 --- a/addons/dogtags/functions/fnc_getDogtagItem.sqf +++ b/addons/dogtags/functions/fnc_getDogtagItem.sqf @@ -1,7 +1,8 @@ #include "..\script_component.hpp" /* * Author: SzwedzikPL - * Server: creates new dogtag item and send it to client. + * Server: Creates a new dog tag item and sends it to client. + * It broacasts the dog tag info to all machines with interfaces. * * Arguments: * 0: Player @@ -11,12 +12,12 @@ * None * * Example: - * [player, unit] call ace_dogtags_fnc_getDogtagItem + * [player, cursorObject] call ace_dogtags_fnc_getDogtagItem * * Public: No */ -if(!isServer) exitWith {}; +if (!isServer) exitWith {}; params ["_player", "_target"]; TRACE_2("getDogtagItem",_player,_target); @@ -28,7 +29,20 @@ if (GVAR(idCounter) > 999) exitWith {ERROR("Ran out of IDs");}; private _dogTagData = [_target] call FUNC(getDogTagData); private _item = format ["ACE_dogtag_%1", GVAR(idCounter)]; -[QGVAR(addDogtagItem), [_item, _dogTagData], [_player]] call CBA_fnc_targetEvent; - // Broadcast data globally, so that clients can use it where needed [QGVAR(broadcastDogtagInfo), [_item, _dogTagData]] call CBA_fnc_globalEvent; + +// Dog tags have no mass, so no need to check if it can fit in container, but check if unit has an inventory at all +[_player, _item, true] call CBA_fnc_addItem; + +_name = _dogtagData param [0, ""]; + +// If data doesn't exist or body has no name, set name as "unknown" +if (_name == "") then { + _name = LELSTRING(common,unknown); +}; + +// Display message +[{ + [QEGVAR(common,displayTextStructured), [_this select 0, 2.5], _this select 1] call CBA_fnc_targetEvent; +}, [format [LLSTRING(takeDogtagSuccess), _name], _player], DOGTAG_SHOW_DELAY] call CBA_fnc_waitAndExecute; diff --git a/addons/dogtags/functions/fnc_showDogtag.sqf b/addons/dogtags/functions/fnc_showDogtag.sqf index 9e01bfc3cd..5de9a9fc62 100644 --- a/addons/dogtags/functions/fnc_showDogtag.sqf +++ b/addons/dogtags/functions/fnc_showDogtag.sqf @@ -1,10 +1,10 @@ #include "..\script_component.hpp" /* * Author: SzwedzikPL - * Shows dogtag. + * Shows dog tag. * * Arguments: - * 0: Dogtag data + * 0: Dog tag data * 1: Display as double tag * * Return Value: @@ -27,8 +27,10 @@ if (_doubleTags) then { } else { (QGVAR(tag) call BIS_fnc_rscLayer) cutRsc [QGVAR(singleTag), "PLAIN", 1, true]; }; -private _display = uiNamespace getvariable [QGVAR(tag), displayNull]; -if(isNull _display) exitWith {}; + +private _display = uiNamespace getVariable [QGVAR(tag), displayNull]; + +if (isNull _display) exitWith {}; private _control = _display displayCtrl 1001; _dogtagData params ["_name", "_code", "_bloodType"]; diff --git a/addons/dogtags/functions/fnc_ssn.sqf b/addons/dogtags/functions/fnc_ssn.sqf index 0ba3499c0b..794422ddd1 100644 --- a/addons/dogtags/functions/fnc_ssn.sqf +++ b/addons/dogtags/functions/fnc_ssn.sqf @@ -1,16 +1,16 @@ #include "..\script_component.hpp" /* * Author: kymckay - * Reports a social security number generated from the units name. + * Reports a social security number generated from the unit's name. * * Arguments: - * 0: Name of a unit + * 0: Unit name * * Return Value: * A random three/two/four format social security number * * Example: - * _ssn = ["AAA"] call ace_dogtags_fnc_ssn + * "name" call ace_dogtags_fnc_ssn * * Public: No */ @@ -18,19 +18,20 @@ params ["_name"]; private _chars = toArray _name; -private _length = count _chars; + // Warning, for strings containing non-latin characters, `_count _name` != `_count _chars` +private _length = count _chars; _chars pushBack _length; _length = _length + 1; private _remainder = 0; -private _nums = [0,0,0,0,0,0,0,0,0]; +private _nums = [0, 0, 0, 0, 0, 0, 0, 0, 0]; for "_index" from 0 to (8 max _length) do { private _inputChar = _chars select (_index % _length); - _nums set [(_index % 9), ((_nums select (_index % 9)) + _inputChar + _remainder) % 10]; + _nums set [_index % 9, ((_nums select (_index % 9)) + _inputChar + _remainder) % 10]; _remainder = (_inputChar + _remainder) % 256; }; -([_nums select [0,3],_nums select [3,2], _nums select [5,4]] apply { _x joinString "" }) joinString "-" +([_nums select [0, 3], _nums select [3, 2], _nums select [5, 4]] apply { _x joinString "" }) joinString "-" diff --git a/addons/dogtags/functions/fnc_takeDogtag.sqf b/addons/dogtags/functions/fnc_takeDogtag.sqf index 1972c91ee0..b374c27121 100644 --- a/addons/dogtags/functions/fnc_takeDogtag.sqf +++ b/addons/dogtags/functions/fnc_takeDogtag.sqf @@ -1,8 +1,8 @@ #include "..\script_component.hpp" /* * Author: SzwedzikPL - * If dogtag is not already taken triggers event on server. - * If dogtag already taken displays info about it. + * If the dog tag hasn't already been taken, it triggers an event on the server. + * If the dog tag has already been taken, it displays info about it. * * Arguments: * 0: Player @@ -12,17 +12,17 @@ * None * * Example: - * [player, unit] call ace_dogtags_fnc_takeDogtag + * [player, cursorObject] call ace_dogtags_fnc_takeDogtag * * Public: No */ params ["_player", "_target"]; -// animation +// Animation _player call EFUNC(common,goKneeling); -// sound +// Sound private _position = _target modelToWorldWorld (_target selectionPosition "neck"); playSound3D [ @@ -35,12 +35,11 @@ playSound3D [ 50 ]; -// display message +// Display message if ((_target getVariable [QGVAR(dogtagTaken), objNull]) == _target) then { - [{ - [_this, 2.5] call EFUNC(common,displayTextStructured); - }, localize LSTRING(dogtagAlreadyTaken), DOGTAG_SHOW_DELAY] call CBA_fnc_waitAndExecute; + [EFUNC(common,displayTextStructured), [LLSTRING(dogtagAlreadyTaken), 2.5], DOGTAG_SHOW_DELAY] call CBA_fnc_waitAndExecute; } else { _target setVariable [QGVAR(dogtagTaken), _target, true]; + [QGVAR(getDogtagItem), [_player, _target]] call CBA_fnc_serverEvent; }; From a7ce63a536a0e77135efbd8adebf98f9ee274aa4 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 20 Jul 2024 08:37:04 +0200 Subject: [PATCH 149/290] Fire - Remove `medical_engine` dependency (#10122) * Remove medical dependency from fire * Update initSettings.inc.sqf --- addons/fire/XEH_postInit.sqf | 32 +++++++++---------- .../ACE_Medical_Treatment_Actions.hpp | 0 addons/fire/compat_medical_engine/config.cpp | 20 ++++++++++++ .../script_component.hpp | 3 ++ addons/fire/config.cpp | 13 +------- addons/fire/functions/fnc_burnSimulation.sqf | 30 ++++++++++------- addons/fire/initSettings.inc.sqf | 2 +- addons/fire/script_component.hpp | 7 ++++ 8 files changed, 67 insertions(+), 40 deletions(-) rename addons/fire/{ => compat_medical_engine}/ACE_Medical_Treatment_Actions.hpp (100%) create mode 100644 addons/fire/compat_medical_engine/config.cpp create mode 100644 addons/fire/compat_medical_engine/script_component.hpp diff --git a/addons/fire/XEH_postInit.sqf b/addons/fire/XEH_postInit.sqf index 641b74fffe..1050d75753 100644 --- a/addons/fire/XEH_postInit.sqf +++ b/addons/fire/XEH_postInit.sqf @@ -1,25 +1,25 @@ #include "script_component.hpp" -[QGVAR(burn), LINKFUNC(burn)] call CBA_fnc_addEventHandler; -[QGVAR(burnEffects), LINKFUNC(burnEffects)] call CBA_fnc_addEventHandler; -[QGVAR(burnSimulation), LINKFUNC(burnSimulation)] call CBA_fnc_addEventHandler; - -[QGVAR(playScream), { - params ["_scream", "_source"]; - - // Only play sound if enabled in settings and enabled for the unit - if (GVAR(enableScreams) && {_source getVariable [QGVAR(enableScreams), true]}) then { - _source say3D _scream; - }; -}] call CBA_fnc_addEventHandler; - -if (!isServer) exitWith {}; - ["CBA_settingsInitialized", { - TRACE_1("settingsInit",GVAR(enabled)); + TRACE_1("settingsInitialized",GVAR(enabled)); if (!GVAR(enabled)) exitWith {}; + [QGVAR(burn), LINKFUNC(burn)] call CBA_fnc_addEventHandler; + [QGVAR(burnEffects), LINKFUNC(burnEffects)] call CBA_fnc_addEventHandler; + [QGVAR(burnSimulation), LINKFUNC(burnSimulation)] call CBA_fnc_addEventHandler; + + [QGVAR(playScream), { + params ["_scream", "_source"]; + + // Only play sound if enabled in settings and enabled for the unit + if (GVAR(enableScreams) && {_source getVariable [QGVAR(enableScreams), true]}) then { + _source say3D _scream; + }; + }] call CBA_fnc_addEventHandler; + + if (!isServer) exitWith {}; + GVAR(fireSources) = createHashMap; [QGVAR(addFireSource), { diff --git a/addons/fire/ACE_Medical_Treatment_Actions.hpp b/addons/fire/compat_medical_engine/ACE_Medical_Treatment_Actions.hpp similarity index 100% rename from addons/fire/ACE_Medical_Treatment_Actions.hpp rename to addons/fire/compat_medical_engine/ACE_Medical_Treatment_Actions.hpp diff --git a/addons/fire/compat_medical_engine/config.cpp b/addons/fire/compat_medical_engine/config.cpp new file mode 100644 index 0000000000..cc4431b18f --- /dev/null +++ b/addons/fire/compat_medical_engine/config.cpp @@ -0,0 +1,20 @@ +#include "script_component.hpp" + +class CfgPatches { + class SUBADDON { + name = COMPONENT_NAME; + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = {"ace_medical_engine"}; + skipWhenMissingDependencies = 1; + author = ECSTRING(common,ACETeam); + authors[] = {}; + url = ECSTRING(main,URL); + VERSION_CONFIG; + + addonRootClass = QUOTE(ADDON); + }; +}; + +#include "ACE_Medical_Treatment_Actions.hpp" diff --git a/addons/fire/compat_medical_engine/script_component.hpp b/addons/fire/compat_medical_engine/script_component.hpp new file mode 100644 index 0000000000..b2ce8adc8d --- /dev/null +++ b/addons/fire/compat_medical_engine/script_component.hpp @@ -0,0 +1,3 @@ +#define SUBCOMPONENT medical_engine +#define SUBCOMPONENT_BEAUTIFIED Medical Engine +#include "..\script_component.hpp" diff --git a/addons/fire/config.cpp b/addons/fire/config.cpp index df2eb5cb79..7a13dd079b 100644 --- a/addons/fire/config.cpp +++ b/addons/fire/config.cpp @@ -1,20 +1,12 @@ #include "script_component.hpp" -#pragma hemtt flag pe23_ignore_has_include -#if __has_include("\z\ace\addons\nomedical\script_component.hpp") -#define PATCH_SKIP "No Medical" -#endif - -#ifdef PATCH_SKIP -ACE_PATCH_NOT_LOADED(ADDON,PATCH_SKIP) -#else class CfgPatches { class ADDON { name = COMPONENT_NAME; units[] = {}; weapons[] = {}; requiredVersion = REQUIRED_VERSION; - requiredAddons[] = {"ace_common", "ace_medical_engine"}; + requiredAddons[] = {"ace_common"}; author = ECSTRING(common,ACETeam); authors[] = {"commy2", "tcvm"}; url = ECSTRING(main,URL); @@ -25,7 +17,4 @@ class CfgPatches { #include "CfgEventHandlers.hpp" #include "CfgSounds.hpp" #include "CfgVehicles.hpp" -#include "ACE_Medical_Treatment_Actions.hpp" #include "RscTitles.hpp" - -#endif diff --git a/addons/fire/functions/fnc_burnSimulation.sqf b/addons/fire/functions/fnc_burnSimulation.sqf index b50afab5dc..ac98de5dda 100644 --- a/addons/fire/functions/fnc_burnSimulation.sqf +++ b/addons/fire/functions/fnc_burnSimulation.sqf @@ -148,19 +148,27 @@ params ["_unit", "_instigator"]; _unit call FUNC(burnReaction); }; - if (!isNull _instigator) then { - _unit setVariable [QEGVAR(medical,lastDamageSource), _instigator]; - _unit setVariable [QEGVAR(medical,lastInstigator), _instigator]; - }; - - // Common burn areas are the hands and face https://www.ncbi.nlm.nih.gov/pubmed/16899341/ - private _bodyPart = ["Head", "Body", "LeftArm", "RightArm", "LeftLeg", "RightLeg"] selectRandomWeighted [0.77, 0.5, 0.8, 0.8, 0.3, 0.3]; - - // Keep pain around unconciousness limit to allow for more fun interactions + // Keep pain around unconsciousness limit to allow for more fun interactions private _damageToAdd = [0.15, _intensity / BURN_MAX_INTENSITY] select (!alive _unit || {GET_PAIN_PERCEIVED(_unit) < (PAIN_UNCONSCIOUS + random 0.2)}); - // Use event directly, as ace_medical_fnc_addDamageToUnit requires unit to be alive - [QEGVAR(medical,woundReceived), [_unit, [[_damageToAdd, _bodyPart, _damageToAdd]], _instigator, "burn"]] call CBA_fnc_localEvent; + if (GETEGVAR(medical,enabled,false)) then { + if (!isNull _instigator) then { + _unit setVariable [QEGVAR(medical,lastDamageSource), _instigator]; + _unit setVariable [QEGVAR(medical,lastInstigator), _instigator]; + }; + + // Common burn areas are the hands and face https://www.ncbi.nlm.nih.gov/pubmed/16899341/ + private _bodyPart = ["Head", "Body", "LeftArm", "RightArm", "LeftLeg", "RightLeg"] selectRandomWeighted [0.77, 0.5, 0.8, 0.8, 0.3, 0.3]; + + // Use event directly, as ace_medical_fnc_addDamageToUnit requires unit to be alive + [QEGVAR(medical,woundReceived), [_unit, [[_damageToAdd, _bodyPart, _damageToAdd]], _instigator, "burn"]] call CBA_fnc_localEvent; + } else { + private _bodyParts = [["HitFace", "HitNeck", "HitHead"], ["HitPelvis", "HitAbdomen", "HitDiaphragm", "HitChest", "HitBody"], ["HitArms", "HitHands"], ["HitLegs"]] selectRandomWeighted [0.77, 0.5, 0.8, 0.3]; + + { + _unit setHitPointDamage [_x, (_unit getHitPointDamage _x) + _damageToAdd, true, _instigator, _instigator]; + } forEach _bodyParts; + }; _unit setVariable [QGVAR(intensity), _intensity, true]; // Globally sync intensity across all clients to make sure simulation is deterministic }; diff --git a/addons/fire/initSettings.inc.sqf b/addons/fire/initSettings.inc.sqf index edcd51a8a7..d9649c2ad9 100644 --- a/addons/fire/initSettings.inc.sqf +++ b/addons/fire/initSettings.inc.sqf @@ -5,7 +5,7 @@ LSTRING(Category_DisplayName), true, 1, - {[QGVAR(fireEnabled), _this] call EFUNC(common,cbaSettings_settingChanged)}, + {[QGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged)}, true // Needs mission restart ] call CBA_fnc_addSetting; diff --git a/addons/fire/script_component.hpp b/addons/fire/script_component.hpp index ebb0002ff6..d79ca0d490 100644 --- a/addons/fire/script_component.hpp +++ b/addons/fire/script_component.hpp @@ -16,7 +16,14 @@ #endif #include "\z\ace\addons\main\script_macros.hpp" + +#pragma hemtt flag pe23_ignore_has_include +#if __has_include("\z\ace\addons\medical_engine\script_macros_medical.hpp") #include "\z\ace\addons\medical_engine\script_macros_medical.hpp" +#else +#define GET_PAIN_PERCEIVED(var) 0 +#define PAIN_UNCONSCIOUS 1 +#endif #define FIRE_MANAGER_PFH_DELAY 0.25 #define FLARE_SIZE_MODIFIER 5 From 4cb358ebf2b476e80be01e8aeb022c12ce2918dc Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 20 Jul 2024 10:26:01 +0200 Subject: [PATCH 150/290] Dogtags - Add missing `private` (#10132) Update fnc_getDogtagItem.sqf --- addons/dogtags/functions/fnc_getDogtagItem.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/dogtags/functions/fnc_getDogtagItem.sqf b/addons/dogtags/functions/fnc_getDogtagItem.sqf index 6a01d8c36f..4f8cc94cc7 100644 --- a/addons/dogtags/functions/fnc_getDogtagItem.sqf +++ b/addons/dogtags/functions/fnc_getDogtagItem.sqf @@ -35,7 +35,7 @@ private _item = format ["ACE_dogtag_%1", GVAR(idCounter)]; // Dog tags have no mass, so no need to check if it can fit in container, but check if unit has an inventory at all [_player, _item, true] call CBA_fnc_addItem; -_name = _dogtagData param [0, ""]; +private _name = _dogtagData param [0, ""]; // If data doesn't exist or body has no name, set name as "unknown" if (_name == "") then { From f6c5425733d7b722915048c66fe35f4fb5dbb659 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 20 Jul 2024 21:10:16 +0200 Subject: [PATCH 151/290] RHS Compats - Add `common` to loadorder (#10133) Add common to RHS compat loadorder --- addons/compat_rhs_afrf3/config.cpp | 2 +- addons/compat_rhs_gref3/config.cpp | 2 +- addons/compat_rhs_saf3/config.cpp | 2 +- addons/compat_rhs_usf3/config.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/compat_rhs_afrf3/config.cpp b/addons/compat_rhs_afrf3/config.cpp index 44fcd30fcb..0b3c990ced 100644 --- a/addons/compat_rhs_afrf3/config.cpp +++ b/addons/compat_rhs_afrf3/config.cpp @@ -7,7 +7,7 @@ class CfgPatches { units[] = {}; weapons[] = {}; requiredVersion = REQUIRED_VERSION; - requiredAddons[] = {"rhs_main_loadorder"}; + requiredAddons[] = {"ace_common", "rhs_main_loadorder"}; author = ECSTRING(common,ACETeam); authors[] = {"Ruthberg", "GitHawk", "BaerMitUmlaut", "commy2", "Skengman2"}; url = ECSTRING(main,URL); diff --git a/addons/compat_rhs_gref3/config.cpp b/addons/compat_rhs_gref3/config.cpp index f2e7aeacde..84717435be 100644 --- a/addons/compat_rhs_gref3/config.cpp +++ b/addons/compat_rhs_gref3/config.cpp @@ -6,7 +6,7 @@ class CfgPatches { units[] = {}; weapons[] = {}; requiredVersion = REQUIRED_VERSION; - requiredAddons[] = {"rhsgref_main_loadorder"}; + requiredAddons[] = {"ace_common", "rhsgref_main_loadorder"}; skipWhenMissingDependencies = 1; author = ECSTRING(common,ACETeam); authors[] = {"PabstMirror", "Ruthberg", "Anton"}; diff --git a/addons/compat_rhs_saf3/config.cpp b/addons/compat_rhs_saf3/config.cpp index 75ee4f5530..71340640ce 100644 --- a/addons/compat_rhs_saf3/config.cpp +++ b/addons/compat_rhs_saf3/config.cpp @@ -6,7 +6,7 @@ class CfgPatches { units[] = {}; weapons[] = {}; requiredVersion = REQUIRED_VERSION; - requiredAddons[] = {"rhssaf_main_loadorder"}; + requiredAddons[] = {"ace_common", "rhssaf_main_loadorder"}; skipWhenMissingDependencies = 1; author = ECSTRING(common,ACETeam); authors[] = {}; diff --git a/addons/compat_rhs_usf3/config.cpp b/addons/compat_rhs_usf3/config.cpp index 73b4723b2c..f08e9fa2bd 100644 --- a/addons/compat_rhs_usf3/config.cpp +++ b/addons/compat_rhs_usf3/config.cpp @@ -7,7 +7,7 @@ class CfgPatches { units[] = {}; weapons[] = {}; requiredVersion = REQUIRED_VERSION; - requiredAddons[] = {"rhsusf_main_loadorder"}; + requiredAddons[] = {"ace_common", "rhsusf_main_loadorder"}; skipWhenMissingDependencies = 1; author = ECSTRING(common,ACETeam); authors[] = {"Ruthberg", "GitHawk", "BaerMitUmlaut", "Fyuran"}; From 3f5a2ee64b6f81c6f3dec623dec7273bef4eac8e Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 20 Jul 2024 21:19:18 +0200 Subject: [PATCH 152/290] RHS Compats - Remove silent `ace_hearing` dependency from RHS compats (#10134) Remove hearing silent hearing dependency from RHS compats --- addons/compat_rhs_afrf3/CfgWeapons.hpp | 30 +-- .../compat_rhs_afrf3_hearing/CfgWeapons.hpp | 28 +++ .../compat_rhs_afrf3_hearing/config.cpp | 19 ++ .../script_component.hpp | 3 + addons/compat_rhs_afrf3/config.cpp | 1 - addons/compat_rhs_usf3/CfgWeapons.hpp | 169 +---------------- .../compat_rhs_usf3_hearing/CfgWeapons.hpp | 174 ++++++++++++++++++ .../compat_rhs_usf3_hearing/config.cpp | 19 ++ .../script_component.hpp | 3 + addons/compat_rhs_usf3/config.cpp | 1 - 10 files changed, 248 insertions(+), 199 deletions(-) create mode 100644 addons/compat_rhs_afrf3/compat_rhs_afrf3_hearing/CfgWeapons.hpp create mode 100644 addons/compat_rhs_afrf3/compat_rhs_afrf3_hearing/config.cpp create mode 100644 addons/compat_rhs_afrf3/compat_rhs_afrf3_hearing/script_component.hpp create mode 100644 addons/compat_rhs_usf3/compat_rhs_usf3_hearing/CfgWeapons.hpp create mode 100644 addons/compat_rhs_usf3/compat_rhs_usf3_hearing/config.cpp create mode 100644 addons/compat_rhs_usf3/compat_rhs_usf3_hearing/script_component.hpp diff --git a/addons/compat_rhs_afrf3/CfgWeapons.hpp b/addons/compat_rhs_afrf3/CfgWeapons.hpp index a6def44c40..a25d1f7cd0 100644 --- a/addons/compat_rhs_afrf3/CfgWeapons.hpp +++ b/addons/compat_rhs_afrf3/CfgWeapons.hpp @@ -108,19 +108,7 @@ class CfgWeapons { EGVAR(overpressure,offset) = 1.65; }; - class H_HelmetB; - class rhs_tsh4: H_HelmetB { - HEARING_PROTECTION_VICCREW; - }; - - class rhs_6b47_bare; - class rhs_6b48: rhs_6b47_bare { - HEARING_PROTECTION_VICCREW; - }; - - class rhs_zsh7a: H_HelmetB { - HEARING_PROTECTION_VICCREW; - }; + class rhs_zsh7a; class rhs_zsh7a_alt: rhs_zsh7a { ACE_Protection = 1; }; @@ -133,22 +121,6 @@ class CfgWeapons { ACE_Protection = 1; }; - class rhs_gssh18: H_HelmetB { - HEARING_PROTECTION_EARMUFF; - }; - - class rhs_6b47; - class rhs_6b47_6m2: rhs_6b47 { - HEARING_PROTECTION_PELTOR; - }; - class rhs_6b47_6m2_1: rhs_6b47 { - HEARING_PROTECTION_PELTOR; - }; - - class rhs_6m2: H_HelmetB { - HEARING_PROTECTION_PELTOR; - }; - class rhs_weap_d81; class rhs_weap_2a70: rhs_weap_d81 { // "Low pressure" 100mm cannon EGVAR(overpressure,range) = 15; diff --git a/addons/compat_rhs_afrf3/compat_rhs_afrf3_hearing/CfgWeapons.hpp b/addons/compat_rhs_afrf3/compat_rhs_afrf3_hearing/CfgWeapons.hpp new file mode 100644 index 0000000000..04edf4d754 --- /dev/null +++ b/addons/compat_rhs_afrf3/compat_rhs_afrf3_hearing/CfgWeapons.hpp @@ -0,0 +1,28 @@ +class CfgWeapons { + class H_HelmetB; + class rhs_tsh4: H_HelmetB { + HEARING_PROTECTION_VICCREW; + }; + class rhs_zsh7a: H_HelmetB { + HEARING_PROTECTION_VICCREW; + }; + class rhs_gssh18: H_HelmetB { + HEARING_PROTECTION_EARMUFF; + }; + class rhs_6m2: H_HelmetB { + HEARING_PROTECTION_PELTOR; + }; + + class rhs_6b47; + class rhs_6b47_6m2: rhs_6b47 { + HEARING_PROTECTION_PELTOR; + }; + class rhs_6b47_6m2_1: rhs_6b47 { + HEARING_PROTECTION_PELTOR; + }; + + class rhs_6b47_bare; + class rhs_6b48: rhs_6b47_bare { + HEARING_PROTECTION_VICCREW; + }; +}; diff --git a/addons/compat_rhs_afrf3/compat_rhs_afrf3_hearing/config.cpp b/addons/compat_rhs_afrf3/compat_rhs_afrf3_hearing/config.cpp new file mode 100644 index 0000000000..4a8056bf0c --- /dev/null +++ b/addons/compat_rhs_afrf3/compat_rhs_afrf3_hearing/config.cpp @@ -0,0 +1,19 @@ +#include "script_component.hpp" +#include "\z\ace\addons\hearing\script_macros_hearingProtection.hpp" + +class CfgPatches { + class SUBADDON { + addonRootClass = QUOTE(COMPONENT); + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = { + "rhs_main_loadorder", + "ace_hearing" + }; + skipWhenMissingDependencies = 1; + VERSION_CONFIG; + }; +}; + +#include "CfgWeapons.hpp" diff --git a/addons/compat_rhs_afrf3/compat_rhs_afrf3_hearing/script_component.hpp b/addons/compat_rhs_afrf3/compat_rhs_afrf3_hearing/script_component.hpp new file mode 100644 index 0000000000..8edb825af3 --- /dev/null +++ b/addons/compat_rhs_afrf3/compat_rhs_afrf3_hearing/script_component.hpp @@ -0,0 +1,3 @@ +#define SUBCOMPONENT hearing +#define SUBCOMPONENT_BEAUTIFIED Hearing +#include "..\script_component.hpp" diff --git a/addons/compat_rhs_afrf3/config.cpp b/addons/compat_rhs_afrf3/config.cpp index 0b3c990ced..8bf5668485 100644 --- a/addons/compat_rhs_afrf3/config.cpp +++ b/addons/compat_rhs_afrf3/config.cpp @@ -1,5 +1,4 @@ #include "script_component.hpp" -#include "\z\ace\addons\hearing\script_macros_hearingProtection.hpp" class CfgPatches { class ADDON { diff --git a/addons/compat_rhs_usf3/CfgWeapons.hpp b/addons/compat_rhs_usf3/CfgWeapons.hpp index 46ac7e56ba..50b09c760f 100644 --- a/addons/compat_rhs_usf3/CfgWeapons.hpp +++ b/addons/compat_rhs_usf3/CfgWeapons.hpp @@ -206,170 +206,7 @@ class CfgWeapons { EGVAR(overpressure,offset) = 0.9; }; - // Fast Helmets - class rhsusf_opscore_01; - class rhsusf_opscore_ut_pelt_nsw: rhsusf_opscore_01 { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_aor1_pelt: rhsusf_opscore_01 { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_aor1_pelt_nsw: rhsusf_opscore_01 { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_bk_pelt: rhsusf_opscore_01 { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_fg_pelt: rhsusf_opscore_01 { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_fg_pelt_nsw: rhsusf_opscore_01 { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_fg_pelt_cam: rhsusf_opscore_01 { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_paint_pelt: rhsusf_opscore_01 { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_paint_pelt_nsw: rhsusf_opscore_01 { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_paint_pelt_nsw_cam: rhsusf_opscore_01 { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_aor2_pelt: rhsusf_opscore_01 { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_aor2_pelt_nsw: rhsusf_opscore_01 { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_ut_pelt: rhsusf_opscore_01 { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_ut_pelt_cam: rhsusf_opscore_01 { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_ut_pelt_nsw_cam: rhsusf_opscore_01 { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_mc_pelt: rhsusf_opscore_01 { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_mc_pelt_nsw: rhsusf_opscore_01 { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_cover; - class rhsusf_opscore_mc_cover_pelt_nsw: rhsusf_opscore_cover { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_mc_cover_pelt: rhsusf_opscore_cover { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_mc_cover_pelt_cam: rhsusf_opscore_cover { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_rg_cover_pelt: rhsusf_opscore_cover { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_coy_cover_pelt: rhsusf_opscore_cover { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_mar_01; - class rhsusf_opscore_mar_ut_pelt: rhsusf_opscore_mar_01 { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_opscore_mar_fg_pelt: rhsusf_opscore_mar_01 { - HEARING_PROTECTION_PELTOR; - }; - - // ACH Helmets - class rhsusf_ach_helmet_ocp; - class rhsusf_ach_bare_des_headset: rhsusf_ach_helmet_ocp { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_ach_bare_des_headset_ess: rhsusf_ach_helmet_ocp { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_ach_bare_headset: rhsusf_ach_helmet_ocp { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_ach_bare_headset_ess: rhsusf_ach_helmet_ocp { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_ach_bare_semi_headset: rhsusf_ach_helmet_ocp { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_ach_bare_semi_headset_ess: rhsusf_ach_helmet_ocp { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_ach_bare_tan_headset: rhsusf_ach_helmet_ocp { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_ach_bare_tan_headset_ess: rhsusf_ach_helmet_ocp { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_ach_bare_wood_headset: rhsusf_ach_helmet_ocp { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_ach_bare_wood_headset_ess: rhsusf_ach_helmet_ocp { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_ach_helmet_headset_ocp: rhsusf_ach_helmet_ocp { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_ach_helmet_headset_ess_ocp: rhsusf_ach_helmet_ocp { - HEARING_PROTECTION_PELTOR; - }; - - // ACVC Helmets - class rhsusf_cvc_helmet: rhsusf_opscore_01 { - HEARING_PROTECTION_VICCREW; - }; - - // MICH Helmets - class rhsusf_mich_bare; - class rhsusf_mich_bare_alt: rhsusf_mich_bare { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_mich_bare_norotos; - class rhsusf_mich_bare_norotos_alt: rhsusf_mich_bare_norotos { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_mich_bare_norotos_arc; - class rhsusf_mich_bare_norotos_arc_alt: rhsusf_mich_bare_norotos_arc { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_mich_bare_semi; - class rhsusf_mich_bare_alt_semi: rhsusf_mich_bare_semi { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_mich_bare_norotos_semi; - class rhsusf_mich_bare_norotos_alt_semi: rhsusf_mich_bare_norotos_semi { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_mich_bare_norotos_arc_semi: rhsusf_mich_bare_norotos_alt_semi { - HEARING_PROTECTION_OPEN; - }; - class rhsusf_mich_bare_norotos_arc_alt_semi: rhsusf_mich_bare_norotos_arc_semi { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_mich_bare_tan; - class rhsusf_mich_bare_alt_tan: rhsusf_mich_bare_tan { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_mich_bare_norotos_tan; - class rhsusf_mich_bare_norotos_alt_tan: rhsusf_mich_bare_norotos_tan { - HEARING_PROTECTION_PELTOR; - }; - class rhsusf_mich_bare_norotos_arc_tan; - class rhsusf_mich_bare_norotos_arc_alt_tan: rhsusf_mich_bare_norotos_arc_tan { - HEARING_PROTECTION_PELTOR; - }; - - class rhsusf_hgu56p: rhsusf_opscore_01 { - HEARING_PROTECTION_VICCREW; - }; + class rhsusf_hgu56p; class rhsusf_hgu56p_visor: rhsusf_hgu56p { ACE_Protection = 1; }; @@ -420,13 +257,9 @@ class CfgWeapons { class rhsusf_hgu56p_mask_black_skull: rhsusf_hgu56p_visor_mask_black_skull { ACE_Protection = 0; }; - class rhsusf_ihadss: rhsusf_opscore_01 { - HEARING_PROTECTION_VICCREW; - }; class H_HelmetB; class RHS_jetpilot_usaf: H_HelmetB { ACE_Protection = 1; - HEARING_PROTECTION_VICCREW; }; }; diff --git a/addons/compat_rhs_usf3/compat_rhs_usf3_hearing/CfgWeapons.hpp b/addons/compat_rhs_usf3/compat_rhs_usf3_hearing/CfgWeapons.hpp new file mode 100644 index 0000000000..f0571e876f --- /dev/null +++ b/addons/compat_rhs_usf3/compat_rhs_usf3_hearing/CfgWeapons.hpp @@ -0,0 +1,174 @@ +class CfgWeapons { + // Fast Helmets + class rhsusf_opscore_01; + class rhsusf_opscore_ut_pelt_nsw: rhsusf_opscore_01 { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_aor1_pelt: rhsusf_opscore_01 { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_aor1_pelt_nsw: rhsusf_opscore_01 { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_bk_pelt: rhsusf_opscore_01 { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_fg_pelt: rhsusf_opscore_01 { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_fg_pelt_nsw: rhsusf_opscore_01 { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_fg_pelt_cam: rhsusf_opscore_01 { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_paint_pelt: rhsusf_opscore_01 { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_paint_pelt_nsw: rhsusf_opscore_01 { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_paint_pelt_nsw_cam: rhsusf_opscore_01 { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_aor2_pelt: rhsusf_opscore_01 { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_aor2_pelt_nsw: rhsusf_opscore_01 { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_ut_pelt: rhsusf_opscore_01 { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_ut_pelt_cam: rhsusf_opscore_01 { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_ut_pelt_nsw_cam: rhsusf_opscore_01 { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_mc_pelt: rhsusf_opscore_01 { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_mc_pelt_nsw: rhsusf_opscore_01 { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_cover; + class rhsusf_opscore_mc_cover_pelt_nsw: rhsusf_opscore_cover { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_mc_cover_pelt: rhsusf_opscore_cover { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_mc_cover_pelt_cam: rhsusf_opscore_cover { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_rg_cover_pelt: rhsusf_opscore_cover { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_coy_cover_pelt: rhsusf_opscore_cover { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_mar_01; + class rhsusf_opscore_mar_ut_pelt: rhsusf_opscore_mar_01 { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_opscore_mar_fg_pelt: rhsusf_opscore_mar_01 { + HEARING_PROTECTION_PELTOR; + }; + + // ACH Helmets + class rhsusf_ach_helmet_ocp; + class rhsusf_ach_bare_des_headset: rhsusf_ach_helmet_ocp { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_ach_bare_des_headset_ess: rhsusf_ach_helmet_ocp { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_ach_bare_headset: rhsusf_ach_helmet_ocp { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_ach_bare_headset_ess: rhsusf_ach_helmet_ocp { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_ach_bare_semi_headset: rhsusf_ach_helmet_ocp { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_ach_bare_semi_headset_ess: rhsusf_ach_helmet_ocp { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_ach_bare_tan_headset: rhsusf_ach_helmet_ocp { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_ach_bare_tan_headset_ess: rhsusf_ach_helmet_ocp { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_ach_bare_wood_headset: rhsusf_ach_helmet_ocp { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_ach_bare_wood_headset_ess: rhsusf_ach_helmet_ocp { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_ach_helmet_headset_ocp: rhsusf_ach_helmet_ocp { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_ach_helmet_headset_ess_ocp: rhsusf_ach_helmet_ocp { + HEARING_PROTECTION_PELTOR; + }; + + // ACVC Helmets + class rhsusf_cvc_helmet: rhsusf_opscore_01 { + HEARING_PROTECTION_VICCREW; + }; + + // MICH Helmets + class rhsusf_mich_bare; + class rhsusf_mich_bare_alt: rhsusf_mich_bare { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_mich_bare_norotos; + class rhsusf_mich_bare_norotos_alt: rhsusf_mich_bare_norotos { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_mich_bare_norotos_arc; + class rhsusf_mich_bare_norotos_arc_alt: rhsusf_mich_bare_norotos_arc { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_mich_bare_semi; + class rhsusf_mich_bare_alt_semi: rhsusf_mich_bare_semi { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_mich_bare_norotos_semi; + class rhsusf_mich_bare_norotos_alt_semi: rhsusf_mich_bare_norotos_semi { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_mich_bare_norotos_arc_semi: rhsusf_mich_bare_norotos_alt_semi { + HEARING_PROTECTION_OPEN; + }; + class rhsusf_mich_bare_norotos_arc_alt_semi: rhsusf_mich_bare_norotos_arc_semi { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_mich_bare_tan; + class rhsusf_mich_bare_alt_tan: rhsusf_mich_bare_tan { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_mich_bare_norotos_tan; + class rhsusf_mich_bare_norotos_alt_tan: rhsusf_mich_bare_norotos_tan { + HEARING_PROTECTION_PELTOR; + }; + class rhsusf_mich_bare_norotos_arc_tan; + class rhsusf_mich_bare_norotos_arc_alt_tan: rhsusf_mich_bare_norotos_arc_tan { + HEARING_PROTECTION_PELTOR; + }; + + class rhsusf_hgu56p: rhsusf_opscore_01 { + HEARING_PROTECTION_VICCREW; + }; + class rhsusf_ihadss: rhsusf_opscore_01 { + HEARING_PROTECTION_VICCREW; + }; + + class H_HelmetB; + class RHS_jetpilot_usaf: H_HelmetB { + HEARING_PROTECTION_VICCREW; + }; +}; diff --git a/addons/compat_rhs_usf3/compat_rhs_usf3_hearing/config.cpp b/addons/compat_rhs_usf3/compat_rhs_usf3_hearing/config.cpp new file mode 100644 index 0000000000..e52454b184 --- /dev/null +++ b/addons/compat_rhs_usf3/compat_rhs_usf3_hearing/config.cpp @@ -0,0 +1,19 @@ +#include "script_component.hpp" +#include "\z\ace\addons\hearing\script_macros_hearingProtection.hpp" + +class CfgPatches { + class SUBADDON { + addonRootClass = QUOTE(COMPONENT); + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = { + "rhsusf_main_loadorder", + "ace_hearing" + }; + skipWhenMissingDependencies = 1; + VERSION_CONFIG; + }; +}; + +#include "CfgWeapons.hpp" diff --git a/addons/compat_rhs_usf3/compat_rhs_usf3_hearing/script_component.hpp b/addons/compat_rhs_usf3/compat_rhs_usf3_hearing/script_component.hpp new file mode 100644 index 0000000000..8edb825af3 --- /dev/null +++ b/addons/compat_rhs_usf3/compat_rhs_usf3_hearing/script_component.hpp @@ -0,0 +1,3 @@ +#define SUBCOMPONENT hearing +#define SUBCOMPONENT_BEAUTIFIED Hearing +#include "..\script_component.hpp" diff --git a/addons/compat_rhs_usf3/config.cpp b/addons/compat_rhs_usf3/config.cpp index f08e9fa2bd..b28a08b22e 100644 --- a/addons/compat_rhs_usf3/config.cpp +++ b/addons/compat_rhs_usf3/config.cpp @@ -1,5 +1,4 @@ #include "script_component.hpp" -#include "\z\ace\addons\hearing\script_macros_hearingProtection.hpp" class CfgPatches { class ADDON { From 05c7f84b014395e331ce737b968039e895c1e1f5 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Sun, 21 Jul 2024 14:31:57 -0500 Subject: [PATCH 153/290] Medical Engine - Allow disabling seat locking on vehicle types (#10123) --- .../medical_engine/functions/fnc_lockUnconsciousSeat.sqf | 8 +++++++- docs/wiki/framework/medical-framework.md | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/addons/medical_engine/functions/fnc_lockUnconsciousSeat.sqf b/addons/medical_engine/functions/fnc_lockUnconsciousSeat.sqf index cc29e75cc1..8441df4ad8 100644 --- a/addons/medical_engine/functions/fnc_lockUnconsciousSeat.sqf +++ b/addons/medical_engine/functions/fnc_lockUnconsciousSeat.sqf @@ -11,7 +11,6 @@ * * Public: No */ -if (missionNamespace getVariable [QGVAR(disableSeatLocking), false]) exitWith {}; params ["_unit"]; private _vehicle = objectParent _unit; @@ -20,6 +19,13 @@ TRACE_3("lockUnconsciousSeat",_unit,_vehicle,lifeState _unit); if (isNull _vehicle) exitWith {}; if (alive _unit && {lifeState _unit != "INCAPACITATED"}) exitWith {}; +private _disable = missionNamespace getVariable [QGVAR(disableSeatLocking), false]; +if (_disable isEqualTo true || { + _disable isEqualType [] && { + (_disable findIf {_vehicle isKindOf _x}) != -1 + } +}) exitWith {}; + switch (true) do { case (_unit isEqualTo (driver _vehicle)): { _vehicle lockDriver true; diff --git a/docs/wiki/framework/medical-framework.md b/docs/wiki/framework/medical-framework.md index 00d9133b00..c0e94b5f9e 100644 --- a/docs/wiki/framework/medical-framework.md +++ b/docs/wiki/framework/medical-framework.md @@ -241,3 +241,10 @@ The damage elements are sorted in descending order according to how much damage Some of ACE Medical's underlying behavior, primarily related to damage handling and the vitals loop, can be fine-tuned by editing `ace_medical_const_` variables, found in [script_macros_medical.hpp](https://github.com/acemod/ACE3/blob/master/addons/medical_engine/script_macros_medical.hpp). Modification of those values should be done by advanced users only. Values and variable names are subject to change without prior warning. Modifying values mid-mission may lead to undefined behavior. Expect minimal support. + +### 5.1 Disable seat locking for unconscious +ACE will lock the seat of an unconscious or dead unit to prevent automatic unloading. This can be disabled by setting: +```sqf +ace_medical_engine_disableSeatLocking = true; // disable on everything +ace_medical_engine_disableSeatLocking = ["ship"]; // disable just on boats +``` From b6e9cabc3477423e56265fbd51f8519a9d863faf Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 22 Jul 2024 08:38:39 +0200 Subject: [PATCH 154/290] Cargo & Dragging - Disable UAV AI when being dragged, carried or cargo (#10100) * Disable UAV AI when being dragged, carried or cargo * Update addons/common/functions/fnc_disableAiUAV.sqf * Improve dragging/carrying conditions, fixed duplicate JIP --- addons/cargo/functions/fnc_loadItem.sqf | 11 +++++ addons/cargo/functions/fnc_unloadItem.sqf | 12 +++++ addons/common/XEH_PREP.hpp | 1 + addons/common/XEH_postInit.sqf | 24 ++++++++++ addons/common/functions/fnc_disableAiUAV.sqf | 45 +++++++++++++++++++ addons/dragging/functions/fnc_carryObject.sqf | 4 +- .../dragging/functions/fnc_carryObjectPFH.sqf | 4 +- addons/dragging/functions/fnc_dragObject.sqf | 4 +- .../dragging/functions/fnc_dragObjectPFH.sqf | 4 +- addons/dragging/functions/fnc_dropObject.sqf | 18 ++++---- .../functions/fnc_dropObject_carry.sqf | 18 ++++---- 11 files changed, 119 insertions(+), 26 deletions(-) create mode 100644 addons/common/functions/fnc_disableAiUAV.sqf diff --git a/addons/cargo/functions/fnc_loadItem.sqf b/addons/cargo/functions/fnc_loadItem.sqf index 21ebc0d52a..aa3117c7dd 100644 --- a/addons/cargo/functions/fnc_loadItem.sqf +++ b/addons/cargo/functions/fnc_loadItem.sqf @@ -62,6 +62,17 @@ if (_item isEqualType objNull) then { // Some objects below water will take damage over time, eventually becoming "water logged" and unfixable (because of negative z attach) [_item, "blockDamage", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); + + // Prevent UAVs from firing + private _UAVCrew = _item call EFUNC(common,getVehicleUAVCrew); + + if (_UAVCrew isNotEqualTo []) then { + { + [_x, true] call EFUNC(common,disableAiUAV); + } forEach _UAVCrew; + + _item setVariable [QGVAR(isUAV), _UAVCrew, true]; + }; }; // Invoke listenable event diff --git a/addons/cargo/functions/fnc_unloadItem.sqf b/addons/cargo/functions/fnc_unloadItem.sqf index f32215fdd7..7580de8488 100644 --- a/addons/cargo/functions/fnc_unloadItem.sqf +++ b/addons/cargo/functions/fnc_unloadItem.sqf @@ -96,6 +96,18 @@ if (_object isEqualType objNull) then { [QEGVAR(zeus,addObjects), [[_object], _objectCurators]] call CBA_fnc_serverEvent; }; + + // Reenable UAV crew + private _UAVCrew = _object getVariable [QGVAR(isUAV), []]; + + if (_UAVCrew isNotEqualTo []) then { + // Reenable AI + { + [_x, false] call EFUNC(common,disableAiUAV); + } forEach _UAVCrew; + + _object setVariable [QGVAR(isUAV), nil, true]; + }; } else { _object = createVehicle [_item, _emptyPosAGL, [], 0, "NONE"]; diff --git a/addons/common/XEH_PREP.hpp b/addons/common/XEH_PREP.hpp index 3a5838a230..5b85d63dda 100644 --- a/addons/common/XEH_PREP.hpp +++ b/addons/common/XEH_PREP.hpp @@ -43,6 +43,7 @@ PREP(deviceKeyFindValidIndex); PREP(deviceKeyRegisterNew); PREP(deprecateComponent); PREP(disableAI); +PREP(disableAiUAV); PREP(disableUserInput); PREP(displayIcon); PREP(displayText); diff --git a/addons/common/XEH_postInit.sqf b/addons/common/XEH_postInit.sqf index b569a4608e..8b7568f75e 100644 --- a/addons/common/XEH_postInit.sqf +++ b/addons/common/XEH_postInit.sqf @@ -133,6 +133,30 @@ _object lockInventory (_set > 0); }] call CBA_fnc_addEventHandler; +[QGVAR(disableAiUAV), { + params ["_unit", "_disable"]; + + if (_disable) then { + private _features = ["AUTOTARGET", "TARGET", "WEAPONAIM"/*, "FIREWEAPON"*/, "RADIOPROTOCOL"]; // TODO: Uncomment in 2.18 + + // Save current status + _unit setVariable [QGVAR(featuresAiUAV), _features apply {[_x, _unit checkAIFeature _x]}]; + + { + _unit enableAIFeature [_x, false]; + } forEach _features; + } else { + // Restore previous status + private _features = _unit getVariable [QGVAR(featuresAiUAV), []]; + + { + _unit enableAIFeature [_x select 0, _x select 1]; + } forEach _features; + + _unit setVariable [QGVAR(featuresAiUAV), nil]; + }; +}] call CBA_fnc_addEventHandler; + //Add a fix for BIS's zeus remoteControl module not reseting variables on DC when RC a unit //This variable is used for isPlayer checks if (isServer) then { diff --git a/addons/common/functions/fnc_disableAiUAV.sqf b/addons/common/functions/fnc_disableAiUAV.sqf new file mode 100644 index 0000000000..195e3ed2dc --- /dev/null +++ b/addons/common/functions/fnc_disableAiUAV.sqf @@ -0,0 +1,45 @@ +#include "..\script_component.hpp" +/* + * Author: johnb43 + * Disables/Enables UAV AI crew members, can be run on any machine and is applied globally. + * + * Arguments: + * 0: Unit + * 1: Disable AI + * + * Return Value: + * None + * + * Example: + * [cursorObject, true] call ace_common_fnc_disableAiUAV + * + * Public: No + */ + +params [["_unit", objNull, [objNull]], ["_disable", true, [false]]]; + +// Allow disabling of Zeus remote controlled units +if (!alive _unit || {isPlayer _unit} || {!unitIsUAV _unit}) exitWith {}; + +if (_disable) then { + // Ignore if already disabled + if (!isNil "_jipID") exitWith {}; + + // Disable shooting and targeting on every machine + // Give predefined JIP ID, in case of simultaneous executions on different machines + private _jipID = [QGVAR(disableAiUAV), [_unit, _disable], QGVAR(disableAiUAV_) + hashValue _unit] call CBA_fnc_globalEventJIP; + [_jipID, _unit] call CBA_fnc_removeGlobalEventJIP; + + _unit setVariable [QGVAR(disableAiUavJipID), _jipID, true]; +} else { + // Restore shooting and targeting to each client's individual state prior to disabling + private _jipID = _unit getVariable QGVAR(disableAiUavJipID); + + if (isNil "_jipID") exitWith {}; + + _jipID call CBA_fnc_removeGlobalEventJIP; + + _unit setVariable [QGVAR(disableAiUavJipID), nil, true]; + + [QGVAR(disableAiUAV), [_unit, _disable]] call CBA_fnc_globalEvent; +}; diff --git a/addons/dragging/functions/fnc_carryObject.sqf b/addons/dragging/functions/fnc_carryObject.sqf index a6b38c4ea5..579e6a0ac3 100644 --- a/addons/dragging/functions/fnc_carryObject.sqf +++ b/addons/dragging/functions/fnc_carryObject.sqf @@ -66,10 +66,10 @@ private _UAVCrew = _target call EFUNC(common,getVehicleUAVCrew); if (_UAVCrew isNotEqualTo []) then { { - _target deleteVehicleCrew _x; + [_x, true] call EFUNC(common,disableAiUAV); } forEach _UAVCrew; - _target setVariable [QGVAR(isUAV), true, true]; + _target setVariable [QGVAR(isUAV), _UAVCrew, true]; }; // Check everything diff --git a/addons/dragging/functions/fnc_carryObjectPFH.sqf b/addons/dragging/functions/fnc_carryObjectPFH.sqf index fcd0f05376..e0a58a26eb 100644 --- a/addons/dragging/functions/fnc_carryObjectPFH.sqf +++ b/addons/dragging/functions/fnc_carryObjectPFH.sqf @@ -73,8 +73,8 @@ if (_unit getHitPointDamage "HitLegs" >= 0.5) exitWith { _idPFH call CBA_fnc_removePerFrameHandler; }; -// Drop static if crew is in it (UAV crew deletion may take a few frames) -if (_target isKindOf "StaticWeapon" && {!(_target getVariable [QGVAR(isUAV), false])} && {(crew _target) isNotEqualTo []}) exitWith { +// Drop static if either non-UAV crew or new UAV crew is in it (ignore saved UAV crew) +if (_target isKindOf "StaticWeapon" && {((crew _target) - (_target getVariable [QGVAR(isUAV), []])) isNotEqualTo []}) exitWith { TRACE_2("static weapon crewed",_unit,_target); [_unit, _target] call FUNC(dropObject_carry); diff --git a/addons/dragging/functions/fnc_dragObject.sqf b/addons/dragging/functions/fnc_dragObject.sqf index 6420ff56df..87272491da 100644 --- a/addons/dragging/functions/fnc_dragObject.sqf +++ b/addons/dragging/functions/fnc_dragObject.sqf @@ -79,10 +79,10 @@ private _UAVCrew = _target call EFUNC(common,getVehicleUAVCrew); if (_UAVCrew isNotEqualTo []) then { { - _target deleteVehicleCrew _x; + [_x, true] call EFUNC(common,disableAiUAV); } forEach _UAVCrew; - _target setVariable [QGVAR(isUAV), true, true]; + _target setVariable [QGVAR(isUAV), _UAVCrew, true]; }; // Check everything diff --git a/addons/dragging/functions/fnc_dragObjectPFH.sqf b/addons/dragging/functions/fnc_dragObjectPFH.sqf index 7c3a6be307..249f3866bb 100644 --- a/addons/dragging/functions/fnc_dragObjectPFH.sqf +++ b/addons/dragging/functions/fnc_dragObjectPFH.sqf @@ -51,8 +51,8 @@ if (_unit distance _target > 10 && {(CBA_missionTime - _startTime) >= 1}) exitWi _idPFH call CBA_fnc_removePerFrameHandler; }; -// Drop static if crew is in it (UAV crew deletion may take a few frames) -if (_target isKindOf "StaticWeapon" && {!(_target getVariable [QGVAR(isUAV), false])} && {(crew _target) isNotEqualTo []}) exitWith { +// Drop static if either non-UAV crew or new UAV crew is in it (ignore saved UAV crew) +if (_target isKindOf "StaticWeapon" && {((crew _target) - (_target getVariable [QGVAR(isUAV), []])) isNotEqualTo []}) exitWith { TRACE_2("static weapon crewed",_unit,_target); [_unit, _target] call FUNC(dropObject); diff --git a/addons/dragging/functions/fnc_dropObject.sqf b/addons/dragging/functions/fnc_dropObject.sqf index 4115f28820..119eaf415a 100644 --- a/addons/dragging/functions/fnc_dropObject.sqf +++ b/addons/dragging/functions/fnc_dropObject.sqf @@ -80,16 +80,16 @@ if (_unit getVariable ["ACE_isUnconscious", false]) then { [_unit, "unconscious", 2] call EFUNC(common,doAnimation); }; -// Recreate UAV crew (add a frame delay or this may cause the vehicle to be moved to [0,0,0]) -if (_target getVariable [QGVAR(isUAV), false]) then { - _target setVariable [QGVAR(isUAV), nil, true]; +// Reenable UAV crew +private _UAVCrew = _target getVariable [QGVAR(isUAV), []]; - [{ - params ["_target"]; - if (!alive _target) exitWith {}; - TRACE_2("restoring uav crew",_target,getPosASL _target); - createVehicleCrew _target; - }, [_target]] call CBA_fnc_execNextFrame; +if (_UAVCrew isNotEqualTo []) then { + // Reenable AI + { + [_x, false] call EFUNC(common,disableAiUAV); + } forEach _UAVCrew; + + _target setVariable [QGVAR(isUAV), nil, true]; }; // Fixes not being able to move when in combat pace diff --git a/addons/dragging/functions/fnc_dropObject_carry.sqf b/addons/dragging/functions/fnc_dropObject_carry.sqf index 32e8adcbe6..d244d93a2e 100644 --- a/addons/dragging/functions/fnc_dropObject_carry.sqf +++ b/addons/dragging/functions/fnc_dropObject_carry.sqf @@ -87,16 +87,16 @@ if !(_target isKindOf "CAManBase") then { [QEGVAR(common,fixFloating), _target, _target] call CBA_fnc_targetEvent; }; -// Recreate UAV crew (add a frame delay or this may cause the vehicle to be moved to [0,0,0]) -if (_target getVariable [QGVAR(isUAV), false]) then { - _target setVariable [QGVAR(isUAV), nil, true]; +// Reenable UAV crew +private _UAVCrew = _target getVariable [QGVAR(isUAV), []]; - [{ - params ["_target"]; - if (!alive _target) exitWith {}; - TRACE_2("restoring uav crew",_target,getPosASL _target); - createVehicleCrew _target; - }, [_target]] call CBA_fnc_execNextFrame; +if (_UAVCrew isNotEqualTo []) then { + // Reenable AI + { + [_x, false] call EFUNC(common,disableAiUAV); + } forEach _UAVCrew; + + _target setVariable [QGVAR(isUAV), nil, true]; }; // Reset mass From db339ab8e35f45f7b4a85881f85f79fb6b9abfa2 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 22 Jul 2024 19:15:43 +0200 Subject: [PATCH 155/290] Cargo - Reenable UAV AI when on ground when paradropped (#10137) Reenable UAV AI when on ground when paradropped --- addons/cargo/functions/fnc_paradropItem.sqf | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/addons/cargo/functions/fnc_paradropItem.sqf b/addons/cargo/functions/fnc_paradropItem.sqf index acd780f463..6a84a20799 100644 --- a/addons/cargo/functions/fnc_paradropItem.sqf +++ b/addons/cargo/functions/fnc_paradropItem.sqf @@ -100,14 +100,26 @@ if (_item isEqualType objNull) then { // Create smoke effect when crate landed [{ - (_this select 0) params ["_object"]; + params ["_object", "_pfhID"]; if (isNull _object) exitWith { - [_this select 1] call CBA_fnc_removePerFrameHandler; + _pfhID call CBA_fnc_removePerFrameHandler; }; if (getPos _object select 2 < 1) exitWith { - [_this select 1] call CBA_fnc_removePerFrameHandler; + _pfhID call CBA_fnc_removePerFrameHandler; + + // Reenable UAV crew + private _UAVCrew = _object getVariable [QGVAR(isUAV), []]; + + if (_UAVCrew isNotEqualTo []) then { + // Reenable AI + { + [_x, false] call EFUNC(common,disableAiUAV); + } forEach _UAVCrew; + + _object setVariable [QGVAR(isUAV), nil, true]; + }; if ((GVAR(disableParadropEffectsClasstypes) findIf {_object isKindOf _x}) == -1) then { private _smoke = "SmokeshellYellow" createVehicle [0, 0, 0]; From 43c1f97dfa65bcf3c4e8d310283caab3a68ac4bf Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 22 Jul 2024 19:27:26 +0200 Subject: [PATCH 156/290] Laser - Remove unnecessary EGVAR (#10139) Remove unnecessary EGVAR --- addons/laser/functions/fnc_addLaserTarget.sqf | 6 +++--- addons/laser/functions/fnc_laserTargetPFH.sqf | 2 +- addons/laser/functions/fnc_showVehicleHud.sqf | 2 +- addons/laser/functions/fnc_toggleLST.sqf | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/addons/laser/functions/fnc_addLaserTarget.sqf b/addons/laser/functions/fnc_addLaserTarget.sqf index 3fc02b2189..f0414fd3ad 100644 --- a/addons/laser/functions/fnc_addLaserTarget.sqf +++ b/addons/laser/functions/fnc_addLaserTarget.sqf @@ -20,9 +20,9 @@ params ["_targetObject", "_vehicle"]; TRACE_2("params",_targetObject,_vehicle); // Get the designator variables, or use defaults -private _waveLength = _vehicle getVariable [QEGVAR(laser,waveLength), ACE_DEFAULT_LASER_WAVELENGTH]; -private _laserCode = _vehicle getVariable [QEGVAR(laser,code), ACE_DEFAULT_LASER_CODE]; -private _beamSpread = _vehicle getVariable [QEGVAR(laser,beamSpread), ACE_DEFAULT_LASER_BEAMSPREAD]; +private _waveLength = _vehicle getVariable [QGVAR(waveLength), ACE_DEFAULT_LASER_WAVELENGTH]; +private _laserCode = _vehicle getVariable [QGVAR(code), ACE_DEFAULT_LASER_CODE]; +private _beamSpread = _vehicle getVariable [QGVAR(beamSpread), ACE_DEFAULT_LASER_BEAMSPREAD]; TRACE_3("codes",_waveLength,_laserCode,_beamSpread); // Laser method is the method ACE_Laser will use to determine from where to where it should project the designator cone diff --git a/addons/laser/functions/fnc_laserTargetPFH.sqf b/addons/laser/functions/fnc_laserTargetPFH.sqf index 0b19b4d1c3..af2098a6f8 100644 --- a/addons/laser/functions/fnc_laserTargetPFH.sqf +++ b/addons/laser/functions/fnc_laserTargetPFH.sqf @@ -29,7 +29,7 @@ GVAR(trackedLaserTargets) = GVAR(trackedLaserTargets) select { TRACE_1("Laser off:",_laserUuid); false } else { - private _newCode = _owner getVariable [QEGVAR(laser,code), ACE_DEFAULT_LASER_CODE]; + private _newCode = _owner getVariable [QGVAR(code), ACE_DEFAULT_LASER_CODE]; if (_laserCode != _newCode) then { TRACE_2("code change",_newCode,_laserCode); [QGVAR(updateCode), [_laserUuid, _newCode]] call CBA_fnc_globalEvent; diff --git a/addons/laser/functions/fnc_showVehicleHud.sqf b/addons/laser/functions/fnc_showVehicleHud.sqf index 778df61a6c..35120a294d 100644 --- a/addons/laser/functions/fnc_showVehicleHud.sqf +++ b/addons/laser/functions/fnc_showVehicleHud.sqf @@ -91,7 +91,7 @@ GVAR(pfID) = [{ // Do Laser Scan: private _ammo = getText (configFile >> "CfgMagazines" >> _vehicle currentMagazineTurret _turretPath >> "ammo"); private _laserSource = _vehicle modelToWorldWorld (_vehicle selectionPosition _seekerSource); - private _laserCode = _vehicle getVariable [QEGVAR(laser,code), ACE_DEFAULT_LASER_CODE]; + private _laserCode = _vehicle getVariable [QGVAR(code), ACE_DEFAULT_LASER_CODE]; private _seekerAngle = getNumber (configFile >> "CfgAmmo" >> _ammo >> "ace_missileguidance" >> "seekerAngle"); private _seekerMaxRange = getNumber (configFile >> "CfgAmmo" >> _ammo >> "ace_missileguidance" >> "seekerMaxRange"); private _laserResult = [_laserSource, vectorDir _vehicle, _seekerAngle, _seekerMaxRange, [ACE_DEFAULT_LASER_WAVELENGTH,ACE_DEFAULT_LASER_WAVELENGTH], _laserCode, _vehicle] call EFUNC(laser,seekerFindLaserSpot); diff --git a/addons/laser/functions/fnc_toggleLST.sqf b/addons/laser/functions/fnc_toggleLST.sqf index 59969d014e..eae4ad68ef 100644 --- a/addons/laser/functions/fnc_toggleLST.sqf +++ b/addons/laser/functions/fnc_toggleLST.sqf @@ -39,7 +39,7 @@ if (_enabled) exitWith {}; [_pfhID] call CBA_fnc_removePerFrameHandler; }; - private _laserCode = _vehicle getVariable [QEGVAR(laser,code), ACE_DEFAULT_LASER_CODE]; + private _laserCode = _vehicle getVariable [QGVAR(code), ACE_DEFAULT_LASER_CODE]; private _angle = 25; private _pos = _vehicle modelToWorldVisualWorld [0,0,0]; From cb3c18c2fb81e37abdc7c1303489c873046b7712 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Tue, 23 Jul 2024 15:28:40 +0200 Subject: [PATCH 157/290] Medical AI - Header fixes (#10140) Header fixes for medical AI --- addons/medical_ai/XEH_postInit.sqf | 2 +- addons/medical_ai/XEH_preInit.sqf | 2 +- addons/medical_ai/functions/fnc_canRequestMedic.sqf | 4 ++-- addons/medical_ai/functions/fnc_healSelf.sqf | 4 ++-- addons/medical_ai/functions/fnc_healUnit.sqf | 5 +++-- addons/medical_ai/functions/fnc_healingLogic.sqf | 2 +- addons/medical_ai/functions/fnc_isInjured.sqf | 2 +- addons/medical_ai/functions/fnc_isSafe.sqf | 2 +- addons/medical_ai/functions/fnc_itemCheck.sqf | 4 ++-- addons/medical_ai/functions/fnc_playTreatmentAnim.sqf | 3 ++- addons/medical_ai/functions/fnc_requestMedic.sqf | 4 ++-- addons/medical_ai/functions/fnc_wasRequested.sqf | 4 ++-- 12 files changed, 20 insertions(+), 18 deletions(-) diff --git a/addons/medical_ai/XEH_postInit.sqf b/addons/medical_ai/XEH_postInit.sqf index 0b225c7f0b..518d540478 100644 --- a/addons/medical_ai/XEH_postInit.sqf +++ b/addons/medical_ai/XEH_postInit.sqf @@ -2,6 +2,7 @@ ["CBA_settingsInitialized", { TRACE_1("settingsInitialized",GVAR(enabledFor)); + if (GVAR(enabledFor) == 0) exitWith {}; // 0: disabled if ((GVAR(enabledFor) == 1) && {!isServer} && {hasInterface}) exitWith {}; // 1: Don't Run on non-hc Clients @@ -20,5 +21,4 @@ }] call CBA_fnc_addClassEventHandler; #include "stateMachine.inc.sqf" - }] call CBA_fnc_addEventHandler; diff --git a/addons/medical_ai/XEH_preInit.sqf b/addons/medical_ai/XEH_preInit.sqf index 5725d1e119..8cdc2ee6ad 100644 --- a/addons/medical_ai/XEH_preInit.sqf +++ b/addons/medical_ai/XEH_preInit.sqf @@ -13,6 +13,6 @@ if (isNil QGVAR(timeSafe_shoot)) then { GVAR(timeSafe_shoot) = 30; }; if (isNil QGVAR(timeSafe_hit)) then { GVAR(timeSafe_hit) = 30; }; if (isNil QGVAR(timeSafe_suppressed)) then { GVAR(timeSafe_suppressed) = 30; }; -GVAR(itemHash) = uinamespace getVariable QGVAR(itemHash); +GVAR(itemHash) = uiNamespace getVariable QGVAR(itemHash); ADDON = true; diff --git a/addons/medical_ai/functions/fnc_canRequestMedic.sqf b/addons/medical_ai/functions/fnc_canRequestMedic.sqf index 685bd57f54..5064e1a732 100644 --- a/addons/medical_ai/functions/fnc_canRequestMedic.sqf +++ b/addons/medical_ai/functions/fnc_canRequestMedic.sqf @@ -4,13 +4,13 @@ * Checks if there is a medic available in the unit's group. * * Arguments: - * None + * Unit * * Return Value: * Can request medic * * Example: - * player call ACE_medical_ai_fnc_canRequestMedic + * player call ace_medical_ai_fnc_canRequestMedic * * Public: No */ diff --git a/addons/medical_ai/functions/fnc_healSelf.sqf b/addons/medical_ai/functions/fnc_healSelf.sqf index 5747637995..60f2b83712 100644 --- a/addons/medical_ai/functions/fnc_healSelf.sqf +++ b/addons/medical_ai/functions/fnc_healSelf.sqf @@ -4,13 +4,13 @@ * Makes the unit heal itself. * * Arguments: - * None + * Unit * * Return Value: * None * * Example: - * call ACE_medical_ai_fnc_healSelf + * cursorObject call ace_medical_ai_fnc_healSelf * * Public: No */ diff --git a/addons/medical_ai/functions/fnc_healUnit.sqf b/addons/medical_ai/functions/fnc_healUnit.sqf index ad867d2570..4f941efc0a 100644 --- a/addons/medical_ai/functions/fnc_healUnit.sqf +++ b/addons/medical_ai/functions/fnc_healUnit.sqf @@ -4,16 +4,17 @@ * Makes a medic heal the next unit that needs treatment. * * Arguments: - * None + * Unit * * Return Value: * None * * Example: - * call ACE_medical_ai_fnc_healUnit + * cursorObject call ace_medical_ai_fnc_healUnit * * Public: No */ + // Player will have to do this manually of course if ([_this] call EFUNC(common,isPlayer)) exitWith {}; // Can't heal other units when unconscious diff --git a/addons/medical_ai/functions/fnc_healingLogic.sqf b/addons/medical_ai/functions/fnc_healingLogic.sqf index fa35b49284..aff69d7865 100644 --- a/addons/medical_ai/functions/fnc_healingLogic.sqf +++ b/addons/medical_ai/functions/fnc_healingLogic.sqf @@ -11,7 +11,7 @@ * Nothing * * Example: - * [a, b] call ACE_medical_ai_fnc_healingLogic + * [cursorObject, cursorObject] call ace_medical_ai_fnc_healingLogic * * Public: No */ diff --git a/addons/medical_ai/functions/fnc_isInjured.sqf b/addons/medical_ai/functions/fnc_isInjured.sqf index a163a4c808..51ae37caae 100644 --- a/addons/medical_ai/functions/fnc_isInjured.sqf +++ b/addons/medical_ai/functions/fnc_isInjured.sqf @@ -10,7 +10,7 @@ * Does unit need treatment * * Example: - * player call ACE_medical_ai_fnc_isInjured + * cursorObject call ace_medical_ai_fnc_isInjured * * Public: No */ diff --git a/addons/medical_ai/functions/fnc_isSafe.sqf b/addons/medical_ai/functions/fnc_isSafe.sqf index 04da058ce0..21d59a15d6 100644 --- a/addons/medical_ai/functions/fnc_isSafe.sqf +++ b/addons/medical_ai/functions/fnc_isSafe.sqf @@ -10,7 +10,7 @@ * Is unit safe enough * * Example: - * call ACE_medical_ai_fnc_isSafe + * cursorObject call ace_medical_ai_fnc_isSafe * * Public: No */ diff --git a/addons/medical_ai/functions/fnc_itemCheck.sqf b/addons/medical_ai/functions/fnc_itemCheck.sqf index 6d91594ce4..320ae62410 100644 --- a/addons/medical_ai/functions/fnc_itemCheck.sqf +++ b/addons/medical_ai/functions/fnc_itemCheck.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: PabstMirror - * Checks if AI healer has items + * Checks if AI healer has items. * * Arguments: * 0: Healer @@ -13,7 +13,7 @@ * 2: Treatment (Optional) * * Example: - * [cursorObject, "@bandage"] call ACE_medical_ai_fnc_itemCheck + * [cursorObject, "@bandage"] call ace_medical_ai_fnc_itemCheck * * Public: No */ diff --git a/addons/medical_ai/functions/fnc_playTreatmentAnim.sqf b/addons/medical_ai/functions/fnc_playTreatmentAnim.sqf index b8e77aab43..cb142f0288 100644 --- a/addons/medical_ai/functions/fnc_playTreatmentAnim.sqf +++ b/addons/medical_ai/functions/fnc_playTreatmentAnim.sqf @@ -12,10 +12,11 @@ * None * * Example: - * [bob, true, true] call ACE_medical_ai_fnc_playTreatmentAnim + * [cursorObject, true, true] call ace_medical_ai_fnc_playTreatmentAnim * * Public: No */ + params ["_unit", "_actionName", "_isSelfTreatment"]; TRACE_3("playTreatmentAnim",_unit,_actionName,_isSelfTreatment); diff --git a/addons/medical_ai/functions/fnc_requestMedic.sqf b/addons/medical_ai/functions/fnc_requestMedic.sqf index 9e59181204..0ea2584fbf 100644 --- a/addons/medical_ai/functions/fnc_requestMedic.sqf +++ b/addons/medical_ai/functions/fnc_requestMedic.sqf @@ -4,13 +4,13 @@ * Sends a request to the units assigned medic to heal it. * * Arguments: - * None + * Unit * * Return Value: * None * * Example: - * call ACE_medical_ai_fnc_requestMedic + * cursorObject call ace_medical_ai_fnc_requestMedic * * Public: No */ diff --git a/addons/medical_ai/functions/fnc_wasRequested.sqf b/addons/medical_ai/functions/fnc_wasRequested.sqf index 3b6c1cf059..ffb9aa3780 100644 --- a/addons/medical_ai/functions/fnc_wasRequested.sqf +++ b/addons/medical_ai/functions/fnc_wasRequested.sqf @@ -4,13 +4,13 @@ * Checks if the unit was requested to treat another unit. * * Arguments: - * None + * Unit * * Return Value: * Was requested * * Example: - * call ACE_medical_ai_fnc_wasRequested + * cursorObject call ace_medical_ai_fnc_wasRequested * * Public: No */ From 74de646a0237d558655e6c4b227791c466c4dc43 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Wed, 24 Jul 2024 15:04:53 +0200 Subject: [PATCH 158/290] Medical AI - Fix splints not being applied in special circumstance & setting adding multiple EH (#10141) Several medical AI fixes - Not applying splints if too many medications were taken - Potential nil for _target - Setting could add multiple EH, require mission restart --- addons/medical_ai/XEH_postInit.sqf | 11 +++++++++++ addons/medical_ai/functions/fnc_healUnit.sqf | 4 ++-- .../medical_ai/functions/fnc_healingLogic.sqf | 6 +++--- addons/medical_ai/initSettings.inc.sqf | 18 +++++------------- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/addons/medical_ai/XEH_postInit.sqf b/addons/medical_ai/XEH_postInit.sqf index 518d540478..248c634156 100644 --- a/addons/medical_ai/XEH_postInit.sqf +++ b/addons/medical_ai/XEH_postInit.sqf @@ -20,5 +20,16 @@ _unit setVariable [QGVAR(lastSuppressed), CBA_missionTime]; }] call CBA_fnc_addClassEventHandler; + if (GVAR(requireItems) == 2) then { + ["CAManBase", "InitPost", { + [{ + params ["_unit"]; + if ((!local _unit) || {!alive _unit} || {isPlayer _unit}) exitWith {}; + TRACE_2("replacing medical items on AI",_unit,typeOf _unit); + [_unit] call EFUNC(common,replaceRegisteredItems); + }, _this] call CBA_fnc_execNextFrame; // need to delay a frame before modifying items in a backpack + }, nil, [IGNORE_BASE_UAVPILOTS], true] call CBA_fnc_addClassEventHandler; + }; + #include "stateMachine.inc.sqf" }] call CBA_fnc_addEventHandler; diff --git a/addons/medical_ai/functions/fnc_healUnit.sqf b/addons/medical_ai/functions/fnc_healUnit.sqf index 4f941efc0a..3635088820 100644 --- a/addons/medical_ai/functions/fnc_healUnit.sqf +++ b/addons/medical_ai/functions/fnc_healUnit.sqf @@ -24,10 +24,10 @@ if IS_UNCONSCIOUS(_this) exitWith { // Find next unit to treat private _healQueue = _this getVariable [QGVAR(healQueue), []]; -private _target = _healQueue select 0; +private _target = _healQueue param [0, objNull]; // If unit died or was healed, be lazy and wait for the next tick -if (isNull _target || {!alive _target} || {!(_target call FUNC(isInjured))}) exitWith { +if (!alive _target || {!(_target call FUNC(isInjured))}) exitWith { _this forceSpeed -1; _target forceSpeed -1; _healQueue deleteAt 0; diff --git a/addons/medical_ai/functions/fnc_healingLogic.sqf b/addons/medical_ai/functions/fnc_healingLogic.sqf index aff69d7865..811ef8d14d 100644 --- a/addons/medical_ai/functions/fnc_healingLogic.sqf +++ b/addons/medical_ai/functions/fnc_healingLogic.sqf @@ -87,9 +87,6 @@ switch (true) do { _treatmentArgs = [_target, selectRandom ["leftarm", "rightarm", "leftleg", "rightleg"], "SalineIV"]; _treatmentItem = "@iv"; }; - case ((count (_target getVariable [VAR_MEDICATIONS, []])) >= 6): { - _treatmentEvent = "#tooManyMeds"; - }; case (((_fractures select 4) == 1) && {([_healer, "splint"] call FUNC(itemCheck)) # 0}): { _treatmentEvent = QEGVAR(medical_treatment,splintLocal); @@ -104,6 +101,9 @@ switch (true) do { _treatmentArgs = [_healer, _target, "rightleg"]; _treatmentItem = "splint"; }; + case ((count (_target getVariable [VAR_MEDICATIONS, []])) >= 6): { + _treatmentEvent = "#tooManyMeds"; + }; case ((IS_UNCONSCIOUS(_target) || {_heartRate <= 50}) && {([_healer, "epinephrine"] call FUNC(itemCheck)) # 0}): { if (CBA_missionTime < (_target getVariable [QGVAR(nextEpinephrine), -1])) exitWith { diff --git a/addons/medical_ai/initSettings.inc.sqf b/addons/medical_ai/initSettings.inc.sqf index a2b06519a4..b8ff7e6134 100644 --- a/addons/medical_ai/initSettings.inc.sqf +++ b/addons/medical_ai/initSettings.inc.sqf @@ -1,7 +1,8 @@ private _categoryArray = [ELSTRING(medical,Category), "STR_TEAM_SWITCH_AI"]; [ - QGVAR(enabledFor), "LIST", + QGVAR(enabledFor), + "LIST", [LLSTRING(enableFor_title), LLSTRING(enableFor_desc)], _categoryArray, [ @@ -15,7 +16,8 @@ private _categoryArray = [ELSTRING(medical,Category), "STR_TEAM_SWITCH_AI"]; ] call CBA_fnc_addSetting; [ - QGVAR(requireItems), "LIST", + QGVAR(requireItems), + "LIST", [LSTRING(requireItems_title), LSTRING(requireItems_desc)], _categoryArray, [ @@ -24,16 +26,6 @@ private _categoryArray = [ELSTRING(medical,Category), "STR_TEAM_SWITCH_AI"]; 0 ], true, // isGlobal - { - if (GVAR(requireItems) != 2) exitWith {}; - ["CAManBase", "initPost", { - [{ - params ["_unit"]; - if ((!local _unit) || {!alive _unit} || {isPlayer _unit}) exitWith {}; - TRACE_2("replacing medical items on AI",_unit,typeOf _unit); - [_unit] call EFUNC(common,replaceRegisteredItems); - }, _this] call CBA_fnc_execNextFrame; // need to delay a frame before modifying items in a backpack - }, nil, [IGNORE_BASE_UAVPILOTS], true] call CBA_fnc_addClassEventHandler; - }, + {[QGVAR(requireItems), _this] call EFUNC(common,cbaSettings_settingChanged)}, true // Needs mission restart ] call CBA_fnc_addSetting; From bfbaae65e1234e99ec378d601682651672bc288a Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 25 Jul 2024 01:17:22 +0200 Subject: [PATCH 159/290] Arsenal - Fix mission and campaign insignia (#10143) --- addons/arsenal/XEH_preInit.sqf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/arsenal/XEH_preInit.sqf b/addons/arsenal/XEH_preInit.sqf index 10cc3989e9..248fc16db2 100644 --- a/addons/arsenal/XEH_preInit.sqf +++ b/addons/arsenal/XEH_preInit.sqf @@ -85,10 +85,10 @@ private _insigniaCondition = toString { // Ref fnc_addListBoxItem, 0/nil = configFile, 1 = campaignConfigFile, 2 = missionConfigFile { - GVAR(insigniaCache) set [_x, 1]; + GVAR(insigniaCache) set [configName _x, 1]; } forEach (_insigniaCondition configClasses (campaignConfigFile >> "CfgUnitInsignia")); { - GVAR(insigniaCache) set [_x, 2]; + GVAR(insigniaCache) set [configName _x, 2]; } forEach (_insigniaCondition configClasses (missionConfigFile >> "CfgUnitInsignia")); ADDON = true; From e99d6d9381cdcecea2f9919bd849ae219583c3a9 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 25 Jul 2024 07:49:45 +0200 Subject: [PATCH 160/290] Medical AI - Make AI take tourniquets into account when medicing (#10142) * Make AI take tourniquets into account when medicing * Update fnc_healingLogic.sqf --- .../medical_ai/functions/fnc_healingLogic.sqf | 47 +++++++++++++++---- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/addons/medical_ai/functions/fnc_healingLogic.sqf b/addons/medical_ai/functions/fnc_healingLogic.sqf index 811ef8d14d..a007b83e4c 100644 --- a/addons/medical_ai/functions/fnc_healingLogic.sqf +++ b/addons/medical_ai/functions/fnc_healingLogic.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: BaerMitUmlaut, PabstMirror - * Applies healing to target + * Applies healing to target. * * Arguments: * 0: Healer @@ -16,6 +16,9 @@ * Public: No */ +// TODO: Add AI tourniquet behaviour +// For now, AI handle player or otherwise scripted tourniquets only + params ["_healer", "_target"]; (_healer getVariable [QGVAR(currentTreatment), [-1]]) params ["_finishTime", "_treatmentTarget", "_treatmentEvent", "_treatmentArgs", "_treatmentItem"]; @@ -40,9 +43,33 @@ if (_finishTime > 0) exitWith { }; }; +// Find a suitable limb (no tourniquets) for injecting and giving IVs +private _fnc_findNoTourniquet = { + private _bodyPart = ""; + private _bodyParts = ["leftarm", "rightarm", "leftleg", "rightleg"]; + private _bodyPartsSaved = +_bodyParts; + + while {_bodyParts isNotEqualTo []} do { + _bodyPart = selectRandom _bodyParts; + + // If no tourniquet on, use that body part + if (_tourniquets select (ALL_BODY_PARTS find _bodyPart) == 0) exitWith {}; + + _bodyParts deleteAt (_bodyParts find _bodyPart); + }; + + // If all limbs have tourniquets, use random limb + if (_bodyPart == "") then { + _bodyPart = selectRandom _bodyPartsSaved; + }; + + _bodyPart +}; + private _isMedic = [_healer] call EFUNC(medical_treatment,isMedic); private _heartRate = GET_HEART_RATE(_target); private _fractures = GET_FRACTURES(_target); +private _tourniquets = GET_TOURNIQUETS(_target); private _treatmentEvent = "#none"; private _treatmentArgs = []; @@ -54,11 +81,13 @@ switch (true) do { // Select first bleeding wound and bandage it private _selection = "?"; { - private _foundBleeding = _y findIf { - _x params ["", "_amount", "_percentage"]; - (_amount * _percentage) > 0 - }; - if (_foundBleeding != -1) exitWith { _selection = _x; }; + // Ignore tourniqueted limbs + if (_tourniquets select (ALL_BODY_PARTS find _x) == 0 && { + _y findIf { + _x params ["", "_amount", "_percentage"]; + (_amount * _percentage) > 0 + } != -1} + ) exitWith { _selection = _x; }; } forEach GET_OPEN_WOUNDS(_target); _treatmentEvent = QEGVAR(medical_treatment,bandageLocal); _treatmentTime = 5; @@ -84,7 +113,7 @@ switch (true) do { }; _treatmentEvent = QEGVAR(medical_treatment,ivBagLocal); _treatmentTime = 5; - _treatmentArgs = [_target, selectRandom ["leftarm", "rightarm", "leftleg", "rightleg"], "SalineIV"]; + _treatmentArgs = [_target, call _fnc_findNoTourniquet, "SalineIV"]; _treatmentItem = "@iv"; }; case (((_fractures select 4) == 1) @@ -115,7 +144,7 @@ switch (true) do { _target setVariable [QGVAR(nextEpinephrine), CBA_missionTime + 10]; _treatmentEvent = QEGVAR(medical_treatment,medicationLocal); _treatmentTime = 2.5; - _treatmentArgs = [_target, selectRandom ["leftarm", "rightarm", "leftleg", "rightleg"], "Epinephrine"]; + _treatmentArgs = [_target, call _fnc_findNoTourniquet, "Epinephrine"]; _treatmentItem = "epinephrine"; }; case (((GET_PAIN_PERCEIVED(_target) > 0.25) || {_heartRate >= 180}) @@ -129,7 +158,7 @@ switch (true) do { _target setVariable [QGVAR(nextMorphine), CBA_missionTime + 30]; _treatmentEvent = QEGVAR(medical_treatment,medicationLocal); _treatmentTime = 2.5; - _treatmentArgs = [_target, selectRandom ["leftarm", "rightarm", "leftleg", "rightleg"], "Morphine"]; + _treatmentArgs = [_target, call _fnc_findNoTourniquet, "Morphine"]; _treatmentItem = "morphine"; }; }; From b85150e6ebc958e951b9d000a55da39486aa7479 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 25 Jul 2024 20:34:26 +0200 Subject: [PATCH 161/290] Explosives - Only add "detonate all" action for dead man switch when necessary (#10146) Only add detonate all when necessary --- .../functions/fnc_addDetonateActions.sqf | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/addons/explosives/functions/fnc_addDetonateActions.sqf b/addons/explosives/functions/fnc_addDetonateActions.sqf index d950278c35..06c4f3c8be 100644 --- a/addons/explosives/functions/fnc_addDetonateActions.sqf +++ b/addons/explosives/functions/fnc_addDetonateActions.sqf @@ -92,19 +92,6 @@ if (_detonator != "ACE_DeadManSwitch") then { ]; }; } else { - //Add action to detonate all explosives (including the inventory explosive): - _children pushBack [ - [ - "Explosive_All_Deadman", - LLSTRING(DetonateAll), - getText (configFile >> "CfgWeapons" >> _detonator >> "picture"), - {[_player] call FUNC(onIncapacitated)}, - {true} - ] call EFUNC(interact_menu,createAction), - [], - _unit - ]; - //Adds actions for the explosives you can connect to the deadman switch. private _connectedInventoryExplosive = _unit getVariable [QGVAR(deadmanInvExplosive), ""]; if ((_connectedInventoryExplosive != "") && {!(_connectedInventoryExplosive in (magazines _unit))}) then { @@ -113,6 +100,22 @@ if (_detonator != "ACE_DeadManSwitch") then { }; _connectedInventoryExplosive = _unit getVariable [QGVAR(deadmanInvExplosive), ""]; + + //Add action to detonate all explosives (including the inventory explosive): + if (_connectedInventoryExplosive != "" || {count _explosivesList > 1}) then { + _children pushBack [ + [ + "Explosive_All_Deadman", + LLSTRING(DetonateAll), + getText (configFile >> "CfgWeapons" >> _detonator >> "picture"), + {[_player] call FUNC(onIncapacitated)}, + {true} + ] call EFUNC(interact_menu,createAction), + [], + _unit + ]; + }; + if (_connectedInventoryExplosive != "") then { //Add the disconnect action private _magConfig = configFile >> "CfgMagazines" >> _connectedInventoryExplosive; From 8eefffe8110af5ed97345e74dbd28a8db04d8371 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 27 Jul 2024 14:43:07 +0200 Subject: [PATCH 162/290] Recoil - Code cleanup (#10150) * Recoil code cleanup * Store recoil values as numbers in config, only `compile` if needed * Updated header --------- Co-authored-by: PabstMirror --- addons/recoil/$PBOPREFIX$ | 2 +- addons/recoil/CfgEventHandlers.hpp | 1 - addons/recoil/CfgMoves.hpp | 1 - addons/recoil/CfgRecoils.hpp | 551 +++++++++++------------ addons/recoil/XEH_PREP.hpp | 1 - addons/recoil/XEH_preInit.sqf | 2 + addons/recoil/functions/fnc_camshake.sqf | 29 +- 7 files changed, 292 insertions(+), 295 deletions(-) diff --git a/addons/recoil/$PBOPREFIX$ b/addons/recoil/$PBOPREFIX$ index 1ab9ffa5e1..efd38b75ed 100644 --- a/addons/recoil/$PBOPREFIX$ +++ b/addons/recoil/$PBOPREFIX$ @@ -1 +1 @@ -z\ace\addons\recoil \ No newline at end of file +z\ace\addons\recoil diff --git a/addons/recoil/CfgEventHandlers.hpp b/addons/recoil/CfgEventHandlers.hpp index 6c29240403..f6503c2479 100644 --- a/addons/recoil/CfgEventHandlers.hpp +++ b/addons/recoil/CfgEventHandlers.hpp @@ -1,4 +1,3 @@ - class Extended_PreStart_EventHandlers { class ADDON { init = QUOTE(call COMPILE_SCRIPT(XEH_preStart)); diff --git a/addons/recoil/CfgMoves.hpp b/addons/recoil/CfgMoves.hpp index 29bca9c81a..aca9d93f3c 100644 --- a/addons/recoil/CfgMoves.hpp +++ b/addons/recoil/CfgMoves.hpp @@ -1,4 +1,3 @@ - // Completely disable BI's camshake on fire. #define ACE_CAMSHAKEFIRE_BASE 0 #define ACE_CAMSHAKEFIRE_LESS 0 diff --git a/addons/recoil/CfgRecoils.hpp b/addons/recoil/CfgRecoils.hpp index c6482937ae..1c0751080c 100644 --- a/addons/recoil/CfgRecoils.hpp +++ b/addons/recoil/CfgRecoils.hpp @@ -1,4 +1,3 @@ - #define KICKBACK 1.4 #define MUZZLETEMP 1.2 @@ -15,28 +14,28 @@ class CfgRecoils { // doc: http://forums.bistudio.com/showthread.php?188999-Recoil-Overhaul-Feedback&s=dba8590ec07adb5ffa87f72d38dde6fc&p=2886744&viewfull=1#post2886744 // {horizontal axis position, vertical axis position, horizontal magnitude, vertical magnitude} muzzleOuter[] = { - QUOTE(0*MUZZLERIGHT_POS), - QUOTE(0.4*MUZZLECLIMB_POS), - QUOTE(0.5*MUZZLERIGHT_MAG), - QUOTE(0.6*MUZZLECLIMB_MAG) + 0*MUZZLERIGHT_POS, + 0.4*MUZZLECLIMB_POS, + 0.5*MUZZLERIGHT_MAG, + 0.6*MUZZLECLIMB_MAG }; // restricted area inside the outer ellipse where the recoil cannot end muzzleInner[] = {0,0.05,0.2,0.2}; // minimum and maximum interval for backward force kickBack[] = { - QUOTE(0.05*KICKBACK), - QUOTE(0.1*KICKBACK) + 0.05*KICKBACK, + 0.1*KICKBACK }; - permanent = QUOTE(0.1*MUZZLEPERM); - temporary = QUOTE(0.01*MUZZLETEMP); + permanent = 0.1*MUZZLEPERM; + temporary = 0.01*MUZZLETEMP; }; class recoil_default: Default { muzzleOuter[] = { - QUOTE(0.3*MUZZLERIGHT_POS), - QUOTE(1*MUZZLECLIMB_POS), - QUOTE(0.3*MUZZLERIGHT_MAG), - QUOTE(0.2*MUZZLECLIMB_MAG) + 0.3*MUZZLERIGHT_POS, + 1*MUZZLECLIMB_POS, + 0.3*MUZZLERIGHT_MAG, + 0.2*MUZZLECLIMB_MAG }; muzzleInner[] = {0, 0, @@ -44,528 +43,528 @@ class CfgRecoils { 0.1 }; kickBack[] = { - QUOTE(0.03*KICKBACK), - QUOTE(0.06*KICKBACK) + 0.03*KICKBACK, + 0.06*KICKBACK }; - permanent = QUOTE(0.1*MUZZLEPERM); - temporary = QUOTE(0.01*MUZZLETEMP); + permanent = 0.1*MUZZLEPERM; + temporary = 0.01*MUZZLETEMP; }; class recoil_mk20: recoil_default { muzzleOuter[] = { - QUOTE(0.2*MUZZLERIGHT_POS), - QUOTE(0.6*MUZZLECLIMB_POS), - QUOTE(0.2*MUZZLERIGHT_MAG), - QUOTE(0.2*MUZZLECLIMB_MAG) + 0.2*MUZZLERIGHT_POS, + 0.6*MUZZLECLIMB_POS, + 0.2*MUZZLERIGHT_MAG, + 0.2*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.01*KICKBACK), - QUOTE(0.03*KICKBACK) + 0.01*KICKBACK, + 0.03*KICKBACK }; - temporary = QUOTE(0.01*MUZZLETEMP); + temporary = 0.01*MUZZLETEMP; }; class recoil_mk20c: recoil_default { muzzleOuter[] = { - QUOTE(0.2*MUZZLERIGHT_POS), - QUOTE(0.8*MUZZLECLIMB_POS), - QUOTE(0.3*MUZZLERIGHT_MAG), - QUOTE(0.2*MUZZLECLIMB_MAG) + 0.2*MUZZLERIGHT_POS, + 0.8*MUZZLECLIMB_POS, + 0.3*MUZZLERIGHT_MAG, + 0.2*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.02*KICKBACK), - QUOTE(0.04*KICKBACK) + 0.02*KICKBACK, + 0.04*KICKBACK }; - temporary = QUOTE(0.015*MUZZLETEMP); + temporary = 0.015*MUZZLETEMP; }; class recoil_trg20: recoil_default { muzzleOuter[] = { - QUOTE(0.2*MUZZLERIGHT_POS), - QUOTE(1*MUZZLECLIMB_POS), - QUOTE(0.3*MUZZLERIGHT_MAG), - QUOTE(0.3*MUZZLECLIMB_MAG) + 0.2*MUZZLERIGHT_POS, + 1*MUZZLECLIMB_POS, + 0.3*MUZZLERIGHT_MAG, + 0.3*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.02*KICKBACK), - QUOTE(0.04*KICKBACK) + 0.02*KICKBACK, + 0.04*KICKBACK }; - temporary = QUOTE(0.015*MUZZLETEMP); + temporary = 0.015*MUZZLETEMP; }; class recoil_trg21: recoil_default { muzzleOuter[] = { - QUOTE(0.2*MUZZLERIGHT_POS), - QUOTE(0.8*MUZZLECLIMB_POS), - QUOTE(0.3*MUZZLERIGHT_MAG), - QUOTE(0.2*MUZZLECLIMB_MAG) + 0.2*MUZZLERIGHT_POS, + 0.8*MUZZLECLIMB_POS, + 0.3*MUZZLERIGHT_MAG, + 0.2*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.01*KICKBACK), - QUOTE(0.03*KICKBACK) + 0.01*KICKBACK, + 0.03*KICKBACK }; - temporary = QUOTE(0.01*MUZZLETEMP); + temporary = 0.01*MUZZLETEMP; }; class recoil_mx: recoil_default { muzzleOuter[] = { - QUOTE(0.3*MUZZLERIGHT_POS), - QUOTE(1*MUZZLECLIMB_POS), - QUOTE(0.4*MUZZLERIGHT_MAG), - QUOTE(0.3*MUZZLECLIMB_MAG) + 0.3*MUZZLERIGHT_POS, + 1*MUZZLECLIMB_POS, + 0.4*MUZZLERIGHT_MAG, + 0.3*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.02*KICKBACK), - QUOTE(0.04*KICKBACK) + 0.02*KICKBACK, + 0.04*KICKBACK }; - temporary = QUOTE(0.01*MUZZLETEMP); + temporary = 0.01*MUZZLETEMP; }; class recoil_mxc: recoil_default { muzzleOuter[] = { - QUOTE(0.3*MUZZLERIGHT_POS), - QUOTE(1.2*MUZZLECLIMB_POS), - QUOTE(0.4*MUZZLERIGHT_MAG), - QUOTE(0.3*MUZZLECLIMB_MAG) + 0.3*MUZZLERIGHT_POS, + 1.2*MUZZLECLIMB_POS, + 0.4*MUZZLERIGHT_MAG, + 0.3*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.03*KICKBACK), - QUOTE(0.06*KICKBACK) + 0.03*KICKBACK, + 0.06*KICKBACK }; - temporary = QUOTE(0.015*MUZZLETEMP); + temporary = 0.015*MUZZLETEMP; }; class recoil_sw: recoil_default { muzzleOuter[] = { - QUOTE(0.3*MUZZLERIGHT_POS), - QUOTE(0.8*MUZZLECLIMB_POS), - QUOTE(0.5*MUZZLERIGHT_MAG), - QUOTE(0.2*MUZZLECLIMB_MAG) + 0.3*MUZZLERIGHT_POS, + 0.8*MUZZLECLIMB_POS, + 0.5*MUZZLERIGHT_MAG, + 0.2*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.02*KICKBACK), - QUOTE(0.04*KICKBACK) + 0.02*KICKBACK, + 0.04*KICKBACK }; - temporary = QUOTE(0.01*MUZZLETEMP); //0.005*MUZZLETEMP; + temporary = 0.01*MUZZLETEMP; //0.005*MUZZLETEMP; }; class recoil_mxm: recoil_default { muzzleOuter[] = { - QUOTE(0.3*MUZZLERIGHT_POS), - QUOTE(0.8*MUZZLECLIMB_POS), - QUOTE(0.4*MUZZLERIGHT_MAG), - QUOTE(0.3*MUZZLECLIMB_MAG) + 0.3*MUZZLERIGHT_POS, + 0.8*MUZZLECLIMB_POS, + 0.4*MUZZLERIGHT_MAG, + 0.3*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.02*KICKBACK), - QUOTE(0.04*KICKBACK) + 0.02*KICKBACK, + 0.04*KICKBACK }; - temporary = QUOTE(0.01*MUZZLETEMP); + temporary = 0.01*MUZZLETEMP; }; class recoil_ktb: recoil_default { muzzleOuter[] = { - QUOTE(0.3*MUZZLERIGHT_POS), - QUOTE(1*MUZZLECLIMB_POS), - QUOTE(0.3*MUZZLERIGHT_MAG), - QUOTE(0.3*MUZZLECLIMB_MAG) + 0.3*MUZZLERIGHT_POS, + 1*MUZZLECLIMB_POS, + 0.3*MUZZLERIGHT_MAG, + 0.3*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.02*KICKBACK), - QUOTE(0.04*KICKBACK) + 0.02*KICKBACK, + 0.04*KICKBACK }; - temporary = QUOTE(0.01*MUZZLETEMP); + temporary = 0.01*MUZZLETEMP; }; class recoil_ktbc: recoil_default { muzzleOuter[] = { - QUOTE(0.3*MUZZLERIGHT_POS), - QUOTE(1.2*MUZZLECLIMB_POS), - QUOTE(0.3*MUZZLERIGHT_MAG), - QUOTE(0.3*MUZZLECLIMB_MAG) + 0.3*MUZZLERIGHT_POS, + 1.2*MUZZLECLIMB_POS, + 0.3*MUZZLERIGHT_MAG, + 0.3*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.03*KICKBACK), - QUOTE(0.06*KICKBACK) + 0.03*KICKBACK, + 0.06*KICKBACK }; - temporary = QUOTE(0.015*MUZZLETEMP); + temporary = 0.015*MUZZLETEMP; }; class recoil_smg_01: recoil_default { muzzleOuter[] = { - QUOTE(0.1*MUZZLERIGHT_POS), - QUOTE(0.8*MUZZLECLIMB_POS), - QUOTE(0.3*MUZZLERIGHT_MAG), - QUOTE(0.2*MUZZLECLIMB_MAG) + 0.1*MUZZLERIGHT_POS, + 0.8*MUZZLECLIMB_POS, + 0.3*MUZZLERIGHT_MAG, + 0.2*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.01*KICKBACK), - QUOTE(0.03*KICKBACK) + 0.01*KICKBACK, + 0.03*KICKBACK }; - temporary = QUOTE(0.015*MUZZLETEMP); + temporary = 0.015*MUZZLETEMP; }; class recoil_smg_02: recoil_default { muzzleOuter[] = { - QUOTE(0.1*MUZZLERIGHT_POS), - QUOTE(0.6*MUZZLECLIMB_POS), - QUOTE(0.2*MUZZLERIGHT_MAG), - QUOTE(0.2*MUZZLECLIMB_MAG) + 0.1*MUZZLERIGHT_POS, + 0.6*MUZZLECLIMB_POS, + 0.2*MUZZLERIGHT_MAG, + 0.2*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.01*KICKBACK), - QUOTE(0.02*KICKBACK) + 0.01*KICKBACK, + 0.02*KICKBACK }; - temporary = QUOTE(0.01*MUZZLETEMP); + temporary = 0.01*MUZZLETEMP; }; class recoil_pdw: recoil_default { muzzleOuter[] = { - QUOTE(0.2*MUZZLERIGHT_POS), - QUOTE(1*MUZZLECLIMB_POS), - QUOTE(0.3*MUZZLERIGHT_MAG), - QUOTE(0.3*MUZZLECLIMB_MAG) + 0.2*MUZZLERIGHT_POS, + 1*MUZZLECLIMB_POS, + 0.3*MUZZLERIGHT_MAG, + 0.3*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.02*KICKBACK), - QUOTE(0.04*KICKBACK) + 0.02*KICKBACK, + 0.04*KICKBACK }; - temporary = QUOTE(0.02*MUZZLETEMP); + temporary = 0.02*MUZZLETEMP; }; class recoil_sdar: recoil_default { muzzleOuter[] = { - QUOTE(0.2*MUZZLERIGHT_POS), - QUOTE(1*MUZZLECLIMB_POS), - QUOTE(0.3*MUZZLERIGHT_MAG), - QUOTE(0.3*MUZZLECLIMB_MAG) + 0.2*MUZZLERIGHT_POS, + 1*MUZZLECLIMB_POS, + 0.3*MUZZLERIGHT_MAG, + 0.3*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.02*KICKBACK), - QUOTE(0.04*KICKBACK) + 0.02*KICKBACK, + 0.04*KICKBACK }; - temporary = QUOTE(0.01*MUZZLETEMP); + temporary = 0.01*MUZZLETEMP; }; class recoil_pistol_p07: recoil_default { muzzleOuter[] = { - QUOTE(0.2*MUZZLERIGHT_POS), - QUOTE(1*MUZZLECLIMB_POS), - QUOTE(0.2*MUZZLERIGHT_MAG), - QUOTE(0.3*MUZZLECLIMB_MAG) + 0.2*MUZZLERIGHT_POS, + 1*MUZZLECLIMB_POS, + 0.2*MUZZLERIGHT_MAG, + 0.3*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.03*KICKBACK), - QUOTE(0.06*KICKBACK) + 0.03*KICKBACK, + 0.06*KICKBACK }; - temporary = QUOTE(0.03*MUZZLETEMP); + temporary = 0.03*MUZZLETEMP; }; class recoil_pistol_rook40: recoil_default { muzzleOuter[] = { - QUOTE(0.2*MUZZLERIGHT_POS), - QUOTE(1*MUZZLECLIMB_POS), - QUOTE(0.2*MUZZLERIGHT_MAG), - QUOTE(0.3*MUZZLECLIMB_MAG) + 0.2*MUZZLERIGHT_POS, + 1*MUZZLECLIMB_POS, + 0.2*MUZZLERIGHT_MAG, + 0.3*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.03*KICKBACK), - QUOTE(0.06*KICKBACK) + 0.03*KICKBACK, + 0.06*KICKBACK }; - temporary = QUOTE(0.02*MUZZLETEMP); + temporary = 0.02*MUZZLETEMP; }; class recoil_pistol_acpc2: recoil_default { muzzleOuter[] = { - QUOTE(0.2*MUZZLERIGHT_POS), - QUOTE(1.5*MUZZLECLIMB_POS), - QUOTE(0.2*MUZZLERIGHT_MAG), - QUOTE(0.3*MUZZLECLIMB_MAG) + 0.2*MUZZLERIGHT_POS, + 1.5*MUZZLECLIMB_POS, + 0.2*MUZZLERIGHT_MAG, + 0.3*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.04*KICKBACK), - QUOTE(0.08*KICKBACK) + 0.04*KICKBACK, + 0.08*KICKBACK }; - temporary = QUOTE(0.04*MUZZLETEMP); + temporary = 0.04*MUZZLETEMP; }; class recoil_pistol_4five: recoil_default { muzzleOuter[] = { - QUOTE(0.2*MUZZLERIGHT_POS), - QUOTE(1.5*MUZZLECLIMB_POS), - QUOTE(0.2*MUZZLERIGHT_MAG), - QUOTE(0.3*MUZZLECLIMB_MAG) + 0.2*MUZZLERIGHT_POS, + 1.5*MUZZLECLIMB_POS, + 0.2*MUZZLERIGHT_MAG, + 0.3*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.04*KICKBACK), - QUOTE(0.08*KICKBACK) + 0.04*KICKBACK, + 0.08*KICKBACK }; - temporary = QUOTE(0.06*MUZZLETEMP); + temporary = 0.06*MUZZLETEMP; }; class recoil_pistol_zubr: recoil_default { muzzleOuter[] = { - QUOTE(0.2*MUZZLERIGHT_POS), - QUOTE(1.5*MUZZLECLIMB_POS), - QUOTE(0.2*MUZZLERIGHT_MAG), - QUOTE(0.3*MUZZLECLIMB_MAG) + 0.2*MUZZLERIGHT_POS, + 1.5*MUZZLECLIMB_POS, + 0.2*MUZZLERIGHT_MAG, + 0.3*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.04*KICKBACK), - QUOTE(0.08*KICKBACK) + 0.04*KICKBACK, + 0.08*KICKBACK }; - temporary = QUOTE(0.08*MUZZLETEMP); + temporary = 0.08*MUZZLETEMP; }; class recoil_pistol_signal: recoil_default { muzzleOuter[] = { - QUOTE(0.2*MUZZLERIGHT_POS), - QUOTE(1.5*MUZZLECLIMB_POS), - QUOTE(0.2*MUZZLERIGHT_MAG), - QUOTE(0.3*MUZZLECLIMB_MAG) + 0.2*MUZZLERIGHT_POS, + 1.5*MUZZLECLIMB_POS, + 0.2*MUZZLERIGHT_MAG, + 0.3*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.02*KICKBACK), - QUOTE(0.04*KICKBACK) + 0.02*KICKBACK, + 0.04*KICKBACK }; - temporary = QUOTE(0.02*MUZZLETEMP); + temporary = 0.02*MUZZLETEMP; }; class recoil_rpg: recoil_default { muzzleOuter[] = { - QUOTE(2*MUZZLERIGHT_POS), - QUOTE(3*MUZZLECLIMB_POS), - QUOTE(1*MUZZLERIGHT_MAG), - QUOTE(0.5*MUZZLECLIMB_MAG) + 2*MUZZLERIGHT_POS, + 3*MUZZLECLIMB_POS, + 1*MUZZLERIGHT_MAG, + 0.5*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.08*KICKBACK), - QUOTE(0.1*KICKBACK) + 0.08*KICKBACK, + 0.1*KICKBACK }; - temporary = QUOTE(0.1*MUZZLETEMP); + temporary = 0.1*MUZZLETEMP; }; class recoil_nlaw: recoil_default { muzzleOuter[] = { - QUOTE(2*MUZZLERIGHT_POS), - QUOTE(3*MUZZLECLIMB_POS), - QUOTE(1*MUZZLERIGHT_MAG), - QUOTE(0.5*MUZZLECLIMB_MAG) + 2*MUZZLERIGHT_POS, + 3*MUZZLECLIMB_POS, + 1*MUZZLERIGHT_MAG, + 0.5*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.06*KICKBACK), - QUOTE(0.08*KICKBACK) + 0.06*KICKBACK, + 0.08*KICKBACK }; - temporary = QUOTE(0.08*MUZZLETEMP); + temporary = 0.08*MUZZLETEMP; }; class recoil_titan_long: recoil_default { muzzleOuter[] = { - QUOTE(2*MUZZLERIGHT_POS), - QUOTE(3*MUZZLECLIMB_POS), - QUOTE(1*MUZZLERIGHT_MAG), - QUOTE(0.5*MUZZLECLIMB_MAG) + 2*MUZZLERIGHT_POS, + 3*MUZZLECLIMB_POS, + 1*MUZZLERIGHT_MAG, + 0.5*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.1*KICKBACK), - QUOTE(0.12*KICKBACK) + 0.1*KICKBACK, + 0.12*KICKBACK }; - temporary = QUOTE(0.15*MUZZLETEMP); + temporary = 0.15*MUZZLETEMP; }; class recoil_titan_short: recoil_default { muzzleOuter[] = { - QUOTE(2*MUZZLERIGHT_POS), - QUOTE(3*MUZZLECLIMB_POS), - QUOTE(1*MUZZLERIGHT_MAG), - QUOTE(0.5*MUZZLECLIMB_MAG) + 2*MUZZLERIGHT_POS, + 3*MUZZLECLIMB_POS, + 1*MUZZLERIGHT_MAG, + 0.5*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.1*KICKBACK), - QUOTE(0.12*KICKBACK) + 0.1*KICKBACK, + 0.12*KICKBACK }; - temporary = QUOTE(0.12*MUZZLETEMP); + temporary = 0.12*MUZZLETEMP; }; class recoil_mk200: recoil_default { muzzleOuter[] = { - QUOTE(0.4*MUZZLERIGHT_POS), - QUOTE(0.6*MUZZLECLIMB_POS), - QUOTE(0.6*MUZZLERIGHT_MAG), - QUOTE(0.2*MUZZLECLIMB_MAG) + 0.4*MUZZLERIGHT_POS, + 0.6*MUZZLECLIMB_POS, + 0.6*MUZZLERIGHT_MAG, + 0.2*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.03*KICKBACK), - QUOTE(0.06*KICKBACK) + 0.03*KICKBACK, + 0.06*KICKBACK }; - temporary = QUOTE(0.01*MUZZLETEMP); //0.005*MUZZLETEMP; + temporary = 0.01*MUZZLETEMP; //0.005*MUZZLETEMP; }; class recoil_zafir: recoil_default { muzzleOuter[] = { - QUOTE(0.5*MUZZLERIGHT_POS), - QUOTE(1*MUZZLECLIMB_POS), - QUOTE(0.7*MUZZLERIGHT_MAG), - QUOTE(0.3*MUZZLECLIMB_MAG) + 0.5*MUZZLERIGHT_POS, + 1*MUZZLECLIMB_POS, + 0.7*MUZZLERIGHT_MAG, + 0.3*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.02*KICKBACK), - QUOTE(0.08*KICKBACK) + 0.02*KICKBACK, + 0.08*KICKBACK }; - temporary = QUOTE(0.01*MUZZLETEMP); //0.005*MUZZLETEMP; + temporary = 0.01*MUZZLETEMP; //0.005*MUZZLETEMP; }; class recoil_m320: recoil_default { muzzleOuter[] = { - QUOTE(1*MUZZLERIGHT_POS), - QUOTE(3*MUZZLECLIMB_POS), - QUOTE(0.5*MUZZLERIGHT_MAG), - QUOTE(0.6*MUZZLECLIMB_MAG) + 1*MUZZLERIGHT_POS, + 3*MUZZLECLIMB_POS, + 0.5*MUZZLERIGHT_MAG, + 0.6*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.08*KICKBACK), - QUOTE(0.1*KICKBACK) + 0.08*KICKBACK, + 0.1*KICKBACK }; - temporary = QUOTE(0.02*MUZZLETEMP); + temporary = 0.02*MUZZLETEMP; }; class recoil_gm6: recoil_default { muzzleOuter[] = { - QUOTE(1.4*MUZZLERIGHT_POS), - QUOTE(3.5*MUZZLECLIMB_POS), - QUOTE(0.7*MUZZLERIGHT_MAG), - QUOTE(0.8*MUZZLECLIMB_MAG) + 1.4*MUZZLERIGHT_POS, + 3.5*MUZZLECLIMB_POS, + 0.7*MUZZLERIGHT_MAG, + 0.8*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.1*KICKBACK), - QUOTE(0.12*KICKBACK) + 0.1*KICKBACK, + 0.12*KICKBACK }; - temporary = QUOTE(0.025*MUZZLETEMP); + temporary = 0.025*MUZZLETEMP; }; class recoil_ebr: recoil_default { muzzleOuter[] = { - QUOTE(0.4*MUZZLERIGHT_POS), - QUOTE(1.5*MUZZLECLIMB_POS), - QUOTE(0.6*MUZZLERIGHT_MAG), - QUOTE(0.4*MUZZLECLIMB_MAG) + 0.4*MUZZLERIGHT_POS, + 1.5*MUZZLECLIMB_POS, + 0.6*MUZZLERIGHT_MAG, + 0.4*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.04*KICKBACK), - QUOTE(0.07*KICKBACK) + 0.04*KICKBACK, + 0.07*KICKBACK }; - temporary = QUOTE(0.01*MUZZLETEMP); + temporary = 0.01*MUZZLETEMP; }; class recoil_dmr_01: recoil_default { muzzleOuter[] = { - QUOTE(0.5*MUZZLERIGHT_POS), - QUOTE(2*MUZZLECLIMB_POS), - QUOTE(0.5*MUZZLERIGHT_MAG), - QUOTE(0.5*MUZZLECLIMB_MAG) + 0.5*MUZZLERIGHT_POS, + 2*MUZZLECLIMB_POS, + 0.5*MUZZLERIGHT_MAG, + 0.5*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.03*KICKBACK), - QUOTE(0.08*KICKBACK) + 0.03*KICKBACK, + 0.08*KICKBACK }; - temporary = QUOTE(0.015*MUZZLETEMP); + temporary = 0.015*MUZZLETEMP; }; class recoil_dmr_02: recoil_default { muzzleOuter[] = { - QUOTE(0.5*MUZZLERIGHT_POS), - QUOTE(2.5*MUZZLECLIMB_POS), - QUOTE(0.6*MUZZLERIGHT_MAG), - QUOTE(0.5*MUZZLECLIMB_MAG) + 0.5*MUZZLERIGHT_POS, + 2.5*MUZZLECLIMB_POS, + 0.6*MUZZLERIGHT_MAG, + 0.5*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.06*KICKBACK), - QUOTE(0.08*KICKBACK) + 0.06*KICKBACK, + 0.08*KICKBACK }; - temporary = QUOTE(0.01*MUZZLETEMP); + temporary = 0.01*MUZZLETEMP; }; class recoil_dmr_03: recoil_default { muzzleOuter[] = { - QUOTE(0.3*MUZZLERIGHT_POS), - QUOTE(1.5*MUZZLECLIMB_POS), - QUOTE(0.5*MUZZLERIGHT_MAG), - QUOTE(0.4*MUZZLECLIMB_MAG) + 0.3*MUZZLERIGHT_POS, + 1.5*MUZZLECLIMB_POS, + 0.5*MUZZLERIGHT_MAG, + 0.4*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.03*KICKBACK), - QUOTE(0.06*KICKBACK) + 0.03*KICKBACK, + 0.06*KICKBACK }; - temporary = QUOTE(0.005*MUZZLETEMP); + temporary = 0.005*MUZZLETEMP; }; class recoil_dmr_04: recoil_default { muzzleOuter[] = { - QUOTE(0.4*MUZZLERIGHT_POS), - QUOTE(1.5*MUZZLECLIMB_POS), - QUOTE(0.5*MUZZLERIGHT_MAG), - QUOTE(0.4*MUZZLECLIMB_MAG) + 0.4*MUZZLERIGHT_POS, + 1.5*MUZZLECLIMB_POS, + 0.5*MUZZLERIGHT_MAG, + 0.4*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.02*KICKBACK), - QUOTE(0.04*KICKBACK) + 0.02*KICKBACK, + 0.04*KICKBACK }; - temporary = QUOTE(0.015*MUZZLETEMP); + temporary = 0.015*MUZZLETEMP; }; class recoil_dmr_05: recoil_default { muzzleOuter[] = { - QUOTE(0.5*MUZZLERIGHT_POS), - QUOTE(2.5*MUZZLECLIMB_POS), - QUOTE(0.8*MUZZLERIGHT_MAG), - QUOTE(0.6*MUZZLECLIMB_MAG) + 0.5*MUZZLERIGHT_POS, + 2.5*MUZZLECLIMB_POS, + 0.8*MUZZLERIGHT_MAG, + 0.6*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.08*KICKBACK), - QUOTE(0.1*KICKBACK) + 0.08*KICKBACK, + 0.1*KICKBACK }; - temporary = QUOTE(0.01*MUZZLETEMP); + temporary = 0.01*MUZZLETEMP; }; class recoil_dmr_06: recoil_default { muzzleOuter[] = { - QUOTE(0.5*MUZZLERIGHT_POS), - QUOTE(2*MUZZLECLIMB_POS), - QUOTE(0.7*MUZZLERIGHT_MAG), - QUOTE(0.5*MUZZLECLIMB_MAG) + 0.5*MUZZLERIGHT_POS, + 2*MUZZLECLIMB_POS, + 0.7*MUZZLERIGHT_MAG, + 0.5*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.05*KICKBACK), - QUOTE(0.1*KICKBACK) + 0.05*KICKBACK, + 0.1*KICKBACK }; - temporary = QUOTE(0.01*MUZZLETEMP); + temporary = 0.01*MUZZLETEMP; }; class recoil_mmg_01: recoil_default { muzzleOuter[] = { - QUOTE(0.6*MUZZLERIGHT_POS), - QUOTE(1.5*MUZZLECLIMB_POS), - QUOTE(0.8*MUZZLERIGHT_MAG), - QUOTE(0.3*MUZZLECLIMB_MAG) + 0.6*MUZZLERIGHT_POS, + 1.5*MUZZLECLIMB_POS, + 0.8*MUZZLERIGHT_MAG, + 0.3*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.02*KICKBACK), - QUOTE(0.08*KICKBACK) + 0.02*KICKBACK, + 0.08*KICKBACK }; - temporary = QUOTE(0.01*MUZZLETEMP); //0.005*MUZZLETEMP; + temporary = 0.01*MUZZLETEMP; //0.005*MUZZLETEMP; }; class recoil_mmg_02: recoil_default { muzzleOuter[] = { - QUOTE(0.5*MUZZLERIGHT_POS), - QUOTE(1.5*MUZZLECLIMB_POS), - QUOTE(0.6*MUZZLERIGHT_MAG), - QUOTE(0.4*MUZZLECLIMB_MAG) + 0.5*MUZZLERIGHT_POS, + 1.5*MUZZLECLIMB_POS, + 0.6*MUZZLERIGHT_MAG, + 0.4*MUZZLECLIMB_MAG }; kickBack[] = { - QUOTE(0.04*KICKBACK), - QUOTE(0.08*KICKBACK) + 0.04*KICKBACK, + 0.08*KICKBACK }; - temporary = QUOTE(0.01*MUZZLETEMP); //0.005*MUZZLETEMP; + temporary = 0.01*MUZZLETEMP; //0.005*MUZZLETEMP; }; }; diff --git a/addons/recoil/XEH_PREP.hpp b/addons/recoil/XEH_PREP.hpp index 9e34c47492..90c7c9cccf 100644 --- a/addons/recoil/XEH_PREP.hpp +++ b/addons/recoil/XEH_PREP.hpp @@ -1,2 +1 @@ - PREP(camshake); diff --git a/addons/recoil/XEH_preInit.sqf b/addons/recoil/XEH_preInit.sqf index ffd1bfc414..1566a79fd4 100644 --- a/addons/recoil/XEH_preInit.sqf +++ b/addons/recoil/XEH_preInit.sqf @@ -7,4 +7,6 @@ PREP_RECOMPILE_START; #include "XEH_PREP.hpp" PREP_RECOMPILE_END; +GVAR(recoilCache) = createHashMap; + ADDON = true; diff --git a/addons/recoil/functions/fnc_camshake.sqf b/addons/recoil/functions/fnc_camshake.sqf index d68da81db7..197d506bf5 100644 --- a/addons/recoil/functions/fnc_camshake.sqf +++ b/addons/recoil/functions/fnc_camshake.sqf @@ -1,17 +1,17 @@ #include "..\script_component.hpp" /* - * Author: Orginal by Ryan Schultz, edited by KoffeinFlummi, commy2 + * Author: Original by Ryan Schultz, edited by KoffeinFlummi, commy2 * Adds camera shake when firing. Called from the unified fired EH only for the local player. * From TMR: Small Arms * * Arguments: - * None. Parameters inherited from EFUNC(common,firedEH) + * Parameters inherited from EFUNC(common,firedEH) * * Return Value: * None * * Example: - * [player, (currentWeapon player), (currentMuzzle player)] call ace_recoil_fnc_camshake; + * [player, currentWeapon player, currentMuzzle player] call ace_recoil_fnc_camshake * * Public: No */ @@ -28,20 +28,19 @@ if (toLowerANSI _weapon in ["throw", "put"]) exitWith {}; private _powerMod = ([0, -0.1, -0.1, 0, -0.2] select (["STAND", "CROUCH", "PRONE", "UNDEFINED", ""] find stance _unit)) + ([0, -1, 0, -1] select (["INTERNAL", "EXTERNAL", "GUNNER", "GROUP"] find cameraView)); -// to get camshake read kickback -private _recoil = missionNamespace getVariable format [QGVAR(%1-%2), _weapon, _muzzle]; - -if (isNil "_recoil") then { +// Get camshake read kickback +private _recoil = GVAR(recoilCache) getOrDefaultCall [_weapon + _muzzle, { private _config = configFile >> "CfgWeapons" >> _weapon; - if (_muzzle == _weapon) then { - _recoil = getText (_config >> "recoil") + private _recoil = if (_muzzle == _weapon) then { + getText (_config >> "recoil") } else { - _recoil = getText (_config >> _muzzle >> "recoil") + getText (_config >> _muzzle >> "recoil") }; if (isClass (configFile >> "CfgRecoils" >> _recoil)) then { _recoil = getArray (configFile >> "CfgRecoils" >> _recoil >> "kickBack"); + if (count _recoil < 2) then { _recoil = [0, 0]; }; @@ -51,12 +50,12 @@ if (isNil "_recoil") then { TRACE_3("Caching Recoil config",_weapon,_muzzle,_recoil); - // parse numbers - _recoil set [0, call compile format ["%1", _recoil select 0]]; - _recoil set [1, call compile format ["%1", _recoil select 1]]; + // Ensure format is correct + _recoil resize [2, 0]; - missionNamespace setVariable [format [QGVAR(%1-%2), _weapon, _muzzle], _recoil]; -}; + // Parse numbers + _recoil apply { if (_x isEqualType 0) then { _x } else { call compile format ["%1", _x] } } // return +}, true]; private _powerCoef = RECOIL_COEF * linearConversion [0, 1, random 1, _recoil select 0, _recoil select 1, false]; From ba22c407e3fff1770030778f4fe8754929b88d09 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Sat, 27 Jul 2024 12:15:28 -0500 Subject: [PATCH 163/290] Common - Add `ace_common_fnc_switchAttachmentMode` (#10135) * Common - Add `ace_common_fnc_switchAttachmentMode` * Update addons/common/functions/fnc_switchAttachmentMode.sqf * Update addons/common/functions/fnc_switchAttachmentMode.sqf * playSound only for ACE_player Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --------- Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> --- addons/common/XEH_PREP.hpp | 1 + .../functions/fnc_switchAttachmentMode.sqf | 61 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 addons/common/functions/fnc_switchAttachmentMode.sqf diff --git a/addons/common/XEH_PREP.hpp b/addons/common/XEH_PREP.hpp index 5b85d63dda..d3972dc7b3 100644 --- a/addons/common/XEH_PREP.hpp +++ b/addons/common/XEH_PREP.hpp @@ -190,6 +190,7 @@ PREP(stopGesture); PREP(stringCompare); PREP(stringToColoredText); PREP(swayLoop); +PREP(switchAttachmentMode); PREP(switchPersistentLaser); PREP(switchToGroupSide); PREP(throttledPublicVariable); diff --git a/addons/common/functions/fnc_switchAttachmentMode.sqf b/addons/common/functions/fnc_switchAttachmentMode.sqf new file mode 100644 index 0000000000..aae742db8a --- /dev/null +++ b/addons/common/functions/fnc_switchAttachmentMode.sqf @@ -0,0 +1,61 @@ +#include "..\script_component.hpp" +/* + * Author: PabstMirror + * Switch attachment from one mode to another - based on CBA_accessory_fnc_switchAttachment + * + * Arguments: + * 0: Unit + * 1: From + * 2: To + * + * Return Value: + * None + * + * Example: + * [player, "ACE_DBAL_A3_Green_VP", "ACE_DBAL_A3_Green"] call ace_common_fnc_switchAttachmentMode + * + * Public: No + */ + +params ["_unit", "_currItem", "_switchItem"]; +TRACE_3("switchAttachmentMode",_unit,_currItem,_switchItem); + +switch (currentWeapon _unit) do { + case (""): {}; + case (primaryWeapon _unit): { + private _currWeaponType = 0; + _unit removePrimaryWeaponItem _currItem; + [{ + params ["_unit", "", "_switchItem"]; + _unit addPrimaryWeaponItem _switchItem; + ["CBA_attachmentSwitched", _this] call CBA_fnc_localEvent; + }, [_unit, _currItem, _switchItem, _currWeaponType]] call CBA_fnc_execNextFrame; + }; + case (handgunWeapon _unit): { + private _currWeaponType = 1; + _unit removeHandgunItem _currItem; + [{ + params ["_unit", "", "_switchItem"]; + _unit addHandgunItem _switchItem; + ["CBA_attachmentSwitched", _this] call CBA_fnc_localEvent; + }, [_unit, _currItem, _switchItem, _currWeaponType]] call CBA_fnc_execNextFrame; + }; + case (secondaryWeapon _unit): { + private _currWeaponType = 2; + _unit removeSecondaryWeaponItem _currItem; + [{ + params ["_unit", "", "_switchItem"]; + _unit addSecondaryWeaponItem _switchItem; + ["CBA_attachmentSwitched", _this] call CBA_fnc_localEvent; + }, [_unit, _currItem, _switchItem, _currWeaponType]] call CBA_fnc_execNextFrame; + }; +}; +private _configSwitchItem = configfile >> "CfgWeapons" >> _switchItem; +private _switchItemHintText = getText (_configSwitchItem >> "MRT_SwitchItemHintText"); +private _switchItemHintImage = getText (_configSwitchItem >> "picture"); +if (_switchItemHintText isNotEqualTo "") then { + [[_switchItemHintImage, 2.0], [_switchItemHintText], true] call CBA_fnc_notify; +}; +if (_unit == ACE_player) then { + playSound "click"; +}; From b7cd72e936b956a675b42a3e2a55cba7f5b54423 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 27 Jul 2024 19:15:50 +0200 Subject: [PATCH 164/290] CSW - Fix belt linking (#10148) * fix unloading to units with full inventory * fix belt linking issues * Enhance workaround * Use unit instead if magSource is null --------- Co-authored-by: Salluci --- .../fnc_reload_handleAddTurretMag.sqf | 5 ++-- .../functions/fnc_reload_handleReturnAmmo.sqf | 24 +++++++++++-------- .../csw/functions/fnc_reload_loadMagazine.sqf | 15 ++++++++++-- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/addons/csw/functions/fnc_reload_handleAddTurretMag.sqf b/addons/csw/functions/fnc_reload_handleAddTurretMag.sqf index d7af22d319..c752f76f59 100644 --- a/addons/csw/functions/fnc_reload_handleAddTurretMag.sqf +++ b/addons/csw/functions/fnc_reload_handleAddTurretMag.sqf @@ -10,7 +10,7 @@ * 2: Source of magazine * 3: Vehicle Magazine * 4: Ammo in magazine - * 5: Unit or object to return ammo to + * 5: Unit or object to return ammo to (default: Source of magazine) * * Return Value: * None @@ -21,7 +21,8 @@ * Public: No */ -params ["_vehicle", "_turret", "_magSource", "_carryMag", "_ammoReceived", ["_returnTo", _magSource]]; +params ["_vehicle", "_turret", "_magSource", "_carryMag", "_ammoReceived"]; +private _returnTo = param [5, _magSource]; TRACE_6("reload_handleAddTurretMag",_vehicle,_turret,_magSource,_carryMag,_ammoReceived,_returnTo); TRACE_2("",local _vehicle,_vehicle turretLocal _turret); diff --git a/addons/csw/functions/fnc_reload_handleReturnAmmo.sqf b/addons/csw/functions/fnc_reload_handleReturnAmmo.sqf index ca445400b0..864bb2ab6f 100644 --- a/addons/csw/functions/fnc_reload_handleReturnAmmo.sqf +++ b/addons/csw/functions/fnc_reload_handleReturnAmmo.sqf @@ -18,13 +18,15 @@ */ params ["_unloadTo", "_carryMag", "_ammo"]; -TRACE_3("reload_handleReturnAmmo",_unloadTo,_carryMag,_ammo); +TRACE_4("reload_handleReturnAmmo",_unloadTo,typeOf _unloadTo,_carryMag,_ammo); private _carryMaxAmmo = getNumber (configFile >> "CfgMagazines" >> _carryMag >> "count"); private _fullMagazines = floor (_ammo / _carryMaxAmmo); private _bulletsRemaining = _ammo % _carryMaxAmmo; -if (_unloadTo isKindOf "CaManBase") then { +private _unloadToUnit = _unloadTo isKindOf "CAManBase"; + +if (_unloadToUnit) then { while {(_fullMagazines > 0) && {[_unloadTo, _carryMag] call CBA_fnc_canAddItem}} do { _unloadTo addMagazine [_carryMag, _carryMaxAmmo]; _fullMagazines = _fullMagazines - 1; @@ -37,19 +39,21 @@ if (_unloadTo isKindOf "CaManBase") then { if ((_fullMagazines == 0) && {_bulletsRemaining == 0}) exitWith {}; -// Try to use existing container -private _container = _unloadTo getVariable [QGVAR(container), objNull]; -if ((_container distance _unloadTo) > 10) then { _container = objNull; }; -if (isNull _container) then { - _container = (nearestObjects [_unloadTo, [["GroundWeaponHolder"], [QGVAR(ammo_holder)]] select GVAR(handleExtraMagazinesType), 10]) param [0, objNull]; +// Try to use object inventory or existing container +private _container = [_unloadTo, objNull] select _unloadToUnit; +if ((maxLoad _container) isEqualTo 0) then { + _container = _unloadTo getVariable [QGVAR(container), objNull]; + if ((_container distance _unloadTo) > 10) then { _container = objNull; }; + if (isNull _container) then { + _container = (nearestObjects [_unloadTo, [["GroundWeaponHolder"], [QGVAR(ammo_holder)]] select GVAR(handleExtraMagazinesType), 10]) param [0, objNull]; + }; }; - if (isNull _container) then { // Create ammo storage container private _weaponRelPos = _unloadTo getRelPos RELATIVE_DIRECTION(270); _weaponRelPos set [2, ((getPosATL _unloadTo) select 2) + 0.05]; - _container = createVehicle [["GroundWeaponHolder", QGVAR(ammo_holder)] select GVAR(handleExtraMagazinesType), [0, 0, 0], [], 0, "NONE"]; + _container = createVehicle [["GroundWeaponHolder", QGVAR(ammo_holder)] select GVAR(handleExtraMagazinesType), [0, 0, 0], [], 0, "CAN_COLLIDE"]; _unloadTo setVariable [QGVAR(container), _container, true]; _container setDir random [0, 180, 360]; _container setPosATL _weaponRelPos; @@ -59,7 +63,7 @@ if (isNull _container) then { TRACE_2("Creating NEW Container",_container,_weaponRelPos); }; -TRACE_3("adding to container",_container,_fullMagazines,_bulletsRemaining); +TRACE_4("adding to container",_container,typeOf _container,_fullMagazines,_bulletsRemaining); if (_fullMagazines > 0) then { _container addMagazineAmmoCargo [_carryMag, _fullMagazines, _carryMaxAmmo]; diff --git a/addons/csw/functions/fnc_reload_loadMagazine.sqf b/addons/csw/functions/fnc_reload_loadMagazine.sqf index 50081a87a5..07db0fb146 100644 --- a/addons/csw/functions/fnc_reload_loadMagazine.sqf +++ b/addons/csw/functions/fnc_reload_loadMagazine.sqf @@ -52,8 +52,19 @@ private _onFinish = { [_magSource, _carryMag, _bestAmmoToSend] call EFUNC(common,removeSpecificMagazine); if (_bestAmmoToSend == 0) exitWith {}; - TRACE_6("calling addTurretMag event",_vehicle,_turret,_magSource,_carryMag,_bestAmmoToSend,_unit); - [QGVAR(addTurretMag), [_vehicle, _turret, _magSource, _carryMag, _bestAmmoToSend, _unit]] call CBA_fnc_globalEvent; + // Workaround for removeSpecificMagazine and WeaponHolders being deleted when empty, give back to the unit if the weapon holder was deleted + // TODO: Pass type and position of deleted object to create a new one + // TODO: Use '_magSource getEntityInfo 14' in 2.18 and the isSetForDeletion flag to execute in same frame + [{ + params ["_magSource", "_unit", "_args"]; + + if (isNull _magSource) then { + _args pushBack _unit; + }; + + TRACE_1("calling addTurretMag event",_args); + [QGVAR(addTurretMag), _args] call CBA_fnc_globalEvent; + }, [_magSource, _unit, [_vehicle, _turret, _magSource, _carryMag, _bestAmmoToSend]]] call CBA_fnc_execNextFrame; }; From aa6e5c30eca6e7a3bb95a681e11e89f74021cca4 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Sat, 27 Jul 2024 12:16:49 -0500 Subject: [PATCH 165/290] Fire - Fix medical macros in compiled sqfc (#10147) * Fire - Fix medical macros in compiled sqfc * Update addons/fire/functions/fnc_burnSimulation.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --------- Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- addons/fire/addon.toml | 3 --- addons/fire/functions/fnc_burnSimulation.sqf | 4 +++- addons/fire/script_component.hpp | 8 -------- 3 files changed, 3 insertions(+), 12 deletions(-) delete mode 100644 addons/fire/addon.toml diff --git a/addons/fire/addon.toml b/addons/fire/addon.toml deleted file mode 100644 index bf39213892..0000000000 --- a/addons/fire/addon.toml +++ /dev/null @@ -1,3 +0,0 @@ -[tools] -pboProject_noBinConfig = true -sqfvm_skipConfigChecks = true diff --git a/addons/fire/functions/fnc_burnSimulation.sqf b/addons/fire/functions/fnc_burnSimulation.sqf index ac98de5dda..e061d1ce91 100644 --- a/addons/fire/functions/fnc_burnSimulation.sqf +++ b/addons/fire/functions/fnc_burnSimulation.sqf @@ -149,7 +149,9 @@ params ["_unit", "_instigator"]; }; // Keep pain around unconsciousness limit to allow for more fun interactions - private _damageToAdd = [0.15, _intensity / BURN_MAX_INTENSITY] select (!alive _unit || {GET_PAIN_PERCEIVED(_unit) < (PAIN_UNCONSCIOUS + random 0.2)}); + private _painPercieved = (0 max ((_unit getVariable [QEGVAR(medical,pain), 0]) - (_unit getVariable [QEGVAR(medical,painSuppress), 0])) min 1); + private _painUnconscious = missionNamespace getVariable [QEGVAR(medical,painUnconsciousThreshold), 0]; + private _damageToAdd = [0.15, _intensity / BURN_MAX_INTENSITY] select (!alive _unit || {_painPercieved < _painUnconscious + random 0.2}); if (GETEGVAR(medical,enabled,false)) then { if (!isNull _instigator) then { diff --git a/addons/fire/script_component.hpp b/addons/fire/script_component.hpp index d79ca0d490..f4b636286b 100644 --- a/addons/fire/script_component.hpp +++ b/addons/fire/script_component.hpp @@ -17,14 +17,6 @@ #include "\z\ace\addons\main\script_macros.hpp" -#pragma hemtt flag pe23_ignore_has_include -#if __has_include("\z\ace\addons\medical_engine\script_macros_medical.hpp") -#include "\z\ace\addons\medical_engine\script_macros_medical.hpp" -#else -#define GET_PAIN_PERCEIVED(var) 0 -#define PAIN_UNCONSCIOUS 1 -#endif - #define FIRE_MANAGER_PFH_DELAY 0.25 #define FLARE_SIZE_MODIFIER 5 #define PRONE_ROLLING_ANIMS [\ From e3d8f4053807e7272ba19114309b591dc4408214 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Sat, 27 Jul 2024 12:37:33 -0500 Subject: [PATCH 166/290] Interaction - Show all possible modes for an attachment (#8154) * Interaction - Show all possible modes for an attachement * Move attach & detach actions under item action * Remove switching from PIP to regular 2D * Remove attachment name from attach/detach actions * Fixed typo in variable name --------- Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- .../fnc_getWeaponAttachmentsActions.sqf | 141 +++++++++++++----- addons/interaction/stringtable.xml | 44 +++--- 2 files changed, 124 insertions(+), 61 deletions(-) diff --git a/addons/interaction/functions/fnc_getWeaponAttachmentsActions.sqf b/addons/interaction/functions/fnc_getWeaponAttachmentsActions.sqf index c771589904..2b8fbe43e9 100644 --- a/addons/interaction/functions/fnc_getWeaponAttachmentsActions.sqf +++ b/addons/interaction/functions/fnc_getWeaponAttachmentsActions.sqf @@ -1,6 +1,6 @@ #include "..\script_component.hpp" /* - * Author: mharis001, Dystopian + * Author: mharis001, Dystopian, PabstMirror, johnb43 * Returns children actions for weapon attachment switching. * * Arguments: @@ -21,48 +21,111 @@ params ["_unit"]; params ["_unit"]; private _currentWeapon = currentWeapon _unit; - if (_currentWeapon isEqualTo "") exitWith {[]}; - private _weaponItems = _unit weaponAccessories _currentWeapon; + + if (_currentWeapon == "") exitWith {[]}; + private _cfgWeapons = configFile >> "CfgWeapons"; - private _actions = []; + private _weaponItems = _unit weaponAccessories _currentWeapon; - // "attach" actions - private _items = _unit call EFUNC(common,uniqueItems); - private _compatibleItems = _currentWeapon call CBA_fnc_compatibleItems; - { + // Get current weapon attachments, as well as compatible attachments in inventory + private _allAttachments = (+_weaponItems) - [""]; + _allAttachments append ((_unit call EFUNC(common,uniqueItems)) arrayIntersect (compatibleItems _currentWeapon)); + + (_allAttachments arrayIntersect _allAttachments) apply { private _config = _cfgWeapons >> _x; - private _name = format [LLSTRING(weaponAttachmentsAttach), getText (_config >> "displayName")]; - private _picture = getText (_config >> "picture"); - private _type = getNumber (_config >> "itemInfo" >> "type"); - private _oldAttachment = _weaponItems select ([TYPE_MUZZLE, TYPE_FLASHLIGHT, TYPE_OPTICS, TYPE_BIPOD] find _type); - - private _action = [ - _x, _name, _picture, - LINKFUNC(switchWeaponAttachment), - {true}, - {}, - [_currentWeapon, _x, _oldAttachment] - ] call EFUNC(interact_menu,createAction); - _actions pushBack [_action, [], _unit]; - } forEach ((_items arrayIntersect _compatibleItems) - _weaponItems); - - // "detach" actions - { - if (_x isEqualTo "") then {continue}; - - private _config = _cfgWeapons >> _x; - private _name = format [LLSTRING(weaponAttachmentsDetach), getText (_config >> "displayName")]; + private _name = getText (_config >> "displayName"); private _picture = getText (_config >> "picture"); - private _action = [ - _x, _name, _picture, - LINKFUNC(switchWeaponAttachment), - {true}, - {}, - [_currentWeapon, "", _x] - ] call EFUNC(interact_menu,createAction); - _actions pushBack [_action, [], _unit]; - } forEach _weaponItems; + [ + [ + _x, + _name, + _picture, + {}, + {true}, + { + params ["_unit", "", "_args"]; + _args params ["_attachment", "_name", "_picture", "_weaponItems", "_currentWeapon"]; - _actions + private _cfgWeapons = configFile >> "CfgWeapons"; + private _attachmentNotOnGun = !(_attachment in _weaponItems); + private _actions = []; + + // "attach" action + if (_attachmentNotOnGun && {[_unit, _attachment] call EFUNC(common,hasItem)}) then { + private _type = getNumber (_cfgWeapons >> _attachment >> "itemInfo" >> "type"); + private _currentAttachment = _weaponItems select ([TYPE_MUZZLE, TYPE_FLASHLIGHT, TYPE_OPTICS, TYPE_BIPOD] find _type); + + _actions pushBack [ + [ + QGVAR(attach_) + _attachment, + LLSTRING(weaponAttachmentsAttach), + _picture, + LINKFUNC(switchWeaponAttachment), + {true}, + {}, + [_currentWeapon, _attachment, _currentAttachment] + ] call EFUNC(interact_menu,createAction), + [], + _unit + ]; + }; + + // Don't show interaction with attachments that aren't on the current weapon + if (_attachmentNotOnGun) exitWith {_actions}; + + // "detach" action + _actions pushBack [ + [ + QGVAR(detach_) + _attachment, + LLSTRING(weaponAttachmentsDetach), + _picture, + LINKFUNC(switchWeaponAttachment), + {true}, + {}, + [_currentWeapon, "", _attachment] + ] call EFUNC(interact_menu,createAction), + [], + _unit + ]; + + private _CBA_PIPItems = configFile >> "CBA_PIPItems"; + + // "switch" action + { + // Ignore 2D scopes when using a PIP scope (e.g. CUP uses this) + if (getText (_CBA_PIPItems >> _x) == _attachment) then { + continue; + }; + + private _config = _cfgWeapons >> _x; + private _modeName = getText (_config >> "MRT_SwitchItemHintText"); + + if (_modeName == "") then { + _modeName = getText (_config >> "displayName"); + }; + + _actions pushBack [ + [ + QGVAR(switch_) + _x, + format ["%1: %2", localize "str_sensortype_switch", _modeName], + getText (_config >> "picture"), + LINKFUNC(switchWeaponAttachment), + {true}, + {}, + [_currentWeapon, _x, ""] + ] call EFUNC(interact_menu,createAction), + [], + _unit + ]; + } forEach ((_attachment call CBA_fnc_switchableAttachments) - [_attachment]); // Don't allow switching to current mode + + _actions + }, + [_x, _name, _picture, _weaponItems, _currentWeapon] + ] call EFUNC(interact_menu,createAction), + [], + _unit + ] + } // return }, _unit, QGVAR(weaponAttachmentsActions), 5, QGVAR(clearWeaponAttachmentsActionsCache)] call EFUNC(common,cachedCall); diff --git a/addons/interaction/stringtable.xml b/addons/interaction/stringtable.xml index 38c86f5f99..5b79a69e69 100644 --- a/addons/interaction/stringtable.xml +++ b/addons/interaction/stringtable.xml @@ -1247,30 +1247,30 @@ 전면유리 부수기 - Attach %1 - Установить %1 - %1 を取り付け - Acoplar %1 - Fixer %1 - Przyczep %1 - Befestige %1 - Attacca %1 - 附加 %1 - %1 붙이기 - Fixar %1 + Attach + Установить + を取り付け + Acoplar + Fixer + Przyczep + Befestige + Attacca + 附加 + 붙이기 + Fixar - Detach %1 - Снять %1 - %1 を外す - Desacoplar %1 - Retirer %1 - Odczep %1 - Löse %1 - Stacca %1 - 拆卸 %1 - %1 떼내기 - Desfixar %1 + Detach + Снять + を外す + Desacoplar + Retirer + Odczep + Löse + Stacca + 拆卸 + 떼내기 + Desfixar Enables attach/detach weapon attachment actions for current weapon. From 56eae4060c81be41ff52096bab1d726d1a48e6c9 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 27 Jul 2024 19:42:31 +0200 Subject: [PATCH 167/290] CSW - Improve function headers & comments (#10149) Code formatting changes from 9234 --- addons/csw/dev/checkStaticWeapons.sqf | 6 +-- .../fnc_aceRearmGetCarryMagazines.sqf | 6 +-- addons/csw/functions/fnc_ai_handleFired.sqf | 2 +- addons/csw/functions/fnc_ai_handleGetIn.sqf | 4 +- addons/csw/functions/fnc_ai_reload.sqf | 24 +++++------ .../fnc_assemble_canDeployWeapon.sqf | 6 +-- .../fnc_assemble_canPickupWeapon.sqf | 14 +++---- .../functions/fnc_assemble_deployTripod.sqf | 8 ++-- .../functions/fnc_assemble_deployWeapon.sqf | 4 +- .../fnc_assemble_deployWeaponModifier.sqf | 4 +- .../functions/fnc_assemble_pickupTripod.sqf | 6 +-- .../functions/fnc_assemble_pickupWeapon.sqf | 40 +++++++++---------- addons/csw/functions/fnc_canDeployTripod.sqf | 8 ++-- addons/csw/functions/fnc_canGetIn.sqf | 4 +- addons/csw/functions/fnc_canPickupTripod.sqf | 5 +-- addons/csw/functions/fnc_getCarryMagazine.sqf | 2 +- addons/csw/functions/fnc_getLoadActions.sqf | 6 +-- addons/csw/functions/fnc_initVehicle.sqf | 8 ++-- addons/csw/functions/fnc_proxyWeapon.sqf | 4 +- .../functions/fnc_reload_canLoadMagazine.sqf | 16 ++++---- .../fnc_reload_canUnloadMagazine.sqf | 4 +- .../fnc_reload_getLoadableMagazines.sqf | 8 ++-- .../fnc_reload_getVehicleMagazine.sqf | 2 +- .../fnc_reload_handleAddTurretMag.sqf | 6 +-- .../fnc_reload_handleRemoveTurretMag.sqf | 8 ++-- .../functions/fnc_reload_handleReturnAmmo.sqf | 4 +- .../csw/functions/fnc_reload_loadMagazine.sqf | 4 +- .../fnc_staticWeaponInit_unloadExtraMags.sqf | 35 ++++++++-------- 28 files changed, 124 insertions(+), 124 deletions(-) diff --git a/addons/csw/dev/checkStaticWeapons.sqf b/addons/csw/dev/checkStaticWeapons.sqf index 7d9917daa7..137dc95334 100644 --- a/addons/csw/dev/checkStaticWeapons.sqf +++ b/addons/csw/dev/checkStaticWeapons.sqf @@ -16,7 +16,7 @@ private _inherited = []; private _config = _x; private _configEnabled = (getNumber (_config >> QUOTE(ADDON) >> "enabled")) == 1; if (_configEnabled) then { - private _configExplicit = (count configProperties [_config, "configName _x == 'ace_csw'", false]) == 1; + private _configExplicit = (count configProperties [_config, toString {configName _x == QUOTE(ADDON)}, false]) == 1; if (_configExplicit) then { _explicitBases pushBack (configName _config); _inherited pushBack []; @@ -43,8 +43,8 @@ private _inherited = []; INFO("------ Logging static magazines with no carry version -------"); private _hash = createHashMap; -// private _logAll = true; // logs all possible weapon magazines (even if not used in a static weapon) -private _logAll = false; +private _logAll = false; // logs all possible weapon magazines (even if not used in a static weapon) when set to true + { private _vehicleType = configName _x; private _turretConfig = [_vehicleType, [0]] call CBA_fnc_getTurret; diff --git a/addons/csw/functions/fnc_aceRearmGetCarryMagazines.sqf b/addons/csw/functions/fnc_aceRearmGetCarryMagazines.sqf index 5230fccf52..f3a6bbde5f 100644 --- a/addons/csw/functions/fnc_aceRearmGetCarryMagazines.sqf +++ b/addons/csw/functions/fnc_aceRearmGetCarryMagazines.sqf @@ -1,11 +1,11 @@ #include "..\script_component.hpp" /* * Author: PabstMirror - * Helper function for ace_rearm; Gets magazines that should be loaded by csw + * Helper function for ace_rearm; Gets magazines that should be loaded by csw. * * Arguments: - * 0: Vehicle - * 1: Specific Turret or pass bool to check all turrets (default: true) + * 0: CSW + * 1: Specific Turret or pass bool to check all turrets (default: true) * * Return Value: * [0: compatible veh mags, 1: carry mags] diff --git a/addons/csw/functions/fnc_ai_handleFired.sqf b/addons/csw/functions/fnc_ai_handleFired.sqf index d92e517091..6f7a645257 100644 --- a/addons/csw/functions/fnc_ai_handleFired.sqf +++ b/addons/csw/functions/fnc_ai_handleFired.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: PabstMirror - * Handles AI Fired EH + * Handles AI Fired EH. * * Arguments: * Fired EH diff --git a/addons/csw/functions/fnc_ai_handleGetIn.sqf b/addons/csw/functions/fnc_ai_handleGetIn.sqf index f14a4ccbc7..14b4453f53 100644 --- a/addons/csw/functions/fnc_ai_handleGetIn.sqf +++ b/addons/csw/functions/fnc_ai_handleGetIn.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* - * Author: Grim - * Handles AI GetIn on an empty weapon + * Author: LinkIsGrim + * Handles AI GetIn on an empty CSW. * * Arguments: * GetIn EH diff --git a/addons/csw/functions/fnc_ai_reload.sqf b/addons/csw/functions/fnc_ai_reload.sqf index 4d6234f94a..288d718a2f 100644 --- a/addons/csw/functions/fnc_ai_reload.sqf +++ b/addons/csw/functions/fnc_ai_reload.sqf @@ -1,10 +1,10 @@ #include "..\script_component.hpp" /* - * Author: PabstMirror, modified by Grim - * Handles AI reloading + * Author: PabstMirror, LinkIsGrim + * Handles AI reloading. * * Arguments: - * 0: Static Weapon + * 0: CSW * 1: Gunner * 2: Weapon * 3: Magazine (default: "") @@ -15,7 +15,7 @@ * Public: No */ -params ["_staticWeapon", "_gunner", "_weapon", ["_magazine", ""]]; +params ["_vehicle", "_gunner", "_weapon", ["_magazine", ""]]; private _turretPath = [_gunner] call EFUNC(common,getTurretIndex); private _reloadSource = objNull; @@ -24,7 +24,7 @@ private _reloadNeededAmmo = -1; private _cfgMagGroups = configFile >> QGVAR(groups); -private _nearSupplies = [_gunner] + ((_staticWeapon nearSupplies 10) select { +private _nearSupplies = [_gunner] + ((_vehicle nearSupplies 10) select { isNull (group _x) || {!([_x] call EFUNC(common,isPlayer)) && {[side group _gunner, side group _x] call BIS_fnc_sideIsFriendly}} }); @@ -49,7 +49,7 @@ private _nearSupplies = [_gunner] + ((_staticWeapon nearSupplies 10) select { private _xWeaponMag = _x; { if ((getNumber (_cfgMagGroups >> _x >> _xWeaponMag)) == 1) then { - private _loadInfo = [_staticWeapon, _turretPath, _x, _xSource] call FUNC(reload_canLoadMagazine); + private _loadInfo = [_vehicle, _turretPath, _x, _xSource] call FUNC(reload_canLoadMagazine); if (_loadInfo select 0) then { _reloadMag = _x; _reloadSource = _xSource; @@ -81,16 +81,16 @@ if (_bestAmmoToSend == -1) exitWith {ERROR("No ammo");}; [_reloadSource, _reloadMag, _bestAmmoToSend] call EFUNC(common,removeSpecificMagazine); private _timeToLoad = 1; -if (!isNull(configOf _staticWeapon >> QUOTE(ADDON) >> "ammoLoadTime")) then { - _timeToLoad = getNumber(configOf _staticWeapon >> QUOTE(ADDON) >> "ammoLoadTime"); +if (!isNull(configOf _vehicle >> QUOTE(ADDON) >> "ammoLoadTime")) then { + _timeToLoad = getNumber(configOf _vehicle >> QUOTE(ADDON) >> "ammoLoadTime"); }; TRACE_1("Reloading in progress",_timeToLoad); [{ - params ["_staticWeapon", "_turretPath", "_gunner", "_reloadMag", "_bestAmmoToSend"]; - if ((!alive _staticWeapon) || {!alive _gunner} || {(_staticWeapon distance _gunner) > 10}) exitWith {TRACE_1("invalid state",_this);}; + params ["_vehicle", "_turretPath", "_gunner", "_reloadMag", "_bestAmmoToSend"]; + if ((!alive _vehicle) || {!alive _gunner} || {(_vehicle distance _gunner) > 10}) exitWith {TRACE_1("invalid state",_this);}; // Reload the static weapon - TRACE_5("calling addTurretMag event",_staticWeapon,_turretPath,_gunner,_reloadMag,_bestAmmoToSend); + TRACE_5("calling addTurretMag event",_vehicle,_turretPath,_gunner,_reloadMag,_bestAmmoToSend); [QGVAR(addTurretMag), _this] call CBA_fnc_globalEvent; -}, [_staticWeapon, _turretPath, _gunner, _reloadMag, _bestAmmoToSend], _timeToLoad] call CBA_fnc_waitAndExecute; +}, [_vehicle, _turretPath, _gunner, _reloadMag, _bestAmmoToSend], _timeToLoad] call CBA_fnc_waitAndExecute; diff --git a/addons/csw/functions/fnc_assemble_canDeployWeapon.sqf b/addons/csw/functions/fnc_assemble_canDeployWeapon.sqf index 65dd81cc41..6dd58fe4fb 100644 --- a/addons/csw/functions/fnc_assemble_canDeployWeapon.sqf +++ b/addons/csw/functions/fnc_assemble_canDeployWeapon.sqf @@ -1,14 +1,14 @@ #include "..\script_component.hpp" /* * Author: tcvm - * Checks if you can deploy a weapon on the tripod + * Checks if you can deploy a weapon on the tripod. * * Arguments: - * 0: Target Tripod + * 0: Target * 1: Player * * Return Value: - * Wether or not you can deploy the weapon + * Whether or not you can deploy the weapon * * Example: * [cursorObject, player] call ace_csw_fnc_assemble_canDeployWeapon diff --git a/addons/csw/functions/fnc_assemble_canPickupWeapon.sqf b/addons/csw/functions/fnc_assemble_canPickupWeapon.sqf index 0d508bfa89..3228373b40 100644 --- a/addons/csw/functions/fnc_assemble_canPickupWeapon.sqf +++ b/addons/csw/functions/fnc_assemble_canPickupWeapon.sqf @@ -1,23 +1,23 @@ #include "..\script_component.hpp" /* * Author: tcvm - * If the CSW is mounted or in use this will not allow you to dismount the weapon + * If the CSW is mounted or in use this will not allow you to dismount the weapon. * * Arguments: - * 0: Static Weapon + * 0: CSW * * Return Value: - * Can Dismount + * Can dismount weapon * * Example: - * [cursorObject] call ace_csw_fnc_assemble_canPickupWeapon + * cursorObject call ace_csw_fnc_assemble_canPickupWeapon * * Public: No */ -params ["_staticWeapon"]; +params ["_vehicle"]; // Assembly mode: [0=disabled, 1=enabled, 2=enabled&unload, 3=default] -private _assemblyMode = [false, true, true, GVAR(defaultAssemblyMode)] select (_staticWeapon getVariable [QGVAR(assemblyMode), 3]); +private _assemblyMode = [false, true, true, GVAR(defaultAssemblyMode)] select (_vehicle getVariable [QGVAR(assemblyMode), 3]); -_assemblyMode && {alive _staticWeapon} && {((crew _staticWeapon) findIf {alive _x && {!unitIsUAV _x}}) == -1} // return +_assemblyMode && {alive _vehicle} && {((crew _vehicle) findIf {alive _x && {!unitIsUAV _x}}) == -1} // return diff --git a/addons/csw/functions/fnc_assemble_deployTripod.sqf b/addons/csw/functions/fnc_assemble_deployTripod.sqf index 29cc4b5876..c69d618066 100644 --- a/addons/csw/functions/fnc_assemble_deployTripod.sqf +++ b/addons/csw/functions/fnc_assemble_deployTripod.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: tcvm - * Deploys the tripod + * Deploys the tripod. * * Arguments: * 0: Unit @@ -10,7 +10,7 @@ * None * * Example: - * [player] call ace_csw_fnc_assemble_deployTripod + * player call ace_csw_fnc_assemble_deployTripod * * Public: No */ @@ -34,7 +34,7 @@ _args params ["_player", "_secondaryWeaponClassname", "_secondaryWeaponInfo"]; TRACE_3("deployTripod finish",_player,_secondaryWeaponClassname,_secondaryWeaponInfo); - private _tripodClassname = getText(configFile >> "CfgWeapons" >> _secondaryWeaponClassname >> QUOTE(ADDON) >> "deploy"); + private _tripodClassname = getText (configFile >> "CfgWeapons" >> _secondaryWeaponClassname >> QUOTE(ADDON) >> "deploy"); // Create a tripod private _cswTripod = createVehicle [_tripodClassname, [0, 0, 0], [], 0, "NONE"]; @@ -96,6 +96,6 @@ } forEach _secondaryWeaponInfo; }; - private _deployTime = getNumber(configFile >> "CfgWeapons" >> _secondaryWeaponClassname >> QUOTE(ADDON) >> "deployTime"); + private _deployTime = getNumber (configFile >> "CfgWeapons" >> _secondaryWeaponClassname >> QUOTE(ADDON) >> "deployTime"); [TIME_PROGRESSBAR(_deployTime), [_player, _secondaryWeaponClassname, _secondaryWeaponInfo], _onFinish, _onFailure, LLSTRING(PlaceTripod_progressBar)] call EFUNC(common,progressBar); }, _this] call CBA_fnc_execNextFrame; diff --git a/addons/csw/functions/fnc_assemble_deployWeapon.sqf b/addons/csw/functions/fnc_assemble_deployWeapon.sqf index 974bf03431..a0e0acdd28 100644 --- a/addons/csw/functions/fnc_assemble_deployWeapon.sqf +++ b/addons/csw/functions/fnc_assemble_deployWeapon.sqf @@ -1,11 +1,11 @@ #include "..\script_component.hpp" /* * Author: tcvm - * Deploys the current CSW + * Deploys the current CSW. * * Arguments: * 0: Target - * 1: Unit + * 1: Player * 2: Args * 3: Action Data * diff --git a/addons/csw/functions/fnc_assemble_deployWeaponModifier.sqf b/addons/csw/functions/fnc_assemble_deployWeaponModifier.sqf index 85b1346415..f98978195d 100644 --- a/addons/csw/functions/fnc_assemble_deployWeaponModifier.sqf +++ b/addons/csw/functions/fnc_assemble_deployWeaponModifier.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: PabstMirror - * Modifies interaction for deploying weapon + * Modifies interaction for deploying weapon. * * Arguments: * 0: Target @@ -21,7 +21,7 @@ params ["_target", "_player", "", "_actionData"]; private _carryWeaponClassname = secondaryWeapon _player; -private _assembleTo = (getText(configFile >> "CfgWeapons" >> _carryWeaponClassname >> QUOTE(ADDON) >> "assembleTo" >> (typeOf _target))); +private _assembleTo = getText (configFile >> "CfgWeapons" >> _carryWeaponClassname >> QUOTE(ADDON) >> "assembleTo" >> typeOf _target); private _icon = getText (configFile >> "CfgVehicles" >> _assembleTo >> "picture"); TRACE_2("",_assembleTo,_icon); diff --git a/addons/csw/functions/fnc_assemble_pickupTripod.sqf b/addons/csw/functions/fnc_assemble_pickupTripod.sqf index 0996c0f3d3..c09400a87f 100644 --- a/addons/csw/functions/fnc_assemble_pickupTripod.sqf +++ b/addons/csw/functions/fnc_assemble_pickupTripod.sqf @@ -1,11 +1,11 @@ #include "..\script_component.hpp" /* * Author: tcvm - * Picks up the tripod and adds it to the player launcher slot + * Picks up the tripod and adds it to the player launcher slot. * * Arguments: * 0: Tripod - * 1: Unit + * 1: Player * * Return Value: * None @@ -56,7 +56,7 @@ if (isNull _weaponHolder || {_tripodPos distance _weaponHolder > 2}) then { _weaponHolder = createVehicle ["GroundWeaponHolder", [0, 0, 0], [], 0, "CAN_COLLIDE"]; _weaponHolder setDir random [0, 180, 360]; - _weaponHolder setVehiclePosition [_tripodPos, [], 0, "CAN_COLLIDE"]; // places object on surface below + _weaponHolder setVehiclePosition [_tripodPos, [], 0, "CAN_COLLIDE"]; // Places object on surface below }; _weaponHolder addWeaponCargoGlobal [_tripodClassname, 1]; diff --git a/addons/csw/functions/fnc_assemble_pickupWeapon.sqf b/addons/csw/functions/fnc_assemble_pickupWeapon.sqf index 468f385efa..65dc5fa740 100644 --- a/addons/csw/functions/fnc_assemble_pickupWeapon.sqf +++ b/addons/csw/functions/fnc_assemble_pickupWeapon.sqf @@ -1,11 +1,11 @@ #include "..\script_component.hpp" /* * Author: tcvm - * Dismounts the weapon from the tripod and drops its backpack beside + * Dismounts the weapon from the tripod and drops its backpack beside. * * Arguments: - * 0: Static Weapon - * 1: Unit + * 0: CSW + * 1: Player * * Return Value: * None @@ -17,10 +17,10 @@ */ [{ - params ["_staticWeapon", "_player"]; - TRACE_2("assemble_pickupWeapon",_staticWeapon,_player); + params ["_vehicle", "_player"]; + TRACE_2("assemble_pickupWeapon",_vehicle,_player); - private _weaponConfig = configOf _staticWeapon >> QUOTE(ADDON); + private _weaponConfig = configOf _vehicle >> QUOTE(ADDON); private _carryWeaponClassname = getText (_weaponConfig >> "disassembleWeapon"); if (!isClass (configFile >> "CfgWeapons" >> _carryWeaponClassname)) exitWith { @@ -37,15 +37,15 @@ private _onDisassembleFunc = getText (_weaponConfig >> "disassembleFunc"); private _pickupTime = getNumber (configFile >> "CfgWeapons" >> _carryWeaponClassname >> QUOTE(ADDON) >> "pickupTime"); - TRACE_4("",typeOf _staticWeapon,_carryWeaponClassname,_turretClassname,_pickupTime); + TRACE_4("",typeOf _vehicle,_carryWeaponClassname,_turretClassname,_pickupTime); private _onFinish = { params ["_args"]; - _args params ["_staticWeapon", "_player", "_carryWeaponClassname", "_turretClassname", "_onDisassembleFunc"]; - TRACE_4("disassemble finish",_staticWeapon,_player,_carryWeaponClassname,_turretClassname); + _args params ["_vehicle", "_player", "_carryWeaponClassname", "_turretClassname", "_onDisassembleFunc"]; + TRACE_4("disassemble finish",_vehicle,_player,_carryWeaponClassname,_turretClassname); - private _weaponPos = (getPosATL _staticWeapon) vectorAdd [0, 0, 0.1]; - private _weaponDir = getDir _staticWeapon; + private _weaponPos = (getPosATL _vehicle) vectorAdd [0, 0, 0.1]; + private _weaponDir = getDir _vehicle; private _carryWeaponMag = []; private _carryWeaponMags = compatibleMagazines _carryWeaponClassname; @@ -64,7 +64,7 @@ TRACE_2("Removing ammo",_xMag,_carryMag); [_player, _carryMag, _xAmmo] call FUNC(reload_handleReturnAmmo); }; - } forEach (magazinesAllTurrets _staticWeapon); + } forEach (magazinesAllTurrets _vehicle); if (_turretClassname isNotEqualTo "") then { private _cswTripod = createVehicle [_turretClassname, [0, 0, 0], [], 0, "NONE"]; @@ -76,7 +76,7 @@ _cswTripod setVelocity [0, 0, -0.05]; _cswTripod setVectorUp (surfaceNormal _weaponPos); }, [_cswTripod, _weaponDir, _weaponPos]] call CBA_fnc_execNextFrame; - [_cswTripod, _staticWeapon] call (missionNamespace getVariable _onDisassembleFunc); + [_cswTripod, _vehicle] call (missionNamespace getVariable _onDisassembleFunc); }; [{ @@ -99,7 +99,7 @@ // Create a new weapon holder (don't try to get an existing one, as no guarantee where it could be) private _weaponHolder = createVehicle ["GroundWeaponHolder", [0, 0, 0], [], 0, "CAN_COLLIDE"]; _weaponHolder setDir random [0, 180, 360]; - _weaponHolder setVehiclePosition [_weaponPos, [], 0, "CAN_COLLIDE"]; // places object on surface below + _weaponHolder setVehiclePosition [_weaponPos, [], 0, "CAN_COLLIDE"]; // Places object on surface below _weaponHolder addWeaponWithAttachmentsCargoGlobal [[_carryWeaponClassname, "", "", "", _carryWeaponMag, [], ""], 1]; }, [_player, _weaponPos, _carryWeaponClassname, _carryWeaponMag, _turretClassname]] call CBA_fnc_execNextFrame; @@ -108,23 +108,23 @@ // Eject dead units (all crew are dead or UAV at this point, otherwise condition would have failed), but ignore UAV units { if (unitIsUAV _x) then { - _staticWeapon deleteVehicleCrew _x; + _vehicle deleteVehicleCrew _x; } else { moveOut _x; }; - } forEach (crew _staticWeapon); + } forEach (crew _vehicle); - deleteVehicle _staticWeapon; + deleteVehicle _vehicle; LOG("end"); }; private _condition = { params ["_args"]; - _args params ["_staticWeapon"]; + _args params ["_vehicle"]; - _staticWeapon call FUNC(assemble_canPickupWeapon) + _vehicle call FUNC(assemble_canPickupWeapon) }; - [TIME_PROGRESSBAR(_pickupTime), [_staticWeapon, _player, _carryWeaponClassname, _turretClassname, _onDisassembleFunc], _onFinish, {}, LLSTRING(DisassembleCSW_progressBar), _condition] call EFUNC(common,progressBar); + [TIME_PROGRESSBAR(_pickupTime), [_vehicle, _player, _carryWeaponClassname, _turretClassname, _onDisassembleFunc], _onFinish, {}, LLSTRING(DisassembleCSW_progressBar), _condition] call EFUNC(common,progressBar); }, _this] call CBA_fnc_execNextFrame; diff --git a/addons/csw/functions/fnc_canDeployTripod.sqf b/addons/csw/functions/fnc_canDeployTripod.sqf index 8969758e4d..9eb7f0a133 100644 --- a/addons/csw/functions/fnc_canDeployTripod.sqf +++ b/addons/csw/functions/fnc_canDeployTripod.sqf @@ -1,10 +1,10 @@ #include "..\script_component.hpp" /* * Author: tcvm - * Checks if the unit can deploy a tripod + * Checks if the player can deploy the tripod. * * Arguments: - * 0: Unit + * 0: Player * * Return Value: * Can deploy @@ -15,8 +15,8 @@ * Public: No */ -params ["_unit"]; +params ["_player"]; -private _secondaryWeapon = secondaryWeapon _unit; +private _secondaryWeapon = secondaryWeapon _player; _secondaryWeapon != "" && {getText (configFile >> "CfgWeapons" >> _secondaryWeapon >> QUOTE(ADDON) >> "type") == "mount"} // return diff --git a/addons/csw/functions/fnc_canGetIn.sqf b/addons/csw/functions/fnc_canGetIn.sqf index 16446c4fb2..9e017c16ef 100644 --- a/addons/csw/functions/fnc_canGetIn.sqf +++ b/addons/csw/functions/fnc_canGetIn.sqf @@ -1,10 +1,10 @@ #include "..\script_component.hpp" /* * Author: tcvm - * Checks if it's possible to get in the CSW + * Checks if it's possible to get in the CSW. * * Arguments: - * 0: Vehicle + * 0: CSW * * Return Value: * None diff --git a/addons/csw/functions/fnc_canPickupTripod.sqf b/addons/csw/functions/fnc_canPickupTripod.sqf index 2ec3b065da..bf25b5a9e8 100644 --- a/addons/csw/functions/fnc_canPickupTripod.sqf +++ b/addons/csw/functions/fnc_canPickupTripod.sqf @@ -1,17 +1,16 @@ #include "..\script_component.hpp" /* * Author: tcvm - * Checks if the unit can pickup the tripod + * Checks if the player can pickup the tripod. * * Arguments: * 0: Tripod - * 1: Unit (not used) * * Return Value: * Can pickup * * Example: - * [cursorObject, player] call ace_csw_fnc_canPickupTripod + * cursorObject call ace_csw_fnc_canPickupTripod * * Public: No */ diff --git a/addons/csw/functions/fnc_getCarryMagazine.sqf b/addons/csw/functions/fnc_getCarryMagazine.sqf index 81e07c6f10..3d94ca2fe1 100644 --- a/addons/csw/functions/fnc_getCarryMagazine.sqf +++ b/addons/csw/functions/fnc_getCarryMagazine.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: PabstMirror, Dystopian - * Gets magazine that the player can carry, suitable to vehicle magazine + * Gets magazine that the player can carry, suitable to vehicle magazine. * * Arguments: * 0: Vehicle Magazine diff --git a/addons/csw/functions/fnc_getLoadActions.sqf b/addons/csw/functions/fnc_getLoadActions.sqf index e505c7f50f..2b28d2dbd6 100644 --- a/addons/csw/functions/fnc_getLoadActions.sqf +++ b/addons/csw/functions/fnc_getLoadActions.sqf @@ -1,10 +1,10 @@ #include "..\script_component.hpp" /* * Author: PabstMirror - * Gets sub actions for what the unit can load into the CSW + * Gets sub actions for what the player can load into the CSW. * * Arguments: - * 0: Vehicle + * 0: CSW * 1: Unit * * Return Value: @@ -35,7 +35,7 @@ private _condition = { ([_target, _turretPath, _carryMag, _magSource] call FUNC(reload_canLoadMagazine)) select 0 }; -private _cfgMagazines = configFile >> "CfgMagazines"; // micro-optimization +private _cfgMagazines = configFile >> "CfgMagazines"; // Micro-optimization private _actions = []; { _x params ["_carryMag", "", "_loadInfo"]; diff --git a/addons/csw/functions/fnc_initVehicle.sqf b/addons/csw/functions/fnc_initVehicle.sqf index 2d7241029f..80ff071f10 100644 --- a/addons/csw/functions/fnc_initVehicle.sqf +++ b/addons/csw/functions/fnc_initVehicle.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: tcvm - * Initializes CSW systems on vehicle + * Initializes CSW systems on vehicle. * * Arguments: * 0: Vehicle @@ -78,7 +78,7 @@ if (hasInterface && {!(_typeOf in GVAR(initializedStaticTypes))}) then { if ((GVAR(ammoHandling) == 0) && {!([false, true, true, GVAR(defaultAssemblyMode)] select (_target getVariable [QGVAR(assemblyMode), 3]))}) exitWith { false }; [_player, _target, ["isNotSwimming", "isNotSitting"]] call EFUNC(common,canInteractWith) }; - private _childenCode = { + private _childrenCode = { BEGIN_COUNTER(getActions); // can remove for final release private _ret = (call FUNC(getLoadActions)) + (call FUNC(getUnloadActions)); END_COUNTER(getActions); @@ -86,10 +86,10 @@ if (hasInterface && {!(_typeOf in GVAR(initializedStaticTypes))}) then { }; if (_configEnabled && {_magazineLocation != ""}) then { private _positionCode = compile _magazineLocation; - private _ammoAction = [QGVAR(magazine), LLSTRING(AmmoHandling_displayName), "", {}, _condition, _childenCode, [], _positionCode, 4] call EFUNC(interact_menu,createAction); + private _ammoAction = [QGVAR(magazine), LLSTRING(AmmoHandling_displayName), "", {}, _condition, _childrenCode, [], _positionCode, 4] call EFUNC(interact_menu,createAction); _ammoActionPath = [_typeOf, 0, [], _ammoAction] call EFUNC(interact_menu,addActionToClass); } else { - private _ammoAction = [QGVAR(magazine), LLSTRING(AmmoHandling_displayName), "", {}, _condition, _childenCode] call EFUNC(interact_menu,createAction); + private _ammoAction = [QGVAR(magazine), LLSTRING(AmmoHandling_displayName), "", {}, _condition, _childrenCode] call EFUNC(interact_menu,createAction); _ammoActionPath = [_typeOf, 0, ["ACE_MainActions"], _ammoAction] call EFUNC(interact_menu,addActionToClass); }; diff --git a/addons/csw/functions/fnc_proxyWeapon.sqf b/addons/csw/functions/fnc_proxyWeapon.sqf index fedd1d412b..42773dc7ec 100644 --- a/addons/csw/functions/fnc_proxyWeapon.sqf +++ b/addons/csw/functions/fnc_proxyWeapon.sqf @@ -1,10 +1,10 @@ #include "..\script_component.hpp" /* * Author: tcvm, PabstMirror - * Handles the use of proxy weapons to bypass engine reload times + * Handles the use of proxy weapons to fix engine-reload times. * * Arguments: - * 0: Vehicle + * 0: CSW * 1: Turret * 2: Proxy weapon needed * 2: Weapon should be emptied diff --git a/addons/csw/functions/fnc_reload_canLoadMagazine.sqf b/addons/csw/functions/fnc_reload_canLoadMagazine.sqf index 70c673299a..d4049706bd 100644 --- a/addons/csw/functions/fnc_reload_canLoadMagazine.sqf +++ b/addons/csw/functions/fnc_reload_canLoadMagazine.sqf @@ -1,16 +1,16 @@ #include "..\script_component.hpp" /* - * Author: PabstMirror &tcvm - * Tests if unit can load a magazine into a static weapon. + * Author: PabstMirror, tcvm + * Tests if unit can load a magazine into a CSW. * * Arguments: - * 0: Static Weapon + * 0: CSW * 1: Turret Path * 2: Carryable Magazine - * 3: Supplier + * 3: Supplier (default: objNull) * * Return Value: - * [CanLoad, LoadedMag, AmmoNeeded, IsBeltLinking] + * [Can Load , Loaded Mag , Ammo Needed , Is Belt Linking ] * * Example: * [cursorObject, [0], "ACE_csw_100Rnd_127x99_mag_red", player] call ace_csw_fnc_reload_canLoadMagazine @@ -28,7 +28,7 @@ if (!alive _vehicle) exitWith { _return }; // Verify holder has carry magazine if ( (!isNull _magSource) && - {!((_magSource isKindOf "Bag_Base") || {_magSource isKindOf "ContainerSupply"})} && // hacky workaround for magazines within dropped backpacks + {!((_magSource isKindOf "Bag_Base") || {_magSource isKindOf "ContainerSupply"})} && // Hacky workaround for magazines within dropped backpacks { ((_vehicle distance _magSource) > 10) || {((magazineCargo _magSource) findIf {_x == _carryMag}) == -1} @@ -42,7 +42,7 @@ private _cfgGroupsCarryMag = configFile >> QGVAR(groups) >> _carryMag; private _desiredAmmo = getNumber (configOf _vehicle >> QUOTE(ADDON) >> "desiredAmmo"); if (_desiredAmmo == 0) then { _desiredAmmo = 100; }; -private _ammoNeeded = _desiredAmmo min getNumber (_cfgMagazinesCarryMag >> "count"); // assume it needs full carry mag +private _ammoNeeded = _desiredAmmo min getNumber (_cfgMagazinesCarryMag >> "count"); // Assume it needs full carry mag private _loadedMag = ""; private _isBeltLinking = false; @@ -62,7 +62,7 @@ scopeName "main"; }; private _maxMagazineAmmo = _desiredAmmo min getNumber (_cfgMagazines >> _xMag >> "count"); if (_xAmmo >= _maxMagazineAmmo) exitWith { - [false, _loadedMag, -6, false] breakOut "main"; // Already at capicity + [false, _loadedMag, -6, false] breakOut "main"; // Already at capacity }; _ammoNeeded = _maxMagazineAmmo - _xAmmo; _isBeltLinking = true; diff --git a/addons/csw/functions/fnc_reload_canUnloadMagazine.sqf b/addons/csw/functions/fnc_reload_canUnloadMagazine.sqf index 4e03625a29..d7899e655a 100644 --- a/addons/csw/functions/fnc_reload_canUnloadMagazine.sqf +++ b/addons/csw/functions/fnc_reload_canUnloadMagazine.sqf @@ -1,10 +1,10 @@ #include "..\script_component.hpp" /* * Author: PabstMirror - * Tests if unit can unload a magazine from a static weapon. + * Tests if unit can unload a magazine from a CSW. * * Arguments: - * 0: Static Weapon + * 0: CSW * 1: Turret Path * 2: Player * 3: Carryable Magazine diff --git a/addons/csw/functions/fnc_reload_getLoadableMagazines.sqf b/addons/csw/functions/fnc_reload_getLoadableMagazines.sqf index 724ee4d09c..861f70350d 100644 --- a/addons/csw/functions/fnc_reload_getLoadableMagazines.sqf +++ b/addons/csw/functions/fnc_reload_getLoadableMagazines.sqf @@ -1,15 +1,15 @@ #include "..\script_component.hpp" /* * Author: PabstMirror - * Gets magazines that the player is carrying that can be loaded into the static weapon + * Gets nearby magazines that can be loaded into the CSW. * * Arguments: - * 0: Vehicle - * 1: Player + * 0: CSW + * 1: Unit * * Return Value: * Mags - * [Carry Magazine , Turret Path , Load Info , Magazine Source ] + * [Carry Magazine , Turret Path , Load Info , Magazine Source ] * * Example: * [cursorObject, player] call ace_csw_fnc_reload_getLoadableMagazines diff --git a/addons/csw/functions/fnc_reload_getVehicleMagazine.sqf b/addons/csw/functions/fnc_reload_getVehicleMagazine.sqf index 6b5b77efee..3682651aac 100644 --- a/addons/csw/functions/fnc_reload_getVehicleMagazine.sqf +++ b/addons/csw/functions/fnc_reload_getVehicleMagazine.sqf @@ -4,7 +4,7 @@ * Finds the best vehicle magazines to create from a carryable magazine for a given weapon. * * Arguments: - * 0: Vehicle + * 0: CSW * 1: Turret * 2: Magazine that is carryable * diff --git a/addons/csw/functions/fnc_reload_handleAddTurretMag.sqf b/addons/csw/functions/fnc_reload_handleAddTurretMag.sqf index c752f76f59..389ae699a4 100644 --- a/addons/csw/functions/fnc_reload_handleAddTurretMag.sqf +++ b/addons/csw/functions/fnc_reload_handleAddTurretMag.sqf @@ -1,11 +1,11 @@ #include "..\script_component.hpp" /* * Author: tcvm, PabstMirror - * Handles adding ammo to a turret - * Called from a global event but only runs where turret is local + * Handles adding ammo to a turret. + * Called from a global event but only runs where turret is local. * * Arguments: - * 0: Static Weapon + * 0: CSW * 1: Turret Path * 2: Source of magazine * 3: Vehicle Magazine diff --git a/addons/csw/functions/fnc_reload_handleRemoveTurretMag.sqf b/addons/csw/functions/fnc_reload_handleRemoveTurretMag.sqf index 51036b525a..dccc9b16d4 100644 --- a/addons/csw/functions/fnc_reload_handleRemoveTurretMag.sqf +++ b/addons/csw/functions/fnc_reload_handleRemoveTurretMag.sqf @@ -1,13 +1,13 @@ #include "..\script_component.hpp" /* * Author: tcvm - * Handles removing ammo from a turret - * Called from a global event but only runs where turret is local + * Handles removing ammo from a turret. + * Called from a global event but only runs where turret is local. * * Arguments: - * 0: Static Weapon + * 0: CSW * 1: Turret Path - * 2: Magainze Unit Can Carry + * 2: Magazine Unit Can Carry * 3: Magazine To Remove From Static * 4: Unit or container to unload to * diff --git a/addons/csw/functions/fnc_reload_handleReturnAmmo.sqf b/addons/csw/functions/fnc_reload_handleReturnAmmo.sqf index 864bb2ab6f..009a39c0d1 100644 --- a/addons/csw/functions/fnc_reload_handleReturnAmmo.sqf +++ b/addons/csw/functions/fnc_reload_handleReturnAmmo.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* - * Author: tcvm and PabstMirror - * Handles returned ammo (either from unloading or leftovers from linking) + * Author: tcvm, PabstMirror + * Handles returned ammo (either from unloading or leftovers from linking). * * Arguments: * 0: Man or Vehicle diff --git a/addons/csw/functions/fnc_reload_loadMagazine.sqf b/addons/csw/functions/fnc_reload_loadMagazine.sqf index 07db0fb146..ac6e992fb8 100644 --- a/addons/csw/functions/fnc_reload_loadMagazine.sqf +++ b/addons/csw/functions/fnc_reload_loadMagazine.sqf @@ -1,10 +1,10 @@ #include "..\script_component.hpp" /* * Author: PabstMirror - * Loads a magazine into a static weapon from a magazine carried by or next to the player. + * Loads a magazine into a CSW from a magazine carried by or next to the player. * * Arguments: - * 0: Vehicle + * 0: CSW * 1: Turret * 2: Unit Carried Magazine * 3: Magazine source diff --git a/addons/csw/functions/fnc_staticWeaponInit_unloadExtraMags.sqf b/addons/csw/functions/fnc_staticWeaponInit_unloadExtraMags.sqf index 98200840a3..1c27a494d5 100644 --- a/addons/csw/functions/fnc_staticWeaponInit_unloadExtraMags.sqf +++ b/addons/csw/functions/fnc_staticWeaponInit_unloadExtraMags.sqf @@ -1,11 +1,12 @@ #include "..\script_component.hpp" /* * Author: tcvm, PabstMirror - * Dumps ammo to container + * Dumps ammo to container. * * Arguments: - * 0: Weapon + * 0: CSW * 1: Using advanced assembly + * 2: Empty weapon * * Return Value: * None @@ -16,11 +17,11 @@ * Public: No */ -params ["_staticWeapon", "_assemblyMode", "_emptyWeapon"]; -TRACE_3("staticWeaponInit_unloadExtraMags",_staticWeapon,_assemblyMode,_emptyWeapon); +params ["_vehicle", "_assemblyMode", "_emptyWeapon"]; +TRACE_3("staticWeaponInit_unloadExtraMags",_vehicle,_assemblyMode,_emptyWeapon); if (!_assemblyMode) exitWith {}; -private _desiredAmmo = getNumber (configOf _staticWeapon >> QUOTE(ADDON) >> "desiredAmmo"); +private _desiredAmmo = getNumber (configOf _vehicle >> QUOTE(ADDON) >> "desiredAmmo"); private _storeExtraMagazines = GVAR(handleExtraMagazines); if (_emptyWeapon) then { _desiredAmmo = 0; @@ -56,41 +57,41 @@ private _containerMagazineCount = []; } else { if ((_xMag select [0,4]) != "fake") then { WARNING_1("Unable to unload [%1] - No matching carry mag",_xMag); }; }; -} forEach (magazinesAllTurrets _staticWeapon); +} forEach (magazinesAllTurrets _vehicle); TRACE_1("Remove all loaded magazines",_magsToRemove); { - _staticWeapon removeMagazinesTurret _x; + _vehicle removeMagazinesTurret _x; if ((_loadedMagazineInfo select [0,2]) isEqualTo _x) then { TRACE_1("Re-add the starting mag",_loadedMagazineInfo); - _staticWeapon addMagazineTurret _loadedMagazineInfo; + _vehicle addMagazineTurret _loadedMagazineInfo; }; } forEach _magsToRemove; -private _secondaryWeaponMagazines = _staticWeapon getVariable [QGVAR(secondaryWeaponMagazines), []]; +private _secondaryWeaponMagazines = _vehicle getVariable [QGVAR(secondaryWeaponMagazines), []]; if (_secondaryWeaponMagazines isNotEqualTo []) then { // Check if the static weapon can take magazines - private _turret = (allTurrets _staticWeapon) param [0, []]; - private _compatibleMagazinesTurret = flatten ((_staticWeapon weaponsTurret _turret) apply {compatibleMagazines _x}); + private _turret = (allTurrets _vehicle) param [0, []]; + private _compatibleMagazinesTurret = flatten ((_vehicle weaponsTurret _turret) apply {compatibleMagazines _x}); private _container = objNull; { - private _vehicleMag = [_staticWeapon, _turret, _x select 0] call FUNC(reload_getVehicleMagazine); + private _vehicleMag = [_vehicle, _turret, _x select 0] call FUNC(reload_getVehicleMagazine); TRACE_3("Re-add previous mag",_x select 0,_turret,_vehicleMag); // If the magazine can be added to the static weapon, do it now if (_vehicleMag in _compatibleMagazinesTurret) then { - _staticWeapon addMagazineTurret [_vehicleMag, _turret, _x select 1]; + _vehicle addMagazineTurret [_vehicleMag, _turret, _x select 1]; } else { // Find a suitable container to place items in if necessary if (isNull _container) then { - _container = (nearestObjects [_staticWeapon, ["GroundWeaponHolder"], 10]) param [0, objNull]; + _container = (nearestObjects [_vehicle, ["GroundWeaponHolder"], 10]) param [0, objNull]; // Create ammo storage container if (isNull _container) then { - _container = createVehicle ["GroundWeaponHolder", getPosATL _staticWeapon, [], 0, "NONE"]; + _container = createVehicle ["GroundWeaponHolder", getPosATL _vehicle, [], 0, "NONE"]; }; }; @@ -99,12 +100,12 @@ if (_secondaryWeaponMagazines isNotEqualTo []) then { }; } forEach _secondaryWeaponMagazines; - _staticWeapon setVariable [QGVAR(secondaryWeaponMagazines), nil, true]; + _vehicle setVariable [QGVAR(secondaryWeaponMagazines), nil, true]; }; if (_storeExtraMagazines) then { TRACE_1("saving extra mags to container",_containerMagazineCount); { - [_staticWeapon, _x, _containerMagazineCount select _forEachIndex] call FUNC(reload_handleReturnAmmo); + [_vehicle, _x, _containerMagazineCount select _forEachIndex] call FUNC(reload_handleReturnAmmo); } forEach _containerMagazineClassnames; }; From a6ab050a075a8cf930c0034a394bdd3ec4c2475e Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Sun, 28 Jul 2024 11:43:03 -0500 Subject: [PATCH 168/290] Dogtags - Rename inventory items via CBA (#10130) * Dogtags - Rename inventory items via CBA * Update addons/dogtags/XEH_postInit.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --------- Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- addons/dogtags/XEH_postInit.sqf | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/addons/dogtags/XEH_postInit.sqf b/addons/dogtags/XEH_postInit.sqf index 3ced843f47..c072090a60 100644 --- a/addons/dogtags/XEH_postInit.sqf +++ b/addons/dogtags/XEH_postInit.sqf @@ -3,6 +3,18 @@ if (hasInterface || isServer) then { [QGVAR(broadcastDogtagInfo), { GVAR(dogtagsData) set _this; + + if (isNil "CBA_fnc_renameInventoryItem") exitWith {}; // requires https://github.com/CBATeam/CBA_A3/pull/1329 + params ["_item", "_dogTagData"]; + private _name = _dogtagData param [0, ""]; + + // If data doesn't exist or body has no name, set name as "unknown" + if (_name == "") then { + _name = LELSTRING(common,unknown); + }; + + _name = [LLSTRING(itemName), ": ", _name] joinString ""; + [_item, _name] call CBA_fnc_renameInventoryItem; }] call CBA_fnc_addEventHandler; if (isServer) then { From 7e93715bcc1b626e8409f582f79e7d994d502076 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Mon, 29 Jul 2024 08:04:36 -0500 Subject: [PATCH 169/290] Medical - Gracefully handle bad configs in testHitpoints (#10156) --- addons/medical/dev/test_hitpointConfigs.sqf | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/addons/medical/dev/test_hitpointConfigs.sqf b/addons/medical/dev/test_hitpointConfigs.sqf index 7bdeb189c2..ff1c3a95b7 100644 --- a/addons/medical/dev/test_hitpointConfigs.sqf +++ b/addons/medical/dev/test_hitpointConfigs.sqf @@ -10,7 +10,11 @@ private _cfgWeapons = configFile >> "CfgWeapons"; private _cfgVehicles = configFile >> "CfgVehicles"; private _uniforms = "getNumber (_x >> 'scope') == 2 && {configName _x isKindOf ['Uniform_Base', _cfgWeapons]}" configClasses _cfgWeapons; -private _units = _uniforms apply {_cfgVehicles >> getText (_x >> "ItemInfo" >> "uniformClass")}; +private _units = _uniforms apply { + private _unitCfg = _cfgVehicles >> getText (_x >> "ItemInfo" >> "uniformClass"); + if (isNull _unitCfg) then { WARNING_2("%1 has invalid uniformClass %2",configName _x,getText (_x >> "ItemInfo" >> "uniformClass")) }; + _unitCfg +}; if (param [0, false]) then { // Check all units (if naked) INFO("checking ALL units"); _units append ((configProperties [configFile >> "CfgVehicles", "(isClass _x) && {(getNumber (_x >> 'scope')) == 2} && {configName _x isKindOf 'CAManBase'}", true])); @@ -21,6 +25,7 @@ INFO_1("Checking uniforms for correct medical hitpoints [%1 units]",count _units private _testPass = true; { private _typeOf = configName _x; + if (_typeOf == "") then { continue }; private _hitpoints = (configProperties [_x >> "HitPoints", "isClass _x", true]) apply {toLowerANSI configName _x}; private _expectedHitPoints = ["hitleftarm","hitrightarm","hitleftleg","hitrightleg","hithead","hitbody"]; private _missingHitPoints = _expectedHitPoints select {!(_x in _hitpoints)}; From 98da279e8f46f29e89b712c9717495083f512fbd Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 29 Jul 2024 15:04:59 +0200 Subject: [PATCH 170/290] Medical AI - Give blood in Cardiac Arrest before doing CPR (#10154) Give blood in CA if needed before doing CPR --- .../medical_ai/functions/fnc_healingLogic.sqf | 93 +++++++++++++++---- .../functions/fnc_playTreatmentAnim.sqf | 2 +- .../medical_ai/functions/fnc_requestMedic.sqf | 7 +- addons/medical_ai/stateMachine.inc.sqf | 9 +- 4 files changed, 84 insertions(+), 27 deletions(-) diff --git a/addons/medical_ai/functions/fnc_healingLogic.sqf b/addons/medical_ai/functions/fnc_healingLogic.sqf index a007b83e4c..213d763b97 100644 --- a/addons/medical_ai/functions/fnc_healingLogic.sqf +++ b/addons/medical_ai/functions/fnc_healingLogic.sqf @@ -35,6 +35,23 @@ if (_finishTime > 0) exitWith { }; if ((_treatmentTarget == _target) && {(_treatmentEvent select [0, 1]) != "#"}) then { [_treatmentEvent, _treatmentArgs, _target] call CBA_fnc_targetEvent; + + // Splints are already logged on their own + switch (_treatmentEvent) do { + case QEGVAR(medical_treatment,bandageLocal): { + [_target, "activity", ELSTRING(medical_treatment,Activity_bandagedPatient), [[_healer, false, true] call EFUNC(common,getName)]] call EFUNC(medical_treatment,addToLog); + }; + case QEGVAR(medical_treatment,ivBagLocal): { + [_target, _treatmentArgs select 2] call EFUNC(medical_treatment,addToTriageCard); + [_target, "activity", ELSTRING(medical_treatment,Activity_gaveIV), [[_healer, false, true] call EFUNC(common,getName)]] call EFUNC(medical_treatment,addToLog); + }; + case QEGVAR(medical_treatment,medicationLocal): { + private _usedItem = ["ACE_epinephrine", "ACE_morphine"] select (_treatmentArgs select 2 == "Morphine"); + [_target, _usedItem] call EFUNC(medical_treatment,addToTriageCard); + [_target, "activity", ELSTRING(medical_treatment,Activity_usedItem), [[_healer, false, true] call EFUNC(common,getName), getText (configFile >> "CfgWeapons" >> _usedItem >> "displayName")]] call EFUNC(medical_treatment,addToLog); + }; + }; + #ifdef DEBUG_MODE_FULL INFO_4("%1->%2: %3 - %4",_healer,_target,_treatmentEvent,_treatmentArgs); systemChat format ["Applying [%1->%2]: %3", _healer, _treatmentTarget, _treatmentEvent]; @@ -75,9 +92,12 @@ private _treatmentEvent = "#none"; private _treatmentArgs = []; private _treatmentTime = 6; private _treatmentItem = ""; -switch (true) do { - case ((GET_WOUND_BLEEDING(_target) > 0) - && {([_healer, "@bandage"] call FUNC(itemCheck)) # 0}): { + +if (true) then { + if ( + (GET_WOUND_BLEEDING(_target) > 0) && + {([_healer, "@bandage"] call FUNC(itemCheck)) # 0} + ) exitWith { // Select first bleeding wound and bandage it private _selection = "?"; { @@ -94,13 +114,26 @@ switch (true) do { _treatmentArgs = [_target, _selection, "FieldDressing"]; _treatmentItem = "@bandage"; }; - case (IN_CRDC_ARRST(_target) && {EGVAR(medical_treatment,cprSuccessChanceMin) > 0}): { + + private _hasIV = ([_healer, "@iv"] call FUNC(itemCheck)) # 0; + private _bloodVolume = GET_BLOOD_VOLUME(_target); + + // If in cardiac arrest, first add some blood to injured if necessary, then do CPR (doing CPR when not enough blood is suboptimal if you have IVs) + // If healer has no IVs, allow AI to do CPR to keep injured alive + if ( + IN_CRDC_ARRST(_target) && + {EGVAR(medical_treatment,cprSuccessChanceMin) > 0} && + {!_hasIV || {_bloodVolume >= BLOOD_VOLUME_CLASS_3_HEMORRHAGE}} + ) exitWith { _treatmentEvent = QEGVAR(medical_treatment,cprLocal); _treatmentArgs = [_healer, _target]; _treatmentTime = 15; }; - case (_isMedic && {GET_BLOOD_VOLUME(_target) < MINIMUM_BLOOD_FOR_STABLE_VITALS} - && {([_healer, "@iv"] call FUNC(itemCheck)) # 0}): { + + private _needsIv = _bloodVolume < MINIMUM_BLOOD_FOR_STABLE_VITALS; + private _canGiveIv = _isMedic && _hasIV && _needsIv; + + if (_canGiveIv) then { // Check if patient's blood volume + remaining IV volume is enough to allow the patient to wake up private _totalIvVolume = 0; //in ml { @@ -108,33 +141,55 @@ switch (true) do { _totalIvVolume = _totalIvVolume + _volumeRemaining; } forEach (_target getVariable [QEGVAR(medical,ivBags), []]); - if (GET_BLOOD_VOLUME(_target) + (_totalIvVolume / 1000) > MINIMUM_BLOOD_FOR_STABLE_VITALS) exitWith { - _treatmentEvent = "#waitForBlood"; + // Check if the medic has to wait, which allows for a little multitasking + if (_bloodVolume + (_totalIvVolume / 1000) >= MINIMUM_BLOOD_FOR_STABLE_VITALS) then { + _treatmentEvent = "#waitForIV"; + _canGiveIv = false; }; + }; + + if (_canGiveIv) exitWith { _treatmentEvent = QEGVAR(medical_treatment,ivBagLocal); _treatmentTime = 5; _treatmentArgs = [_target, call _fnc_findNoTourniquet, "SalineIV"]; _treatmentItem = "@iv"; }; - case (((_fractures select 4) == 1) - && {([_healer, "splint"] call FUNC(itemCheck)) # 0}): { + + if ( + ((_fractures select 4) == 1) && + {([_healer, "splint"] call FUNC(itemCheck)) # 0} + ) exitWith { _treatmentEvent = QEGVAR(medical_treatment,splintLocal); _treatmentTime = 6; _treatmentArgs = [_healer, _target, "leftleg"]; _treatmentItem = "splint"; }; - case (((_fractures select 5) == 1) - && {([_healer, "splint"] call FUNC(itemCheck)) # 0}): { + + if ( + ((_fractures select 5) == 1) && + {([_healer, "splint"] call FUNC(itemCheck)) # 0} + ) exitWith { _treatmentEvent = QEGVAR(medical_treatment,splintLocal); _treatmentTime = 6; _treatmentArgs = [_healer, _target, "rightleg"]; _treatmentItem = "splint"; }; - case ((count (_target getVariable [VAR_MEDICATIONS, []])) >= 6): { + + // Wait until the injured has enough blood before administering drugs + if (_needsIv) then { + _treatmentEvent = "#waitForIV" + }; + + if (_treatmentEvent == "#waitForIV") exitWith {}; + + if ((count (_target getVariable [VAR_MEDICATIONS, []])) >= 6) exitWith { _treatmentEvent = "#tooManyMeds"; }; - case ((IS_UNCONSCIOUS(_target) || {_heartRate <= 50}) - && {([_healer, "epinephrine"] call FUNC(itemCheck)) # 0}): { + + if ( + ((IS_UNCONSCIOUS(_target) && {_heartRate < 160}) || {_heartRate <= 50}) && + {([_healer, "epinephrine"] call FUNC(itemCheck)) # 0} + ) exitWith { if (CBA_missionTime < (_target getVariable [QGVAR(nextEpinephrine), -1])) exitWith { _treatmentEvent = "#waitForEpinephrineToTakeEffect"; }; @@ -147,8 +202,11 @@ switch (true) do { _treatmentArgs = [_target, call _fnc_findNoTourniquet, "Epinephrine"]; _treatmentItem = "epinephrine"; }; - case (((GET_PAIN_PERCEIVED(_target) > 0.25) || {_heartRate >= 180}) - && {([_healer, "morphine"] call FUNC(itemCheck)) # 0}): { + + if ( + (((GET_PAIN_PERCEIVED(_target) > 0.25) && {_heartRate > 40}) || {_heartRate >= 180}) && + {([_healer, "morphine"] call FUNC(itemCheck)) # 0} + ) exitWith { if (CBA_missionTime < (_target getVariable [QGVAR(nextMorphine), -1])) exitWith { _treatmentEvent = "#waitForMorphineToTakeEffect"; }; @@ -169,6 +227,7 @@ _healer setVariable [QGVAR(currentTreatment), [CBA_missionTime + _treatmentTime, if ((_treatmentEvent select [0,1]) != "#") then { private _treatmentClassname = _treatmentArgs select 2; if (_treatmentEvent == QEGVAR(medical_treatment,splintLocal)) then { _treatmentClassname = "Splint" }; + if (_treatmentEvent == QEGVAR(medical_treatment,cprLocal)) then { _treatmentClassname = "CPR" }; [_healer, _treatmentClassname, (_healer == _target)] call FUNC(playTreatmentAnim); }; diff --git a/addons/medical_ai/functions/fnc_playTreatmentAnim.sqf b/addons/medical_ai/functions/fnc_playTreatmentAnim.sqf index cb142f0288..9b663f65b2 100644 --- a/addons/medical_ai/functions/fnc_playTreatmentAnim.sqf +++ b/addons/medical_ai/functions/fnc_playTreatmentAnim.sqf @@ -12,7 +12,7 @@ * None * * Example: - * [cursorObject, true, true] call ace_medical_ai_fnc_playTreatmentAnim + * [cursorObject, "Splint", true] call ace_medical_ai_fnc_playTreatmentAnim * * Public: No */ diff --git a/addons/medical_ai/functions/fnc_requestMedic.sqf b/addons/medical_ai/functions/fnc_requestMedic.sqf index 0ea2584fbf..758fa80a1f 100644 --- a/addons/medical_ai/functions/fnc_requestMedic.sqf +++ b/addons/medical_ai/functions/fnc_requestMedic.sqf @@ -17,8 +17,11 @@ private _assignedMedic = _this getVariable QGVAR(assignedMedic); private _healQueue = _assignedMedic getVariable [QGVAR(healQueue), []]; -_healQueue pushBack _this; -_assignedMedic setVariable [QGVAR(healQueue), _healQueue]; + +// Only update if it was actually changed +if (_healQueue pushBackUnique _this != -1) then { + _assignedMedic setVariable [QGVAR(healQueue), _healQueue]; +}; #ifdef DEBUG_MODE_FULL systemChat format ["%1 requested %2 for medical treatment", _this, _assignedMedic]; diff --git a/addons/medical_ai/stateMachine.inc.sqf b/addons/medical_ai/stateMachine.inc.sqf index 03483f4981..73b82f98a9 100644 --- a/addons/medical_ai/stateMachine.inc.sqf +++ b/addons/medical_ai/stateMachine.inc.sqf @@ -17,13 +17,8 @@ GVAR(stateMachine) = [{call EFUNC(common,getLocalUnits)}, true] call CBA_statema #endif }, {}, {}, "Safe"] call CBA_statemachine_fnc_addState; -[GVAR(stateMachine), LINKFUNC(healSelf), {}, { - _this setVariable [QGVAR(treatmentOverAt), nil]; -}, "HealSelf"] call CBA_statemachine_fnc_addState; - -[GVAR(stateMachine), LINKFUNC(healUnit), {}, { - _this setVariable [QGVAR(treatmentOverAt), nil]; -}, "HealUnit"] call CBA_statemachine_fnc_addState; +[GVAR(stateMachine), LINKFUNC(healSelf), {}, {}, "HealSelf"] call CBA_statemachine_fnc_addState; +[GVAR(stateMachine), LINKFUNC(healUnit), {}, {}, "HealUnit"] call CBA_statemachine_fnc_addState; // Add Transistions [statemachine, originalState, targetState, condition, onTransition, name] [GVAR(stateMachine), "Initial", "Injured", LINKFUNC(isInjured), {}, "Injured"] call CBA_statemachine_fnc_addTransition; From 4e56d58210100850cd8139d453c0cd061d8db788 Mon Sep 17 00:00:00 2001 From: Enrico Machado Date: Wed, 31 Jul 2024 02:45:31 +0100 Subject: [PATCH 171/290] Translations - Add and Improve Portuguese (#10155) --- addons/captives/stringtable.xml | 1 + .../compat_cup_weapons_csw/stringtable.xml | 7 +++ addons/fastroping/stringtable.xml | 3 +- addons/hearing/stringtable.xml | 2 + addons/hitreactions/stringtable.xml | 2 + addons/medical_gui/stringtable.xml | 36 +++++++++++ addons/medical_statemachine/stringtable.xml | 2 + addons/medical_status/stringtable.xml | 2 + addons/medical_treatment/stringtable.xml | 61 +++++++++++++++++++ addons/medical_vitals/stringtable.xml | 2 + addons/microdagr/stringtable.xml | 2 + addons/nightvision/stringtable.xml | 36 +++++++++-- addons/noradio/stringtable.xml | 1 + addons/novehicleclanlogo/stringtable.xml | 2 + addons/overheating/stringtable.xml | 5 ++ addons/parachute/stringtable.xml | 1 + addons/realisticnames/stringtable.xml | 13 +++- addons/reload/stringtable.xml | 6 +- addons/reloadlaunchers/stringtable.xml | 6 ++ addons/smallarms/stringtable.xml | 6 ++ addons/towing/stringtable.xml | 12 ++++ addons/trenches/stringtable.xml | 10 +++ addons/ui/stringtable.xml | 5 ++ addons/vehicle_damage/stringtable.xml | 4 ++ addons/vehiclelock/stringtable.xml | 1 + addons/vehicles/stringtable.xml | 2 + addons/viewdistance/stringtable.xml | 1 + addons/viewports/stringtable.xml | 2 + addons/viewrestriction/stringtable.xml | 20 ++++++ addons/volume/stringtable.xml | 16 +++++ 30 files changed, 259 insertions(+), 10 deletions(-) diff --git a/addons/captives/stringtable.xml b/addons/captives/stringtable.xml index 4fc86ec58f..dfc293028d 100644 --- a/addons/captives/stringtable.xml +++ b/addons/captives/stringtable.xml @@ -158,6 +158,7 @@ 目隠しを外す Снять повязку с глаз Quitar vendas de los ojos + Remover a venda Cable Tie diff --git a/addons/compat_cup_weapons/compat_cup_weapons_csw/stringtable.xml b/addons/compat_cup_weapons/compat_cup_weapons_csw/stringtable.xml index ea16be2905..89b025d647 100644 --- a/addons/compat_cup_weapons/compat_cup_weapons_csw/stringtable.xml +++ b/addons/compat_cup_weapons/compat_cup_weapons_csw/stringtable.xml @@ -9,6 +9,7 @@ [CSW] AGS30 Gurt [CSW] Cinta de AGS30 [CSW] Nastro AGS30 + [CSW] Cinto de AGS30 [CSW] MK19 Belt @@ -18,6 +19,7 @@ [CSW] MK19 Gurt [CSW] Cinta de MK19 [CSW] Nastro MK19 + [CSW] Cinto de MK19 [CSW] TOW Tube @@ -27,6 +29,7 @@ [CSW] TOW Rohr [CSW] Tubo de TOW [CSW] Tubo TOW + [CSW] Tubo de TOW [CSW] TOW2 Tube @@ -36,6 +39,7 @@ [CSW] TOW2 Rohr [CSW] Tubo de TOW2 [CSW] Tubo TOW2 + [CSW] Tubo de TOW2 [CSW] PG-9 Round @@ -45,6 +49,7 @@ [CSW] PG-9 Rakete [CSW] Carga de PG-9 [CSW] Razzo PG-9 + [CSW] Cartucho PG-9 [CSW] OG-9 Round @@ -54,6 +59,7 @@ [CSW] OG-9 Rakete [CSW] Carga de OG-9 [CSW] Razzo OG-9 + [CSW] Cartucho OG-9 [CSW] M1 HE @@ -74,6 +80,7 @@ [CSW] M84 Rauch [CSW] Humo M84 [CSW] M84 Fumogeno + [CSW] M84 Fumígeno [CSW] M60A2 WP diff --git a/addons/fastroping/stringtable.xml b/addons/fastroping/stringtable.xml index 10ea50a7c5..89418c0f99 100644 --- a/addons/fastroping/stringtable.xml +++ b/addons/fastroping/stringtable.xml @@ -134,7 +134,7 @@ Equipa el helicoptero seleccionado con un Sistema de Inserción/Extracción Rápida por Cuerda Equipaggia l'elicottero selezionato con il Fast Rope Insertion Extraction System Vybavit vybraný vrtulník systémem Fast Rope Insertion Extraction (FRIES) - Equipa um helicóptero selecionado com um sistema de Fast Rope Insertion Extraction System + Equipa o helicóptero selecionado com um Sistema de Inserção/Extração Rápida por Corda Снаряжает выбранный вертолет оборудованием для спуска десанта по канатам 選択されたヘリコプターで Fast Rope Insertion Extraction System を使えるようにします。 선택된 헬리콥터에 패스트로프 투입 및 탈출 시스템을 장착합니다. @@ -298,6 +298,7 @@ Schnelles-Abseilen Fast Rope 패스트로프 + Descida rápida pela corda Require rope item to deploy diff --git a/addons/hearing/stringtable.xml b/addons/hearing/stringtable.xml index 9aba1ab56b..08419d4e42 100644 --- a/addons/hearing/stringtable.xml +++ b/addons/hearing/stringtable.xml @@ -372,6 +372,7 @@ Mettre/enlever les bouchons Ohrstöpsel einsetzen/herausnehmen Poner/quitar tapones + Colocar/retirar protetores auriculares Only units with heavy weapons @@ -382,6 +383,7 @@ Sólo unidades con armas pesadas Solo a unità con armi pesanti 중화기를 가진 유닛만 해당 + Apenas unidades com armas pesadas diff --git a/addons/hitreactions/stringtable.xml b/addons/hitreactions/stringtable.xml index ff541ad6a3..251cd437bc 100644 --- a/addons/hitreactions/stringtable.xml +++ b/addons/hitreactions/stringtable.xml @@ -24,6 +24,7 @@ 플레이어가 무기를 떨굴 확률 (팔 피격) Spieler Wahrscheinlichkeit, die Waffe fallen zu lassen (Arm Treffer) Probabilità dei giocatori di far cadere l'arma (colpo al braccio) + Probabilidade do jogador de largar a arma após tiro no braço AI Weapon Drop Chance (Arm Hit) @@ -32,6 +33,7 @@ 인공지능이 무기를 떨굴 확률 (팔 피격) KI-Wahrscheinlichkeit, die Waffe fallen zu lassen (Arm Treffer) Probabilità dell'IA di far cadere l'arma (colpo al braccio) + Probabilidade da IA de largar a arma após tiro no braço diff --git a/addons/medical_gui/stringtable.xml b/addons/medical_gui/stringtable.xml index 3f816aa39b..6dfc16f9b9 100644 --- a/addons/medical_gui/stringtable.xml +++ b/addons/medical_gui/stringtable.xml @@ -222,6 +222,7 @@ Zeige Triage-Einstufung im Interaktionsmenü 在交互式菜单中显示分诊级别 상호작용 메뉴에서 부상자 카드 보기 + Mostrar Nível de Triagem no Menu de Interação Shows the patient's triage level by changing the color of the main and medical menu actions. @@ -234,6 +235,7 @@ Zeigt die Triage-Einstufung des Patienten durch Ändern der Farbe der Aktionen des Hauptmenüs und des medizinischen Menüs an. 通过改变主菜单和医疗菜单动作的颜色来显示伤员的分诊级别。 환자의 부상자 카드를 상호작용에서 볼 수 있게 합니다. + Mostra o nível de triagem do paciente alterando a cor das ações do menu principal e do menu médico. Medical @@ -294,6 +296,7 @@ 医療情報一時表示 Просмотр медицинской информации Ojear Información Médica + Visualização rápida das informações médicas Medical Peek Duration @@ -305,6 +308,7 @@ 医療情報一時表示の表示時間 Продолжительность медицинского осмотра Duración del Ojear Información Médica + Duração da visualização geral das informações médicas How long the medical info peek remains open after releasing the key. @@ -316,6 +320,7 @@ 医療情報一時表示キーを放してからどれだけ長く情報表示するか。 Как долго окно просмотра медицинской информации остается открытым после отпускания клавиши. Durante cuánto tiempo la información médica ojeada permanece abierta una ves se deje de apretar la tecla. + Quanto tempo a visualização rápida das informações médicas permanece aberta após soltar a tecla. Load Patient @@ -570,6 +575,7 @@ 自分に切り替え Переключиться на себя Cambiar a uno mismo + Trocar para si mesmo Switch to target @@ -581,6 +587,7 @@ 相手に切り替え Переключиться на цель Cambiar al objetivo + Trocar para paciente Head @@ -1008,6 +1015,7 @@ 出血はしていない Кровотечения нет Sin sangrado + Sem sangramento Slow bleeding @@ -1019,6 +1027,7 @@ 出血は穏やか Медленное кровотечение Sangrado lento + Sangramento lento Moderate bleeding @@ -1030,6 +1039,7 @@ 出血はそこそこ速い Умеренное кровотечение Sangrado moderado + Sangramento moderado Severe bleeding @@ -1041,6 +1051,7 @@ 出血は激しい Сильное кровотечение Sangrado severo + Sangramento grave Massive bleeding @@ -1052,6 +1063,7 @@ 出血は酷く多い Огромное кровотечение Sangrado masivo + Sangramento massivo in Pain @@ -1127,6 +1139,7 @@ 失血なし Потери крови нет Sin pérdida de sangre + Sem perda de sangue @@ -1271,6 +1284,7 @@ Información de paciente Patienteninformation 환자 정보 + Informações do paciente Blood Loss Colors @@ -1283,6 +1297,7 @@ 失血颜色 출혈 색상 Colores de pérdida de sangre + Cores de perda de sangue Defines the 10 color gradient used to indicate blood loss in Medical GUIs. @@ -1295,6 +1310,7 @@ 失血颜色,用于医学图形用户界面。10种渐变颜色。 출혈로 인한 의료 GUI의 색상을 변경합니다. 총 10가지 색상이 있습니다. Define los 10 gradientes de color utilizados para indicar la pérdida de sangre en la interfaz gráfica del sistema Médico. + Define os 10 gradientes de cores utilizados para indicar perda de sangue nas interfaces médicas. Blood Loss Color %1 @@ -1307,6 +1323,7 @@ 失血颜色 %1 출혈 색상 %1 Color de pérdida de sangre %1 + Cor de perda de sangue %1 Damage Colors @@ -1319,6 +1336,7 @@ 负伤颜色 피해 색상 Colores de daño + Cores de dano Defines the 10 color gradient used to indicate damage in Medical GUIs. @@ -1331,6 +1349,7 @@ 负伤颜色,用于医学图形用户界面。10种渐变颜色。 의료 GUI에 쓰이는 피해 색상입니다. 총 10가지 색상이 있습니다. Define los 10 gradientes de color utilizados para indicar el daño en la interfaz gráfiica del sistema Médico. + Define os 10 gradientes de cor utilizados para indicar dano nas interfaces médicas. Damage Color %1 @@ -1343,6 +1362,7 @@ 负伤颜色 %1 피해 색상 %1 Color de daño %1 + Cor de dano %1 Show Blood Loss @@ -1355,6 +1375,7 @@ Показывать кровопотерю Mostrar pérdida de sangre Afficher les pertes de sang + Mostrar perda de sangue Show qualitative blood loss in the injury list. @@ -1367,6 +1388,7 @@ Показывать тяжесть кровопотери в списке ранений. Mostrar la pérdida de sangre cualitativa en la lista de heridas. Afficher la quantité de sang perdue + Mostrar perda de sangue qualitativa na lista de feridas. Show Bleeding State @@ -1412,6 +1434,7 @@ 被弾時の医療情報一時表示 Показать медицинскую информацию о попадании Ojear Información Médica en Impacto + Visualização rápida das informações médicas durante uma lesão Temporarily show medical info when injured. @@ -1424,6 +1447,7 @@ 被弾時に医療情報を一時的に表示します。 Временно показывать медицинскую информацию при травме. Temporalmente muestra la información médica cuando es herido. + Mostrar informações médicas temporariamente durante uma lesão. Medical Peek Duration on Hit @@ -1436,6 +1460,7 @@ 被弾時の医療情報一時表示の表示時間 Продолжительность медицинского осмотра при попадании Duración de Ojear la Información Médica cuando hay Impacto + Duração da visualização rápida de informações médicas durante uma lesão How long the medical info peek remains open after being injured. @@ -1448,6 +1473,7 @@ 被弾時の医療情報の一時表示をどれだけ長く表示するか。 Как долго окно просмотра медицинской информации остается открытым после получения травмы. Durante cuánto tiempo la información médica ojeada permanece abierta una tras haber sido herido. + Quanto tempo a visualização rápida de informações médicas permanece aberta após ser ferido. Show Trauma Sustained @@ -1486,6 +1512,7 @@ 身体部位の輪郭表示の色 Цвет контура части тела Color de Contorno de las Partes del Cuerpo + Cor do contorno da parte do corpo Color of outline around selected body part. @@ -1498,6 +1525,7 @@ 選択した身体部位の輪郭表示の色。 Цвет контура вокруг выбранной части тела. Color del contorno alrededor de la parte del cuerpo seleccionada. + Cor do contorno em volta da parte do corpo selecionada. Minor Trauma @@ -1562,6 +1590,7 @@ Лево I + E R @@ -1574,6 +1603,7 @@ Право D + D in your inventory @@ -1586,6 +1616,7 @@ 個あなたが保有 в вашем инвентаре en tu inventario + em seu inventário in patient's inventory @@ -1598,6 +1629,7 @@ 個患者が保有 в инвентаре пациента en el inventario del paciente + no inventário do paciente in vehicle's inventory @@ -1610,6 +1642,7 @@ 個車両内に保有 в инвентаре транспорта en el inventario del vehículo + no inventário do veículo No effect until tourniquet removed @@ -1621,6 +1654,7 @@ 止血帯を外すまで効果を発揮しません Никакого эффекта до тех пор, пока жгут не будет снят Sin efecto hasta que se quita el torniquete + Sem efeito até o torniquete ser removido Show Tourniquet Warning @@ -1632,6 +1666,7 @@ 止血帯の警告を表示 Показать предупреждение о наложении жгута Mostrar Advertencia de Torniquete + Mostrar aviso de torniquete Show a warning tooltip when a tourniquet will interfere with a medical action. @@ -1643,6 +1678,7 @@ 止血帯が医療行為を妨げる場合には、警告ツールチップを表示します。 Показать всплывающую подсказку с предупреждением, когда жгут помешает медицинскому вмешательству. Muestra un mensaje de advertencia cuando un torniquete interfiera con una acción médica. + Mostra uma dica de aviso quando um torniquete interfere com uma ação médica. diff --git a/addons/medical_statemachine/stringtable.xml b/addons/medical_statemachine/stringtable.xml index 2b828d506e..9c1d807bd0 100644 --- a/addons/medical_statemachine/stringtable.xml +++ b/addons/medical_statemachine/stringtable.xml @@ -173,6 +173,7 @@ Wykrwawienie podczas zatrzymanej akcji serca 心脏骤停期间失血情况 심정지 중 출혈 + Sangramento durante parada cardíaca Controls whether a person can die in cardiac arrest by blood loss before the cardiac arrest time runs out. @@ -185,6 +186,7 @@ Kontroluje czy śmierć osoby może nastąpić poprzez wykrwawienie zanim wyczerpię się Czas Zatrzymania Akcji Serca. 控制单位是否会在心脏骤停时间耗完之前因失血过多而死亡。 지정한 심정지 시간이 다 되기 전에 출혈로 인해 사망할 수 있는 지를 결정합니다. + Controla se uma pessoa pode morrer em parada cardíaca por perda de sangue antes que o tempo de parada cardíaca acabe. diff --git a/addons/medical_status/stringtable.xml b/addons/medical_status/stringtable.xml index ea3f77429b..cefc85ff42 100644 --- a/addons/medical_status/stringtable.xml +++ b/addons/medical_status/stringtable.xml @@ -127,6 +127,7 @@ 武器を落とす確率 Шанс выпадения оружия Probabilidad de Soltar Arma + Probabilidade de largar a arma Chance for a player to drop their weapon when going unconscious.\nHas no effect on AI. @@ -138,6 +139,7 @@ プレーヤーが意識を失ったときに武器を落とす可能性。\nAI には影響しません。 Шанс для игрока выронить свое оружие, когда он теряет сознание.\nНе влияет на ИИ Probabilidad del jugador de soltar su arma cuando quedan inconscientes.\nNo tiene efecto sobre la IA. + Chance de um jogador largar sua arma quando ficar inconsciente.\nNão tem efeito sobre a IA. diff --git a/addons/medical_treatment/stringtable.xml b/addons/medical_treatment/stringtable.xml index 383048626a..2be4541677 100644 --- a/addons/medical_treatment/stringtable.xml +++ b/addons/medical_treatment/stringtable.xml @@ -75,6 +75,7 @@ 已启用 & 可以诊断死亡/心搏骤停 활성화 및 사망/심정지 진찰 가능 Habilitado y poder diagnosticar Muerte/Parada cardíaca + Habilitado e permite diagnosticar morte/parada cardíaca Abilitato e può diagnosticare Morte/Arresto Cardiaco @@ -161,6 +162,7 @@ Attivi e possono riaprirsi 已启用 & 可以伤口开裂 활성화 및 붕대 풀림 구현 + Habilitado e pode reabrir Wound Reopening Coefficient @@ -175,6 +177,7 @@ Coeficiente de reapertura de heridas 伤口开裂系数 붕대 풀림 계수 + Coeficiente de reabertura de feridas Coefficient for controlling the wound reopening chance. The final reopening chance is determined by multiplying this value with the specific reopening chance for the wound type and bandage used. @@ -189,6 +192,7 @@ Coeficiente que controla la probabilidad de reapertura de heridas. La probabilidad final de reapertura de heridas queda determinada multiplicando este valor por la probabilidad específica del tipo de herida y venda usada. 用于控制伤口开裂概率的系数。最终的重开放概率=该值x伤口类型x所使用的绷带的具体开裂概率。 붕대가 풀리는 확률 계수를 정합니다. 최종 붕대 풀림 계수는 상처의 종류와 쓰인 붕대의 합의 결과에 계수를 곱한 결과입니다. + Coeficiente para controlar a chance de reabertura da ferida. A chance final de reabertura é determinada multiplicando este valor com a chance específica de reabertura para o tipo de ferida e bandagem usada. Clear Trauma @@ -201,6 +205,7 @@ 清理创伤 상처 제거 Despejar trauma + Remover trauma Controls when hitpoint damage from wounds is healed. @@ -213,6 +218,7 @@ 控制伤口治疗后确定受伤部位的受伤情况。 상처가 언제 제거되는 지를 결정합니다. Controla cuando los puntos de daño de las heridas son curados. + Controla quando o dano de pontos de vida de feridas é curado. After Bandage @@ -225,6 +231,7 @@ 包扎后 붕대 묶은 후 Después de vendado + Após fechamento com bandagens After Stitch @@ -237,6 +244,7 @@ 缝合后 상처 봉합 후 Después de sutura + Após sutura Boost medical training when in medical vehicles or facilities. Untrained becomes medic, medic becomes doctor. @@ -329,6 +337,7 @@ Tempo di utilizzo dell'autoiniettore 自动注射器治疗时间 주사기 사용 시간 + Tempo de tratamento de auto-injetores Time, in seconds, required to administer medication using an autoinjector. @@ -341,6 +350,7 @@ Tempo in secondi richiesto per ricevere medicina da un autoiniettore. 使用自动注射器给药所需的时间(秒) 초 단위로 주사기를 사용하는데 걸리는 시간을 정합니다. + Tempo, em segundos, necessário para administrar medicações usando o auto-injetor. Tourniquet Treatment Time @@ -353,6 +363,7 @@ Czas aplikacji stazy 止血带治疗时间 지혈대 사용 시간 + Tempo de tratamento de torniquetes Time, in seconds, required to apply/remove a tourniquet. @@ -365,6 +376,7 @@ Czas w sekundach potrzebny do założenia/zdjęcia stazy. 使用/移除止血带所需的时间(秒) 초 단위로 지혈대를 사용/제거하는 데 걸리는 시간을 정합니다. + Tempo, em segundos, necessário para aplicar/remover um torniquete. IV Bag Treatment Time @@ -377,6 +389,7 @@ Czas aplikacji IV 静脉输液袋治疗时间 수액용기 사용 시간 + Tempo de tratamento de bolsas de IV Time, in seconds, required to administer an IV bag. @@ -389,6 +402,7 @@ Czas w sekundach potrzebny na aplikację transfuzji IV. 使用静脉输液所需的时间(秒) 초 단위로 수액용기를 사용하는 데 걸리는 시간을 정합니다. + Tempo, em segundos, necessário para administrar uma bolsa de IV. Splint Treatment Time @@ -401,6 +415,7 @@ Czas aplikacji szyny 夹板治疗时间 부목 사용 시간 + Tempo de tratamento de talas Time, in seconds, required to apply a splint. @@ -413,6 +428,7 @@ Czas w sekundach potrzebny na aplikację szyny. 使用夹板所需的时间(秒) 초 단위로 부목을 사용하는데 걸리는 시간을 정합니다. + Tempo, em segundos, necessário para aplicar uma talas. Body Bag Use Time @@ -425,6 +441,7 @@ Czas użycia worka na ciało 尸袋使用时间 시체 운반용 부대 사용 시간 + Tempo de uso de sacos de cadáver Time, in seconds, required to put a patient in a body bag. @@ -437,6 +454,7 @@ Czas w sekundach potrzebny na spakowanie ciała do worka na ciało. 装入裹尸袋时间 초 단위로 시체 운반용 부대를 사용하는데 걸리는 시간을 정합니다. + Tempo, em segundos, necessário para colocar um paciente em um saco de cadáver. Grave Digging Time @@ -448,6 +466,7 @@ 墓掘りの所要時間 Время рытья могилы Tiempo de Cavado de Tumba + Tempo de escavação de cova Time, in seconds, required to dig a grave for a body. @@ -459,6 +478,7 @@ 遺体の墓を掘るのに掛かる時間。 (秒単位) Время в секундах, необходимое для того, чтобы выкопать могилу для тела. Tiempo, en segundos, requerido para cavar una tumba para un cuerpo. + Tempo, em segundos, necessário para cavar uma cova para um corpo. Allow Epinephrine @@ -636,6 +656,7 @@ Kendi PAK Kullanımı Usar EPA sobre uno mismo 개인응급키트 자가 사용 + Auto-tratamento com KPS Enables the use of PAKs to heal oneself. @@ -651,6 +672,7 @@ Kendini iyileştirmek için PAK'ların kullanılmasını sağlar. Habilita el uso de EPA para curarse a uno mismo. 개인응급키트를 사용자 본인에게 쓸 수 있는 지를 정합니다. + Permite o uso de KPS para se tratar. Time Coefficient PAK @@ -815,6 +837,7 @@ Tempo di suturazione ferita. 伤口缝合时间 상처 봉합 시간 + Tempo de sutura de feridas Time, in seconds, required to stitch a single wound. @@ -827,6 +850,7 @@ Tempo in secondi richiesto per suturare una singola ferita. 缝合一个伤口所需的时间(秒) 초 단위로, 한 상처를 봉합하는데 걸리는 시간을 설정합니다. + Tempo, em segundos, necessário para suturar uma única ferida. Self IV Transfusion @@ -869,6 +893,7 @@ Permetti di insaccare un paziente svenuto 允许昏迷者装入尸袋 기절 인원 시체 운반용 부대에 옮기기 + Permitir inconscientes em sacos de cadáver Enables placing an unconscious patient in a body bag. @@ -881,6 +906,7 @@ Permette l'uso della sacca per morti anche su pazienti che sono solo svenuti (causa la morte del paziente) 能够将昏迷的伤员装入尸袋中。 기절 상태의 인원을 시체 운반용 부대에 옮겨 담을 수 있는 지를 정합니다. + Permite colocar um paciente inconsciente em um saco de cadáver. Allow Grave Digging @@ -892,6 +918,7 @@ Autoriser le creusement de tombes 墓掘りを許可 Рытье могил + Permitir escavamento de cova Enables digging graves to dispose of corpses. @@ -903,6 +930,7 @@ Active la possibilité de creuser des tombes pour enterrer les cadavres. 墓を掘って死体を処理できるようになります。 Позволяет рыть могилы для захоронения трупов. + Permite escavar covas para se livrar de cadáveres. Only if dead @@ -914,6 +942,7 @@ Uniquement s'il est mort 死体のみ Только если мертв + Apenas se estiver morto Create Grave Markers @@ -925,6 +954,7 @@ Créer des pierres tombales 墓標を作成 Надгробные знаки + Criar marcadores de covas Enables the creation of grave markers when digging graves. @@ -936,6 +966,7 @@ Active la création de pierres tombales lors de l'enterrement de cadavres. 墓を掘った際、墓標を作成できるようにします。 Позволяет создавать надгробные знаки при рытье могил. + Permite a criação de marcadores de covas ao escavá-las. Allow IV Transfusion @@ -950,6 +981,7 @@ Доступ к внутривенному переливанию Permitir transfusión de IV 수액용기 사용 허가 + Permitir transfusão IV Training level required to transfuse IVs. @@ -964,6 +996,7 @@ Уровень навыка, требуемый для осуществления внутривенного переливания. Nivel de capacitación requerido para transfusiones de IV. 수액용기를 사용하는데 필요한 등급을 정합니다. + Nível de treinamento necessário para transfusões IV. Locations IV Transfusion @@ -976,6 +1009,7 @@ Luoghi Fleboclisi EV 静脉输液地点 수액용기 사용 장소 + Locais para transfusão IV Controls where IV transfusions can be performed. @@ -988,6 +1022,7 @@ Luoghi in cui è possibile applicare Fleboclisi Endovenose. 控制何地可以静脉输液 수액용기를 사용할 수 있는 장소를 정합니다. + Controla onde as transfusões IV podem ser realizadas. Convert Vanilla Items @@ -1220,6 +1255,7 @@ 心肺复苏的最低成功率 최소 심폐소생술 성공 가능성 RCP posibilidad mínima de resultado satisfactorio + Probabilidade mínima de sucesso de RCP CPR Success Chance Maximum @@ -1232,6 +1268,7 @@ 心肺复苏的最高成功率 최대 심폐소생술 성공 가능성 RCP posibilidad máxima de resultado satisfactorio + Probabilidade máxima de sucesso de RCP Minimum probability that performing CPR will restore heart rhythm.\nThis minimum value is used when the patient has at least "Lost a fatal amount of blood".\nAn interpolated probability is used when the patient's blood volume is between the minimum and maximum thresholds. @@ -1244,6 +1281,7 @@ 实施心肺复苏恢复心律的最小可能性。\n当伤员至少有"致命失血量"时,就取该最小值。\n当伤员的血量介于最小和最大阈值之间时,将使用插值概率。 심폐소생술 시 제일 낮은 성공 가능성을 결정합니다.\n이 가능성은 환자가 최소 "심각한 양의 혈액을 잃음"일 때 사용됩니다. Probabilidad mínima de que realizar RCP restaure el ritmo cardíaco.\n Este valor mínimo es utilizado cuando el paciente tiene al menos "Pérdida fatal de sangre".\n Una probabilidad interpolada es usada cuando el volumen de sangre del paciente está entre el umbral mínimo y máximo. + Probabilidade mínima do RCP restaurar a frequência cardíaca.\nEste valor é usado em pacientes que "perderam uma quantidade fatal de sangue".\nValores entre quantidades extremas de sangue resultam em uma probabilidade interpolada entre a mínima e a máxima. Maximum probability that performing CPR will restore heart rhythm.\nThis maximum value is used when the patient has at most "Lost some blood".\nAn interpolated probability is used when the patient's blood volume is between the minimum and maximum thresholds. @@ -1256,6 +1294,7 @@ 实施心肺复苏恢复心律的最大可能性。\n当伤员最多“失血一些”时,就取该最大值。\n当伤员的血量介于最小和最大阈值之间时,将使用插值概率。 심폐소생술 시 제일 높은 성공 가능성을 결정합니다.\n이 가능성은 환자가 최소 "혈액을 조금 잃음"일 때 사용됩니다. Probabilidad máxima de que realizar RCP restaure el ritmo cardíaco.\n Este valor máximo es utilizado cuando el paciente tiene como mucho "Pérdida de un poco de sangre".\n Una probabilidad interpolada es usada cuando el volumen de sangre del paciente está entre el umbral mínimo y máximo. + Probabilidade máxima do RCP restaurar a frequência cardíaca.\nEste valor é usado em pacientes que "perderam pouco sangue".\nValores entre quantidades extremas de sangue resultam em uma probabilidade interpolada entre a mínima e a máxima. CPR Treatment Time @@ -1268,6 +1307,7 @@ HLW Behandlungsdauer 心肺复苏时间 심폐소생술 시행 시간 + Duração do RCP Time, in seconds, required to perform CPR on a patient. @@ -1280,6 +1320,7 @@ Zeit in Sekunden, die benötigt wird, um eine HLW durzuführen. 对伤员实施心肺复苏所需的时间(秒) 초 단위로, 심폐소생술을 진행하는 시간을 결정합니다. + Tempo, em segundos, necessário para realizar RCP em um paciente. Holster Required @@ -1294,6 +1335,7 @@ Необходимость убирать оружие Requiere enfundar 무장여부 + Necessário guardar armas Controls whether weapons must be holstered / lowered in order to perform medical actions.\nExcept Exam options allow examination actions (checking pulse, blood pressure, response) at all times regardless of this setting. @@ -1308,6 +1350,7 @@ Нужно ли убирать оружие для проведения медицинских действий.\nОпция «Проверка разрешена» разрешает проверять пульс, кровяное давление или реакцию независимо от этого параметра. Controla si las armas deben estar enfundadas / bajadas para realizar acciones médicas. \n Excepto Las opciones de examen permiten acciones de examen (control del pulso, presión arterial, respuesta) en todo momento, independientemente de esta configuración. 치료하기에 앞서 손에서 무기를 집어넣을 지/내릴지를 결정합니다.\n검사제외 옵션의 경우 맥박 확인, 혈압 확인, 반응 확인은 앞선 옵션에 구애받지 않고 사용할 수 있습니다. + Controla se as armas devem ser guardadas/abaixadas para realizar ações médicas.\n"Exceto exame" faz com que ações de verificação de pulso, pressão arterial e resposta sejam permitidas a qualquer momento. Lowered or Holstered @@ -1322,6 +1365,7 @@ Опущено или убрано Bajada o enfundada 내리거나 집어넣기 + Abaixada ou guardada Lowered or Holstered (Except Exam) @@ -1336,6 +1380,7 @@ Опущено или убрано (Проверка разрешена) Bajada o enfundada (excepto examen) 내리거나 집어넣기(검사 제외) + Abaixada ou guardada (exceto exame) Holstered Only @@ -1350,6 +1395,7 @@ Только убрано Solo enfundada 집어넣기 + Guardada apenas Holstered Only (Except Exam) @@ -1364,6 +1410,7 @@ Только убрано (Проверка разрешена) Solo enfundada (excepto examen) 집어넣기(검사 제외) + Guardada apenas (exceto exame) [ACE] Medical Supply Crate (Basic) @@ -2454,6 +2501,7 @@ 봉합술 Suture Нить + Sutura Surgical Suture for stitching injuries. @@ -2465,6 +2513,7 @@ 상처를 꿰메는 수술용 봉합술. Suture chirurgicale pour suturer les blessures. Хирургическая нить для зашивания травм. + Sutura cirúrgica para fechar feridas. Surgical Suture for stitching injuries. @@ -2476,6 +2525,7 @@ 상처를 꿰메는 수술용 봉합술. Suture chirurgicale pour suturer les blessures. Хирургическая нить для зашивания травм. + Sutura cirúrgica para fechar feridas. Bodybag @@ -4180,6 +4230,7 @@ %1 은 반응이 없고, 얕은 헐떡임과 경련증세를 보입니다 %1 не реагирует на раздражители, поверхностно дышит, в конвульсиях %1 no responde, dando pequeñas bocanadas y convulsionando + %1 está inconsciente, com respiração curta e convulsionando %1 is in cardiac arrest @@ -4200,6 +4251,7 @@ %1 은 반응이 없고, 움직임이 없으며 차갑습니다 %1 не реагирует на раздражители, не шевелится и холодный %1 no responde, sin movimiento y frío + %1 está inconsciente, sem movimento e frio %1 is dead @@ -4694,6 +4746,7 @@ 墓を掘る Выкопать могилу для тела Cavar tumba para cuerpo + Escavar cova para cadáver Digging grave for body... @@ -4705,6 +4758,7 @@ 墓を掘っています Рытьё могилы для тела... Cavando tumba para cuerpo... + Escavando cova para cadáver... %1 has bandaged patient @@ -4947,6 +5001,7 @@ Der Körper zuckte und kann nicht tot sein! 身体抽搐了一下,可能还没死! 꿈틀대는걸 보니 죽은 것 같지는 않습니다! + O corpo se retorceu e pode não estar morto! Check name on headstone @@ -4958,6 +5013,7 @@ 墓石の名前を確認 Проверьте имя на надгробии Comprobar nombre en la lápida + Checar nome na lápide Bandage Rollover @@ -4969,6 +5025,7 @@ 包帯の繰り越し Перевязка множественных ран Vendaje múltiple + Bandagem de Múltiplas Feridas If enabled, bandages can close different types of wounds on the same body part.\nBandaging multiple injuries will scale bandaging time accordingly. @@ -4980,6 +5037,7 @@ 有効にすると、体の同じ部分にある別の種類の傷を一つの包帯で閉じることができます。\n複数の傷に包帯を巻くと、それに応じて包帯時間が変動します。 Если эта функция включена, бинты могут закрывать различные типы ран на одной и той же части тела.\nПри перевязке нескольких повреждений время перевязки будет увеличено соответствующим образом. Si se habilita, las vendas pueden cerrar diferentes tipos de heridas en la misma parte del cuerpo.n\Vendar múltiples heridas escala el tiempo de vendado acorde. + Se habilitado, bandagens podem fechar diferentes tipos de ferimento na mesma parte do corpo.\nO fechamento de múltiplas feridas modificará o tempo de aplicação proporcionalmente. Bandage Effectiveness Coefficient @@ -4991,6 +5049,7 @@ 包帯有効性係数 Коэф. эффективности повязки Coeficiente de Efectividad de Vendado + Coeficiente de Eficácia da Bandagem Determines how effective bandages are at closing wounds. @@ -5002,6 +5061,7 @@ 包帯が傷をふさぐのにどれだけ効果的かを定義します。 Определяет, насколько эффективны бинты при закрытии ран. Determina como de efectivos son los vendajes cerrando heridas. + Determina o quão efetivas as bandagens são em fechar ferimentos. Medical Items @@ -5016,6 +5076,7 @@ Medizinisches Material 医療品 Objetos médicos + Objetos médicos Zeus Treatment Time Coefficient diff --git a/addons/medical_vitals/stringtable.xml b/addons/medical_vitals/stringtable.xml index 2fe7336dc0..25b278732e 100644 --- a/addons/medical_vitals/stringtable.xml +++ b/addons/medical_vitals/stringtable.xml @@ -21,6 +21,7 @@ Activer la simulation de la SpO2 SpO2-Simulation aktivieren Habilitar Simulación SpO2 + Habilitar simulação de SpO2 Enables oxygen saturation simulation, providing variable heart rate and oxygen demand based on physical activity and altitude. Required for Airway Management. @@ -31,6 +32,7 @@ Permet de simuler la saturation en oxygène, de modifier la fréquence cardiaque et la consommation d'oxygène en fonction de l'activité physique et de l'altitude. Nécessaire pour la gestion des voies respiratoires. Aktiviert die Simulation der Sauerstoffsättigung und bietet variable Herzfrequenz und Sauerstoffbedarf basierend auf körperlicher Aktivität und Geländehöhe. Erforderlich für das Atemwegsmanagement. Habilita la saturación de oxígeno, utilizando la demanda de oxígeno y ritmo cardíaco basado en la actividad física y la altitud. Requerido para el Manejo de las Vías Aéreas. + Habilita a saturação de oxigênio, tornando variáveis o batimento cardíaco e demanda de oxigênio baseados em atividade física e altitude. Necessário para o gerenciamento de vias aéreas. diff --git a/addons/microdagr/stringtable.xml b/addons/microdagr/stringtable.xml index c9bd546afc..0aa0dafacf 100644 --- a/addons/microdagr/stringtable.xml +++ b/addons/microdagr/stringtable.xml @@ -605,6 +605,7 @@ MicroDAGR - Poprzedni Tryb 微型 GPS 接收器—上一个模式 마이크로DAGR - 이전 모드 + MicroDAGR - Modo Anterior MicroDAGR - Next Mode @@ -617,6 +618,7 @@ MicroDAGR - Kolejny Tryb 微型 GPS 接收器—下一个模式 마이크로DAGR - 다음 모드 + MicroDAGR - Modo Seguinte diff --git a/addons/nightvision/stringtable.xml b/addons/nightvision/stringtable.xml index 1c1cd61ba7..1911681dd6 100644 --- a/addons/nightvision/stringtable.xml +++ b/addons/nightvision/stringtable.xml @@ -28,6 +28,7 @@ 夜视仪(一代,棕色) 아투경 (1세대, 갈색) Gafas de visión nocturna (Gen1, Marrón) + Óculos de Visão Noturna (Gen1, Marrom) NV Goggles (Gen1, Black) @@ -40,6 +41,7 @@ 夜视仪(一代,黑色) 아투경 (1세대, 검정) Gafas de visión nocturna (Gen1, Negro) + Óculos de Visão Noturna (Gen1, Preto) NV Goggles (Gen1, Green) @@ -52,6 +54,7 @@ 夜视仪(一代,绿色) 아투경 (1세대, 녹색) Gafas de visión nocturna (Gen1, Verde) + Óculos de Visão Noturna (Gen1, Verde) NV Goggles (Gen2, Brown) @@ -64,6 +67,7 @@ 夜视仪(二代,棕色) 아투경 (2세대, 갈색) Gafas de visión nocturna (Gen2, Marrón) + Óculos de Visão Noturna (Gen2, Marrom) NV Goggles (Gen2, Black) @@ -76,6 +80,7 @@ 夜视仪(二代,黑色) 아투경 (2세대, 검정) Gafas de visión nocturna (Gen2, Negro) + Óculos de Visão Noturna (Gen2, Preto) NV Goggles (Gen2, Green) @@ -88,6 +93,7 @@ 夜视仪(二代,绿色) 아투경 (2세대, 녹색) Gafas de visión nocturna (Gen2, Verde) + Óculos de Visão Noturna (Gen2, Verde) NV Goggles (Gen3) @@ -96,7 +102,7 @@ NS-Brille (3. Gen.) Visore Notturno (Gen3) Gogle noktowizyjne (Gen3) - Óculos de visão noturna (Gen3) + Óculos de Visão Noturna (Gen3) ПНВ (Gen3) Gafas de visión nocturna (Gen3) Éjjellátó szemüveg (3. Gen.) @@ -113,7 +119,7 @@ NS-Brille (3. Gen., braun) Visore Notturno (Gen3, Marrone) Gogle noktowizyjne (Gen3, Brązowe) - Óculos de visão noturna (Gen3, marrons) + Óculos de Visão Noturna (Gen3, Marrom) ПНВ (Gen3, Коричневый) Gafas de visión nocturna (Gen3, Marrón) Éjjellátó szemüveg (3. Gen., barna) @@ -133,6 +139,7 @@ JVN (Gen3, marron, WP) ПНВ (Gen3, Коричневый, БФ) Gafas de visión nocturna (Gen3, Marrón, FB) + Óculos de Visão Noturna (Gen3, Marrom, FB) Night Vision Goggles, White Phosphor @@ -144,6 +151,7 @@ Jumelles Vision Nocturne, Phosphore blanc Очки ночного видения, белый фосфор Gafas de Visión Nocturna, Fósforo Blanco + Óculos de Visão Nortuna, Fósforo Branco NV Goggles (Gen3, Green) @@ -152,7 +160,7 @@ NS-Brille (3. Gen., grün) Visore Notturno (Gen3, Verde) Gogle noktowizyjne (Gen3, Zielone) - Óculos de visão noturna (Gen3, verdes) + Óculos de Visão Noturna (Gen3, verdes) ПНВ (Gen3, Зелёный) Gafas de visión nocturna (Gen3, Verde) Éjjellátó szemüveg (3. Gen., zöld) @@ -172,6 +180,7 @@ JVN (Gen3, vertes, WP) ПНВ (Gen3, Зелёный, БФ) Gafas de visión nocturna (Gen3, Verde, FB) + Óculos de Visão Noturna (Gen3, Verde, FB) NV Goggles (Gen3, Black) @@ -180,7 +189,7 @@ NS-Brille (3. Gen., schwarz) Visore Notturno (Gen3, Nero) Gogle noktowizyjne (Gen3, Czarne) - Óculos de visão noturna (Gen3, pretos) + Óculos de Visão Noturna (Gen3, Preto) ПНВ (Gen3, Чёрный) Gafas de visión nocturna (Gen3, Negro) Éjjellátó szemüveg (3. Gen., fekete) @@ -200,6 +209,7 @@ JVN (Gen3, noires, WP) ПНВ (Gen3, Чёрный, БФ) Gafas de visión nocturna (Gen3, Negro, FB) + Óculos de Visão Noturna (Gen3, Preto, FB) NV Goggles (Gen4, Brown) @@ -212,6 +222,7 @@ 夜视仪(四代,棕色) 야투경 (4세대, 갈색) Gafas de visión nocturna (Gen4, Marrón) + Óculos de Visão Noturna (Gen4, Marrom) NV Goggles (Gen4, Brown, WP) @@ -223,6 +234,7 @@ JVN (Gen4, marron, WP) ПНВ (Gen4, Коричневый, БФ) Gafas de visión nocturna (Gen4, Marrón, FB) + Óculos de Visão Noturna (Gen4, Marrom, FB) NV Goggles (Gen4, Black) @@ -235,6 +247,7 @@ 夜视仪(四代,黑色) 야투경 (4세대, 검정) Gafas de visión nocturna (Gen4, Negro) + Óculos de Visão Noturna (Gen4, Preto) NV Goggles (Gen4, Black, WP) @@ -246,6 +259,7 @@ JVN (Gen4, noires, WP) ПНВ (Gen4, Чёрный, БФ) Gafas de visión nocturna (Gen4, Negro, FB) + Óculos de Visão Noturna (Gen4, Preto, FB) NV Goggles (Gen4, Green) @@ -258,6 +272,7 @@ 夜视仪(四代,绿色) 야투경 (4세대, 녹색) Gafas de visión nocturna (Gen4, Verde) + Óculos de Visão Noturna (Gen4, Verde) NV Goggles (Gen4, Green, WP) @@ -269,6 +284,7 @@ JVN (Gen4, vertes, WP) ПНВ (Gen4, Зелёный, БФ) Gafas de visión nocturna (Gen4, Verde, FB) + Óculos de Visão Noturna (Gen4, Verde, FB) NV Goggles (Wide, Brown) @@ -281,6 +297,7 @@ 夜视仪(宽,棕色) 야투경 (넓음, 갈색) Gafas de visión nocturna (Panorámicas, Marrón) + Óculos de Visão Noturna (Panorâmico, Marrom) NV Goggles (Wide, Brown, WP) @@ -292,6 +309,7 @@ JVN (Large, marron, WP) ПНВ (Широкий, Коричневый, БФ) Gafas de visión nocturna (Panorámicas, Marrón, FB) + Óculos de Visão Noturna (Panorâmico, Marrom, FB) NV Goggles (Wide, Black) @@ -304,6 +322,7 @@ 夜视仪(宽,黑色) 야투경 (넓음, 검정) Gafas de visión nocturna (Panorámicas, Negro) + Óculos de Visão Noturna (Panorâmico, Preto) NV Goggles (Wide, Black, WP) @@ -315,6 +334,7 @@ JVN (Large, noires, WP) ПНВ (Широкий, Чёрный, БФ) Gafas de visión nocturna (Panorámicas, Negro, FB) + Óculos de Visão Noturna (Panorâmico, Preto, FB) NV Goggles (Wide, Green) @@ -327,6 +347,7 @@ 夜视仪(宽,绿色) 야투경 (넓음, 녹색) Gafas de visión nocturna (Panorámicas, Verde) + Óculos de Visão Noturna (Panorâmico, Verde) NV Goggles (Wide, Green, WP) @@ -338,6 +359,7 @@ JVN (Large, vertes, WP) ПНВ (Широкий, Зелёный, БФ) Gafas de visión nocturna (Panorámicas, Verde, FB) + Óculos de Visão Noturna (Panorâmico, Verde, FB) Brightness: %1 @@ -365,7 +387,7 @@ Augmenter la luminosité des JVN Увеличить яркость ПНВ Éjjellátó fényerejének növelése - Aumentar Luminosidade do EVN + Aumentar Luminosidade do OVN Aumenta la luminosità dell'NVG 暗視装置の明度を上げる 야투경 밝기 높이기 @@ -382,7 +404,7 @@ Abaisser la luminosité des JVN Уменьшить яркость ПНВ Éjjellátó fényerejének csökkentése - Diminuir Luminosidade do EVN + Diminuir Luminosidade do OVN Riduci la luminosità dell'NVG 暗視装置の明度を下げる 야투경 밝기 줄이기 @@ -598,6 +620,7 @@ Génération de jumelles de vision nocturne Генерация ночного видения Generación de Visión Nocturna + Geração de Visão Noturna Gen %1 @@ -609,6 +632,7 @@ Gen %1 Генерация %1 Gen %1 + Gen %1 diff --git a/addons/noradio/stringtable.xml b/addons/noradio/stringtable.xml index d1cf51f0e6..d41827ebfa 100644 --- a/addons/noradio/stringtable.xml +++ b/addons/noradio/stringtable.xml @@ -12,6 +12,7 @@ Нет рации No Radio Pas de radio + Sem Rádio Mute Player diff --git a/addons/novehicleclanlogo/stringtable.xml b/addons/novehicleclanlogo/stringtable.xml index 96d463f582..1e07c85ce8 100644 --- a/addons/novehicleclanlogo/stringtable.xml +++ b/addons/novehicleclanlogo/stringtable.xml @@ -11,6 +11,7 @@ Clan-Logo von Fahrzeugen entfernen Rimuovi Icone Clan dai veicoli Retirer les logos de clan des véhicules + Remover logo do clã de veículos Prevents clan logo from being displayed on vehicles controlled by players. @@ -22,6 +23,7 @@ Verhindert, dass das Clan-Logo auf von Spielern kontrollierten Fahrzeugen angezeigt wird. Impedisce la visualizzazione di icone clan sui veicoli controllati da giocatori. Empêche les logos de clan d'être affichés sur les véhicules contrôlés par des joueurs. + Previne o logo do clã de ser mostrado em veículos controlados por jogadores. diff --git a/addons/overheating/stringtable.xml b/addons/overheating/stringtable.xml index d5e8ad7ca8..0d3f0dd96e 100644 --- a/addons/overheating/stringtable.xml +++ b/addons/overheating/stringtable.xml @@ -58,6 +58,7 @@ 过热系数 과열 계수 Coeficiente de calentamiento + Coeficiente de aquecimento Coefficient for the amount of heat a weapon generates per shot.\nHigher value increases heat. @@ -70,6 +71,7 @@ 武器每次射击产生的热量系数。\n数值越高,热量越高。 매 발사마다 만들어지는 열에 계수를 적용합니다.\n높은 계수는 더 많은 열을 발생시킵니다. Coeficiente para la cantidad de calor que genera un arma por disparo.\nValores más altos incrementan el calor + Coeficiente da quantidade de calor que um armamento gera por disparo.\nValores mais altos potencializam o aquecimento. Cooling Coefficient @@ -82,6 +84,7 @@ Коэф. остывания Coeficiente de enfriado Coefficient de refroidissement + Coeficiente de resfriamento Coefficient for how quickly a weapon cools down.\nHigher value increases cooling speed. @@ -94,6 +97,7 @@ Коэффициент скорости остывания орудия.\nЧем больше значение, тем быстрее остывает. Coeficiente para cómo de rápido se enfría un arma.\nValores más altos incrementan la velocidad de enfriamiento. Coefficient de rapidité de refroidissement de l'arme.\nUne valeur élevée augmente la vitesse de refroidissement. + Coeficiente que determina o quão rápido a arma resfria.\nValores mais altos potencializam o resfriamento. Suppressor Coefficient @@ -106,6 +110,7 @@ Коэф. глушителя Coeficiente del silenciador Coefficient de suppresion + Coeficiente de supressão Coefficient for how much additional heat is added from having a suppressor attached.\nHigher value increases heat, 0 means no additional heat from the suppressor. diff --git a/addons/parachute/stringtable.xml b/addons/parachute/stringtable.xml index db48a6109c..b13483dca5 100644 --- a/addons/parachute/stringtable.xml +++ b/addons/parachute/stringtable.xml @@ -146,6 +146,7 @@ 开伞失败率 낙하산 펼치기 실패 확률 Probabilidad de fallo de paracaidas + Probabilidade de falha do paraquedas diff --git a/addons/realisticnames/stringtable.xml b/addons/realisticnames/stringtable.xml index af864f64df..89c4775d1b 100644 --- a/addons/realisticnames/stringtable.xml +++ b/addons/realisticnames/stringtable.xml @@ -1324,7 +1324,7 @@ Demoliční nálož M183 M183 Charge de démolition M183 комплектный подрывной заряд - M183 Sacola de Demolição + M183 Conjunto de Carga de Demolição M183 romboló töltet M183 Carica da Demolizioni M183 梱包爆薬 @@ -1345,6 +1345,7 @@ M183 Geballte Sprengladung (Werfbar) M183 炸药包(可投掷) M183 폭파 장약 (투척) + M183 Carga de Demolição (Arremessável) M112 Demolition Block @@ -1375,6 +1376,7 @@ M112 Sprengladung (Werfbar) M112 塑性炸药(可投掷) M112 폭파 장약 (투척) + M112 Carga de Demolição (Arremessável) M67 Fragmentation Grenade @@ -4076,6 +4078,7 @@ 엘칸 스펙터OS (초목) ELCAN SpecterOS (обильная растительность) ELCAN SpecterOS (Exuberante) + ELCAN SpecterOS (Exuberante) ELCAN SpecterOS (Arid) @@ -4088,6 +4091,7 @@ 엘칸 스펙터OS (건조) ELCAN SpecterOS (сухая местность) ELCAN SpecterOS (Árido) + ELCAN SpecterOS (Árido) ELCAN SpecterOS 7.62 (Black) @@ -4100,6 +4104,7 @@ 엘칸 스펙터OS 7.62 (검정) ELCAN SpecterOS 7.62 (чёрный) ELCAN SpecterOS 7.62 (Negro) + ELCAN SpecterOS 7.62 (Preto) ELCAN SpecterOS 7.62 (Lush) @@ -4112,6 +4117,7 @@ 엘칸 스펙터OS 7.62 (초목) ELCAN SpecterOS 7.62 (обильная растительность) ELCAN SpecterOS 7.62 (Exuberante) + ELCAN SpecterOS 7.62 (Exuberante) ELCAN SpecterOS 7.62 (Arid) @@ -4124,6 +4130,7 @@ 엘칸 스펙터OS 7.62 (건조) ELCAN SpecterOS 7.62 (сухая местность) ELCAN SpecterOS 7.62 (Árido) + ELCAN SpecterOS 7.62 (Árido) SIG BRAVO4 / ROMEO3 (Black) @@ -4408,6 +4415,7 @@ 버리스 XTR II (낡음) Burris XTR II (старый) Burris XTR II (Viejo) + Burris XTR II (Velho) Burris XTR II (ASP-1 Kir) @@ -4420,6 +4428,7 @@ 버리스 XTR II (ASP-1 키르용) Burris XTR II (ASP-1 Kir) Burris XTR II (ASP-1 Kir) + Burris XTR II (ASP-1 Kir) EOTech XPS3 (Tan) @@ -4480,6 +4489,7 @@ 이오텍 XPS3 (초목) EOTech XPS3 (обильная растительность) EOTech XPS3 (Exuberante) + EOTech XPS3 (Exuberante) EOTech XPS3 (Arid) @@ -4492,6 +4502,7 @@ 이오텍 XPS3 (건조) EOTech XPS3 (сухая местность) EOTech XPS3 (Árido) + EOTech XPS3 (Árido) EOTech XPS3 SMG (Tan) diff --git a/addons/reload/stringtable.xml b/addons/reload/stringtable.xml index 2f0c6c60c1..ec860ff46a 100644 --- a/addons/reload/stringtable.xml +++ b/addons/reload/stringtable.xml @@ -107,7 +107,7 @@ Gurt anhängen Töltényheveder összekötése Combina nastro - Ligar cintos de munição + Conectar cintos de munição ベルトを繋げる 탄띠 연결 连接弹链 @@ -123,7 +123,7 @@ Gurt anhängen... Töltényheveder összekötése folyamatban... Combinando nastro... - Ligando cintos... + Conectando cintos... ベルトを繋げています・・・ 탄띠 연결 중... 正在连接弹链... @@ -139,6 +139,7 @@ 탄띠가 연결되었습니다 Ремень был пристегнут Cinta enganchada + Cinto conectado Belt could not be linked @@ -150,6 +151,7 @@ 탄띠를 연결할 수 없습니다 Ремень не удалось пристегнуть La cinta no ha podido ser enganchada + Cinto não pôde ser conectado diff --git a/addons/reloadlaunchers/stringtable.xml b/addons/reloadlaunchers/stringtable.xml index b55ccde170..6324a97b55 100644 --- a/addons/reloadlaunchers/stringtable.xml +++ b/addons/reloadlaunchers/stringtable.xml @@ -11,6 +11,7 @@ Affichage de notifications lors d'une rechargement par un ami Отображает уведомления о загрузке помощника Mostrar notificaciones para recarga de compañero + Mostrar notificações para Carregamento de Companheiro Displays notifications when an assistant loads a gunner's launcher. @@ -22,6 +23,7 @@ Affiche une notofication lorsqu'un assistant recharge l'arme du tireur. Отображает уведомления, когда помощник загружает пусковую установку стрелка. Mostrar notificaciones cuando un asistente recarga el lanzador del tirador. + Notifica quando um assistente carrega o lançador do atirador Load launcher @@ -50,6 +52,7 @@ %1이(가) 당신의 발사기를 장전했습니다. %1 загружает Вашу установку %1 está cargando tu lanzador + %1 está carregando seu lançador %1 stopped loading your launcher @@ -61,6 +64,7 @@ %1이(가) 당신의 발사기 장전을 멈췄습니다. %1 прекратил загружать Вашу установку %1 paró de cargar tu lanzador + %1 parou de carregar seu lançador Loading launcher... @@ -123,6 +127,7 @@ 발사기를 장전할 수 없습니다. Не удалось загрузить пусковую установку El lanzador no ha podido ser cargado + O lançador não pôde ser carregado Buddy Loading @@ -134,6 +139,7 @@ バディローディング Перезарядка помощником Cargado de Compañero + Carregamento de Companheiro diff --git a/addons/smallarms/stringtable.xml b/addons/smallarms/stringtable.xml index 0b89a38b0d..ebb387113a 100644 --- a/addons/smallarms/stringtable.xml +++ b/addons/smallarms/stringtable.xml @@ -30,6 +30,7 @@ .45 ACP 25Rnd マガジン .45 ACP 25发 弹匣 .45 ACP 25발 탄창 + Carregador 25Mun. .45 ACP .45 ACP 25Rnd Tracers (Green) Mag @@ -44,6 +45,7 @@ .45 ACP 25Rnd トレーサー (緑) マガジン .45 ACP 25发 弹匣(曳光,绿) .45 ACP 25발 예광탄 (초록) 탄창 + Carregador 25Mun. .45 ACP Traçante (Verde) .45 ACP 25Rnd Tracers (Red) Mag @@ -58,6 +60,7 @@ .45 ACP 25Rnd トレーサー (赤) マガジン .45 ACP 25发 弹匣(曳光,红) .45 ACP 25발 예광탄 (빨강) 탄창 + Carregador 25Mun. .45 ACP Traçante (Vermelha) .45 ACP 25Rnd Tracers (Yellow) Mag @@ -72,6 +75,7 @@ .45 ACP 25Rnd トレーサー (黄) マガジン .45 ACP 25发 弹匣(曳光,黄) .45 ACP 25발 예광탄 (노랑) 탄창 + Carregador 25Mun. .45 ACP Traçante (Amarela) .45 ACP 8Rnd Mag @@ -86,6 +90,7 @@ .45 ACP 8Rnd マガジン .45 ACP 8发 弹匣 .45 ACP 8발 탄창 + Carregador 8Mun. .45 ACP .45 ACP 15Rnd Mag @@ -100,6 +105,7 @@ .45 ACP 15Rnd マガジン .45 ACP 15发 弹匣 .45 ACP 15발 탄창 + Carregador 15Mun. .45 ACP diff --git a/addons/towing/stringtable.xml b/addons/towing/stringtable.xml index 949d36dd48..7549fb3c8a 100644 --- a/addons/towing/stringtable.xml +++ b/addons/towing/stringtable.xml @@ -12,6 +12,7 @@ 牵引 견인 Remolcado + Rebocando Attach Tow Rope @@ -24,6 +25,7 @@ 系上牵引绳 견인줄 부착 Sujetar cuerda de remolcado + Fixar corda de reboque Attaching Cancelled @@ -36,6 +38,7 @@ 取消系上绳索 견인 취소됨 Sujección cancelada + Reboque cancelado Attach Tow Rope (3.2m) @@ -48,6 +51,7 @@ 系上牵引绳(3.2米) 견인줄 부착(3.2M) Sujetar cuerda de remolcado (3.2m) + Fixar corda de reboque (3,2m) Attach Tow Rope (6.2m) @@ -60,6 +64,7 @@ 系上牵引绳(6.2米) 견인줄 부착(6.2M) Sujetar cuerda de remolcado (6.2m) + Fixar corda de reboque (6,2m) Attach Tow Rope (12.2m) @@ -72,6 +77,7 @@ 系上牵引绳(12.2米) 견인줄 부착(12.2M) Sujetar cuerda de remolcado (12.2m) + Fixar corda de reboque (12,2m) Attach Tow Rope (15.2m) @@ -84,6 +90,7 @@ 系上牵引绳(15.2米) 견인줄 부착(15.2M) Sujetar cuerda de remolcado (15.2m) + Fixar corda de reboque (15,2m) Attach Tow Rope (18.3m) @@ -96,6 +103,7 @@ 系上牵引绳(18.3米) 견인줄 부착(18.2M) Sujetar cuerda de remolcado (18.3m) + Fixar corda de reboque (18,3m) Attach Tow Rope (27.4m) @@ -108,6 +116,7 @@ 系上牵引绳(27.4米) 견인줄 부착(27.4M) Sujetar cuerda de remolcado (27.4m) + Fixar corda de reboque (27,4m) Attach Tow Rope (36.6m) @@ -120,6 +129,7 @@ 系上牵引绳(36.6米) 견인줄 부착(36.6M) Sujetar cuerda de remolcado (36.6m) + Fixar corda de reboque (36,6m) Detach Tow Rope @@ -132,6 +142,7 @@ 解开牵引绳 견인줄 분리 Desmontar cuerda de remolcado + Soltar corda de reboque Add Tow Rope to Vehicle Inventory @@ -143,6 +154,7 @@ 車両のインベントリに牽引ロープを追加する Abschleppseil zum Fahrzeuginventar hinzufügen Ajouter une corde à l'inventaire des véhicules + Adicionar corda de reboque ao inventário do veículo diff --git a/addons/trenches/stringtable.xml b/addons/trenches/stringtable.xml index 4b47ee6a14..5242603bc2 100644 --- a/addons/trenches/stringtable.xml +++ b/addons/trenches/stringtable.xml @@ -237,6 +237,7 @@ Camuffa la trincea 塹壕を偽装 Graben tarnen + Camuflar trincheira Removing Trench @@ -265,6 +266,7 @@ ACE Trincee ACE 战壕 ACE 참호 + ACE Trincheiras Small Trench Dig Duration @@ -277,6 +279,7 @@ Trincea piccola - Durata di scavo 小型战壕挖掘时间 소형참호 건설 시간 + Duração de Escavamento de Trincheira Pequena Time, in seconds, required to dig a small trench. @@ -289,6 +292,7 @@ Tempo in secondi per scavare una trincea piccola. 挖一条小型战壕所需的时间(秒)。 소형 참호를 팔 때 필요한 시간을 설정합니다. (초 단위) + Tempo, em segundos, necessário para cavar uma trincheira pequena. Small Trench Remove Duration @@ -301,6 +305,7 @@ Trincea piccola - Durata di rimozione 小型战壕回填时间 소형참호 제거 시간 + Duração de Remoção de Trincheira Pequena Time, in seconds, required to remove a small trench. @@ -313,6 +318,7 @@ Tempo in secondi per rimuovere una trincea piccola. 回填一条小型战壕所需的时间(秒)。 소형 참호를 제거할때 필요한 시간을 설정합니다. (초 단위) + Tempo, em segundos, necessário para remover uma trincheira pequena. Big Trench Dig Duration @@ -325,6 +331,7 @@ Trincea grande - Durata di scavo 大型战壕挖掘时间 대형참호 건설 시간 + Duração de Escavamento de Trincheira Grande Time, in seconds, required to dig a big trench. @@ -337,6 +344,7 @@ Tempo in secondi per scavare una trincea grande. 挖一条大型战壕所需的时间(秒)。 대형 참호를 팔때 필요한 시간을 설정합니다. (초 단위) + Tempo, em segundos, necessário para cavar uma trincheira grande. Big Trench Remove Duration @@ -349,6 +357,7 @@ Trincea grande - Durata di rimozione 大型战壕回填时间 대형참호 제거 시간 + Duração de Remoção de Trincheira Grande Time, in seconds, required to remove a big trench. @@ -361,6 +370,7 @@ Tempo in secondi per rimuovere una trincea grande. 回填一条大型战壕所需的时间(秒)。 대형 참호를 제거할때 필요한 시간을 설정합니다. (초 단위) + Tempo, em segundos, necessário para remover uma trincheira grande. diff --git a/addons/ui/stringtable.xml b/addons/ui/stringtable.xml index 2578f58c6d..11089428c2 100644 --- a/addons/ui/stringtable.xml +++ b/addons/ui/stringtable.xml @@ -168,6 +168,7 @@ Filigrana per versione in fase di sviluppo 开发建设水印 개발용 빌드 워터마크 + Marca d'agua de versão de desenvolvimento Weapon Name @@ -680,6 +681,7 @@ 启用移动速度指示器 이동 속도 표시기 활성화 Habilitar indicador de velocidad de movimiento + Habilitar indicador de velocidade de movimento Enables movement speed indicator for player character. @@ -692,6 +694,7 @@ 为玩家角色启用移动速度指示器。 플레이어 캐릭터를 위한 이동속도 표시기를 활성화합니다. Habilita el indicador de velocidad de movimiento para el personaje del jugador. + Habilita o indicador de velocidade de movimento do personagem do jogador. Hide Default Action Icon @@ -704,6 +707,7 @@ Standardaktionssymbol ausblenden Masquer l'icône d'action par défaut Nascondi Icona dell'Interazione Standard + Esconder ícone padrão de ação Hides the icon shown automatically when something is in front of the cursor. Requires a game restart.\nWarning: Does not remove the action itself! It is advisable to unbind 'Use default action' key to prevent unwanted interactions. @@ -716,6 +720,7 @@ Blendet das Symbol aus, das automatisch angezeigt wird, wenn sich etwas vor dem Cursor befindet. Erfordert einen Neustart des Spiels.\nWarnung: Die Aktion selbst wird nicht entfernt! Es empfiehlt sich, die Belegung der Taste 'Standardaktion verwenden' aufzuheben, um unerwünschte Interaktionen zu verhindern. Cache l'icône qui s'affiche automatiquement lorsque quelque chose est devant le curseur. Nécessite un redémarrage du jeu.\nAvertissement : l'action n'est pas supprimée ! Il est recommandé d'annuler l'affectation du bouton 'Utiliser l'action par défaut' afin d'éviter des interactions indésirables. Nasconde l'icona mostrata in automatico quando qualcosa è davanti al cursore. La modifica richiede un riavvio del gioco.\nAttenzione: Non rimuovere l'azione stessa! È consigliato rimuovere solo il tasto dall'assegnazione 'Usa Azione Standard' per impedire interazioni non volute. + Esconde o ícone mostrado automaticamente quando algo está a frente do cursor. É preciso reiniciar o jogo.\nAviso: Não remove a ação em si! É recomendado desvincular a tecla de "Usar ação padrão" para previnir interações indesejadas. diff --git a/addons/vehicle_damage/stringtable.xml b/addons/vehicle_damage/stringtable.xml index 4a8fdb4264..8e0bb6fe70 100644 --- a/addons/vehicle_damage/stringtable.xml +++ b/addons/vehicle_damage/stringtable.xml @@ -12,6 +12,7 @@ ACE 고급 차량 피해 ACE Продвинутое повреждение техники ACE Daño avanzado de vehículos + ACE Dano avançãdo de veículos Enable/Disable advanced vehicle damage @@ -24,6 +25,7 @@ 고급 차량 피해 활성화/비활성화 Включить/выключить продвинутое повреждение техники Habilitar/Deshabilitar el daño avanzado de vehículos + Ativar/Desativar dano avançado de veículo Enable/Disable advanced car damage (Experimental) @@ -36,6 +38,7 @@ 고급 차량 피해(실험용) 활성화/비활성화 Включить/выключить продвинутое повреждение машин (экспериментальное) Habilita/Deshabilita el daño avanzado de coche (Experimental) + Ativar/Desativar dano avançado de carro (Experimental) Enable/Disable advanced car damage @@ -48,6 +51,7 @@ 고급 차량 피해 활성화/비활성화 Продвинутое повреждение машин Habilitar/Deshabilitar daño avanzado de coche (Experimental) + Ativar/Desativar dano avançado de carro Wreck (Turret) diff --git a/addons/vehiclelock/stringtable.xml b/addons/vehiclelock/stringtable.xml index b247967fe1..7f89ec4950 100644 --- a/addons/vehiclelock/stringtable.xml +++ b/addons/vehiclelock/stringtable.xml @@ -288,6 +288,7 @@ Unklaren Sperrzustand entfernen 移除不明确的上锁状态 불분명한 잠금상태 제거 + Remover estado de bloqueio ambíguo As Is diff --git a/addons/vehicles/stringtable.xml b/addons/vehicles/stringtable.xml index 741901d75c..6148bcdd25 100644 --- a/addons/vehicles/stringtable.xml +++ b/addons/vehicles/stringtable.xml @@ -29,6 +29,7 @@ Круиз-контроль включён Control de crucero encendido Régulateur de vitesse activé + Controle de cruzeiro ativado Speed Limiter off @@ -58,6 +59,7 @@ Круиз-контроль выключен Control de crucero apagado Régulateur de vitesse désactivé + Controle de cruzeiro desativado Speed Limit diff --git a/addons/viewdistance/stringtable.xml b/addons/viewdistance/stringtable.xml index eb7ed94838..2c2e92d24e 100644 --- a/addons/viewdistance/stringtable.xml +++ b/addons/viewdistance/stringtable.xml @@ -129,6 +129,7 @@ Значение 0 будет использовать настройки видео по умолчанию Establecer a 0 utiliza las opciones de video por defecto La valeur 0 permet d'utiliser les paramètres vidéo par défaut + Estabelecer em 0 utilizará as configurações padrão de vídeo Client View Distance (On Foot) diff --git a/addons/viewports/stringtable.xml b/addons/viewports/stringtable.xml index be78cdc995..22f7d77813 100644 --- a/addons/viewports/stringtable.xml +++ b/addons/viewports/stringtable.xml @@ -12,6 +12,7 @@ Periscopios Sichtfenster Périscopes + Periscópios Allows crew to look through periscopes @@ -24,6 +25,7 @@ Permite a la tripulación asomarse a través de los periscopios Ermöglicht der Besatzung den Blick durch Periskope Permet à l'équipage de regarder à travers des périscopes. + Permite que a tripulação olhe através de periscópios diff --git a/addons/viewrestriction/stringtable.xml b/addons/viewrestriction/stringtable.xml index fee4a9bf33..7356e6412f 100644 --- a/addons/viewrestriction/stringtable.xml +++ b/addons/viewrestriction/stringtable.xml @@ -15,6 +15,7 @@ Ограничение обзора Görüntüyü Kısıtla Reestricción de Vista + Restrição do Modo de Visão View restriction settings to limit the usage of 1st or 3rd person views globally or per vehicle type. @@ -29,6 +30,7 @@ Настройки ограничения обзора при виде от 1-го или 3-го лица. Общие для всех, или Выборочные, в зависимости от техники. 1. veya 3. kişi görünümlerinin kullanımını genel olarak veya araç türüne göre sınırlamak için kısıtlama ayarlarını görüntüleyin. Opciones de Reestricción de Vista para limitar el uso de 1º o 3º persona globalmente o según el tipo de vehículo. + A restrição do modo de visão limita o uso de 1ª ou 3ª pessoa globalmente ou por tipo de veículo. Mode @@ -44,6 +46,7 @@ Режим установок Mod Modo + Modo Sets global mode. Default: Disabled @@ -59,6 +62,7 @@ Общие установки для всех. По умолчанию: Отключено. Global modu ayarlar. Varsayılan: Devre Dışı Establece el modo global. Defecto: Deshabilitado + Define o modo global. Padrão: Desabilitado (Selective) Foot @@ -74,6 +78,7 @@ (Выборочные) Пешком (Seçilebilir) Ayakta (Selectivo) Pie + (Seletivo) A pé Selective mode on Foot. Default: Disabled (Requires Mode: Selective) @@ -89,6 +94,7 @@ Выборочные установки без техники. По умолчанию: Отключено (требуется режим: Выборочные) Ayakta iken seçilen görüş modu. Varsayılan: Etkin Değil Modo selectivo a pie. Defecto: Deshabilitado (Requiere Modo: Selectivo) + Modo seletivo a pé. Padrão: Desabilitado (Modo necessário: Seletivo) (Selective) Land Vehicles @@ -104,6 +110,7 @@ (Выборочные) Наземная техника (Seçilebilir) Kara Araçları (Selectivo) Vehículos de tierra + (Seletivo) Veículos terrestres Selective mode in Land Vehicles. Default: Disabled (Requires Mode: Selective) @@ -119,6 +126,7 @@ Выборочные установки для наземной техники. По умолчанию: Отключено (требуется режим: Выборочные) Kara araçlarında iken seçilen görüş modu. Varsayılan: Etkin Değil Modo selectivo en vehículos de tierra.Defecto: Deshabilitado (Requiere Modo: Selectivo) + Modo seletivo em veículos terrestres. Padrão: Desabilitado (Modo necessário: Seletivo) (Selective) Air Vehicles @@ -134,6 +142,7 @@ (Выборочные) Авиатехника (Seçilebilir) Hava Araçları (Selectivo) Vehículos aéreos + (Seletivo) Aeronaves Selective mode in Air Vehicles. Default: Disabled (Requires Mode: Selective) @@ -149,6 +158,7 @@ Выборочные установки для авиатехники. По умолчанию: Отключено (требуется режим: Выборочные) Hava araçlarında iken seçilen görüş modu. Varsayılan: Etkin Değil Modo selectivo en vehículos aéreos. Defecto: Deshabilitado (Requiere Modo: Selectivo) + Modo seletivo em aeronaves. Padrão: Desabilitado (Modo necessário: Seletivo) (Selective) Sea Vehicles @@ -164,6 +174,7 @@ (Выборочные) Водный транспорт (Seçilebilir) Deniz Araçları (Selectivo) Vehículos marítimos + (Seletivo) Veículos aquáticos Selective mode in Sea Vehicles. Default: Disabled (Requires Mode: Selective) @@ -179,6 +190,7 @@ Выборочные установки для водного транспорта. По умолчанию: Отключено (требуется режим: Выборочные) Deniz araçlarında iken seçilen görüş modu. Varsayılan: Etkin Değil Modo selectivo en vehículos marítimos. Defecto: Deshabilitado (Requiere Modo: Selectivo) + Modo seletivo em veículos aquáticos. Padrão: Desabilitado (Modo necessário: Seletivo) (Selective) UAVs @@ -194,6 +206,7 @@ (Выборочные) Беспиплотники (Seçilebilir) IHA'lar (Selectivo) VANTs + (Seletivo) VANTs Selective mode in UAVs. Default: Disabled (Requires Mode: Selective) @@ -209,6 +222,7 @@ Выборочные установки для беспилотников. По умолчанию: Отключено (требуется режим: Выборочные) IHA araçlarında iken seçilen görüş modu. Varsayılan: Etkin Değil Modo selectivo en VANTs. Defecto: Deshabilitado (Requiere Modo: Selectivo) + Modo seletivo em VANTs. Padrão: Desabilitado (Modo necessário: Seletivo) Disabled @@ -224,6 +238,7 @@ Отключено Devre Dışı Deshabilitado + Desabilitado Forced 1st Person @@ -238,6 +253,7 @@ От 1-го лица (принудительно) 1. Kişi Görüşüne Zorla Forzada 1º persona + Forçada 1ª pessoa Forced 3rd Person @@ -252,6 +268,7 @@ От 3-го лица (принудительно) 3. Kişi Görüşüne Zorla Forzada 3º persona + Forçada 3ª pessoa Selective @@ -267,6 +284,7 @@ Выборочный Seçilebilinir Selectivo + Seletivo Preserve view for vehicle types @@ -281,6 +299,7 @@ 차량 타입에 따른 시야 정보 저장 Preservar vista para los tipos de vehículos Conserver la vue pour les types de véhicules + Mantém o modo de visão por tipo de veículo Switch view on vehicle change to last used in this vehicle type (Requires Mode: Disabled) @@ -295,6 +314,7 @@ 해당 차량 타입에서 마지막으로 사용했던 시야로 설정하여 봅니다 (모드 - 사용 안함 필요) Cambiar vista en el cambio de vehículo hacia la última usada en ese tipo de vehículo (Requiere Modo: Deshabilitado) Lors d'un changement de véhicule, change la vue pour la dernière utilisée dans ce type de véhicule (Mod requis : désactivé). + Ao trocar de veículo, troca o modo de visão para aquele usado anteriormente no mesmo tipo de veículo (Modo necessário: Desabilitado) diff --git a/addons/volume/stringtable.xml b/addons/volume/stringtable.xml index feecb28b10..08aae728a1 100644 --- a/addons/volume/stringtable.xml +++ b/addons/volume/stringtable.xml @@ -14,6 +14,7 @@ Głosność Ses Volumen + Volume Toggle Volume @@ -28,6 +29,7 @@ Przełącz Głosność Sesi Aç/Kapat Activar control de volumen + Alternar volume Toggle volume reduction. @@ -42,6 +44,7 @@ Przełącz redukcje głosności Ses azaltmayı aç / kapat. Activar reducción de volumen. + Alternar redução de volume Lowered volume @@ -56,6 +59,7 @@ Zmniejszona głosność Azaltılmış ses Volumen reducido + Volume reduzido Restored volume @@ -69,6 +73,7 @@ Громкость восстановлена Przywrócona głosność Volumen restaurado + Volume restaurado Reduction @@ -82,6 +87,7 @@ Уменьшение Redukcja Reducción + Redução Reduce volume by this percentage. @@ -95,6 +101,7 @@ Уменьшает громкость Zmniejsz głosność o tyle procent Reducir el volumen este porcentaje. + Reduzir o volume por esta porcentagem. Lower in vehicles @@ -109,6 +116,7 @@ Zmniejsz w pojazdach Araçlarda Daha Düşük Reducir en vehículos + Reduzir em veículos Automatically lower volume when inside vehicles. @@ -123,6 +131,7 @@ Automatycznie zmniejsz głosność będąc w pojeździe Araçlara binince sesi azalt. Reduce automáticamente el volumen dentro de vehículos. + Reduz automaticamente o volume dentro de veículos. Show notification @@ -137,6 +146,7 @@ Pokaż powiadomienie Bildirim Göster Mostrar notificación + Mostrar notificação Show notification when lowering/restoring volume. @@ -151,6 +161,7 @@ Pokaż powiadomienie zmniejszając/odnawiając głosność Ses azaltıldığın da bildirim göster. Mostrar notificación cuando se disminuye/restaura el volumen. + Mostrar notificação quando o volume for reduzido/restaurado Fade delay @@ -164,6 +175,7 @@ Задержка затухания Opoznienie wyciszenia Retardo en disminución gradual + Atraso de alteração gradual de volume Time it takes (in seconds) for the sound to fade in/out. @@ -177,6 +189,7 @@ Время (сек.) для затухания/восстановления звука. Ilość czasu (w sekundach) ile zajmuje wyciszenie/zgłośnienie dźwięku Tiempo que tarda (en segundos) para que se active o desactive la disminuación gradual del volumen + Tempo de atraso (em segundos) para que o volume do som sofra alteração gradual Reminder if lowered @@ -191,6 +204,7 @@ Przypomnij o zmniejszonej głosności dźwięku Eğer Düşükse Hatırlat Recordatorio s reducido + Lembrete de redução sonora Reminds you every minute if your volume is lowered. @@ -205,6 +219,7 @@ Przypomina co minuten o zmniejszonej głosności dźwięku Eğer ses düşükse her dakika hatırlatır. Te recuerda cada minuto si el volumen está siendo reducido. + Te notifica a cada minuto se o volume sonoro estiver reduzido. Volume still lowered @@ -219,6 +234,7 @@ Dźwięk jest nadal zmniejszony Ses hala düşük Volumen todavía reducido + Volume ainda está reduzido From 6a25e9365af5479a282c6b06e13eb37f3c86df95 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Fri, 2 Aug 2024 13:59:18 +0200 Subject: [PATCH 172/290] Safemode - Refactor (#10111) * Refactor safemode * Further improvements and fixes * Update XEH_postInit.sqf * Don't allow binoculars to be set to safe * Add API for getting weapon safety status * Update fnc_jamWeapon.sqf * Added doc * Update fnc_playChangeFiremodeSound.sqf * Update addons/overheating/functions/fnc_jamWeapon.sqf Co-authored-by: PabstMirror * Update addons/weaponselect/functions/fnc_selectWeaponMode.sqf Co-authored-by: PabstMirror --------- Co-authored-by: PabstMirror --- .../common/functions/fnc_getWeaponMuzzles.sqf | 23 +++-- .../overheating/functions/fnc_jamWeapon.sqf | 8 +- addons/safemode/CfgEventHandlers.hpp | 1 - addons/safemode/XEH_PREP.hpp | 4 +- addons/safemode/XEH_postInit.sqf | 22 +++-- .../functions/fnc_getWeaponSafety.sqf | 45 ++++++++++ addons/safemode/functions/fnc_lockSafety.sqf | 89 ++++++++++--------- .../functions/fnc_playChangeFiremodeSound.sqf | 20 +++-- .../functions/fnc_setSafeModeVisual.sqf | 8 +- .../functions/fnc_setWeaponSafety.sqf | 35 +++++--- .../safemode/functions/fnc_unlockSafety.sqf | 80 ++++++----------- .../functions/fnc_selectWeaponMode.sqf | 4 +- docs/wiki/framework/safemode-framework.md | 58 ++++++++++++ 13 files changed, 257 insertions(+), 140 deletions(-) create mode 100644 addons/safemode/functions/fnc_getWeaponSafety.sqf create mode 100644 docs/wiki/framework/safemode-framework.md diff --git a/addons/common/functions/fnc_getWeaponMuzzles.sqf b/addons/common/functions/fnc_getWeaponMuzzles.sqf index 11fffaf196..0184a0c8c8 100644 --- a/addons/common/functions/fnc_getWeaponMuzzles.sqf +++ b/addons/common/functions/fnc_getWeaponMuzzles.sqf @@ -1,6 +1,6 @@ #include "..\script_component.hpp" /* - * Author: commy2 + * Author: commy2, johnb43 * Get the muzzles of a weapon. * * Arguments: @@ -10,19 +10,30 @@ * All weapon muzzles * * Example: - * ["gun"] call ace_common_fnc_getWeaponMuzzles + * "arifle_AK12_F" call ace_common_fnc_getWeaponMuzzles * * Public: Yes */ params [["_weapon", "", [""]]]; -private _muzzles = getArray (configFile >> "CfgWeapons" >> _weapon >> "muzzles"); +private _config = configFile >> "CfgWeapons" >> _weapon; +if (!isClass _config) exitWith { + [] // return +}; + +private _muzzles = []; + +// Get config case muzzle names { if (_x == "this") then { - _muzzles set [_forEachIndex, configName (configFile >> "CfgWeapons" >> _weapon)]; + _muzzles pushBack (configName _config); + } else { + if (isClass (_config >> _x)) then { + _muzzles pushBack (configName (_config >> _x)); + }; }; -} forEach _muzzles; +} forEach getArray (_config >> "muzzles"); -_muzzles +_muzzles // return diff --git a/addons/overheating/functions/fnc_jamWeapon.sqf b/addons/overheating/functions/fnc_jamWeapon.sqf index 9a5b8b1049..afe6d15e97 100644 --- a/addons/overheating/functions/fnc_jamWeapon.sqf +++ b/addons/overheating/functions/fnc_jamWeapon.sqf @@ -80,9 +80,11 @@ if (_unit getVariable [QGVAR(JammingActionID), -1] == -1) then { private _condition = { private _unit = _this select 1; - [_unit] call CBA_fnc_canUseWeapon - && {currentMuzzle _unit in (_unit getVariable [QGVAR(jammedWeapons), []])} - && {!(currentMuzzle _unit in (_unit getVariable [QEGVAR(safemode,safedWeapons), []]))} + (weaponState _unit) params ["_currentWeapon", "_currentMuzzle"]; + + _unit call CBA_fnc_canUseWeapon + && {_currentMuzzle in (_unit getVariable [QGVAR(jammedWeapons), []])} + && {!(["ace_safemode"] call EFUNC(common,isModLoaded)) || {!([_unit, _currentWeapon, _currentMuzzle] call EFUNC(safemode,getWeaponSafety))}} }; private _statement = { diff --git a/addons/safemode/CfgEventHandlers.hpp b/addons/safemode/CfgEventHandlers.hpp index 6c29240403..f6503c2479 100644 --- a/addons/safemode/CfgEventHandlers.hpp +++ b/addons/safemode/CfgEventHandlers.hpp @@ -1,4 +1,3 @@ - class Extended_PreStart_EventHandlers { class ADDON { init = QUOTE(call COMPILE_SCRIPT(XEH_preStart)); diff --git a/addons/safemode/XEH_PREP.hpp b/addons/safemode/XEH_PREP.hpp index 2f23aa02c9..499ae80867 100644 --- a/addons/safemode/XEH_PREP.hpp +++ b/addons/safemode/XEH_PREP.hpp @@ -1,6 +1,6 @@ - +PREP(getWeaponSafety); PREP(lockSafety); PREP(playChangeFiremodeSound); PREP(setSafeModeVisual); -PREP(unlockSafety); PREP(setWeaponSafety); +PREP(unlockSafety); diff --git a/addons/safemode/XEH_postInit.sqf b/addons/safemode/XEH_postInit.sqf index db922f9b35..79064789d5 100644 --- a/addons/safemode/XEH_postInit.sqf +++ b/addons/safemode/XEH_postInit.sqf @@ -4,18 +4,26 @@ if (!hasInterface) exitWith {}; -["ACE3 Weapons", QGVAR(safeMode), localize LSTRING(SafeMode), { +["ACE3 Weapons", QGVAR(safeMode), LLSTRING(SafeMode), { // Conditions: canInteract if !([ACE_player, objNull, ["isNotEscorting", "isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; - // Conditions: specific - if !([ACE_player] call CBA_fnc_canUseWeapon && {currentWeapon ACE_player != binocular ACE_player} && {currentWeapon ACE_player != ""}) exitWith {false}; - // Statement - [ACE_player, currentWeapon ACE_player, currentMuzzle ACE_player] call FUNC(lockSafety); + (weaponState ACE_player) params ["_currentWeapon", "_currentMuzzle"]; + + // Conditions: specific + if !(ACE_player call CBA_fnc_canUseWeapon && {_currentWeapon != ""} && {_currentWeapon != binocular ACE_player}) exitWith {false}; + + // Statement: Toggle weapon safety + [ACE_player, _currentWeapon, _currentMuzzle] call FUNC(lockSafety); + true }, {false}, [DIK_GRAVE, [false, true, false]], false] call CBA_fnc_addKeybind; ["unit", { - private _weaponSafe = currentWeapon ACE_player in (ACE_player getVariable [QGVAR(safedWeapons), []]); - [!_weaponSafe] call FUNC(setSafeModeVisual); + (weaponState ACE_player) params ["_currentWeapon", "_currentMuzzle"]; + + private _weaponSafe = [ACE_player, _currentWeapon, _currentMuzzle] call FUNC(getWeaponSafety); + + // Player HUD + !_weaponSafe call FUNC(setSafeModeVisual); }] call CBA_fnc_addPlayerEventHandler; diff --git a/addons/safemode/functions/fnc_getWeaponSafety.sqf b/addons/safemode/functions/fnc_getWeaponSafety.sqf new file mode 100644 index 0000000000..b171d974e4 --- /dev/null +++ b/addons/safemode/functions/fnc_getWeaponSafety.sqf @@ -0,0 +1,45 @@ +#include "..\script_component.hpp" +/* + * Author: johnb43 + * Getter for weapon safety state. + * + * Arguments: + * 0: Unit + * 1: Weapon + * 2: Muzzle (default: current muzzle of weapon) + * + * Return Value: + * Safety status + * + * Example: + * [ACE_player, currentWeapon ACE_player] call ace_safemode_fnc_getWeaponSafety + * + * Public: Yes + */ + +params [ + ["_unit", objNull, [objNull]], + ["_weapon", "", [""]], + ["_muzzle", nil, [""]] +]; + +if (_weapon == "" || {!(_unit hasWeapon _weapon)}) exitWith {false}; + +// Check if weapon is a binocular +if ((_weapon call EFUNC(common,getItemType)) select 1 == "binocular") exitWith {false}; + +// Check for invalid muzzles +_muzzle = if (isNil "_muzzle") then { + // Get current weapon muzzle if not defined + (_unit weaponState _weapon) select 1 +} else { + // Get config case muzzle names + private _muzzles = _weapon call EFUNC(common,getWeaponMuzzles); + + _muzzles param [_muzzles findIf {_x == _muzzle}, ""] +}; + +// Weapon is not available +if (_muzzle == "") exitWith {false}; + +_muzzle in ((_unit getVariable [QGVAR(safedWeapons), createHashMap]) getOrDefault [_weapon, createHashMap]) // return diff --git a/addons/safemode/functions/fnc_lockSafety.sqf b/addons/safemode/functions/fnc_lockSafety.sqf index 6c617c1898..28adb42df9 100644 --- a/addons/safemode/functions/fnc_lockSafety.sqf +++ b/addons/safemode/functions/fnc_lockSafety.sqf @@ -1,13 +1,13 @@ #include "..\script_component.hpp" /* - * Author: commy2 - * Put weapon on safety, or take it off safety if safety is already put on. + * Author: commy2, johnb43 + * Puts weapon on safety, or take it off safety if safety is already put on. * * Arguments: * 0: Unit * 1: Weapon * 2: Muzzle - * 3: Show hint + * 3: Show hint (default: true) * * Return Value: * None @@ -18,67 +18,74 @@ * Public: No */ -params ["_unit", "_weapon", "_muzzle", ["_hint", true, [true]]]; +params ["_unit", "_weapon", "_muzzle", ["_hint", true]]; -private _safedWeapons = _unit getVariable [QGVAR(safedWeapons), []]; +private _safedWeapons = _unit getVariable QGVAR(safedWeapons); -if (_weapon in _safedWeapons) exitWith { - _this call FUNC(unlockSafety); +if (isNil "_safedWeapons") then { + _safedWeapons = createHashMap; + + _unit setVariable [QGVAR(safedWeapons), _safedWeapons]; }; -_safedWeapons pushBack _weapon; +// See if the current weapon has locked muzzles +private _safedWeaponMuzzles = _safedWeapons getOrDefault [_weapon, createHashMap, true]; -_unit setVariable [QGVAR(safedWeapons), _safedWeapons]; +// If muzzle is locked, unlock it (toggle) +if (_muzzle in _safedWeaponMuzzles) exitWith { + [_unit, _weapon, _muzzle, _hint] call FUNC(unlockSafety); +}; -if (_unit getVariable [QGVAR(actionID), -1] == -1) then { +private _firemode = (_unit weaponState _muzzle) select 2; + +// This syntax of selectWeapon doesn't mess with gun lights and lasers +_unit selectWeapon [_weapon, _muzzle, _firemode]; + +// Store new muzzle & firemode +_safedWeaponMuzzles set [_muzzle, _firemode]; + +// Lock muzzle +if (isNil {_unit getVariable QGVAR(actionID)}) then { _unit setVariable [QGVAR(actionID), [ _unit, "DefaultAction", { + params ["", "_unit"]; + if ( - [_this select 1] call CBA_fnc_canUseWeapon - && { - if (currentMuzzle (_this select 1) in ((_this select 1) getVariable [QGVAR(safedWeapons), []])) then { - if (inputAction "nextWeapon" > 0) exitWith { - [_this select 1, currentWeapon (_this select 1), currentMuzzle (_this select 1)] call FUNC(unlockSafety); + _unit call CBA_fnc_canUseWeapon && { + (weaponState _unit) params ["_currentWeapon", "_currentMuzzle"]; + + // Block firing the muzzle in safe mode + if (_currentMuzzle in ((_unit getVariable [QGVAR(safedWeapons), createHashMap]) getOrDefault [_currentWeapon, createHashMap])) then { + if (inputAction "nextWeapon" > 0 || {inputAction "prevWeapon" > 0}) exitWith { + [_unit, _currentWeapon, _currentMuzzle] call FUNC(unlockSafety); + false }; + true - } else {false} + } else { + false + } } ) then { - // player hud - [false] call FUNC(setSafeModeVisual); + // Player HUD + false call FUNC(setSafeModeVisual); + true } else { - // player hud - [true] call FUNC(setSafeModeVisual); + // Player HUD + true call FUNC(setSafeModeVisual); + false }; }, {} ] call EFUNC(common,addActionEventHandler)]; }; -if (_muzzle isEqualType "") then { - private _laserEnabled = _unit isIRLaserOn _weapon || {_unit isFlashlightOn _weapon}; - - _unit selectWeapon _muzzle; - - if ( - _laserEnabled - && { - _muzzle == primaryWeapon _unit // prevent UGL switch - || {"" == primaryWeapon _unit} // Arma switches to primary weapon if exists - } - ) then { - {_unit action [_x, _unit]} forEach ["GunLightOn", "IRLaserOn"]; - }; -}; - -// play fire mode selector sound +// Play fire mode selector sound [_unit, _weapon, _muzzle] call FUNC(playChangeFiremodeSound); -// show info box unless disabled +// Show info box unless disabled if (_hint) then { - private _picture = getText (configFile >> "CfgWeapons" >> _weapon >> "picture"); - [localize LSTRING(PutOnSafety), _picture] call EFUNC(common,displayTextPicture); + [LLSTRING(PutOnSafety), getText (configFile >> "CfgWeapons" >> _weapon >> "picture")] call EFUNC(common,displayTextPicture); }; - diff --git a/addons/safemode/functions/fnc_playChangeFiremodeSound.sqf b/addons/safemode/functions/fnc_playChangeFiremodeSound.sqf index 257e5864f6..1edc236334 100644 --- a/addons/safemode/functions/fnc_playChangeFiremodeSound.sqf +++ b/addons/safemode/functions/fnc_playChangeFiremodeSound.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: commy2 - * Play weapon firemode change sound. + * Plays weapon firemode change sound. * * Arguments: * 0: Unit @@ -21,21 +21,23 @@ params ["_unit", "_weapon"]; private _sound = getArray (configFile >> "CfgWeapons" >> _weapon >> "changeFiremodeSound"); if (_sound isEqualTo []) exitWith { - playSound "ACE_Sound_Click"; + playSoundUI ["ACE_Sound_Click"]; }; -// get position where to play the sound (position of the weapon) -private _position = _unit modelToWorldVisualWorld (_unit selectionPosition "RightHand"); - -_sound params ["_filename", ["_volume", 1], ["_soundPitch", 1], ["_distance", 0]]; +_sound params [["_filename", ""], ["_volume", 1], ["_soundPitch", 1], ["_distance", 0]]; if (_filename == "") exitWith { - playSound "ACE_Sound_Click"; + playSoundUI ["ACE_Sound_Click"]; }; -// add file extension .wss as default +// Add file extension .wss as default if !(toLowerANSI (_filename select [count _filename - 4]) in [".wav", ".ogg", ".wss"]) then { _filename = format ["%1.wss", _filename]; }; -playSound3D [_filename, objNull, false, _position, _volume, _soundPitch, _distance]; +// Get position where to play the sound (position of the weapon) +private _position = _unit modelToWorldVisualWorld (_unit selectionPosition "RightHand"); + +playSound3D [_filename, objNull, insideBuilding _unit >= 0.5, _position, _volume, _soundPitch, _distance]; + +nil // return diff --git a/addons/safemode/functions/fnc_setSafeModeVisual.sqf b/addons/safemode/functions/fnc_setSafeModeVisual.sqf index d62a542b9d..12b7f864ef 100644 --- a/addons/safemode/functions/fnc_setSafeModeVisual.sqf +++ b/addons/safemode/functions/fnc_setSafeModeVisual.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: commy2 - * Show firemode indicator, representing safety lock + * Shows firemode indicator, representing safety lock. * * Arguments: * 0: Show firemode @@ -10,7 +10,7 @@ * None * * Example: - * [true] call ace_safemode_fnc_setSafeModeVisual + * true call ace_safemode_fnc_setSafeModeVisual * * Public: No */ @@ -27,8 +27,8 @@ if (_show) then { private _config = configFile >> "RscInGameUI" >> "RscUnitInfoSoldier" >> "WeaponInfoControlsGroupLeft" >> "controls" >> "CA_ModeTexture"; _control ctrlSetPosition [getNumber (_config >> "x"), getNumber (_config >> "y"), getNumber (_config >> "w"), getNumber (_config >> "h")]; - _control ctrlCommit 0; } else { _control ctrlSetPosition [0, 0, 0, 0]; - _control ctrlCommit 0; }; + +_control ctrlCommit 0; diff --git a/addons/safemode/functions/fnc_setWeaponSafety.sqf b/addons/safemode/functions/fnc_setWeaponSafety.sqf index d80e1d8c38..3db0033bf8 100644 --- a/addons/safemode/functions/fnc_setWeaponSafety.sqf +++ b/addons/safemode/functions/fnc_setWeaponSafety.sqf @@ -1,13 +1,14 @@ #include "..\script_component.hpp" /* - * Author: Brostrom.A - * Safe or unsafe the given weapon based on weapon state; locked or unlocked. + * Author: Brostrom.A, johnb43 + * Lock or unlock the given weapon based on weapon state. * * Arguments: * 0: Unit * 1: Weapon * 2: State * 3: Show hint (default: true) + * 4: Muzzle (default: current muzzle of weapon) * * Return Value: * None @@ -22,17 +23,31 @@ params [ ["_unit", objNull, [objNull]], ["_weapon", "", [""]], ["_state", true, [true]], - ["_hint", true, [true]] + ["_hint", true, [true]], + ["_muzzle", nil, [""]] ]; -if (_weapon == "") exitWith {}; +// Don't allow to set weapon safety if unit doesn't have one (but allow removing safety, in case unit doesn't have weapon anymore) +if (_weapon == "" || {_state && {!(_unit hasWeapon _weapon)}}) exitWith {}; -private _safedWeapons = _unit getVariable [QGVAR(safedWeapons), []]; +// Check if weapon is a binocular +if ((_weapon call EFUNC(common,getItemType)) select 1 == "binocular") exitWith {}; -_weapon = configName (configFile >> "CfgWeapons" >> _weapon); +// Check for invalid muzzles +_muzzle = if (isNil "_muzzle") then { + // Get current weapon muzzle if not defined + (_unit weaponState _weapon) select 1 +} else { + // Get config case muzzle names + private _muzzles = _weapon call EFUNC(common,getWeaponMuzzles); -private _muzzle = currentMuzzle _unit; - -if (_state isNotEqualTo (_weapon in _safedWeapons)) then { - [_unit, _weapon, _muzzle, _hint] call FUNC(lockSafety); + _muzzles param [_muzzles findIf {_x == _muzzle}, ""] }; + +// Weapon is not available +if (_muzzle == "") exitWith {}; + +// If the weapon is already in the desired state, don't do anything +if (_state == (_muzzle in ((_unit getVariable [QGVAR(safedWeapons), createHashMap]) getOrDefault [_weapon, createHashMap]))) exitWith {}; + +[_unit, _weapon, _muzzle, _hint] call FUNC(lockSafety); diff --git a/addons/safemode/functions/fnc_unlockSafety.sqf b/addons/safemode/functions/fnc_unlockSafety.sqf index 10372f1a2e..97716025dc 100644 --- a/addons/safemode/functions/fnc_unlockSafety.sqf +++ b/addons/safemode/functions/fnc_unlockSafety.sqf @@ -1,13 +1,13 @@ #include "..\script_component.hpp" /* - * Author: commy2 - * Take weapon of safety lock. + * Author: commy2, johnb43 + * Takes the weapon safety lock off. * * Arguments: * 0: Unit * 1: Weapon * 2: Muzzle - * 3: Show hint + * 3: Show hint (default: true) * * Return Value: * None @@ -18,67 +18,37 @@ * Public: No */ -params ["_unit", "_weapon", "_muzzle", ["_hint", true, [true]]]; +params ["_unit", "_weapon", "_muzzle", ["_hint", true]]; -private _safedWeapons = _unit getVariable [QGVAR(safedWeapons), []]; -_safedWeapons deleteAt (_safedWeapons find _weapon); +private _safedWeaponMuzzles = (_unit getVariable QGVAR(safedWeapons)) get _weapon; +private _firemode = _safedWeaponMuzzles deleteAt _muzzle; -_unit setVariable [QGVAR(safedWeapons), _safedWeapons]; +// Remove action if all weapons have removed their safeties +if (_safedWeaponMuzzles isEqualTo createHashMap) then { + (_unit getVariable QGVAR(safedWeapons)) deleteAt _weapon; -// remove action if all weapons have put their safety on -if (_safedWeapons isEqualTo []) then { - [_unit, "DefaultAction", _unit getVariable [QGVAR(actionID), -1]] call EFUNC(common,removeActionEventHandler); - _unit setVariable [QGVAR(actionID), -1]; -}; + private _ehID = _unit getVariable QGVAR(actionID); -private _laserEnabled = _unit isIRLaserOn _weapon || {_unit isFlashlightOn _weapon}; + if (!isNil "_ehID" && {(_unit getVariable QGVAR(safedWeapons)) isEqualTo createHashMap}) then { + [_unit, "DefaultAction", _ehID] call EFUNC(common,removeActionEventHandler); -_unit selectWeapon _muzzle; - -if ( - _laserEnabled - && { - _muzzle == primaryWeapon _unit // prevent UGL switch - || {"" == primaryWeapon _unit} // Arma switches to primary weapon if exists - } -) then { - {_unit action [_x, _unit]} forEach ["GunLightOn", "IRLaserOn"]; -}; - -if (inputAction "nextWeapon" > 0) then { - // switch to the last mode to roll over to first after the default nextWeapon action - // get weapon modes - private _modes = []; - { - if (getNumber (configFile >> "CfgWeapons" >> _weapon >> _x >> "showToPlayer") == 1) then { - _modes pushBack _x; - }; - if (_x == "this") then { - _modes pushBack _weapon; - }; - } forEach getArray (configFile >> "CfgWeapons" >> _weapon >> "modes"); - - // select last mode - private _mode = _modes select (count _modes - 1); - - // switch to last mode - private _index = 0; - while { - _index < 299 && {currentMuzzle _unit != _weapon || {currentWeaponMode _unit != _mode}} - } do { - _unit action ["SwitchWeapon", _unit, _unit, _index]; - _index = _index + 1; + _unit setVariable [QGVAR(actionID), nil]; }; -} else { - // play fire mode selector sound +}; + +// Let engine handle switching to next firemode/muzzle +if (inputAction "nextWeapon" == 0 && {inputAction "prevWeapon" == 0}) then { + // This syntax of selectWeapon doesn't mess with gun lights and lasers + _unit selectWeapon [_weapon, _muzzle, _firemode]; + + // Play fire mode selector sound [_unit, _weapon, _muzzle] call FUNC(playChangeFiremodeSound); }; -// player hud -[true] call FUNC(setSafeModeVisual); +// Player HUD +true call FUNC(setSafeModeVisual); -// show info box unless disabled +// Show info box unless disabled if (_hint) then { - private _picture = getText (configFile >> "CfgWeapons" >> _weapon >> "picture"); - [localize LSTRING(TookOffSafety), _picture] call EFUNC(common,displayTextPicture); + [LLSTRING(TookOffSafety), getText (configFile >> "CfgWeapons" >> _weapon >> "picture")] call EFUNC(common,displayTextPicture); }; diff --git a/addons/weaponselect/functions/fnc_selectWeaponMode.sqf b/addons/weaponselect/functions/fnc_selectWeaponMode.sqf index fd22bd4462..3a63e1097f 100644 --- a/addons/weaponselect/functions/fnc_selectWeaponMode.sqf +++ b/addons/weaponselect/functions/fnc_selectWeaponMode.sqf @@ -28,8 +28,8 @@ if (currentWeapon _unit != _weapon) exitWith { }; // Unlock safety -if (_weapon in (_unit getVariable [QEGVAR(safemode,safedWeapons), []])) exitWith { - [_unit, _weapon, _weapon] call EFUNC(safemode,unlockSafety); +if ((["ace_safemode"] call EFUNC(common,isModLoaded)) && {[_unit, _weapon] call EFUNC(safemode,getWeaponSafety)}) exitWith { + [_unit, _weapon, false] call EFUNC(safemode,setWeaponSafety); }; private _modes = _weapon call EFUNC(common,getWeaponModes); diff --git a/docs/wiki/framework/safemode-framework.md b/docs/wiki/framework/safemode-framework.md new file mode 100644 index 0000000000..540254fdfa --- /dev/null +++ b/docs/wiki/framework/safemode-framework.md @@ -0,0 +1,58 @@ +--- +layout: wiki +title: Safemode Framework +description: Explains how to use the weapon safety API. +group: framework +order: 5 +parent: wiki +mod: ace +version: + major: 3 + minor: 0 + patch: 0 +--- + +## 1. Scripting + +### 1.1 Setting weapon safety status + +`ace_safemode_fnc_setWeaponSafety` +If you want the state of the currently selected muzzle, either pass the muzzle by name or leave it blank (= `nil`). +If the unit doesn't have a weapon, its safety can't be locked, but it can be unlocked. + +```sqf + * Lock or unlock the given weapon based on weapon state. + * + * Arguments: + * 0: Unit + * 1: Weapon + * 2: State + * 3: Show hint (default: true) + * 4: Muzzle (default: current muzzle of weapon) + * + * Return Value: + * None + * + * Example: + * [ACE_player, currentWeapon ACE_player, true] call ace_safemode_fnc_setWeaponSafety +``` + +### 1.2 Getting weapon safety status + +`ace_safemode_fnc_getWeaponSafety` +If you want the state of the currently selected muzzle, either pass the muzzle by name or leave it blank (= `nil`). + +```sqf + * Getter for weapon safety state. + * + * Arguments: + * 0: Unit + * 1: Weapon + * 2: Muzzle (default: current muzzle of weapon) + * + * Return Value: + * Safety status + * + * Example: + * [ACE_player, currentWeapon ACE_player] call ace_safemode_fnc_getWeaponSafety +``` From 90d855c2c582c81b9ee03ad92b83c4283ab61280 Mon Sep 17 00:00:00 2001 From: Will/KJW <100206101+SpicyBagpipes@users.noreply.github.com> Date: Fri, 2 Aug 2024 13:52:44 +0100 Subject: [PATCH 173/290] Nightvision - Improve NVG Brightness adjustment limits (#10136) * Update fnc_changeNVGBrightness.sqf * Update XEH_postInit.sqf * Update addons/nightvision/XEH_postInit.sqf Co-authored-by: PabstMirror * Update XEH_postInit.sqf * Update fnc_changeNVGBrightness.sqf * Update nightvision-framework.md * load order independence Co-authored-by: PabstMirror --------- Co-authored-by: PabstMirror Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> --- addons/nightvision/XEH_postInit.sqf | 3 +++ addons/nightvision/functions/fnc_changeNVGBrightness.sqf | 2 +- docs/wiki/framework/nightvision-framework.md | 7 +++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/addons/nightvision/XEH_postInit.sqf b/addons/nightvision/XEH_postInit.sqf index 5a1aa19b82..2933877771 100644 --- a/addons/nightvision/XEH_postInit.sqf +++ b/addons/nightvision/XEH_postInit.sqf @@ -21,6 +21,9 @@ GVAR(ppeffectRadialBlur) = -1; GVAR(ppeffectColorCorrect) = -1; GVAR(ppeffectBlur) = -1; +if (isNil QGVAR(const_MaxBrightness)) then { GVAR(const_MaxBrightness) = 0; }; +if (isNil QGVAR(const_MinBrightness)) then { GVAR(const_MinBrightness) = -6; }; + GVAR(isUsingMagnification) = false; ["CBA_settingsInitialized", { diff --git a/addons/nightvision/functions/fnc_changeNVGBrightness.sqf b/addons/nightvision/functions/fnc_changeNVGBrightness.sqf index 1697fa907e..d0b210fe29 100644 --- a/addons/nightvision/functions/fnc_changeNVGBrightness.sqf +++ b/addons/nightvision/functions/fnc_changeNVGBrightness.sqf @@ -23,7 +23,7 @@ private _effectsEnabled = GVAR(effectScaling) != 0; private _defaultBrightness = [-3, 0] select _effectsEnabled; private _brightness = _player getVariable [QGVAR(NVGBrightness), _defaultBrightness]; -_brightness = ((_brightness + _changeInBrightness) min 0) max -6; +_brightness = ((_brightness + _changeInBrightness) min GVAR(const_MaxBrightness)) max GVAR(const_MinBrightness); _player setVariable [QGVAR(NVGBrightness), _brightness, false]; // Display default setting as 0 diff --git a/docs/wiki/framework/nightvision-framework.md b/docs/wiki/framework/nightvision-framework.md index 5f91421b8d..939398ee28 100644 --- a/docs/wiki/framework/nightvision-framework.md +++ b/docs/wiki/framework/nightvision-framework.md @@ -43,3 +43,10 @@ Additional color presets ```cpp ace_nightvision_colorPreset[] = {0.0, {0.0, 0.0, 0.0, 0.0}, {1.1, 0.8, 1.9, 0.9}, {1, 1, 6, 0.0}}; // White Phosphor Preset ``` + +## 3. Brightness Limits + +```cpp +ace_nightvision_const_maxBrightness = 0; // Defaults, change at your leisure +ace_nightvision_const_minBrightness = -6; +``` From 2db56cc4bb691f9eeaeb74945382cc58ca7db14c Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 3 Aug 2024 10:16:46 +0200 Subject: [PATCH 174/290] Advanced Ballistics/Field Rations - Notify restart requirement (#10161) Add notification for settings requiring restart --- addons/advanced_ballistics/initSettings.inc.sqf | 8 ++++++-- addons/field_rations/initSettings.inc.sqf | 6 +++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/addons/advanced_ballistics/initSettings.inc.sqf b/addons/advanced_ballistics/initSettings.inc.sqf index 957044f343..28a1d6d826 100644 --- a/addons/advanced_ballistics/initSettings.inc.sqf +++ b/addons/advanced_ballistics/initSettings.inc.sqf @@ -5,7 +5,9 @@ private _category = format ["ACE %1", localize LSTRING(DisplayName)]; [LSTRING(enabled_DisplayName), LSTRING(enabled_Description)], _category, false, - 1 + 1, + {[QGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart ] call CBA_fnc_addSetting; [ @@ -45,5 +47,7 @@ private _category = format ["ACE %1", localize LSTRING(DisplayName)]; [LSTRING(simulationInterval_DisplayName), LSTRING(simulationInterval_Description)], _category, [0, 0.2, 0.05, 2], - 1 + 1, + {[QGVAR(simulationInterval), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart ] call CBA_fnc_addSetting; diff --git a/addons/field_rations/initSettings.inc.sqf b/addons/field_rations/initSettings.inc.sqf index 86bf04aed2..16e2d4eb2d 100644 --- a/addons/field_rations/initSettings.inc.sqf +++ b/addons/field_rations/initSettings.inc.sqf @@ -4,9 +4,9 @@ [ELSTRING(common,Enabled), LSTRING(Enabled_Description)], LSTRING(DisplayName), false, - true, - {}, - true // Needs restart + 1, + {[QXGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart ] call CBA_fnc_addSetting; [ From c491b784686f00d02fc188300eabd519b8ce6962 Mon Sep 17 00:00:00 2001 From: amsteadrayle <2516219+amsteadrayle@users.noreply.github.com> Date: Mon, 5 Aug 2024 05:38:26 -0400 Subject: [PATCH 175/290] Recoil - Tweak launcher recoil to be more realistic (#9528) * First pass at RPG recoil tweaks * Crank up camera shake when using launcher --------- Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- addons/recoil/CfgRecoils.hpp | 13 +++++++------ addons/recoil/functions/fnc_camshake.sqf | 3 +++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/addons/recoil/CfgRecoils.hpp b/addons/recoil/CfgRecoils.hpp index 1c0751080c..b8d181e566 100644 --- a/addons/recoil/CfgRecoils.hpp +++ b/addons/recoil/CfgRecoils.hpp @@ -332,16 +332,17 @@ class CfgRecoils { class recoil_rpg: recoil_default { muzzleOuter[] = { - 2*MUZZLERIGHT_POS, - 3*MUZZLECLIMB_POS, - 1*MUZZLERIGHT_MAG, + 0.0*MUZZLERIGHT_POS, + 0.1*MUZZLECLIMB_POS, + 0.3*MUZZLERIGHT_MAG, 0.5*MUZZLECLIMB_MAG }; kickBack[] = { - 0.08*KICKBACK, - 0.1*KICKBACK + 0.0*KICKBACK, + 0.08*KICKBACK }; - temporary = 0.1*MUZZLETEMP; + permanent = 1.0*MUZZLEPERM; + temporary = 0.05*MUZZLETEMP; }; class recoil_nlaw: recoil_default { diff --git a/addons/recoil/functions/fnc_camshake.sqf b/addons/recoil/functions/fnc_camshake.sqf index 197d506bf5..9c6e78608f 100644 --- a/addons/recoil/functions/fnc_camshake.sqf +++ b/addons/recoil/functions/fnc_camshake.sqf @@ -61,6 +61,9 @@ private _powerCoef = RECOIL_COEF * linearConversion [0, 1, random 1, _recoil sel if (isWeaponRested _unit) then {_powerMod = _powerMod - 0.07}; if (isWeaponDeployed _unit) then {_powerMod = _powerMod - 0.11}; +if (_weapon isEqualTo secondaryWeapon _unit) then { + _powerCoef = _powerCoef + 25.0; +}; private _camshake = [ _powerCoef * (BASE_POWER + _powerMod) max 0, From 4226cd383e57c0fd8725df515787f57e8f93a140 Mon Sep 17 00:00:00 2001 From: Grim <69561145+LinkIsGrim@users.noreply.github.com> Date: Mon, 5 Aug 2024 06:38:46 -0300 Subject: [PATCH 176/290] Interact Menu - Add inheritance support to removeActionFromClass (#8396) * Add inheritance & exclusion support * Update documentation in wiki * additional check for parent class in findIf * forEach instead of count Co-authored-by: PabstMirror * condition for children of excluded classes * touch everything but the params check * apply configName in same line * fix param data type for _excludedClasses Co-authored-by: PabstMirror * Update addons/interact_menu/functions/fnc_removeActionFromClass.sqf Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * Fix & formatting * Fix missing _x & headers, remove invalid classes --------- Co-authored-by: Salluci <69561145+Salluci@users.noreply.github.com> Co-authored-by: PabstMirror Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- addons/interact_menu/XEH_preInit.sqf | 10 +++-- .../functions/fnc_addActionToClass.sqf | 33 +++++++++------ .../functions/fnc_removeActionFromClass.sqf | 40 +++++++++++++++++-- .../framework/interactionMenu-framework.md | 5 +++ 4 files changed, 69 insertions(+), 19 deletions(-) diff --git a/addons/interact_menu/XEH_preInit.sqf b/addons/interact_menu/XEH_preInit.sqf index 88269bcc04..a62996df68 100644 --- a/addons/interact_menu/XEH_preInit.sqf +++ b/addons/interact_menu/XEH_preInit.sqf @@ -88,8 +88,8 @@ GVAR(inheritedClassesMan) = []; if (GVAR(inheritedClassesAll) pushBackUnique _type == -1) exitWith { END_COUNTER(InitPost); }; { - _x params ["_objectType", "_typeNum", "_parentPath", "_action"]; - if (_object isKindOf _objectType) then { + _x params ["_objectType", "_typeNum", "_parentPath", "_action", "_excludedClasses"]; + if (_type isKindOf _objectType && {_excludedClasses findIf {_type isKindOf _x} == -1}) then { [_type, _typeNum, _parentPath, _action] call FUNC(addActionToClass); }; } forEach GVAR(inheritedActionsAll); @@ -102,8 +102,10 @@ GVAR(inheritedClassesMan) = []; if (GVAR(inheritedClassesMan) pushBackUnique _type == -1) exitWith { END_COUNTER(InitPost); }; { - _x params ["_typeNum", "_parentPath", "_action"]; - [_type, _typeNum, _parentPath, _action] call FUNC(addActionToClass); + _x params ["_typeNum", "_parentPath", "_action", "_excludedClasses"]; + if (_excludedClasses findIf {_type isKindOf _x} == -1) then { // skip excluded classes and children + [_type, _typeNum, _parentPath, _action] call FUNC(addActionToClass); + }; } forEach GVAR(inheritedActionsMan); END_COUNTER(InitPost); }, true, ["VirtualMan_F"]] call CBA_fnc_addClassEventHandler; diff --git a/addons/interact_menu/functions/fnc_addActionToClass.sqf b/addons/interact_menu/functions/fnc_addActionToClass.sqf index ccea8c4654..91197d02d9 100644 --- a/addons/interact_menu/functions/fnc_addActionToClass.sqf +++ b/addons/interact_menu/functions/fnc_addActionToClass.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: esteldunedain - * Insert an ACE action to a class, under a certain path + * Inserts an ACE action to a class, under a certain path. * Note: This function is NOT global. * * Arguments: @@ -10,12 +10,13 @@ * 2: Parent path of the new action * 3: Action * 4: Use Inheritance (default: false) + * 5: Classes excluded from inheritance (children included) (default: []) * * Return Value: * The entry full path, which can be used to remove the entry, or add children entries . * * Example: - * [typeOf cursorTarget, 0, ["ACE_TapShoulderRight"],VulcanPinchAction] call ace_interact_menu_fnc_addActionToClass; + * [typeOf cursorTarget, 0, ["ACE_TapShoulderRight"], VulcanPinchAction] call ace_interact_menu_fnc_addActionToClass; * * Public: Yes */ @@ -25,22 +26,30 @@ if (!params [["_objectType", "", [""]], ["_typeNum", 0, [0]], ["_parentPath", [] ERROR("Bad Params"); [] }; -TRACE_4("addActionToClass",_objectType,_typeNum,_parentPath,_action); +private _useInheritance = _this param [4, false, [false]]; +private _excludedClasses = _this param [5, [], [[]]]; +TRACE_6("addActionToClass",_objectType,_typeNum,_parentPath,_action,_useInheritance,_excludedClasses); -if (param [4, false, [false]]) exitwith { +if (_useInheritance) exitwith { BEGIN_COUNTER(addAction); + private _cfgVehicles = configFile >> "CfgVehicles"; // store this so we don't resolve for every element + _excludedClasses = (_excludedClasses apply {configName (_cfgVehicles >> _x)}) - [""]; // ends up being faster than toLower'ing everything else if (_objectType == "CAManBase") then { - GVAR(inheritedActionsMan) pushBack [_typeNum, _parentPath, _action]; + GVAR(inheritedActionsMan) pushBack [_typeNum, _parentPath, _action, _excludedClasses]; { - [_x, _typeNum, _parentPath, _action] call FUNC(addActionToClass); - } forEach GVAR(inheritedClassesMan); - } else { - GVAR(inheritedActionsAll) pushBack [_objectType, _typeNum, _parentPath, _action]; - { - if (_x isKindOf _objectType) then { + private _type = _x; + if (_excludedClasses findIf {_type isKindOf _x} == -1) then { // skip excluded classes and children [_x, _typeNum, _parentPath, _action] call FUNC(addActionToClass); }; - } forEach GVAR(inheritedClassesAll); + } forEach (GVAR(inheritedClassesMan) - _excludedClasses); + } else { + GVAR(inheritedActionsAll) pushBack [_objectType, _typeNum, _parentPath, _action, _excludedClasses]; + { + private _type = _x; + if (_type isKindOf _objectType && {_excludedClasses findIf {_type isKindOf _x} == -1}) then { + [_type, _typeNum, _parentPath, _action] call FUNC(addActionToClass); + }; + } forEach (GVAR(inheritedClassesAll) - _excludedClasses); }; END_COUNTER(addAction); diff --git a/addons/interact_menu/functions/fnc_removeActionFromClass.sqf b/addons/interact_menu/functions/fnc_removeActionFromClass.sqf index 7585616ef6..87cc8609cc 100644 --- a/addons/interact_menu/functions/fnc_removeActionFromClass.sqf +++ b/addons/interact_menu/functions/fnc_removeActionFromClass.sqf @@ -1,29 +1,63 @@ #include "..\script_component.hpp" /* * Author: esteldunedain - * Removes an action from a class + * Removes an action from a class. * * Arguments: * 0: TypeOf of the class * 1: Type of action, 0 for actions, 1 for self-actions * 2: Full path of the new action + * 3: Remove action from child classes (default: false) * * Return Value: * None * * Example: - * [typeOf cursorTarget, 0,["ACE_TapShoulderRight","VulcanPinch"]] call ace_interact_menu_fnc_removeActionFromClass; + * [typeOf cursorTarget, 0, ["ACE_TapShoulderRight", "VulcanPinch"]] call ace_interact_menu_fnc_removeActionFromClass; * * Public: No */ -params ["_objectType", "_typeNum", "_fullPath"]; +params ["_objectType", "_typeNum", "_fullPath", ["_useInheritance", false, [false]]]; _objectType = _objectType call EFUNC(common,getConfigName); private _res = _fullPath call FUNC(splitPath); _res params ["_parentPath", "_actionName"]; +if (_useInheritance) exitWith { + // Only need to run for classes that have already been initialized + { + [_x, _typeNum, _fullPath] call FUNC(removeActionFromClass); + } forEach (GVAR(inheritedClassesAll) select {_x isKindOf _objectType}); + + // Find same path and actionName, and check if it's a parent class, needs to be checked for all classes + private _index = GVAR(inheritedActionsAll) findIf { + _x params ["_currentType", "", "_currentParentPath", "_currentAction"]; + + [_objectType isKindOf _currentType, _currentParentPath, _currentAction select 0] isEqualTo [true, _parentPath, _actionName] + }; + + // Add to exclude classes + if (_index != -1) then { + (GVAR(inheritedActionsAll) select _index select 4) pushBackUnique _objectType; + }; + + // Children of CAManBase need special treatment because of inheritedActionsMan array + if (_objectType isKindOf "CAManBase") then { + private _index = GVAR(inheritedActionsMan) findIf { + _x params ["", "_currentParentPath", "_currentAction"]; + + [_currentParentPath, _currentAction select 0] isEqualTo [_parentPath, _actionName] + }; + + // Different index because array doesn't include _objectType + if (_index != -1) then { + (GVAR(inheritedActionsMan) select _index select 3) pushBackUnique _objectType; + }; + }; +}; + private _namespace = [GVAR(ActNamespace), GVAR(ActSelfNamespace)] select _typeNum; private _actionTrees = _namespace getOrDefault [_objectType, []]; diff --git a/docs/wiki/framework/interactionMenu-framework.md b/docs/wiki/framework/interactionMenu-framework.md index fb66fb3918..18d5aec70f 100644 --- a/docs/wiki/framework/interactionMenu-framework.md +++ b/docs/wiki/framework/interactionMenu-framework.md @@ -110,6 +110,7 @@ Important: `ace_common_fnc_canInteractWith` is not automatically checked and nee * 2: Parent path of the new action * 3: Action * 4: Use Inheritance (Default: False) + * 5: Classes excluded from inheritance (children included) (Default: []) */ ``` By default this function will not use inheritance, so actions will only be added to the specific class. @@ -169,6 +170,10 @@ Using `addActionToClass` inheritance: _action = ["CheckFuel", "Check Fuel", "", {hint format ["Fuel: %1", fuel _target]}, {true}] call ace_interact_menu_fnc_createAction; ["LandVehicle", 0, ["ACE_MainActions"], _action, true] call ace_interact_menu_fnc_addActionToClass; +// Same as above, but children of "MRAP_01_Base" will not have the action +_action = ["CheckFuel", "Check Fuel", "", {hint format ["Fuel: %1", fuel _target]}, {true}] call ace_interact_menu_fnc_createAction; +["LandVehicle", 0, ["ACE_MainActions"], _action, true, ["MRAP_01_Base"]] call ace_interact_menu_fnc_addActionToClass; + // Adds action to check external fuel levels on tanks. Will be a sub action of the previous action. _action = ["CheckExtTank","Check External Tank","",{hint format ["Ext Tank: %1", 5]},{true}] call ace_interact_menu_fnc_createAction; ["Tank_F", 0, ["ACE_MainActions", "CheckFuel"], _action, true] call ace_interact_menu_fnc_addActionToClass; From cd678c5b90bfb0fc997f2ee798c55dffd2c0801b Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 5 Aug 2024 11:39:01 +0200 Subject: [PATCH 177/290] Medical AI - Add tourniquet support (#10158) Add tourniquet support for Medical AI --- addons/medical_ai/XEH_preStart.sqf | 1 + addons/medical_ai/functions/fnc_healUnit.sqf | 4 + .../medical_ai/functions/fnc_healingLogic.sqf | 238 +++++++++++++----- .../functions/fnc_tourniquetRemove.sqf | 15 +- 4 files changed, 196 insertions(+), 62 deletions(-) diff --git a/addons/medical_ai/XEH_preStart.sqf b/addons/medical_ai/XEH_preStart.sqf index b4d795cbbf..ccb92538b7 100644 --- a/addons/medical_ai/XEH_preStart.sqf +++ b/addons/medical_ai/XEH_preStart.sqf @@ -20,6 +20,7 @@ private _itemHash = createHashMap; } forEach [ ["@bandage", ["FieldDressing", "PackingBandage", "ElasticBandage", "QuikClot"]], ["@iv", ["SalineIV", "SalineIV_500", "SalineIV_250", "BloodIV", "BloodIV_500", "BloodIV_250", "PlasmaIV", "PlasmaIV_500", "PlasmaIV_250"]], + ["tourniquet", ["ApplyTourniquet"]], ["splint", ["splint"]], ["morphine", ["morphine"]], ["epinephrine", ["epinephrine"]] diff --git a/addons/medical_ai/functions/fnc_healUnit.sqf b/addons/medical_ai/functions/fnc_healUnit.sqf index 3635088820..319d5533b1 100644 --- a/addons/medical_ai/functions/fnc_healUnit.sqf +++ b/addons/medical_ai/functions/fnc_healUnit.sqf @@ -47,6 +47,10 @@ if (_this distance _target > 2.5) exitWith { _this setVariable [QGVAR(currentTreatment), nil]; if (CBA_missionTime >= (_this getVariable [QGVAR(nextMoveOrder), CBA_missionTime])) then { _this setVariable [QGVAR(nextMoveOrder), CBA_missionTime + 10]; + + // Medic, when doing a lot of treatment, moves away from injured over time (because of animations) + // Need to allow the medic to move back to the injured again + _this forceSpeed -1; _this doMove getPosATL _target; #ifdef DEBUG_MODE_FULL systemChat format ["%1 moving to %2", _this, _target]; diff --git a/addons/medical_ai/functions/fnc_healingLogic.sqf b/addons/medical_ai/functions/fnc_healingLogic.sqf index 213d763b97..c9fe046ef8 100644 --- a/addons/medical_ai/functions/fnc_healingLogic.sqf +++ b/addons/medical_ai/functions/fnc_healingLogic.sqf @@ -27,13 +27,28 @@ if (_finishTime > 0) exitWith { if (CBA_missionTime >= _finishTime) then { TRACE_5("treatment finished",_finishTime,_treatmentTarget,_treatmentEvent,_treatmentArgs,_treatmentItem); _healer setVariable [QGVAR(currentTreatment), nil]; + + private _usedItem = ""; + if ((GVAR(requireItems) > 0) && {_treatmentItem != ""}) then { ([_healer, _treatmentItem] call FUNC(itemCheck)) params ["_itemOk", "_itemClassname", "_treatmentClass"]; - if (!_itemOk) exitWith { _treatmentEvent = "#fail"; }; // no item after delay - _healer removeItem _itemClassname; - if (_treatmentClass != "") then { _treatmentArgs set [2, _treatmentClass]; }; + // No item after treatment done + if (!_itemOk) exitWith { + _treatmentEvent = "#fail"; + }; + + if (_treatmentClass != "") then { + _healer removeItem _itemClassname; + _usedItem = _itemClassname; + _treatmentArgs set [2, _treatmentClass]; + }; }; if ((_treatmentTarget == _target) && {(_treatmentEvent select [0, 1]) != "#"}) then { + // There is no event for tourniquet removal, so handle calling function directly + if (_treatmentEvent == QGVAR(tourniquetRemove)) exitWith { + _treatmentArgs call EFUNC(medical_treatment,tourniquetRemove); + }; + [_treatmentEvent, _treatmentArgs, _target] call CBA_fnc_targetEvent; // Splints are already logged on their own @@ -42,14 +57,25 @@ if (_finishTime > 0) exitWith { [_target, "activity", ELSTRING(medical_treatment,Activity_bandagedPatient), [[_healer, false, true] call EFUNC(common,getName)]] call EFUNC(medical_treatment,addToLog); }; case QEGVAR(medical_treatment,ivBagLocal): { - [_target, _treatmentArgs select 2] call EFUNC(medical_treatment,addToTriageCard); + if (_usedItem == "") then { + _usedItem = "ACE_salineIV"; + }; + + [_target, _usedItem] call EFUNC(medical_treatment,addToTriageCard); [_target, "activity", ELSTRING(medical_treatment,Activity_gaveIV), [[_healer, false, true] call EFUNC(common,getName)]] call EFUNC(medical_treatment,addToLog); }; case QEGVAR(medical_treatment,medicationLocal): { - private _usedItem = ["ACE_epinephrine", "ACE_morphine"] select (_treatmentArgs select 2 == "Morphine"); + if (_usedItem == "") then { + _usedItem = ["ACE_epinephrine", "ACE_morphine"] select (_treatmentArgs select 2 == "Morphine"); + }; + [_target, _usedItem] call EFUNC(medical_treatment,addToTriageCard); [_target, "activity", ELSTRING(medical_treatment,Activity_usedItem), [[_healer, false, true] call EFUNC(common,getName), getText (configFile >> "CfgWeapons" >> _usedItem >> "displayName")]] call EFUNC(medical_treatment,addToLog); }; + case QEGVAR(medical_treatment,tourniquetLocal): { + [_target, "ACE_tourniquet"] call EFUNC(medical_treatment,addToTriageCard); + [_target, "activity", ELSTRING(medical_treatment,Activity_appliedTourniquet), [[_healer, false, true] call EFUNC(common,getName)]] call EFUNC(medical_treatment,addToLog); + }; }; #ifdef DEBUG_MODE_FULL @@ -63,29 +89,61 @@ if (_finishTime > 0) exitWith { // Find a suitable limb (no tourniquets) for injecting and giving IVs private _fnc_findNoTourniquet = { private _bodyPart = ""; - private _bodyParts = ["leftarm", "rightarm", "leftleg", "rightleg"]; - private _bodyPartsSaved = +_bodyParts; - while {_bodyParts isNotEqualTo []} do { - _bodyPart = selectRandom _bodyParts; + // If all limbs have tourniquets, find the least damaged limb and try to bandage it + if ((_tourniquets select [2]) find 0 == -1) then { + // If no bandages available, wait + if !(([_healer, "@bandage"] call FUNC(itemCheck)) # 0) exitWith { + _treatmentEvent = "#waitForNonTourniquetedLimb"; // TODO: Medic can move onto another patient/should be flagged as out of supplies + }; - // If no tourniquet on, use that body part - if (_tourniquets select (ALL_BODY_PARTS find _bodyPart) == 0) exitWith {}; + // Bandage the least bleeding body part + private _bodyPartBleeding = [0, 0, 0, 0]; - _bodyParts deleteAt (_bodyParts find _bodyPart); + { + // Ignore head and torso + private _partIndex = (ALL_BODY_PARTS find _x) - 2; + + if (_partIndex >= 0) then { + { + _x params ["", "_amountOf", "_bleeding"]; + _bodyPartBleeding set [_partIndex, (_bodyPartBleeding select _partIndex) + (_amountOf * _bleeding)]; + } forEach _y; + }; + } forEach GET_OPEN_WOUNDS(_target); + + private _minBodyPartBleeding = selectMin _bodyPartBleeding; + private _selection = ALL_BODY_PARTS select ((_bodyPartBleeding find _minBodyPartBleeding) + 2); + + // If not bleeding anymore, remove the tourniquet + if (_minBodyPartBleeding == 0) exitWith { + _treatmentEvent = QGVAR(tourniquetRemove); + _treatmentTime = 7; + _treatmentArgs = [_healer, _target, _selection]; + }; + + // Otherwise keep bandaging + _treatmentEvent = QEGVAR(medical_treatment,bandageLocal); + _treatmentTime = 5; + _treatmentArgs = [_target, _selection, "FieldDressing"]; + _treatmentItem = "@bandage"; + } else { + // Select a random non-tourniqueted limb otherwise + private _bodyParts = ["leftarm", "rightarm", "leftleg", "rightleg"]; + + while {_bodyParts isNotEqualTo []} do { + _bodyPart = selectRandom _bodyParts; + + // If no tourniquet on, use that body part + if (_tourniquets select (ALL_BODY_PARTS find _bodyPart) == 0) exitWith {}; + + _bodyParts deleteAt (_bodyParts find _bodyPart); + }; }; - // If all limbs have tourniquets, use random limb - if (_bodyPart == "") then { - _bodyPart = selectRandom _bodyPartsSaved; - }; - - _bodyPart + _bodyPart // return }; -private _isMedic = [_healer] call EFUNC(medical_treatment,isMedic); -private _heartRate = GET_HEART_RATE(_target); -private _fractures = GET_FRACTURES(_target); private _tourniquets = GET_TOURNIQUETS(_target); private _treatmentEvent = "#none"; @@ -94,46 +152,77 @@ private _treatmentTime = 6; private _treatmentItem = ""; if (true) then { - if ( - (GET_WOUND_BLEEDING(_target) > 0) && - {([_healer, "@bandage"] call FUNC(itemCheck)) # 0} - ) exitWith { - // Select first bleeding wound and bandage it - private _selection = "?"; + if (IS_BLEEDING(_target)) exitWith { + private _hasBandage = ([_healer, "@bandage"] call FUNC(itemCheck)) # 0; + private _hasTourniquet = ([_healer, "tourniquet"] call FUNC(itemCheck)) # 0; + + // Patient is not worth treating if bloodloss can't be stopped + if !(_hasBandage || _hasTourniquet) exitWith { + _treatmentEvent = "#cantStabilise"; // TODO: Medic should be flagged as out of supplies + }; + + // Bandage the heaviest bleeding body part + private _bodyPartBleeding = [0, 0, 0, 0, 0, 0]; + { + private _partIndex = ALL_BODY_PARTS find _x; + // Ignore tourniqueted limbs - if (_tourniquets select (ALL_BODY_PARTS find _x) == 0 && { - _y findIf { - _x params ["", "_amount", "_percentage"]; - (_amount * _percentage) > 0 - } != -1} - ) exitWith { _selection = _x; }; + if (_tourniquets select _partIndex == 0) then { + { + _x params ["", "_amountOf", "_bleeding"]; + _bodyPartBleeding set [_partIndex, (_bodyPartBleeding select _partIndex) + (_amountOf * _bleeding)]; + } forEach _y; + }; } forEach GET_OPEN_WOUNDS(_target); + + private _maxBodyPartBleeding = selectMax _bodyPartBleeding; + private _bodyPartIndex = _bodyPartBleeding find _maxBodyPartBleeding; + private _selection = ALL_BODY_PARTS select _bodyPartIndex; + + // Apply tourniquet if moderate bleeding or no bandage is available, and if not head and torso + if (_hasTourniquet && {_bodyPartIndex > HITPOINT_INDEX_BODY} && {!_hasBandage || {_maxBodyPartBleeding > 0.3}}) exitWith { + _treatmentEvent = QEGVAR(medical_treatment,tourniquetLocal); + _treatmentTime = 7; + _treatmentArgs = [_target, _selection]; + _treatmentItem = "tourniquet"; + }; + _treatmentEvent = QEGVAR(medical_treatment,bandageLocal); _treatmentTime = 5; _treatmentArgs = [_target, _selection, "FieldDressing"]; _treatmentItem = "@bandage"; }; - private _hasIV = ([_healer, "@iv"] call FUNC(itemCheck)) # 0; private _bloodVolume = GET_BLOOD_VOLUME(_target); + private _needsIV = _bloodVolume < MINIMUM_BLOOD_FOR_STABLE_VITALS; + private _canGiveIV = _needsIV && + {_healer call EFUNC(medical_treatment,isMedic)} && + {([_healer, "@iv"] call FUNC(itemCheck)) # 0}; // Has IVs + private _doCPR = IN_CRDC_ARRST(_target) && {EGVAR(medical_treatment,cprSuccessChanceMin) > 0}; // If in cardiac arrest, first add some blood to injured if necessary, then do CPR (doing CPR when not enough blood is suboptimal if you have IVs) // If healer has no IVs, allow AI to do CPR to keep injured alive if ( - IN_CRDC_ARRST(_target) && - {EGVAR(medical_treatment,cprSuccessChanceMin) > 0} && - {!_hasIV || {_bloodVolume >= BLOOD_VOLUME_CLASS_3_HEMORRHAGE}} + _doCPR && + {!_canGiveIV || {_bloodVolume >= BLOOD_VOLUME_CLASS_3_HEMORRHAGE}} ) exitWith { _treatmentEvent = QEGVAR(medical_treatment,cprLocal); _treatmentArgs = [_healer, _target]; _treatmentTime = 15; }; - private _needsIv = _bloodVolume < MINIMUM_BLOOD_FOR_STABLE_VITALS; - private _canGiveIv = _isMedic && _hasIV && _needsIv; + private _bodypart = ""; - if (_canGiveIv) then { + if ( + _canGiveIV && { + // If all limbs are tourniqueted, bandage the one with the least amount of wounds, so that the tourniquet can be removed + _bodyPart = call _fnc_findNoTourniquet; + _bodyPart == "" + } + ) exitWith {}; + + if (_canGiveIV) then { // Check if patient's blood volume + remaining IV volume is enough to allow the patient to wake up private _totalIvVolume = 0; //in ml { @@ -144,17 +233,20 @@ if (true) then { // Check if the medic has to wait, which allows for a little multitasking if (_bloodVolume + (_totalIvVolume / 1000) >= MINIMUM_BLOOD_FOR_STABLE_VITALS) then { _treatmentEvent = "#waitForIV"; - _canGiveIv = false; + _needsIV = false; + _canGiveIV = false; }; }; - if (_canGiveIv) exitWith { + if (_canGiveIV) exitWith { _treatmentEvent = QEGVAR(medical_treatment,ivBagLocal); _treatmentTime = 5; - _treatmentArgs = [_target, call _fnc_findNoTourniquet, "SalineIV"]; + _treatmentArgs = [_target, _bodyPart, "SalineIV"]; _treatmentItem = "@iv"; }; + private _fractures = GET_FRACTURES(_target); + if ( ((_fractures select 4) == 1) && {([_healer, "splint"] call FUNC(itemCheck)) # 0} @@ -176,47 +268,70 @@ if (true) then { }; // Wait until the injured has enough blood before administering drugs - if (_needsIv) then { - _treatmentEvent = "#waitForIV" - }; + // (_needsIV && !_canGiveIV), but _canGiveIV is false here, otherwise IV would be given + if (_needsIV || {_treatmentEvent == "#waitForIV"}) exitWith { + // If injured is in cardiac arrest and the healer is doing nothing else, start CPR + if (_doCPR) exitWith { + _treatmentEvent = QEGVAR(medical_treatment,cprLocal); // TODO: Medic remains in this loop until injured is given enough IVs or dies + _treatmentArgs = [_healer, _target]; + _treatmentTime = 15; + }; - if (_treatmentEvent == "#waitForIV") exitWith {}; + // If the injured needs IVs, but healer can't give it to them, have healder wait + if (_needsIV) exitWith { + _treatmentEvent = "#needsIV"; // TODO: Medic can move onto another patient + }; + }; if ((count (_target getVariable [VAR_MEDICATIONS, []])) >= 6) exitWith { - _treatmentEvent = "#tooManyMeds"; + _treatmentEvent = "#tooManyMeds"; // TODO: Medic can move onto another patient }; + private _heartRate = GET_HEART_RATE(_target); + if ( - ((IS_UNCONSCIOUS(_target) && {_heartRate < 160}) || {_heartRate <= 50}) && + (IS_UNCONSCIOUS(_target) || {_heartRate <= 50}) && {([_healer, "epinephrine"] call FUNC(itemCheck)) # 0} ) exitWith { if (CBA_missionTime < (_target getVariable [QGVAR(nextEpinephrine), -1])) exitWith { _treatmentEvent = "#waitForEpinephrineToTakeEffect"; }; if (_heartRate > 180) exitWith { - _treatmentEvent = "#waitForSlowerHeart"; + _treatmentEvent = "#waitForSlowerHeart"; // TODO: Medic can move onto another patient, after X amount of time of high HR }; + + // If all limbs are tourniqueted, bandage the one with the least amount of wounds, so that the tourniquet can be removed + _bodyPart = call _fnc_findNoTourniquet; + + if (_bodyPart == "") exitWith {}; + _target setVariable [QGVAR(nextEpinephrine), CBA_missionTime + 10]; _treatmentEvent = QEGVAR(medical_treatment,medicationLocal); _treatmentTime = 2.5; - _treatmentArgs = [_target, call _fnc_findNoTourniquet, "Epinephrine"]; + _treatmentArgs = [_target, _bodyPart, "Epinephrine"]; _treatmentItem = "epinephrine"; }; if ( - (((GET_PAIN_PERCEIVED(_target) > 0.25) && {_heartRate > 40}) || {_heartRate >= 180}) && + ((GET_PAIN_PERCEIVED(_target) > 0.25) || {_heartRate >= 180}) && {([_healer, "morphine"] call FUNC(itemCheck)) # 0} ) exitWith { if (CBA_missionTime < (_target getVariable [QGVAR(nextMorphine), -1])) exitWith { _treatmentEvent = "#waitForMorphineToTakeEffect"; }; if (_heartRate < 60) exitWith { - _treatmentEvent = "#waitForFasterHeart"; + _treatmentEvent = "#waitForFasterHeart"; // TODO: Medic can move onto another patient, after X amount of time of low HR }; + + // If all limbs are tourniqueted, bandage the one with the least amount of wounds, so that the tourniquet can be removed + _bodyPart = call _fnc_findNoTourniquet; + + if (_bodyPart == "") exitWith {}; + _target setVariable [QGVAR(nextMorphine), CBA_missionTime + 30]; _treatmentEvent = QEGVAR(medical_treatment,medicationLocal); _treatmentTime = 2.5; - _treatmentArgs = [_target, call _fnc_findNoTourniquet, "Morphine"]; + _treatmentArgs = [_target, _bodyPart, "Morphine"]; _treatmentItem = "morphine"; }; }; @@ -224,11 +339,16 @@ if (true) then { _healer setVariable [QGVAR(currentTreatment), [CBA_missionTime + _treatmentTime, _target, _treatmentEvent, _treatmentArgs, _treatmentItem]]; // Play animation -if ((_treatmentEvent select [0,1]) != "#") then { - private _treatmentClassname = _treatmentArgs select 2; - if (_treatmentEvent == QEGVAR(medical_treatment,splintLocal)) then { _treatmentClassname = "Splint" }; - if (_treatmentEvent == QEGVAR(medical_treatment,cprLocal)) then { _treatmentClassname = "CPR" }; - [_healer, _treatmentClassname, (_healer == _target)] call FUNC(playTreatmentAnim); +if ((_treatmentEvent select [0, 1]) != "#") then { + private _treatmentClassname = switch (_treatmentEvent) do { + case QEGVAR(medical_treatment,splintLocal): {"Splint"}; + case QEGVAR(medical_treatment,cprLocal): {"CPR"}; + case QEGVAR(medical_treatment,tourniquetLocal): {"ApplyTourniquet"}; + case QGVAR(tourniquetRemove): {"RemoveTourniquet"}; + default {_treatmentArgs select 2}; + }; + + [_healer, _treatmentClassname, _healer == _target] call FUNC(playTreatmentAnim); }; #ifdef DEBUG_MODE_FULL diff --git a/addons/medical_treatment/functions/fnc_tourniquetRemove.sqf b/addons/medical_treatment/functions/fnc_tourniquetRemove.sqf index 8a6be10bb4..97680353e4 100644 --- a/addons/medical_treatment/functions/fnc_tourniquetRemove.sqf +++ b/addons/medical_treatment/functions/fnc_tourniquetRemove.sqf @@ -26,7 +26,9 @@ private _partIndex = ALL_BODY_PARTS find tolowerANSI _bodyPart; private _tourniquets = GET_TOURNIQUETS(_patient); if (_tourniquets select _partIndex == 0) exitWith { - [LSTRING(noTourniquetOnBodyPart), 1.5] call EFUNC(common,displayTextStructured); + if (_medic == ACE_player) then { + [LSTRING(noTourniquetOnBodyPart), 1.5] call EFUNC(common,displayTextStructured); + }; }; _tourniquets set [_partIndex, 0]; @@ -39,8 +41,15 @@ TRACE_1("clearConditionCaches: tourniquetRemove",_nearPlayers); [QEGVAR(interact_menu,clearConditionCaches), [], _nearPlayers] call CBA_fnc_targetEvent; // Add tourniquet item to medic or patient -private _receiver = [_patient, _medic, _medic] select GVAR(allowSharedEquipment); -[_receiver, "ACE_tourniquet"] call EFUNC(common,addToInventory); +if (_medic call EFUNC(common,isPlayer)) then { + private _receiver = [_patient, _medic, _medic] select GVAR(allowSharedEquipment); + [_receiver, "ACE_tourniquet"] call EFUNC(common,addToInventory); +} else { + // If the medic is AI, only return tourniquet if enabled + if (missionNamespace getVariable [QEGVAR(medical_ai,requireItems), 0] > 0) then { + [_medic, "ACE_tourniquet"] call EFUNC(common,addToInventory); + }; +}; // Handle occluded medications that were blocked due to tourniquet private _occludedMedications = _patient getVariable [QEGVAR(medical,occludedMedications), []]; From c31ef9e16b7e6f7122ea9535498d5c374d9929f0 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 5 Aug 2024 11:39:35 +0200 Subject: [PATCH 178/290] Medical AI - Add command actions to heal injured units (#10164) * Add AI command menu for healing * Moved actions to separate function * Minor cleanup --- addons/medical_ai/XEH_PREP.hpp | 1 + addons/medical_ai/XEH_postInit.sqf | 3 + .../fnc_addHealingCommandActions.sqf | 88 +++++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 addons/medical_ai/functions/fnc_addHealingCommandActions.sqf diff --git a/addons/medical_ai/XEH_PREP.hpp b/addons/medical_ai/XEH_PREP.hpp index de4ac3c38a..3cf2b3e244 100644 --- a/addons/medical_ai/XEH_PREP.hpp +++ b/addons/medical_ai/XEH_PREP.hpp @@ -1,3 +1,4 @@ +PREP(addHealingCommandActions); PREP(canRequestMedic); PREP(healingLogic); PREP(healSelf); diff --git a/addons/medical_ai/XEH_postInit.sqf b/addons/medical_ai/XEH_postInit.sqf index 248c634156..9ddd8273fd 100644 --- a/addons/medical_ai/XEH_postInit.sqf +++ b/addons/medical_ai/XEH_postInit.sqf @@ -20,6 +20,9 @@ _unit setVariable [QGVAR(lastSuppressed), CBA_missionTime]; }] call CBA_fnc_addClassEventHandler; + // Add command actions to command AI medics to treat other units + call FUNC(addHealingCommandActions); + if (GVAR(requireItems) == 2) then { ["CAManBase", "InitPost", { [{ diff --git a/addons/medical_ai/functions/fnc_addHealingCommandActions.sqf b/addons/medical_ai/functions/fnc_addHealingCommandActions.sqf new file mode 100644 index 0000000000..cc91ca7eb3 --- /dev/null +++ b/addons/medical_ai/functions/fnc_addHealingCommandActions.sqf @@ -0,0 +1,88 @@ +#include "..\script_component.hpp" +/* + * Author: johnb43 + * Adds ACE actions for the player to command medics to heal injured units. + * + * Arguments: + * None + * + * Return Value: + * None + * + * Example: + * call ace_medical_ai_fnc_addHealingCommandActions + * + * Public: No + */ + +if (!hasInterface) exitWith {}; + +private _action = [ + QGVAR(heal), + localize "STR_A3_Task180_name", + "", + {}, + {_player == leader _player}, + { + private _units = units _player; + + (_units select {_x call EFUNC(common,isAwake) && {_x call EFUNC(medical_treatment,isMedic)} && {!(_x call EFUNC(common,isPlayer))}}) apply { + [ + [ + QGVAR(medicHeal_) + str _x, + format ["%1: (%2)", [_x, false, true] call EFUNC(common,getName), groupID _x], + "", + {}, + {true}, + { + (_this select 2) params ["_healer", "_units"]; + + (_units select {_x call FUNC(isInjured)}) apply { + [ + [ + QGVAR(healUnit_) + str _x, + format [localize "str_action_heal_soldier", ([_x, false, true] call EFUNC(common,getName)) + " (" + str groupID _x + ")"], + "", + { + (_this select 2) params ["_healer", "_target"]; + + private _assignedMedic = _target getVariable [QGVAR(assignedMedic), objNull]; + + // Remove from previous medic's queue + if (!isNull _assignedMedic && {_healer != _assignedMedic}) then { + private _healQueue = _assignedMedic getVariable [QGVAR(healQueue), []]; + + _healQueue deleteAt (_healQueue find _target); + + _assignedMedic setVariable [QGVAR(healQueue), _healQueue]; + }; + + _target setVariable [QGVAR(assignedMedic), _healer]; + + // Add to new medic + private _healQueue = _healer getVariable [QGVAR(healQueue), []]; + + _healQueue deleteAt (_healQueue find _target); + _healQueue insert [0, [_target]]; + + _healer setVariable [QGVAR(healQueue), _healQueue]; + }, + {true}, + {}, + [_healer, _x] + ] call EFUNC(interact_menu,createAction), + [], + _x + ] + }; + }, + [_x, _units] + ] call EFUNC(interact_menu,createAction), + [], + _x + ] + }; + } +] call EFUNC(interact_menu,createAction); + +["CAManBase", 1, ["ACE_SelfActions"], _action, true] call EFUNC(interact_menu,addActionToClass); From f4f2dbaad9d1af8ed5d91bfb1b01fec4bdc97205 Mon Sep 17 00:00:00 2001 From: Fabio Schick <58027418+mrschick@users.noreply.github.com> Date: Tue, 6 Aug 2024 00:33:00 +0200 Subject: [PATCH 179/290] Docs - Add missing info to Interaction Menu Framework (#10160) * Interaction Exceptions * Additional Action Parameters --- .../framework/interactionMenu-framework.md | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/wiki/framework/interactionMenu-framework.md b/docs/wiki/framework/interactionMenu-framework.md index 18d5aec70f..ce8bfd87b8 100644 --- a/docs/wiki/framework/interactionMenu-framework.md +++ b/docs/wiki/framework/interactionMenu-framework.md @@ -59,6 +59,10 @@ class CfgVehicles { | `distance` | Number | External Base Actions Only, Max distance player can be from action point | | `position` | String (of code) | External Base Actions Only, Code to return a position in model cords (priority over `selection`) | | `selection` | String | External Base Actions Only, A memory point for `selectionPosition` | +| `doNotCheckLOS` | Number | (1=true) - Ignores blocked LOS to the interaction node even when beyond 1.2m | +| `showDisabled` | Number | Currently has no effect | +| `enableInside` | Number | Currently has no effect | +| `canCollapse` | Number | Currently has no effect | Actions can be inserted anywhere on the config tree, e.g. hearing's earplugs is a sub action of `ACE_Equipment`: @@ -72,6 +76,25 @@ class CAManBase: Man { }; ``` +Interaction exceptions are defined by several components: + +| Component | Exception | Description | +| ---------- | ----------- | ------------------- | +| `captives` | `"isNotEscorting"` | Can interact while escorting a captive | +| | `"isNotHandcuffed"` | Can interact while handcuffed | +| | `"isNotSurrendering"` | Can interact while surrendering | +| `common` | `"isNotDead"` | Can interact while dead | +| | `"notOnMap"` | Can interact while in Map | +| | `"isNotInside"` | Can interact while inside a vehicle | +| | `"isNotInZeus"` | Can interact while in the zeus interface | +| | `"isNotUnconscious"` | Can interact while unconscious | +| `dragging` | `"isNotDragging"` | Can interact while dragging | +| | `"isNotCarrying"` | Can interact while carrying | +| `interaction` | `"isNotSwimming"` | Can interact while swimming/diving | +| | `"isNotOnLadder"` | Can interact while climbing a ladder | +| `refuel` | `"isNotRefueling"` | Can interact while carrying refueling nozzle | +| `sitting` | `"isNotSitting"` | Can interact while sitting in a chair | + ## 3. Adding actions via scripts Two steps, creating an action (array) and then adding it to either a class or object. From 92e10bc578b5affc8161e5a9b57b9b0748c4c291 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Tue, 6 Aug 2024 09:33:52 +0200 Subject: [PATCH 180/290] Fix overlapping CSW interaction position for SPG-9, improve positions for Mk19 and DSHKM (#10165) Fix overlappting CSW interaction position for SPG-9, improve Mk19 and DSHKM --- .../compat_cup_weapons_csw/CfgVehicles.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/compat_cup_weapons/compat_cup_weapons_csw/CfgVehicles.hpp b/addons/compat_cup_weapons/compat_cup_weapons_csw/CfgVehicles.hpp index 3924ae0386..752745fb35 100644 --- a/addons/compat_cup_weapons/compat_cup_weapons_csw/CfgVehicles.hpp +++ b/addons/compat_cup_weapons/compat_cup_weapons_csw/CfgVehicles.hpp @@ -65,7 +65,7 @@ class CfgVehicles { class ace_csw { enabled = 1; proxyWeapon = "CUP_proxy_DSHKM"; - magazineLocation = "_target selectionPosition 'magazine'"; + magazineLocation = "_target selectionPosition 'otocvez'"; disassembleWeapon = "CUP_DSHKM_carry"; disassembleTurret = "ace_csw_kordTripod"; desiredAmmo = 100; @@ -119,7 +119,7 @@ class CfgVehicles { class ace_csw { enabled = 1; proxyWeapon = "CUP_proxy_MK19"; - magazineLocation = "_target selectionPosition 'magazine'"; + magazineLocation = "_target selectionPosition 'otochlaven'"; disassembleWeapon = "CUP_MK19_carry"; disassembleTurret = "ace_csw_m3TripodLow"; desiredAmmo = 48; @@ -165,7 +165,7 @@ class CfgVehicles { class ace_csw { enabled = 1; proxyWeapon = "CUP_proxy_SPG9"; - magazineLocation = "_target selectionPosition 'otochlaven'"; + magazineLocation = "_target selectionPosition 'handle'"; disassembleWeapon = "CUP_SPG9_carry"; disassembleTurret = "ace_csw_spg9Tripod"; desiredAmmo = 1; From 973cfdd1c4eeec2a97e7482d8faf88b69489fa36 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Tue, 6 Aug 2024 09:48:10 +0200 Subject: [PATCH 181/290] Common - Move missing compats warning to pre start (#10162) * Remove missing compats warning * move to common/preStart * ? --------- Co-authored-by: PabstMirror --- addons/advanced_ballistics/XEH_postInit.sqf | 16 --------------- addons/common/XEH_preStart.sqf | 22 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/addons/advanced_ballistics/XEH_postInit.sqf b/addons/advanced_ballistics/XEH_postInit.sqf index 9d0dd0ee4b..f61fdb3188 100644 --- a/addons/advanced_ballistics/XEH_postInit.sqf +++ b/addons/advanced_ballistics/XEH_postInit.sqf @@ -24,22 +24,6 @@ if (!hasInterface) exitWith {}; // Register Perframe Handler [LINKFUNC(handleFirePFH), GVAR(simulationInterval)] call CBA_fnc_addPerFrameHandler; - - //Add warnings for missing compat PBOs (only if AB is on) - { - _x params ["_modPBO", "_compatPBO"]; - if ([_modPBO] call EFUNC(common,isModLoaded) && {!([_compatPBO] call EFUNC(common,isModLoaded))}) then { - WARNING_2("Weapon Mod [%1] missing ace compat pbo [%2] (from @ace\optionals)",_modPBO,_compatPBO); - }; - } forEach [ - ["RH_acc","ace_compat_rh_acc"], - ["RH_de_cfg","ace_compat_rh_de"], - ["RH_m4_cfg","ace_compat_rh_m4"], - ["RH_PDW","ace_compat_rh_pdw"], - ["RKSL_PMII","ace_compat_rksl_pm_ii"], - ["iansky_opt","ace_compat_sma3_iansky"], - ["R3F_Armes","ace_compat_r3f"] - ]; }] call CBA_fnc_addEventHandler; #ifdef DEBUG_MODE_FULL diff --git a/addons/common/XEH_preStart.sqf b/addons/common/XEH_preStart.sqf index 208adea7b1..3168243c06 100644 --- a/addons/common/XEH_preStart.sqf +++ b/addons/common/XEH_preStart.sqf @@ -15,3 +15,25 @@ uiNamespace setVariable [QGVAR(addonCache), createHashMap]; // Cache for FUNC(getConfigName) uiNamespace setVariable [QGVAR(configNames), createHashMap]; + +//Add warnings for missing compat PBOs +GVAR(isModLoadedCache) = createHashMap; +{ + _x params ["_modPBO", "_compatPBO"]; + if ([_modPBO] call FUNC(isModLoaded) && {!([_compatPBO] call FUNC(isModLoaded))}) then { + WARNING_2("Weapon Mod [%1] missing ace compat pbo [%2]",_modPBO,_compatPBO); + }; +} forEach [ + ["CUP_Creatures_People_LoadOrder","ace_compat_cup_units"], + ["CUP_Vehicles_LoadOrder","ace_compat_cup_vehicles"], + ["CUP_Weapons_LoadOrder","ace_compat_cup_weapons"], + ["r3f_armes_c","ace_compat_r3f"], + ["RF_Data_Loadorder","ace_compat_rf"], + ["RH_acc","ace_compat_rh_acc"], + ["RH_de_cfg","ace_compat_rh_de"], + ["RH_m4_cfg","ace_compat_rh_m4"], + ["RH_PDW","ace_compat_rh_pdw"], + ["RKSL_PMII","ace_compat_rksl_pm_ii"], + ["iansky_opt","ace_compat_sma3_iansky"], + ["R3F_Armes","ace_compat_r3f"] +]; From b9a361fd3906c9e1e7d37fba51f8190f5df66618 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Tue, 6 Aug 2024 18:15:01 +0200 Subject: [PATCH 182/290] Vehicle damage - Fix ERA/SLAT not being detected (#10168) * Fix ERA/SLAT not being detected --- addons/vehicle_damage/functions/fnc_addEventHandler.sqf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/vehicle_damage/functions/fnc_addEventHandler.sqf b/addons/vehicle_damage/functions/fnc_addEventHandler.sqf index a7e59c75a1..05f8e084c2 100644 --- a/addons/vehicle_damage/functions/fnc_addEventHandler.sqf +++ b/addons/vehicle_damage/functions/fnc_addEventHandler.sqf @@ -28,8 +28,8 @@ private _hitpointHash = [[], nil] call CBA_fnc_hashCreate; private _vehicleConfig = configOf _vehicle; private _hitpointsConfig = _vehicleConfig >> "HitPoints"; private _turretConfig = _vehicleConfig >> "Turrets"; -private _eraHitpoints = [_vehicleConfig >> QGVAR(eraHitpoints), "ARRAY", []] call CBA_fnc_getConfigEntry; -private _slatHitpoints = [_vehicleConfig >> QGVAR(slatHitpoints), "ARRAY", []] call CBA_fnc_getConfigEntry; +private _eraHitpoints = ([_vehicleConfig >> QGVAR(eraHitpoints), "ARRAY", []] call CBA_fnc_getConfigEntry) apply {toLowerANSI _x}; +private _slatHitpoints = ([_vehicleConfig >> QGVAR(slatHitpoints), "ARRAY", []] call CBA_fnc_getConfigEntry) apply {toLowerANSI _x}; // Add hitpoint names to config for quick lookup { From 80a310d4c6e3c035821ede30d4789d283fa53b58 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 8 Aug 2024 09:29:41 +0200 Subject: [PATCH 183/290] Vehicles - Remove unneeded magazines (#10172) Remove unneeded magazines --- addons/vehicles/CfgWeapons.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/addons/vehicles/CfgWeapons.hpp b/addons/vehicles/CfgWeapons.hpp index 2fbe4e5246..0c2eb0e4de 100644 --- a/addons/vehicles/CfgWeapons.hpp +++ b/addons/vehicles/CfgWeapons.hpp @@ -13,8 +13,7 @@ class CfgWeapons { class ACE_LMG_coax_DenelMG4: LMG_coax {}; class LMG_Minigun: LMG_RCWS { - // Add the following: "2000Rnd_762x51_Belt_T_Green","2000Rnd_762x51_Belt_T_Red","2000Rnd_762x51_Belt_T_Yellow","5000Rnd_762x51_Belt","5000Rnd_762x51_Yellow_Belt" - magazines[] = {"PylonWeapon_2000Rnd_65x39_belt", "1000Rnd_65x39_Belt","1000Rnd_65x39_Belt_Green","1000Rnd_65x39_Belt_Tracer_Green","1000Rnd_65x39_Belt_Tracer_Red","1000Rnd_65x39_Belt_Tracer_Yellow","1000Rnd_65x39_Belt_Yellow","2000Rnd_65x39_Belt","2000Rnd_65x39_Belt_Green","2000Rnd_65x39_Belt_Tracer_Green","2000Rnd_65x39_Belt_Tracer_Green_Splash","2000Rnd_65x39_Belt_Tracer_Red","2000Rnd_65x39_Belt_Tracer_Yellow","2000Rnd_65x39_Belt_Tracer_Yellow_Splash","2000Rnd_65x39_Belt_Yellow","2000Rnd_762x51_Belt_T_Green","2000Rnd_762x51_Belt_T_Red","2000Rnd_762x51_Belt_T_Yellow","200Rnd_65x39_Belt","200Rnd_65x39_Belt_Tracer_Green","200Rnd_65x39_Belt_Tracer_Red","200Rnd_65x39_Belt_Tracer_Yellow","5000Rnd_762x51_Belt","5000Rnd_762x51_Yellow_Belt","500Rnd_65x39_Belt","500Rnd_65x39_Belt_Tracer_Red_Splash","500Rnd_65x39_Belt_Tracer_Green_Splash","500Rnd_65x39_Belt_Tracer_Yellow_Splash"}; + magazines[] += {"2000Rnd_762x51_Belt_T_Green","2000Rnd_762x51_Belt_T_Red","2000Rnd_762x51_Belt_T_Yellow","5000Rnd_762x51_Belt","5000Rnd_762x51_Yellow_Belt"}; }; class HMG_127: LMG_RCWS { From 7838dea543414806f452bce804c31623f82d1b2a Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 8 Aug 2024 10:01:39 +0200 Subject: [PATCH 184/290] Common - Improve persistent lights/lasers (#10118) * Improve persistent lasers * Update addons/common/functions/fnc_switchPersistentLaser.sqf Co-authored-by: PabstMirror * Fix inventory changes toggling laser, removed alignment code * Update addons/common/functions/fnc_switchPersistentLaser.sqf Co-authored-by: PabstMirror * Added API for setting weapon lights/lasers * Fix undefined variables --------- Co-authored-by: PabstMirror --- addons/common/XEH_PREP.hpp | 1 + .../fnc_setWeaponLightLaserState.sqf | 59 ++++++++++ .../functions/fnc_switchPersistentLaser.sqf | 110 ++++++++++++------ 3 files changed, 132 insertions(+), 38 deletions(-) create mode 100644 addons/common/functions/fnc_setWeaponLightLaserState.sqf diff --git a/addons/common/XEH_PREP.hpp b/addons/common/XEH_PREP.hpp index d3972dc7b3..3614775345 100644 --- a/addons/common/XEH_PREP.hpp +++ b/addons/common/XEH_PREP.hpp @@ -178,6 +178,7 @@ PREP(setupLocalUnitsHandler); PREP(setVariableJIP); PREP(setVariablePublic); PREP(setVolume); +PREP(setWeaponLightLaserState); PREP(showHud); PREP(statusEffect_addType); PREP(statusEffect_get); diff --git a/addons/common/functions/fnc_setWeaponLightLaserState.sqf b/addons/common/functions/fnc_setWeaponLightLaserState.sqf new file mode 100644 index 0000000000..7f50573acb --- /dev/null +++ b/addons/common/functions/fnc_setWeaponLightLaserState.sqf @@ -0,0 +1,59 @@ +#include "..\script_component.hpp" +/* + * Author: johnb43 + * Toggles the unit's current weapon's light & laser. + * API for persistent lasers. Doesn't work on AI, as they have their own logic. + * + * Arguments: + * 0: Unit + * 1: Weapon light/laser state (default: false) + * + * Return Value: + * None + * + * Example: + * [player, true] call ace_common_fnc_setWeaponLightLaserState + * + * Public: Yes + */ + +params [["_unit", objNull, [objNull]], ["_state", false, [false]]]; + +if (!local _unit || {!alive _unit} || {!(_unit call FUNC(isPlayer))}) exitWith {}; + +if !(_unit call CBA_fnc_canUseWeapon) exitWith {}; + +private _currentWeapon = currentWeapon _unit; + +// Exit if unit has no weapon selected +if (_currentWeapon == "") exitWith {}; + +private _weaponIndex = [_unit, _currentWeapon] call FUNC(getWeaponIndex); + +// Ignore binoculars +if (_weaponIndex == -1) exitWith {}; + +_unit setVariable [QGVAR(laserEnabled_) + str _weaponIndex, _state]; + +// Turn off light/laser (switching between weapons can leave previous weapon laser on) +action ["GunLightOff", _unit]; +action ["IRLaserOff", _unit]; + +// Light/laser is off, don't need to do anything more +if (!_state) exitWith {}; + +// Turn laser on next frame (if weapon hasn't changed) +[{ + params ["_unit", "_currentWeapon"]; + + private _weaponState = (weaponState _unit) select [0, 3]; + + if (_weaponState select 0 != _currentWeapon) exitWith {}; + + action ["GunLightOn", _unit]; + action ["IRLaserOn", _unit]; + + _unit selectWeapon _weaponState; +}, [_unit, _currentWeapon]] call CBA_fnc_execNextFrame; + +nil diff --git a/addons/common/functions/fnc_switchPersistentLaser.sqf b/addons/common/functions/fnc_switchPersistentLaser.sqf index a2b7b9c1a8..d258284edb 100644 --- a/addons/common/functions/fnc_switchPersistentLaser.sqf +++ b/addons/common/functions/fnc_switchPersistentLaser.sqf @@ -1,6 +1,6 @@ #include "..\script_component.hpp" /* - * Author: Dystopian + * Author: Dystopian, johnb43 * Controls persistent laser state. * * Arguments: @@ -17,51 +17,85 @@ params ["_enabled"]; +if (!hasInterface) exitwith {}; + +// Reset state +{ + ACE_player setVariable [QGVAR(laserEnabled_) + str _x, nil]; +} forEach [0, 1, 2]; + if (!_enabled) exitWith { if (isNil QGVAR(laserKeyDownEH)) exitWith {}; - ["KeyDown", GVAR(laserKeyDownEH)] call CBA_fnc_removeDisplayHandler; + + removeUserActionEventHandler ["headlights", "Activate", GVAR(laserKeyDownEH)]; + ["loadout", GVAR(laserLoadoutEH)] call CBA_fnc_removePlayerEventHandler; ["turret", GVAR(laserTurretEH)] call CBA_fnc_removePlayerEventHandler; ["vehicle", GVAR(laserVehicleEH)] call CBA_fnc_removePlayerEventHandler; ["weapon", GVAR(laserWeaponEH)] call CBA_fnc_removePlayerEventHandler; + + GVAR(laserKeyDownEH) = nil; + GVAR(laserLoadoutEH) = nil; + GVAR(laserTurretEH) = nil; + GVAR(laserVehicleEH) = nil; + GVAR(laserWeaponEH) = nil; }; -GVAR(laserKeyDownEH) = ["KeyDown", { - if !((_this select 1) in actionKeys "headlights") exitWith {false}; - private _weapon = currentWeapon ACE_player; - [ - { - params ["_weapon", "_laserWasEnabled"]; - private _laserEnabled = ACE_player isIRLaserOn _weapon || {ACE_player isFlashlightOn _weapon}; - if (_laserEnabled && {_laserWasEnabled} || {!_laserEnabled && {!_laserWasEnabled}}) exitWith {}; - private _weaponIndex = [ACE_player, _weapon] call FUNC(getWeaponIndex); - ACE_player setVariable [QGVAR(laserEnabled_) + str _weaponIndex, [nil, true] select _laserEnabled]; - }, - [_weapon, ACE_player isIRLaserOn _weapon || {ACE_player isFlashlightOn _weapon}] - ] call CBA_fnc_execNextFrame; - false -}] call CBA_fnc_addDisplayHandler; +private _fnc_getLightLaserState = { + private _currentWeapon = currentWeapon ACE_player; -private _laserEH = { - if (sunOrMoon == 1) exitWith {}; - params ["_player"]; - private _weaponIndex = [_player, currentWeapon _player] call FUNC(getWeaponIndex); - if ( - !(_player getVariable [QGVAR(laserEnabled_) + str _weaponIndex, false]) - || {_weaponIndex > 0 && {"" != primaryWeapon _player}} // Arma switches to primary weapon if exists - || {!(_player call CBA_fnc_canUseWeapon)} // ignore in vehicle except FFV - ) exitWith {}; - [ - // wait for weapon in "ready to fire" direction - {0.01 > getCameraViewDirection _this vectorDistance (_this weaponDirection currentWeapon _this)}, - {{_this action [_x, _this]} forEach ["GunLightOn", "IRLaserOn"]}, - _player, - 3, - {{_this action [_x, _this]} forEach ["GunLightOn", "IRLaserOn"]} - ] call CBA_fnc_waitUntilAndExecute; + if (_currentWeapon == "") exitWith {}; + + // Ignore in vehicle except FFV + if !(ACE_player call CBA_fnc_canUseWeapon) exitWith {}; + + private _weaponIndex = [ACE_player, _currentWeapon] call FUNC(getWeaponIndex); + + if (_weaponIndex == -1) exitWith {}; + + // Light/laser state only changes in the next frame + [{ + ACE_player setVariable [ + QGVAR(laserEnabled_) + str (_this select 1), + ACE_player isIRLaserOn (_this select 0) || {ACE_player isFlashlightOn (_this select 0)} + ]; + }, [_currentWeapon, _weaponIndex]] call CBA_fnc_execNextFrame; }; -GVAR(laserLoadoutEH) = ["loadout", _laserEH] call CBA_fnc_addPlayerEventHandler; -GVAR(laserTurretEH) = ["turret", _laserEH] call CBA_fnc_addPlayerEventHandler; -GVAR(laserVehicleEH) = ["vehicle", _laserEH] call CBA_fnc_addPlayerEventHandler; -GVAR(laserWeaponEH) = ["weapon", _laserEH] call CBA_fnc_addPlayerEventHandler; +// Get current weapon light/laser state +call _fnc_getLightLaserState; + +// Update state every time it's changed +GVAR(laserKeyDownEH) = addUserActionEventHandler ["headlights", "Activate", _fnc_getLightLaserState]; + +// Dropping weapons turns off lights/lasers +GVAR(lastWeapons) = [primaryWeapon ACE_player, handgunWeapon ACE_player, secondaryWeapon ACE_player]; + +// Monitor weapon addition/removal here +GVAR(laserLoadoutEH) = ["loadout", { + params ["_unit"]; + + private _weapons = [primaryWeapon _unit, handgunWeapon _unit, secondaryWeapon _unit]; + + if (_weapons isEqualTo GVAR(lastWeapons)) exitWith {}; + + GVAR(lastWeapons) = _weapons; + + [ + _unit, + _unit getVariable [QGVAR(laserEnabled_) + str ([_unit, currentWeapon _unit] call FUNC(getWeaponIndex)), false] + ] call FUNC(setWeaponLightLaserState); +}] call CBA_fnc_addPlayerEventHandler; + +private _fnc_switchPersistentLaserEH = { + params ["_unit"]; + + [ + _unit, + _unit getVariable [QGVAR(laserEnabled_) + str ([_unit, currentWeapon _unit] call FUNC(getWeaponIndex)), false] + ] call FUNC(setWeaponLightLaserState); +}; + +GVAR(laserTurretEH) = ["turret", _fnc_switchPersistentLaserEH] call CBA_fnc_addPlayerEventHandler; +GVAR(laserVehicleEH) = ["vehicle", _fnc_switchPersistentLaserEH] call CBA_fnc_addPlayerEventHandler; +GVAR(laserWeaponEH) = ["weapon", _fnc_switchPersistentLaserEH] call CBA_fnc_addPlayerEventHandler; From 0b2a8f23e63deb5f53c0ee585ec1bf3056554dd1 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 8 Aug 2024 17:26:52 +0200 Subject: [PATCH 185/290] Vehicle Damage - Let AP trigger ERA/SLAT (#10169) Let AP trigger ERA/SLAT --- addons/vehicle_damage/functions/fnc_processHit.sqf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/vehicle_damage/functions/fnc_processHit.sqf b/addons/vehicle_damage/functions/fnc_processHit.sqf index 2402df7fc2..ff1a0adadd 100644 --- a/addons/vehicle_damage/functions/fnc_processHit.sqf +++ b/addons/vehicle_damage/functions/fnc_processHit.sqf @@ -313,11 +313,11 @@ switch (_hitArea) do { case "slat": { TRACE_2("hit slat",_warheadType,_warheadTypeStr); // incredibly small chance of AP destroying SLAT - if (_warheadType isEqualTo WARHEAD_TYPE_HEAT || { _warheadType isEqualTo WARHEAD_TYPE_TANDEM } || { _warheadType isEqualTo WARHEAD_TYPE_HE } || { 0.01 > random 1 }) then { + if (_warheadType in [WARHEAD_TYPE_HE, WARHEAD_TYPE_AP, WARHEAD_TYPE_HEAT, WARHEAD_TYPE_TANDEM] || { 0.01 > random 1 }) then { private _currentDamage = _vehicle getHitIndex _hitIndex; TRACE_3("damaged slat",_warheadType,_warheadTypeStr,_currentDamage); - if (_warheadType isEqualTo WARHEAD_TYPE_HEAT || { _warheadType isEqualTo WARHEAD_TYPE_TANDEM }) then { + if (_warheadType in [WARHEAD_TYPE_HEAT, WARHEAD_TYPE_TANDEM, WARHEAD_TYPE_AP]) then { [_vehicle, _hitIndex, _hitpointName, 1] call FUNC(addDamage); } else { [_vehicle, _hitIndex, _hitpointName, _currentDamage + (0.5 max random 1)] call FUNC(addDamage); @@ -330,7 +330,7 @@ switch (_hitArea) do { }; case "era": { TRACE_2("hit era",_warheadType,_warheadTypeStr); - if (_warheadType isEqualTo WARHEAD_TYPE_HEAT || { _warheadType isEqualTo WARHEAD_TYPE_TANDEM } || { 0.05 > random 1 }) then { + if (_warheadType in [WARHEAD_TYPE_AP, WARHEAD_TYPE_HEAT, WARHEAD_TYPE_TANDEM] || { 0.05 > random 1 }) then { private _currentDamage = _vehicle getHitIndex _hitIndex; TRACE_3("damaged era",_warheadType,_warheadTypeStr,_currentDamage); [_vehicle, _hitIndex, _hitpointName, 1] call FUNC(addDamage); From 5afe06999f2a4a5fcea0c3b85bdee60a1aec0b89 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Thu, 8 Aug 2024 17:27:27 +0200 Subject: [PATCH 186/290] Chemlights - Add pretty name for addon (#10174) Add pretty name for chemlights addon --- addons/chemlights/config.cpp | 1 + addons/chemlights/script_component.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/addons/chemlights/config.cpp b/addons/chemlights/config.cpp index 263fcb1a57..7f30429e79 100644 --- a/addons/chemlights/config.cpp +++ b/addons/chemlights/config.cpp @@ -3,6 +3,7 @@ class CfgPatches { class ADDON { + name = COMPONENT_NAME; units[] = {"ACE_Box_Chemlights","ACE_Item_Chemlight_Shield","ACE_Item_Chemlight_Shield_Green","ACE_Item_Chemlight_Shield_Red","ACE_Item_Chemlight_Shield_Blue","ACE_Item_Chemlight_Shield_Yellow","ACE_Item_Chemlight_Shield_Orange","ACE_Item_Chemlight_Shield_White","ModuleChemlightOrange","ModuleChemlightWhite","ModuleChemlightHiRed","ModuleChemlightHiYellow","ModuleChemlightHiWhite","ModuleChemlightHiBlue","ModuleChemlightHiGreen","ModuleChemlightUltraHiOrange"}; weapons[] = {"ACE_Chemlight_Shield", "ACE_Chemlight_Shield_Green","ACE_Chemlight_Shield_Red","ACE_Chemlight_Shield_Blue","ACE_Chemlight_Shield_Yellow","ACE_Chemlight_Shield_Orange","ACE_Chemlight_Shield_White"}; requiredVersion = REQUIRED_VERSION; diff --git a/addons/chemlights/script_component.hpp b/addons/chemlights/script_component.hpp index 324af2c55c..5095ebe666 100644 --- a/addons/chemlights/script_component.hpp +++ b/addons/chemlights/script_component.hpp @@ -1,4 +1,5 @@ #define COMPONENT chemlights +#define COMPONENT_BEAUTIFIED Chemlights #include "\z\ace\addons\main\script_mod.hpp" // #define DEBUG_MODE_FULL From 4db0f7de24b973885f395e216ddf096f029dc23a Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Fri, 9 Aug 2024 23:08:07 +0200 Subject: [PATCH 187/290] Interaction - Improve `FUNC(switchWeaponAttachment)` (#10145) * Improve swtichWeaponAttachment * change interact_SWA to use common_SAM (#10176) * change interact_SWA to use common_SAM * Directly call * exit on bad arg * Update fnc_switchAttachmentMode.sqf * Minor optimisations * Cleanup leftover code, use unit instead of target --------- Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> * Update addons/interaction/functions/fnc_switchWeaponAttachment.sqf * Revert some unnecessary changes * Remove sound, as it was part of the CBA attachment switching & pass missing parameter * Add sound back, to indicate new attachment --------- Co-authored-by: PabstMirror --- .../functions/fnc_switchAttachmentMode.sqf | 36 ++++++++++++------- .../fnc_getWeaponAttachmentsActions.sqf | 10 ++++-- .../functions/fnc_switchWeaponAttachment.sqf | 36 +++++++++++++------ 3 files changed, 57 insertions(+), 25 deletions(-) diff --git a/addons/common/functions/fnc_switchAttachmentMode.sqf b/addons/common/functions/fnc_switchAttachmentMode.sqf index aae742db8a..f721428a53 100644 --- a/addons/common/functions/fnc_switchAttachmentMode.sqf +++ b/addons/common/functions/fnc_switchAttachmentMode.sqf @@ -2,26 +2,31 @@ /* * Author: PabstMirror * Switch attachment from one mode to another - based on CBA_accessory_fnc_switchAttachment + * ToDo: Port this to CBA? * * Arguments: * 0: Unit - * 1: From - * 2: To + * 1: Weapon (String or CBA-Weapon-Index (not ace's getWeaponIndex)) + * 2: From + * 3: To * * Return Value: * None * * Example: - * [player, "ACE_DBAL_A3_Green_VP", "ACE_DBAL_A3_Green"] call ace_common_fnc_switchAttachmentMode + * [player, 0, "ACE_DBAL_A3_Green_VP", "ACE_DBAL_A3_Green"] call ace_common_fnc_switchAttachmentMode * * Public: No */ - -params ["_unit", "_currItem", "_switchItem"]; -TRACE_3("switchAttachmentMode",_unit,_currItem,_switchItem); -switch (currentWeapon _unit) do { - case (""): {}; +params ["_unit", "_weapon", "_currItem", "_switchItem"]; +TRACE_4("switchAttachmentMode",_unit,_weapon,_currItem,_switchItem); + +if (_weapon isEqualTo "") exitWith {}; + +private _exit = _unit != ACE_player; +switch (_weapon) do { + case 0; case (primaryWeapon _unit): { private _currWeaponType = 0; _unit removePrimaryWeaponItem _currItem; @@ -31,6 +36,7 @@ switch (currentWeapon _unit) do { ["CBA_attachmentSwitched", _this] call CBA_fnc_localEvent; }, [_unit, _currItem, _switchItem, _currWeaponType]] call CBA_fnc_execNextFrame; }; + case 1; case (handgunWeapon _unit): { private _currWeaponType = 1; _unit removeHandgunItem _currItem; @@ -40,6 +46,7 @@ switch (currentWeapon _unit) do { ["CBA_attachmentSwitched", _this] call CBA_fnc_localEvent; }, [_unit, _currItem, _switchItem, _currWeaponType]] call CBA_fnc_execNextFrame; }; + case 2; case (secondaryWeapon _unit): { private _currWeaponType = 2; _unit removeSecondaryWeaponItem _currItem; @@ -49,13 +56,18 @@ switch (currentWeapon _unit) do { ["CBA_attachmentSwitched", _this] call CBA_fnc_localEvent; }, [_unit, _currItem, _switchItem, _currWeaponType]] call CBA_fnc_execNextFrame; }; + default { + ERROR_1("bad weapon - %1",_this); + _exit = true; + }; }; +if (_exit) exitWith {}; // Don't notify if the unit isn't the local player or if an invalid weapon was passed + private _configSwitchItem = configfile >> "CfgWeapons" >> _switchItem; private _switchItemHintText = getText (_configSwitchItem >> "MRT_SwitchItemHintText"); private _switchItemHintImage = getText (_configSwitchItem >> "picture"); -if (_switchItemHintText isNotEqualTo "") then { + +playSound "click"; +if (_switchItemHintText != "") then { [[_switchItemHintImage, 2.0], [_switchItemHintText], true] call CBA_fnc_notify; }; -if (_unit == ACE_player) then { - playSound "click"; -}; diff --git a/addons/interaction/functions/fnc_getWeaponAttachmentsActions.sqf b/addons/interaction/functions/fnc_getWeaponAttachmentsActions.sqf index 2b8fbe43e9..e91a027068 100644 --- a/addons/interaction/functions/fnc_getWeaponAttachmentsActions.sqf +++ b/addons/interaction/functions/fnc_getWeaponAttachmentsActions.sqf @@ -44,7 +44,7 @@ params ["_unit"]; {}, {true}, { - params ["_unit", "", "_args"]; + params ["", "_unit", "_args"]; _args params ["_attachment", "_name", "_picture", "_weaponItems", "_currentWeapon"]; private _cfgWeapons = configFile >> "CfgWeapons"; @@ -110,10 +110,14 @@ params ["_unit"]; QGVAR(switch_) + _x, format ["%1: %2", localize "str_sensortype_switch", _modeName], getText (_config >> "picture"), - LINKFUNC(switchWeaponAttachment), + { + params ["", "_unit", "_actionParams"]; + _actionParams params ["_weapon", "_newAttachment", "_oldAttachment"]; + [_unit, _weapon, _oldAttachment, _newAttachment] call EFUNC(common,switchAttachmentMode); + }, {true}, {}, - [_currentWeapon, _x, ""] + [_currentWeapon, _x, _attachment] ] call EFUNC(interact_menu,createAction), [], _unit diff --git a/addons/interaction/functions/fnc_switchWeaponAttachment.sqf b/addons/interaction/functions/fnc_switchWeaponAttachment.sqf index aaefb3315e..6fede34962 100644 --- a/addons/interaction/functions/fnc_switchWeaponAttachment.sqf +++ b/addons/interaction/functions/fnc_switchWeaponAttachment.sqf @@ -4,9 +4,12 @@ * Switches weapon attachment. * * Arguments: - * 0: Target - * 1: Player (not used) + * 0: Target (not used) + * 1: Player * 2: Action params + * - 0: Weapon + * - 1: New Attachment + * - 2: Old Attachment * * Return Value: * None @@ -17,11 +20,13 @@ * Public: No */ -params ["_unit", "", "_actionParams"]; +params ["", "_unit", "_actionParams"]; _actionParams params ["_weapon", "_newAttachment", "_oldAttachment"]; TRACE_3("Switching attachment",_weapon,_newAttachment,_oldAttachment); -[_unit, "Gear"] call EFUNC(common,doGesture); +private _currWeaponType = [_unit, _weapon] call EFUNC(common,getWeaponIndex); + +if (_currWeaponType == -1) exitWith {}; private _addNew = _newAttachment isNotEqualTo ""; private _removeOld = _oldAttachment isNotEqualTo ""; @@ -38,22 +43,33 @@ if (_removeOld && {!([_unit, _oldAttachment] call CBA_fnc_canAddItem)}) exitWith }; }; +[_unit, "Gear"] call EFUNC(common,doGesture); + if (_removeOld) then { [{ - params ["_unit", "_weapon", "_oldAttachment"]; - switch (_weapon) do { - case (primaryWeapon _unit): {_unit removePrimaryWeaponItem _oldAttachment;}; - case (handgunWeapon _unit): {_unit removeHandgunItem _oldAttachment;}; - default {_unit removeSecondaryWeaponItem _oldAttachment;}; + params ["_unit", "_currWeaponType", "_oldAttachment"]; + + switch (_currWeaponType) do { + case 0: {_unit removePrimaryWeaponItem _oldAttachment}; + case 1: {_unit removeSecondaryWeaponItem _oldAttachment}; + case 2: {_unit removeHandgunItem _oldAttachment}; + default {}; }; + _unit addItem _oldAttachment; - }, [_unit, _weapon, _oldAttachment], 0.3] call CBA_fnc_waitAndExecute; + }, [_unit, _currWeaponType, _oldAttachment], 0.3] call CBA_fnc_waitAndExecute; }; if (!_addNew) exitWith {}; [{ params ["_unit", "_weapon", "_newAttachment"]; + _unit addWeaponItem [_weapon, _newAttachment]; + + if (_unit != ACE_player) exitWith {}; + [[getText (configFile >> "CfgWeapons" >> _newAttachment >> "picture"), 4], true] call CBA_fnc_notify; + + playSound "click"; }, [_unit, _weapon, _newAttachment], 1] call CBA_fnc_waitAndExecute; From b2a3fac4b64ac5bd9ea6bd612491b1e519a2a661 Mon Sep 17 00:00:00 2001 From: tuntematonjr Date: Sat, 10 Aug 2024 00:35:35 +0300 Subject: [PATCH 188/290] Medical Feedback - Add parameters to fnc_playInjuredSound (#10175) * Additional parameters - added parameters to allow changing distances for sounds for each severity. - added parameter to allow unconscious units to do sounds. * fix conditio * Updated header formatting + minor tweaks --------- Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- .../functions/fnc_playInjuredSound.sqf | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/addons/medical_feedback/functions/fnc_playInjuredSound.sqf b/addons/medical_feedback/functions/fnc_playInjuredSound.sqf index c278e6e08a..b33b533e25 100644 --- a/addons/medical_feedback/functions/fnc_playInjuredSound.sqf +++ b/addons/medical_feedback/functions/fnc_playInjuredSound.sqf @@ -6,8 +6,11 @@ * * Arguments: * 0: Unit - * 1: Type (optional) ["hit" (default) or "moan"] - * 2: Severity (optional) [0 (default), 1, 2] + * 1: Type ["hit", "moan"] (default: "hit") + * 2: Severity [0, 1, 2] (default: 0) + * 3: Hit sound distances (default: [50, 60, 70]) + * 4: Moan sound distances (default: [10, 15, 20]) + * 5: Allow unconscious units (default: false) * * Return Value: * None @@ -20,18 +23,18 @@ #define TIME_OUT_HIT 1 #define TIME_OUT_MOAN [12, 7.5, 5] -params [["_unit", objNull, [objNull]], ["_type", "hit", [""]], ["_severity", 0, [0]]]; +params [["_unit", objNull, [objNull]], ["_type", "hit", [""]], ["_severity", 0, [0]], ["_hitDistances", [50, 60, 70], [[]], [3]], ["_moanDistances", [10, 15, 20], [[]], [3]], ["_allowUnconscious", false, [true]]]; // TRACE_3("",_unit,_type,_severity); if (!local _unit) exitWith { ERROR_2("playInjuredSound: Unit not local or null [%1:%2]",_unit,typeOf _unit); }; -if !(_unit call EFUNC(common,isAwake)) exitWith {}; +if (!_allowUnconscious && {!(_unit call EFUNC(common,isAwake))}) exitWith {}; // Limit network traffic by only sending the event to players who can potentially hear it private _distance = if (_type == "hit") then { - [50, 60, 70] select _severity; + _hitDistances select _severity } else { - [10, 15, 20] select _severity; + _moanDistances select _severity }; private _targets = allPlayers inAreaArray [ASLToAGL getPosASL _unit, _distance, _distance, 0, false, _distance]; if (_targets isEqualTo []) exitWith {}; From 22c71ba80e91cf9576f2ca60aa3df77b1e069a87 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 10 Aug 2024 15:48:34 +0200 Subject: [PATCH 189/290] CSW - Fix round count in GMG belt description (#10180) * Correct round count in GMG belt * Fixed failing CI --- addons/csw/CfgMagazines.hpp | 1 + addons/csw/stringtable.xml | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/addons/csw/CfgMagazines.hpp b/addons/csw/CfgMagazines.hpp index 86ad73c58f..2466bbe696 100644 --- a/addons/csw/CfgMagazines.hpp +++ b/addons/csw/CfgMagazines.hpp @@ -58,6 +58,7 @@ class CfgMagazines { class GVAR(20Rnd_20mm_G_belt): 40Rnd_20mm_G_belt { author = ECSTRING(common,ACETeam); displayName = CSTRING(GMGBelt_displayName); + descriptionShort = CSTRING(GMGBelt_descriptionShort); model = "\A3\Structures_F_EPB\Items\Military\Ammobox_rounds_F.p3d"; picture = QPATHTOF(UI\ammoBox_50bmg_ca.paa); type = 256; diff --git a/addons/csw/stringtable.xml b/addons/csw/stringtable.xml index da794376ab..5d11773490 100644 --- a/addons/csw/stringtable.xml +++ b/addons/csw/stringtable.xml @@ -672,6 +672,22 @@ [CSW] Лента 20-мм гранат для ст. гранатомёта [CSW] 20mm 고속유탄발사기 탄띠 + + Caliber: 20 mm<br/>Rounds: 20<br />Used in: Grenade Launcher + 口徑:20 mm<br/>個數:20<br />用於:榴彈發射器 + Calibre : 20 mm<br/>Munitions : 20<br />Application : lance-grenades + Calibre: 20 mm<br/>Cargas: 20<br />Se usa en: lanzagranadas + Calibro: 20 mm<br/>Munizioni: 20<br />Si usa in: lanciagranate + Kaliber: 20 mm<br/>Naboje: 20<br />Używane w: granatniku + Калибр: 20 мм<br/>Кол-во: 20<br />Применение: гранатомет + Kaliber: 20 mm<br/>Patronen: 20<br />Eingesetzt von: Granatenwerfer + Ráže: 20 mm<br/>Munice: 20<br />Použití: Granátomet + Calibre: 20 mm<br/>Balas: 20<br />Uso em: Lança-granadas + 구경: 20mm<br />탄 수: 20<br />사용 가능: 유탄발사기 + 口径:20 毫米<br/>容弹量:20<br />用于:枪榴弹发射器 + 口径:20 mm <br/>弾薬:20<br />使用:グレネードランチャー + Kalibre: 20 mm<br/>Mermi: 20<br />Kullanıldığı Yer: Bombaatar + M3 Tripod Trípode M3 From 9e4bcc5d72a764fa448657fd9361af5ff37451ad Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 10 Aug 2024 19:06:45 +0200 Subject: [PATCH 190/290] Explosives - Remove `delayTime` for explosives, as it no longer serves any purpose (#10181) Remove `delayTime` for explosives, as it no longer serves any purpose --- addons/compat_gm/compat_gm_explosives/CfgMagazines.hpp | 2 -- .../compat_rhs_afrf3_explosives/CfgMagazines.hpp | 2 -- .../compat_rhs_saf3_explosives/CfgMagazines.hpp | 1 - .../compat_rhs_usf3_explosives/CfgMagazines.hpp | 1 - addons/compat_spe/compat_spe_explosives/CfgMagazines.hpp | 5 ----- addons/explosives/CfgMagazines.hpp | 3 --- docs/wiki/development/ace3-config-entries.md | 1 - docs/wiki/framework/explosives-framework.md | 1 - 8 files changed, 16 deletions(-) diff --git a/addons/compat_gm/compat_gm_explosives/CfgMagazines.hpp b/addons/compat_gm/compat_gm_explosives/CfgMagazines.hpp index 17d51d3b45..7cbbcd4eab 100644 --- a/addons/compat_gm/compat_gm_explosives/CfgMagazines.hpp +++ b/addons/compat_gm/compat_gm_explosives/CfgMagazines.hpp @@ -2,7 +2,6 @@ class CfgMagazines { // Explosives class gm_explosive_petn_charge_base; class gm_explosive_petn_charge: gm_explosive_petn_charge_base { - EGVAR(explosives,DelayTime) = 1; EGVAR(explosives,Placeable) = 1; EGVAR(explosives,SetupObject) =QEGVAR(explosives,Place_gm_explosive_petn); useAction = 0; @@ -21,7 +20,6 @@ class CfgMagazines { class gm_explosive_plnp_charge_base; class gm_explosive_plnp_charge: gm_explosive_plnp_charge_base { - EGVAR(explosives,DelayTime) = 1; EGVAR(explosives,Placeable) = 1; EGVAR(explosives,SetupObject) =QEGVAR(explosives,Place_gm_explosive_plnp); useAction = 0; diff --git a/addons/compat_rhs_afrf3/compat_rhs_afrf3_explosives/CfgMagazines.hpp b/addons/compat_rhs_afrf3/compat_rhs_afrf3_explosives/CfgMagazines.hpp index 4f8e808bd5..3b9be4a3a6 100644 --- a/addons/compat_rhs_afrf3/compat_rhs_afrf3_explosives/CfgMagazines.hpp +++ b/addons/compat_rhs_afrf3/compat_rhs_afrf3_explosives/CfgMagazines.hpp @@ -42,7 +42,6 @@ class CfgMagazines { }; class rhs_ec75_mag: ATMine_Range_Mag { - EGVAR(explosives,DelayTime) = 1; EGVAR(explosives,SetupObject) = QEGVAR(explosives,Place_rhs_ec75); useAction = 0; class ACE_Triggers { @@ -133,7 +132,6 @@ class CfgMagazines { }; class rhs_mine_ozm72_c_mag: rhs_mine_ozm72_a_mag { - EGVAR(explosives,DelayTime) = 1; EGVAR(explosives,SetupObject) = QEGVAR(explosives,Place_rhs_mine_ozm72_c); useAction = 0; class ACE_Triggers { diff --git a/addons/compat_rhs_saf3/compat_rhs_saf3_explosives/CfgMagazines.hpp b/addons/compat_rhs_saf3/compat_rhs_saf3_explosives/CfgMagazines.hpp index c004f58446..2cda6e7265 100644 --- a/addons/compat_rhs_saf3/compat_rhs_saf3_explosives/CfgMagazines.hpp +++ b/addons/compat_rhs_saf3/compat_rhs_saf3_explosives/CfgMagazines.hpp @@ -51,7 +51,6 @@ class CfgMagazines { class CA_Magazine; class rhssaf_tm100_mag: CA_Magazine { useAction = 0; - EGVAR(explosives,DelayTime) = 1; EGVAR(explosives,Placeable) = 1; EGVAR(explosives,SetupObject) = QEGVAR(explosives,Place_rhssaf_tm100); class ACE_Triggers { diff --git a/addons/compat_rhs_usf3/compat_rhs_usf3_explosives/CfgMagazines.hpp b/addons/compat_rhs_usf3/compat_rhs_usf3_explosives/CfgMagazines.hpp index 332c2bf1f2..aa2485dcdc 100644 --- a/addons/compat_rhs_usf3/compat_rhs_usf3_explosives/CfgMagazines.hpp +++ b/addons/compat_rhs_usf3/compat_rhs_usf3_explosives/CfgMagazines.hpp @@ -1,7 +1,6 @@ class CfgMagazines { class CA_Magazine; class rhsusf_m112_mag: CA_Magazine { - EGVAR(explosives,delayTime) = 1; EGVAR(explosives,placeable) = 1; EGVAR(explosives,setupObject) = QEGVAR(explosives,Place_rhsusf_explosive_m112); useAction = 0; diff --git a/addons/compat_spe/compat_spe_explosives/CfgMagazines.hpp b/addons/compat_spe/compat_spe_explosives/CfgMagazines.hpp index 7c1945fcb8..27c0ff68aa 100644 --- a/addons/compat_spe/compat_spe_explosives/CfgMagazines.hpp +++ b/addons/compat_spe/compat_spe_explosives/CfgMagazines.hpp @@ -1,7 +1,6 @@ class CfgMagazines { class SPE_Mine_Magazine; class SPE_US_TNT_4pound_mag: SPE_Mine_Magazine { - EGVAR(explosives,DelayTime) = 1; EGVAR(explosives,Placeable) = 1; EGVAR(explosives,SetupObject) = QEXPLOSIVES_PLACE(4LBTNT); useAction = 0; @@ -19,7 +18,6 @@ class CfgMagazines { }; class SPE_US_TNT_half_pound_mag: SPE_Mine_Magazine { - EGVAR(explosives,DelayTime) = 1; EGVAR(explosives,Placeable) = 1; EGVAR(explosives,SetupObject) = QEXPLOSIVES_PLACE(halfLBTNT); useAction = 0; @@ -37,7 +35,6 @@ class CfgMagazines { }; class SPE_US_Bangalore_mag: SPE_Mine_Magazine { - EGVAR(explosives,DelayTime) = 1; EGVAR(explosives,Placeable) = 1; EGVAR(explosives,SetupObject) = QEXPLOSIVES_PLACE(bangalore); useAction = 0; @@ -55,7 +52,6 @@ class CfgMagazines { }; class SPE_Ladung_Small_MINE_mag: SPE_Mine_Magazine { - EGVAR(explosives,DelayTime) = 1; EGVAR(explosives,Placeable) = 1; EGVAR(explosives,SetupObject) = QEXPLOSIVES_PLACE(smallLadung); useAction = 0; @@ -73,7 +69,6 @@ class CfgMagazines { }; class SPE_Ladung_Big_MINE_mag: SPE_Mine_Magazine { - EGVAR(explosives,DelayTime) = 1; EGVAR(explosives,Placeable) = 1; EGVAR(explosives,SetupObject) = QEXPLOSIVES_PLACE(bigLadung); useAction = 0; diff --git a/addons/explosives/CfgMagazines.hpp b/addons/explosives/CfgMagazines.hpp index 7bb2c6ff02..65f5dd7eb3 100644 --- a/addons/explosives/CfgMagazines.hpp +++ b/addons/explosives/CfgMagazines.hpp @@ -4,7 +4,6 @@ class CfgMagazines { GVAR(Placeable) = 1; useAction = 0; GVAR(SetupObject) = "ACE_Explosives_Place_ATMine"; // CfgVehicle class for setup object. - GVAR(DelayTime) = 2.5; class ACE_Triggers { SupportedTriggers[] = {"PressurePlate"}; class PressurePlate { @@ -50,7 +49,6 @@ class CfgMagazines { GVAR(Placeable) = 1; useAction = 0; GVAR(SetupObject) = "ACE_Explosives_Place_Claymore"; - GVAR(DelayTime) = 1.5; class ACE_Triggers { SupportedTriggers[] = {"Command", "MK16_Transmitter"}; class Command { @@ -64,7 +62,6 @@ class CfgMagazines { GVAR(Placeable) = 1; useAction = 0; GVAR(SetupObject) = "ACE_Explosives_Place_SatchelCharge"; - GVAR(DelayTime) = 1; class ACE_Triggers { SupportedTriggers[] = {"Timer", "Command", "MK16_Transmitter", "DeadmanSwitch"}; class Timer { diff --git a/docs/wiki/development/ace3-config-entries.md b/docs/wiki/development/ace3-config-entries.md index 9e656ad48c..c1e44430b5 100644 --- a/docs/wiki/development/ace3-config-entries.md +++ b/docs/wiki/development/ace3-config-entries.md @@ -140,7 +140,6 @@ ace_isbelt ace_attachable ace_placeable ace_setupobject -ace_delaytime ace_triggers ace_magazines_forcemagazinemuzzlevelocity ``` diff --git a/docs/wiki/framework/explosives-framework.md b/docs/wiki/framework/explosives-framework.md index 8abffa9448..dfaf5bdafb 100644 --- a/docs/wiki/framework/explosives-framework.md +++ b/docs/wiki/framework/explosives-framework.md @@ -28,7 +28,6 @@ class CfgMagazines { ACE_Explosives_Placeable = 1; // Can be placed useAction = 0; // Disable the vanilla interaction ACE_Explosives_SetupObject = "banana_satchel_place"; // The object placed before the explosive is armed - ACE_Explosives_DelayTime = 1.5; // Seconds between trigger activation and explosion class ACE_Triggers { // Trigger configurations SupportedTriggers[] = {"Timer", "Command", "MK16_Transmitter", "DeadmanSwitch"}; // Triggers that can be used class Timer { From d7c98ea366738748d53aff44eb445f2e9aa2993a Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 10 Aug 2024 19:19:36 +0200 Subject: [PATCH 191/290] Medical AI - Fix specific treatment items not being removed (#10179) Fix treatment items not being removed Bug introduced in #10158 --- addons/medical_ai/functions/fnc_healingLogic.sqf | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/medical_ai/functions/fnc_healingLogic.sqf b/addons/medical_ai/functions/fnc_healingLogic.sqf index c9fe046ef8..f5d13f7410 100644 --- a/addons/medical_ai/functions/fnc_healingLogic.sqf +++ b/addons/medical_ai/functions/fnc_healingLogic.sqf @@ -37,9 +37,10 @@ if (_finishTime > 0) exitWith { _treatmentEvent = "#fail"; }; + _healer removeItem _itemClassname; + _usedItem = _itemClassname; + if (_treatmentClass != "") then { - _healer removeItem _itemClassname; - _usedItem = _itemClassname; _treatmentArgs set [2, _treatmentClass]; }; }; From e181cffc832b5a445c2df4811e057dcd711ade32 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sat, 10 Aug 2024 19:58:43 +0200 Subject: [PATCH 192/290] RHS Compats - Remove nametags related functions being called if nametags isn't loaded (#10177) Don't call nametags related functions if nametags isn't loaded --- addons/compat_rhs_afrf3/XEH_postInit.sqf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/compat_rhs_afrf3/XEH_postInit.sqf b/addons/compat_rhs_afrf3/XEH_postInit.sqf index be180179a5..e740d0d8a6 100644 --- a/addons/compat_rhs_afrf3/XEH_postInit.sqf +++ b/addons/compat_rhs_afrf3/XEH_postInit.sqf @@ -1,5 +1,7 @@ #include "script_component.hpp" +if !(["ace_nametags"] call EFUNC(common,isModLoaded)) exitWith {}; + private _russianRankIcons = [ QPATHTOEF(nametags,UI\icons_russia\private_gs.paa), QPATHTOEF(nametags,UI\icons_russia\corporal_gs.paa), From 346d56c6594b9c0b3aab04290303dca9beade5c2 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Sat, 10 Aug 2024 13:53:01 -0500 Subject: [PATCH 193/290] QuickMount - Fix keybind (#10184) --- addons/quickmount/XEH_postInitClient.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/quickmount/XEH_postInitClient.sqf b/addons/quickmount/XEH_postInitClient.sqf index 6dbd38742b..30f655edd8 100644 --- a/addons/quickmount/XEH_postInitClient.sqf +++ b/addons/quickmount/XEH_postInitClient.sqf @@ -4,6 +4,6 @@ if (!hasInterface) exitWith {}; ["ACE3 Movement", QGVAR(mount), [LLSTRING(KeybindName), LLSTRING(KeybindDescription)], "", { if (!dialog) then { - call FUNC(getInNearest); + [] call FUNC(getInNearest); }; }] call CBA_fnc_addKeybind; From e36363e8ccea9b0727e3413f5fcc58993b89680c Mon Sep 17 00:00:00 2001 From: Dart <59131299+DartRuffian@users.noreply.github.com> Date: Sat, 10 Aug 2024 14:01:12 -0500 Subject: [PATCH 194/290] Arsenal - Add `ace_arsenal_fnc_saveLoadout` as API to save loadouts (#10151) * Added fnc_saveLoadout * Changed to toLower for other languages * GitHub didn't like editing the file in the browser * Fix case-sensitive _loadoutIndex Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> * Unicode support Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> * setVariable in case no loadouts are saved * Fix return not happening properly * Added scripting example * Update docs/wiki/framework/arsenal-framework.md --------- Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- addons/arsenal/XEH_PREP.hpp | 1 + addons/arsenal/functions/fnc_saveLoadout.sqf | 37 ++++++++++++++++++++ docs/wiki/framework/arsenal-framework.md | 9 +++++ 3 files changed, 47 insertions(+) create mode 100644 addons/arsenal/functions/fnc_saveLoadout.sqf diff --git a/addons/arsenal/XEH_PREP.hpp b/addons/arsenal/XEH_PREP.hpp index 94d4739b60..d0819056f2 100644 --- a/addons/arsenal/XEH_PREP.hpp +++ b/addons/arsenal/XEH_PREP.hpp @@ -78,6 +78,7 @@ PREP(removeStat); PREP(removeVirtualItems); PREP(renameDefaultLoadout); PREP(replaceUniqueItemsLoadout); +PREP(saveLoadout); PREP(scanConfig); PREP(showItem); PREP(sortPanel); diff --git a/addons/arsenal/functions/fnc_saveLoadout.sqf b/addons/arsenal/functions/fnc_saveLoadout.sqf new file mode 100644 index 0000000000..05e712e45f --- /dev/null +++ b/addons/arsenal/functions/fnc_saveLoadout.sqf @@ -0,0 +1,37 @@ +#include "..\script_component.hpp" +/* + * Author: DartRuffian + * Saves a given loadout to the client's profile. + * + * Arguments: + * 0: Name of loadout + * 1: CBA extended loadout or getUnitLoadout array + * 2: Replace existing loadout (default: false) + * + * Return Value: + * True if loadout was saved, otherwise false + * + * Example: + * ["Current Loadout", getUnitLoadout ACE_player] call ace_arsenal_fnc_saveLoadout + * + * Public: Yes + */ + +params [["_name", "", [""]], ["_loadout", [], [[]]], ["_replaceExisting", false, [false]]]; + +if (_name == "" || {_loadout isEqualTo []}) exitWith { false }; + +private _loadouts = profileNamespace getVariable [QGVAR(saved_loadouts), []]; +private _loadoutIndex = _loadouts findIf {(_x#0) == _name}; + +// If a loadout with same name already exists and no overwriting enabled, quit +if (!_replaceExisting && {_loadoutIndex != -1}) exitWith { false }; + +if (_loadoutIndex == -1) then { + _loadouts pushBack [_name, _loadout]; +} else { + _loadouts set [_loadoutIndex, [_name, _loadout]]; +}; + +profileNamespace setVariable [QGVAR(saved_loadouts), _loadouts]; +true diff --git a/docs/wiki/framework/arsenal-framework.md b/docs/wiki/framework/arsenal-framework.md index 954bbc0a7e..a02dcdf646 100644 --- a/docs/wiki/framework/arsenal-framework.md +++ b/docs/wiki/framework/arsenal-framework.md @@ -588,3 +588,12 @@ TAG_my_arsenal_essentials = ["arifle_AK12_F", "LMG_03_F"]; [ace_arsenal_currentBox, TAG_my_arsenal_essentials] call ace_arsenal_fnc_addVirtualItems }] call CBA_fnc_addEventHandler; ``` + +### 10.4 Saving loadouts to profile +A loadout can be saved to the player's profile using `ace_arsenal_fnc_saveLoadout`. + +```sqf +private _loadout = [ACE_player] call CBA_fnc_getLoadout; // or getUnitLoadout ACE_player +private _replaceExisting = true; // optional, default: false +["Current Loadout", _loadout, _replaceExisting] call ace_arsenal_fnc_saveLoadout; +``` From 96f81f1c9b5b85d28414900efb96701810f96d64 Mon Sep 17 00:00:00 2001 From: Dystopian Date: Sun, 11 Aug 2024 07:29:50 +0300 Subject: [PATCH 195/290] Interaction - Add actions based on animations (#6144) * Add actions based on animations * Add setting * Add ability to set items for users * Add actions for 1.82 changes Add actions for backpacks, canisters, entrench tool. Move items and backpack to WeaponHolder. * Add RHS 0.4.6 ZIL spare * Update to new standards * Handle RHS BTR retread system * Make init faster: move condition to configClasses * Fix CUP fake anims * Refactor * Rework * Rename init function * Decrease number of classes to init * Fix merge mistake * Apply suggestions from code review * Updated code for current mod structure * Multiple fixes & tweaks - Made anim setting require a mission restart - Handle more types of items that can be spawned - Prioritise adding items to inventory and only drop on ground if no inventory space - Add more position checks to make certain no valid position are present before stopping - If 1 item was spawned in, it's considered as success - Disable RHS' wheel replacement only if ace_repair is loaded * Update CfgVehicles.hpp * cache config lookup at preStart * Fix error * Add text config entry for progress bar title * Restructure interactions, improved some locations & added interaction to some missing vehicles * Reverted preInit change --------- Co-authored-by: jonpas Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> Co-authored-by: PabstMirror --- addons/compat_rhs_afrf3/XEH_preInit.sqf | 8 + .../compat_rhs_afrf3_repair/CfgVehicles.hpp | 123 +++++++++++ .../compat_rhs_afrf3_repair/config.cpp | 21 ++ .../script_component.hpp | 3 + addons/compat_rhs_usf3/CfgVehicles.hpp | 6 +- .../compat_rhs_usf3_refuel/CfgVehicles.hpp | 52 +++++ .../compat_rhs_usf3_refuel/config.cpp | 1 + .../compat_rhs_usf3_repair/CfgVehicles.hpp | 126 ++++++++++++ .../compat_rhs_usf3_repair/config.cpp | 23 +++ .../script_component.hpp | 3 + .../compat_rhs_usf3_trenches/CfgVehicles.hpp | 48 +++++ .../compat_rhs_usf3_trenches/config.cpp | 23 +++ .../script_component.hpp | 3 + addons/interaction/CfgVehicles.hpp | 135 ++++++++++++ addons/interaction/XEH_PREP.hpp | 1 + addons/interaction/XEH_postInit.sqf | 10 +- addons/interaction/XEH_preInit.sqf | 1 + addons/interaction/XEH_preStart.sqf | 10 + .../functions/fnc_initAnimActions.sqf | 194 ++++++++++++++++++ addons/interaction/initSettings.inc.sqf | 10 + addons/interaction/stringtable.xml | 4 + addons/refuel/CfgVehicles.hpp | 42 ++++ addons/repair/CfgVehicles.hpp | 57 +++++ addons/trenches/CfgVehicles.hpp | 40 ++++ 24 files changed, 939 insertions(+), 5 deletions(-) create mode 100644 addons/compat_rhs_afrf3/compat_rhs_afrf3_repair/CfgVehicles.hpp create mode 100644 addons/compat_rhs_afrf3/compat_rhs_afrf3_repair/config.cpp create mode 100644 addons/compat_rhs_afrf3/compat_rhs_afrf3_repair/script_component.hpp create mode 100644 addons/compat_rhs_usf3/compat_rhs_usf3_refuel/CfgVehicles.hpp create mode 100644 addons/compat_rhs_usf3/compat_rhs_usf3_repair/CfgVehicles.hpp create mode 100644 addons/compat_rhs_usf3/compat_rhs_usf3_repair/config.cpp create mode 100644 addons/compat_rhs_usf3/compat_rhs_usf3_repair/script_component.hpp create mode 100644 addons/compat_rhs_usf3/compat_rhs_usf3_trenches/CfgVehicles.hpp create mode 100644 addons/compat_rhs_usf3/compat_rhs_usf3_trenches/config.cpp create mode 100644 addons/compat_rhs_usf3/compat_rhs_usf3_trenches/script_component.hpp create mode 100644 addons/interaction/functions/fnc_initAnimActions.sqf diff --git a/addons/compat_rhs_afrf3/XEH_preInit.sqf b/addons/compat_rhs_afrf3/XEH_preInit.sqf index b47cf6628d..2ca4338e90 100644 --- a/addons/compat_rhs_afrf3/XEH_preInit.sqf +++ b/addons/compat_rhs_afrf3/XEH_preInit.sqf @@ -6,4 +6,12 @@ PREP_RECOMPILE_START; #include "XEH_PREP.hpp" PREP_RECOMPILE_END; +// Disable RHS' wheel replacement mechanic +if (["ace_repair"] call EFUNC(common,isModLoaded)) then { + RHS_Retread_Enabled = false; + rhs_btr70_EnableRetread = false; + rhs_TypeTirePressure = 1; + RHS_BTR_Effects_Init = true; +}; + ADDON = true; diff --git a/addons/compat_rhs_afrf3/compat_rhs_afrf3_repair/CfgVehicles.hpp b/addons/compat_rhs_afrf3/compat_rhs_afrf3_repair/CfgVehicles.hpp new file mode 100644 index 0000000000..1acd977b99 --- /dev/null +++ b/addons/compat_rhs_afrf3/compat_rhs_afrf3_repair/CfgVehicles.hpp @@ -0,0 +1,123 @@ +class CfgVehicles { + class Wheeled_APC_F; + class rhs_btr_base: Wheeled_APC_F { + class EGVAR(interaction,anims) { + class wheel_1_unhide { + positions[] = {{-0.8, -1.7, 0}}; + items[] = {"ACE_Wheel"}; + name = ECSTRING(repair,RemoveWheel); + text = ECSTRING(repair,RemovingWheel); + }; + class wheel_2_unhide { + positions[] = {{0.35, -2.9, -0.1}}; + items[] = {"ACE_Wheel"}; + name = ECSTRING(repair,RemoveWheel); + text = ECSTRING(repair,RemovingWheel); + }; + }; + }; + class rhs_btr70_vmf: rhs_btr_base { + class EGVAR(interaction,anims): EGVAR(interaction,anims) { + class wheel_1_unhide: wheel_1_unhide { + positions[] = {{-1.2, -2.6, 0.2}}; + }; + class wheel_2_unhide: wheel_2_unhide { + positions[] = {{-0.3, -3.8, 0}}; + }; + }; + }; + + class rhs_btr70_msv: rhs_btr70_vmf {}; + class rhs_btr80_msv: rhs_btr70_msv { + class EGVAR(interaction,anims): EGVAR(interaction,anims) { + class wheel_1_unhide: wheel_1_unhide { + positions[] = {{-1, -2.5, 0.6}}; + }; + class wheel_2_unhide: wheel_2_unhide { + enabled = 0; + }; + }; + }; + + class Truck_F; + class rhs_truck: Truck_F { + class EGVAR(interaction,anims) { + class spare_hide { + selections[] = {"spare"}; + items[] = {"ACE_Wheel"}; + name = ECSTRING(repair,RemoveWheel); + text = ECSTRING(repair,RemovingWheel); + }; + }; + }; + + class RHS_Ural_BaseTurret: Truck_F { + class EGVAR(interaction,anims) { + class spare_hide { + selections[] = {"spare"}; + items[] = {"ACE_Wheel"}; + name = ECSTRING(repair,RemoveWheel); + text = ECSTRING(repair,RemovingWheel); + }; + }; + }; + + class rhs_zil131_base: Truck_F { + class EGVAR(interaction,anims) { + class spare_hide { + selections[] = {"spare"}; + items[] = {"ACE_Wheel"}; + name = ECSTRING(repair,RemoveWheel); + text = ECSTRING(repair,RemovingWheel); + }; + }; + }; + + class rhs_kraz255_base; + class rhs_kraz255b1_base: rhs_kraz255_base { + class EGVAR(interaction,anims) { + class spare_hide { + selections[] = {"spare"}; + items[] = {"ACE_Wheel"}; + name = ECSTRING(repair,RemoveWheel); + text = ECSTRING(repair,RemovingWheel); + }; + }; + }; + + class O_Truck_02_covered_F; + class rhs_kamaz5350: O_Truck_02_covered_F { + class EGVAR(interaction,anims) { + class spare_hide { + selections[] = {"spare"}; + items[] = {"ACE_Wheel"}; + name = ECSTRING(repair,RemoveWheel); + text = ECSTRING(repair,RemovingWheel); + }; + }; + }; + + class MRAP_02_base_F; + class rhs_tigr_base: MRAP_02_base_F { + class EGVAR(interaction,anims) { + class spare_hide { + selections[] = {"spare"}; + items[] = {"ACE_Wheel"}; + name = ECSTRING(repair,RemoveWheel); + text = ECSTRING(repair,RemovingWheel); + }; + }; + }; + + class Offroad_01_base_f; + class RHS_UAZ_Base: Offroad_01_base_f { + class EGVAR(interaction,anims) { + class spare_hide { + selections[] = {"spare"}; + items[] = {"ACE_Wheel"}; + name = ECSTRING(repair,RemoveWheel); + text = ECSTRING(repair,RemovingWheel); + }; + }; + }; +}; diff --git a/addons/compat_rhs_afrf3/compat_rhs_afrf3_repair/config.cpp b/addons/compat_rhs_afrf3/compat_rhs_afrf3_repair/config.cpp new file mode 100644 index 0000000000..d6d4fab107 --- /dev/null +++ b/addons/compat_rhs_afrf3/compat_rhs_afrf3_repair/config.cpp @@ -0,0 +1,21 @@ +#include "script_component.hpp" + +class CfgPatches { + class SUBADDON { + name = COMPONENT_NAME; + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = { + "rhs_main_loadorder", + "ace_repair" + }; + skipWhenMissingDependencies = 1; + author = ECSTRING(common,ACETeam); + authors[] = {"Dystopian", "johnb43"}; + url = ECSTRING(main,URL); + VERSION_CONFIG; + }; +}; + +#include "CfgVehicles.hpp" diff --git a/addons/compat_rhs_afrf3/compat_rhs_afrf3_repair/script_component.hpp b/addons/compat_rhs_afrf3/compat_rhs_afrf3_repair/script_component.hpp new file mode 100644 index 0000000000..1af928486c --- /dev/null +++ b/addons/compat_rhs_afrf3/compat_rhs_afrf3_repair/script_component.hpp @@ -0,0 +1,3 @@ +#define SUBCOMPONENT repair +#define SUBCOMPONENT_BEAUTIFIED Repair +#include "..\script_component.hpp" diff --git a/addons/compat_rhs_usf3/CfgVehicles.hpp b/addons/compat_rhs_usf3/CfgVehicles.hpp index 0593c5a868..3933e543ec 100644 --- a/addons/compat_rhs_usf3/CfgVehicles.hpp +++ b/addons/compat_rhs_usf3/CfgVehicles.hpp @@ -43,8 +43,7 @@ class CfgVehicles { EGVAR(refuel,fuelCapacity) = 302; }; - class Truck_F; - class Truck_01_base_F: Truck_F {}; + class Truck_01_base_F; class rhsusf_fmtv_base: Truck_01_base_F { EGVAR(refuel,fuelCapacity) = 219; }; @@ -55,8 +54,7 @@ class CfgVehicles { EGVAR(refuel,fuelCargo) = 900; // 45 jerrycans }; - class rhsusf_HEMTT_A4_base: Truck_01_base_F {}; - class rhsusf_M977A4_usarmy_wd: rhsusf_HEMTT_A4_base {}; + class rhsusf_M977A4_usarmy_wd; class rhsusf_M977A4_AMMO_usarmy_wd: rhsusf_M977A4_usarmy_wd { EGVAR(rearm,defaultSupply) = 1200; }; diff --git a/addons/compat_rhs_usf3/compat_rhs_usf3_refuel/CfgVehicles.hpp b/addons/compat_rhs_usf3/compat_rhs_usf3_refuel/CfgVehicles.hpp new file mode 100644 index 0000000000..445cab8226 --- /dev/null +++ b/addons/compat_rhs_usf3/compat_rhs_usf3_refuel/CfgVehicles.hpp @@ -0,0 +1,52 @@ +class CfgVehicles { + class rhsusf_stryker_base; + class rhsusf_stryker_m1126_base: rhsusf_stryker_base { + class EGVAR(interaction,anims) { + class Hide_FCans { + positions[] = {{-0.7, -3, -0.4}}; + items[] = {"Land_CanisterFuel_F", "Land_CanisterFuel_F"}; + name = ECSTRING(refuel,TakeFuelCanister); + text = ECSTRING(refuel,TakeFuelCanisterAction); + }; + }; + }; + class rhsusf_stryker_m1127_base: rhsusf_stryker_m1126_base { + class EGVAR(interaction,anims): EGVAR(interaction,anims) { + class Hide_FCans: Hide_FCans { + positions[] = {{-0.5, -3, -0.4}}; + }; + }; + }; + + class rhsusf_stryker_m1126_m2_base: rhsusf_stryker_m1126_base {}; + class rhsusf_stryker_m1132_m2_base: rhsusf_stryker_m1126_m2_base { + class EGVAR(interaction,anims): EGVAR(interaction,anims) { + class Hide_FCans: Hide_FCans { + positions[] = {{-1, -4, -0.4}}; + }; + }; + }; + class rhsusf_stryker_m1134_base: rhsusf_stryker_m1132_m2_base { + class EGVAR(interaction,anims): EGVAR(interaction,anims) { + class Hide_FCans: Hide_FCans { + positions[] = {{-0.7, -3, -0.7}}; + }; + }; + }; + + class rhsusf_m1a2tank_base; + class rhsusf_m1a2sep2_base: rhsusf_m1a2tank_base { + class EGVAR(interaction,anims) { + class fuelcans_hide { + // Rotate interactions with turret rotation + positions[] = { + "[0.23, -0.6, 0] vectorAdd ([[1.1, -3.6, 0.6], [0, 0, 1], deg (_target animationPhase 'MainTurret')] call CBA_fnc_vectRotate3D)", + "[0.23, -0.6, 0] vectorAdd ([[-1.1, -3.6, 0.6], [0, 0, 1], deg (_target animationPhase 'MainTurret')] call CBA_fnc_vectRotate3D)" + }; + items[] = {"Land_CanisterFuel_F", "Land_CanisterFuel_F"}; + name = ECSTRING(refuel,TakeFuelCanister); + text = ECSTRING(refuel,TakeFuelCanisterAction); + }; + }; + }; +}; diff --git a/addons/compat_rhs_usf3/compat_rhs_usf3_refuel/config.cpp b/addons/compat_rhs_usf3/compat_rhs_usf3_refuel/config.cpp index bf600d5d5a..391e22d95e 100644 --- a/addons/compat_rhs_usf3/compat_rhs_usf3_refuel/config.cpp +++ b/addons/compat_rhs_usf3/compat_rhs_usf3_refuel/config.cpp @@ -21,3 +21,4 @@ class CfgPatches { }; #include "CfgEventHandlers.hpp" +#include "CfgVehicles.hpp" diff --git a/addons/compat_rhs_usf3/compat_rhs_usf3_repair/CfgVehicles.hpp b/addons/compat_rhs_usf3/compat_rhs_usf3_repair/CfgVehicles.hpp new file mode 100644 index 0000000000..26341db1da --- /dev/null +++ b/addons/compat_rhs_usf3/compat_rhs_usf3_repair/CfgVehicles.hpp @@ -0,0 +1,126 @@ +class CfgVehicles { + class Truck_01_base_F; + class rhsusf_fmtv_base: Truck_01_base_F { + class EGVAR(interaction,anims) { + class hide_spare { + positions[] = {{1, 1.4, 0}}; + items[] = {"ACE_Wheel"}; + name = ECSTRING(repair,RemoveWheel); + text = ECSTRING(repair,RemovingWheel); + }; + }; + }; + class rhsusf_M1078A1P2_fmtv_usarmy: rhsusf_fmtv_base {}; + class rhsusf_M1078A1P2_B_fmtv_usarmy: rhsusf_M1078A1P2_fmtv_usarmy {}; + class rhsusf_M1078A1P2_B_M2_fmtv_usarmy: rhsusf_M1078A1P2_B_fmtv_usarmy { + class EGVAR(interaction,anims): EGVAR(interaction,anims) { + class hide_spare: hide_spare { + positions[] = {{1, 1.4, -0.5}}; + }; + }; + }; + class rhsusf_M1078A1R_SOV_M2_D_fmtv_socom: rhsusf_M1078A1P2_B_M2_fmtv_usarmy { + class EGVAR(interaction,anims): EGVAR(interaction,anims) { + class hide_spare: hide_spare { + positions[] = {{1, 1, -0.5}}; + }; + }; + }; + class rhsusf_M1083A1P2_fmtv_usarmy: rhsusf_M1078A1P2_fmtv_usarmy {}; + class rhsusf_M1083A1P2_B_fmtv_usarmy: rhsusf_M1083A1P2_fmtv_usarmy {}; + class rhsusf_M1083A1P2_B_M2_fmtv_usarmy: rhsusf_M1083A1P2_B_fmtv_usarmy { + class EGVAR(interaction,anims): EGVAR(interaction,anims) { + class hide_spare: hide_spare { + positions[] = {{1, 1.4, -0.5}}; + }; + }; + }; + class rhsusf_M1084A1P2_fmtv_usarmy: rhsusf_M1083A1P2_fmtv_usarmy { + class EGVAR(interaction,anims): EGVAR(interaction,anims) { + class hide_spare: hide_spare { + positions[] = {{1, 1.8, 0}}; + }; + }; + }; + class rhsusf_M1084A1P2_B_M2_fmtv_usarmy: rhsusf_M1083A1P2_B_M2_fmtv_usarmy { + class EGVAR(interaction,anims): EGVAR(interaction,anims) { + class hide_spare: hide_spare { + positions[] = {{1, 1.8, -0.5}}; + }; + }; + }; + class rhsusf_M1085A1P2_B_Medical_fmtv_usarmy: rhsusf_M1083A1P2_B_fmtv_usarmy { + class EGVAR(interaction,anims): EGVAR(interaction,anims) { + class hide_spare: hide_spare { + positions[] = {{1, 6.1, 0}}; + }; + }; + }; + + class rhsusf_HEMTT_A4_base: Truck_01_base_F { + class EGVAR(interaction,anims) { + class hide_spare { + positions[] = {"_target selectionPosition 'sparewheel' vectorAdd [0.6, 0.6, -0.4]"}; + items[] = {"ACE_Wheel"}; + name = ECSTRING(repair,RemoveWheel); + text = ECSTRING(repair,RemovingWheel); + }; + }; + }; + + class MRAP_01_base_F; + class rhsusf_m1151_base: MRAP_01_base_F { + class EGVAR(interaction,anims) { + class hide_spare { + positions[] = {"_target selectionPosition 'sparewheel' vectorAdd [-0.465, 0, 0]"}; + items[] = {"ACE_Wheel"}; + name = ECSTRING(repair,RemoveWheel); + text = ECSTRING(repair,RemovingWheel); + }; + }; + }; + // Don't inherit, as it's easier for the trenches compat + class rhsusf_M1165A1_GMV_SAG2_base: rhsusf_m1151_base { + class EGVAR(interaction,anims) { + class hide_spare { + positions[] = {"_target selectionPosition 'sparewheel_gmv' vectorAdd [0, -0.44, 0]"}; + items[] = {"ACE_Wheel"}; + name = ECSTRING(repair,RemoveWheel); + text = ECSTRING(repair,RemovingWheel); + }; + }; + }; + + class rhsusf_rg33_base: MRAP_01_base_F { + class EGVAR(interaction,anims) { + class hide_spare { + selections[] = {"sparewheel"}; + items[] = {"ACE_Wheel"}; + name = ECSTRING(repair,RemoveWheel); + text = ECSTRING(repair,RemovingWheel); + }; + }; + }; + + class rhsusf_M1239_base: MRAP_01_base_F { + class EGVAR(interaction,anims) { + class hide_spare { + selections[] = {"sparewheel"}; + items[] = {"ACE_Wheel"}; + name = ECSTRING(repair,RemoveWheel); + text = ECSTRING(repair,RemovingWheel); + }; + }; + }; + + class rhsusf_MATV_base: MRAP_01_base_F { + class EGVAR(interaction,anims) { + class hide_spare { + selections[] = {"sparewheel"}; + items[] = {"ACE_Wheel"}; + name = ECSTRING(repair,RemoveWheel); + text = ECSTRING(repair,RemovingWheel); + }; + }; + }; +}; diff --git a/addons/compat_rhs_usf3/compat_rhs_usf3_repair/config.cpp b/addons/compat_rhs_usf3/compat_rhs_usf3_repair/config.cpp new file mode 100644 index 0000000000..b204f64166 --- /dev/null +++ b/addons/compat_rhs_usf3/compat_rhs_usf3_repair/config.cpp @@ -0,0 +1,23 @@ +#include "script_component.hpp" + +class CfgPatches { + class SUBADDON { + name = COMPONENT_NAME; + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = { + "rhsusf_main_loadorder", + "ace_repair" + }; + skipWhenMissingDependencies = 1; + author = ECSTRING(common,ACETeam); + authors[] = {"johnb43"}; + url = ECSTRING(main,URL); + VERSION_CONFIG; + + addonRootClass = QUOTE(ADDON); + }; +}; + +#include "CfgVehicles.hpp" diff --git a/addons/compat_rhs_usf3/compat_rhs_usf3_repair/script_component.hpp b/addons/compat_rhs_usf3/compat_rhs_usf3_repair/script_component.hpp new file mode 100644 index 0000000000..1af928486c --- /dev/null +++ b/addons/compat_rhs_usf3/compat_rhs_usf3_repair/script_component.hpp @@ -0,0 +1,3 @@ +#define SUBCOMPONENT repair +#define SUBCOMPONENT_BEAUTIFIED Repair +#include "..\script_component.hpp" diff --git a/addons/compat_rhs_usf3/compat_rhs_usf3_trenches/CfgVehicles.hpp b/addons/compat_rhs_usf3/compat_rhs_usf3_trenches/CfgVehicles.hpp new file mode 100644 index 0000000000..ba4dd16cd7 --- /dev/null +++ b/addons/compat_rhs_usf3/compat_rhs_usf3_trenches/CfgVehicles.hpp @@ -0,0 +1,48 @@ +class CfgVehicles { + class rhsusf_stryker_base; + class rhsusf_stryker_m1126_base: rhsusf_stryker_base { + class EGVAR(interaction,anims) { + class Hide_PioKit { + positions[] = {{-1, -2.2, -0.5}}; + items[] = {"ACE_EntrenchingTool"}; + name = ECSTRING(trenches,EntrenchingToolName); + text = ECSTRING(trenches,EntrenchingToolName); + }; + }; + }; + class rhsusf_stryker_m1127_base: rhsusf_stryker_m1126_base { + class EGVAR(interaction,anims): EGVAR(interaction,anims) { + class Hide_PioKit: Hide_PioKit { + positions[] = {{-0.8, -2.2, -0.5}}; + }; + }; + }; + + class rhsusf_stryker_m1126_m2_base: rhsusf_stryker_m1126_base {}; + class rhsusf_stryker_m1132_m2_base: rhsusf_stryker_m1126_m2_base { + class EGVAR(interaction,anims): EGVAR(interaction,anims) { + class Hide_PioKit: Hide_PioKit { + positions[] = {{-1.3, -3.3, -0.5}}; + }; + }; + }; + class rhsusf_stryker_m1134_base: rhsusf_stryker_m1132_m2_base { + class EGVAR(interaction,anims): EGVAR(interaction,anims) { + class Hide_PioKit: Hide_PioKit { + positions[] = {{-1, -2.2, -0.8}}; + }; + }; + }; + + class rhsusf_m1151_base; + class rhsusf_M1165A1_GMV_SAG2_base: rhsusf_m1151_base { + class EGVAR(interaction,anims) { + class tools_hide { + positions[] = {{0.365, 1.5, -0.4}}; + items[] = {"ACE_EntrenchingTool"}; + name = ECSTRING(trenches,EntrenchingToolName); + text = ECSTRING(trenches,EntrenchingToolName); + }; + }; + }; +}; diff --git a/addons/compat_rhs_usf3/compat_rhs_usf3_trenches/config.cpp b/addons/compat_rhs_usf3/compat_rhs_usf3_trenches/config.cpp new file mode 100644 index 0000000000..aea4c9daeb --- /dev/null +++ b/addons/compat_rhs_usf3/compat_rhs_usf3_trenches/config.cpp @@ -0,0 +1,23 @@ +#include "script_component.hpp" + +class CfgPatches { + class SUBADDON { + name = COMPONENT_NAME; + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = { + "rhsusf_main_loadorder", + "ace_trenches" + }; + skipWhenMissingDependencies = 1; + author = ECSTRING(common,ACETeam); + authors[] = {"johnb43"}; + url = ECSTRING(main,URL); + VERSION_CONFIG; + + addonRootClass = QUOTE(ADDON); + }; +}; + +#include "CfgVehicles.hpp" diff --git a/addons/compat_rhs_usf3/compat_rhs_usf3_trenches/script_component.hpp b/addons/compat_rhs_usf3/compat_rhs_usf3_trenches/script_component.hpp new file mode 100644 index 0000000000..10b90eb71e --- /dev/null +++ b/addons/compat_rhs_usf3/compat_rhs_usf3_trenches/script_component.hpp @@ -0,0 +1,3 @@ +#define SUBCOMPONENT trenches +#define SUBCOMPONENT_BEAUTIFIED Trenches +#include "..\script_component.hpp" diff --git a/addons/interaction/CfgVehicles.hpp b/addons/interaction/CfgVehicles.hpp index 6ae0d4a982..b3a0c1d37e 100644 --- a/addons/interaction/CfgVehicles.hpp +++ b/addons/interaction/CfgVehicles.hpp @@ -372,6 +372,16 @@ class CfgVehicles { }; class Car_F: Car {}; + class Offroad_01_base_F: Car_F { + class GVAR(anims) { + class HideBackpacks { + positions[] = {{-1.15, -1.15, -0.2}, {1.1, -1.15, -0.2}, {1.1, -2.5, -0.2}}; + items[] = {"B_TacticalPack_blk", "B_TacticalPack_blk", "B_Carryall_khk", "B_Carryall_khk"}; + name = "$STR_a3_cfgvehicleclasses_backpacks0"; + text = "$STR_a3_cfgvehicleclasses_backpacks0"; + }; + }; + }; class Quadbike_01_base_F: Car_F { class ACE_Actions: ACE_Actions { class ACE_MainActions: ACE_MainActions { @@ -405,6 +415,49 @@ class CfgVehicles { }; }; + class Wheeled_APC_F; + class APC_Wheeled_01_base_F: Wheeled_APC_F { + class GVAR(anims) { + class showBags { + phase = 0; + // Rotate interactions with turret rotation + positions[] = { + "[0, -1.6, 0] vectorAdd ([[1, -1, 0.1], [0, 0, 1], deg (_target animationPhase 'MainTurret')] call CBA_fnc_vectRotate3D)", + "[0, -1.6, 0] vectorAdd ([[-1, -1, 0.1], [0, 0, 1], deg (_target animationPhase 'MainTurret')] call CBA_fnc_vectRotate3D)" + }; + selections[] = {"vhc_bags"}; + items[] = {"B_Carryall_cbr", "B_Carryall_cbr"}; + name = "$STR_a3_cfgvehicleclasses_backpacks0"; + text = "$STR_a3_cfgvehicleclasses_backpacks0"; + }; + }; + }; + class APC_Wheeled_02_base_F: Wheeled_APC_F { + class GVAR(anims); + }; + class APC_Wheeled_02_base_v2_F: APC_Wheeled_02_base_F { + class GVAR(anims): GVAR(anims) { + class showBags { + phase = 0; + selections[] = {"vhc_bags"}; + items[] = {"B_Carryall_cbr"}; + name = "$STR_BACKPACK_CONTAINER_NAME"; + text = "$STR_BACKPACK_CONTAINER_NAME"; + }; + }; + }; + class APC_Wheeled_03_base_F: Wheeled_APC_F { + class GVAR(anims) { + class showBags { + phase = 0; + selections[] = {"vhc_bags"}; + items[] = {"B_Carryall_cbr", "B_Carryall_cbr"}; + name = "$STR_a3_cfgvehicleclasses_backpacks0"; + text = "$STR_a3_cfgvehicleclasses_backpacks0"; + }; + }; + }; + class Tank: LandVehicle { class ACE_Actions { class ACE_MainActions { @@ -432,6 +485,88 @@ class CfgVehicles { }; }; }; + class Tank_F; + class LT_01_base_F: Tank_F { + class GVAR(anims) { + class showBags { + phase = 0; + selections[] = {"vhc_bags"}; + items[] = {"B_Carryall_cbr"}; + name = "$STR_BACKPACK_CONTAINER_NAME"; + text = "$STR_BACKPACK_CONTAINER_NAME"; + }; + class showBags2: showBags { + selections[] = {"vhc_bags2"}; + }; + }; + }; + + class APC_Tracked_01_base_F: Tank_F { + class GVAR(anims); + }; + class B_APC_Tracked_01_base_F: APC_Tracked_01_base_F { + class GVAR(anims): GVAR(anims) { + class showBags { + phase = 0; + selections[] = {"vhc_bags"}; + positions[] = {"private _pos = _target selectionPosition 'vhc_bags'; _pos set [0, -(_pos select 0)]; _pos"}; // Mirror position to other side of vehicle + items[] = {"B_Carryall_cbr", "B_Carryall_cbr", "B_Carryall_cbr", "B_Carryall_cbr", "B_Carryall_cbr"}; + name = "$STR_a3_cfgvehicleclasses_backpacks0"; + text = "$STR_a3_cfgvehicleclasses_backpacks0"; + }; + }; + }; + class B_APC_Tracked_01_CRV_F: B_APC_Tracked_01_base_F { + class GVAR(anims): GVAR(anims) { + class showBags: showBags { + items[] = {"B_Carryall_cbr", "B_Carryall_cbr", "B_Carryall_cbr", "B_Carryall_cbr"}; + }; + }; + }; + + class APC_Tracked_02_base_F: Tank_F { + class GVAR(anims); + }; + class O_APC_Tracked_02_base_F: APC_Tracked_02_base_F {}; + class O_APC_Tracked_02_cannon_F: O_APC_Tracked_02_base_F { + class GVAR(anims): GVAR(anims) { + class showBags { + phase = 0; + selections[] = {"vhc_bags"}; + items[] = {"B_Carryall_cbr", "B_Carryall_cbr", "B_Carryall_cbr"}; + name = "$STR_a3_cfgvehicleclasses_backpacks0"; + text = "$STR_a3_cfgvehicleclasses_backpacks0"; + }; + }; + }; + + class APC_Tracked_03_base_F: Tank_F { + class GVAR(anims) { + class showBags { + phase = 0; + selections[] = {"vhc_bags"}; + items[] = {"B_Carryall_cbr", "B_Carryall_cbr"}; + name = "$STR_a3_cfgvehicleclasses_backpacks0"; + text = "$STR_a3_cfgvehicleclasses_backpacks0"; + }; + }; + }; + + class MBT_01_base_F: Tank_F { + class GVAR(anims); + }; + class B_MBT_01_base_F: MBT_01_base_F {}; + class B_MBT_01_cannon_F: B_MBT_01_base_F { + class GVAR(anims): GVAR(anims) { + class showBags { + phase = 0; + selections[] = {"vhc_bags"}; + items[] = {"B_Carryall_cbr", "B_Carryall_cbr", "B_Carryall_cbr", "B_Carryall_cbr", "B_Carryall_cbr", "B_Carryall_cbr"}; + name = "$STR_a3_cfgvehicleclasses_backpacks0"; + text = "$STR_a3_cfgvehicleclasses_backpacks0"; + }; + }; + }; class Motorcycle: LandVehicle { class ACE_Actions { diff --git a/addons/interaction/XEH_PREP.hpp b/addons/interaction/XEH_PREP.hpp index 554f903704..26d4cf4d00 100644 --- a/addons/interaction/XEH_PREP.hpp +++ b/addons/interaction/XEH_PREP.hpp @@ -54,4 +54,5 @@ PREP(push); // misc PREP(canFlip); +PREP(initAnimActions); PREP(replaceTerrainObject); diff --git a/addons/interaction/XEH_postInit.sqf b/addons/interaction/XEH_postInit.sqf index f461e2a770..dc1c167d7c 100644 --- a/addons/interaction/XEH_postInit.sqf +++ b/addons/interaction/XEH_postInit.sqf @@ -149,11 +149,20 @@ GVAR(isOpeningDoor) = false; ["isNotOnLadder", {getNumber (configFile >> "CfgMovesMaleSdr" >> "States" >> animationState (_this select 0) >> "ACE_isLadder") != 1}] call EFUNC(common,addCanInteractWithCondition); ["CBA_settingsInitialized", { + TRACE_2("settingsInitialized",GVAR(disableNegativeRating),GVAR(enableAnimActions)); + if (GVAR(disableNegativeRating)) then { player addEventHandler ["HandleRating", { (_this select 1) max 0 }]; }; + + if (!GVAR(enableAnimActions)) exitWith {}; + + // Don't add inherited anim actions (but actions are added to child classes) + { + [_x, "InitPost", LINKFUNC(initAnimActions), true, [], true] call CBA_fnc_addClassEventHandler; + } forEach (keys (uiNamespace getVariable QGVAR(animActionsClasses))); }] call CBA_fnc_addEventHandler; { @@ -162,7 +171,6 @@ GVAR(isOpeningDoor) = false; }] 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 diff --git a/addons/interaction/XEH_preInit.sqf b/addons/interaction/XEH_preInit.sqf index c5873bcfc9..ec73b62b1b 100644 --- a/addons/interaction/XEH_preInit.sqf +++ b/addons/interaction/XEH_preInit.sqf @@ -16,6 +16,7 @@ DFUNC(repair_Statement) = { // moved from config because of build problems }; if (hasInterface) then { + GVAR(initializedAnimClasses) = []; GVAR(replaceTerrainModels) = createHashMapFromArray call (uiNamespace getVariable QGVAR(cacheReplaceTerrainModels)); }; diff --git a/addons/interaction/XEH_preStart.sqf b/addons/interaction/XEH_preStart.sqf index 331b5c6d36..39da54b3b5 100644 --- a/addons/interaction/XEH_preStart.sqf +++ b/addons/interaction/XEH_preStart.sqf @@ -23,3 +23,13 @@ private _cacheReplaceTerrainModels = createHashMap; } forEach _replaceTerrainClasses; uiNamespace setVariable [QGVAR(cacheReplaceTerrainModels), compileFinal str _cacheReplaceTerrainModels]; + + +// Cache classes with anim actions +private _animActionsClasses = (QUOTE(isClass (_x >> QQGVAR(anims)) && {!isClass (inheritsFrom _x >> QQGVAR(anims))}) configClasses (configFile >> "CfgVehicles")); +_animActionsClasses = _animActionsClasses apply { configName _x }; +_animActionsClasses = _animActionsClasses select { + private _class = _x; + (_animActionsClasses findIf {(_class != _x) && {_class isKindOf _x}}) == -1 // filter classes that already have a parent in the list +}; +uiNamespace setVariable [QGVAR(animActionsClasses), compileFinal (_animActionsClasses createHashMapFromArray [])]; diff --git a/addons/interaction/functions/fnc_initAnimActions.sqf b/addons/interaction/functions/fnc_initAnimActions.sqf new file mode 100644 index 0000000000..673946a2e1 --- /dev/null +++ b/addons/interaction/functions/fnc_initAnimActions.sqf @@ -0,0 +1,194 @@ +#include "..\script_component.hpp" +/* + * Author: Dystopian + * Initializes object interactions based on animations. + * + * Arguments: + * 0: Target + * + * Return Value: + * None + * + * Example: + * cursorObject call ace_interaction_fnc_initAnimActions + * + * Public: No + */ + +params ["_object"]; + +private _class = typeOf _object; + +if (_class in GVAR(initializedAnimClasses)) exitWith {}; + +GVAR(initializedAnimClasses) pushBack _class; + +private _statement = { + params ["_target", "_player", "_params"]; + _params params ["_anim", "_phase", "_duration", "_text"]; + TRACE_5("statement",_target,_player,_anim,_phase,_duration); + + [ + _duration, + [_target, _player, _anim, _phase], + { + (_this select 0) params ["_target", "_player", "_anim", "_phase"]; + + private _items = _target getVariable [ + format [QGVAR(animsItems_%1), _anim], + getArray (configOf _target >> QGVAR(anims) >> _anim >> "items") + ]; + + // If 1 object was spawned in, consider it a success + private _success = false; + + if (_items isNotEqualTo []) then { + if (_items isEqualType "") then { + _items = [_items]; + }; + + private _weaponHolder = objNull; + + { + private _type = (_x call EFUNC(common,getItemType)) select 0; + + if (_type == "") then { + private _emptyPosAGL = []; + + // This covers testing vehicle stability and finding a safe position + for "_i" from 1 to 3 do { + _emptyPosAGL = [_target, _x, _player] call EFUNC(common,findUnloadPosition); + + if (_emptyPosAGL isNotEqualTo []) exitWith {}; + }; + + // If still no valid position, try the next item + if (_emptyPosAGL isEqualTo []) then { + [LELSTRING(common,NoRoomToUnload)] call EFUNC(common,displayTextStructured); + + continue; + }; + + private _object = createVehicle [_x, _emptyPosAGL, [], 0, "CAN_COLLIDE"]; + + if (!isNull _object) then { + // Prevent items from taking damage when unloaded + [_object, "blockDamage", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); + [EFUNC(common,statusEffect_set), [_object, "blockDamage", QUOTE(ADDON), false], 2] call CBA_fnc_waitAndExecute; + + _success = true; + } else { + WARNING_1("Failed to create object of type '%1'",_x); + }; + + continue; + }; + + // Functions/code below are guaranteed to spawn in objects + _success = true; + + // getItemType considers backpacks as weapons, so handle them first + if (getNumber (configFile >> "CfgVehicles" >> _x >> "isBackpack") == 1) then { + if (backpack _player == "") then { + _player addBackpackGlobal _x; + } else { + if (isNull _weaponHolder) then { + _weaponHolder = nearestObject [_player, "WeaponHolder"]; + + if (isNull _weaponHolder || {_player distance _weaponHolder > 2}) then { + _weaponHolder = createVehicle ["GroundWeaponHolder", [0, 0, 0], [], 0, "NONE"]; + _weaponHolder setPosASL getPosASL _player; + }; + }; + + _weaponHolder addBackpackCargoGlobal [_x, 1]; + }; + + continue; + }; + + switch (_type) do { + case "weapon": { + [_player, _x, true] call CBA_fnc_addWeapon; + }; + case "item": { + [_player, _x, true] call CBA_fnc_addItem; + }; + case "magazine": { + [_player, _x, -1, true] call CBA_fnc_addMagazine; + }; + }; + } forEach _items; + }; + + if (!_success) exitWith {}; + + _target animate [_anim, _phase, true]; + }, + {}, + _text, + { + (_this select 0) params ["_target", "", "_anim", "_phase"]; + + _target animationPhase _anim != _phase + }, + ["isNotSwimming"] + ] call EFUNC(common,progressBar); +}; + +private _condition = { + params ["_target", "_player", "_params"]; + _params params ["_anim", "_phase"]; + + _target animationPhase _anim != _phase + && {[_player, _target, ["isNotSwimming"]] call EFUNC(common,canInteractWith)} +}; + +private _config = configOf _object; + +{ + private _animConfig = _x; + private _anim = configName _animConfig; + + private _animationSourcesConfig = _config >> "AnimationSources" >> _anim; + + if !( + isClass _animationSourcesConfig // anim exist + && {0 != [_animationSourcesConfig >> "scope", "NUMBER", 1] call CBA_fnc_getConfigEntry} // anim not hidden + && {isNumber (_animationSourcesConfig >> "initPhase")} // anim correct (some CUP anims are inherited and cleared) + && {0 != [_animConfig >> "enabled", "NUMBER", 1] call CBA_fnc_getConfigEntry} // anim enabled + ) then {continue}; + + private _positions = []; + { + if (_x isEqualType "") then { + _positions pushBack compile _x; + } else { + _positions pushBack _x; + }; + } forEach getArray (_animConfig >> "positions"); + + _positions append getArray (_animConfig >> "selections"); + + if (_positions isEqualTo []) then { + ERROR_2("No action position for _class %1 anim %2",_class,_anim); + continue; + }; + + private _phase = [_animConfig >> "phase", "NUMBER", 1] call CBA_fnc_getConfigEntry; + private _name = [_animConfig >> "name", "TEXT", localize "str_a3_cfgactions_unmountitem0"] call CBA_fnc_getConfigEntry; + private _icon = [_animConfig >> "icon", "TEXT", "\A3\ui_f\data\igui\cfg\actions\take_ca.paa"] call CBA_fnc_getConfigEntry; + private _duration = [_animConfig >> "duration", "NUMBER", 10] call CBA_fnc_getConfigEntry; + private _text = getText (_animConfig >> "text"); + + { + private _action = [ + format [QGVAR(anim_%1_%2), _anim, _forEachIndex], + _name, _icon, _statement, _condition, {}, + [_anim, _phase, _duration, _text], + _x + ] call EFUNC(interact_menu,createAction); + [_class, 0, [], _action] call EFUNC(interact_menu,addActionToClass); + TRACE_3("add anim",_class,_anim,_x); + } forEach _positions; +} forEach configProperties [_config >> QGVAR(anims), "isClass _x"]; diff --git a/addons/interaction/initSettings.inc.sqf b/addons/interaction/initSettings.inc.sqf index 2cefb162a7..4adc5a6daf 100644 --- a/addons/interaction/initSettings.inc.sqf +++ b/addons/interaction/initSettings.inc.sqf @@ -38,6 +38,16 @@ true ] call CBA_fnc_addSetting; +[ + QGVAR(enableAnimActions), "CHECKBOX", + LSTRING(SettingAnimActionsName), + format ["ACE %1", LLSTRING(DisplayName)], + true, + true, + {[QGVAR(enableAnimActions), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart +] call CBA_fnc_addSetting; + [ QGVAR(interactWithTerrainObjects), "CHECKBOX", ["str_a3_modules_moduleomquest_defend_f_attributes_useterrainobject0", LSTRING(interactWithTerrainObjects_Description)], diff --git a/addons/interaction/stringtable.xml b/addons/interaction/stringtable.xml index 5b79a69e69..3d1daf9c3c 100644 --- a/addons/interaction/stringtable.xml +++ b/addons/interaction/stringtable.xml @@ -1324,5 +1324,9 @@ Advertencia: puede provocar que algunos objetos choquen con otros. Aviso: pode causar que alguns objetos colidam com outros. + + Interaction with animations + Взаимодействие с анимациями + diff --git a/addons/refuel/CfgVehicles.hpp b/addons/refuel/CfgVehicles.hpp index 44575a141d..dbbcaf04d1 100644 --- a/addons/refuel/CfgVehicles.hpp +++ b/addons/refuel/CfgVehicles.hpp @@ -238,6 +238,20 @@ class CfgVehicles { // Patria = LAV GVAR(fuelCapacity) = 269; }; + class APC_Wheeled_02_base_F: Wheeled_APC_F { + class EGVAR(interaction,anims); + }; + class APC_Wheeled_02_base_v2_F: APC_Wheeled_02_base_F { + class EGVAR(interaction,anims): EGVAR(interaction,anims) { + class showCanisters { + phase = 0; + positions[] = {{-1.188, -3.87, -0.769}, {1.638, -3.87, -0.769}}; + items[] = {"Land_CanisterFuel_F", "Land_CanisterFuel_F", "Land_CanisterFuel_F", "Land_CanisterFuel_F"}; + name = CSTRING(TakeFuelCanister); + text = CSTRING(TakeFuelCanisterAction); + }; + }; + }; class Truck_F: Car_F { GVAR(fuelCapacity) = 400; @@ -308,12 +322,14 @@ class CfgVehicles { class MBT_01_base_F: Tank_F { // Merkava IV GVAR(fuelCapacity) = 1400; + class EGVAR(interaction,anims); }; class MBT_02_base_F: Tank_F { // T100 Black Eagle // Assuming T80 GVAR(fuelCapacity) = 1100; + class EGVAR(interaction,anims); }; class MBT_03_base_F: Tank_F { @@ -324,11 +340,37 @@ class CfgVehicles { class MBT_01_arty_base_F: MBT_01_base_F { // Assuming similar 2S3 GVAR(fuelCapacity) = 830; + + class EGVAR(interaction,anims): EGVAR(interaction,anims) { + class showCanisters { + phase = 0; + // Rotate interactions with turret rotation + positions[] = { + "[0, -2.5, 0] vectorAdd ([[1.6, -2.4, -0.3], [0, 0, 1], deg (_target animationPhase 'MainTurret')] call CBA_fnc_vectRotate3D)", + "[0, -2.5, 0] vectorAdd ([[1.8, 0.55, -0.7], [0, 0, 1], deg (_target animationPhase 'MainTurret')] call CBA_fnc_vectRotate3D)", + "[0, -2.5, 0] vectorAdd ([[-1.8, 0.55, -0.7], [0, 0, 1], deg (_target animationPhase 'MainTurret')] call CBA_fnc_vectRotate3D)" + }; + items[] = {"Land_CanisterFuel_F", "Land_CanisterFuel_F", "Land_CanisterFuel_F", "Land_CanisterFuel_F", "Land_CanisterFuel_F", "Land_CanisterFuel_F", "Land_CanisterFuel_F"}; + name = CSTRING(TakeFuelCanister); + text = CSTRING(TakeFuelCanisterAction); + }; + }; }; class MBT_02_arty_base_F: MBT_02_base_F { // Assuming similar 2S3 GVAR(fuelCapacity) = 830; + + class EGVAR(interaction,anims): EGVAR(interaction,anims) { + class showCanisters { + phase = 0; + // Rotate interactions with turret rotation + positions[] = {"[0, -2.1, 0] vectorAdd ([[1.6, -2.65, -0.3], [0, 0, 1], deg (_target animationPhase 'MainTurret')] call CBA_fnc_vectRotate3D)"}; + items[] = {"Land_CanisterFuel_F"}; + name = CSTRING(TakeFuelCanister); + text = CSTRING(TakeFuelCanisterAction); + }; + }; }; class Heli_Light_02_base_F: Helicopter_Base_H { diff --git a/addons/repair/CfgVehicles.hpp b/addons/repair/CfgVehicles.hpp index ce74737b76..6172b72679 100644 --- a/addons/repair/CfgVehicles.hpp +++ b/addons/repair/CfgVehicles.hpp @@ -429,9 +429,33 @@ class CfgVehicles { GVAR(hitpointPositions)[] = {{"HitTurret", {0,-2,0}}}; }; + class Tank_F; + class APC_Tracked_02_base_F: Tank_F { + class EGVAR(interaction,anims) { + class showTracks { + phase = 0; + positions[] = {{-1.7, -3.875, -0.7}, {1.7, -3.875, -0.7}}; + items[] = {"ACE_Track", "ACE_Track", "ACE_Track"}; + name = CSTRING(RemoveTrack); + text = CSTRING(RemovingTrack); + }; + }; + }; + class Car_F: Car { class HitPoints; }; + class Offroad_02_base_F: Car_F { + class EGVAR(interaction,anims) { + class hideSpareWheel { + selections[] = {"spare_wheel"}; + items[] = {"ACE_Wheel"}; + name = CSTRING(RemoveWheel); + text = CSTRING(RemovingWheel); + }; + }; + }; + class Truck_F: Car_F { class HitPoints: HitPoints { class HitLBWheel; @@ -449,10 +473,43 @@ class CfgVehicles { }; }; + class Truck_01_viv_base_F; + class Truck_01_cargo_base_F: Truck_01_viv_base_F { + class EGVAR(interaction,anims) { + class Tyre1_hide { + selections[] = {"tyre1_hide"}; + items[] = {"ACE_Wheel"}; + name = CSTRING(RemoveWheel); + text = CSTRING(RemovingWheel); + }; + }; + }; + class Truck_01_flatbed_base_F: Truck_01_viv_base_F { + class EGVAR(interaction,anims) { + class Tyre1_hide { + selections[] = {"tyre1_hide"}; + items[] = {"ACE_Wheel"}; + name = CSTRING(RemoveWheel); + text = CSTRING(RemovingWheel); + }; + }; + }; + class Quadbike_01_base_F: Car_F { GVAR(hitpointPositions)[] = { {"HitEngine", {0, 0.5, -0.7}}, {"HitFuel", {0, 0, -0.5}} }; }; class Hatchback_01_base_F: Car_F { GVAR(hitpointPositions)[] = {{"HitBody", {0, 0.7, -0.5}}, {"HitFuel", {0, -1.75, -0.75}}}; }; + + class Van_02_base_F: Truck_F { + class EGVAR(interaction,anims) { + class spare_tyre_hide { + positions[] = {"[[-1.2, -3.7, -0.4], [-0.45, -3.5, -0.4]] select (_target animationPhase 'Door_4_source' == 0)"}; + items[] = {"ACE_Wheel"}; + name = CSTRING(RemoveWheel); + text = CSTRING(RemovingWheel); + }; + }; + }; }; diff --git a/addons/trenches/CfgVehicles.hpp b/addons/trenches/CfgVehicles.hpp index bec66e2e64..554a75149b 100644 --- a/addons/trenches/CfgVehicles.hpp +++ b/addons/trenches/CfgVehicles.hpp @@ -106,4 +106,44 @@ class CfgVehicles { MACRO_ADDITEM(ACE_EntrenchingTool,50); }; }; + + class Wheeled_APC_F; + class APC_Wheeled_02_base_F: Wheeled_APC_F { + class EGVAR(interaction,anims); + }; + class APC_Wheeled_02_base_v2_F: APC_Wheeled_02_base_F { + class EGVAR(interaction,anims): EGVAR(interaction,anims) { + class showTools { + phase = 0; + positions[] = {{-1.108, -1.47, -0.769}}; + items[] = {"ACE_EntrenchingTool"}; + name = CSTRING(EntrenchingToolName); + text = CSTRING(EntrenchingToolName); + }; + }; + }; + class APC_Wheeled_03_base_F: Wheeled_APC_F { + class EGVAR(interaction,anims) { + class showTools { + phase = 0; + positions[] = {{-0.9, -3, -0.5}}; + items[] = {"ACE_EntrenchingTool"}; + name = CSTRING(EntrenchingToolName); + text = CSTRING(EntrenchingToolName); + }; + }; + }; + + class Tank_F; + class LT_01_base_F: Tank_F { + class EGVAR(interaction,anims) { + class showTools { + phase = 0; + positions[] = {{0.6, 0, -0.3}}; + items[] = {"ACE_EntrenchingTool"}; + name = CSTRING(EntrenchingToolName); + text = CSTRING(EntrenchingToolName); + }; + }; + }; }; From 0b4029b12f28e067cf9553406698683cefbb7d9d Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Sun, 11 Aug 2024 02:19:35 -0500 Subject: [PATCH 196/290] Medical AI - AI will remove tourniquets (#10166) * Medical AI - AI will remove tourniquets * Medical AI - Improve tourniquet removal (for #10166) (#10178) * Fixes & tweaks - Have AI remove tourniquets ASAP - Fixed bug where AI would not remove tourniquet, because it didn't have any bandages - Allowed for more multitasking * Allow healer to administer morphine if out of bandages * Remove TODO comment * Allow AI to remove tourniquets from limbs with no open wounds * Update addons/medical_ai/functions/fnc_healingLogic.sqf --------- Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> --- .../medical_ai/functions/fnc_healingLogic.sqf | 135 +++++++++++------- addons/medical_ai/functions/fnc_isInjured.sqf | 1 + 2 files changed, 86 insertions(+), 50 deletions(-) diff --git a/addons/medical_ai/functions/fnc_healingLogic.sqf b/addons/medical_ai/functions/fnc_healingLogic.sqf index f5d13f7410..84b05327a5 100644 --- a/addons/medical_ai/functions/fnc_healingLogic.sqf +++ b/addons/medical_ai/functions/fnc_healingLogic.sqf @@ -16,9 +16,6 @@ * Public: No */ -// TODO: Add AI tourniquet behaviour -// For now, AI handle player or otherwise scripted tourniquets only - params ["_healer", "_target"]; (_healer getVariable [QGVAR(currentTreatment), [-1]]) params ["_finishTime", "_treatmentTarget", "_treatmentEvent", "_treatmentArgs", "_treatmentItem"]; @@ -87,47 +84,68 @@ if (_finishTime > 0) exitWith { }; }; -// Find a suitable limb (no tourniquets) for injecting and giving IVs +// Bandage a limb up, then remove the tourniquet on it +private _fnc_removeTourniquet = { + params [["_removeAllTourniquets", false]]; + + // Ignore head & torso if not removing all tourniquets (= administering drugs/IVs) + private _offset = [2, 0] select _removeAllTourniquets; + + // Bandage the least bleeding body part + private _bodyPartBleeding = []; + _bodyPartBleeding resize [[4, 6] select _removeAllTourniquets, -1]; + + { + // Ignore head and torso, if only looking for place to administer drugs/IVs + private _partIndex = (ALL_BODY_PARTS find _x) - _offset; + + if (_partIndex >= 0 && {_tourniquets select _partIndex != 0}) then { + { + _x params ["", "_amountOf", "_bleeding"]; + + // max 0, to set the baseline to 0, as body parts with no wounds are marked with -1 + _bodyPartBleeding set [_partIndex, ((_bodyPartBleeding select _partIndex) max 0) + (_amountOf * _bleeding)]; + } forEach _y; + }; + } forEach GET_OPEN_WOUNDS(_target); + + // If there are no open wounds, check if there are tourniquets on limbs with no open wounds (stitched or fully healed), + // as we know there have to be tourniquets at this point + if (_bodyPartBleeding findIf {_x != -1} == -1) then { + _bodyPartBleeding set [_tourniquets findIf {_x != 0}, 0]; + }; + + // Ignore body parts that don't have open wounds (-1) + private _minBodyPartBleeding = selectMin (_bodyPartBleeding select {_x != -1}); + private _selection = ALL_BODY_PARTS select ((_bodyPartBleeding find _minBodyPartBleeding) + _offset); + + // If not bleeding anymore, remove the tourniquet + if (_minBodyPartBleeding == 0) exitWith { + _treatmentEvent = QGVAR(tourniquetRemove); + _treatmentTime = 7; + _treatmentArgs = [_healer, _target, _selection]; + }; + + // If no bandages available, wait + // If check is done at the start of the scope, it will miss the edge case where the unit ran out of bandages just as they finished bandaging tourniqueted body part + if !(([_healer, "@bandage"] call FUNC(itemCheck)) # 0) exitWith { + _treatmentEvent = "#waitForBandages"; // TODO: Medic can move onto another patient/should be flagged as out of supplies + }; + + // Otherwise keep bandaging + _treatmentEvent = QEGVAR(medical_treatment,bandageLocal); + _treatmentTime = 5; + _treatmentArgs = [_target, _selection, "FieldDressing"]; + _treatmentItem = "@bandage"; +}; + +// Find a suitable limb (no tourniquets) for adminstering drugs/IVs private _fnc_findNoTourniquet = { private _bodyPart = ""; // If all limbs have tourniquets, find the least damaged limb and try to bandage it if ((_tourniquets select [2]) find 0 == -1) then { - // If no bandages available, wait - if !(([_healer, "@bandage"] call FUNC(itemCheck)) # 0) exitWith { - _treatmentEvent = "#waitForNonTourniquetedLimb"; // TODO: Medic can move onto another patient/should be flagged as out of supplies - }; - - // Bandage the least bleeding body part - private _bodyPartBleeding = [0, 0, 0, 0]; - - { - // Ignore head and torso - private _partIndex = (ALL_BODY_PARTS find _x) - 2; - - if (_partIndex >= 0) then { - { - _x params ["", "_amountOf", "_bleeding"]; - _bodyPartBleeding set [_partIndex, (_bodyPartBleeding select _partIndex) + (_amountOf * _bleeding)]; - } forEach _y; - }; - } forEach GET_OPEN_WOUNDS(_target); - - private _minBodyPartBleeding = selectMin _bodyPartBleeding; - private _selection = ALL_BODY_PARTS select ((_bodyPartBleeding find _minBodyPartBleeding) + 2); - - // If not bleeding anymore, remove the tourniquet - if (_minBodyPartBleeding == 0) exitWith { - _treatmentEvent = QGVAR(tourniquetRemove); - _treatmentTime = 7; - _treatmentArgs = [_healer, _target, _selection]; - }; - - // Otherwise keep bandaging - _treatmentEvent = QEGVAR(medical_treatment,bandageLocal); - _treatmentTime = 5; - _treatmentArgs = [_target, _selection, "FieldDressing"]; - _treatmentItem = "@bandage"; + call _fnc_removeTourniquet; } else { // Select a random non-tourniqueted limb otherwise private _bodyParts = ["leftarm", "rightarm", "leftleg", "rightleg"]; @@ -270,7 +288,7 @@ if (true) then { // Wait until the injured has enough blood before administering drugs // (_needsIV && !_canGiveIV), but _canGiveIV is false here, otherwise IV would be given - if (_needsIV || {_treatmentEvent == "#waitForIV"}) exitWith { + if (_needsIV || {_doCPR && {_treatmentEvent == "#waitForIV"}}) exitWith { // If injured is in cardiac arrest and the healer is doing nothing else, start CPR if (_doCPR) exitWith { _treatmentEvent = QEGVAR(medical_treatment,cprLocal); // TODO: Medic remains in this loop until injured is given enough IVs or dies @@ -284,23 +302,30 @@ if (true) then { }; }; - if ((count (_target getVariable [VAR_MEDICATIONS, []])) >= 6) exitWith { + // These checks are not exitWith, so that the medic can try to bandage up tourniqueted body parts + if ((count (_target getVariable [VAR_MEDICATIONS, []])) >= 6) then { _treatmentEvent = "#tooManyMeds"; // TODO: Medic can move onto another patient }; private _heartRate = GET_HEART_RATE(_target); + private _canGiveEpinephrine = !(_treatmentEvent in ["#tooManyMeds", "#waitForIV"]) && + {IS_UNCONSCIOUS(_target) || {_heartRate <= 50}} && + {([_healer, "epinephrine"] call FUNC(itemCheck)) # 0}; - if ( - (IS_UNCONSCIOUS(_target) || {_heartRate <= 50}) && - {([_healer, "epinephrine"] call FUNC(itemCheck)) # 0} - ) exitWith { - if (CBA_missionTime < (_target getVariable [QGVAR(nextEpinephrine), -1])) exitWith { + // This allows for some multitasking + if (_canGiveEpinephrine) then { + if (CBA_missionTime < (_target getVariable [QGVAR(nextEpinephrine), -1])) then { _treatmentEvent = "#waitForEpinephrineToTakeEffect"; - }; - if (_heartRate > 180) exitWith { - _treatmentEvent = "#waitForSlowerHeart"; // TODO: Medic can move onto another patient, after X amount of time of high HR + _canGiveEpinephrine = false; }; + if (_heartRate > 180) then { + _treatmentEvent = "#waitForSlowerHeart"; // TODO: Medic can move onto another patient, after X amount of time of high HR + _canGiveEpinephrine = false; + }; + }; + + if (_canGiveEpinephrine) exitWith { // If all limbs are tourniqueted, bandage the one with the least amount of wounds, so that the tourniquet can be removed _bodyPart = call _fnc_findNoTourniquet; @@ -313,8 +338,18 @@ if (true) then { _treatmentItem = "epinephrine"; }; + // Remove all remaining tourniquets by bandaging all body parts + if (_tourniquets isNotEqualTo DEFAULT_TOURNIQUET_VALUES) then { + true call _fnc_removeTourniquet; + }; + + // If the healer can bandage or remove tourniquets, do that + if (_treatmentEvent in [QEGVAR(medical_treatment,bandageLocal), QGVAR(tourniquetRemove)]) exitWith {}; + + // Otherwise, if the healer is either done or out of bandages, continue if ( - ((GET_PAIN_PERCEIVED(_target) > 0.25) || {_heartRate >= 180}) && + !(_treatmentEvent in ["#tooManyMeds", "#waitForIV"]) && + {(GET_PAIN_PERCEIVED(_target) > 0.25) || {_heartRate >= 180}} && {([_healer, "morphine"] call FUNC(itemCheck)) # 0} ) exitWith { if (CBA_missionTime < (_target getVariable [QGVAR(nextMorphine), -1])) exitWith { diff --git a/addons/medical_ai/functions/fnc_isInjured.sqf b/addons/medical_ai/functions/fnc_isInjured.sqf index 51ae37caae..2a4b689514 100644 --- a/addons/medical_ai/functions/fnc_isInjured.sqf +++ b/addons/medical_ai/functions/fnc_isInjured.sqf @@ -24,3 +24,4 @@ if !(alive _this) exitWith {false}; private _fractures = GET_FRACTURES(_this); ((_fractures select 4) == 1) || {(_fractures select 5) == 1} } +|| { GET_TOURNIQUETS(_this) isNotEqualTo DEFAULT_TOURNIQUET_VALUES } From ff31bc69a8406934c53126bf34ba759890bbd01f Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sun, 11 Aug 2024 17:06:59 +0200 Subject: [PATCH 197/290] Medical AI - Prevent medics from being blocked on treatments they can't complete (#10167) * Add tourniquet support for Medical AI * Stop blocking start * Renamed states, condensed `canHeal` * Renamed `tooManyMeds` state * Update addons/medical_ai/functions/fnc_healUnit.sqf Co-authored-by: PabstMirror * Change states to use singular, add states for autoinjectors & splint --------- Co-authored-by: PabstMirror --- addons/medical_ai/functions/fnc_healUnit.sqf | 8 ++- .../medical_ai/functions/fnc_healingLogic.sqf | 61 +++++++++++-------- 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/addons/medical_ai/functions/fnc_healUnit.sqf b/addons/medical_ai/functions/fnc_healUnit.sqf index 319d5533b1..6d94749d1f 100644 --- a/addons/medical_ai/functions/fnc_healUnit.sqf +++ b/addons/medical_ai/functions/fnc_healUnit.sqf @@ -27,7 +27,13 @@ private _healQueue = _this getVariable [QGVAR(healQueue), []]; private _target = _healQueue param [0, objNull]; // If unit died or was healed, be lazy and wait for the next tick -if (!alive _target || {!(_target call FUNC(isInjured))}) exitWith { +// If the unit can't be healed, go to the next unit to be healed +if (!alive _target || {!(_target call FUNC(isInjured))} || { + private _treatmentEvent = (_this getVariable [QGVAR(currentTreatment), []]) param [2, ""]; + + // Target still needs healing, but the healer doesn't have the required items (only happens if GVAR(requireItems) != 0) or needs to wait + (_treatmentEvent select [0, 6]) == "#needs" +}) exitWith { _this forceSpeed -1; _target forceSpeed -1; _healQueue deleteAt 0; diff --git a/addons/medical_ai/functions/fnc_healingLogic.sqf b/addons/medical_ai/functions/fnc_healingLogic.sqf index 84b05327a5..9c7ce1c847 100644 --- a/addons/medical_ai/functions/fnc_healingLogic.sqf +++ b/addons/medical_ai/functions/fnc_healingLogic.sqf @@ -1,7 +1,9 @@ #include "..\script_component.hpp" /* - * Author: BaerMitUmlaut, PabstMirror + * Author: BaerMitUmlaut, PabstMirror, johnb43 * Applies healing to target. + * States that contain "needs" are states in which the medic is blocked, either temporairly (HR too high/low) or until resupplied, from treating. + * States that contain "wait" are states where the medic waits temporairly before continuing treatment. * * Arguments: * 0: Healer @@ -129,7 +131,7 @@ private _fnc_removeTourniquet = { // If no bandages available, wait // If check is done at the start of the scope, it will miss the edge case where the unit ran out of bandages just as they finished bandaging tourniqueted body part if !(([_healer, "@bandage"] call FUNC(itemCheck)) # 0) exitWith { - _treatmentEvent = "#waitForBandages"; // TODO: Medic can move onto another patient/should be flagged as out of supplies + _treatmentEvent = "#needsBandage"; }; // Otherwise keep bandaging @@ -177,7 +179,7 @@ if (true) then { // Patient is not worth treating if bloodloss can't be stopped if !(_hasBandage || _hasTourniquet) exitWith { - _treatmentEvent = "#cantStabilise"; // TODO: Medic should be flagged as out of supplies + _treatmentEvent = "#needsBandageOrTourniquet"; }; // Bandage the heaviest bleeding body part @@ -264,25 +266,20 @@ if (true) then { _treatmentItem = "@iv"; }; - private _fractures = GET_FRACTURES(_target); + // Leg fractures + private _index = (GET_FRACTURES(_target) select [4, 2]) find 1; if ( - ((_fractures select 4) == 1) && - {([_healer, "splint"] call FUNC(itemCheck)) # 0} + _index != -1 && { + // In case the unit doesn't have a splint, set state here + _treatmentEvent = "#needsSplint"; + + ([_healer, "splint"] call FUNC(itemCheck)) # 0 + } ) exitWith { _treatmentEvent = QEGVAR(medical_treatment,splintLocal); _treatmentTime = 6; - _treatmentArgs = [_healer, _target, "leftleg"]; - _treatmentItem = "splint"; - }; - - if ( - ((_fractures select 5) == 1) && - {([_healer, "splint"] call FUNC(itemCheck)) # 0} - ) exitWith { - _treatmentEvent = QEGVAR(medical_treatment,splintLocal); - _treatmentTime = 6; - _treatmentArgs = [_healer, _target, "rightleg"]; + _treatmentArgs = [_healer, _target, ALL_BODY_PARTS select (_index + 4)]; _treatmentItem = "splint"; }; @@ -291,26 +288,32 @@ if (true) then { if (_needsIV || {_doCPR && {_treatmentEvent == "#waitForIV"}}) exitWith { // If injured is in cardiac arrest and the healer is doing nothing else, start CPR if (_doCPR) exitWith { - _treatmentEvent = QEGVAR(medical_treatment,cprLocal); // TODO: Medic remains in this loop until injured is given enough IVs or dies + // Medic remains in this loop until injured is given enough IVs or dies + _treatmentEvent = QEGVAR(medical_treatment,cprLocal); _treatmentArgs = [_healer, _target]; _treatmentTime = 15; }; // If the injured needs IVs, but healer can't give it to them, have healder wait if (_needsIV) exitWith { - _treatmentEvent = "#needsIV"; // TODO: Medic can move onto another patient + _treatmentEvent = "#needsIV"; }; }; // These checks are not exitWith, so that the medic can try to bandage up tourniqueted body parts if ((count (_target getVariable [VAR_MEDICATIONS, []])) >= 6) then { - _treatmentEvent = "#tooManyMeds"; // TODO: Medic can move onto another patient + _treatmentEvent = "#needsFewerMeds"; }; private _heartRate = GET_HEART_RATE(_target); - private _canGiveEpinephrine = !(_treatmentEvent in ["#tooManyMeds", "#waitForIV"]) && + private _canGiveEpinephrine = !(_treatmentEvent in ["#needsFewerMeds", "#waitForIV"]) && {IS_UNCONSCIOUS(_target) || {_heartRate <= 50}} && - {([_healer, "epinephrine"] call FUNC(itemCheck)) # 0}; + { + // In case the unit doesn't have a epinephrine injector, set state here + _treatmentEvent = "#needsEpinephrine"; + + ([_healer, "epinephrine"] call FUNC(itemCheck)) # 0 + }; // This allows for some multitasking if (_canGiveEpinephrine) then { @@ -320,7 +323,7 @@ if (true) then { }; if (_heartRate > 180) then { - _treatmentEvent = "#waitForSlowerHeart"; // TODO: Medic can move onto another patient, after X amount of time of high HR + _treatmentEvent = "#needsSlowerHeart"; _canGiveEpinephrine = false; }; }; @@ -348,15 +351,21 @@ if (true) then { // Otherwise, if the healer is either done or out of bandages, continue if ( - !(_treatmentEvent in ["#tooManyMeds", "#waitForIV"]) && + !(_treatmentEvent in ["#needsFewerMeds", "#waitForIV"]) && {(GET_PAIN_PERCEIVED(_target) > 0.25) || {_heartRate >= 180}} && - {([_healer, "morphine"] call FUNC(itemCheck)) # 0} + { + // In case the unit doesn't have a morphine injector, set state here + _treatmentEvent = "#needsMorphine"; + + ([_healer, "morphine"] call FUNC(itemCheck)) # 0 + } ) exitWith { if (CBA_missionTime < (_target getVariable [QGVAR(nextMorphine), -1])) exitWith { _treatmentEvent = "#waitForMorphineToTakeEffect"; }; + if (_heartRate < 60) exitWith { - _treatmentEvent = "#waitForFasterHeart"; // TODO: Medic can move onto another patient, after X amount of time of low HR + _treatmentEvent = "#needsFasterHeart"; }; // If all limbs are tourniqueted, bandage the one with the least amount of wounds, so that the tourniquet can be removed From b7f48a912f44d4ec56b0103f976f0fca465faa0f Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sun, 11 Aug 2024 17:08:50 +0200 Subject: [PATCH 198/290] IR Light - Fix bad item replacements and switching to primary weapons (#10119) * Fix bad item replacements and switching to primary weapons * Update addons/irlight/functions/fnc_initItemContextMenu.sqf * Update fnc_initItemContextMenu.sqf * Remove unused funtions * Various fixes/tweaks - Added a weapon parameter to `switchAttachmentMode` - Made `switchPersistentLaser` take pointer switching into account - Fixed IR light attachments being added to the wrong weapon --- .../functions/fnc_switchPersistentLaser.sqf | 12 +++--- addons/irlight/XEH_PREP.hpp | 2 - addons/irlight/XEH_postInit.sqf | 43 +++++++++---------- .../irlight/functions/fnc_getGlowOffset.sqf | 41 ------------------ .../functions/fnc_initItemContextMenu.sqf | 38 ++++++++-------- .../irlight/functions/fnc_onLightToggled.sqf | 36 ---------------- 6 files changed, 48 insertions(+), 124 deletions(-) delete mode 100644 addons/irlight/functions/fnc_getGlowOffset.sqf delete mode 100644 addons/irlight/functions/fnc_onLightToggled.sqf diff --git a/addons/common/functions/fnc_switchPersistentLaser.sqf b/addons/common/functions/fnc_switchPersistentLaser.sqf index d258284edb..79c0e91f72 100644 --- a/addons/common/functions/fnc_switchPersistentLaser.sqf +++ b/addons/common/functions/fnc_switchPersistentLaser.sqf @@ -54,12 +54,14 @@ private _fnc_getLightLaserState = { if (_weaponIndex == -1) exitWith {}; // Light/laser state only changes in the next frame + // However, as by default changing attachment modes is CTRL + L, the vanilla EH triggers when lights are bound to L (even despite CBA intercepting keystroke) + // Therefore, add an extra frame of delay, after which the previous laser state will have been restored [{ ACE_player setVariable [ QGVAR(laserEnabled_) + str (_this select 1), ACE_player isIRLaserOn (_this select 0) || {ACE_player isFlashlightOn (_this select 0)} ]; - }, [_currentWeapon, _weaponIndex]] call CBA_fnc_execNextFrame; + }, [_currentWeapon, _weaponIndex], 2] call CBA_fnc_execAfterNFrames; }; // Get current weapon light/laser state @@ -68,14 +70,14 @@ call _fnc_getLightLaserState; // Update state every time it's changed GVAR(laserKeyDownEH) = addUserActionEventHandler ["headlights", "Activate", _fnc_getLightLaserState]; -// Dropping weapons turns off lights/lasers -GVAR(lastWeapons) = [primaryWeapon ACE_player, handgunWeapon ACE_player, secondaryWeapon ACE_player]; +// Dropping weapons, as well as switching light/laser attachments turns off lights/lasers +GVAR(lastWeapons) = (getUnitLoadout ACE_player) select [0, 3]; // Monitor weapon addition/removal here GVAR(laserLoadoutEH) = ["loadout", { - params ["_unit"]; + params ["_unit", "_loadout"]; - private _weapons = [primaryWeapon _unit, handgunWeapon _unit, secondaryWeapon _unit]; + private _weapons = _loadout select [0, 3]; if (_weapons isEqualTo GVAR(lastWeapons)) exitWith {}; diff --git a/addons/irlight/XEH_PREP.hpp b/addons/irlight/XEH_PREP.hpp index db1a29d22e..83c619aab8 100644 --- a/addons/irlight/XEH_PREP.hpp +++ b/addons/irlight/XEH_PREP.hpp @@ -1,3 +1 @@ -PREP(getGlowOffset); PREP(initItemContextMenu); -PREP(onLightToggled); diff --git a/addons/irlight/XEH_postInit.sqf b/addons/irlight/XEH_postInit.sqf index d95186f07b..77b98936c1 100644 --- a/addons/irlight/XEH_postInit.sqf +++ b/addons/irlight/XEH_postInit.sqf @@ -1,30 +1,27 @@ #include "script_component.hpp" -[] call FUNC(initItemContextMenu); - -addUserActionEventHandler ["headlights", "Deactivate", LINKFUNC(onLightToggled)]; +call FUNC(initItemContextMenu); ["ACE3 Equipment", QGVAR(hold), LLSTRING(MomentarySwitch), { - ACE_player action ["GunLightOn", ACE_player]; - ACE_player action ["IRLaserOn", ACE_player]; - [] call FUNC(onLightToggled); + if !(ACE_player call CBA_fnc_canUseWeapon) exitWith {}; + + // Save current weapon state to reapply later + private _weaponState = (weaponState ACE_player) select [0, 3]; + + action ["GunLightOn", ACE_player]; + action ["IRLaserOn", ACE_player]; + + ACE_player selectWeapon _weaponState; + true }, { - ACE_player action ["GunLightOff", ACE_player]; - ACE_player action ["IRLaserOff", ACE_player]; - [] call FUNC(onLightToggled); - true + if !(ACE_player call CBA_fnc_canUseWeapon) exitWith {}; + + // Save current weapon state to reapply later + private _weaponState = (weaponState ACE_player) select [0, 3]; + + action ["GunLightOff", ACE_player]; + action ["IRLaserOff", ACE_player]; + + ACE_player selectWeapon _weaponState; }] call CBA_fnc_addKeybind; - -["CBA_attachmentSwitched", { - params ["", "", "_item"]; - - private _substr = _item select [0, 8]; - if ( - ACE_player getVariable [QGVAR(isTurnedOn), false] - && {_substr == "ACE_SPIR" || {_substr == "ACE_DBAL"}} - ) then { - ACE_player action ["GunLightOn", ACE_player]; - ACE_player action ["IRLaserOn", ACE_player]; - }; -}] call CBA_fnc_addEventHandler; diff --git a/addons/irlight/functions/fnc_getGlowOffset.sqf b/addons/irlight/functions/fnc_getGlowOffset.sqf deleted file mode 100644 index 613e551111..0000000000 --- a/addons/irlight/functions/fnc_getGlowOffset.sqf +++ /dev/null @@ -1,41 +0,0 @@ -#include "..\script_component.hpp" -/* - * Author: BaerMitUmlaut - * Gets the player model offset of the IR laser origin. - * Currently unused, see onLightToggled. - * - * Arguments: - * None - * - * Return Value: - * None - * - * Example: - * [] call ace_irlight_fnc_getGlowOffset - * - * Public: No - */ - -if (isNil QGVAR(offsetCache)) then { - GVAR(offsetCache) = createHashMap; -}; - -private _weapon = currentWeapon ACE_player; -private _laser = ((weaponsItems ACE_player) select {_x#0 == _weapon})#0#2; - -GVAR(offsetCache) getOrDefaultCall [[_weapon, _laser], { - private _model = getText (configFile >> "CfgWeapons" >> _weapon >> "model"); - private _dummy = createSimpleObject [_model, [0, 0, 0], true]; - private _proxyOffset = _dummy selectionPosition ["\a3\data_f\proxies\weapon_slots\SIDE.001", 1]; - _proxyOffset = [_proxyOffset#1, _proxyOffset#0 * -1, _proxyOffset#2]; - deleteVehicle _dummy; - - _model = getText (configFile >> "CfgWeapons" >> _laser >> "model"); - _dummy = createSimpleObject [_model, [0, 0, 0], true]; - private _selection = getText (configFile >> "CfgWeapons" >> _laser >> "ItemInfo" >> "Pointer" >> "irLaserPos"); - private _laserOffset = _dummy selectionPosition [_selection, "Memory"]; - _laserOffset = [_laserOffset#1, _laserOffset#0 * -1, _laserOffset#2 * -1]; - deleteVehicle _dummy; - - _proxyOffset vectorAdd _laserOffset -}, true]; diff --git a/addons/irlight/functions/fnc_initItemContextMenu.sqf b/addons/irlight/functions/fnc_initItemContextMenu.sqf index fa75eba77b..75a9508b18 100644 --- a/addons/irlight/functions/fnc_initItemContextMenu.sqf +++ b/addons/irlight/functions/fnc_initItemContextMenu.sqf @@ -10,7 +10,7 @@ * None * * Example: - * [] call ace_irlight_fnc_initItemContextMenu + * call ace_irlight_fnc_initItemContextMenu * * Public: No */ @@ -19,30 +19,34 @@ _x params ["_variant", "_displayName"]; [ - "ACE_DBAL_A3_Red", "POINTER", _displayName, [], "", { + "ACE_DBAL_A3_Red", + "POINTER", + _displayName, + [], + "", + { params ["", "", "_item", "", "_variant"]; private _baseClass = getText (configFile >> "CfgWeapons" >> _item >> "baseWeapon"); _item != _baseClass + _variant }, { - params ["", "", "_item", "", "_variant"]; + params ["_unit", "", "_item", "_slot", "_variant"]; + + private _weapon = switch (_slot) do { + case "RIFLE_POINTER": {primaryWeapon _unit}; + case "LAUNCHER_POINTER": {secondaryWeapon _unit}; + case "PISTOL_POINTER": {handgunWeapon _unit}; + default {""}; + }; + + if (_weapon == "") exitWith {}; private _baseClass = getText (configFile >> "CfgWeapons" >> _item >> "baseWeapon"); - ACE_player removePrimaryWeaponItem _item; - ACE_player addPrimaryWeaponItem (_baseClass + _variant); - playSound "click"; - - if (_turnedOn) then { - // Force update of flashlight - ACE_player action ["GunLightOff", ACE_player]; - - { - ACE_player action ["GunLightOn", ACE_player]; - ACE_player action ["IRLaserOn", ACE_player]; - } call CBA_fnc_execNextFrame; - }; - }, false, _variant + [_unit, _weapon, _item, _baseClass + _variant] call EFUNC(common,switchAttachmentMode); + }, + false, + _variant ] call CBA_fnc_addItemContextMenuOption; } forEach [ ["", LSTRING(Mode_IRDual)], diff --git a/addons/irlight/functions/fnc_onLightToggled.sqf b/addons/irlight/functions/fnc_onLightToggled.sqf deleted file mode 100644 index b3592f28f6..0000000000 --- a/addons/irlight/functions/fnc_onLightToggled.sqf +++ /dev/null @@ -1,36 +0,0 @@ -#include "..\script_component.hpp" -/* - * Author: BaerMitUmlaut - * Handles toggling flashlights on and off. - * - * Arguments: - * None - * - * Return Value: - * None - * - * Example: - * [] call ace_irlight_fnc_onLightToggled - * - * Public: No - */ - -private _isTurnedOn = ACE_player isFlashlightOn primaryWeapon ACE_player - || ACE_player isIRLaserOn primaryWeapon ACE_player; -ACE_player setVariable [QGVAR(isTurnedOn), _isTurnedOn]; - -// This is a surprise tool that will help us later -// Requires: https://feedback.bistudio.com/T170774 -/* -deleteVehicle (ACE_player getVariable [QGVAR(glow), objNull]); - -if (ACE_player isIRLaserOn currentWeapon ACE_player) then { - private _offset = [] call FUNC(getGlowOffset); - private _glow = createSimpleObject [QPATHTOF(data\irglow.p3d), [0, 0, 0]]; - _glow attachTo [ACE_player, _offset, "proxy:\a3\characters_f\proxies\weapon.001", true]; - _glow setObjectTexture [0, "#(rgb,8,8,3)color(0.35,0,0.38,0.1)"]; - _glow setObjectScale 0.1; - - ACE_player setVariable [QGVAR(glow), _glow]; -}; -*/ From 70c832239212b22d9e03d730485f6fcb878ca670 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sun, 11 Aug 2024 17:10:48 +0200 Subject: [PATCH 199/290] Aegis Compat - Overwrite some Aegis changes (#10173) * Overwrite some Aegis changes * Preemptively overwrite upcoming changes to Aegis --- addons/compat_aegis/$PBOPREFIX$ | 1 + addons/compat_aegis/CfgVehicles.hpp | 82 ++++++++++++++++++++++++ addons/compat_aegis/config.cpp | 18 ++++++ addons/compat_aegis/script_component.hpp | 5 ++ 4 files changed, 106 insertions(+) create mode 100644 addons/compat_aegis/$PBOPREFIX$ create mode 100644 addons/compat_aegis/CfgVehicles.hpp create mode 100644 addons/compat_aegis/config.cpp create mode 100644 addons/compat_aegis/script_component.hpp diff --git a/addons/compat_aegis/$PBOPREFIX$ b/addons/compat_aegis/$PBOPREFIX$ new file mode 100644 index 0000000000..1fc8683847 --- /dev/null +++ b/addons/compat_aegis/$PBOPREFIX$ @@ -0,0 +1 @@ +z\ace\addons\compat_aegis diff --git a/addons/compat_aegis/CfgVehicles.hpp b/addons/compat_aegis/CfgVehicles.hpp new file mode 100644 index 0000000000..8b069b517e --- /dev/null +++ b/addons/compat_aegis/CfgVehicles.hpp @@ -0,0 +1,82 @@ +class CfgVehicles { + class Tank; + class Tank_F: Tank { + class Turrets { + class MainTurret; + }; + }; + + class MBT_01_base_F: Tank_F { + class Turrets: Turrets { + class MainTurret: MainTurret { + // Overwrite the changes Aegis makes for the .338 coax MG on the Slammer/Merkava + // The idea is: + // 1) keep it as realistic as possible + // 2) easier to overwrite something with skipWhenMissingDependencies than to not overwrite something if another mod is loaded + weapons[] = {"cannon_120mm", "ACE_LMG_coax_MAG58_mem3"}; // Base 1.82: "cannon_120mm","LMG_coax" + magazines[] = { + "24Rnd_120mm_APFSDS_shells_Tracer_Red", + "12Rnd_120mm_HE_shells_Tracer_Red", + "12Rnd_120mm_HEAT_MP_T_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "4Rnd_120mm_LG_cannon_missiles" // Aegis adds laser-guided munitions + }; + }; + }; + }; + + class B_MBT_01_base_F: MBT_01_base_F {}; + class B_MBT_01_cannon_F: B_MBT_01_base_F {}; + class B_MBT_01_TUSK_F: B_MBT_01_cannon_F { + class Turrets: Turrets { + class MainTurret: MainTurret { + weapons[] = {"cannon_120mm", "ACE_LMG_coax_MAG58_mem3"}; // Base 1.82: "cannon_120mm","LMG_coax" + magazines[] = { + "24Rnd_120mm_APFSDS_shells_Tracer_Red", + "12Rnd_120mm_HE_shells_Tracer_Red", + "12Rnd_120mm_HEAT_MP_T_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "200Rnd_762x51_Belt_Red", + "4Rnd_120mm_LG_cannon_missiles" // Aegis adds laser-guided munitions + }; + }; + }; + }; +}; diff --git a/addons/compat_aegis/config.cpp b/addons/compat_aegis/config.cpp new file mode 100644 index 0000000000..51a70b06ff --- /dev/null +++ b/addons/compat_aegis/config.cpp @@ -0,0 +1,18 @@ +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + name = COMPONENT_NAME; + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = {"ace_vehicles", "A3_Aegis_Armor_F_Aegis_MBT_01"}; + skipWhenMissingDependencies = 1; + author = ECSTRING(common,ACETeam); + authors[] = {"johnb43"}; + url = ECSTRING(main,URL); + VERSION_CONFIG; + }; +}; + +#include "CfgVehicles.hpp" diff --git a/addons/compat_aegis/script_component.hpp b/addons/compat_aegis/script_component.hpp new file mode 100644 index 0000000000..d6fb73bd46 --- /dev/null +++ b/addons/compat_aegis/script_component.hpp @@ -0,0 +1,5 @@ +#define COMPONENT compat_aegis +#define COMPONENT_BEAUTIFIED Aegis Compatibility + +#include "\z\ace\addons\main\script_mod.hpp" +#include "\z\ace\addons\main\script_macros.hpp" From be23ae7ecdd516edf18c782cf9a6f999ae59d3bf Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Sun, 11 Aug 2024 23:24:01 +0200 Subject: [PATCH 200/290] Medical GUI - Make separate file for keybinds (#10190) * Make separate file for keybinds * Add missing ; --- addons/medical_gui/XEH_postInit.sqf | 60 +------------------------ addons/medical_gui/initKeybinds.inc.sqf | 55 +++++++++++++++++++++++ 2 files changed, 57 insertions(+), 58 deletions(-) create mode 100644 addons/medical_gui/initKeybinds.inc.sqf diff --git a/addons/medical_gui/XEH_postInit.sqf b/addons/medical_gui/XEH_postInit.sqf index 2b7fb8ce52..6d18696b0e 100644 --- a/addons/medical_gui/XEH_postInit.sqf +++ b/addons/medical_gui/XEH_postInit.sqf @@ -2,6 +2,8 @@ if (!hasInterface) exitWith {}; +#include "initKeybinds.inc.sqf" + GVAR(target) = objNull; GVAR(previousTarget) = objNull; GVAR(selectedBodyPart) = 0; @@ -35,64 +37,6 @@ GVAR(selfInteractionActions) = []; }; }] call CBA_fnc_addEventHandler; -["ACE3 Common", QGVAR(openMedicalMenuKey), localize LSTRING(OpenMedicalMenu), { - // Get target (cursorTarget, cursorObject, and lineIntersectsSurfaces along camera to maxDistance), if not valid then target is ACE_player - TRACE_3("Open menu key",cursorTarget,cursorObject,ACE_player); - private _target = cursorTarget; - if !(_target isKindOf "CAManBase" && {[ACE_player, _target] call FUNC(canOpenMenu)}) then { - _target = cursorObject; - if !(_target isKindOf "CAManBase" && {[ACE_player, _target] call FUNC(canOpenMenu)}) then { - private _start = AGLToASL positionCameraToWorld [0, 0, 0]; - private _end = AGLToASL positionCameraToWorld [0, 0, GVAR(maxDistance)]; - private _intersections = lineIntersectsSurfaces [_start, _end, ACE_player, objNull, true, -1, "FIRE"]; - { - _x params ["", "", "_intersectObject"]; - // Only look "through" player and player's vehicle - if (!(_intersectObject isKindOf "CAManBase") && {_intersectObject != vehicle ACE_player}) exitWith {}; - if (_intersectObject != ACE_player && {_intersectObject isKindOf "CAManBase" && {[ACE_player, _intersectObject] call FUNC(canOpenMenu)}}) exitWith { - _target =_intersectObject - }; - } forEach _intersections; - if (!(_target isKindOf "CAManBase") || {!([ACE_player, _target] call FUNC(canOpenMenu))}) then { - _target = ACE_player; - }; - }; - }; - - // Check conditions: canInteract and canOpenMenu - if !([ACE_player, _target, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; - if !([ACE_player, _target] call FUNC(canOpenMenu)) exitWith {false}; - - // Statement - [_target] call FUNC(openMenu); - false -}, { - // Close menu if enough time passed from opening - if (CBA_missionTime - GVAR(lastOpenedOn) > 0.5) exitWith { - [objNull] call FUNC(openMenu); - }; - false -}, [DIK_H, [false, false, false]], false, 0] call CBA_fnc_addKeybind; - -["ACE3 Common", QGVAR(peekMedicalInfoKey), localize LSTRING(PeekMedicalInfo), -{ - // Conditions: canInteract - if !([ACE_player, objNull, []] call EFUNC(common,canInteractWith)) exitWith {false}; - - // Statement - [ACE_player, -1] call FUNC(displayPatientInformation); - false -}, { - if (CBA_missionTime - GVAR(peekLastOpenedOn) > GVAR(peekMedicalInfoReleaseDelay)) then { - [{ - CBA_missionTime - GVAR(peekLastOpenedOn) > GVAR(peekMedicalInfoReleaseDelay) - }, {QGVAR(RscPatientInfo) cutFadeOut 0.3}] call CBA_fnc_waitUntilAndExecute; - }; - GVAR(peekLastOpenedOn) = CBA_missionTime; - false -}, [DIK_H, [false, true, false]], false, 0] call CBA_fnc_addKeybind; - - // Close patient information display when interaction menu is closed ["ace_interactMenuClosed", { QGVAR(RscPatientInfo) cutFadeOut 0.3; diff --git a/addons/medical_gui/initKeybinds.inc.sqf b/addons/medical_gui/initKeybinds.inc.sqf new file mode 100644 index 0000000000..53c577084e --- /dev/null +++ b/addons/medical_gui/initKeybinds.inc.sqf @@ -0,0 +1,55 @@ +["ACE3 Common", QGVAR(openMedicalMenuKey), LLSTRING(OpenMedicalMenu), { + // Get target (cursorTarget, cursorObject, and lineIntersectsSurfaces along camera to maxDistance), if not valid then target is ACE_player + TRACE_3("Open menu key",cursorTarget,cursorObject,ACE_player); + private _target = cursorTarget; + if !(_target isKindOf "CAManBase" && {[ACE_player, _target] call FUNC(canOpenMenu)}) then { + _target = cursorObject; + if !(_target isKindOf "CAManBase" && {[ACE_player, _target] call FUNC(canOpenMenu)}) then { + private _start = AGLToASL positionCameraToWorld [0, 0, 0]; + private _end = AGLToASL positionCameraToWorld [0, 0, GVAR(maxDistance)]; + private _intersections = lineIntersectsSurfaces [_start, _end, ACE_player, objNull, true, -1, "FIRE"]; + { + _x params ["", "", "_intersectObject"]; + // Only look "through" player and player's vehicle + if (!(_intersectObject isKindOf "CAManBase") && {_intersectObject != vehicle ACE_player}) exitWith {}; + if (_intersectObject != ACE_player && {_intersectObject isKindOf "CAManBase" && {[ACE_player, _intersectObject] call FUNC(canOpenMenu)}}) exitWith { + _target = _intersectObject; + }; + } forEach _intersections; + if (!(_target isKindOf "CAManBase") || {!([ACE_player, _target] call FUNC(canOpenMenu))}) then { + _target = ACE_player; + }; + }; + }; + + // Check conditions: canInteract and canOpenMenu + if !([ACE_player, _target, ["isNotInside", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; + if !([ACE_player, _target] call FUNC(canOpenMenu)) exitWith {false}; + + // Statement + [_target] call FUNC(openMenu); + false +}, { + // Close menu if enough time passed from opening + if (CBA_missionTime - GVAR(lastOpenedOn) > 0.5) exitWith { + [objNull] call FUNC(openMenu); + }; +}, [DIK_H, [false, false, false]], false, 0] call CBA_fnc_addKeybind; + +["ACE3 Common", QGVAR(peekMedicalInfoKey), LLSTRING(PeekMedicalInfo), { + // Conditions: canInteract + if !([ACE_player, objNull, []] call EFUNC(common,canInteractWith)) exitWith {false}; + + // Statement + [ACE_player, -1] call FUNC(displayPatientInformation); + false +}, { + if (CBA_missionTime - GVAR(peekLastOpenedOn) > GVAR(peekMedicalInfoReleaseDelay)) then { + [{ + CBA_missionTime - GVAR(peekLastOpenedOn) > GVAR(peekMedicalInfoReleaseDelay) + }, { + QGVAR(RscPatientInfo) cutFadeOut 0.3; + }] call CBA_fnc_waitUntilAndExecute; + }; + GVAR(peekLastOpenedOn) = CBA_missionTime; +}, [DIK_H, [false, true, false]], false, 0] call CBA_fnc_addKeybind; From c8e7b6396bb469c679bcdc93ad82647f0d265543 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 12 Aug 2024 01:28:51 +0200 Subject: [PATCH 201/290] Medical Damage - Improve custom wound handling (#9310) --- addons/medical_damage/CfgEventHandlers.hpp | 6 +++ addons/medical_damage/XEH_postInit.sqf | 4 ++ addons/medical_damage/XEH_preInit.sqf | 2 + .../functions/fnc_parseWoundHandlersCfg.sqf | 39 ++++++++++++++----- .../functions/fnc_woundReceived.sqf | 9 ++++- 5 files changed, 48 insertions(+), 12 deletions(-) create mode 100644 addons/medical_damage/XEH_postInit.sqf diff --git a/addons/medical_damage/CfgEventHandlers.hpp b/addons/medical_damage/CfgEventHandlers.hpp index 865276cfba..f6503c2479 100644 --- a/addons/medical_damage/CfgEventHandlers.hpp +++ b/addons/medical_damage/CfgEventHandlers.hpp @@ -9,3 +9,9 @@ class Extended_PreInit_EventHandlers { init = QUOTE(call COMPILE_SCRIPT(XEH_preInit)); }; }; + +class Extended_PostInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_SCRIPT(XEH_postInit)); + }; +}; diff --git a/addons/medical_damage/XEH_postInit.sqf b/addons/medical_damage/XEH_postInit.sqf new file mode 100644 index 0000000000..39b1c9301e --- /dev/null +++ b/addons/medical_damage/XEH_postInit.sqf @@ -0,0 +1,4 @@ +#include "script_component.hpp" + +// Reload configs (handle functions being compiled after medical_damage's preInit) +call FUNC(parseConfigForInjuries); diff --git a/addons/medical_damage/XEH_preInit.sqf b/addons/medical_damage/XEH_preInit.sqf index 344b9c81ee..b389a0eaa0 100644 --- a/addons/medical_damage/XEH_preInit.sqf +++ b/addons/medical_damage/XEH_preInit.sqf @@ -10,11 +10,13 @@ PREP_RECOMPILE_END; call FUNC(parseConfigForInjuries); +/* addMissionEventHandler ["Loaded",{ INFO("Mission Loaded - Reloading medical configs for extension"); // Reload configs into extension (handle full game restart) call FUNC(parseConfigForInjuries); }]; +*/ [QEGVAR(medical,woundReceived), LINKFUNC(woundReceived)] call CBA_fnc_addEventHandler; diff --git a/addons/medical_damage/functions/fnc_parseWoundHandlersCfg.sqf b/addons/medical_damage/functions/fnc_parseWoundHandlersCfg.sqf index 0dad747c68..010f02b7f5 100644 --- a/addons/medical_damage/functions/fnc_parseWoundHandlersCfg.sqf +++ b/addons/medical_damage/functions/fnc_parseWoundHandlersCfg.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: Pterolatypus - * Read a list of wound handler entries from config, accounting for inheritance + * Read a list of wound handler entries from config, accounting for inheritance. * * Arguments: * 0: The config class containing the entries @@ -10,24 +10,43 @@ * None * * Example: - * [configFile >> "ace_medical_injuries" >> "damageTypes"] call ace_medical_damage_fnc_parseWoundHandlersCfg + * [configFile >> "ace_medical_injuries" >> "damageTypes" >> "woundHandlers"] call ace_medical_damage_fnc_parseWoundHandlersCfg * * Public: No */ + params ["_config"]; -// read all valid entries from config and store +// Read all valid entries from config and store private _entries = []; + { - private _entryResult = call compile getText _x; - if !(isNil "_entryResult") then { - _entries pushBack _entryResult; - } + private _entryResult = getText _x; + + if (_entryResult != "") then { + if (ADDON) then { + // Runs in postInit + _entryResult = call compile _entryResult; + + if (!isNil "_entryResult") then { + if (_entryResult isEqualType {}) then { + _entries pushBack _entryResult; + } else { + ERROR_2("Wound handler '%1' needs to be a function, but is of type %2.",configName _x,toLowerANSI typeName _entryResult); + }; + }; + } else { + // Runs in preInit + // In case function doesn't exist yet, wrap in extra layer + _entries pushBack (compile format ["call %1", _entryResult]); + }; + }; } forEach configProperties [_config, "isText _x", false]; private _parent = inheritsFrom _config; + if (isNull _parent) exitWith {_entries}; -// recursive call for parent -// can't use configProperties for inheritance since it returns entries in the wrong order -([_parent] call FUNC(parseWoundHandlersCfg)) + _entries; +// Recursive call for parent +// Can't use configProperties for inheritance since it returns entries in the wrong order +([_parent] call FUNC(parseWoundHandlersCfg)) + _entries // return diff --git a/addons/medical_damage/functions/fnc_woundReceived.sqf b/addons/medical_damage/functions/fnc_woundReceived.sqf index a7e3861dee..c31cf5b378 100644 --- a/addons/medical_damage/functions/fnc_woundReceived.sqf +++ b/addons/medical_damage/functions/fnc_woundReceived.sqf @@ -17,18 +17,23 @@ * * Public: No */ + params ["_unit", "_allDamages", "_shooter", "_ammo"]; private _typeOfDamage = _ammo call FUNC(getTypeOfDamage); + if (_typeOfDamage in GVAR(damageTypeDetails)) then { (GVAR(damageTypeDetails) get _typeOfDamage) params ["", "", "_woundHandlers"]; private _damageData = [_unit, _allDamages, _typeOfDamage]; + { _damageData = _damageData call _x; TRACE_1("Wound handler returned",_damageData); - if !(_damageData isEqualType [] && {(count _damageData) >= 3}) exitWith { - TRACE_1("Return invalid, terminating wound handling",_damageData); + + // If invalid return, exit + if (isNil "_damageData" || {!(_damageData isEqualType [])} || {(count _damageData) < 3}) exitWith { + TRACE_1("Return invalid, skipping wound handling",_damageData); }; } forEach _woundHandlers; }; From fff66bc27c65bbaac9b44a8aa545eb8d6b95fee8 Mon Sep 17 00:00:00 2001 From: Grim <69561145+LinkIsGrim@users.noreply.github.com> Date: Sun, 11 Aug 2024 20:29:11 -0300 Subject: [PATCH 202/290] Medical - Make Peripheral Resistance affect blood loss (#8420) Co-authored-by: Salluci <69561145+Salluci@users.noreply.github.com> Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com> Co-authored-by: PabstMirror --- addons/medical_status/functions/fnc_getBloodLoss.sqf | 3 ++- .../functions/fnc_updatePeripheralResistance.sqf | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/medical_status/functions/fnc_getBloodLoss.sqf b/addons/medical_status/functions/fnc_getBloodLoss.sqf index c2a6604679..5193ccbb0b 100644 --- a/addons/medical_status/functions/fnc_getBloodLoss.sqf +++ b/addons/medical_status/functions/fnc_getBloodLoss.sqf @@ -21,9 +21,10 @@ private _woundBleeding = GET_WOUND_BLEEDING(_unit); if (_woundBleeding == 0) exitWith {0}; private _cardiacOutput = [_unit] call FUNC(getCardiacOutput); +private _resistance = _unit getVariable [VAR_PERIPH_RES, DEFAULT_PERIPH_RES]; // can use value directly since this is sum of default and adjustments // even if heart stops blood will still flow slowly (gravity) -private _bloodLoss = (_woundBleeding * (_cardiacOutput max CARDIAC_OUTPUT_MIN) * EGVAR(medical,bleedingCoefficient)); +private _bloodLoss = (_woundBleeding * (_cardiacOutput max CARDIAC_OUTPUT_MIN) * (DEFAULT_PERIPH_RES / _resistance) * EGVAR(medical,bleedingCoefficient)); private _eventArgs = [_unit, _bloodLoss]; // Pass by reference diff --git a/addons/medical_vitals/functions/fnc_updatePeripheralResistance.sqf b/addons/medical_vitals/functions/fnc_updatePeripheralResistance.sqf index 30f8038d80..05056fa0a3 100644 --- a/addons/medical_vitals/functions/fnc_updatePeripheralResistance.sqf +++ b/addons/medical_vitals/functions/fnc_updatePeripheralResistance.sqf @@ -20,4 +20,4 @@ params ["_unit", "_peripheralResistanceAdjustment", "_deltaT", "_syncValue"]; -_unit setVariable [VAR_PERIPH_RES, 0 max (DEFAULT_PERIPH_RES + _peripheralResistanceAdjustment), _syncValue]; +_unit setVariable [VAR_PERIPH_RES, 1 max (DEFAULT_PERIPH_RES + _peripheralResistanceAdjustment), _syncValue]; From 3ff635f82d8639f3497c422c4b4efa8e3e4d812e Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Sun, 11 Aug 2024 18:29:33 -0500 Subject: [PATCH 203/290] Common - Use hashmap for `canInteractWith` check (#10189) --- addons/common/XEH_preInit.sqf | 2 ++ .../functions/fnc_addCanInteractWithCondition.sqf | 15 +-------------- addons/common/functions/fnc_canInteractWith.sqf | 8 ++------ .../fnc_removeCanInteractWithCondition.sqf | 14 +------------- 4 files changed, 6 insertions(+), 33 deletions(-) diff --git a/addons/common/XEH_preInit.sqf b/addons/common/XEH_preInit.sqf index b559cb5dd9..f2194deb64 100644 --- a/addons/common/XEH_preInit.sqf +++ b/addons/common/XEH_preInit.sqf @@ -12,6 +12,8 @@ GVAR(showHudHash) = createHashMap; GVAR(vehicleIconCache) = createHashMap; // for getVehicleIcon GVAR(wheelSelections) = createHashMap; +GVAR(InteractionConditions) = createHashMap; + GVAR(blockItemReplacement) = false; // Cache for FUNC(isModLoaded) diff --git a/addons/common/functions/fnc_addCanInteractWithCondition.sqf b/addons/common/functions/fnc_addCanInteractWithCondition.sqf index 3dce27cf55..1d315f5aa5 100644 --- a/addons/common/functions/fnc_addCanInteractWithCondition.sqf +++ b/addons/common/functions/fnc_addCanInteractWithCondition.sqf @@ -19,17 +19,4 @@ params ["_conditionName", "_conditionFunc"]; _conditionName = toLowerANSI _conditionName; - -private _conditions = missionNamespace getVariable [QGVAR(InteractionConditions), [[],[]]]; -_conditions params ["_conditionNames", "_conditionFuncs"]; - -private _index = _conditionNames find _conditionName; - -if (_index == -1) then { - _index = count _conditionNames; -}; - -_conditionNames set [_index, _conditionName]; -_conditionFuncs set [_index, _conditionFunc]; - -GVAR(InteractionConditions) = _conditions; +GVAR(InteractionConditions) set [_conditionName, _conditionFunc]; diff --git a/addons/common/functions/fnc_canInteractWith.sqf b/addons/common/functions/fnc_canInteractWith.sqf index dd684d0619..134a3101e4 100644 --- a/addons/common/functions/fnc_canInteractWith.sqf +++ b/addons/common/functions/fnc_canInteractWith.sqf @@ -27,15 +27,11 @@ private _owner = _target getVariable [QGVAR(owner), objNull]; if (!isNull _owner && {_unit != _owner}) exitWith {false}; // check general conditions -private _conditions = missionNamespace getVariable [QGVAR(InteractionConditions), [[],[]]]; -_conditions params ["_conditionNames", "_conditionFuncs"]; - private _canInteract = true; - { - if (!(_x in _exceptions) && {!([_unit, _target] call (_conditionFuncs select _forEachIndex))}) exitWith { + if (!(_x in _exceptions) && {!([_unit, _target] call _y)}) exitWith { _canInteract = false; }; -} forEach _conditionNames; +} forEach GVAR(InteractionConditions); _canInteract diff --git a/addons/common/functions/fnc_removeCanInteractWithCondition.sqf b/addons/common/functions/fnc_removeCanInteractWithCondition.sqf index 6c5e8b56b6..841a9a00b1 100644 --- a/addons/common/functions/fnc_removeCanInteractWithCondition.sqf +++ b/addons/common/functions/fnc_removeCanInteractWithCondition.sqf @@ -18,16 +18,4 @@ params ["_conditionName"]; _conditionName = toLowerANSI _conditionName; - -private _conditions = missionNamespace getVariable [QGVAR(InteractionConditions), [[],[]]]; - -_conditions params ["_conditionNames", "_conditionFuncs"]; - -private _index = _conditionNames find _conditionName; - -if (_index == -1) exitWith {}; - -_conditionNames deleteAt _index; -_conditionFuncs deleteAt _index; - -GVAR(InteractionConditions) = _conditions; +GVAR(InteractionConditions) deleteAt _conditionName; From 285f903b147b3f1b29ad5ce9154d1009d0ddc7da Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Sun, 11 Aug 2024 18:30:08 -0500 Subject: [PATCH 204/290] General - Optimize some loops with `forEachReversed` (#10191) --- .../medical_vitals/functions/fnc_handleUnitVitals.sqf | 6 +++--- .../functions/fnc_updateTrajectoryPFH.sqf | 10 ++-------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/addons/medical_vitals/functions/fnc_handleUnitVitals.sqf b/addons/medical_vitals/functions/fnc_handleUnitVitals.sqf index c284b00701..77aec7fd62 100644 --- a/addons/medical_vitals/functions/fnc_handleUnitVitals.sqf +++ b/addons/medical_vitals/functions/fnc_handleUnitVitals.sqf @@ -85,17 +85,17 @@ if (_adjustments isNotEqualTo []) then { private _timeInSystem = CBA_missionTime - _timeAdded; if (_timeInSystem >= _maxTimeInSystem) then { _deleted = true; - _adjustments set [_forEachIndex, objNull]; + _adjustments deleteAt _forEachIndex; } else { private _effectRatio = (((_timeInSystem / _timeTillMaxEffect) ^ 2) min 1) * (_maxTimeInSystem - _timeInSystem) / _maxTimeInSystem; if (_hrAdjust != 0) then { _hrTargetAdjustment = _hrTargetAdjustment + _hrAdjust * _effectRatio; }; if (_painAdjust != 0) then { _painSupressAdjustment = _painSupressAdjustment + _painAdjust * _effectRatio; }; if (_flowAdjust != 0) then { _peripheralResistanceAdjustment = _peripheralResistanceAdjustment + _flowAdjust * _effectRatio; }; }; - } forEach _adjustments; + } forEachReversed _adjustments; if (_deleted) then { - _unit setVariable [VAR_MEDICATIONS, _adjustments - [objNull], true]; + _unit setVariable [VAR_MEDICATIONS, _adjustments, true]; _syncValues = true; }; }; diff --git a/addons/winddeflection/functions/fnc_updateTrajectoryPFH.sqf b/addons/winddeflection/functions/fnc_updateTrajectoryPFH.sqf index 4ebea1f507..6f54dfbba1 100644 --- a/addons/winddeflection/functions/fnc_updateTrajectoryPFH.sqf +++ b/addons/winddeflection/functions/fnc_updateTrajectoryPFH.sqf @@ -25,7 +25,6 @@ _args set [0, CBA_missionTime]; private _isWind = (vectorMagnitude wind > 0); - private _deleted = false; { _x params ["_bullet", "_airFriction"]; @@ -33,8 +32,7 @@ private _bulletSpeedSqr = vectorMagnitudeSqr _bulletVelocity; if ((!alive _bullet) || {(_bullet isKindOf "BulletBase") && {_bulletSpeedSqr < 10000}}) then { - GVAR(trackedBullets) set [_forEachIndex, objNull]; - _deleted = true; + GVAR(trackedBullets) deleteAt _forEachIndex; } else { if (_isWind) then { private _trueVelocity = _bulletVelocity vectorDiff wind; @@ -50,11 +48,7 @@ }; _bullet setVelocity _bulletVelocity; }; - } forEach GVAR(trackedBullets); - - if (_deleted) then { - GVAR(trackedBullets) = GVAR(trackedBullets) - [objNull]; - }; + } forEachReversed GVAR(trackedBullets); // END_COUNTER(pfeh); }, GVAR(simulationInterval), [CBA_missionTime]] call CBA_fnc_addPerFrameHandler; From 43d42c85cd2bcb03ff96e8f4355d32e8a8565fb3 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 12 Aug 2024 01:31:02 +0200 Subject: [PATCH 205/290] Cookoff - Use `triggerAmmo` instead of `setDamage` (#10185) --- .../fnc_detonateAmmunitionServerLoop.sqf | 29 +++++++------------ .../cookoff/functions/fnc_getVehicleAmmo.sqf | 2 +- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/addons/cookoff/functions/fnc_detonateAmmunitionServerLoop.sqf b/addons/cookoff/functions/fnc_detonateAmmunitionServerLoop.sqf index 7fdcedda51..946cb4f7d8 100644 --- a/addons/cookoff/functions/fnc_detonateAmmunitionServerLoop.sqf +++ b/addons/cookoff/functions/fnc_detonateAmmunitionServerLoop.sqf @@ -91,7 +91,7 @@ private _configMagazine = configFile >> "CfgMagazines" >> _magazineClassname; private _ammo = getText (_configMagazine >> "ammo"); private _configAmmo = configFile >> "CfgAmmo" >> _ammo; -private _simType = toLower getText (_configAmmo >> "simulation"); +private _simType = toLowerANSI getText (_configAmmo >> "simulation"); private _speed = linearConversion [0, 1, random 1, 1, 20, true]; private _effect2pos = _object selectionPosition "destructionEffect2"; @@ -100,7 +100,7 @@ private _fnc_spawnProjectile = { // If the magazines are inside of the cargo (inventory), don't let their projectiles escape the interior of the vehicle if (!_spawnProjectile) exitWith {}; - params ["_object", "_ammo", "_speed", "_flyAway"]; + params ["_flyAway"]; private _spawnPos = _object modelToWorld [-0.2 + random 0.4, -0.2 + random 0.4, random 3]; @@ -117,7 +117,7 @@ private _fnc_spawnProjectile = { _projectile setVectorDir _vectorVelocity; _projectile setVelocity _vectorVelocity; } else { - _projectile setDamage 1; + triggerAmmo _projectile; }; }; @@ -126,14 +126,14 @@ switch (_simType) do { [QGVAR(playCookoffSound), [_object, _simType]] call CBA_fnc_globalEvent; if (random 1 < 0.6) then { - [_object, _ammo, _speed, true] call _fnc_spawnProjectile; + true call _fnc_spawnProjectile; }; }; case "shotshell": { [QGVAR(playCookoffSound), [_object, _simType]] call CBA_fnc_globalEvent; if (random 1 < 0.15) then { - [_object, _ammo, _speed, true] call _fnc_spawnProjectile; + true call _fnc_spawnProjectile; }; }; case "shotgrenade": { @@ -141,7 +141,7 @@ switch (_simType) do { _speed = 0; }; - [_object, _ammo, _speed, random 1 < 0.5] call _fnc_spawnProjectile; + (random 1 < 0.5) call _fnc_spawnProjectile; }; case "shotrocket"; case "shotmissile"; @@ -149,7 +149,7 @@ switch (_simType) do { if (random 1 < 0.1) then { [QGVAR(playCookoffSound), [_object, _simType]] call CBA_fnc_globalEvent; - [_object, _ammo, _speed, random 1 < 0.3] call _fnc_spawnProjectile; + (random 1 < 0.3) call _fnc_spawnProjectile; } else { createVehicle ["ACE_ammoExplosionLarge", _object modelToWorld _effect2pos, [], 0 , "CAN_COLLIDE"]; }; @@ -157,22 +157,13 @@ switch (_simType) do { case "shotdirectionalbomb"; case "shotmine": { if (random 1 < 0.5) then { - // Not all explosives detonate on destruction, some have scripted alternatives - if (getNumber (_configAmmo >> "triggerWhenDestroyed") != 1) then { - _ammo = getText (_configAmmo >> QEGVAR(explosives,explosive)); - }; - - // If a scripted alternative doesn't exist use generic explosion - if (_ammo != "") then { - [_object, _ammo, 0, false] call _fnc_spawnProjectile; - } else { - createVehicle ["SmallSecondary", _object modelToWorld _effect2pos, [], 0 , "CAN_COLLIDE"]; - }; + // _speed should be 0, but as it doesn't fly away, no need to set _speed + false call _fnc_spawnProjectile; }; }; case "shotilluminating": { if (random 1 < 0.15) then { - [_object, _ammo, _speed, random 1 < 0.3] call _fnc_spawnProjectile; + (random 1 < 0.3) call _fnc_spawnProjectile; }; }; }; diff --git a/addons/cookoff/functions/fnc_getVehicleAmmo.sqf b/addons/cookoff/functions/fnc_getVehicleAmmo.sqf index df4385d30d..35ca6fae26 100644 --- a/addons/cookoff/functions/fnc_getVehicleAmmo.sqf +++ b/addons/cookoff/functions/fnc_getVehicleAmmo.sqf @@ -52,7 +52,7 @@ private _ammo = ""; _x params ["_magazine", "_count"]; if (_count > 0 && {!(_magazine call FUNC(isMagazineFlare))}) then { - _ammoToDetonate pushBack [_magazine, _count, false]; + _ammoToDetonate pushBack [_magazine, _count, random 1 < 0.5]; _totalAmmo = _totalAmmo + _count; }; } forEach (magazinesAmmoCargo _object); From ada7b93219f298b7b83df6c48cca5bfa868bcc80 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 12 Aug 2024 15:15:09 +0200 Subject: [PATCH 206/290] General - Use `QUOTE(ADDON)` for status effects (#10195) Use ADDON for status effects --- addons/attach/functions/fnc_attach.sqf | 8 ++++---- addons/captives/functions/fnc_handleRespawn.sqf | 4 ++-- addons/captives/functions/fnc_setHandcuffed.sqf | 8 ++++---- addons/captives/functions/fnc_setSurrendered.sqf | 8 ++++---- addons/common/XEH_postInit.sqf | 16 ++++++++-------- .../explosives/functions/fnc_setupExplosive.sqf | 8 ++++---- addons/rearm/functions/fnc_dropAmmo.sqf | 4 ++-- addons/rearm/functions/fnc_grabAmmo.sqf | 4 ++-- addons/rearm/functions/fnc_takeSuccess.sqf | 4 ++-- addons/refuel/functions/fnc_handleDisconnect.sqf | 2 +- addons/refuel/functions/fnc_returnNozzle.sqf | 4 ++-- .../functions/fnc_startNozzleInHandsPFH.sqf | 4 ++-- addons/refuel/functions/fnc_takeNozzle.sqf | 6 +++--- addons/sandbag/functions/fnc_deploy.sqf | 4 ++-- addons/sandbag/functions/fnc_deployCancel.sqf | 4 ++-- addons/sandbag/functions/fnc_deployConfirm.sqf | 4 ++-- addons/switchunits/functions/fnc_initPlayer.sqf | 2 +- .../functions/fnc_cancelTLdeploy.sqf | 4 ++-- .../functions/fnc_confirmTLdeploy.sqf | 4 ++-- .../tacticalladder/functions/fnc_positionTL.sqf | 4 ++-- addons/trenches/functions/fnc_placeCancel.sqf | 4 ++-- addons/trenches/functions/fnc_placeConfirm.sqf | 4 ++-- addons/trenches/functions/fnc_placeTrench.sqf | 4 ++-- 23 files changed, 59 insertions(+), 59 deletions(-) diff --git a/addons/attach/functions/fnc_attach.sqf b/addons/attach/functions/fnc_attach.sqf index 6a0c408271..d1e9f12987 100644 --- a/addons/attach/functions/fnc_attach.sqf +++ b/addons/attach/functions/fnc_attach.sqf @@ -50,8 +50,8 @@ if (_unit == _attachToVehicle) then { //Self Attachment } else { GVAR(placeAction) = PLACE_WAITING; - [_unit, "forceWalk", "ACE_Attach", true] call EFUNC(common,statusEffect_set); - [_unit, "blockThrow", "ACE_Attach", true] call EFUNC(common,statusEffect_set); + [_unit, "forceWalk", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); + [_unit, "blockThrow", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); [{[localize LSTRING(PlaceAction), ""] call EFUNC(interaction,showMouseHint)}, []] call CBA_fnc_execNextFrame; _unit setVariable [QGVAR(placeActionEH), [_unit, "DefaultAction", {true}, {GVAR(placeAction) = PLACE_APPROVE;}] call EFUNC(common,AddActionEventHandler)]; @@ -88,8 +88,8 @@ if (_unit == _attachToVehicle) then { //Self Attachment {!([_attachToVehicle, _unit, _itemClassname] call FUNC(canAttach))}) then { [_idPFH] call CBA_fnc_removePerFrameHandler; - [_unit, "forceWalk", "ACE_Attach", false] call EFUNC(common,statusEffect_set); - [_unit, "blockThrow", "ACE_Attach", false] call EFUNC(common,statusEffect_set); + [_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); + [_unit, "blockThrow", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); [] call EFUNC(interaction,hideMouseHint); [_unit, "DefaultAction", (_unit getVariable [QGVAR(placeActionEH), -1])] call EFUNC(common,removeActionEventHandler); _unit removeAction _actionID; diff --git a/addons/captives/functions/fnc_handleRespawn.sqf b/addons/captives/functions/fnc_handleRespawn.sqf index 1dc6ca7bfa..f3c728d053 100644 --- a/addons/captives/functions/fnc_handleRespawn.sqf +++ b/addons/captives/functions/fnc_handleRespawn.sqf @@ -40,12 +40,12 @@ if (_respawn > 3) then { if (_unit getVariable [QGVAR(isHandcuffed), false]) then { [_unit, false] call FUNC(setHandcuffed); }; - [_unit, "setCaptive", QGVAR(Handcuffed), false] call EFUNC(common,statusEffect_set); + [_unit, "setCaptive", QGVAR(handcuffed), false] call EFUNC(common,statusEffect_set); if (_unit getVariable [QGVAR(isSurrendering), false]) then { [_unit, false] call FUNC(setSurrendered); }; - [_unit, "setCaptive", QGVAR(Surrendered), false] call EFUNC(common,statusEffect_set); + [_unit, "setCaptive", QGVAR(surrendered), false] call EFUNC(common,statusEffect_set); if (_unit getVariable [QGVAR(isEscorting), false]) then { _unit setVariable [QGVAR(isEscorting), false, true]; diff --git a/addons/captives/functions/fnc_setHandcuffed.sqf b/addons/captives/functions/fnc_setHandcuffed.sqf index d3d9fa4e6b..2ccd36493c 100644 --- a/addons/captives/functions/fnc_setHandcuffed.sqf +++ b/addons/captives/functions/fnc_setHandcuffed.sqf @@ -41,8 +41,8 @@ if ((_unit getVariable [QGVAR(isHandcuffed), false]) isEqualTo _state) exitWith if (_state) then { _unit setVariable [QGVAR(isHandcuffed), true, true]; - [_unit, "setCaptive", QGVAR(Handcuffed), true] call EFUNC(common,statusEffect_set); - [_unit, "blockRadio", QGVAR(Handcuffed), true] call EFUNC(common,statusEffect_set); + [_unit, "setCaptive", QGVAR(handcuffed), true] call EFUNC(common,statusEffect_set); + [_unit, "blockRadio", QGVAR(handcuffed), true] call EFUNC(common,statusEffect_set); if (_unit getVariable [QGVAR(isSurrendering), false]) then { //If surrendering, stop [_unit, false] call FUNC(setSurrendered); @@ -82,8 +82,8 @@ if (_state) then { }, [_unit], 0.01] call CBA_fnc_waitAndExecute; } else { _unit setVariable [QGVAR(isHandcuffed), false, true]; - [_unit, "setCaptive", QGVAR(Handcuffed), false] call EFUNC(common,statusEffect_set); - [_unit, "blockRadio", QGVAR(Handcuffed), false] call EFUNC(common,statusEffect_set); + [_unit, "setCaptive", QGVAR(handcuffed), false] call EFUNC(common,statusEffect_set); + [_unit, "blockRadio", QGVAR(handcuffed), false] call EFUNC(common,statusEffect_set); //remove AnimChanged EH private _animChangedEHID = _unit getVariable [QGVAR(handcuffAnimEHID), -1]; diff --git a/addons/captives/functions/fnc_setSurrendered.sqf b/addons/captives/functions/fnc_setSurrendered.sqf index 887bfb2680..3a3724c94d 100644 --- a/addons/captives/functions/fnc_setSurrendered.sqf +++ b/addons/captives/functions/fnc_setSurrendered.sqf @@ -44,8 +44,8 @@ if (_state) then { _unit setVariable [QGVAR(isSurrendering), true, true]; - [_unit, "setCaptive", QGVAR(Surrendered), true] call EFUNC(common,statusEffect_set); - [_unit, "blockRadio", QGVAR(Surrendered), true] call EFUNC(common,statusEffect_set); + [_unit, "setCaptive", QGVAR(surrendered), true] call EFUNC(common,statusEffect_set); + [_unit, "blockRadio", QGVAR(surrendered), true] call EFUNC(common,statusEffect_set); if (_unit == ACE_player) then { ["captive", [false, false, false, false, false, false, false, false, false, true]] call EFUNC(common,showHud); @@ -71,8 +71,8 @@ if (_state) then { }, [_unit], 0.01] call CBA_fnc_waitAndExecute; } else { _unit setVariable [QGVAR(isSurrendering), false, true]; - [_unit, "setCaptive", QGVAR(Surrendered), false] call EFUNC(common,statusEffect_set); - [_unit, "blockRadio", QGVAR(Surrendered), false] call EFUNC(common,statusEffect_set); + [_unit, "setCaptive", QGVAR(surrendered), false] call EFUNC(common,statusEffect_set); + [_unit, "blockRadio", QGVAR(surrendered), false] call EFUNC(common,statusEffect_set); //remove AnimChanged EH private _animChangedEHID = _unit getVariable [QGVAR(surrenderAnimEHID), -1]; diff --git a/addons/common/XEH_postInit.sqf b/addons/common/XEH_postInit.sqf index 8b7568f75e..48fdab954b 100644 --- a/addons/common/XEH_postInit.sqf +++ b/addons/common/XEH_postInit.sqf @@ -19,16 +19,16 @@ //Status Effect EHs: [QGVAR(setStatusEffect), LINKFUNC(statusEffect_set)] call CBA_fnc_addEventHandler; -["forceWalk", false, ["ace_advanced_fatigue", "ACE_SwitchUnits", "ACE_Attach", "ace_dragging", "ACE_Explosives", "ACE_Ladder", "ACE_Sandbag", "ACE_refuel", "ACE_rearm", "ACE_Trenches", "ace_medical_fracture"]] call FUNC(statusEffect_addType); -["blockSprint", false, ["ace_advanced_fatigue", "ace_dragging", "ace_medical_fracture"]] call FUNC(statusEffect_addType); -["setCaptive", true, [QEGVAR(captives,Handcuffed), QEGVAR(captives,Surrendered)]] call FUNC(statusEffect_addType); -["blockDamage", false, ["fixCollision", "ACE_cargo"]] call FUNC(statusEffect_addType); -["blockEngine", false, ["ACE_Refuel"]] call FUNC(statusEffect_addType); -["blockThrow", false, ["ACE_Attach", "ACE_concertina_wire", "ace_dragging", "ACE_Explosives", "ACE_Ladder", "ACE_rearm", "ACE_refuel", "ACE_Sandbag", "ACE_Trenches", "ACE_tripod"]] call FUNC(statusEffect_addType); +["forceWalk", false, ["ace_advanced_fatigue", "ace_attach", "ace_dragging", "ace_explosives", QEGVAR(medical,fracture), "ace_rearm", "ace_refuel", "ace_sandbag", "ace_switchunits", "ace_tacticalladder", "ace_trenches"]] call FUNC(statusEffect_addType); +["blockSprint", false, ["ace_advanced_fatigue", "ace_dragging", QEGVAR(medical,fracture)]] call FUNC(statusEffect_addType); +["setCaptive", true, [QEGVAR(captives,handcuffed), QEGVAR(captives,surrendered)]] call FUNC(statusEffect_addType); +["blockDamage", false, ["fixCollision", "ace_cargo"]] call FUNC(statusEffect_addType); +["blockEngine", false, ["ace_refuel"]] call FUNC(statusEffect_addType); +["blockThrow", false, ["ace_attach", "ace_concertina_wire", "ace_dragging", "ace_explosives", "ace_rearm", "ace_refuel", "ace_sandbag", "ace_tacticalladder", "ace_trenches", "ace_tripod"]] call FUNC(statusEffect_addType); ["setHidden", true, ["ace_unconscious"]] call FUNC(statusEffect_addType); -["blockRadio", false, [QEGVAR(captives,Handcuffed), QEGVAR(captives,Surrendered), "ace_unconscious"]] call FUNC(statusEffect_addType); +["blockRadio", false, [QEGVAR(captives,handcuffed), QEGVAR(captives,surrendered), "ace_unconscious"]] call FUNC(statusEffect_addType); ["blockSpeaking", false, ["ace_unconscious"]] call FUNC(statusEffect_addType); -["disableWeaponAssembly", false, ["ace_common", "ace_common_lockVehicle", "ace_csw"]] call FUNC(statusEffect_addType); +["disableWeaponAssembly", false, ["ace_common", QGVAR(lockVehicle), "ace_csw"]] call FUNC(statusEffect_addType); ["lockInventory", true, [], true] call FUNC(statusEffect_addType); [QGVAR(forceWalk), { diff --git a/addons/explosives/functions/fnc_setupExplosive.sqf b/addons/explosives/functions/fnc_setupExplosive.sqf index 918bbb0c33..d25e5d3276 100644 --- a/addons/explosives/functions/fnc_setupExplosive.sqf +++ b/addons/explosives/functions/fnc_setupExplosive.sqf @@ -29,8 +29,8 @@ if (!isClass (configFile >> "CfgVehicles" >> _setupObjectClass)) exitWith {ERROR private _p3dModel = getText (configFile >> "CfgVehicles" >> _setupObjectClass >> "model"); if (_p3dModel == "") exitWith {ERROR("No Model");}; //"" - will crash game! -[_unit, "forceWalk", "ACE_Explosives", true] call EFUNC(common,statusEffect_set); -[_unit, "blockThrow", "ACE_Explosives", true] call EFUNC(common,statusEffect_set); +[_unit, "forceWalk", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); +[_unit, "blockThrow", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); //Show mouse buttons: [localize LSTRING(PlaceAction), localize LSTRING(CancelAction), localize LSTRING(ScrollAction)] call EFUNC(interaction,showMouseHint); @@ -149,8 +149,8 @@ GVAR(TweakedAngle) = 0; [_pfID] call CBA_fnc_removePerFrameHandler; GVAR(pfeh_running) = false; - [_unit, "forceWalk", "ACE_Explosives", false] call EFUNC(common,statusEffect_set); - [_unit, "blockThrow", "ACE_Explosives", false] call EFUNC(common,statusEffect_set); + [_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); + [_unit, "blockThrow", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); [] call EFUNC(interaction,hideMouseHint); [_unit, "DefaultAction", (_unit getVariable [QGVAR(placeActionEH), -1])] call EFUNC(common,removeActionEventHandler); [_unit, "zoomtemp", (_unit getVariable [QGVAR(cancelActionEH), -1])] call EFUNC(common,removeActionEventHandler); diff --git a/addons/rearm/functions/fnc_dropAmmo.sqf b/addons/rearm/functions/fnc_dropAmmo.sqf index af4b74ee77..ba89c9cd91 100644 --- a/addons/rearm/functions/fnc_dropAmmo.sqf +++ b/addons/rearm/functions/fnc_dropAmmo.sqf @@ -38,8 +38,8 @@ if (_actionID != -1) then { _unit removeAction _actionID; _unit setVariable [QGVAR(ReleaseActionID), nil]; }; -[_unit, "forceWalk", "ACE_rearm", false] call EFUNC(common,statusEffect_set); -[_unit, "blockThrow", "ACE_rearm", false] call EFUNC(common,statusEffect_set); +[_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); +[_unit, "blockThrow", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); if (_unholster) then { REARM_UNHOLSTER_WEAPON diff --git a/addons/rearm/functions/fnc_grabAmmo.sqf b/addons/rearm/functions/fnc_grabAmmo.sqf index d355485309..b8c53371d8 100644 --- a/addons/rearm/functions/fnc_grabAmmo.sqf +++ b/addons/rearm/functions/fnc_grabAmmo.sqf @@ -19,8 +19,8 @@ params ["_dummy", "_unit"]; REARM_HOLSTER_WEAPON; -[_unit, "forceWalk", "ACE_rearm", true] call EFUNC(common,statusEffect_set); -[_unit, "blockThrow", "ACE_rearm", true] call EFUNC(common,statusEffect_set); +[_unit, "forceWalk", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); +[_unit, "blockThrow", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); [ TIME_PROGRESSBAR(5), diff --git a/addons/rearm/functions/fnc_takeSuccess.sqf b/addons/rearm/functions/fnc_takeSuccess.sqf index 717d549b86..1d112f2645 100644 --- a/addons/rearm/functions/fnc_takeSuccess.sqf +++ b/addons/rearm/functions/fnc_takeSuccess.sqf @@ -36,8 +36,8 @@ if (_vehicle == _unit) exitWith { [_unit, _magazineClass, _rounds] call EFUNC(csw,reload_handleReturnAmmo); }; -[_unit, "forceWalk", "ACE_rearm", true] call EFUNC(common,statusEffect_set); -[_unit, "blockThrow", "ACE_rearm", true] call EFUNC(common,statusEffect_set); +[_unit, "forceWalk", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); +[_unit, "blockThrow", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); private _dummy = [_unit, _magazineClass] call FUNC(createDummy); [_dummy, _unit] call FUNC(pickUpAmmo); diff --git a/addons/refuel/functions/fnc_handleDisconnect.sqf b/addons/refuel/functions/fnc_handleDisconnect.sqf index cf4b37cce9..3aa1831a18 100644 --- a/addons/refuel/functions/fnc_handleDisconnect.sqf +++ b/addons/refuel/functions/fnc_handleDisconnect.sqf @@ -24,4 +24,4 @@ private _nozzle = _unit getVariable [QGVAR(nozzle), objNull]; if (isNull _nozzle) exitWith {}; [_unit, _nozzle] call FUNC(dropNozzle); -[_unit, "forceWalk", "ACE_refuel", false] call EFUNC(common,statusEffect_set); +[_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); diff --git a/addons/refuel/functions/fnc_returnNozzle.sqf b/addons/refuel/functions/fnc_returnNozzle.sqf index ea84f6a518..eba836ed8a 100644 --- a/addons/refuel/functions/fnc_returnNozzle.sqf +++ b/addons/refuel/functions/fnc_returnNozzle.sqf @@ -43,12 +43,12 @@ if (isNull _nozzle || {_source != _nozzle getVariable QGVAR(source)}) exitWith { deleteVehicle _helper; }; deleteVehicle _nozzle; - + // Restore ability to drag and carry this object _source setVariable [QEGVAR(dragging,canCarry), _source getVariable [QGVAR(canCarryLast), false], true]; _source setVariable [QEGVAR(dragging,canDrag), _source getVariable [QGVAR(canDragLast), false], true]; - [_source, "blockEngine", "ACE_Refuel", false] call EFUNC(common,statusEffect_set); + [_source, "blockEngine", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); }, "", localize LSTRING(ReturnAction), diff --git a/addons/refuel/functions/fnc_startNozzleInHandsPFH.sqf b/addons/refuel/functions/fnc_startNozzleInHandsPFH.sqf index 611fa85e90..3e4dc23afb 100644 --- a/addons/refuel/functions/fnc_startNozzleInHandsPFH.sqf +++ b/addons/refuel/functions/fnc_startNozzleInHandsPFH.sqf @@ -23,8 +23,8 @@ #define END_PFH \ _unit setVariable [QGVAR(hint), nil]; \ call EFUNC(interaction,hideMouseHint); \ - [_unit, "forceWalk", "ACE_refuel", false] call EFUNC(common,statusEffect_set); \ - [_unit, "blockThrow", "ACE_refuel", false] call EFUNC(common,statusEffect_set); \ + [_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); \ + [_unit, "blockThrow", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); \ [_idPFH] call CBA_fnc_removePerFrameHandler; params ["_unit", "_nozzle"]; diff --git a/addons/refuel/functions/fnc_takeNozzle.sqf b/addons/refuel/functions/fnc_takeNozzle.sqf index cd8f8b4eb4..51db8789e5 100644 --- a/addons/refuel/functions/fnc_takeNozzle.sqf +++ b/addons/refuel/functions/fnc_takeNozzle.sqf @@ -80,7 +80,7 @@ params [ _nozzle setVariable [QGVAR(attachPos), _attachPos, true]; _nozzle setVariable [QGVAR(source), _source, true]; - [_source, "blockEngine", "ACE_Refuel", true] call EFUNC(common,statusEffect_set); + [_source, "blockEngine", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); _source setVariable [QGVAR(isConnected), true, true]; _source setVariable [QGVAR(ownedNozzle), _nozzle, true]; @@ -100,8 +100,8 @@ params [ _unit call EFUNC(common,fixLoweredRifleAnimation); _unit action ["SwitchWeapon", _unit, _unit, 299]; - [_unit, "forceWalk", "ACE_refuel", true] call EFUNC(common,statusEffect_set); - [_unit, "blockThrow", "ACE_refuel", true] call EFUNC(common,statusEffect_set); + [_unit, "forceWalk", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); + [_unit, "blockThrow", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); [_unit, _nozzle] call FUNC(startNozzleInHandsPFH); }, diff --git a/addons/sandbag/functions/fnc_deploy.sqf b/addons/sandbag/functions/fnc_deploy.sqf index 1ef8485112..3181890748 100644 --- a/addons/sandbag/functions/fnc_deploy.sqf +++ b/addons/sandbag/functions/fnc_deploy.sqf @@ -18,8 +18,8 @@ params ["_unit"]; // prevent the placing unit from running -[_unit, "forceWalk", "ACE_Sandbag", true] call EFUNC(common,statusEffect_set); -[_unit, "blockThrow", "ACE_Sandbag", true] call EFUNC(common,statusEffect_set); +[_unit, "forceWalk", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); +[_unit, "blockThrow", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); // create the sandbag private _sandBag = createVehicle ["ACE_SandbagObject_NoGeo", [0, 0, 0], [], 0, "NONE"]; diff --git a/addons/sandbag/functions/fnc_deployCancel.sqf b/addons/sandbag/functions/fnc_deployCancel.sqf index aa2c2419a3..bccae637e5 100644 --- a/addons/sandbag/functions/fnc_deployCancel.sqf +++ b/addons/sandbag/functions/fnc_deployCancel.sqf @@ -21,8 +21,8 @@ params ["_unit", "_key"]; if (_key != 1 || {GVAR(deployPFH) == -1}) exitWith {}; // enable running again -[_unit, "forceWalk", "ACE_Sandbag", false] call EFUNC(common,statusEffect_set); -[_unit, "blockThrow", "ACE_Sandbag", false] call EFUNC(common,statusEffect_set); +[_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); +[_unit, "blockThrow", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); // delete placement dummy deleteVehicle GVAR(sandBag); diff --git a/addons/sandbag/functions/fnc_deployConfirm.sqf b/addons/sandbag/functions/fnc_deployConfirm.sqf index 20b821b3b5..ef2aafd97c 100644 --- a/addons/sandbag/functions/fnc_deployConfirm.sqf +++ b/addons/sandbag/functions/fnc_deployConfirm.sqf @@ -18,8 +18,8 @@ params ["_unit"]; // enable running again -[_unit, "forceWalk", "ACE_Sandbag", false] call EFUNC(common,statusEffect_set); -[_unit, "blockThrow", "ACE_Sandbag", false] call EFUNC(common,statusEffect_set); +[_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); +[_unit, "blockThrow", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); // remove sandbag from inventory _unit removeItem "ACE_Sandbag_empty"; diff --git a/addons/switchunits/functions/fnc_initPlayer.sqf b/addons/switchunits/functions/fnc_initPlayer.sqf index ffc0f7ad63..ba9c3f77b3 100644 --- a/addons/switchunits/functions/fnc_initPlayer.sqf +++ b/addons/switchunits/functions/fnc_initPlayer.sqf @@ -36,7 +36,7 @@ if (vehicle _playerUnit == _playerUnit) then { removeAllContainers _playerUnit; _playerUnit linkItem "ItemMap"; - [_playerUnit, "forceWalk", "ACE_SwitchUnits", true] call EFUNC(common,statusEffect_set); + [_playerUnit, "forceWalk", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); [] call FUNC(addMapFunction); }; diff --git a/addons/tacticalladder/functions/fnc_cancelTLdeploy.sqf b/addons/tacticalladder/functions/fnc_cancelTLdeploy.sqf index 7c05cbbe63..24013f02d7 100644 --- a/addons/tacticalladder/functions/fnc_cancelTLdeploy.sqf +++ b/addons/tacticalladder/functions/fnc_cancelTLdeploy.sqf @@ -23,8 +23,8 @@ params ["_unit", "_key"]; if (_key != 1 || {isNull GVAR(ladder)}) exitWith {}; // enable running again -[_unit, "forceWalk", "ACE_Ladder", false] call EFUNC(common,statusEffect_set); -[_unit, "blockThrow", "ACE_Ladder", false] call EFUNC(common,statusEffect_set); +[_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); +[_unit, "blockThrow", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); detach GVAR(ladder); diff --git a/addons/tacticalladder/functions/fnc_confirmTLdeploy.sqf b/addons/tacticalladder/functions/fnc_confirmTLdeploy.sqf index 9fe13e4e65..8211dc5f9d 100644 --- a/addons/tacticalladder/functions/fnc_confirmTLdeploy.sqf +++ b/addons/tacticalladder/functions/fnc_confirmTLdeploy.sqf @@ -19,8 +19,8 @@ params ["_unit", "_ladder"]; // enable running again -[_unit, "forceWalk", "ACE_Ladder", false] call EFUNC(common,statusEffect_set); -[_unit, "blockThrow", "ACE_Ladder", false] call EFUNC(common,statusEffect_set); +[_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); +[_unit, "blockThrow", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); private _pos1 = getPosASL _ladder; private _pos2 = _ladder modelToWorldWorld (_ladder selectionPosition "check2"); diff --git a/addons/tacticalladder/functions/fnc_positionTL.sqf b/addons/tacticalladder/functions/fnc_positionTL.sqf index 6d6f78f1a3..e9168d75a1 100644 --- a/addons/tacticalladder/functions/fnc_positionTL.sqf +++ b/addons/tacticalladder/functions/fnc_positionTL.sqf @@ -21,8 +21,8 @@ params ["_unit", "_ladder"]; // prevent the placing unit from running -[_unit, "forceWalk", "ACE_Ladder", true] call EFUNC(common,statusEffect_set); -[_unit, "blockThrow", "ACE_Ladder", true] call EFUNC(common,statusEffect_set); +[_unit, "forceWalk", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); +[_unit, "blockThrow", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); { _ladder animate [_x, 0]; diff --git a/addons/trenches/functions/fnc_placeCancel.sqf b/addons/trenches/functions/fnc_placeCancel.sqf index a06ecff459..f3cd20c0be 100644 --- a/addons/trenches/functions/fnc_placeCancel.sqf +++ b/addons/trenches/functions/fnc_placeCancel.sqf @@ -21,8 +21,8 @@ params ["_unit", "_key"]; if (_key != 1 || {GVAR(digPFH) == -1}) exitWith {}; // enable running again -[_unit, "forceWalk", "ACE_Trenches", false] call EFUNC(common,statusEffect_set); -[_unit, "blockThrow", "ACE_Trenches", false] call EFUNC(common,statusEffect_set); +[_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); +[_unit, "blockThrow", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); // delete placement dummy deleteVehicle GVAR(trench); diff --git a/addons/trenches/functions/fnc_placeConfirm.sqf b/addons/trenches/functions/fnc_placeConfirm.sqf index 03d4791e02..9a49df86e7 100644 --- a/addons/trenches/functions/fnc_placeConfirm.sqf +++ b/addons/trenches/functions/fnc_placeConfirm.sqf @@ -18,8 +18,8 @@ params ["_unit"]; // enable running again -[_unit, "forceWalk", "ACE_Trenches", false] call EFUNC(common,statusEffect_set); -[_unit, "blockThrow", "ACE_Trenches", false] call EFUNC(common,statusEffect_set); +[_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); +[_unit, "blockThrow", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); // remove dig pfh [GVAR(digPFH)] call CBA_fnc_removePerFrameHandler; diff --git a/addons/trenches/functions/fnc_placeTrench.sqf b/addons/trenches/functions/fnc_placeTrench.sqf index f49aef4a38..e6e03e0b57 100644 --- a/addons/trenches/functions/fnc_placeTrench.sqf +++ b/addons/trenches/functions/fnc_placeTrench.sqf @@ -27,8 +27,8 @@ GVAR(trenchPlacementData) = getArray (configFile >> "CfgVehicles" >> _trenchClas TRACE_1("",GVAR(trenchPlacementData)); // prevent the placing unit from running -[_unit, "forceWalk", "ACE_Trenches", true] call EFUNC(common,statusEffect_set); -[_unit, "blockThrow", "ACE_Trenches", true] call EFUNC(common,statusEffect_set); +[_unit, "forceWalk", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); +[_unit, "blockThrow", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); // create the trench private _trench = createVehicle [_noGeoModel, [0, 0, 0], [], 0, "NONE"]; From 198c09dccd257c502eb8b50ee32cec45153968c1 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 12 Aug 2024 15:15:35 +0200 Subject: [PATCH 207/290] CUP Compat - Improve explosives compat (#10193) Updated CUP explosives compat --- .../compat_cup_weapons_explosives/CfgVehicles.hpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/addons/compat_cup_weapons/compat_cup_weapons_explosives/CfgVehicles.hpp b/addons/compat_cup_weapons/compat_cup_weapons_explosives/CfgVehicles.hpp index d10c315c3d..17a7c59848 100644 --- a/addons/compat_cup_weapons/compat_cup_weapons_explosives/CfgVehicles.hpp +++ b/addons/compat_cup_weapons/compat_cup_weapons_explosives/CfgVehicles.hpp @@ -1,32 +1,31 @@ class CfgVehicles { class ACE_Explosives_Place; class ACE_PipeBomb_place_CUP: ACE_Explosives_Place { - displayName = "Satchel Charge"; + displayName = "$STR_CUP_dn_PipeBomb"; model = "\CUP\Weapons\CUP_Weapons_Put\CUP_Satchel.p3d"; - ace_explosives_offset[] = {0, 0, 0}; }; class ACE_Mine_place_CUP: ACE_Explosives_Place { - displayName = "AT-15 Anti-Tank Mine"; + displayName = "$STR_CUP_dn_Mine"; model = "\CUP\Weapons\CUP_Weapons_Put\CUP_AT15.p3d"; - ace_explosives_offset[] = {0, 0, 0}; }; class ACE_MineE_place_CUP: ACE_Explosives_Place { - displayName = "TM46 Anti-Tank Mine"; + displayName = "$STR_CUP_dn_MineE"; model = "\CUP\Weapons\CUP_Weapons_Put\CUP_TM46.p3d"; - ace_explosives_offset[] = {0, 0, 0}; }; class ACE_IED_V1_place_CUP: ACE_Explosives_Place { - displayName = "IED"; + displayName = "$STR_A3_CfgVehicles_IEDUrbanSmall_F"; model = "\CUP\Weapons\CUP_Weapons_Put\CUP_IED_V1.p3d"; - ace_explosives_offset[] = {0, 0, 0}; }; class ACE_IED_V2_place_CUP: ACE_IED_V1_place_CUP { + displayName = "$STR_A3_CfgVehicles_IEDUrbanBig_F"; model = "\CUP\Weapons\CUP_Weapons_Put\CUP_IED_V2.p3d"; }; class ACE_IED_V3_place_CUP: ACE_IED_V1_place_CUP { + displayName = "$STR_A3_CfgVehicles_IEDLandSmall_F"; model = "\CUP\Weapons\CUP_Weapons_Put\CUP_IED_V3.p3d"; }; class ACE_IED_V4_place_CUP: ACE_IED_V1_place_CUP { + displayName = "$STR_A3_CfgVehicles_IEDLandBig_F"; model = "\CUP\Weapons\CUP_Weapons_Put\CUP_IED_V4.p3d"; }; }; From 5e65e56c5e7ad9cf915508cf47d0f7ff1baa2c82 Mon Sep 17 00:00:00 2001 From: johnb432 <58661205+johnb432@users.noreply.github.com> Date: Mon, 12 Aug 2024 15:16:27 +0200 Subject: [PATCH 208/290] Wiki - Fix dependencies list on wiki (#10109) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix dependencies list on wiki * laser-guided Co-authored-by: Jouni Järvinen * Update docs/wiki/feature/xm157.md Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> * Moved medical_menu to medical-gui --------- Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> Co-authored-by: Jouni Järvinen --- addons/atragmx/config.cpp | 2 +- addons/kestrel4500/config.cpp | 2 +- addons/rangecard/config.cpp | 2 +- docs/Gemfile | 2 ++ docs/wiki/development/dependencies.md | 18 +++++++----- docs/wiki/feature/artillerytables.md | 30 +++++++++++++++++++ docs/wiki/feature/cargo.md | 41 ++++++++++++++++++++++++++ docs/wiki/feature/casings.md | 17 +++++++++++ docs/wiki/feature/cookoff.md | 22 ++++++++++++++ docs/wiki/feature/dogtags.md | 40 +++++++++++++++++++++++++ docs/wiki/feature/field-rations.md | 30 +++++++++++++++++++ docs/wiki/feature/fieldmanual.md | 23 +++++++++++++++ docs/wiki/feature/gestures.md | 32 ++++++++++++++++++++ docs/wiki/feature/gunbag.md | 32 ++++++++++++++++++++ docs/wiki/feature/index.md | 8 ++--- docs/wiki/feature/killtracker.md | 17 +++++++++++ docs/wiki/feature/logistics-rope.md | 22 ++++++++++++++ docs/wiki/feature/maverick.md | 17 +++++++++++ docs/wiki/feature/medical-gui.md | 22 ++++++++++++++ docs/wiki/feature/medical_menu.md | 17 ----------- docs/wiki/feature/metis.md | 17 +++++++++++ docs/wiki/feature/minedetector.md | 25 ++++++++++++++++ docs/wiki/feature/mk6mortar.md | 2 -- docs/wiki/feature/quickmount.md | 27 +++++++++++++++++ docs/wiki/feature/realisticweights.md | 19 ++++++++++++ docs/wiki/feature/testmissions.md | 2 +- docs/wiki/feature/towing.md | 33 +++++++++++++++++++++ docs/wiki/feature/trenches.md | 42 +++++++++++++++++++++++++++ docs/wiki/feature/viewports.md | 1 + docs/wiki/feature/viewrestrictions.md | 17 +++++++++++ docs/wiki/feature/xm157.md | 27 +++++++++++++++++ docs/wiki/framework/index.md | 2 +- docs/wiki/functions/index.md | 2 +- optionals/nomedical/config.cpp | 2 +- optionals/norealisticnames/config.cpp | 2 +- tools/extract_dependencies.py | 3 ++ 36 files changed, 580 insertions(+), 39 deletions(-) create mode 100644 docs/wiki/feature/artillerytables.md create mode 100644 docs/wiki/feature/cargo.md create mode 100644 docs/wiki/feature/casings.md create mode 100644 docs/wiki/feature/cookoff.md create mode 100644 docs/wiki/feature/dogtags.md create mode 100644 docs/wiki/feature/field-rations.md create mode 100644 docs/wiki/feature/fieldmanual.md create mode 100644 docs/wiki/feature/gestures.md create mode 100644 docs/wiki/feature/gunbag.md create mode 100644 docs/wiki/feature/killtracker.md create mode 100644 docs/wiki/feature/logistics-rope.md create mode 100644 docs/wiki/feature/maverick.md create mode 100644 docs/wiki/feature/medical-gui.md delete mode 100644 docs/wiki/feature/medical_menu.md create mode 100644 docs/wiki/feature/metis.md create mode 100644 docs/wiki/feature/minedetector.md create mode 100644 docs/wiki/feature/quickmount.md create mode 100644 docs/wiki/feature/realisticweights.md create mode 100644 docs/wiki/feature/towing.md create mode 100644 docs/wiki/feature/trenches.md create mode 100644 docs/wiki/feature/viewrestrictions.md create mode 100644 docs/wiki/feature/xm157.md diff --git a/addons/atragmx/config.cpp b/addons/atragmx/config.cpp index 125d4a488e..9b02aba491 100644 --- a/addons/atragmx/config.cpp +++ b/addons/atragmx/config.cpp @@ -6,7 +6,7 @@ class CfgPatches { units[] = {"ACE_Item_ATragMX"}; weapons[] = {"ACE_ATragMX"}; requiredVersion = REQUIRED_VERSION; - requiredAddons[] = {"ACE_Advanced_Ballistics", "ACE_common", "ACE_weather"}; + requiredAddons[] = {"ace_advanced_ballistics", "ace_common", "ace_weather"}; author = ECSTRING(common,ACETeam); authors[] = {"Ruthberg"}; url = ECSTRING(main,URL); diff --git a/addons/kestrel4500/config.cpp b/addons/kestrel4500/config.cpp index 5ea15f07ff..fc339ccf6b 100644 --- a/addons/kestrel4500/config.cpp +++ b/addons/kestrel4500/config.cpp @@ -6,7 +6,7 @@ class CfgPatches { units[] = {"ACE_Item_Kestrel4500"}; weapons[] = {"ACE_Kestrel4500"}; requiredVersion = REQUIRED_VERSION; - requiredAddons[] = {"ACE_common", "ACE_weather"}; + requiredAddons[] = {"ace_common", "ace_weather"}; author = ECSTRING(common,ACETeam); authors[] = {ECSTRING(common,ACETeam), "Ruthberg"}; url = ECSTRING(main,URL); diff --git a/addons/rangecard/config.cpp b/addons/rangecard/config.cpp index f300fb1a30..56ebec629d 100644 --- a/addons/rangecard/config.cpp +++ b/addons/rangecard/config.cpp @@ -6,7 +6,7 @@ class CfgPatches { units[] = {"ACE_Item_RangeCard"}; weapons[] = {"ACE_RangeCard"}; requiredVersion = REQUIRED_VERSION; - requiredAddons[] = {"ACE_Advanced_Ballistics","ace_scopes"}; + requiredAddons[] = {"ace_advanced_ballistics", "ace_scopes"}; author = ECSTRING(common,ACETeam); authors[] = {"Ruthberg"}; url = ECSTRING(main,URL); diff --git a/docs/Gemfile b/docs/Gemfile index 053c27dc35..486c7aac0f 100644 --- a/docs/Gemfile +++ b/docs/Gemfile @@ -1,2 +1,4 @@ source 'https://rubygems.org' gem 'github-pages' +gem 'tzinfo-data' +gem 'webrick' diff --git a/docs/wiki/development/dependencies.md b/docs/wiki/development/dependencies.md index b43371034c..c6d0f87d63 100644 --- a/docs/wiki/development/dependencies.md +++ b/docs/wiki/development/dependencies.md @@ -21,16 +21,18 @@ Because `ace_zeus` is being removed you must also remove any components that req ## 2. Dependencies -{% assign pages_by_title = site.pages | sort: "title" %} +{% assign pages_by_title = site.pages | sort_natural: "title" %} {% for page in pages_by_title %} {%- if page.group == 'feature' and page.component -%} - ### {{ page.title }} + {%- unless page.version.removed -%} + ### {{ page.title }} + + {% capture component %}{{ page.component }}{% endcapture %} + {% include dependencies_list.md component=component %} - {% capture component %}{{ page.component }}{% endcapture %} - {% include dependencies_list.md component=component %} - - {%- if page.core_component -%} - _Note: This module is required by nearly all other modules. Do NOT remove it!_ - {% endif %} + {%- if page.core_component -%} + _Note: This module is required by nearly all other modules. Do NOT remove it!_ + {% endif %} + {% endunless %} {% endif %} {% endfor %} diff --git a/docs/wiki/feature/artillerytables.md b/docs/wiki/feature/artillerytables.md new file mode 100644 index 0000000000..4bdfb5c5d5 --- /dev/null +++ b/docs/wiki/feature/artillerytables.md @@ -0,0 +1,30 @@ +--- +layout: wiki +title: Artillery Tables +component: artillerytables +description: Adds universal rangetables for artillery. +group: feature +category: equipment +parent: wiki +mod: ace +version: + major: 3 + minor: 13 + patch: 0 +--- + +## 1. Overview + +### 1.1 Features +- Adds a rangetable to accurately take out your target without the artillery computer. +- Shows accurate elevation and azimuth. +- Optionally adds wind deflection and air friction for shells. +- Optionally disables artillery computers. + +## 2. Usage + +### 2.1 Opening a rangetable +- Enter a piece of artillery. +- Use Self Interact Ctrl+⊞ Win (ACE3 default). +- Select `Equipment`. +- Select the rangetable of the piece of artillery you are in. diff --git a/docs/wiki/feature/cargo.md b/docs/wiki/feature/cargo.md new file mode 100644 index 0000000000..304ba70944 --- /dev/null +++ b/docs/wiki/feature/cargo.md @@ -0,0 +1,41 @@ +--- +layout: wiki +title: Cargo +component: cargo +description: Adds the ability to transport cargo using vehicles. +group: feature +category: interaction +parent: wiki +mod: ace +version: + major: 3 + minor: 3 + patch: 0 +--- + +## 1. Overview +Adds the ability to load and unload cargo from vehicles. Unloading can happen via two methods: Regular unloading and deploying, where you can preplace the item before it's unloaded. + +## 2. Usage + +### 2.1 Loading an object +- Interact with the object to be loaded ⊞ win. +- Select the `Load` option. +- Select which vehicle you want to load the object in. +- Wait for the progress bar to finish. To cancel loading, press Escape. + +### 2.2 Checking a vehicle's cargo +- Interact with the vehicle whose cargo is to b e checked ⊞ win. +- Select the `Cargo` option. + +### 2.3 Unloading an object from a vehicle +- Open the vehicle's cargo menu (see "Checking a vehicle's cargo") +- Press `Unload`. +- Wait for the progress bar to finish. To cancel unloading, press Escape. + +### 2.4 Deploying an object from a vehicle +- Open the vehicle's cargo menu (see "Checking a vehicle's cargo") +- Press `Deploy`. +- Use the mouse to fine tune the placement of the object. +- When ready to place, press left click to start deploying the object. +- Wait for the progress bar to finish. To cancel deploying, press Escape. diff --git a/docs/wiki/feature/casings.md b/docs/wiki/feature/casings.md new file mode 100644 index 0000000000..8bcf24a696 --- /dev/null +++ b/docs/wiki/feature/casings.md @@ -0,0 +1,17 @@ +--- +layout: wiki +title: Casings +component: casings +description: Adds infantry bullet casings on the ground when weapons are fired. +group: feature +category: realism +parent: wiki +mod: ace +version: + major: 3 + minor: 15 + patch: 0 +--- + +## 1. Overview +Spits out casings from infantry weapons when fired. diff --git a/docs/wiki/feature/cookoff.md b/docs/wiki/feature/cookoff.md new file mode 100644 index 0000000000..19a3289388 --- /dev/null +++ b/docs/wiki/feature/cookoff.md @@ -0,0 +1,22 @@ +--- +layout: wiki +title: Cook-off +component: cookoff +description: Adds cook-off effects to vehicles and ammunition boxes that have had their ammunition detonated or that have been destroyed. +group: feature +category: realism +parent: wiki +mod: ace +version: + major: 3 + minor: 7 + patch: 0 +--- + +## 1. Overview + +### 1.1 Features +- Adds engine fires when a vehicle's engine is damaged heavily. +- Optionally adds fire if a vehicle suffers ammunition detonations (requires `Vehicle Damage` to be enabled). +- Optionally adds ammunition detonation if a vehicle is destroyed. +- Optionally adds ammunition detonation if an ammunition box is destroyed or hit with explosive, incendiary or tracer ammunition. diff --git a/docs/wiki/feature/dogtags.md b/docs/wiki/feature/dogtags.md new file mode 100644 index 0000000000..9f1d27e371 --- /dev/null +++ b/docs/wiki/feature/dogtags.md @@ -0,0 +1,40 @@ +--- +layout: wiki +title: Dog Tags +component: dogtags +description: Adds dog tags to units. +group: feature +category: realism +parent: wiki +mod: ace +version: + major: 3 + minor: 7 + patch: 0 +--- + +## 1. Overview +Provides dog tags to units, which include name, social security number and blood type as information. + +## 2. Usage + +### 2.1 Checking a unit's dog tags +- Interact with the unconscious or dead unit whose dog tags are to be checked ⊞ win. +- Select the `Dog Tag` option. +- Select the `Check` option. + +### 2.2 Taking a unit's dog tags +- Interact with the unconscious or dead unit whose dog tags are to be checked ⊞ win. +- Select the `Dog Tag` option. +- Select the `Take` option. +- If the one of the two dog tags has already been taken, it will inform you and not give you the 2nd dog tag + +### 2.3 Checking what dog tags you have via self-interaction +- Use Self Interact Ctrl+⊞ Win (ACE3 default). +- Select the `Equipment` option. +- Select the `Check Dog Tag` option. + +### 2.4 Checking what dog tags you have via context menu +- Open your inventory and find the dog tag you want to inspect. +- Double click the item. +- Click `Check Dog Tag`. diff --git a/docs/wiki/feature/field-rations.md b/docs/wiki/feature/field-rations.md new file mode 100644 index 0000000000..63daad9963 --- /dev/null +++ b/docs/wiki/feature/field-rations.md @@ -0,0 +1,30 @@ +--- +layout: wiki +title: Field Rations +component: field_rations +description: Adds a thirst and hunger system, along with food to replenish those. +group: feature +category: realism +parent: wiki +mod: acex +version: + major: 3 + minor: 4 + patch: 0 +--- + +## 1. Overview +Simulates hunger and thirst which need to be replenished. This system is affected by other modules, such as weather and medical, and can in turn affect fatigue. + +## 2. Usage + +### 2.1 Satiate hunger/Quench thirst via self-interaction +- Pick up a drink. +- Use Self Interact Ctrl+⊞ Win (ACE3 default). +- Select the `Survival` option. +- Choose an item to consume. + +### 2.2 Satiate hunger/Quench thirst via context menu +- Open your inventory and find the item you want to consume. +- Double click the item. +- Click `Eat/Drink`. diff --git a/docs/wiki/feature/fieldmanual.md b/docs/wiki/feature/fieldmanual.md new file mode 100644 index 0000000000..bf6af86fe2 --- /dev/null +++ b/docs/wiki/feature/fieldmanual.md @@ -0,0 +1,23 @@ +--- +layout: wiki +title: Field Manual +component: fieldmanual +description: Adds ACE3 content to the field manual. +group: feature +category: general +parent: wiki +mod: ace +version: + major: 3 + minor: 16 + patch: 0 +--- + +## 1. Overview +Provides information on items and mechanics that ACE3 adds. + +## 2. Usage + +### 2.1 Opening the field manual +- Press Escape. +- Press `Field Manual`. diff --git a/docs/wiki/feature/gestures.md b/docs/wiki/feature/gestures.md new file mode 100644 index 0000000000..30be084be3 --- /dev/null +++ b/docs/wiki/feature/gestures.md @@ -0,0 +1,32 @@ +--- +layout: wiki +title: Gestures +component: gestures +description: Adds gestures that can be used for communication. +group: feature +category: interaction +parent: wiki +mod: ace +version: + major: 3 + minor: 4 + patch: 0 +--- + +## 1. Overview +Adds the ability to use 14 gestures for communication. + +## 2. Usage + +### 2.1 Using gestures via self-interaction + +- Use Self Interact Ctrl+⊞ Win (ACE3 default). +- Select the `Gestures` option. + +### 2.2 Rebinding keybinds for gestures + +- Press Escape. +- Select `Options`. +- Select `Controls`. +- Select `Configure Addons`. +- Select `ACE Gestures`. diff --git a/docs/wiki/feature/gunbag.md b/docs/wiki/feature/gunbag.md new file mode 100644 index 0000000000..35e2dd5e59 --- /dev/null +++ b/docs/wiki/feature/gunbag.md @@ -0,0 +1,32 @@ +--- +layout: wiki +title: Gun Bag +component: gunbag +description: Adds a gun bag that can be used to store a weapon. +group: feature +category: equipment +parent: wiki +mod: ace +version: + major: 3 + minor: 6 + patch: 0 +--- + +## 1. Overview +Adds easy handling and storage of an additional weapon in a backpack. + +## 2. Usage + +### 2.1 Interacting with your gun bag via self-interaction +- Use Self Interact Ctrl+⊞ Win (ACE3 default). +- Select the `Equipment` option. +- Select the `Gunbag` option. + +### 2.2 Interacting with your gun bag via the ACE arsenal +- Open an ACE arsenal. +- Get yourself a gun bag if you don't have one already. +- Select the primary weapon or backpack tab to interact with weapon. + +### 2.3 Interacting with another unit's gun bag +- Interact with the unit ⊞ win. diff --git a/docs/wiki/feature/index.md b/docs/wiki/feature/index.md index 41fd0fdeea..1c7039dfd2 100644 --- a/docs/wiki/feature/index.md +++ b/docs/wiki/feature/index.md @@ -19,7 +19,7 @@ redirect_from: "/wiki/featurex"

General