Merge branch 'master' into pr/8215

This commit is contained in:
PabstMirror 2024-03-28 14:45:59 -05:00
commit b5d0ae600a
859 changed files with 10154 additions and 3906 deletions

View File

@ -11,11 +11,10 @@ sort-direction: ascending
categories:
- title: '**ADDED:**'
labels:
- 'kind/feature request'
- 'kind/added feature'
- 'kind/feature'
- title: '**FIXED:**'
labels:
- 'kind/bug fix'
- 'kind/bug-fix'
- title: '**IMPROVED:**'
labels:
- 'kind/enhancement'
@ -23,17 +22,16 @@ categories:
- title: '**CHANGED:**'
labels:
- 'kind/cleanup'
- 'area/compatibility'
- 'kind/change'
- title: '**SETTINGS:**'
labels:
- 'kind/setting'
- title: '**TRANSLATIONS:**'
labels:
- 'area/translations'
- 'kind/translation'
exclude-labels:
- 'ignore changelog'
- 'ignore-changelog'
- 'dependencies'
change-template: '- $TITLE (#$NUMBER)'

View File

@ -48,7 +48,7 @@ jobs:
- name: Rename build folder
run: mv .hemttout/build .hemttout/@ace
- name: Upload Artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ace3-${{ github.sha }}-nobin
path: .hemttout/@*

View File

@ -47,7 +47,7 @@ jobs:
destination: docs/_site/
- name: Upload Artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: jekyll-site
path: docs/_site/
@ -63,7 +63,7 @@ jobs:
steps:
- name: Download Artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: jekyll-site
path: _site/

View File

@ -23,7 +23,7 @@ jobs:
cd build
cmake .. && cmake --build .
- name: Upload Artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ace3_extensions-${{ matrix.os }}-debug
path: extensions/build

View File

@ -38,7 +38,7 @@ jobs:
- name: Rename build folder
run: mv .hemttout/build .hemttout/@ace
- name: Upload Artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ace3-${{ github.sha }}
path: .hemttout/@*

View File

@ -67,18 +67,19 @@ jobs:
xcopy /e /h /q z\ace\tools\pDummies\gm gm\
xcopy /e /h /q z\ace\tools\pDummies\vn vn\
xcopy /e /h /q z\ace\tools\pDummies\WW2 WW2\
xcopy /e /h /q z\ace\tools\pDummies\CUP CUP\
- name: Build
run: py P:\z\ace\tools\make.py ci
env:
PYTHONUNBUFFERED: 1
- name: Archive logs
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
if: ${{ always() }}
with:
name: logs
path: temp/*.log
- name: Archive @ace
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: '@ace3-${{ github.sha }}'
path: z\ace\release\@ace

View File

@ -11,6 +11,6 @@ jobs:
steps:
- name: Release Drafter
if: github.repository == 'acemod/ACE3'
uses: release-drafter/release-drafter@v5
uses: release-drafter/release-drafter@v6
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

1
.gitignore vendored
View File

@ -20,3 +20,4 @@ CHANGELOG.md
sqfvm.exe
ArmaScriptCompiler.exe
*.sqfc
!extras/**/*.zip

View File

@ -6,6 +6,7 @@
# request, preferably including an email address.
# CORE TEAM
BaerMitUmlaut
Brett Mayson
bux578 <github@jonathandavid.de>
commy2
@ -25,6 +26,7 @@ Kieran
kymckay
mharis001 <mhariszakar@gmail.com>
MikeMF
MiszczuZPolski
NouberNou
PabstMirror <pabstmirror@gmail.com>
Ruthberg <ulteq@web.de>
@ -56,7 +58,6 @@ Arcanum417 <lubos.len@gmail.com>
Arkhir <wonsz666@gmail.com >
ARV187 aka Spark23
Asgar Serran <piechottaf@web.de>
BaerMitUmlaut
Bamse <bamsis@gmail.com>
Barman75
Bla1337
@ -126,6 +127,7 @@ Keithen <Keithen.Neu@gmail.com>
Kllrt <kllrtik@gmail.com>
KokaKolaA3
Krzyciu
LAxemann
legman <juicemelon@msn.com>
Legolasindar "Viper" <legolasindar@gmail.com>
licht-im-Norden87 <lichtimnorden87@gmail.com>
@ -190,3 +192,4 @@ YetheSamartaka
xrufix
Zakant <Zakant@gmx.de>
zGuba
Zman6258

View File

@ -5,7 +5,7 @@
<p align="center">
<a href="https://github.com/acemod/ACE3/releases/latest">
<img src="https://img.shields.io/badge/Version-3.16.1-blue.svg?style=flat-square" alt="ACE3 Version">
<img src="https://img.shields.io/github/release/acemod/ACE3.svg?style=flat-square&label=Version" alt="ACE3 Version">
</a>
<a href="https://github.com/acemod/ACE3/issues">
<img src="https://img.shields.io/github/issues-raw/acemod/ACE3.svg?style=flat-square&label=Issues" alt="ACE3 Issues">

View File

@ -1,7 +1,5 @@
#include "script_component.hpp"
#include "initKeybinds.inc.sqf"
GVAR(currentbulletID) = -1;
GVAR(Protractor) = false;
@ -11,6 +9,8 @@ GVAR(currentGrid) = 0;
if (!hasInterface) exitWith {};
#include "initKeybinds.inc.sqf"
["CBA_settingsInitialized", {
//If not enabled, dont't add PFEH
if (!GVAR(enabled)) exitWith {};
@ -19,11 +19,11 @@ if (!hasInterface) exitWith {};
[] call FUNC(initializeTerrainExtension);
// Register fire event handler
["ace_firedPlayer", DFUNC(handleFired)] call CBA_fnc_addEventHandler;
["ace_firedPlayerNonLocal", DFUNC(handleFired)] call CBA_fnc_addEventHandler;
["ace_firedPlayer", LINKFUNC(handleFired)] call CBA_fnc_addEventHandler;
["ace_firedPlayerNonLocal", LINKFUNC(handleFired)] call CBA_fnc_addEventHandler;
// Register Perframe Handler
[FUNC(handleFirePFH), GVAR(simulationInterval)] call CBA_fnc_addPerFrameHandler;
[LINKFUNC(handleFirePFH), GVAR(simulationInterval)] call CBA_fnc_addPerFrameHandler;
//Add warnings for missing compat PBOs (only if AB is on)
{

View File

@ -17,7 +17,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);
TRACE_10("firedEH:",_unit,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile,_vehicle,_gunner,_turret);
if (!(_ammo isKindOf "BulletBase")) exitWith {};
if (!alive _projectile) exitWith {};

View File

@ -22,7 +22,7 @@ private _initStartTime = diag_tickTime;
private _mapSize = worldSize;
if (("ace_advanced_ballistics" callExtension format["init:%1:%2", worldName, _mapSize]) == "Terrain already initialized") exitWith {
INFO_1("Terrain already initialized [world: %1]", worldName);
INFO_1("Terrain already initialized [world: %1]",worldName);
#ifdef DEBUG_MODE_FULL
systemChat "AdvancedBallistics: Terrain already initialized";
#endif
@ -33,14 +33,14 @@ private _gridCells = _mapGrids * _mapGrids;
GVAR(currentGrid) = 0;
INFO_2("Starting Terrain Extension [cells: %1] [world: %2]", _gridCells, worldName);
INFO_2("Starting Terrain Extension [cells: %1] [world: %2]",_gridCells,worldName);
[{
params ["_args","_idPFH"];
_args params ["_mapGrids", "_gridCells", "_initStartTime"];
if (GVAR(currentGrid) >= _gridCells) exitWith {
INFO_2("Finished terrain initialization in %1 seconds [world: %2]", (diag_tickTime - _initStartTime) toFixed 2, worldName);
INFO_2("Finished terrain initialization in %1 seconds [world: %2]",(diag_tickTime - _initStartTime) toFixed 2,worldName);
#ifdef DEBUG_MODE_FULL
systemChat format["AdvancedBallistics: Finished terrain initialization in %1 seconds", (diag_tickTime - _initStartTime) toFixed 2];
#endif
@ -53,7 +53,7 @@ INFO_2("Starting Terrain Extension [cells: %1] [world: %2]", _gridCells, worldNa
private _gridCenter = [_x + 25, _y + 25];
private _gridHeight = round(getTerrainHeightASL _gridCenter);
private _gridNumObjects = count (_gridCenter nearObjects ["Building", 50]);
private _gridSurfaceIsWater = if (surfaceIsWater _gridCenter) then {1} else {0};
private _gridSurfaceIsWater = parseNumber (surfaceIsWater _gridCenter);
"ace_advanced_ballistics" callExtension format["set:%1:%2:%3", _gridHeight, _gridNumObjects, _gridSurfaceIsWater];
GVAR(currentGrid) = GVAR(currentGrid) + 1;
if (GVAR(currentGrid) >= _gridCells) exitWith {};

View File

@ -44,6 +44,9 @@ if (!(_dragModel in [1, 2, 5, 6, 7, 8])) then {
_dragModel = 1;
};
private _ballisticCoefficients = getArray(_ammoConfig >> "ACE_ballisticCoefficients");
if (_ballisticCoefficients isEqualTo []) then {
_ballisticCoefficients = [0.5];
};
private _velocityBoundaries = getArray(_ammoConfig >> "ACE_velocityBoundaries");
private _atmosphereModel = getText(_ammoConfig >> "ACE_standardAtmosphere");
if (_atmosphereModel isEqualTo "") then {
@ -66,7 +69,7 @@ if ((_typicalSpeed > 0) && {_typicalSpeed < 360}) then {
if (_inheritedBarrelConfig || _inheritedTempConfig) then {
private _parentConfig = inheritsFrom _ammoConfig;
private _parentSpeed = getNumber (_parentConfig >> "typicalSpeed");
WARNING_4("Subsonic Ammo %1 (%2 m/s) missing `ACE_muzzleVelocities` or `ACE_ammoTempMuzzleVelocityShifts` configs, attempting to use parent %3 (%4m/s)",_this,_typicalSpeed,configName _parentConfig, _parentSpeed);
WARNING_4("Subsonic Ammo %1 (%2 m/s) missing `ACE_muzzleVelocities` or `ACE_ammoTempMuzzleVelocityShifts` configs, attempting to use parent %3 (%4m/s)",_this,_typicalSpeed,configName _parentConfig,_parentSpeed);
if (_parentSpeed <= 0) exitWith {//Handle weird or null parent
_muzzleVelocityTable = [];
_ammoTempMuzzleVelocityShifts = [];

View File

@ -21,7 +21,7 @@
private _weaponConfig = (configFile >> "CfgWeapons" >> _this);
private _barrelTwist = 0 max getNumber(_weaponConfig >> "ACE_barrelTwist");
private _twistDirection = [0, 1] select (_barrelTwist != 0);
private _twistDirection = parseNumber (_barrelTwist != 0);
if (isNumber (_weaponConfig >> "ACE_twistDirection")) then {
_twistDirection = getNumber (_weaponConfig >> "ACE_twistDirection");
if !(_twistDirection in [-1, 0, 1]) then {

View File

@ -2,35 +2,6 @@
if (!hasInterface) exitWith {};
["baseline", {
private _fatigue = ACE_player getVariable [QGVAR(aimFatigue), 0];
switch (stance ACE_player) do {
case ("CROUCH"): {
(1.0 + _fatigue ^ 2 * 0.1)
};
case ("PRONE"): {
(1.0 + _fatigue ^ 2 * 2.0)
};
default {
(1.5 + _fatigue ^ 2 * 3.0)
};
};
}, QUOTE(ADDON)] call EFUNC(common,addSwayFactor);
["multiplier", {
switch (true) do {
case (isWeaponRested ACE_player): {
GVAR(swayFactor) * GVAR(restedSwayFactor)
};
case (isWeaponDeployed ACE_player): {
GVAR(swayFactor) * GVAR(deployedSwayFactor)
};
default {
GVAR(swayFactor)
};
};
}, QUOTE(ADDON)] call EFUNC(common,addSwayFactor);
// 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;
@ -39,6 +10,21 @@ if (!hasInterface) exitWith {};
["CBA_settingsInitialized", {
if (!GVAR(enabled)) exitWith {};
["baseline", {
private _fatigue = ACE_player getVariable [QGVAR(aimFatigue), 0];
switch (stance ACE_player) do {
case ("CROUCH"): {
(1.0 + _fatigue ^ 2 * 0.1)
};
case ("PRONE"): {
(1.0 + _fatigue ^ 2 * 2.0)
};
default {
(1.5 + _fatigue ^ 2 * 3.0)
};
};
}, QUOTE(ADDON)] call EFUNC(common,addSwayFactor);
// - Post process effect ------------------------------------------------------
GVAR(ppeBlackout) = ppEffectCreate ["ColorCorrections", 4220];
GVAR(ppeBlackout) ppEffectEnable true;
@ -60,7 +46,7 @@ if (!hasInterface) exitWith {};
}, true] call CBA_fnc_addPlayerEventHandler;
// - Duty factors -------------------------------------------------------------
if (["ace_medical"] call EFUNC(common,isModLoaded)) then {
if (GVAR(medicalLoaded)) 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);

View File

@ -13,5 +13,6 @@ GVAR(dutyList) = createHashMap;
GVAR(setAnimExclusions) = [];
GVAR(inertia) = 0;
GVAR(inertiaCache) = createHashMap;
GVAR(medicalLoaded) = ["ace_medical"] call EFUNC(common,isModLoaded);
ADDON = true;

View File

@ -23,6 +23,12 @@ if (!alive ACE_player) exitWith {
_staminaBarContainer ctrlCommit 1;
};
private _oxygen = 0.9; // Default AF oxygen saturation
if (GVAR(medicalLoaded) && {EGVAR(medical_vitals,simulateSpo2)}) then {
_oxygen = (ACE_player getVariable [QEGVAR(medical,spo2), 97]) / 100;
};
private _currentWork = REE;
private _currentSpeed = (vectorMagnitude (velocity ACE_player)) min 6;
@ -42,8 +48,8 @@ GVAR(muscleDamage) = (GVAR(muscleDamage) + (_currentWork / GVAR(peakPower)) ^ 3.
private _muscleIntegritySqrt = sqrt (1 - GVAR(muscleDamage));
// 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 * _muscleIntegritySqrt;
private _ae2PathwayPowerFatigued = GVAR(ae2PathwayPower) * sqrt (GVAR(ae2Reserve) / AE2_MAXRESERVE) * _oxygen * _muscleIntegritySqrt;
// Calculate how much power is consumed from each reserve
private _ae1Power = _currentWork min _ae1PathwayPowerFatigued;
@ -58,8 +64,8 @@ GVAR(anReserve) = GVAR(anReserve) - _anPower / WATTSPERATP;
GVAR(anFatigue) = GVAR(anFatigue) + _anPower * (0.057 / GVAR(peakPower)) * 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 * 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;
// Anaerobic ATP reserver and fatigue recovery
GVAR(anReserve) = ((GVAR(anReserve)
@ -70,9 +76,9 @@ GVAR(anFatigue) = ((GVAR(anFatigue)
- (_ae1PathwayPowerFatigued + _ae2PathwayPowerFatigued - _ae1Power - _ae2Power) * (0.057 / GVAR(peakPower)) * GVAR(anFatigue) ^ 2 * GVAR(recoveryFactor)
) min 1) max 0;
private _aeReservePercentage = (GVAR(ae1Reserve) / AE1_MAXRESERVE + GVAR(ae2Reserve) / AE2_MAXRESERVE) / 2;
private _anReservePercentage = GVAR(anReserve) / AN_MAXRESERVE;
private _perceivedFatigue = 1 - (_anReservePercentage min _aeReservePercentage);
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);

View File

@ -80,30 +80,3 @@
[0, 5, 1, 1],
true
] call CBA_fnc_addSetting;
[
QGVAR(swayFactor),
"SLIDER",
[LSTRING(SwayFactor), LSTRING(SwayFactor_Description)],
LSTRING(DisplayName),
[0, 5, 1, 1],
true
] call CBA_fnc_addSetting;
[
QGVAR(restedSwayFactor),
"SLIDER",
[LSTRING(RestedSwayFactor), LSTRING(RestedSwayFactor_Description)],
LSTRING(DisplayName),
[0, 5, 1, 2],
true
] call CBA_fnc_addSetting;
[
QGVAR(deployedSwayFactor),
"SLIDER",
[LSTRING(DeployedSwayFactor), LSTRING(DeployedSwayFactor_Description)],
LSTRING(DisplayName),
[0, 5, 1, 2],
true
] call CBA_fnc_addSetting;

View File

@ -44,7 +44,7 @@
<Italian>Influenza la prestazione generale di tutti i giocatori smuniti di un fattore personalizzato. Maggiore significa migliore.</Italian>
<Chinese>影響所有玩家的體力表現,值越高代表體力越好</Chinese>
<Chinesesimp>影响所有玩家的体力表现,值越高代表体力越好</Chinesesimp>
<Russian>Влияет на общую производительность игроков, у которых не задано персональное значение.</Russian>
<Russian>Влияет на общую производительность игроков, у которых не задано персональное значение. Чем выше, тем лучше.</Russian>
<Portuguese>Influencia na performance geral de todos os jogadores sem nenhum fator personalizado. Quanto maior, melhor.</Portuguese>
<Czech>Ovlivňuje celkový výkon všech hráčů bez vlastního faktoru. Vyšší znamená lépe.</Czech>
</Key>
@ -59,7 +59,7 @@
<Italian>Influenza la prestazione personalizzata di questa unità. Maggiore significa migliore.</Italian>
<Chinese>影響這個單位的體力表現,值越高代表體力越好</Chinese>
<Chinesesimp>影响这个单位的体力表现,值越高代表体力越好</Chinesesimp>
<Russian>Влияет на общую производительность юнита.</Russian>
<Russian>Влияет на общую производительность юнита.Чем выше, тем лучше.</Russian>
<Portuguese>Influencia na performance geral dessa unidade. Quanto maior, melhor.</Portuguese>
<Czech>Ovlivňuje celkový výkon této jednotky. Vyšší znamená lépe.</Czech>
</Key>
@ -154,72 +154,6 @@
<Portuguese>Define o quanto que um terreno íngrime aumenta na perda de estamina. Quanto maior, maior a perda de estamina.</Portuguese>
<Czech>Nastavuje, o kolik strmý terén zvyšuje ztrátu výdrže. Vyšší znamená vyšší ztrátu výdrže.</Czech>
</Key>
<Key ID="STR_ACE_Advanced_Fatigue_SwayFactor">
<English>Sway factor</English>
<Spanish>Factor de balanceo de mira</Spanish>
<German>Verwacklungsfaktor</German>
<Japanese>手ぶれ因数</Japanese>
<Chinesesimp>抖动系数</Chinesesimp>
<Chinese>抖動因素</Chinese>
<French>Facteur de tremblement</French>
<Italian>Fattore di Oscillazione</Italian>
<Polish>Czynnik kołysania</Polish>
<Russian>Фактор колебания прицела</Russian>
<Portuguese>Fator de Balanço de Mira</Portuguese>
<Czech>Faktor kývání</Czech>
<Korean>손떨림 정도</Korean>
</Key>
<Key ID="STR_ACE_Advanced_Fatigue_SwayFactor_Description">
<English>Influences the amount of weapon sway. Higher means more sway.</English>
<Spanish>Afecta al la estabilidad de la mira. Más alto significa más balanceo</Spanish>
<German>Beeinflusst, wie ruhig man eine Waffe halten kann. Ein höherer Wert bedeutet weniger Stabilisierung.</German>
<Japanese>武器の手ぶれの量に影響します。値が高いほど、手ぶれが強くなります。</Japanese>
<Chinesesimp>影响手持武器的晃动程度,数值越高,抖动的越厉害。</Chinesesimp>
<Chinese>影響手持武器晃動程度,數值越高抖動越厲害</Chinese>
<French>Influe sur l'amplitude du tremblement de l'arme. Une valeur plus élevée signifie plus de tremblement.</French>
<Italian>Influenza l'aumento di oscillazione dell'arma quando affaticato. Maggiore significa più oscillazione.</Italian>
<Polish>Wpływa na poziom kołysania broni. Większa ilość znaczy większe kołysanie.</Polish>
<Russian>Влияет на колебания прицела оружия. Чем выше - тем больше.</Russian>
<Portuguese>Influencia a quantidade de balanço da mira da arma. Quanto maior, mais balanço.</Portuguese>
<Czech>Ovlivňuje množství kývání zbraní. Vyšší znamená více kývání.</Czech>
<Korean>손떨림의 정도를 정합니다. 높을 수록 많이 휘적입니다.</Korean>
</Key>
<Key ID="STR_ACE_Advanced_Fatigue_RestedSwayFactor">
<English>Rested sway factor</English>
<French>Facteur de balancement au repos</French>
<Korean>휴식 시 손떨림 정도</Korean>
<Portuguese>Fator de balanço de mira em repouso</Portuguese>
<German>Verwacklungsfaktor, wenn aufgelegt</German>
<Italian>Fattore di Oscillazione Appoggiato</Italian>
<Japanese>静止時の手ぶれ係数</Japanese>
</Key>
<Key ID="STR_ACE_Advanced_Fatigue_RestedSwayFactor_Description">
<English>Influences the amount of weapon sway while weapon is rested.</English>
<French>Influence le degré de balancement de l'arme au repos.</French>
<Korean>무기가 아무런 행동도 하지 않는 동안 무기가 흔들리는 정도를 정합니다.</Korean>
<Portuguese>Influencia a quantidade de balanço de mira enquanto a arma está em repouso.</Portuguese>
<German>Beeinflusst, wie ruhig man die Waffe hält, während sie aufgelegt ist.</German>
<Italian>Determina la quantità di oscillazione dell'arma quando questa è appoggiata.</Italian>
<Japanese>静止している時の武器の手ぶれの量に影響します。</Japanese>
</Key>
<Key ID="STR_ACE_Advanced_Fatigue_DeployedSwayFactor">
<English>Deployed sway factor</English>
<French>Facteur de balancement déployé</French>
<Korean>거치 시 손떨림 정도</Korean>
<Portuguese>Fator de balanço de mira em posição de tiro</Portuguese>
<German>Verwacklungsfaktor, wenn Zweibein aufgestellt ist.</German>
<Italian>Fattore di Oscillazione su Bipode</Italian>
<Japanese>展開時の手ぶれ係数</Japanese>
</Key>
<Key ID="STR_ACE_Advanced_Fatigue_DeployedSwayFactor_Description">
<English>Influences the amount of weapon sway while weapon is deployed.</English>
<French>Influence le degré de balancement de l'arme déployée.</French>
<Korean>무기를 거치하는 동안 무기를 흔드는 정도를 정합니다.</Korean>
<Portuguese>Influencia a quantidade de balanço de mira enquanto a arma está em posição de tiro.</Portuguese>
<German>Beeinflusst, wie ruhig man die Waffen hält, während das Zweibein aufgestellt ist.</German>
<Italian>Determina la quantità di oscillazione dell'arma quando questa è stabilizzata usando il bipode.</Italian>
<Japanese>武器の展開(Cキー)時の武器の手ぶれの量に影響します。</Japanese>
</Key>
<Key ID="STR_ACE_Advanced_Fatigue_Enabled">
<English>Enabled</English>
<Spanish>Activada</Spanish>
@ -246,7 +180,7 @@
<Italian>Abilita/Disabilita la Fatica Avanzata.</Italian>
<Chinese>啟用/關閉進階體力.</Chinese>
<Chinesesimp>启用/关闭进阶体力。</Chinesesimp>
<Russian>Включает / Отключает Продвинутую усталость</Russian>
<Russian>Включает/отключает Продвинутую усталость</Russian>
<Portuguese>Ativa/Desativa Fadiga Avançada.</Portuguese>
<Czech>Aktivuje / deaktivuje Pokročilou únavu.</Czech>
</Key>

View File

@ -2,11 +2,14 @@
// Fired XEH
GVAR(ammoEventHandlers) = createHashMap;
[QGVAR(throwFiredXEH), FUNC(throwFiredXEH)] call CBA_fnc_addEventHandler;
[QGVAR(throwFiredXEH), LINKFUNC(throwFiredXEH)] call CBA_fnc_addEventHandler;
// Exit on HC
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;
{

View File

@ -19,7 +19,7 @@ params ["_unit"];
if !(_unit getVariable [QGVAR(inHand), false]) exitWith {false};
if (vehicle _unit != _unit) exitWith {
if (!isNull objectParent _unit) exitWith {
private _startPos = eyePos _unit;
private _aimLinePos = AGLToASL (positionCameraToWorld [0, 0, 1]);
private _intersections = lineIntersectsSurfaces [_startPos, _aimLinePos, _unit, objNull, false];

View File

@ -53,6 +53,12 @@ _unit setVariable [QGVAR(dropDistance), DROP_DISTANCE_DEFAULT];
// Remove controls hint (check if ever enabled is inside the function)
call EFUNC(interaction,hideMouseHint);
// Hide wind info after throw, if it was temporarily enabled for the throw
if (GVAR(tempWindInfo)) then {
EGVAR(weather,WindInfo) = false;
GVAR(tempWindInfo) = false;
};
// Remove throw action
[_unit, "DefaultAction", _unit getVariable [QGVAR(throwAction), -1]] call EFUNC(common,removeActionEventHandler);

View File

@ -17,9 +17,9 @@
params ["_magazineClassname"];
_magazineClassname = toLower _magazineClassname;
_magazineClassname = toLowerANSI _magazineClassname;
private _throwMuzzles = getArray (configFile >> "CfgWeapons" >> "Throw" >> "muzzles");
_throwMuzzles = _throwMuzzles select {_magazineClassname in ((getArray (configFile >> "CfgWeapons" >> "Throw" >> _x >> "magazines")) apply {toLower _x})};
_throwMuzzles = _throwMuzzles select {_magazineClassname in ((getArray (configFile >> "CfgWeapons" >> "Throw" >> _x >> "magazines")) apply {toLowerANSI _x})};
[_throwMuzzles select 0, ""] select (_throwMuzzles isEqualTo [])

View File

@ -18,6 +18,15 @@
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);

View File

@ -45,7 +45,7 @@ if (!(_unit getVariable [QGVAR(primed), false])) then {
private _newVelocity = (_p1 vectorFromTo _p2) vectorMultiply _velocity;
// Adjust for throwing from inside vehicles, where we have a vehicle-based velocity that can't be compensated for by a human
if (vehicle _unit != _unit) then {
if (!isNull objectParent _unit) then {
_newVelocity = _newVelocity vectorAdd (velocity (vehicle _unit));
};

View File

@ -40,3 +40,11 @@ private _category = format ["ACE %1", localize LSTRING(Category)];
true,
1
] call CBA_fnc_addSetting;
[
QGVAR(enableTempWindInfo), "CHECKBOX",
[LSTRING(EnableTempWindInfo_DisplayName), LSTRING(EnableTempWindInfo_Description)],
_category,
true,
0
] call CBA_fnc_addSetting;

View File

@ -185,6 +185,20 @@
<Portuguese>Permite que arremessáveis fixados em objetos sejam pegos.</Portuguese>
<Czech>Zapíná schopnost zvednutí předmětů z objektů ke kterým jsou připnuté.</Czech>
</Key>
<Key ID="STR_ACE_Advanced_Throwing_EnableTempWindInfo_DisplayName">
<English>Show Temporary Wind Info</English>
<German>Zeige temporäre Windinformationen</German>
<Italian>Mostra informazioni sul vento temporaneamente</Italian>
<Japanese>一時的に風の情報を表示</Japanese>
<Korean>바람 정보 임시로 표시</Korean>
</Key>
<Key ID="STR_ACE_Advanced_Throwing_EnableTempWindInfo_Description">
<English>Temporarily display Wind Info while throwing, to aid in placing smoke grenades effectively.</English>
<German>Zeige während des werfens Windinformationen an, um Rauchgranaten effektiver zu platzieren.</German>
<Italian>Mostra le informazioni sul vento durante il lancio di granate, facilitando il piazzamento ottimale di fumogeni.</Italian>
<Japanese>投擲行動中に風向きの情報を一時的に表示し、発煙手榴弾の煙幕を効果的に展開しやすくします。</Japanese>
<Korean>연막탄을 효과적으로 배치하는 데 도움이 되도록 투척하는 동안 일시적으로 바람 정보를 표시합니다.</Korean>
</Key>
<Key ID="STR_ACE_Advanced_Throwing_Prepare">
<English>Prepare/Change Throwable</English>
<Spanish>Preparar/Cambiar objetos lanzables</Spanish>

View File

@ -16,7 +16,7 @@
} forEach _sections;
}] call CBA_fnc_addEventHandler;
[QGVAR(unGarrison), FUNC(unGarrison)] call CBA_fnc_addEventHandler;
[QGVAR(unGarrison), LINKFUNC(unGarrison)] call CBA_fnc_addEventHandler;
[QGVAR(doMove), {
params ["_unitsArray"];
@ -73,6 +73,6 @@
if (isServer) then {
["CAManBase", "init", {
// wait for HMD to be assigned so `hmd _unit` works
[FUNC(assignNVG), _this, 1] call CBA_fnc_waitAndExecute;
[LINKFUNC(assignNVG), _this, 1] call CBA_fnc_waitAndExecute;
}] call CBA_fnc_addClassEventHandler;
};

View File

@ -7,8 +7,8 @@
* 0: The building(s) nearest this position are used <POSITION>
* 1: Limit the building search to those type of building <ARRAY>
* 2: Units that will be garrisoned <ARRAY>
* 3: Radius to fill building(s) <SCALAR> (default: 50)
* 4: 0: even filling, 1: building by building, 2: random filling <SCALAR> (default: 0)
* 3: Radius to fill building(s) <NUMBER> (default: 50)
* 4: 0: even filling, 1: building by building, 2: random filling <NUMBER> (default: 0)
* 5: True to fill building(s) from top to bottom <BOOL> (default: false) (note: only works with filling mode 0 and 1)
* 6: Teleport units <BOOL> (default: false)
@ -128,7 +128,7 @@ switch (_fillingType) do {
} else {
private _pos = _building select 0;
private _nearestUnits = (_pos nearEntities ["CAManBase", 2]);
LOG(format [ARR_3("fnc_garrison: Unit detection | %1 units nearby | %2 units within height",count _nearestUnits, {floor ((getPos _x) select 2) == floor (_pos select 2)} count _nearestUnits)]);
LOG(format [ARR_3("fnc_garrison: Unit detection | %1 units nearby | %2 units within height",count _nearestUnits,{floor ((getPos _x) select 2) == floor (_pos select 2)} count _nearestUnits)]);
if (count _nearestUnits > 0 && {[_nearestUnits, _pos] call _fnc_comparePos}) then {
LOG(format [ARR_2("fnc_garrison: Unit present | removing position | %1 positions remaining for this building",count (_buildingsIndex select (_buildingsIndex find _building)) - 1)]);
@ -177,7 +177,7 @@ switch (_fillingType) do {
} else {
private _pos = _building select 0;
private _nearestUnits = (_pos nearEntities ["CAManBase", 2]);
LOG(format [ARR_3("fnc_garrison: Unit detection | %1 units nearby | %2 units within height",count _nearestUnits, {floor ((getPos _x) select 2) == floor (_pos select 2)} count _nearestUnits)]);
LOG(format [ARR_3("fnc_garrison: Unit detection | %1 units nearby | %2 units within height",count _nearestUnits,{floor ((getPos _x) select 2) == floor (_pos select 2)} count _nearestUnits)]);
if (count _nearestUnits > 0 && {[_nearestUnits, _pos] call _fnc_comparePos}) then {
LOG(format [ARR_2("fnc_garrison: Unit present | removing position | %1 positions remaining for this building",count (_buildingsIndex select (_buildingsIndex find _building)) - 1)]);
@ -224,7 +224,7 @@ switch (_fillingType) do {
} else {
private _pos = selectRandom _building;
private _nearestUnits = (_pos nearEntities ["CAManBase", 2]);
LOG(format [ARR_3("fnc_garrison: Unit detection | %1 units nearby | %2 units within height",count _nearestUnits, {floor ((getPos _x) select 2) == floor (_pos select 2)} count _nearestUnits)]);
LOG(format [ARR_3("fnc_garrison: Unit detection | %1 units nearby | %2 units within height",count _nearestUnits,{floor ((getPos _x) select 2) == floor (_pos select 2)} count _nearestUnits)]);
if (count _nearestUnits > 0 && {[_nearestUnits, _pos] call _fnc_comparePos}) then {
LOG(format [ARR_2("fnc_garrison: Unit present | removing position | %1 positions remaining for this building",count (_buildingsIndex select (_buildingsIndex find _building)) - 1)]);
@ -258,7 +258,7 @@ switch (_fillingType) do {
};
};
TRACE_1(format [ARR_2("fnc_garrison: while loop ended | %1 units ready to be treated by PFH",count _unitMoveList)], _teleport);
TRACE_1(format [ARR_2("fnc_garrison: while loop ended | %1 units ready to be treated by PFH",count _unitMoveList)],_teleport);
// Update the unit list and remove duplicate positions and units
private _garrison_unitMoveList = missionNameSpace getVariable [QGVAR(garrison_unitMoveList), []];
@ -279,5 +279,5 @@ if (_teleport) then {
[_unitMoveList] call FUNC(garrisonMove);
};
TRACE_1(format [ARR_3("fnc_garrison: End | %1 units left | %2 buildings left", count _unitsArray, count _buildingsIndex)], _unitsArray);
TRACE_1(format [ARR_3("fnc_garrison: End | %1 units left | %2 buildings left",count _unitsArray,count _buildingsIndex)],_unitsArray);
_unitsArray

View File

@ -81,13 +81,13 @@ if (isNil QGVAR(garrison_moveUnitPFH)) then {
[QGVAR(enableAttack), [[_unit], true], _unit] call CBA_fnc_targetEvent;
};
LOG(format [ARR_2("garrisonMove PFH: unit in position | %1 units left", count _unitMoveList)]);
LOG(format [ARR_2("garrisonMove PFH: unit in position | %1 units left",count _unitMoveList)]);
};
// Check if unit is alive or even existing
if (!alive _unit || {_unit getVariable [QGVAR(garrisoned), false]}) then {
_unitMoveList deleteAt (_unitMoveList find _x);
LOG(format [ARR_2("garrisonMove PFH: unit dead, deleted or garrisoned via TP | %1 units left", count _unitMoveList)]);
LOG(format [ARR_2("garrisonMove PFH: unit dead, deleted or garrisoned via TP | %1 units left",count _unitMoveList)]);
} else {
private _unitPos = getPos _unit;

View File

@ -28,7 +28,7 @@ _units = _units select {local _x};
private _leader = leader _unit;
TRACE_3("fnc_ungarrison: unit and leader",_unit , _leader, (_leader == _unit));
TRACE_3("fnc_ungarrison: unit and leader",_unit,_leader,(_leader == _unit));
_unit setVariable [QGVAR(garrisonned), false, true];

View File

@ -90,6 +90,7 @@
<French>Equipement JVN automatique</French>
<Portuguese>Equipar NVGs automaticamente</Portuguese>
<Japanese>暗視装置の自動装備</Japanese>
<Russian>Автоматическое оснащение ПНВ</Russian>
</Key>
<Key ID="STR_ACE_AI_AssignNVG_Description">
<English>Equips NVG in inventory during night time and unequips it during day time.\nDoes not add NVGs to inventory!</English>
@ -100,6 +101,7 @@
<French>Equipe des JVN pendant la nuit et les déséquipe le jour.\nN'ajoute pas les JVN dans l'intenvaire !</French>
<Portuguese>Equipa o NVG do inventário durante a noite e desequipa durante o dia.\nNão adiciona NVGs ao inventário!</Portuguese>
<Japanese>インベントリ内の暗視装置を夜間に装備し、日中は解除し収納します。\nこれはNVGをインベントリに追加しません。</Japanese>
<Russian>Экипирует ПНВ в ночное время и отключает его в дневное время.\nНе добавляет ПНВ в инвентарь!</Russian>
</Key>
</Package>
</Project>

View File

@ -17,13 +17,13 @@
*
* Public: No
*/
params ["_vehicle", "_group", "_type", "_value"];
TRACE_4("droneModifyWaypoint",_vehicle,_group,_type,_value);
private _index = (currentWaypoint _group) min count waypoints _group;
private _waypoint = [_group, _index];
switch (toLower _type) do {
switch (toLowerANSI _type) do {
case ("height"): {
private _pos = waypointPosition _waypoint;
_pos set [2, _value];

View File

@ -29,7 +29,10 @@ private _currentLoiterRadius = waypointLoiterRadius _waypoint;
private _currentLoiterType = waypointLoiterType _waypoint;
// Set pos to ATL
_pos set [2, if (_currentHeight >= 50) then { _currentHeight } else { 0 }];
_pos set [
2,
[0, _currentHeight] select (_currentHeight >= 50)
];
// [_group] call CBA_fnc_clearWaypoints;
_waypoint = _group addWaypoint [_pos, 0];

View File

@ -29,7 +29,7 @@
<Russian>Открыть грузовой отсек</Russian>
<Italian>Apri la rampa di carico</Italian>
<Portuguese>Abrir porta de carga</Portuguese>
<Japanese>カーゴ ドアを開く</Japanese>
<Japanese>貨物室ドアを 開く</Japanese>
<Korean>화물칸 개방</Korean>
<Chinese>開啟貨艙門</Chinese>
<Chinesesimp>开启货舱门</Chinesesimp>
@ -46,7 +46,7 @@
<Russian>Закрыть грузовой отсек</Russian>
<Italian>Chiudi la rampa di carico</Italian>
<Portuguese>Fechar porta de carga</Portuguese>
<Japanese>カーゴ ドアを閉じる</Japanese>
<Japanese>貨物室ドアを 閉じる</Japanese>
<Korean>화물칸 폐쇄</Korean>
<Chinese>關閉貨艙門</Chinese>
<Chinesesimp>关闭货舱门</Chinesesimp>

View File

@ -123,7 +123,9 @@ class GVAR(stats) {
stats[] = {"maximumLoad"};
displayName = "$STR_a3_rscdisplayarsenal_stat_load";
showBar = 1;
showText = 1;
barStatement = QUOTE([ARR_3((_this select 0) select 0,_this select 1,[ARR_3([ARR_2(0,500)],[ARR_2(0.01,1)],false)])] call FUNC(statBarStatement_default));
textStatement = QUOTE(call FUNC(statTextStatement_load));
tabs[] = {{3,4,5}, {}};
};
class ACE_smokeChemTTL: statBase {

View File

@ -110,7 +110,7 @@ class Cfg3DEN {
h = QUOTE(65 * ATTRIBUTE_H);
drawSideArrows = 1;
disableOverflow = 1;
columns[] = {0.05, 0.15, 0.85};
columns[] = {0.05, 0.15, 0.83, 0.87};
};
class ArrowLeft: ctrlButton {
idc = IDC_ATTRIBUTE_LIST_LEFT;

View File

@ -16,6 +16,8 @@ PREP(attributeKeyDown);
PREP(attributeLoad);
PREP(attributeMode);
PREP(attributeSelect);
PREP(baseAttachment);
PREP(baseOptic);
PREP(baseWeapon);
PREP(buttonActionsPage);
PREP(buttonCargo);
@ -96,6 +98,7 @@ PREP(statBarStatement_rateOfFIre);
PREP(statTextStatement_accuracy);
PREP(statTextStatement_explosionTime);
PREP(statTextStatement_illuminators);
PREP(statTextStatement_load);
PREP(statTextStatement_magCount);
PREP(statTextStatement_mass);
PREP(statTextStatement_rateOfFire);

View File

@ -22,7 +22,8 @@ GVAR(lastSortDirectionRight) = DESCENDING;
params ["_object"];
// If the arsenal is already open, refresh arsenal display
if (!isNil QGVAR(currentBox) && {GVAR(currentBox) isEqualTo _object}) then {
// Deliberate == check, fail on objNull
if (!isNil QGVAR(currentBox) && {GVAR(currentBox) == _object}) then {
[true, true] call FUNC(refresh);
};
}] call CBA_fnc_addEventHandler;
@ -69,7 +70,7 @@ GVAR(lastSortDirectionRight) = DESCENDING;
if (!isNil QGVAR(currentLoadoutsTab) && {GVAR(currentLoadoutsTab) == IDC_buttonSharedLoadouts}) then {
private _curSelData = _contentPanelCtrl lnbData [lnbCurSelRow _contentPanelCtrl, 1];
([_loadoutData] call FUNC(verifyLoadout)) params ["_extendedLoadout", "_nullItemsAmount", "_unavailableItemsAmount"];
([_loadoutData] call FUNC(verifyLoadout)) params ["_extendedLoadout", "_nullItemsList", "_unavailableItemsList"];
_extendedLoadout params ["_loadout"];
private _newRow = _contentPanelCtrl lnbAddRow [_playerName, _loadoutName];
@ -80,10 +81,10 @@ GVAR(lastSortDirectionRight) = DESCENDING;
_contentPanelCtrl lnbSetData [[_newRow, 1], _playerName + _loadoutName];
// Set color of row, depending if items are unavailable/missing
if (_nullItemsAmount > 0) then {
if (_nullItemsList isNotEqualTo []) then {
_contentPanelCtrl lnbSetColor [[_newRow, 1], [1, 0, 0, 0.8]];
} else {
if (_unavailableItemsAmount > 0) then {
if (_unavailableItemsList isNotEqualTo []) then {
_contentPanelCtrl lnbSetColor [[_newRow, 1], [1, 1, 1, 0.25]];
};
};
@ -107,24 +108,16 @@ GVAR(lastSortDirectionRight) = DESCENDING;
private _face = _extendedInfo getOrDefault [QGVAR(face), ""];
if (_face != "") then {
if (isMultiplayer) then {
private _id = [QGVAR(broadcastFace), [_unit, _face], QGVAR(centerFace_) + netId _unit] call CBA_fnc_globalEventJIP;
[_id, _unit] call CBA_fnc_removeGlobalEventJIP;
} else {
_unit setFace _face;
};
private _id = [QGVAR(broadcastFace), [_unit, _face], QGVAR(centerFace_) + hashValue _unit] call CBA_fnc_globalEventJIP;
[_id, _unit] call CBA_fnc_removeGlobalEventJIP;
};
// Set voice
private _voice = _extendedInfo getOrDefault [QGVAR(voice), ""];
if (_voice != "") then {
if (isMultiplayer) then {
private _id = [QGVAR(broadcastVoice), [_unit, _voice], QGVAR(centerVoice_) + netId _unit] call CBA_fnc_globalEventJIP;
[_id, _unit] call CBA_fnc_removeGlobalEventJIP;
} else {
_unit setSpeaker _voice;
};
private _id = [QGVAR(broadcastVoice), [_unit, _voice], QGVAR(centerVoice_) + hashValue _unit] call CBA_fnc_globalEventJIP;
[_id, _unit] call CBA_fnc_removeGlobalEventJIP;
};
// Set insignia
@ -146,7 +139,7 @@ GVAR(lastSortDirectionRight) = DESCENDING;
// Set voice if enabled
if (GVAR(loadoutsSaveVoice)) then {
_extendedInfo set [QGVAR(voice), speaker _unit];
_extendedInfo set [QGVAR(voice), (speaker _unit) call EFUNC(common,getConfigName)];
};
// Set insignia if enabled

View File

@ -12,57 +12,10 @@ PREP_RECOMPILE_END;
#include "initSettings.inc.sqf"
// Arsenal events
[QGVAR(statsToggle), {
params ["_display", "_showStats"];
private _statsCtrlGroupCtrl = _display displayCtrl IDC_statsBox;
private _statsPreviousPageCtrl = _display displayCtrl IDC_statsPreviousPage;
private _statsNextPageCtrl = _display displayCtrl IDC_statsNextPage;
private _statsCurrentPageCtrl = _display displayCtrl IDC_statsCurrentPage;
{
_x ctrlShow (GVAR(showStats) && {_showStats});
} forEach [
_statsCtrlGroupCtrl,
_statsPreviousPageCtrl,
_statsNextPageCtrl,
_statsCurrentPageCtrl
];
}] call CBA_fnc_addEventHandler;
[QGVAR(statsChangePage), {
_this call FUNC(buttonStatsPage);
}] call CBA_fnc_addEventHandler;
[QGVAR(displayStats), {
_this call FUNC(handleStats);
}] call CBA_fnc_addEventHandler;
[QGVAR(actionsChangePage), {
_this call FUNC(buttonActionsPage);
}] call CBA_fnc_addEventHandler;
[QGVAR(displayActions), {
_this call FUNC(handleActions);
}] call CBA_fnc_addEventHandler;
[QGVAR(actionsToggle), {
params ["_display", "_showActions"];
private _actionsCtrlGroupCtrl = _display displayCtrl IDC_actionsBox;
private _actionsPreviousPageCtrl = _display displayCtrl IDC_actionsPreviousPage;
private _actionsNextPageCtrl = _display displayCtrl IDC_actionsNextPage;
private _actionsCurrentPageCtrl = _display displayCtrl IDC_actionsCurrentPage;
{
_x ctrlShow (GVAR(showActions) && {_showActions});
} forEach [
_actionsCtrlGroupCtrl,
_actionsPreviousPageCtrl,
_actionsNextPageCtrl,
_actionsCurrentPageCtrl
];
}] call CBA_fnc_addEventHandler;
[QGVAR(statsChangePage), LINKFUNC(buttonStatsPage)] call CBA_fnc_addEventHandler;
[QGVAR(displayStats), LINKFUNC(handleStats)] call CBA_fnc_addEventHandler;
[QGVAR(actionsChangePage), LINKFUNC(buttonActionsPage)] call CBA_fnc_addEventHandler;
[QGVAR(displayActions), LINKFUNC(handleActions)] call CBA_fnc_addEventHandler;
call FUNC(compileActions);
call FUNC(compileSorts);
@ -83,8 +36,59 @@ call FUNC(compileStats);
EGVAR(common,blockItemReplacement) = false;
}] call CBA_fnc_addEventHandler;
[QGVAR(cargoChanged), {
params ["_display"];
// Only update actions if necessary, this can get performance-intensive using the arrow keys
if (!GVAR(updateActionsOnCargoChange)) exitWith {};
private _actionInfo = [_display];
_actionInfo append GVAR(actionInfo);
[QGVAR(displayActions), _actionInfo] call CBA_fnc_localEvent;
}] call CBA_fnc_addEventHandler;
// Setup Tools tab
[keys (uiNamespace getVariable [QGVAR(configItemsTools), createHashMap]), LLSTRING(toolsTab), TOOLS_TAB_ICON, -1, true] call FUNC(addRightPanelButton);
// TODO: make IDCs able to match IDX with simple math?
GVAR(idxMap) = createHashMapFromArray [
[IDC_buttonPrimaryWeapon, IDX_VIRT_PRIMARY_WEAPONS],
[IDC_buttonHandgun, IDX_VIRT_HANDGUN_WEAPONS],
[IDC_buttonSecondaryWeapon, IDX_VIRT_SECONDARY_WEAPONS],
[IDC_buttonHeadgear, IDX_VIRT_HEADGEAR],
[IDC_buttonUniform, IDX_VIRT_UNIFORM],
[IDC_buttonVest, IDX_VIRT_VEST],
[IDC_buttonBackpack, IDX_VIRT_BACKPACK],
[IDC_buttonGoggles, IDX_VIRT_GOGGLES],
[IDC_buttonNVG, IDX_VIRT_NVG],
[IDC_buttonBinoculars, IDX_VIRT_BINO],
[IDC_buttonMap, IDX_VIRT_MAP],
[IDC_buttonGPS, IDX_VIRT_COMMS],
[IDC_buttonRadio, IDX_VIRT_RADIO],
[IDC_buttonCompass, IDX_VIRT_COMPASS],
[IDC_buttonWatch, IDX_VIRT_WATCH]
];
// Make new hashmaps for face/voice/insignia so mission makers can disable them
// Copies of hashmaps aren't final
GVAR(faceCache) = +(uiNamespace getVariable QGVAR(faceCache));
GVAR(voiceCache) = +(uiNamespace getVariable QGVAR(voiceCache));
GVAR(insigniaCache) = +(uiNamespace getVariable QGVAR(insigniaCache));
// Get mission/campaign insignias
// BIS_fnc_setUnitInsignia will look in mission config, then campaign, then global config last, so overwrite accordingly
private _insigniaCondition = toString {
if (isNumber (_x >> "scope")) then {
getNumber (_x >> "scope") == 2
} else {
true
};
};
// Ref fnc_addListBoxItem, 0/nil = configFile, 1 = campaignConfigFile, 2 = missionConfigFile
{
GVAR(insigniaCache) set [_x, 1];
} forEach (_insigniaCondition configClasses (campaignConfigFile >> "CfgUnitInsignia"));
{
GVAR(insigniaCache) set [_x, 2];
} forEach (_insigniaCondition configClasses (missionConfigFile >> "CfgUnitInsignia"));
ADDON = true;

View File

@ -155,6 +155,8 @@
#define IDC_statsNextPage 53
#define IDC_statsCurrentPage 54
#define IDC_actionsBox 90
#define IDC_actionsBackground1 90010
#define IDC_actionsBackground2 90011
#define IDC_actionsText1 9001
#define IDC_actionsButton1 9002
#define IDC_actionsText2 9003
@ -268,6 +270,7 @@
#define IDX_VIRT_UNIQUE_UNKNOWN_ITEMS 25
// Indexes of current items array
// Should match IDX_VIRT_X macros for any left panel tabs
#define IDX_CURR_PRIMARY_WEAPON 0
#define IDX_CURR_SECONDARY_WEAPON 1
#define IDX_CURR_HANDGUN_WEAPON 2
@ -487,3 +490,6 @@ if (!isNil QGVAR(customRightPanelButtons)) then {\
_contentPanelCtrl lnbSetPicture [[_newRow, 7], getText (configFile >> "CfgVehicles" >> (_loadout select IDX_LOADOUT_BACKPACK) select 0 >> "picture")];\
_contentPanelCtrl lnbSetPicture [[_newRow, 8], getText (_cfgWeapons >> _loadout select IDX_LOADOUT_HEADGEAR >> "picture")];\
_contentPanelCtrl lnbSetPicture [[_newRow, 9], getText (configFile >> "CfgGlasses" >> _loadout select IDX_LOADOUT_GOGGLES >> "picture")];
#define ACTION_TYPE_TEXT 0
#define ACTION_TYPE_BUTTON 1

View File

@ -1,4 +1,5 @@
#include "..\script_component.hpp"
#include "..\defines.hpp"
/*
* Author: johnb43
* Adds custom action buttons.
@ -10,6 +11,7 @@
* 3: Actions <ARRAY of ARRAYS>
* 4: Condition <CODE> (default: {true})
* 5: Scope editor <NUMBER> (default: 2)
* 6: Update when cargo content changes <BOOL> (default: false)
*
* Return Value:
* 0: Array of IDs <ARRAY of STRINGS>
@ -30,7 +32,8 @@ params [
["_title", "", [""]],
["_actions", [], [[]]],
["_rootCondition", {true}, [{}]],
["_scopeEditor", 2, [0]]
["_scopeEditor", 2, [0]],
["_updateOnCargoChange", false, [false]]
];
// Compile actions from config (in case this is called before preInit)
@ -38,13 +41,13 @@ call FUNC(compileActions);
// Skip if not allowed in editor and in editor
if (is3DEN && {_scopeEditor != 2}) exitWith {
TRACE_1("Skipping action because in editor", _rootClass);
TRACE_1("Skipping action because in editor",_rootClass);
[]
};
// Class can't contain ~, because it's used for formatting result
if ("~" in _rootClass) exitWith {
TRACE_1("Classname can't contain '~'", _rootClass);
TRACE_1("Classname can't contain '~'",_rootClass);
[]
};
@ -65,7 +68,7 @@ private _fnc_addToGroup = {
// Don't allow two of the same class
if (_group findIf {(_x select 0) == _class} != -1) then {
TRACE_1("An action with this ID already exists", _class);
TRACE_1("An action with this ID already exists",_class);
continue;
};
@ -119,4 +122,8 @@ private _group = [];
};
} forEach _tabs;
if (_updateOnCargoChange) then {
GVAR(updateActionsOnCargoChange) = true;
};
_return

View File

@ -6,9 +6,10 @@
*
* Arguments:
* 0: Config category, must be "CfgWeapons", "CfgVehicles", "CfgMagazines", "CfgVoice" or "CfgUnitInsignia" <STRING>
* 1: Classname <STRING>
* 1: Classname (must be in config case) <STRING>
* 2: Panel control <CONTROL>
* 3: Name of the picture entry in that Cfg class <STRING> (default: "picture")
* 4: Config root <NUMBER> (default: 0 -> configFile)
*
* Return Value:
* None
@ -19,9 +20,9 @@
* Public: Yes
*/
params ["_configCategory", "_className", "_ctrlPanel", ["_pictureEntryName", "picture", [""]]];
params ["_configCategory", "_className", "_ctrlPanel", ["_pictureEntryName", "picture", [""]], ["_configRoot", 0, [0]]];
private _skip = GVAR(favoritesOnly) && {!(_className in GVAR(currentItems))} && {!((toLower _className) in GVAR(favorites))};
private _skip = GVAR(favoritesOnly) && {!(_className in GVAR(currentItems))} && {!((toLowerANSI _className) in GVAR(favorites))};
if (_skip) then {
switch (GVAR(currentLeftPanel)) do {
case IDC_buttonPrimaryWeapon: {
@ -41,10 +42,10 @@ if (_skip) then {
if (_skip) exitWith {};
// Sanitise key, as it's public; If not in cache, find info and cache it for later use
((uiNamespace getVariable QGVAR(addListBoxItemCache)) getOrDefaultCall [_configCategory + _className, {
// If not in cache, find info and cache it for later use
((uiNamespace getVariable QGVAR(addListBoxItemCache)) getOrDefaultCall [_configCategory + _className + str _configRoot, {
// Get classname (config case), display name, picture and DLC
private _configPath = configFile >> _configCategory >> _className;
private _configPath = ([configFile, campaignConfigFile, missionConfigFile] select _configRoot) >> _configCategory >> _className;
private _dlcName = _configPath call EFUNC(common,getAddon);
// If _pictureEntryName is empty, then this item has no picture (e.g. faces)
@ -57,7 +58,7 @@ _ctrlPanel lbSetPicture [_lbAdd, _itemPicture];
_ctrlPanel lbSetPictureRight [_lbAdd, ["", _modPicture] select GVAR(enableModIcons)];
_ctrlPanel lbSetTooltip [_lbAdd, format ["%1\n%2", _displayName, _className]];
if ((toLower _className) in GVAR(favorites)) then {
if ((toLowerANSI _className) in GVAR(favorites)) then {
_ctrlPanel lbSetColor [_lbAdd, FAVORITES_COLOR];
_ctrlPanel lbSetSelectColor [_lbAdd, FAVORITES_COLOR];
};

View File

@ -66,7 +66,8 @@ _items = _items select {
_x isKindOf ["CBA_MiscItem", _cfgWeapons] && {getNumber (_configItemInfo >> "type") in [TYPE_MUZZLE, TYPE_OPTICS, TYPE_FLASHLIGHT, TYPE_BIPOD]} ||
{getNumber (_configItemInfo >> "type") in [TYPE_FIRST_AID_KIT, TYPE_MEDIKIT, TYPE_TOOLKIT]} ||
{getText (_cfgWeapons >> _x >> "simulation") == "ItemMineDetector"} ||
{getNumber (_cfgMagazines >> _x >> "ACE_isUnique") == 1}
{getNumber (_cfgMagazines >> _x >> "ACE_isUnique") == 1} ||
{getNumber (_cfgMagazines >> _x >> "ACE_asItem") == 1}
};
GVAR(customRightPanelButtons) set [_position, [_items apply {_x call EFUNC(common,getConfigName)}, _picture, _tooltip, _moveOnOverwrite]];

View File

@ -72,7 +72,7 @@ private _fnc_addToTabs = {
_currentTab pushBack _sort;
_return pushBack _sortName;
} else {
TRACE_1("A sort with this ID already exists", _sortName);
TRACE_1("A sort with this ID already exists",_sortName);
};
} forEach _tabsToAddTo;
};

View File

@ -77,7 +77,7 @@ private _fnc_addToTabs = {
// Find if there is an entry with same ID
if (_currentTab findIf {_x select 5 == _statName} != -1) then {
TRACE_1("A stat with this ID already exists", _statName);
TRACE_1("A stat with this ID already exists",_statName);
} else {
_stat = +_finalArray;
_stat set [5, _statName];
@ -109,11 +109,10 @@ private _tabToChange = [];
{
_x params ["_tab", "_tabSide"];
_tabToChange = if (_tabSide == "R") then {
_tabToChange = [
GVAR(statsListLeftPanel),
GVAR(statsListRightPanel)
} else {
GVAR(statsListLeftPanel)
};
] select (_tabSide == "R");
_stats = _tabToChange select _tab;

View File

@ -46,6 +46,7 @@ private _cfgWeapons = configFile >> "CfgWeapons";
private _cfgMagazines = configFile >> "CfgMagazines";
private _cfgVehicles = configFile >> "CfgVehicles";
private _cfgGlasses = configFile >> "CfgGlasses";
private _dlcName = "";
// Exit with current items (no specific category)
if (_category == IDX_CAT_ALL) exitWith {
@ -73,6 +74,12 @@ if (_category == IDX_CAT_ALL) exitWith {
_listbox lnbSetData [[_index, 1], _x];
_listbox lnbSetPicture [[_index, 0], getText (_config >> "picture")];
_listbox lnbSetTooltip [[_index, 0], _x];
_dlcName = _config call EFUNC(common,getAddon);
if (_dlcName != "") then {
_listbox lnbSetPicture [[_index, 2], (modParams [_dlcName, ["logo"]]) param [0, ""]];
};
};
} forEach _attributeItems;
@ -130,12 +137,20 @@ private _config = _cfgClass;
_alpha = 0.5;
};
_index = _listbox lnbAddRow ["", _displayName, _symbol];
_index = _listbox lnbAddRow ["", _displayName, "", _symbol];
_listbox lnbSetData [[_index, 1], _x];
_listbox lnbSetPicture [[_index, 0], getText (_config >> _x >> "picture")];
_listbox lnbSetTooltip [[_index, 0], _x];
_listbox lnbSetColor [[_index, 1], [1, 1, 1, _alpha]];
_listbox lnbSetColor [[_index, 2], [1, 1, 1, _alpha]];
_listbox lnbSetColor [[_index, 3], [1, 1, 1, _alpha]];
// Mod icon is in column 2
_dlcName = (_config >> _x) call EFUNC(common,getAddon);
if (_dlcName != "") then {
_listbox lnbSetPicture [[_index, 2], (modParams [_dlcName, ["logo"]]) param [0, ""]];
_listbox lnbSetPictureColor [[_index, 2], [1, 1, 1, _alpha]];
};
};
} forEach (keys _categoryItems);

View File

@ -35,9 +35,10 @@ if (_addItem && {_itemIndex == -1}) exitWith {
_attributeItems pushBack _itemClassname;
// Change symbol and increase alpha
_listbox lnbSetText [[_currentRow, 2], [SYMBOL_ITEM_VIRTUAL, SYMBOL_ITEM_REMOVE] select _attributeMode];
_listbox lnbSetText [[_currentRow, 3], [SYMBOL_ITEM_VIRTUAL, SYMBOL_ITEM_REMOVE] select _attributeMode];
_listbox lnbSetColor [[_currentRow, 1], [1, 1, 1, 1]];
_listbox lnbSetColor [[_currentRow, 2], [1, 1, 1, 1]];
_listbox lnbSetPictureColor [[_currentRow, 2], [1, 1, 1, 1]]; // mod icon is in column 2
_listbox lnbSetColor [[_currentRow, 3], [1, 1, 1, 1]];
};
// Remove item if in list
@ -45,7 +46,8 @@ if (!_addItem && {_itemIndex != -1}) exitWith {
_attributeItems deleteAt _itemIndex;
// Change symbol and reduce alpha
_listbox lnbSetText [[_currentRow, 2], SYMBOL_ITEM_NONE];
_listbox lnbSetText [[_currentRow, 3], SYMBOL_ITEM_NONE];
_listbox lnbSetColor [[_currentRow, 1], [1, 1, 1, 0.5]];
_listbox lnbSetColor [[_currentRow, 2], [1, 1, 1, 0.5]];
_listbox lnbSetPictureColor [[_currentRow, 2], [1, 1, 1, 0.5]]; // mod icon is in column 2
_listbox lnbSetColor [[_currentRow, 3], [1, 1, 1, 0.5]];
};

View File

@ -0,0 +1,51 @@
#include "..\script_component.hpp"
/*
* Author: Jonpas, LinkIsGrim
* Returns base attachment for CBA scripted attachment
* Adapted from CBA_fnc_switchableAttachments
*
* Arguments:
* 0: Attachment <STRING>
*
* Return Value:
* Base attachment <STRING>
*
* Example:
* "ACE_acc_pointer_green_IR" call ace_arsenal_fnc_baseAttachment
*
* Public: Yes
*/
params [["_item", "", [""]]];
TRACE_1("looking up base attachment",_item);
private _switchableClasses = [];
private _cfgWeapons = configfile >> "CfgWeapons";
private _config = _cfgWeapons >> _item;
_item = configName _config;
while {
_config = _cfgWeapons >> getText (_config >> "MRT_SwitchItemNextClass");
isClass _config && {_switchableClasses pushBackUnique configName _config != -1}
} do {};
_config = _cfgWeapons >> _item;
private _backward = [];
while {
_config = _cfgWeapons >> getText (_config >> "MRT_SwitchItemPrevClass");
isClass _config && {_backward pushBackUnique configName _config != -1}
} do {};
_switchableClasses append _backward;
_switchableClasses = _switchableClasses arrayIntersect _switchableClasses;
{
if (getNumber (_cfgWeapons >> _x >> "scope") == 2) exitWith {
TRACE_2("found class",_item,_x);
_item = _x;
};
} forEach _switchableClasses;
_item

View File

@ -0,0 +1,32 @@
#include "..\script_component.hpp"
/*
* Author: Jonpas, LinkIsGrim
* Returns base optic for CBA scripted optics (PIP and 2D)
*
* Arguments:
* 0: Optic <STRING>
*
* Return Value:
* Base optic <STRING>
*
* Example:
* "CUP_optic_Elcan_SpecterDR_black_PIP" call ace_arsenal_fnc_baseOptic
*
* Public: Yes
*/
params [["_optic", "", [""]]];
// PIP
private _baseClasses = configProperties [configFile >> "CBA_PIPItems", "getText _x == _optic"];
// Carry Handle
{
_baseClasses append (configProperties [_x, "getText _x == _optic"]);
} forEach configProperties [configFile >> "CBA_CarryHandleTypes"];
if (_baseClasses isNotEqualTo []) then {
_optic = configName (_baseClasses select 0);
};
_optic

View File

@ -19,7 +19,7 @@
params [["_weapon", "", [""]]];
// Check if item is cached
(uiNamespace getVariable QGVAR(baseWeaponNameCache)) getOrDefaultCall [toLower _weapon, {
(uiNamespace getVariable QGVAR(baseWeaponNameCache)) getOrDefaultCall [toLowerANSI _weapon, {
private _cfgWeapons = configfile >> "CfgWeapons";
private _config = _cfgWeapons >> _weapon;

View File

@ -2,12 +2,12 @@
#include "..\defines.hpp"
/*
* Author: Brett Mayson
* Handles the previous / next page buttons for actions
* Handles the previous / next page buttons for actions.
*
* Arguments:
* 0: Arsenal display <DISPLAY>
* 1: Actions control <CONTROL>
* 2: Previous or next <BOOL> (false = previous, true = next)
* 1: Actions page <CONTROL>
* 2: Previous (false) or next (true) page <BOOL>
*
* Return Value:
* None
@ -17,10 +17,11 @@
params ["_display", "_control", "_nextPage"];
TRACE_1("control enabled", ctrlEnabled _control);
TRACE_1("control enabled",ctrlEnabled _control);
if !(ctrlEnabled _control) exitWith {};
GVAR(currentActionPage) = GVAR(currentActionPage) + ([-1, 1] select _nextPage);
GVAR(actionsInfo) params ["_panelControl", "_curSel", "_itemCfg"];
[QGVAR(displayActions), [_display, _panelControl, _curSel, _itemCfg]] call CBA_fnc_localEvent;

View File

@ -52,10 +52,20 @@ private _ctrl = controlNull;
IDC_buttonCurrentMag2,
IDC_iconBackgroundCurrentMag,
IDC_iconBackgroundCurrentMag2,
IDC_statsBox,
IDC_statsPreviousPage,
IDC_statsNextPage,
IDC_statsCurrentPage
IDC_statsCurrentPage,
IDC_actionsBox,
IDC_actionsPreviousPage,
IDC_actionsNextPage,
IDC_actionsCurrentPage
];
[QGVAR(statsToggle), [_display, _showToggle]] call CBA_fnc_localEvent;
[QGVAR(actionsToggle), [_display, _showToggle]] call CBA_fnc_localEvent;
if (!_showToggle) exitWith {};
// When showing the stats/actions again, update them to fit with currently selected item
GVAR(actionsInfo) params ["_control", "_curSel", "_itemCfg"];
[QGVAR(displayStats), [_display, _control, _curSel, _itemCfg]] call CBA_fnc_localEvent;
[QGVAR(displayActions), [_display, _control, _curSel, _itemCfg]] call CBA_fnc_localEvent;

View File

@ -17,11 +17,11 @@
params ["_display", "_control", "_nextPage"];
TRACE_1("control enabled", ctrlEnabled _control);
TRACE_1("control enabled",ctrlEnabled _control);
if !(ctrlEnabled _control) exitWith {};
GVAR(currentStatPage) = [GVAR(currentStatPage) - 1, GVAR(currentStatPage) + 1] select _nextPage;
GVAR(currentStatPage) = GVAR(currentStatPage) + ([-1, 1] select _nextPage);
GVAR(statsInfo) params ["_isLeftPanel", "_panelControl", "_curSel", "_itemCfg"];
GVAR(statsInfo) params ["", "_panelControl", "_curSel", "_itemCfg"];
[QGVAR(displayStats), [_display, _panelControl, _curSel, _itemCfg]] call CBA_fnc_localEvent;

View File

@ -1,4 +1,5 @@
#include "..\script_component.hpp"
#include "..\defines.hpp"
/*
* Author: Brett Mayson
* Create the internal actions arrays when needed for the first time.
@ -37,6 +38,8 @@ private _actionList = [
private _configGroupEntries = "true" configClasses (configFile >> QGVAR(actions));
GVAR(updateActionsOnCargoChange) = false;
{
private _scopeEditor = getNumber (_x >> "scopeEditor");
@ -48,6 +51,10 @@ private _configGroupEntries = "true" configClasses (configFile >> QGVAR(actions)
private _rootDisplayName = getText (_x >> "displayName");
private _rootCondition = getText (_x >> "condition");
private _rootTabs = getArray (_x >> "tabs");
private _updateOnCargoChanged = getNumber (_x >> "updateOnCargoChanged");
if (_updateOnCargoChanged > 0) then {
GVAR(updateActionsOnCargoChange) = true;
};
if (_rootCondition != "") then {
_rootCondition = compile _rootCondition;

View File

@ -101,7 +101,7 @@ private _priority = 0;
(_finalArray select 4) set [1, compile (getText (_x >> "textStatement"))];
};
TRACE_3("stats array", _finalArray, _leftTabsList, _rightTabsList);
TRACE_3("stats array",_finalArray,_leftTabsList,_rightTabsList);
if (_leftTabsList isNotEqualTo []) then {
[_statsListLeftPanel, _leftTabsList, "L"] call _fnc_addToTabs;

View File

@ -1,7 +1,7 @@
#include "..\script_component.hpp"
#include "..\defines.hpp"
/*
* Author: Alganthe, johnb43
* Author: Alganthe, johnb43, LinkIsGrim
* Fills left panel.
*
* Arguments:
@ -17,21 +17,28 @@
params ["_display", "_control", ["_animate", true]];
private _ctrlIDC = ctrlIDC _control;
private _ctrlPanel = _display displayCtrl IDC_leftTabContent;
private _idxVirt = GVAR(idxMap) getOrDefault [_ctrlIDC, -1, true];
// Fade old control background
if (!isNil QGVAR(currentLeftPanel)) then {
private _previousCtrlBackground = _display displayCtrl (GVAR(currentLeftPanel) - 1);
_previousCtrlBackground ctrlSetFade 1;
_previousCtrlBackground ctrlCommit ([0, FADE_DELAY] select _animate);
// When switching tabs, clear searchbox
if (GVAR(currentLeftPanel) != _ctrlIDC) then {
(_display displayCtrl IDC_leftSearchbar) ctrlSetText "";
(_display displayCtrl IDC_rightSearchbar) ctrlSetText "";
};
};
// Show new control background
private _ctrlIDC = ctrlIDC _control;
private _ctrlBackground = _display displayCtrl (_ctrlIDC - 1);
_ctrlBackground ctrlSetFade 0;
_ctrlBackground ctrlCommit ([0, FADE_DELAY] select _animate);
private _ctrlPanel = _display displayCtrl IDC_leftTabContent;
// Force a "refresh" animation of the panel
if (_animate) then {
_ctrlPanel ctrlSetFade 1;
@ -41,212 +48,82 @@ if (_animate) then {
};
_ctrlPanel lbSetCurSel -1;
// Purge old data
lbClear _ctrlPanel;
// Handle icons and filling
private _selectedItem = switch (true) do {
// Primary weapons, secondary weapons, handgun weapons
case (_ctrlIDC in [IDC_buttonPrimaryWeapon, IDC_buttonHandgun, IDC_buttonSecondaryWeapon]): {
// Purge old data
lbClear _ctrlPanel;
// Add "Empty" entry
private _addEmpty = _ctrlPanel lbAdd format [" <%1>", localize "str_empty"];
_ctrlPanel lbSetValue [_addEmpty, -1];
// Add selected tab's weapons
private _index = [IDC_buttonPrimaryWeapon, IDC_buttonSecondaryWeapon, IDC_buttonHandgun] find _ctrlIDC;
{
["CfgWeapons", _x, _ctrlPanel] call FUNC(addListBoxItem);
} forEach (keys ((GVAR(virtualItems) get IDX_VIRT_WEAPONS) get _index));
GVAR(currentItems) select _index
};
// Uniforms, vests, backpacks
case (_ctrlIDC in [IDC_buttonUniform, IDC_buttonVest, IDC_buttonBackpack]): {
// Purge old data
lbClear _ctrlPanel;
// Add "Empty" entry
private _addEmpty = _ctrlPanel lbAdd format [" <%1>", localize "str_empty"];
_ctrlPanel lbSetValue [_addEmpty, -1];
switch (_ctrlIDC) do {
// Add uniforms
case IDC_buttonUniform: {
{
["CfgWeapons", _x, _ctrlPanel] call FUNC(addListBoxItem);
} forEach (keys (GVAR(virtualItems) get IDX_VIRT_UNIFORM));
GVAR(currentItems) select IDX_CURR_UNIFORM
};
// Add vests
case IDC_buttonVest: {
{
["CfgWeapons", _x, _ctrlPanel] call FUNC(addListBoxItem);
} forEach (keys (GVAR(virtualItems) get IDX_VIRT_VEST));
GVAR(currentItems) select IDX_CURR_VEST
};
// Add backpacks
case IDC_buttonBackpack: {
{
["CfgVehicles", _x, _ctrlPanel] call FUNC(addListBoxItem);
} forEach (keys (GVAR(virtualItems) get IDX_VIRT_BACKPACK));
GVAR(currentItems) select IDX_CURR_BACKPACK
};
};
};
// Other
default {
// Don't reset right panel selection if left tab is binos
if (_ctrlIDC != IDC_buttonBinoculars) then {
GVAR(currentRightPanel) = nil;
};
lbClear _ctrlPanel;
// For every left tab except faces and voices, add "Empty" entry
if !(_ctrlIDC in [IDC_buttonFace, IDC_buttonVoice]) then {
private _addEmpty = _ctrlPanel lbAdd format [" <%1>", localize "str_empty"];
_ctrlPanel lbSetValue [_addEmpty, -1];
};
switch (_ctrlIDC) do {
// Headgear
case IDC_buttonHeadgear: {
{
["CfgWeapons", _x, _ctrlPanel] call FUNC(addListBoxItem);
} forEach (keys (GVAR(virtualItems) get IDX_VIRT_HEADGEAR));
GVAR(currentItems) select IDX_CURR_HEADGEAR
};
// Facewear
case IDC_buttonGoggles: {
{
["CfgGlasses", _x, _ctrlPanel] call FUNC(addListBoxItem);
} forEach (keys (GVAR(virtualItems) get IDX_VIRT_GOGGLES));
GVAR(currentItems) select IDX_CURR_GOGGLES
};
// NVGs
case IDC_buttonNVG: {
{
["CfgWeapons", _x, _ctrlPanel] call FUNC(addListBoxItem);
} forEach (keys (GVAR(virtualItems) get IDX_VIRT_NVG));
GVAR(currentItems) select IDX_CURR_NVG
};
// Binoculars
case IDC_buttonBinoculars: {
{
["CfgWeapons", _x, _ctrlPanel] call FUNC(addListBoxItem);
} forEach (keys (GVAR(virtualItems) get IDX_VIRT_BINO));
GVAR(currentItems) select IDX_CURR_BINO
};
// Maps
case IDC_buttonMap: {
{
["CfgWeapons", _x, _ctrlPanel] call FUNC(addListBoxItem);
} forEach (keys (GVAR(virtualItems) get IDX_VIRT_MAP));
GVAR(currentItems) select IDX_CURR_MAP
};
// Compasses
case IDC_buttonCompass: {
{
["CfgWeapons", _x, _ctrlPanel] call FUNC(addListBoxItem);
} forEach (keys (GVAR(virtualItems) get IDX_VIRT_COMPASS));
GVAR(currentItems) select IDX_CURR_COMPASS
};
// Radios
case IDC_buttonRadio: {
{
["CfgWeapons", _x, _ctrlPanel] call FUNC(addListBoxItem);
} forEach (keys (GVAR(virtualItems) get IDX_VIRT_RADIO));
GVAR(currentItems) select IDX_CURR_RADIO
};
// Watches
case IDC_buttonWatch: {
{
["CfgWeapons", _x, _ctrlPanel] call FUNC(addListBoxItem);
} forEach (keys (GVAR(virtualItems) get IDX_VIRT_WATCH));
GVAR(currentItems) select IDX_CURR_WATCH
};
// GPS and UAV Terminals
case IDC_buttonGPS: {
{
["CfgWeapons", _x, _ctrlPanel] call FUNC(addListBoxItem);
} forEach (keys (GVAR(virtualItems) get IDX_VIRT_COMMS));
GVAR(currentItems) select IDX_CURR_COMMS
};
// Faces
case IDC_buttonFace: {
private _lbAdd = -1;
{
_y params ["_displayName", "_modPicture"];
_lbAdd = _ctrlPanel lbAdd _displayName;
_ctrlPanel lbSetData [_lbAdd, _x];
_ctrlPanel lbSetTooltip [_lbAdd, format ["%1\n%2", _displayName, _x]];
_ctrlPanel lbSetPictureRight [_lbAdd, _modPicture];
} forEach (uiNamespace getVariable QGVAR(faceCache));
GVAR(currentFace)
};
// Voices
case IDC_buttonVoice: {
{
["CfgVoice", _x, _ctrlPanel, "icon"] call FUNC(addListBoxItem);
} forEach (uiNamespace getVariable QGVAR(voiceCache));
GVAR(currentVoice)
};
// Insignia
case IDC_buttonInsignia: {
// Insignia from config
{
["CfgUnitInsignia", _x, _ctrlPanel, "texture"] call FUNC(addListBoxItem);
} forEach (uiNamespace getVariable QGVAR(insigniaCache));
private _displayName = "";
private _className = "";
private _lbAdd = -1;
// Insignia from mission file
{
_className = configName _x;
_displayName = getText (_x >> "displayName");
_lbAdd = _ctrlPanel lbAdd _displayName;
_ctrlPanel lbSetData [_lbAdd, _className];
_ctrlPanel lbSetPicture [_lbAdd, getText (_x >> "texture")];
_ctrlPanel lbSetTooltip [_lbAdd, format ["%1\n%2", _displayName, _className]];
} forEach ("(if (isNumber (_x >> 'scope')) then {getNumber (_x >> 'scope')} else {2}) == 2" configClasses (missionConfigFile >> "CfgUnitInsignia"));
GVAR(currentInsignia)
};
// Unknown
default {""};
};
};
// For every left tab except faces and voices, add "Empty" entry
if !(_ctrlIDC in [IDC_buttonFace, IDC_buttonVoice]) then {
private _addEmpty = _ctrlPanel lbAdd format [" <%1>", localize "str_empty"];
_ctrlPanel lbSetValue [_addEmpty, -1];
};
// When switching tabs, clear searchbox
if (GVAR(currentLeftPanel) != _ctrlIDC) then {
(_display displayCtrl IDC_leftSearchbar) ctrlSetText "";
(_display displayCtrl IDC_rightSearchbar) ctrlSetText "";
// Don't reset the current right panel for weapons, binos and containers
if !(_idxVirt in [IDX_VIRT_PRIMARY_WEAPONS, IDX_VIRT_SECONDARY_WEAPONS, IDX_VIRT_HANDGUN_WEAPONS, IDX_VIRT_BINO, IDX_VIRT_UNIFORM, IDX_VIRT_VEST, IDX_VIRT_BACKPACK]) then {
GVAR(currentRightPanel) = nil;
};
GVAR(currentLeftPanel) = _ctrlIDC;
// Add items to the listbox
private _selectedItem = if (_idxVirt != -1) then { // Items
private _configParent = switch (_idxVirt) do {
case IDX_VIRT_GOGGLES: {"CfgGlasses"};
case IDX_VIRT_BACKPACK: {"CfgVehicles"};
default {"CfgWeapons"};
};
private _items = if (_idxVirt < IDX_VIRT_HEADGEAR) then {
keys ((GVAR(virtualItems) get IDX_VIRT_WEAPONS) get _idxVirt)
} else {
keys (GVAR(virtualItems) get _idxVirt)
};
{
[_configParent, _x, _ctrlPanel] call FUNC(addListBoxItem);
} forEach _items;
GVAR(currentItems) select _idxVirt
} else { // Special cases
switch (_ctrlIDC) do {
// Faces
case IDC_buttonFace: {
private _lbAdd = -1; // micro-optimization
// Faces need to be added like this because their config path is
// configFile >> "CfgFaces" >> face category >> className
{
_y params ["_displayName", "_modPicture"];
_lbAdd = _ctrlPanel lbAdd _displayName;
_ctrlPanel lbSetData [_lbAdd, _x];
_ctrlPanel lbSetTooltip [_lbAdd, format ["%1\n%2", _displayName, _x]];
_ctrlPanel lbSetPictureRight [_lbAdd, ["", _modPicture] select GVAR(enableModIcons)];
} forEach GVAR(faceCache); // HashMap, not array
GVAR(currentFace)
};
// Voices
case IDC_buttonVoice: {
{
["CfgVoice", _x, _ctrlPanel, "icon"] call FUNC(addListBoxItem);
} forEach (keys GVAR(voiceCache));
GVAR(currentVoice)
};
// Insignia
case IDC_buttonInsignia: {
{
["CfgUnitInsignia", _x, _ctrlPanel, "texture", _y] call FUNC(addListBoxItem);
} forEach GVAR(insigniaCache);
GVAR(currentInsignia)
};
// Unknown
default {
WARNING_1("Unknown arsenal left panel with IDC %1, update ace_arsenal_idxMap and relevant macros if adding a new tab",_ctrlIDC);
""
};
};
};
// Trigger event
GVAR(currentLeftPanel) = _ctrlIDC;
[QGVAR(leftPanelFilled), [_display, _ctrlIDC, GVAR(currentRightPanel)]] call CBA_fnc_localEvent;
// Sort

View File

@ -1,12 +1,16 @@
#include "..\script_component.hpp"
#include "..\defines.hpp"
/*
* Author: Alganthe, johnb43
* Fill loadouts list.
* Author: Alganthe, johnb43, LinkIsGrim
* Fill loadouts list over multiple frames. LOADOUTS_PER_FRAME macro does what it says on the tin.
* Should only ever be called by display load (with optional params as default) and by itself.
* Listen to ace_arsenal_loadoutsListFilled event if you need to iterate over the loadouts list.
*
* Arguments:
* 0: Loadouts display <DISPLAY>
* 1: Tab control <CONTROL>
* 2: Current frame filling loadouts list <NUMBER> (default: 0)
* 3: Frames necessary to fill loadouts list <NUMBER> (default: -1)
*
* Return Value:
* None
@ -14,29 +18,46 @@
* Public: No
*/
params ["_display", "_control"];
// Can just be modified directly, no further setup needed
#define LOADOUTS_PER_FRAME 10
(_display displayCtrl IDC_textEditBox) ctrlSetText "";
params ["_display", "_control", ["_currentFrame", 0], ["_framesToFill", -1]];
if (isNull _display) exitWith {
TRACE_2("display closed, aborting",_currentFrame,_framesToFill);
};
private _contentPanelCtrl = _display displayCtrl IDC_contentPanel;
if (_currentFrame == 0) then {
(_display displayCtrl IDC_textEditBox) ctrlSetText "";
// Force a "refresh" animation of the panel
_contentPanelCtrl ctrlSetFade 1;
_contentPanelCtrl ctrlCommit 0;
_contentPanelCtrl ctrlSetFade 0;
_contentPanelCtrl ctrlCommit FADE_DELAY;
// Force a "refresh" animation of the panel
_contentPanelCtrl ctrlSetFade 1;
_contentPanelCtrl ctrlCommit 0;
_contentPanelCtrl ctrlSetFade 0;
_contentPanelCtrl ctrlCommit FADE_DELAY;
_contentPanelCtrl lnbSetCurSelRow -1;
lnbClear _contentPanelCtrl;
_contentPanelCtrl lnbSetCurSelRow -1;
lnbClear _contentPanelCtrl;
};
private _sharedLoadoutsVars = GVAR(sharedLoadoutsNamespace) getVariable QGVAR(sharedLoadoutsVars);
private _cfgWeapons = configFile >> "CfgWeapons";
private _cfgWeapons = configFile >> "CfgWeapons"; // Used by ADD_LOADOUTS_LIST_PICTURES macro, do not remove
private _newRow = -1;
if (GVAR(currentLoadoutsTab) != IDC_buttonSharedLoadouts) then {
private _loadoutNameAndTab = "";
private _loadoutCachedInfo = "";
private _sharingEnabled = GVAR(allowSharedLoadouts) && {isMultiplayer};
private _loadouts = [
profileNamespace getVariable [QGVAR(saved_loadouts), []],
GVAR(defaultLoadoutsList)
] select (ctrlIDC _control == IDC_buttonDefaultLoadouts);
if (_currentFrame == 0) then {
_framesToFill = floor ((count _loadouts) / LOADOUTS_PER_FRAME);
TRACE_2("filling loadouts list",_currentFrame,_framesToFill);
_this set [3, _framesToFill];
};
// Add all loadouts to loadout list
{
@ -50,15 +71,16 @@ if (GVAR(currentLoadoutsTab) != IDC_buttonSharedLoadouts) then {
_loadoutCachedInfo = [_loadoutData] call FUNC(verifyLoadout);
_contentPanelCtrl setVariable [_loadoutNameAndTab, _loadoutCachedInfo];
_loadoutCachedInfo params ["", "_nullItemsAmount", "_unavailableItemsAmount", "_nullItemsList", "_unavailableItemsList"];
_loadoutCachedInfo params ["", "_nullItemsList", "_unavailableItemsList", "_missingExtendedInfo"];
// Log missing / nil items to RPT (only once per arsenal session)
if (GVAR(EnableRPTLog) && {(_nullItemsAmount > 0) || {_unavailableItemsAmount > 0}}) then {
if (GVAR(EnableRPTLog) && {(_nullItemsList isNotEqualTo []) || {_unavailableItemsList isNotEqualTo [] || {_missingExtendedInfo isNotEqualTo []}}}) then {
private _printComponent = "ACE_Arsenal - Loadout:";
private _printNullItemsList = ["Missing items:", str _nullItemsList] joinString " ";
private _printUnavailableItemsList = ["Unavailable items:", str _unavailableItemsList] joinString " ";
private _printMissingExtendedInfo = ["Missing extended loadout:", str _missingExtendedInfo] joinString " ";
diag_log text (format ["%1%5 %2%5 %3%5 %4", _printComponent, "Name: " + _loadoutName, _printNullItemsList, _printUnavailableItemsList, endl]);
diag_log text (format ["%1%6 %2%6 %3%6 %4%6 %5", _printComponent, "Name: " + _loadoutName, _printNullItemsList, _printUnavailableItemsList, _printMissingExtendedInfo, endl]);
};
};
@ -69,18 +91,18 @@ if (GVAR(currentLoadoutsTab) != IDC_buttonSharedLoadouts) then {
_contentPanelCtrl lnbSetColumnsPos [0, 0.05, 0.40, 0.50, 0.60, 0.70, 0.75, 0.80, 0.85, 0.90];
};
_loadoutCachedInfo params ["_extendedLoadout", "_nullItemsAmount", "_unavailableItemsAmount"];
_extendedLoadout params ["_loadout"];
_loadoutCachedInfo params ["_extendedLoadout", "_nullItemsList", "_unavailableItemsList"];
_extendedLoadout params ["_loadout"]; // Used by ADD_LOADOUTS_LIST_PICTURES macro, do not remove
_newRow = _contentPanelCtrl lnbAddRow ["", _loadoutName];
ADD_LOADOUTS_LIST_PICTURES
// Change color on loadout lines that have items that aren't available or don't exist
if (_nullItemsAmount > 0) then {
if (_nullItemsList isNotEqualTo []) then {
_contentPanelCtrl lnbSetColor [[_newRow, 1], [1, 0, 0, 0.8]]; // Red
} else {
if (_unavailableItemsAmount > 0) then {
if (_unavailableItemsList isNotEqualTo []) then {
_contentPanelCtrl lnbSetColor [[_newRow, 1], [1, 1, 1, 0.25]]; // Gray
};
};
@ -90,10 +112,16 @@ if (GVAR(currentLoadoutsTab) != IDC_buttonSharedLoadouts) then {
_contentPanelCtrl lnbSetPicture [[_newRow, 0], QPATHTOF(data\iconPublic.paa)];
_contentPanelCtrl lnbSetValue [[_newRow, 0], 1];
};
} forEach ([profileNamespace getVariable [QGVAR(saved_loadouts), []], GVAR(defaultLoadoutsList)] select (ctrlIDC _control == IDC_buttonDefaultLoadouts));
} forEach (_loadouts select [_currentFrame * LOADOUTS_PER_FRAME, [LOADOUTS_PER_FRAME, count _loadouts] select is3DEN]);
} else {
private _allPlayerNames = allPlayers apply {name _x};
private _loadouts = _sharedLoadoutsVars apply {GVAR(sharedLoadoutsNamespace) getVariable _x};
private _loadoutVar = "";
if (_currentFrame == 0) then {
_framesToFill = floor ((count _loadouts) / LOADOUTS_PER_FRAME);
TRACE_2("filling loadouts list",_currentFrame,_framesToFill);
_this set [3, _framesToFill];
};
{
_x params ["_playerName", "_loadoutName", "_loadoutData"];
@ -107,8 +135,8 @@ if (GVAR(currentLoadoutsTab) != IDC_buttonSharedLoadouts) then {
[QGVAR(loadoutUnshared), [_contentPanelCtrl, profileName, _loadoutName]] call CBA_fnc_remoteEvent;
} else {
([_loadoutData] call FUNC(verifyLoadout)) params ["_extendedLoadout", "_nullItemsAmount", "_unavailableItemsAmount"];
_extendedLoadout params ["_loadout"];
([_loadoutData] call FUNC(verifyLoadout)) params ["_extendedLoadout", "_nullItemsList", "_unavailableItemsList"];
_extendedLoadout params ["_loadout"]; // Used by ADD_LOADOUTS_LIST_PICTURES macro, do not remove
_contentPanelCtrl lnbSetColumnsPos [0, 0.15, 0.40, 0.50, 0.60, 0.70, 0.75, 0.80, 0.85, 0.90];
_newRow = _contentPanelCtrl lnbAddRow [_playerName, _loadoutName];
@ -118,17 +146,23 @@ if (GVAR(currentLoadoutsTab) != IDC_buttonSharedLoadouts) then {
_contentPanelCtrl lnbSetData [[_newRow, 1], _loadoutVar];
// Change color on loadout lines that have items that aren't available or don't exist
if (_nullItemsAmount > 0) then {
if (_nullItemsList isNotEqualTo []) then {
_contentPanelCtrl lnbSetColor [[_newRow, 1], [1, 0, 0, 0.8]]; // Red
} else {
if (_unavailableItemsAmount > 0) then {
if (_unavailableItemsList isNotEqualTo []) then {
_contentPanelCtrl lnbSetColor [[_newRow, 1], [1, 1, 1, 0.25]]; // Gray
};
};
};
} forEach (_sharedLoadoutsVars apply {GVAR(sharedLoadoutsNamespace) getVariable _x});
} forEach (_loadouts select [_currentFrame * LOADOUTS_PER_FRAME, [LOADOUTS_PER_FRAME, count _loadouts] select is3DEN]);
};
if (!is3DEN && _currentFrame != _framesToFill) exitWith {
_this set [2, _currentFrame + 1];
[FUNC(fillLoadoutsList), _this] call CBA_fnc_execNextFrame;
};
TRACE_3("finished",_currentFrame,_framesToFill,lnbSize _contentPanelCtrl);
[QGVAR(loadoutsListFilled), [_display, _control]] call CBA_fnc_localEvent;
// Sort loadouts alphabetically

View File

@ -53,7 +53,7 @@ if (GVAR(favoritesOnly)) then {
private _fnc_fillRightContainer = {
params ["_configCategory", "_className", ["_isUnique", false, [false]], ["_unknownOrigin", false, [false]]];
if (GVAR(favoritesOnly) && {!(_className in _currentCargo)} && {!((toLower _className) in GVAR(favorites))}) exitWith {};
if (GVAR(favoritesOnly) && {!(_className in _currentCargo)} && {!((toLowerANSI _className) in GVAR(favorites))}) exitWith {};
// If item is not in the arsenal, it must be unique
if (!_isUnique && {!(_className in GVAR(virtualItemsFlat))}) then {
@ -87,9 +87,9 @@ private _fnc_fillRightContainer = {
_ctrlPanel lnbSetText [[_lbAdd, 1], _displayName];
_ctrlPanel lnbSetData [[_lbAdd, 0], _className];
_ctrlPanel lnbSetPicture [[_lbAdd, 0], _picture];
_ctrlPanel lnbSetValue [[_lbAdd, 2], [0, 1] select _isUnique];
_ctrlPanel lnbSetValue [[_lbAdd, 2], parseNumber _isUnique];
_ctrlPanel lnbSetTooltip [[_lbAdd, 0], format ["%1\n%2", _displayName, _className]];
if ((toLower _className) in GVAR(favorites)) then {
if ((toLowerANSI _className) in GVAR(favorites)) then {
_ctrlPanel lnbSetColor [[_lbAdd, 1], FAVORITES_COLOR];
_ctrlPanel lnbSetColorRight [[_lbAdd, 1], FAVORITES_COLOR];
};

View File

@ -7,7 +7,7 @@
* Arguments:
* 0: Arsenal display <DISPLAY>
* 1: Current panel control <CONTROL>
* 2: Current panel selection <SCALAR>
* 2: Current panel selection <NUMBER>
* 3: Item config entry <CONFIG>
*
* Return Value:
@ -15,7 +15,6 @@
*
* Public: No
*/
params ["_display", "_control", "_curSel", "_itemCfg"];
GVAR(actionsInfo) = [_control, _curSel, _itemCfg];
@ -46,13 +45,12 @@ private _groups = (GVAR(actionList) select _panel) select {
};
private _show = _groups isNotEqualTo [];
private _ctrl = _display displayCtrl IDC_actionsBox;
_ctrl ctrlShow _show;
_ctrl ctrlCommit 0.15;
private _actionsBoxCtrl = _display displayCtrl IDC_actionsBox;
_actionsBoxCtrl ctrlShow _show;
_actionsBoxCtrl ctrlCommit FADE_DELAY;
if (!_show) exitWith {};
private _actionsBoxCtrl = _display displayCtrl IDC_actionsBox;
private _actionsCurrentPageCtrl = _display displayCtrl IDC_actionsCurrentPage;
private _currentPage = GVAR(currentActionPage);
@ -79,33 +77,29 @@ private _items = _group select 3 select {
};
_actionsCurrentPageCtrl ctrlSetText (_group select 1);
_actionsCurrentPageCtrl ctrlSetFade 0;
_actionsCurrentPageCtrl ctrlShow true;
_actionsCurrentPageCtrl ctrlCommit 0;
private _activeCtrls = [];
{
_x params ["", "_type", "_label", "_statement"];
private _idc = 9001 + _forEachIndex * 2;
private _actionTextCtrl = _display displayCtrl _idc;
private _actionButtonCtrl = _display displayCtrl (_idc + 1);
private _idc = IDC_actionsText1 + _type + _forEachIndex * 2;
private _actionCtrl = _display displayCtrl _idc;
switch (_type) do {
case ACTION_TYPE_BUTTON: {
_actionButtonCtrl ctrlRemoveAllEventHandlers "ButtonClick";
_actionButtonCtrl ctrlAddEventHandler ["ButtonClick", {
_actionCtrl ctrlRemoveAllEventHandlers "ButtonClick";
_actionCtrl ctrlAddEventHandler ["ButtonClick", {
if (is3DEN) exitWith {[true] call FUNC(refresh)};
[{
[true] call FUNC(refresh);
}] call CBA_fnc_execNextFrame;
}];
_actionButtonCtrl ctrlAddEventHandler ["ButtonClick", _statement];
_actionButtonCtrl ctrlSetText _label;
_actionButtonCtrl ctrlSetFade 0;
_actionButtonCtrl ctrlEnable true;
_actionButtonCtrl ctrlCommit 0;
_actionTextCtrl ctrlSetFade 1;
_actionTextCtrl ctrlCommit 0;
_actionCtrl ctrlAddEventHandler ["ButtonClick", _statement];
_actionCtrl ctrlSetText _label;
_actionCtrl ctrlEnable true;
};
case ACTION_TYPE_TEXT: {
private _text = call _statement;
@ -113,38 +107,43 @@ _actionsCurrentPageCtrl ctrlCommit 0;
if (isNil "_text") then {
_text = "";
};
if (_text isEqualType []) then {
_text = _text joinString endl;
};
_actionTextCtrl ctrlSetText _text;
_actionTextCtrl ctrlSetFade 0;
_actionTextCtrl ctrlCommit 0;
_actionButtonCtrl ctrlSetFade 1;
_actionButtonCtrl ctrlEnable false;
_actionButtonCtrl ctrlCommit 0;
};
default {
_actionTextCtrl ctrlSetFade 1;
_actionTextCtrl ctrlCommit 0;
_actionButtonCtrl ctrlSetFade 1;
_actionButtonCtrl ctrlEnable false;
_actionButtonCtrl ctrlCommit 0;
_actionCtrl ctrlSetText _text;
_actionCtrl ctrlSetPositionH (ctrlTextHeight _actionCtrl);
_actionCtrl ctrlEnable false;
};
};
if (_activeCtrls isNotEqualTo []) then {
(ctrlPosition (_activeCtrls select -1)) params ["", "_lastPosY", "", "_lastPosH"];
_actionCtrl ctrlSetPositionY (_lastPosY + _lastPosH + GRID_H);
} else {
_actionCtrl ctrlSetPositionY ((5 + _type) * GRID_H);
};
_actionCtrl ctrlShow true;
_actionCtrl ctrlCommit 0;
_activeCtrls pushBack _actionCtrl;
} forEach _items;
private _actionCount = count _items;
{
private _idc = 9001 + _x * 2;
private _actionTextCtrl = _display displayCtrl _idc;
private _actionButtonCtrl = _display displayCtrl (_idc + 1);
private _idc = ctrlIDC _x;
if (_idc < IDC_actionsText1 || _idc > IDC_actionsButton5) then {continue};
_actionTextCtrl ctrlSetFade 1;
_actionTextCtrl ctrlCommit 0;
_actionButtonCtrl ctrlSetFade 1;
_actionButtonCtrl ctrlCommit 0;
} forEach ([0, 1, 2, 3, 4] select [_actionCount, 5]);
_x ctrlShow false;
_x ctrlEnable false;
_x ctrlSetPositionY 0;
_x ctrlCommit 0;
} forEach ((allControls _actionsBoxCtrl) select {!(_x in _activeCtrls)});
private _pos = ctrlPosition _actionsBoxCtrl;
_pos set [3, ([11, (5 * _actionCount) + 6] select (_actionCount > 0)) * GRID_H];
_actionsBoxCtrl ctrlSetPosition _pos;
(ctrlPosition (_activeCtrls select -1)) params ["", "_lastPosY", "", "_lastPosH"];
private _actionsBoxHeight = _lastPosY + _lastPosH + GRID_H;
_actionsBoxCtrl ctrlSetPositionH _actionsBoxHeight;
_actionsBoxCtrl ctrlCommit 0;
private _background = _display displayCtrl IDC_actionsBackground1;
_background ctrlSetPositionH _actionsBoxHeight;
_background ctrlCommit 0;

View File

@ -78,10 +78,10 @@ if (!isNull curatorCamera) then {
// Make face and voice selection JIP compatible; 3DEN doesn't need this though
if (isMultiplayer && {!is3DEN}) then {
private _id = [QGVAR(broadcastFace), [GVAR(center), GVAR(currentFace)], QGVAR(centerFace_) + netId GVAR(center)] call CBA_fnc_globalEventJIP;
private _id = [QGVAR(broadcastFace), [GVAR(center), GVAR(currentFace)], QGVAR(centerFace_) + hashValue GVAR(center)] call CBA_fnc_globalEventJIP;
[_id, GVAR(center)] call CBA_fnc_removeGlobalEventJIP;
_id = [QGVAR(broadcastVoice), [GVAR(center), GVAR(currentVoice)], QGVAR(centerVoice_) + netId GVAR(center)] call CBA_fnc_globalEventJIP;
_id = [QGVAR(broadcastVoice), [GVAR(center), GVAR(currentVoice)], QGVAR(centerVoice_) + hashValue GVAR(center)] call CBA_fnc_globalEventJIP;
[_id, GVAR(center)] call CBA_fnc_removeGlobalEventJIP;
};
@ -115,12 +115,11 @@ GVAR(currentVoice) = nil;
GVAR(currentInsignia) = nil;
GVAR(currentAction) = nil;
GVAR(showStats) = nil;
GVAR(currentStatPage) = nil;
GVAR(statsInfo) = nil;
GVAR(showActions) = nil;
GVAR(currentActionPage) = nil;
GVAR(actionsInfo) = nil;
profileNamespace setVariable [QGVAR(favorites), GVAR(favorites)];
GVAR(favoritesOnly) = nil;

View File

@ -68,18 +68,17 @@ if (isNil QGVAR(virtualItems)) then {
GVAR(virtualItemsFlatAll) = +GVAR(virtualItemsFlat);
GVAR(currentFace) = face GVAR(center);
GVAR(currentVoice) = speaker GVAR(center);
GVAR(currentVoice) = (speaker GVAR(center)) call EFUNC(common,getConfigName);
GVAR(currentInsignia) = GVAR(center) call BIS_fnc_getUnitInsignia;
GVAR(currentAction) = "Stand";
GVAR(shiftState) = false;
GVAR(showStats) = true;
GVAR(currentStatPage) = 0;
GVAR(statsInfo) = [true, controlNull, nil, nil];
GVAR(showActions) = true;
GVAR(currentActionPage) = 0;
GVAR(actionsInfo) = [controlNull, nil, nil];
// Update current item list
call FUNC(updateCurrentItemsList);

View File

@ -147,7 +147,7 @@ if (!isNull _loadoutsDisplay) then {
// Right panel lnb + and - buttons
case (_keyPressed in [DIK_LEFT, DIK_RIGHT]): {
if (GVAR(rightTabLnBFocus)) then {
[_display, [1, 0] select (_keyPressed == DIK_LEFT)] call FUNC(buttonCargo);
[_display, parseNumber (_keyPressed != DIK_LEFT)] call FUNC(buttonCargo);
};
};
};

View File

@ -27,9 +27,9 @@ private _favorited = false;
// Favorites/blacklist will always be lowercase to handle configCase changes
private _item = "";
if (_isLnB) then {
_item = toLower (_control lnbData [_curSel, 0]);
_item = toLowerANSI (_control lnbData [_curSel, 0]);
} else {
_item = toLower (_control lbData _curSel);
_item = toLowerANSI (_control lbData _curSel);
};
if (_item in GVAR(favorites)) then {

View File

@ -683,14 +683,19 @@ switch (GVAR(currentLeftPanel)) do {
TOGGLE_RIGHT_PANEL_HIDE
private _unitInsigniaConfig = configFile >> "CfgUnitInsignia" >> _item;
// Check for correct config: First mission, then campaign and finally regular config
private _itemCfg = missionConfigFile >> "CfgUnitInsignia" >> _item;
if (isNull _itemCfg) then {
_itemCfg = campaignConfigFile >> "CfgUnitInsignia" >> _item;
};
if (isNull _itemCfg) then {
_itemCfg = configFile >> "CfgUnitInsignia" >> _item;
};
// Display new items's info on the bottom right
if (isNull _unitInsigniaConfig) then {
[_display, _control, _curSel, missionConfigFile >> "CfgUnitInsignia" >> _item] call FUNC(itemInfo);
} else {
[_display, _control, _curSel, _unitInsigniaConfig] call FUNC(itemInfo);
};
[_display, _control, _curSel, _itemCfg] call FUNC(itemInfo);
};
};

View File

@ -25,6 +25,11 @@ if (canSuspend) exitWith {
[{_this call FUNC(refresh)}, _this] call CBA_fnc_directCall;
};
private _display = findDisplay IDD_ace_arsenal;
// Exit quietly if no display found
if (isNull _display) exitWith {};
if (_updateItems) then {
// Update current item list
call FUNC(updateCurrentItemsList);
@ -65,6 +70,4 @@ if (!_animate) then {
[{GVAR(refreshing) = false}, nil, 3] call CBA_fnc_execAfterNFrames;
};
private _display = findDisplay IDD_ace_arsenal;
[_display, _display displayCtrl GVAR(currentLeftPanel), _animate] call FUNC(fillLeftPanel);

View File

@ -42,8 +42,14 @@ if (_global && {isMultiplayer} && {!isNil "_id"}) then {
};
// If the arsenal is already open and not ignoring content (see FUNC(openBox)), close arsenal display
if (!isNil QGVAR(currentBox) && {GVAR(currentBox) isEqualTo _object} && {isNil QGVAR(ignoredVirtualItems)}) then {
[LLSTRING(noVirtualItems), false, 5, 1] call EFUNC(common,displayText);
// Delay a frame in case this is running on display open
[{(findDisplay IDD_ace_arsenal) closeDisplay 0}] call CBA_fnc_execNextFrame;
// Deliberate == check, fail on objNull
if (!isNil QGVAR(currentBox) && {GVAR(currentBox) == _object} && {isNil QGVAR(ignoredVirtualItems)}) then {
// Delay a frame in case this is running on display open/close
[{
private _display = findDisplay IDD_ace_arsenal;
if (isNull _display) exitWith {};
[LLSTRING(noVirtualItems), false, 5, 1] call EFUNC(common,displayText);
_display closeDisplay 0;
}] call CBA_fnc_execNextFrame;
};

View File

@ -31,7 +31,7 @@ private _tabToChange = [];
_stringCount = count _currentID;
// Make sure to keep at least 1 sort per category, so make default sort not deletable
if ("ace_alphabetically" in toLower (_currentID select [0, _stringCount - 3])) then {
if ("ace_alphabetically" in toLowerANSI (_currentID select [0, _stringCount - 3])) then {
continue;
};

View File

@ -25,7 +25,6 @@ if (count _loadout == 2) then {
if (count _loadout != 10) exitWith {[]};
private _weapon = "";
private _weaponsInfo = [];
private _uniqueBaseCfgText = "";
private _cfgWeapons = configFile >> "CfgWeapons";
@ -43,7 +42,7 @@ private _cfgVehicles = configFile >> "CfgVehicles";
// Check weapon & weapon attachments
{
// Magazines
// Magazines in weapons have 2 entries: Name and ammo count
if (_forEachIndex in [4, 5]) then {
_x params [["_magazine", ""], "_count"];
@ -69,23 +68,69 @@ private _cfgVehicles = configFile >> "CfgVehicles";
_x params [["_containerClass", ""], ["_items", []]];
if (_containerClass != "") then {
_uniqueBaseCfgText = (getText ([_cfgWeapons, _cfgVehicles] select (_forEachIndex == IDX_LOADOUT_BACKPACK) >> _containerClass >> QGVAR(uniqueBase))) call EFUNC(common,getConfigName);
if (_forEachIndex == IDX_LOADOUT_BACKPACK) then {
// Check for non-preset first
_uniqueBaseCfgText = [_containerClass, "CfgVehicles"] call CBA_fnc_getNonPresetClass;
if (_uniqueBaseCfgText != "") then {
(_x select 0) set [0, _uniqueBaseCfgText];
if (_uniqueBaseCfgText != "") then {
_containerClass = _uniqueBaseCfgText;
};
// Check if non-preset backpack has a unique base
_uniqueBaseCfgText = (getText (_cfgVehicles >> _containerClass >> QGVAR(uniqueBase))) call EFUNC(common,getConfigName);
if (_uniqueBaseCfgText != "") then {
_containerClass = _uniqueBaseCfgText;
};
_x set [0, _containerClass];
} else {
_uniqueBaseCfgText = (getText (_cfgWeapons >> _containerClass >> QGVAR(uniqueBase))) call EFUNC(common,getConfigName);
if (_uniqueBaseCfgText != "") then {
_x set [0, _uniqueBaseCfgText];
};
};
// Check if container has items that need replacing with a defined base
{
switch (true) do {
// Containers have 2 entries: Name and isBackpack
case (_x isEqualTypeArray ["", false]);
case (_x isEqualTypeArray ["", false]): {
_x params ["_containerClass", "_isBackpack"];
if (_containerClass != "") then {
if (_isBackpack) then {
// Check for non-preset first
_uniqueBaseCfgText = [_containerClass, "CfgVehicles"] call CBA_fnc_getNonPresetClass;
if (_uniqueBaseCfgText != "") then {
_containerClass = _uniqueBaseCfgText;
};
// Check if non-preset backpack has a unique base
_uniqueBaseCfgText = (getText (_cfgVehicles >> _containerClass >> QGVAR(uniqueBase))) call EFUNC(common,getConfigName);
if (_uniqueBaseCfgText != "") then {
_containerClass = _uniqueBaseCfgText;
};
_x set [0, _containerClass];
} else {
_uniqueBaseCfgText = (getText (_cfgWeapons >> _containerClass >> QGVAR(uniqueBase))) call EFUNC(common,getConfigName);
if (_uniqueBaseCfgText != "") then {
_x set [0, _uniqueBaseCfgText];
};
};
};
};
// Misc. items have 2 entries: Name and amount
case (_x isEqualTypeArray ["", 0]): {
_x params ["_item", "_arg"];
_x params ["_item"];
if (_item != "") then {
_uniqueBaseCfgText = (getText ([_cfgWeapons, _cfgVehicles] select ((_arg isEqualType false) && {_arg}) >> _item >> QGVAR(uniqueBase))) call EFUNC(common,getConfigName);
_uniqueBaseCfgText = (getText (_cfgWeapons >> _item >> QGVAR(uniqueBase))) call EFUNC(common,getConfigName);
if (_uniqueBaseCfgText != "") then {
_x set [0, _uniqueBaseCfgText];
@ -94,7 +139,7 @@ private _cfgVehicles = configFile >> "CfgVehicles";
};
// Weapons have 2 entries: Weapon info array and amount
case (_x isEqualTypeArray [[], 0]): {
_weaponsInfo = _x select 0;
_x params ["_weaponsInfo"];
// Check weapon & weapon attachments
{

View File

@ -160,7 +160,7 @@ private _magazineMiscItems = createHashMap;
{
_magazineMiscItems set [configName _x, nil];
} forEach ((toString {getNumber (_x >> "ACE_isUnique") == 1}) configClasses _cfgMagazines);
} forEach ((toString {getNumber (_x >> "ACE_isUnique") == 1 || getNumber (_x >> "ACE_asItem") == 1}) configClasses _cfgMagazines);
// Remove invalid/non-existent entries
_grenadeList deleteAt "";
@ -282,11 +282,42 @@ uiNamespace setVariable [QGVAR(CBAdisposableLaunchers), compileFinal _launchers]
uiNamespace setVariable [QGVAR(configItemsTools), compileFinal _toolList];
// Compatibility: Override baseWeapon for RHS optics
// No good way to do this via script for other attachments, needs manual compat
// No good way to do this via script for other RHS attachments, needs manual compat
private _baseWeaponCache = uiNamespace getVariable QGVAR(baseWeaponNameCache);
{
private _baseAttachment = configName (_cfgWeapons >> getText (_x >> "rhs_optic_base"));
if (_baseAttachment != "") then {
_baseWeaponCache set [toLower configName _x, _baseAttachment];
_baseWeaponCache set [toLowerANSI configName _x, _baseAttachment];
};
} forEach ("getText (_x >> 'rhs_optic_base') != ''" configClasses _cfgWeapons);
// Compatibility: Override baseWeapon for CBA Scripted Optics
// Adapted from https://github.com/Theseus-Aegis/Mods/blob/master/addons/armory/functions/fnc_getBaseVariant.sqf
private _isScriptedOptic = toString {
isClass (_x >> "CBA_ScriptedOptic") ||
{(getText (_x >> "weaponInfoType")) regexMatch "CBA_scriptedOptic.*?"}
};
{
private _xClass = toLowerANSI configName _x;
private _baseOptic = _xClass call FUNC(baseOptic);
if (_baseOptic != "" && {_baseOptic != _xClass}) then {
TRACE_2("updating baseOptic",_xClass,_baseOptic);
_baseWeaponCache set [_xClass, _baseOptic];
};
} forEach (_isScriptedOptic configClasses _cfgWeapons);
// Compatibility: Override baseWeapon for CBA Scripted Attachments
private _isScriptedAttachment = toString {
getText (_x >> "MRT_SwitchItemNextClass") != "" ||
{getText (_x >> "MRT_SwitchItemPrevClass") != ""}
};
{
private _xClass = toLowerANSI configName _x;
private _baseAttachment = _xClass call FUNC(baseAttachment);
if (_baseAttachment != "" && {_baseAttachment != _xClass}) then {
TRACE_2("updating baseAttachment",_xClass,_baseAttachment);
_baseWeaponCache set [_xClass, _baseAttachment];
};
} forEach (_isScriptedAttachment configClasses _cfgWeapons);

View File

@ -15,6 +15,10 @@
params ["_control"];
// https://community.bistudio.com/wiki/toString, see comment
// However, using 55295 did not work as expected, 55291 was found by trial and error
#define HIGHEST_VALUE_CHAR 55291
// When filling the sorting panel, FUNC(sortPanel) is called twice, so ignore first call
if (GVAR(ignoreFirstSortPanelCall)) exitWith {
GVAR(ignoreFirstSortPanelCall) = false;
@ -29,6 +33,7 @@ private _sortDirectionCtrl = _display displayCtrl ([IDC_sortLeftTabDirection, ID
private _cfgMagazines = configFile >> "CfgMagazines";
private _cfgFaces = configFile >> "CfgFaces";
private _cfgUnitInsignia = configFile >> "CfgUnitInsignia";
private _cfgUnitInsigniaCampaign = campaignConfigFile >> "CfgUnitInsignia";
private _cfgUnitInsigniaMission = missionConfigFile >> "CfgUnitInsignia";
if (_rightSort) then {
@ -126,7 +131,6 @@ private _selected = if (_right) then {
_panel lbData _curSel
};
private _originalNames = createHashMap;
private _item = "";
private _quantity = "";
private _itemCfg = configNull;
@ -136,12 +140,8 @@ private _fillerChar = toString [1];
private _magazineMiscItems = uiNamespace getVariable QGVAR(magazineMiscItems);
private _sortCache = uiNamespace getVariable QGVAR(sortCache);
private _faceCache = if (_cfgClass == _cfgFaces) then {
uiNamespace getVariable [QGVAR(faceCache), createHashMap]
} else {
createHashMap
};
private _faceCache = uiNamespace getVariable QGVAR(faceCache);
private _insigniaCache = uiNamespace getVariable QGVAR(insigniaCache);
private _countColumns = if (_right) then {
count lnbGetColumnsPosition _panel
@ -150,9 +150,9 @@ private _countColumns = if (_right) then {
};
private _for = if (_right) then {
for '_i' from 0 to (lnbSize _panel select 0) - 1
for "_i" from 0 to (lnbSize _panel select 0) - 1
} else {
for '_i' from 0 to (lbSize _panel) - 1
for "_i" from 0 to (lbSize _panel) - 1
};
_for do {
@ -163,6 +163,14 @@ _for do {
_panel lbData _i
};
// Check if entry is "Empty"
if (!_right && {(_panel lbValue _i) == -1}) then {
// Set to lowest/highest lexicographical value, so that "Empty" is always at the top
_panel lbSetTextRight [_i, ["", toString [HIGHEST_VALUE_CHAR, HIGHEST_VALUE_CHAR, HIGHEST_VALUE_CHAR, HIGHEST_VALUE_CHAR, HIGHEST_VALUE_CHAR]] select (_sortDirection == ASCENDING)];
continue;
};
// Get item's count
_quantity = if (_right) then {
parseNumber (_panel lnbText [_i, 2])
@ -179,18 +187,22 @@ _for do {
_itemCfg = if !(_cfgClass in [_cfgFaces, _cfgUnitInsignia]) then {
_cfgClass >> _item
} else {
// If insignia, check both config and mission file
// If insignia, check for correct config: First mission, then campaign and finally regular config
if (_cfgClass == _cfgUnitInsignia) then {
_itemCfg = _cfgClass >> _item;
_itemCfg = _cfgUnitInsigniaMission >> _item;
if (isNull _itemCfg) then {
_itemCfg = _cfgUnitInsigniaMission >> _item;
_itemCfg = _cfgUnitInsigniaCampaign >> _item;
};
if (isNull _itemCfg) then {
_itemCfg = _cfgUnitInsignia >> _item;
};
_itemCfg
} else {
// If face, check correct category
_cfgClass >> (_faceCache get _item) param [2, "Man_A3"] >> _item
_cfgClass >> (_faceCache getOrDefault [_item, []]) param [2, "Man_A3"] >> _item
};
};
@ -216,37 +228,29 @@ _for do {
_value
}, true];
// Save the current row's item's name in a cache and set text to it's sorting value
// Set the right text temporarily, so it can be used for sorting
if (_right) then {
_name = _panel lnbText [_i, 1];
_originalNames set [_item, _name];
// Use value, display name and classname to sort, which means a fixed alphabetical order is guaranteed
// Filler char has lowest lexicographical order possible
_panel lnbSetText [[_i, 1], format ["%1%2%4%3", _value, _name, _item, _fillerChar]];
// Filler char has lowest lexicographical value possible
_panel lnbSetTextRight [[_i, 1], format ["%1%2%4%3", _value, _panel lnbText [_i, 1], _item, _fillerChar]];
} else {
if (_item != "") then {
_name = _panel lbText _i;
_originalNames set [_item, _name];
// Use value, display name and classname to sort, which means a fixed alphabetical order is guaranteed
// Filler char has lowest lexicographical order possible
_panel lbSetText [_i, format ["%1%2%4%3", _value, _name, _item, _fillerChar]];
// Filler char has lowest lexicographical value possible
_panel lbSetTextRight [_i, format ["%1%2%4%3", _value, _panel lbText _i, _item, _fillerChar]];
};
};
};
// Sort alphabetically, find the previously selected item, select it again and reset text to original text
// Sort alphabetically, find the previously selected item and select it again
if (_right) then {
_panel lnbSort [1, _sortDirection == ASCENDING];
[_panel, 1] lnbSortBy ["TEXT", _sortDirection == ASCENDING, false, true, true]; // do not support unicode, as it's much more performance intensive (~3x more)
_for do {
_item = _panel lnbData [_i, 0];
// Remove sorting text, as it blocks the item name otherwise
_panel lnbSetTextRight [[_i, 1], ""];
_panel lnbSetText [[_i, 1], _originalNames get _item];
// Set selection after text, otherwise item info box on the right side shows invalid name
if (_curSel != -1 && {_item == _selected}) then {
if (_curSel != -1 && {(_panel lnbData [_i, 0]) == _selected}) then {
_panel lnbSetCurSelRow _i;
// To avoid unnecessary checks after previsouly selected item was found
@ -254,17 +258,17 @@ if (_right) then {
};
};
} else {
lbSort [_panel, ["DESC", "ASC"] select _sortDirection];
_panel lbSortBy ["TEXT", _sortDirection == ASCENDING, false, true, true]; // do not support unicode, as it's much more performance intensive (~3x more)
_for do {
_item = _panel lbData _i;
// Check if valid item (problems can be caused when searching)
if (_item != "") then {
_panel lbSetText [_i, _originalNames get _item];
// Remove sorting text, as it blocks the item name otherwise
_panel lbSetTextRight [_i, ""];
};
// Set selection after text, otherwise item info box on the right side shows invalid name
if (_curSel != -1 && {_item == _selected}) then {
_panel lbSetCurSel _i;

View File

@ -17,7 +17,7 @@ params ["", "_config"];
TRACE_1("statTextStatement_binoVisionMode",_config);
private _text = [];
private _visionModes = getArray (_config >> "visionMode") apply {toLower _x};
private _visionModes = getArray (_config >> "visionMode") apply {toLowerANSI _x};
{
if (_x in _visionModes) then {
_text pushBack (localize ([LSTRING(VisionNormal), LSTRING(VisionNight), LSTRING(VisionThermal)] select _forEachIndex));

View File

@ -31,9 +31,9 @@ if (_allItems isEqualTo []) then { _allItems = [configName _config] };
|| {_illum && {([_xCfg >> "Flashlight" >> "irLight", "NUMBER", 0] call CBA_fnc_getConfigEntry) == 1}};
private _text = switch (true) do { // shorthand roughly based on PEQ-15
case (_laser && _illum): { if (_isIR) then { "IR-DUAL" } else { "VIS-DUAL" } };
case (_laser): { if (_isIR) then { "IR-AIM" } else { "VIS-AIM" } }; // AIM
case (_illum): { if (_isIR) then { "IR-ILM" } else { "VIS-ILM" } }; // ILLUMIATION
case (_laser && _illum): { ["VIS-DUAL", "IR-DUAL"] select _isIR }; // DUAL
case (_laser): { ["VIS-AIM", "IR-AIM"] select _isIR }; // AIM
case (_illum): { ["VIS-ILM", "IR-ILM"] select _isIR }; // ILLUMIATION
default { "_" }; // there are some purely cosmetic attachements
};
_allModes pushBackUnique _text;

View File

@ -0,0 +1,26 @@
#include "..\script_component.hpp"
/*
* Author: PabstMirror
* Text statement for the load stat.
*
* Arguments:
* 0: Stats <ARRAY>
* 1: Item config path <CONFIG>
*
* Return Value:
* Stat Text <STRING>
*
* Public: No
*/
params ["_stats", "_config"];
TRACE_2("statTextStatement_load",_stats,_config);
if (!isNull (_config >> "ItemInfo" >> "containerClass")) then { // Uniform/Vest
_config = configfile >> "CfgVehicles" >> getText (_config >> "ItemInfo" >> "containerClass");
};
private _load = getNumber (_config >> (_stats # 0));
if (_load <= 0) exitWith { LELSTRING(common,none) };
format ["%1kg (%2lb)", (_load * 0.1 * (1 / 2.2046)) toFixed 2, (_load * 0.1) toFixed 2]

View File

@ -17,7 +17,7 @@ params ["", "_config"];
TRACE_1("statTextStatement_scopeVisionMode",_config);
private _opticsModes = ("true" configClasses (_config >> "ItemInfo" >> "OpticsModes")) apply {
private _visionMode = getArray (_x >> "visionMode") apply {toLower _x};
private _visionMode = getArray (_x >> "visionMode") apply {toLowerANSI _x};
[
getNumber (_x >> "useModelOptics") == 1, // Is in optics
_visionMode isEqualTo [], // Optional NVG
@ -67,7 +67,9 @@ if (!_primaryNVGSupported && {(_opticsModes select {_x select 1}) isEqualTo _opt
_primaryNVGSupported = true;
};
if (_primaryNVGIntegrated) exitWith {LLSTRING(statVisionMode_IntPrim)};
if (_primaryTiIntegrated && _primaryNVGIntegrated) exitWith {LLSTRING(statVisionMode_intPrimTi)};
if (_primaryTiIntegrated) exitWith {LLSTRING(statVisionMode_ti)};
if (_primaryNVGIntegrated) exitWith {LLSTRING(statVisionMode_intPrim)};
if (_primaryNVGSupported) exitWith {LLSTRING(statVisionMode_supPrim)};
if (_secondaryNVGSupported) exitWith {LLSTRING(statVisionMode_supSec)};

View File

@ -63,8 +63,12 @@ private _indexCurrentItems = -1;
};
// Backpack
case IDX_LOADOUT_BACKPACK: {
GVAR(currentItems) set [IDX_CURR_BACKPACK, _x param [0, ""]];
GVAR(currentItems) set [IDX_CURR_BACKPACK_ITEMS, _x param [1, []]];
_x params [["_backpack", ""], ["_items", []]];
if (_backpack != "") then {
_backpack = [_backpack, "CfgVehicles"] call CBA_fnc_getNonPresetClass;
};
GVAR(currentItems) set [IDX_CURR_BACKPACK, _backpack];
GVAR(currentItems) set [IDX_CURR_BACKPACK_ITEMS, _items];
};
// Helmet
case IDX_LOADOUT_HEADGEAR: {

View File

@ -101,6 +101,11 @@ private _fnc_uniqueEquipment = {
case IDX_LOADOUT_BACKPACK: {
_x params [["_containerClass", ""]];
// Handle preset (loaded/AI) backpacks
if (_containerClass != "" && _forEachIndex == IDX_LOADOUT_BACKPACK) then {
_containerClass = [_containerClass, "CfgVehicles"] call CBA_fnc_getNonPresetClass;
};
// Remove all unique equipment in tab; Add container as a unique equipment
[GVAR(virtualItems) get (_forEachIndex + 1), _containerClass] call _fnc_uniqueEquipment;
};

View File

@ -13,289 +13,93 @@
* Public: No
*/
#define NOT_IN_ARSENAL !(_name in GVAR(virtualItemsFlat))
params ["_loadout"];
private _extendedInfo = createHashMap;
// Check if the provided loadout is a CBA extended loadout
if (count _loadout == 2) then {
_extendedInfo = _loadout select 1;
_extendedInfo = +(_loadout select 1); // Copy the hashmap to prevent events from modifiyng the profileNamespace extendedInfo
_loadout = _loadout select 0;
};
private _cfgWeapons = configFile >> "CfgWeapons";
private _cfgMagazines = configFile >> "CfgMagazines";
private _cfgVehicles = configFile >> "CfgVehicles";
private _cfgGlasses = configFile >> "CfgGlasses";
private _weapons = GVAR(virtualItems) get IDX_VIRT_WEAPONS;
private _attachments = GVAR(virtualItems) get IDX_VIRT_ATTACHMENTS;
private _name = "";
private _nullItemsAmount = 0;
private _unavailableItemsAmount = 0;
private _itemArray = [];
private _nullItemsList = [];
private _unavailableItemsList = [];
private _missingExtendedInfo = [];
// Search for all items and turn them into config case; Don't touch other value types
private _fnc_toConfigCase = {
// Search for all items and check their availability
private _fnc_filterLoadout = {
_this apply {
if (_x isEqualType "") then {
if (_x != "") then {
_name = _x call EFUNC(common,getConfigName);
if (_x isEqualType "" && {_x != ""}) then {
_name = _x call EFUNC(common,getConfigName);
// If item doesn't exist in config, "" is returned
// Just return unaltered item name in that case, so it can be documented as being unavailable
if (_name != "") then {
_name
} else {
_x
};
// If item doesn't exist in config, "" is returned
if (_name == "") then {
_nullItemsList pushBack _x;
} else {
_x
// Check if item or its base weapon exist in the arsenal
if NOT_IN_ARSENAL then {
_name = _name call FUNC(baseWeapon);
if NOT_IN_ARSENAL then {
// This could be a backpack
private _temp = [_name, "CfgVehicles"] call CBA_fnc_getNonPresetClass;
if (_temp == "") then { // It's not
_unavailableItemsList pushBack _name;
_name = "";
} else { // It is
_name = _temp;
// Check if it's available again
if NOT_IN_ARSENAL then {
_unavailableItemsList pushBack _name;
_name = "";
};
};
};
};
};
_name
} else {
// Handle arrays
if (_x isEqualType []) then {
_x call _fnc_toConfigCase
_itemArray = _x call _fnc_filterLoadout;
// If "" is given as a container, an error is thrown, therefore, filter out all unavailable/null containers
if (count _itemArray == 2 && {(_itemArray select 0) isEqualTo ""} && {(_itemArray select 1) isEqualType []}) then {
_itemArray = [];
};
_itemArray
} else {
// All other types
// All other types and empty strings
_x
};
};
};
};
// Convert loadout to config case
// Convert loadout to config case and replace null/unavailable items
// Loadout might come from a different modpack, which might have different config naming
_loadout = _loadout call _fnc_toConfigCase;
_loadout = _loadout call _fnc_filterLoadout;
// Check a weapon, with its attachments and magazines, if items are available
private _fnc_weaponCheck = {
params ["_weaponArray", ["_index", -1]];
{
private _class = _extendedInfo getOrDefault [_x, ""];
private _cache = missionNamespace getVariable (_x + "Cache");
{
// Weapons and attachments
if (_x isEqualType "") then {
if (_x != "") then {
// Check if item exists
if (isClass (_cfgWeapons >> _x)) then {
// Get base weapon
_x = _x call FUNC(baseWeapon);
// Check if item is available in arsenal
if !(
// Weapon class name is at the very start of the array
if (_forEachIndex == 0) then {
// If the type of weapon is known, only look through that array
if (_index != -1) then {
// If binos, choose differently
if (_index == IDX_LOADOUT_BINO) then {
_x in (GVAR(virtualItems) get IDX_VIRT_BINO)
} else {
_x in (_weapons get _index)
};
} else {
_x in (_weapons get IDX_VIRT_PRIMARY_WEAPONS) ||
{_x in (_weapons get IDX_VIRT_SECONDARY_WEAPONS)} ||
{_x in (_weapons get IDX_VIRT_HANDGUN_WEAPONS)} ||
{_x in (GVAR(virtualItems) get IDX_VIRT_BINO)}
};
} else {
_x in (_attachments get IDX_VIRT_OPTICS_ATTACHMENTS) ||
{_x in (_attachments get IDX_VIRT_FLASHLIGHT_ATTACHMENTS)} ||
{_x in (_attachments get IDX_VIRT_MUZZLE_ATTACHMENTS)} ||
{_x in (_attachments get IDX_VIRT_BIPOD_ATTACHMENTS)}
}
) then {
_unavailableItemsList pushBackUnique _x;
_weaponArray set [_forEachIndex, ""];
INC(_unavailableItemsAmount);
};
} else {
_nullItemsList pushBackUnique _x;
_weaponArray set [_forEachIndex, ""];
INC(_nullItemsAmount);
};
};
} else {
// Magazines
if (_x isNotEqualTo []) then {
_x params ["_magazine"];
// Check if item exists
if (isClass (_cfgMagazines >> _magazine)) then {
// Check if item is available in arsenal
if !(_magazine in (GVAR(virtualItems) get IDX_VIRT_ITEMS_ALL)) then {
_unavailableItemsList pushBackUnique _magazine;
_weaponArray set [_forEachIndex, []];
INC(_unavailableItemsAmount);
};
} else {
_nullItemsList pushBackUnique _magazine;
_weaponArray set [_forEachIndex, []];
INC(_nullItemsAmount);
};
};
};
} forEach _weaponArray;
};
private _item = "";
// Go through entire loadout to check if items are available in current arsenal
for "_dataIndex" from IDX_LOADOUT_PRIMARY_WEAPON to IDX_LOADOUT_ASSIGNEDITEMS do {
switch (_dataIndex) do {
// Primary weapon, Secondary weapon, Handgun weapon, Binoculars
case IDX_LOADOUT_PRIMARY_WEAPON;
case IDX_LOADOUT_SECONDARY_WEAPON;
case IDX_LOADOUT_HANDGUN_WEAPON;
case IDX_LOADOUT_BINO: {
[_loadout select _dataIndex, _dataIndex] call _fnc_weaponCheck;
};
// Uniform, vest, backpack
case IDX_LOADOUT_UNIFORM;
case IDX_LOADOUT_VEST;
case IDX_LOADOUT_BACKPACK: {
(_loadout select _dataIndex) params [["_item", ""], ["_containerItems", []]];
if (_item != "") then {
// Check if item exists
if (isClass (_cfgVehicles >> _item) || {isClass (_cfgWeapons >> _item)}) then {
// Check if item is available in arsenal
if !(_item in (GVAR(virtualItems) get (_dataIndex + 1))) then {
_unavailableItemsList pushBackUnique _item;
_loadout set [_dataIndex, []];
INC(_unavailableItemsAmount);
} else {
{
switch (true) do {
// Magazines have each 3 entries: Name, number of magazines and ammo count
case (_x isEqualTypeArray ["", 0, 0]): {
_x params ["_item"];
// Check if item exists
if (isClass (_cfgMagazines >> _item)) then {
// Check if item is available in arsenal
if !(
_item in (GVAR(virtualItems) get IDX_VIRT_ITEMS_ALL) ||
{_item in (GVAR(virtualItems) get IDX_VIRT_GRENADES)} ||
{_item in (GVAR(virtualItems) get IDX_VIRT_EXPLOSIVES)} ||
{_item in (GVAR(virtualItems) get IDX_VIRT_MISC_ITEMS)}
) then {
_unavailableItemsList pushBackUnique _item;
((_loadout select _dataIndex) select 1) set [_forEachIndex, []];
INC(_unavailableItemsAmount);
};
} else {
_nullItemsList pushBackUnique _item;
((_loadout select _dataIndex) select 1) set [_forEachIndex, []];
INC(_nullItemsAmount);
};
};
// Weapons have 2 entries: Weapon info array and amount
case (_x isEqualTypeArray [[], 0]): {
[_x select 0] call _fnc_weaponCheck;
};
// Misc. items have 2 entries: Name and amount, containers have 2 entries: Name and isBackpack
default {
_x params ["_item"];
// Check if item exists
if (
isClass (_cfgWeapons >> _item) ||
{isClass (_cfgMagazines >> _item)} ||
{isClass (_cfgGlasses >> _item)} ||
{isClass (_cfgVehicles >> _item)}
) then {
// Check if item is available in arsenal
if !(_item in GVAR(virtualItemsFlat)) then {
_unavailableItemsList pushBackUnique _item;
((_loadout select _dataIndex) select 1) set [_forEachIndex, []];
INC(_unavailableItemsAmount);
};
} else {
_nullItemsList pushBackUnique _item;
((_loadout select _dataIndex) select 1) set [_forEachIndex, []];
INC(_nullItemsAmount);
};
};
};
} forEach _containerItems;
};
} else {
_nullItemsList pushBackUnique _item;
_loadout set [_dataIndex, []];
INC(_nullItemsAmount);
};
};
};
// Headgear
case IDX_LOADOUT_HEADGEAR: {
_item = _loadout select _dataIndex;
if (_item != "") then {
// Check if item exists
if (isClass (_cfgWeapons >> _item)) then {
// Check if item is available in arsenal
if !(_item in (GVAR(virtualItems) get IDX_VIRT_HEADGEAR)) then {
_unavailableItemsList pushBackUnique _item;
_loadout set [_dataIndex, ""];
INC(_unavailableItemsAmount);
};
} else {
_nullItemsList pushBackUnique _item;
_loadout set [_dataIndex, ""];
INC(_nullItemsAmount);
};
};
};
// Facewear
case IDX_LOADOUT_GOGGLES: {
_item = _loadout select _dataIndex;
if (_item != "") then {
// Check if item exists
if (isClass (_cfgGlasses >> _item)) then {
// Check if item is available in arsenal
if !(_item in (GVAR(virtualItems) get IDX_VIRT_GOGGLES)) then {
_unavailableItemsList pushBackUnique _item;
_loadout set [_dataIndex, ""];
INC(_unavailableItemsAmount);
};
} else {
_nullItemsList pushBackUnique _item;
_loadout set [_dataIndex, ""];
INC(_nullItemsAmount);
};
};
};
// Assigned items: Map, Compass, Watch, GPS / UAV Terminal, Radio, NVGs
case IDX_LOADOUT_ASSIGNEDITEMS: {
private _assignedItems = _loadout select _dataIndex;
for "_subIndex" from 0 to 5 do {
_item = _assignedItems select _subIndex;
if (_item != "") then {
// Check if item exists
if (isClass (_cfgWeapons >> _item)) then {
// Check if item is available in arsenal
if !(_item in (GVAR(virtualItems) get (IDX_VIRT_NVG + ([2, 6, 4, 3, 5, 0] select _subIndex)))) then {
_unavailableItemsList pushBackUnique _item;
_assignedItems set [_subIndex, ""];
INC(_unavailableItemsAmount);
};
} else {
_nullItemsList pushBackUnique _item;
_assignedItems set [_subIndex, ""];
INC(_nullItemsAmount);
};
};
};
};
// Previously voices were stored in lower case (speaker command returns lower case), so this is to make old loadouts compatible
if (_class != "" && {_x == QGVAR(voice)}) then {
_class = _class call EFUNC(common,getConfigName);
};
};
if (_class != "" && {!(_class in _cache)}) then {
_missingExtendedInfo pushBack [_x, _class];
_extendedInfo deleteAt _x;
};
} forEach [QGVAR(insignia), QGVAR(face), QGVAR(voice)];
[[_loadout, _extendedInfo], _nullItemsAmount, _unavailableItemsAmount, _nullItemsList, _unavailableItemsList]
// Raise event for 3rd party: mostly for handling extended info
// Pass all items, including duplicates
[QGVAR(loadoutVerified), [_loadout, _extendedInfo, _nullItemsList, _unavailableItemsList, _missingExtendedInfo]] call CBA_fnc_localEvent;
[[_loadout, _extendedInfo], _nullItemsList arrayIntersect _nullItemsList, _unavailableItemsList arrayIntersect _unavailableItemsList, _missingExtendedInfo]

View File

@ -15,6 +15,3 @@
#endif
#include "\z\ace\addons\main\script_macros.hpp"
#define ACTION_TYPE_BUTTON 0
#define ACTION_TYPE_TEXT 1

View File

@ -613,7 +613,7 @@
<French>Le set d'équipement suivant a été supprimé :</French>
<German>Folgende Ausrüstung wurde entfernt:</German>
<Polish>Następujący zestaw został skasowany:</Polish>
<Japanese>次の装備は削除されました:</Japanese>
<Japanese>装備を削除しました:</Japanese>
<Italian>Il seguente equipaggiamento è stato eliminato:</Italian>
<Korean>다음 로드아웃이 삭제됨 :</Korean>
<Chinese>以下的裝備已被刪除:</Chinese>
@ -629,7 +629,7 @@
<French>Le set d'équipement suivant n'est plus public :</French>
<German>Folgende Ausrüstung ist nicht mehr öffentlich:</German>
<Polish>Następujący zestaw nie jest już publiczny:</Polish>
<Japanese>次の装備は非公開になりました:</Japanese>
<Japanese>装備を非公開にしました:</Japanese>
<Italian>Il seguente equipaggiamento non è più pubblico:</Italian>
<Korean>다음 로드아웃이 더이상 공용이 아님:</Korean>
<Chinese>以下的裝備已不再被分享:</Chinese>
@ -645,7 +645,7 @@
<French>Le champ "nom" est vide !</French>
<German>Das Feld "Name" ist leer!</German>
<Polish>Pole nazwy jest puste!</Polish>
<Japanese>名前が空です!</Japanese>
<Japanese>名前が空です!</Japanese>
<Italian>Il campo del nome è vuoto!</Italian>
<Korean>이름칸이 비었습니다!</Korean>
<Chinese>名稱欄位為空!</Chinese>
@ -677,7 +677,7 @@
<French>Un de vos sets d'équipement ayant le même nom est public.</French>
<German>Eine deiner Ausrüstungen mit dem gleichen Namen ist öffentlich</German>
<Polish>Jeden z Twoich zestawów nazwany tak samo jest już publiczny</Polish>
<Japanese>あなたの装備は既に公開されているものと同名で</Japanese>
<Japanese>あなたのものと同じ名前の装備が既に公開されていま</Japanese>
<Italian>Un tuo equipaggiamento con lo stesso nome è pubblico</Italian>
<Korean>같은 이름의 로드아웃이 공용에 있습니다.</Korean>
<Chinese>已有相同名稱的裝備在公用分享區</Chinese>
@ -693,7 +693,7 @@
<French>Le set d'équipement suivant a été enregistré :</French>
<German>Folgende Ausrüstung wurde gespeichert:</German>
<Polish>Następujący zestaw został zapisany:</Polish>
<Japanese>次の装備は保存されました:</Japanese>
<Japanese>装備を保存しました:</Japanese>
<Italian>Il seguente equipaggiamento è stato salvato:</Italian>
<Korean>다음 로드아웃이 저장됨:</Korean>
<Chinese>以下的裝備已被保存:</Chinese>
@ -709,7 +709,7 @@
<French>Le set d'équipement suivant a été chargé :</French>
<German>Folgene Ausrüstung wurde geladen:</German>
<Polish>Następujący zestaw został wczytany:</Polish>
<Japanese>次の装備が読み込みされました:</Japanese>
<Japanese>装備を読み込みました:</Japanese>
<Italian>Il seguente equipaggiamento è stato caricato:</Italian>
<Korean>다음 로드아웃을 불러옴:</Korean>
<Chinese>以下的裝備已被載入:</Chinese>
@ -725,7 +725,7 @@
<French>Un set d'équipement ayant le même nom existe déjà !</French>
<German>Eine Ausrüstung mit dem gleichen Namen existiert bereits!</German>
<Polish>Zestaw z tą nazwą już istnieje!</Polish>
<Japanese>既にその名前は装備に使われています!</Japanese>
<Japanese>既に同じ名前の装備が存在しています!</Japanese>
<Italian>Un equipaggiamento con lo stesso nome è gia esistente!</Italian>
<Korean>같은 이름의 로드아웃이 이미 존재합니다!</Korean>
<Chinese>已有相同名稱的裝備!</Chinese>
@ -741,7 +741,7 @@
<French>a été renommé en</French>
<German>wurde umbenannt in</German>
<Polish>zmienił nazwę na</Polish>
<Japanese>次の名前に変更されました</Japanese>
<Japanese>を次の名前に変更しました:</Japanese>
<Italian>È stato rinominato in</Italian>
<Korean>이름이 다음과 같이 변경됨:</Korean>
<Chinese>已被改名為</Chinese>
@ -1181,7 +1181,7 @@
<English>Nightvision Support</English>
<Spanish>Soporte de visión nocturna</Spanish>
<German>Nachtsicht Unterstützung</German>
<Japanese>暗視装置への対応有無</Japanese>
<Japanese>暗視装置への対応</Japanese>
<Polish>Wsparcie noktowizyjne</Polish>
<Italian>Supporto visore notturno</Italian>
<Russian>Поддержка ночного видения</Russian>
@ -1191,7 +1191,7 @@
<Chinesesimp>支持夜视仪</Chinesesimp>
<Czech>Podpora nočního vidění</Czech>
<Turkish>Gece Görüş Desteği</Turkish>
<Korean>야간투시 지원여부</Korean>
<Korean>야간투시 지원</Korean>
</Key>
<Key ID="STR_ACE_Arsenal_statVisionMode_supPrim">
<English>Primary supported</English>
@ -1206,7 +1206,7 @@
<Chinese>主武器支援</Chinese>
<Chinesesimp>主镜支持</Chinesesimp>
<Czech>Hlavní část hledí podporuje</Czech>
<Korean>주무기 지원여부</Korean>
<Korean>주무기 지원</Korean>
</Key>
<Key ID="STR_ACE_Arsenal_statVisionMode_supSec">
<English>Secondary supported</English>
@ -1221,9 +1221,9 @@
<Chinese>次要武器支援</Chinese>
<Chinesesimp>副镜支持</Chinesesimp>
<Czech>Vedlejší část hledí podporuje</Czech>
<Korean>보조무기 지원여부</Korean>
<Korean>보조무기 지원</Korean>
</Key>
<Key ID="STR_ACE_Arsenal_statVisionMode_IntPrim">
<Key ID="STR_ACE_Arsenal_statVisionMode_intPrim">
<English>Primary integrated</English>
<Spanish>Primaria integrada</Spanish>
<German>Primär Integriert</German>
@ -1236,7 +1236,21 @@
<Chinese>整合主武器</Chinese>
<Chinesesimp>主镜内置</Chinesesimp>
<Czech>Integrováno do hlavní části hledí</Czech>
<Korean>주무기 내장여부</Korean>
<Korean>주무기 내장</Korean>
</Key>
<Key ID="STR_ACE_Arsenal_statVisionMode_ti">
<English>Thermal integrated</English>
<Italian>Termico integrato</Italian>
<Japanese>熱画像装置内蔵</Japanese>
<Russian>Интегрирован тепловизор.</Russian>
<Korean>열화상 내장</Korean>
</Key>
<Key ID="STR_ACE_Arsenal_statVisionMode_intPrimTi">
<English>Thermal &amp; Primary integrated</English>
<Italian>Termico e Primario integrato</Italian>
<Japanese>熱画像装置内蔵・プライマリに内蔵</Japanese>
<Russian>Интегрирован тепловизор и осн.прицел.</Russian>
<Korean>열화상과 주무기 내장</Korean>
</Key>
<Key ID="STR_ACE_Arsenal_statVisionMode_NoSup">
<English>Not Supported</English>
@ -1257,7 +1271,7 @@
<Key ID="STR_ACE_Arsenal_statVisionModeGeneric">
<English>Vision Mode</English>
<German>Sichtmodus</German>
<Japanese>ビジョン モード</Japanese>
<Japanese>映像モード</Japanese>
<Italian>Modalità Visiva</Italian>
<Chinese>視覺模式</Chinese>
<Chinesesimp>视觉模式</Chinesesimp>
@ -1495,7 +1509,7 @@
<Spanish>Añade automáticamente accesorios o cargadores (de la categoría seleccionada) a todas las armas de la lista de objetos</Spanish>
<German>Es werden automatisch kompatible Aufsätze oder Magazine für alle ausgewählten Waffen hinzugefügt</German>
<Polish>Automatycznie doda kompatybilne dodatki oraz magazynki (odpowiednio do każdej kategorii) dla wszystkich broni na liście</Polish>
<Japanese>現在のアイテムリスト内にある全武器に対応する アタッチメントと弾倉(選択したカテゴリに基づく)を自動的に追加します</Japanese>
<Japanese>現在のアイテムリスト内全武器に対応する アタッチメントと弾倉(選択したカテゴリに基づく)を自動的に追加します</Japanese>
<Russian>Добавляет совместимые приспособления или магазины (в зависимости от выбранной категории) для всего оружия в текущем списке предметов</Russian>
<Portuguese>Irá automaticamente adicionar acessórios ou carregadores (baseado na categoria selecionada) para todas as armas na lista de itens atual</Portuguese>
<French>Ajoute automatiquement des accessoires ou des chargeurs compatibles (en fonction de la catégorie sélectionnée), pour toutes les armes de la liste actuelle.</French>
@ -1592,6 +1606,7 @@
<Korean>내림차순</Korean>
<French>Décroissant</French>
<Portuguese>Decrescente</Portuguese>
<Russian>Нисходящий</Russian>
</Key>
<Key ID="STR_ACE_Arsenal_sortAscending">
<English>Ascending</English>
@ -1602,6 +1617,7 @@
<Korean>오름차순</Korean>
<French>Croissant</French>
<Portuguese>Crescente</Portuguese>
<Russian>Восходящий</Russian>
</Key>
<Key ID="STR_ACE_Arsenal_toolsTab">
<English>Tools</English>
@ -1628,6 +1644,7 @@
<Korean>장탄 수</Korean>
<French>Nombre de munitions</French>
<Portuguese>Quantidade de munição</Portuguese>
<Russian>Количество боеприпасов</Russian>
</Key>
<Key ID="STR_ACE_Arsenal_statIlluminators">
<English>Illuminators</English>
@ -1637,6 +1654,7 @@
<Korean>조명</Korean>
<Portuguese>Iluminadores</Portuguese>
<Japanese>イルミネーター</Japanese>
<Russian>Осветители</Russian>
</Key>
<Key ID="STR_ACE_Arsenal_defaultToFavoritesSetting">
<English>Default to Favorites</English>
@ -1647,6 +1665,7 @@
<Korean>즐겨찾기 기본값</Korean>
<French>Favoris par défaut</French>
<Portuguese>Favoritos por padrão</Portuguese>
<Russian>По умолчанию - Избранное</Russian>
</Key>
<Key ID="STR_ACE_Arsenal_defaultToFavoritesTooltip">
<English>Controls whether the ACE Arsenal defaults to showing all items or favorites.</English>
@ -1657,6 +1676,7 @@
<Korean>ACE 아스널이 기본적으로 모든 아이템 또는 즐겨찾기를 표시할 지 여부를 조정합니다.</Korean>
<French>Contrôle si l'arsenal ACE affiche par défaut tous les éléments ou les favoris.</French>
<Portuguese>Controla se o Arsenal ACE exibe por padrão todos os itens ou favoritos.</Portuguese>
<Russian>Определяет, будет ли в арсенале ACE по умолчанию отображаться все предметы или избранное.</Russian>
</Key>
<Key ID="STR_ACE_Arsenal_favoritesColorSetting">
<English>Favorites Color</English>
@ -1667,6 +1687,7 @@
<Korean>즐겨찾기 색상</Korean>
<French>Couleurs favorites</French>
<Portuguese>Cor dos favoritos</Portuguese>
<Russian>Избранный цвет</Russian>
</Key>
<Key ID="STR_ACE_Arsenal_favoritesColorTooltip">
<English>Highlight color for favorited items.</English>
@ -1677,6 +1698,7 @@
<Korean>즐겨찾기한 아이템을 색상으로 강조합니다.</Korean>
<French>Met en surbrillance les éléments favoris.</French>
<Portuguese>Cor de destaque para itens favoritados.</Portuguese>
<Russian>Выделите цветом любимые предметы.</Russian>
</Key>
<Key ID="STR_ACE_Arsenal_buttonFavoritesTooltip">
<English>Switch between displaying all items or your favorites.\nDouble click while holding Shift to add or remove an item.</English>
@ -1687,6 +1709,7 @@
<Korean>모든 아이템을 표시하거나 즐겨찾기를 표시할 때 전환합니다\nShift 키를 누른 상태에서 두 번 클릭하여 아이템을 추가하거나 제거합니다.</Korean>
<French>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.</French>
<Portuguese>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.</Portuguese>
<Russian>Переключайтесь между отображением всех элементов или ваших избранных.\nДважды щелкните, удерживая Shift, чтобы добавить или удалить элемент.</Russian>
</Key>
<Key ID="STR_ACE_Arsenal_buttonSearchTooltip">
<English>Search\nCTRL + Click to enable live results</English>
@ -1694,6 +1717,7 @@
<Italian>Cerca\nCTRL + Click per modificare i risultati mentre scrivi</Italian>
<Japanese>検索\nCTRL + クリックで検索結果の即時表示を有効化</Japanese>
<Korean>검색\nCtrl + 클릭으로 실시간 검색 결과를 활성화</Korean>
<Russian>Поиск\nCtrl + Click для включения результатов в реальном времени</Russian>
</Key>
</Package>
</Project>

View File

@ -450,24 +450,23 @@ class GVAR(display) {
h = QUOTE(55 * GRID_H);
class controls {
class actionsStaticBackground1: ctrlStaticBackground {
idc = -1;
idc = IDC_actionsBackground1;
x = QUOTE(0);
y = QUOTE(0);
w = QUOTE(47 * GRID_W);
h = QUOTE(56 * GRID_H);
h = QUOTE(55 * GRID_H);
colorBackground[]={0.1,0.1,0.1,0.5};
};
class actionsStaticBackground2: ctrlStaticBackground {
idc = -1;
idc = IDC_actionsBackground2;
x = QUOTE(0);
y = QUOTE(0);
w = QUOTE(47 * GRID_W);
h = QUOTE(5 * GRID_H);
colorBackground[]={0.1,0.1,0.1,0.8};
};
class actionsText1: RscText {
class actionsText1: RscTextMulti {
idc = IDC_actionsText1;
fade = 1;
x = QUOTE(0 * GRID_W);
y = QUOTE(5 * GRID_H);
w = QUOTE(45 * GRID_W);
@ -479,7 +478,6 @@ class GVAR(display) {
};
class actionsButton1: ctrlButton {
idc = IDC_actionsButton1;
fade = 1;
text = "";
x = QUOTE(1 * GRID_W);
y = QUOTE(6 * GRID_H);
@ -566,6 +564,7 @@ class GVAR(display) {
colorSelect[] = {1,1,1,1};
colorSelect2[] = {1,1,1,1};
colorPictureRightSelected[] = {1,1,1,1};
colorTextRight[] = {0.5, 0.5, 0.5, 0};
onLBSelChanged = QUOTE(_this call FUNC(onSelChangedLeft));
onLBDblClick = QUOTE(_this call FUNC(onPanelDblClick));
onSetFocus = QUOTE(GVAR(leftTabFocus) = true);
@ -596,6 +595,7 @@ class GVAR(display) {
colorSelect[] = {1,1,1,1};
colorSelect2[] = {1,1,1,1};
colorPictureRightSelected[] = {1,1,1,1};
colorTextRight[] = {0.5, 0.5, 0.5, 0};
columns[] = {0.07, 0.15, 0.75};
idcLeft = IDC_arrowMinus;
idcRIght = IDC_arrowPlus;

View File

@ -1 +0,0 @@
#include "..\script_component.hpp"

View File

@ -65,7 +65,7 @@ GVAR(magModeData) = [];
{
_x params ["_xDisplayNameShort", "_xDisplayName", "_xInitSpeed", "_xAirFriction"];
if (_allSameCharge) then {
_ctrlChargeList lbAdd format ["%1", _xDisplayNameShort];
_ctrlChargeList lbAdd _xDisplayNameShort;
_ctrlChargeList lbSetTooltip [count GVAR(magModeData), format ["%1\n%2 m/s\n%3", _xDisplayName, _xInitSpeed toFixed 1, _xAirFriction]];
GVAR(magModeData) pushBack [_xInitSpeed, _xAirFriction];
} else {

View File

@ -22,10 +22,10 @@ private _ctrlElevationHigh = _dialog displayCtrl IDC_BUTTON_ELEV_HIGH;
private _ctrlElevationLow = _dialog displayCtrl IDC_BUTTON_ELEV_LOW;
GVAR(lastElevationMode) = param [0, GVAR(lastElevationMode)]; // update if passed a new value
GVAR(lastCharge) = lbCurSel _ctrlChargeList;
GVAR(lastTablePage) = lbCurSel _ctrlChargeList;
// get data for currently selected mag/mode combo:
(GVAR(magModeData) select GVAR(lastCharge)) params [["_muzzleVelocity", -1], ["_airFriction", 0]];
(GVAR(magModeData) select GVAR(lastTablePage)) params [["_muzzleVelocity", -1], ["_airFriction", 0]];
private _elevMin = _dialog getVariable [QGVAR(elevMin), 0];
private _elevMax = _dialog getVariable [QGVAR(elevMax), 0];
_ctrlElevationHigh ctrlSetTextColor ([[0.25,0.25,0.25,1],[1,1,1,1]] select GVAR(lastElevationMode));

View File

@ -1,8 +1,10 @@
#include "script_component.hpp"
if (!hasInterface) exitWith {};
#include "initKeybinds.inc.sqf"
GVAR(active) = false;
GVAR(initialised) = false;
[QEGVAR(vector,rangefinderData), {_this call FUNC(sord)}] call CBA_fnc_addEventHandler;
[QEGVAR(vector,rangefinderData), LINKFUNC(sord)] call CBA_fnc_addEventHandler;

View File

@ -15,7 +15,7 @@
* Public: No
*/
LOG_2("Trying to load gunlist from profile [Version: %1][Count: %2]", profileNamespace getVariable [ARR_2(QGVAR(profileNamespaceVersion), 'none')], count (profileNamespace getVariable [ARR_2(QGVAR(gunList), [])]));
LOG_2("Trying to load gunlist from profile [Version: %1][Count: %2]",profileNamespace getVariable [ARR_2(QGVAR(profileNamespaceVersion),'none')],count (profileNamespace getVariable [ARR_2(QGVAR(gunList),[])]));
private _resetGunList = true;
if ((profileNamespace getVariable ["ACE_ATragMX_profileNamespaceVersion", 0]) == ATRAGMX_PROFILE_NAMESPACE_VERSION && {count (profileNamespace getVariable ["ACE_ATragMX_gunList", []]) > 0}) then {

View File

@ -90,7 +90,7 @@ if (GVAR(showWind2)) then {
_elevationAbs = Round(_elevationAbs * 100) / 100;
if (_elevationAbs > 0) then {
ctrlSetText [400, format["%1", abs(_elevationAbs)]];
ctrlSetText [400, str abs _elevationAbs];
} else {
if (_elevationAbs < 0) then {
ctrlSetText [400, format["%1D", abs(_elevationAbs)]];
@ -100,7 +100,7 @@ if (_elevationAbs > 0) then {
};
_elevationRel = Round(_elevationRel * 100) / 100;
if (_elevationRel > 0) then {
ctrlSetText [401, format["%1", abs(_elevationRel)]];
ctrlSetText [401, str abs _elevationRel];
} else {
if (_elevationRel < 0) then {
ctrlSetText [401, format["%1D", abs(_elevationRel)]];
@ -110,7 +110,7 @@ if (_elevationRel > 0) then {
};
_elevationCur = Round(_elevationCur * 100) / 100;
if (_elevationCur > 0) then {
ctrlSetText [402, format["%1", abs(_elevationCur)]];
ctrlSetText [402, str abs _elevationCur];
} else {
if (_elevationCur < 0) then {
ctrlSetText [402, format["%1D", abs(_elevationCur)]];

View File

@ -57,7 +57,7 @@ if (!_isChemlight) then {
_unit addItem _itemName;
};
if (toLower _itemName in ["b_ir_grenade", "o_ir_grenade", "i_ir_grenade"]) then {
if (toLowerANSI _itemName in ["b_ir_grenade", "o_ir_grenade", "i_ir_grenade"]) then {
// Hack for dealing with X_IR_Grenade effect not dissapearing on deleteVehicle
detach _attachedObject;
_attachedObject setPos ((getPos _unit) vectorAdd [0, 0, -1000]);

View File

@ -41,7 +41,11 @@ if (_initSpeedCoef > 0) then {
};
private _abAdjustText = "";
if (_magIsForCurrentWeapon && {["ace_advanced_ballistics"] call EFUNC(common,isModLoaded)}) then {
if (
_magIsForCurrentWeapon &&
{missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]} &&
{missionNamespace getVariable [QEGVAR(advanced_ballistics,barrelLengthInfluenceEnabled), false]} // this can be on while AB is off or vice-versa
) then {
private _configAmmo = (configFile >> "CfgAmmo" >> (getText (_configMagazine >> "ammo")));
private _barrelLength = getNumber (_configWeapon >> "ACE_barrelLength");
private _muzzleVelocityTable = getArray (_configAmmo >> "ACE_muzzleVelocities");

View File

@ -37,7 +37,10 @@ if (_magazine isEqualTo "") then {
};
private _abAdjustText = "";
if (["ace_advanced_ballistics"] call EFUNC(common,isModLoaded)) then {
if (
missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false] &&
{missionNamespace getVariable [QEGVAR(advanced_ballistics,barrelLengthInfluenceEnabled), false]} // this can be on while AB is off or vice-versa
) then {
private _configAmmo = (configFile >> "CfgAmmo" >> (getText (_configMagazine >> "ammo")));
private _barrelLength = getNumber (_configWeapon >> "ACE_barrelLength");
private _muzzleVelocityTable = getArray (_configAmmo >> "ACE_muzzleVelocities");

View File

@ -3539,6 +3539,7 @@
<Korean>인공지능 사용</Korean>
<French>Utilisation de l'IA</French>
<Portuguese>Utilização por IA</Portuguese>
<Russian>Использование ИИ</Russian>
</Key>
<Key ID="STR_ACE_Ballistics_ammoUsageShort_illumination">
<English>Illum</English>
@ -3549,6 +3550,7 @@
<Korean>조명탄</Korean>
<French>Fusées éclairantes</French>
<Portuguese>Sinalizadoras</Portuguese>
<Russian>Осветители</Russian>
</Key>
<Key ID="STR_ACE_Ballistics_ammoUsageShort_concealment">
<English>Smoke</English>
@ -3559,6 +3561,7 @@
<Korean>연막탄</Korean>
<French>Fumigènes</French>
<Portuguese>Fumígenas</Portuguese>
<Russian>Дым</Russian>
</Key>
<Key ID="STR_ACE_Ballistics_ammoUsageShort_infantry">
<English>Inf</English>
@ -3569,6 +3572,7 @@
<Korean>보병</Korean>
<French>Infanterie</French>
<Portuguese>Infantaria</Portuguese>
<Russian>Пехота</Russian>
</Key>
<Key ID="STR_ACE_Ballistics_ammoUsageShort_lightVehicle">
<English>Veh</English>
@ -3579,6 +3583,7 @@
<Korean>차량</Korean>
<French>Véhicule</French>
<Portuguese>Veículo</Portuguese>
<Russian>Техника</Russian>
</Key>
<Key ID="STR_ACE_Ballistics_ammoUsageShort_armor">
<English>Armor</English>
@ -3589,6 +3594,7 @@
<Korean>기갑</Korean>
<French>Blindage</French>
<Portuguese>Blindagem</Portuguese>
<Russian>Бронетехника</Russian>
</Key>
<Key ID="STR_ACE_Ballistics_ammoUsageShort_aircraft">
<English>Air</English>
@ -3599,6 +3605,7 @@
<Korean>항공</Korean>
<French>Aviation</French>
<Portuguese>Aeronaves</Portuguese>
<Russian>Авиация</Russian>
</Key>
</Package>
</Project>

View File

@ -25,14 +25,14 @@ if (isServer) then {
};
["unit", FUNC(handlePlayerChanged)] call CBA_fnc_addPlayerEventHandler;
[QGVAR(moveInCaptive), FUNC(vehicleCaptiveMoveIn)] call CBA_fnc_addEventHandler;
[QGVAR(moveOutCaptive), FUNC(vehicleCaptiveMoveOut)] call CBA_fnc_addEventHandler;
[QGVAR(moveInCaptive), LINKFUNC(vehicleCaptiveMoveIn)] call CBA_fnc_addEventHandler;
[QGVAR(moveOutCaptive), LINKFUNC(vehicleCaptiveMoveOut)] call CBA_fnc_addEventHandler;
[QGVAR(setHandcuffed), FUNC(setHandcuffed)] call CBA_fnc_addEventHandler;
[QGVAR(setSurrendered), FUNC(setSurrendered)] call CBA_fnc_addEventHandler;
[QGVAR(setHandcuffed), LINKFUNC(setHandcuffed)] call CBA_fnc_addEventHandler;
[QGVAR(setSurrendered), LINKFUNC(setSurrendered)] call CBA_fnc_addEventHandler;
//Medical Integration Events
["ace_unconscious", FUNC(handleOnUnconscious)] call CBA_fnc_addEventHandler;
["ace_unconscious", LINKFUNC(handleOnUnconscious)] call CBA_fnc_addEventHandler;
if (!hasInterface) exitWith {};

View File

@ -16,7 +16,7 @@
*/
params ["_vehicle"];
TRACE_1("params", _vehicle);
TRACE_1("params",_vehicle);
scopeName "main";

View File

@ -27,7 +27,7 @@ if (_isUnconc) then {
};
} else {
//Woke up: if handcuffed, goto animation
if (_unit getVariable [QGVAR(isHandcuffed), false] && {vehicle _unit == _unit}) then {
if (_unit getVariable [QGVAR(isHandcuffed), false] && {isNull objectParent _unit}) then {
[_unit] call EFUNC(common,fixLoweredRifleAnimation);
[_unit, "ACE_AmovPercMstpScapWnonDnon", 1] call EFUNC(common,doAnimation);
};

View File

@ -145,6 +145,7 @@
<Polish>Załóż opaskę na oczy</Polish>
<Korean>포로 눈 가리기</Korean>
<Japanese>目隠しをする</Japanese>
<Russian>Завязать глаза пленному</Russian>
</Key>
<Key ID="STR_ACE_Captives_RemoveBlindfoldCaptive">
<English>Remove blindfold</English>
@ -154,6 +155,7 @@
<Polish>Zdejmij opaskę z oczu</Polish>
<Korean>눈가리개 풀기</Korean>
<Japanese>目隠しを外す</Japanese>
<Russian>Снять повязку с глаз</Russian>
</Key>
<Key ID="STR_ACE_Captives_CableTie">
<English>Cable Tie</English>
@ -484,7 +486,7 @@
<Chinesesimp>设置在光标下的单位成俘虏状态。</Chinesesimp>
<Korean>커서의 병력을 포박합니다.</Korean>
<Polish>Ustawia jednostkę pod kursorem jako jeniec.</Polish>
<Russian>Арестовывает указанный курсором юнит</Russian>
<Russian>Арестовывает указанный курсором юнит.</Russian>
<Portuguese>Torna a unidade sob o cursor um prisioneiro</Portuguese>
<French>Capture l'unité sous le curseur.</French>
<Czech>Nastaví jednotku pod kurzorem jako zajatce.</Czech>

View File

@ -15,3 +15,17 @@ class Extended_PostInit_EventHandlers {
init = QUOTE(call COMPILE_SCRIPT(XEH_postInit));
};
};
class Extended_Killed_EventHandlers {
class CAManBase {
class ADDON {
killed = QUOTE((_this select 0) call FUNC(handleDeployInterrupt));
};
};
};
class Extended_DisplayLoad_EventHandlers {
class RscDisplayMission {
ADDON = QUOTE(_this call COMPILE_SCRIPT(XEH_missionDisplayLoad));
};
};

View File

@ -2,10 +2,15 @@ PREP(addCargoItem);
PREP(addCargoVehiclesActions);
PREP(canLoadItemIn);
PREP(canUnloadItem);
PREP(deployCancel);
PREP(deployConfirm);
PREP(getCargoSpaceLeft);
PREP(getNameItem);
PREP(getSelectedItem);
PREP(getSizeItem);
PREP(handleDestroyed);
PREP(handleDeployInterrupt);
PREP(handleScrollWheel);
PREP(initObject);
PREP(initVehicle);
PREP(loadItem);
@ -16,6 +21,7 @@ PREP(removeCargoItem);
PREP(renameObject);
PREP(setSize);
PREP(setSpace);
PREP(startDeploy);
PREP(startLoadIn);
PREP(startUnload);
PREP(unloadCarryItem);

View File

@ -0,0 +1,11 @@
#include "script_component.hpp"
params ["_display"];
_display displayAddEventHandler ["MouseZChanged", {(_this select 1) call FUNC(handleScrollWheel)}];
_display displayAddEventHandler ["MouseButtonDown", {
// Right clicking cancels deployment
if (_this select 1 == 1) then {
ACE_player call FUNC(handleDeployInterrupt);
};
}];

View File

@ -17,10 +17,10 @@
}] call CBA_fnc_addEventHandler;
["ace_unloadCargo", {
params ["_item", "_vehicle", ["_unloader", objNull]];
TRACE_3("UnloadCargo EH",_item,_vehicle,_unloader);
params ["_item", "_vehicle", ["_unloader", objNull], ["_place", []]];
TRACE_4("UnloadCargo EH",_item,_vehicle,_unloader,_place);
private _unloaded = [_item, _vehicle, _unloader] call FUNC(unloadItem); // returns true if successful
private _unloaded = [_item, _vehicle, _unloader, _place] call FUNC(unloadItem); // returns true if successful
// Show hint as feedback
private _hint = [LSTRING(unloadingFailed), LSTRING(unloadedItem)] select _unloaded;
@ -36,13 +36,25 @@
};
}] call CBA_fnc_addEventHandler;
// Direction must be set before setting position according to wiki
[QGVAR(setDirAndUnload), {
params ["_item", "_emptyPosAGL", "_direction"];
_item setDir _direction;
[QGVAR(serverUnload), [_item, _emptyPosAGL]] call CBA_fnc_serverEvent;
}] call CBA_fnc_addEventHandler;
// hideObjectGlobal must be executed before setPos to ensure light objects are rendered correctly
// Do both on server to ensure they are executed in the correct order
[QGVAR(serverUnload), {
params ["_item", "_emptyPosAGL"];
_item hideObjectGlobal false;
_item setPosASL (AGLtoASL _emptyPosAGL);
[_item, "blockDamage", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
// Let objects remain invulernable for a short while after placement
[EFUNC(common,statusEffect_set), [_item, "blockDamage", QUOTE(ADDON), false], 2] call CBA_fnc_waitAndExecute;
}] call CBA_fnc_addEventHandler;
[QGVAR(paradropItem), {
@ -166,3 +178,38 @@ if (isServer) then {
_bodyBag setVariable [QGVAR(customName), [_target, false, true] call EFUNC(common,getName), true];
}] call CBA_fnc_addEventHandler;
};
// Set variables, even on machines without interfaces, just to be safe
GVAR(selectedItem) = objNull;
GVAR(itemPreviewObject) = objNull;
GVAR(deployPFH) = -1;
GVAR(deployDistance) = -1;
GVAR(deployDirection) = 0;
GVAR(deployHeight) = 0;
GVAR(canDeploy) = false;
if (!hasInterface) exitWith {};
// Cancel object deployment if interact menu opened
["ace_interactMenuOpened", {ACE_player call FUNC(handleDeployInterrupt)}] call CBA_fnc_addEventHandler;
// Cancel deploy on player change. This does work when returning to lobby, but not when hard disconnecting
["unit", LINKFUNC(handleDeployInterrupt)] call CBA_fnc_addPlayerEventHandler;
["vehicle", {(_this select 0) call FUNC(handleDeployInterrupt)}] call CBA_fnc_addPlayerEventHandler;
["weapon", {(_this select 0) call FUNC(handleDeployInterrupt)}] call CBA_fnc_addPlayerEventHandler;
// When changing feature cameras, stop deployment
["featureCamera", {(_this select 0) call FUNC(handleDeployInterrupt)}] call CBA_fnc_addPlayerEventHandler;
// Handle falling unconscious while trying to deploy
["ace_unconscious", {(_this select 0) call FUNC(handleDeployInterrupt)}] call CBA_fnc_addEventHandler;
// Handle surrendering and handcuffing
["ace_captiveStatusChanged", {
params ["_unit", "_state"];
// If surrendered or handcuffed, stop deployment
if (_state) then {
_unit call FUNC(handleDeployInterrupt);
};
}] call CBA_fnc_addEventHandler;

Some files were not shown because too many files have changed in this diff Show More