Compare commits

..

No commits in common. "master" and "v3.17.0" have entirely different histories.

1640 changed files with 85872 additions and 28766 deletions

View File

@ -11,8 +11,5 @@ trim_trailing_whitespace = true
[*.md] [*.md]
trim_trailing_whitespace = false trim_trailing_whitespace = false
[*.yml]
indent_size = 2
[Makefile] [Makefile]
indent_style = tab indent_style = tab

View File

@ -23,14 +23,14 @@ All good? Then proceed and fill out the items below.
**Mods (complete and add to the following information):** **Mods (complete and add to the following information):**
- **Arma 3:** `x.xx` [e.g. 1.00 stable, rc, dev] - **Arma 3:** `x.xx` [e.g. 1.00 stable, rc, dev]
- **CBA:** `3.x.x` [e.g. 3.0.0 stable, commit hash] - **CBA:** `3.x.x` [e.g. 3.0.0 stable, commit hash]
- **ACE3:** `3.x.x` [e.g. 3.0.0 stable, commit hash] - **ACE3:** `3.x.x` [eg. 3.0.0 stable, commit hash]
<!-- Make sure to reproduce the issue with only CBA and ACE3 on a newly created mission! --> <!-- Make sure to reproduce the issue with only CBA and ACE3 on a newly created mission! -->
**Description:** **Description:**
A clear and concise description of what the bug is. A clear and concise description of what the bug is.
**Steps to reproduce:** **Steps to reproduce:**
_Follow [this flowchart](https://ace3.acemod.org/img/wiki/user/issue_flowchart.webp)!_ _Follow [https://ace3.acemod.org/img/wiki/user/issue_flowchart.webp](this flowchart)!_
1. _Go to ..._ 1. _Go to ..._
2. _Click ..._ 2. _Click ..._

View File

@ -27,6 +27,15 @@ jobs:
- name: Validate function headers - name: Validate function headers
run: python3 docs/tools/document_functions.py --debug run: python3 docs/tools/document_functions.py --debug
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout the source code
uses: actions/checkout@v4
- name: Lint (sqflint)
uses: arma-actions/sqflint@master
continue-on-error: true # No failure due to many false-positives
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:

View File

@ -1,65 +1,29 @@
name: Extensions name: Extensions
on: on:
push: pull_request:
paths: paths:
- 'extension/**' - 'extensions/**'
- 'Cargo.toml'
- 'Cargo.lock'
- '.github/workflows/extensions.yml'
jobs: jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout the source code
uses: actions/checkout@master
- name: Install dependencies
run: |
rustup toolchain update stable --no-self-update
rustup default stable
rustup component add clippy rustfmt
- name: Run rustfmt
run: cargo fmt -- --check
- name: Run clippy
run: cargo clippy --all -- -Dwarnings
test:
runs-on: ubuntu-latest
container:
image: xd009642/tarpaulin
options: --security-opt seccomp=unconfined
steps:
- name: Checkout the source code
uses: actions/checkout@master
- name: Test & Coverage
run: cargo tarpaulin --verbose --no-default-features --workspace --timeout 240
build: build:
runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
arrays: [ os: [windows-latest]
os: { tag: "windows-latest", target: "i686-pc-windows-msvc" },
os: { tag: "windows-latest", target: "x86_64-pc-windows-msvc" },
]
runs-on: ${{ matrix.arrays.os.tag }}
steps: steps:
- name: Checkout the source code - name: Checkout the source code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Install stable Rust
uses: actions-rs/toolchain@v1
with:
target: ${{ matrix.arrays.os.target }}
toolchain: stable
default: true
- name: Rust Cache
uses: Swatinem/rust-cache@v2
- name: Build - name: Build
run: cargo build --verbose shell: cmd
- name: Upload run: |
uses: actions/upload-artifact@v2 cd extensions
mkdir build
cd build
cmake .. && cmake --build .
- name: Upload Artifact
uses: actions/upload-artifact@v4
with: with:
name: ${{ matrix.arrays.os.target }} name: ace3_extensions-${{ matrix.os }}-debug
path: target/debug/ace.dll path: extensions/build
if-no-files-found: error
retention-days: 30

View File

@ -33,8 +33,6 @@ jobs:
xcopy /e /h /q pullrequest\addons addons\ xcopy /e /h /q pullrequest\addons addons\
xcopy /e /h /q pullrequest\optionals optionals\ xcopy /e /h /q pullrequest\optionals optionals\
xcopy /e /h /q pullrequest\include include\ xcopy /e /h /q pullrequest\include include\
xcopy /y /h /q pullrequest\ace.dll ace.dll
xcopy /y /h /q pullrequest\ace_x64.dll ace_x64.dll
- name: Run HEMTT build - name: Run HEMTT build
run: hemtt build run: hemtt build
- name: Rename build folder - name: Rename build folder

3
.gitignore vendored
View File

@ -2,6 +2,8 @@
*.zip *.zip
release/* release/*
releases/* releases/*
extensions/vcproj32/*
extensions/vcproj64/*
.vscode/* .vscode/*
hemtt hemtt
hemtt.exe hemtt.exe
@ -18,5 +20,4 @@ CHANGELOG.md
sqfvm.exe sqfvm.exe
ArmaScriptCompiler.exe ArmaScriptCompiler.exe
*.sqfc *.sqfc
target/
!extras/**/*.zip !extras/**/*.zip

View File

@ -28,32 +28,38 @@ exclude = [
"zeus/functions/fnc_zeusAttributes.sqf", "zeus/functions/fnc_zeusAttributes.sqf",
] ]
[hemtt.launch.default] [hemtt.launch]
workshop = [ workshop = [
"450814997", # CBA_A3 "450814997", # CBA_A3
] ]
[hemtt.launch.spe] [hemtt.launch.spe]
extends = "default" workshop = [
"450814997", # CBA_A3
]
dlc = [ dlc = [
"spe" "spe"
] ]
[hemtt.launch.vn] [hemtt.launch.vn]
extends = "default" workshop = [
"450814997", # CBA_A3's Workshop ID
]
dlc = [ dlc = [
"S.O.G. Prairie Fire", "S.O.G. Prairie Fire",
] ]
[hemtt.launch.ws] [hemtt.launch.ws]
extends = "default" workshop = [
"450814997", # CBA_A3's Workshop ID
]
dlc = [ dlc = [
"Western Sahara", "Western Sahara",
] ]
[hemtt.launch.rhs] [hemtt.launch.rhs]
extends = "default"
workshop = [ workshop = [
"450814997", # CBA_A3's Workshop ID
"843425103", # RHS AFRF Workshop ID "843425103", # RHS AFRF Workshop ID
"843577117", # RHS USAF Workshop ID "843577117", # RHS USAF Workshop ID
"843593391", # RHS GREF Workshop ID "843593391", # RHS GREF Workshop ID

1364
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +0,0 @@
[workspace]
resolver = "2"
members = [
"extension"
]
[profile.release]
opt-level = "z"
lto = true
codegen-units = 1
strip = true

BIN
ace.dll

Binary file not shown.

BIN
ace_advanced_ballistics.dll Normal file

Binary file not shown.

Binary file not shown.

BIN
ace_artillerytables.dll Normal file

Binary file not shown.

BIN
ace_artillerytables_x64.dll Normal file

Binary file not shown.

BIN
ace_break_line.dll Normal file

Binary file not shown.

BIN
ace_break_line_x64.dll Normal file

Binary file not shown.

BIN
ace_clipboard.dll Normal file

Binary file not shown.

BIN
ace_clipboard_x64.dll Normal file

Binary file not shown.

BIN
ace_fcs.dll Normal file

Binary file not shown.

BIN
ace_fcs_x64.dll Normal file

Binary file not shown.

Binary file not shown.

View File

@ -1,10 +1,10 @@
#include "script_component.hpp" #include "script_component.hpp"
#include "initKeybinds.inc.sqf" GVAR(currentbulletID) = -1;
GVAR(Protractor) = false; GVAR(Protractor) = false;
GVAR(ProtractorStart) = CBA_missionTime; GVAR(ProtractorStart) = CBA_missionTime;
GVAR(allBullets) = createHashMap; GVAR(allBullets) = [];
GVAR(currentGrid) = 0; GVAR(currentGrid) = 0;
if (!hasInterface) exitWith {}; if (!hasInterface) exitWith {};
@ -24,6 +24,22 @@ if (!hasInterface) exitWith {};
// Register Perframe Handler // Register Perframe Handler
[LINKFUNC(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)
{
_x params ["_modPBO", "_compatPBO"];
if ([_modPBO] call EFUNC(common,isModLoaded) && {!([_compatPBO] call EFUNC(common,isModLoaded))}) then {
WARNING_2("Weapon Mod [%1] missing ace compat pbo [%2] (from @ace\optionals)",_modPBO,_compatPBO);
};
} forEach [
["RH_acc","ace_compat_rh_acc"],
["RH_de_cfg","ace_compat_rh_de"],
["RH_m4_cfg","ace_compat_rh_m4"],
["RH_PDW","ace_compat_rh_pdw"],
["RKSL_PMII","ace_compat_rksl_pm_ii"],
["iansky_opt","ace_compat_sma3_iansky"],
["R3F_Armes","ace_compat_r3f"]
];
}] call CBA_fnc_addEventHandler; }] call CBA_fnc_addEventHandler;
#ifdef DEBUG_MODE_FULL #ifdef DEBUG_MODE_FULL

View File

@ -18,3 +18,10 @@ class CfgPatches {
#include "CfgVehicles.hpp" #include "CfgVehicles.hpp"
#include "RscTitles.hpp" #include "RscTitles.hpp"
#include "ACE_Settings.hpp" #include "ACE_Settings.hpp"
class ACE_Extensions {
class ace_advanced_ballistics {
windows = 1;
client = 1;
};
};

View File

@ -80,7 +80,7 @@ for "_i" from 0 to (count _cfgWeapons)-1 do {
diag_log text format ["AB_Diagnose_barrelTwist,%1,%2,%3,%4,%5",_weapon,_magazine,_ammo,_twistDirection,_barrelTwist]; diag_log text format ["AB_Diagnose_barrelTwist,%1,%2,%3,%4,%5",_weapon,_magazine,_ammo,_twistDirection,_barrelTwist];
}; };
if (_barrelLength == 0) then { if (_barrelLength == 0) then {
diag_log text format ["AB_Diagnose_barrelLength,%1,%2,%3,%4",_weapon,_magazine,_ammo,_barrelLength]; diag_log text format ["AB_Diagnose_barrelLength,%1,%2,%3,%4,%5",_weapon,_magazine,_ammo,_barrelLength];
}; };
}; };
} forEach _magazines; } forEach _magazines;

View File

@ -1,6 +1,6 @@
#include "..\script_component.hpp" #include "..\script_component.hpp"
/* /*
* Author: Glowbal, Ruthberg, joko // Jonas, Brett Mayson * Author: Glowbal, Ruthberg, joko // Jonas
* Handle the PFH for Bullets * Handle the PFH for Bullets
* *
* Arguments: * Arguments:
@ -17,7 +17,7 @@
private _deleted = false; private _deleted = false;
{ {
_y params ["_bullet","_caliber","_bulletTraceVisible"]; _x params ["_bullet","_caliber","_bulletTraceVisible","_index"];
if (alive _bullet) then { if (alive _bullet) then {
private _bulletVelocity = velocity _bullet; private _bulletVelocity = velocity _bullet;
@ -27,21 +27,13 @@ private _deleted = false;
drop ["\A3\data_f\ParticleEffects\Universal\Refract","","Billboard",1,0.1,getPos _bullet,[0,0,0],0,1.275,1,0,[0.02*_caliber,0.01*_caliber],[[0,0,0,0.65],[0,0,0,0.2]],[1,0],0,0,"","",""]; drop ["\A3\data_f\ParticleEffects\Universal\Refract","","Billboard",1,0.1,getPos _bullet,[0,0,0],0,1.275,1,0,[0.02*_caliber,0.01*_caliber],[[0,0,0,0.65],[0,0,0,0.2]],[1,0],0,0,"","",""];
}; };
( _bullet setVelocity (_bulletVelocity vectorAdd (parseSimpleArray ("ace_advanced_ballistics" callExtension format["simulate:%1:%2:%3:%4:%5:%6", _index, _bulletVelocity, _bulletPosition, wind, ASLToATL(_bulletPosition) select 2, CBA_missionTime toFixed 6])));
"ace" callExtension ["ballistics:bullet:simulate", [
_x,
_bulletVelocity,
_bulletPosition,
wind,
ASLToATL(_bulletPosition) select 2,
CBA_missionTime toFixed 6
]]
) params ["_data", "_code"];
if (_code == 0) then {
_bullet setVelocity (_bulletVelocity vectorAdd (parseSimpleArray (_data)));
};
} else { } else {
GVAR(allBullets) deleteAt _x; GVAR(allBullets) set [_forEachIndex, objNull];
"ace" callExtension ["ballistics:bullet:delete", [_x]]; _deleted = true;
}; };
} forEach GVAR(allBullets) } forEach GVAR(allBullets);
if (_deleted) then {
GVAR(allBullets) = GVAR(allBullets) - [objNull];
};

View File

@ -1,6 +1,6 @@
#include "..\script_component.hpp" #include "..\script_component.hpp"
/* /*
* Author: Glowbal, Ruthberg, Brett Mayson * Author: Glowbal, Ruthberg
* *
* Handles advanced ballistics for (BulletBase) projectiles. Called from the unified fired EH only for players. * Handles advanced ballistics for (BulletBase) projectiles. Called from the unified fired EH only for players.
* *
@ -19,7 +19,7 @@
//IGNORE_PRIVATE_WARNING ["_unit", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile", "_vehicle", "_gunner", "_turret"]; //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 (!(_ammo isKindOf "BulletBase")) exitWith {};
if (!alive _projectile) exitWith {}; if (!alive _projectile) exitWith {};
if (underwater _unit) exitWith {}; if (underwater _unit) exitWith {};
@ -120,26 +120,8 @@ if (_caliber * _bulletLength * _bulletMass * _barrelTwist > 0) then {
_stabilityFactor = [_caliber, _bulletLength, _bulletMass, _barrelTwist, _muzzleVelocity, _temperature, _barometricPressure] call FUNC(calculateStabilityFactor); _stabilityFactor = [_caliber, _bulletLength, _bulletMass, _barrelTwist, _muzzleVelocity, _temperature, _barometricPressure] call FUNC(calculateStabilityFactor);
}; };
("ace" callExtension [ GVAR(currentbulletID) = (GVAR(currentbulletID) + 1) % 10000;
"ballistics:bullet:new", [
_ammoCount, "ace_advanced_ballistics" callExtension format["new:%1:%2:%3:%4:%5:%6:%7:%8:%9:%10:%11:%12:%13:%14:%15:%16:%17:%18", GVAR(currentbulletID), _ammoCount, _airFriction, _ballisticCoefficients, _velocityBoundaries, _atmosphereModel, _dragModel, _stabilityFactor, _twistDirection, _transonicStabilityCoef, getPosASL _projectile, _bulletVelocity, EGVAR(common,mapLatitude), EGVAR(weather,currentTemperature), EGVAR(common,mapAltitude), EGVAR(weather,currentHumidity), EGVAR(weather,currentOvercast), CBA_missionTime toFixed 6];
_airFriction,
_ballisticCoefficients, GVAR(allBullets) pushBack [_projectile, _caliber, _bulletTraceVisible, GVAR(currentbulletID)];
_velocityBoundaries,
_atmosphereModel,
_dragModel,
_stabilityFactor,
_twistDirection,
_transonicStabilityCoef,
_bulletVelocity,
EGVAR(common,mapLatitude),
EGVAR(weather,currentTemperature),
EGVAR(common,mapAltitude),
EGVAR(weather,currentHumidity),
EGVAR(weather,currentOvercast),
CBA_missionTime toFixed 6
]
]) params ["_id", "_code"];
if (_code == 0) then {
GVAR(allBullets) set [_id, [_projectile, _caliber, _bulletTraceVisible]];
};

View File

@ -21,14 +21,7 @@ if (!GVAR(enabled)) exitWith {};
private _initStartTime = diag_tickTime; private _initStartTime = diag_tickTime;
private _mapSize = worldSize; private _mapSize = worldSize;
( if (("ace_advanced_ballistics" callExtension format["init:%1:%2", worldName, _mapSize]) == "Terrain already initialized") exitWith {
"ace" callExtension ["ballistics:map:init", [worldName, _mapSize]]
) params ["_data", "_code"];
if (_code != 0) exitWith {
ERROR("Error initializing map")
};
if (_data == "true") exitWith {
INFO_1("Terrain already initialized [world: %1]",worldName); INFO_1("Terrain already initialized [world: %1]",worldName);
#ifdef DEBUG_MODE_FULL #ifdef DEBUG_MODE_FULL
systemChat "AdvancedBallistics: Terrain already initialized"; systemChat "AdvancedBallistics: Terrain already initialized";
@ -60,7 +53,8 @@ INFO_2("Starting Terrain Extension [cells: %1] [world: %2]",_gridCells,worldName
private _gridCenter = [_x + 25, _y + 25]; private _gridCenter = [_x + 25, _y + 25];
private _gridHeight = round(getTerrainHeightASL _gridCenter); private _gridHeight = round(getTerrainHeightASL _gridCenter);
private _gridNumObjects = count (_gridCenter nearObjects ["Building", 50]); private _gridNumObjects = count (_gridCenter nearObjects ["Building", 50]);
"ace" callExtension ["ballistics:map:set", [GVAR(currentGrid), _gridHeight, _gridNumObjects, surfaceIsWater _gridCenter]]; private _gridSurfaceIsWater = parseNumber (surfaceIsWater _gridCenter);
"ace_advanced_ballistics" callExtension format["set:%1:%2:%3", _gridHeight, _gridNumObjects, _gridSurfaceIsWater];
GVAR(currentGrid) = GVAR(currentGrid) + 1; GVAR(currentGrid) = GVAR(currentGrid) + 1;
if (GVAR(currentGrid) >= _gridCells) exitWith {}; if (GVAR(currentGrid) >= _gridCells) exitWith {};
}; };

View File

@ -40,7 +40,7 @@ if (_transonicStabilityCoef == 0) then {
_transonicStabilityCoef = 0.5; _transonicStabilityCoef = 0.5;
}; };
private _dragModel = getNumber(_ammoConfig >> "ACE_dragModel"); private _dragModel = getNumber(_ammoConfig >> "ACE_dragModel");
if !(_dragModel in [1, 2, 5, 6, 7, 8]) then { if (!(_dragModel in [1, 2, 5, 6, 7, 8])) then {
_dragModel = 1; _dragModel = 1;
}; };
private _ballisticCoefficients = getArray(_ammoConfig >> "ACE_ballisticCoefficients"); private _ballisticCoefficients = getArray(_ammoConfig >> "ACE_ballisticCoefficients");

View File

@ -5,9 +5,7 @@ private _category = format ["ACE %1", localize LSTRING(DisplayName)];
[LSTRING(enabled_DisplayName), LSTRING(enabled_Description)], [LSTRING(enabled_DisplayName), LSTRING(enabled_Description)],
_category, _category,
false, false,
1, 1
{[QGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged)},
true // Needs mission restart
] call CBA_fnc_addSetting; ] call CBA_fnc_addSetting;
[ [
@ -47,7 +45,5 @@ private _category = format ["ACE %1", localize LSTRING(DisplayName)];
[LSTRING(simulationInterval_DisplayName), LSTRING(simulationInterval_Description)], [LSTRING(simulationInterval_DisplayName), LSTRING(simulationInterval_Description)],
_category, _category,
[0, 0.2, 0.05, 2], [0, 0.2, 0.05, 2],
1, 1
{[QGVAR(simulationInterval), _this] call EFUNC(common,cbaSettings_settingChanged)},
true // Needs mission restart
] call CBA_fnc_addSetting; ] call CBA_fnc_addSetting;

View File

@ -46,7 +46,7 @@
<Hungarian>Fejlett ballisztika</Hungarian> <Hungarian>Fejlett ballisztika</Hungarian>
<Russian>Продвинутая баллистика</Russian> <Russian>Продвинутая баллистика</Russian>
<Italian>Balistica Avanzata</Italian> <Italian>Balistica Avanzata</Italian>
<Japanese>高度な弾道計算</Japanese> <Japanese>アドバンスド弾道計算</Japanese>
<Korean>고급 탄도학</Korean> <Korean>고급 탄도학</Korean>
<Chinese>先進彈道系統</Chinese> <Chinese>先進彈道系統</Chinese>
<Chinesesimp>进阶弹道系统</Chinesesimp> <Chinesesimp>进阶弹道系统</Chinesesimp>
@ -63,7 +63,7 @@
<Hungarian>Fejlett ballisztika</Hungarian> <Hungarian>Fejlett ballisztika</Hungarian>
<Russian>Продвинутая баллистика</Russian> <Russian>Продвинутая баллистика</Russian>
<Italian>Balistica Avanzata</Italian> <Italian>Balistica Avanzata</Italian>
<Japanese>高度な弾道計算を有効化</Japanese> <Japanese>アドバンスド弾道計算を有効化</Japanese>
<Korean>고급 탄도학</Korean> <Korean>고급 탄도학</Korean>
<Chinese>先進彈道系統</Chinese> <Chinese>先進彈道系統</Chinese>
<Chinesesimp>进阶弹道系统</Chinesesimp> <Chinesesimp>进阶弹道系统</Chinesesimp>
@ -80,7 +80,7 @@
<Hungarian>Engedélyezi a fejlett ballisztikát</Hungarian> <Hungarian>Engedélyezi a fejlett ballisztikát</Hungarian>
<Russian>Включает продвинутую баллистику</Russian> <Russian>Включает продвинутую баллистику</Russian>
<Italian>Abilita Balistica Avanzata</Italian> <Italian>Abilita Balistica Avanzata</Italian>
<Japanese>高度な弾道計算を有効化します。</Japanese> <Japanese>アドバンスド弾道計算は高度な弾道計算処理を有効化します。</Japanese>
<Korean>고급 탄도학을 적용합니다</Korean> <Korean>고급 탄도학을 적용합니다</Korean>
<Chinese>啟用先進彈道系統</Chinese> <Chinese>啟用先進彈道系統</Chinese>
<Chinesesimp>启用进阶弹道系统</Chinesesimp> <Chinesesimp>启用进阶弹道系统</Chinesesimp>
@ -280,7 +280,7 @@
<Hungarian>Meghatározza a játékos körüli hatókört (méterben), ahol a lövedékek fejlett ballisztikát használnak</Hungarian> <Hungarian>Meghatározza a játékos körüli hatókört (méterben), ahol a lövedékek fejlett ballisztikát használnak</Hungarian>
<Russian>Определяет радиус вокруг игрока (в метрах), в котором продвинутая баллистика применяется к снарядам</Russian> <Russian>Определяет радиус вокруг игрока (в метрах), в котором продвинутая баллистика применяется к снарядам</Russian>
<Italian>Definisce il raggio attorno al giocatore (in metri) entro il quale la Balistica Avanzata è applicata ai proiettili</Italian> <Italian>Definisce il raggio attorno al giocatore (in metri) entro il quale la Balistica Avanzata è applicata ai proiettili</Italian>
<Japanese>高度な弾道計算が飛翔体に適用される半径距離 (プレイヤー中心、メートル単位) を定義します。</Japanese> <Japanese>アドバンスド弾道計算の適用半径範囲 (プレイヤー中心、メートル単位) を定義します。</Japanese>
<Korean>플레이어 주위의 발사체를 고급 탄도학으로 정의하는 범위를 정합니다(미터)</Korean> <Korean>플레이어 주위의 발사체를 고급 탄도학으로 정의하는 범위를 정합니다(미터)</Korean>
<Chinese>以玩家的半徑距離(公尺)定義先進彈道系統啟用範圍</Chinese> <Chinese>以玩家的半徑距離(公尺)定義先進彈道系統啟用範圍</Chinese>
<Chinesesimp>定义玩家周围的半径(米),在这个半径内,进阶弹道系统会被启用</Chinesesimp> <Chinesesimp>定义玩家周围的半径(米),在这个半径内,进阶弹道系统会被启用</Chinesesimp>
@ -297,7 +297,7 @@
<Russian>Этот модуль включает симуляцию продвинутой баллистики - при этом на траекторию полета снаряда влияют различные параметры, такие как температура воздуха, атмосферное давление, влажность, гравитация, тип боеприпаса и оружия, из которого произвели выстрел.</Russian> <Russian>Этот модуль включает симуляцию продвинутой баллистики - при этом на траекторию полета снаряда влияют различные параметры, такие как температура воздуха, атмосферное давление, влажность, гравитация, тип боеприпаса и оружия, из которого произвели выстрел.</Russian>
<Spanish>Este módulo permite la simulación balística avanzada - es decir, la trayectoria de los proyectiles está influenciada por variables como la temperatura del aire, la presión atmosférica, la humedad, la gravedad, el tipo de municiones y el arma desde el que fue disparada.</Spanish> <Spanish>Este módulo permite la simulación balística avanzada - es decir, la trayectoria de los proyectiles está influenciada por variables como la temperatura del aire, la presión atmosférica, la humedad, la gravedad, el tipo de municiones y el arma desde el que fue disparada.</Spanish>
<Italian>Questo modulo abilita la simulazione della Balistica Avanzata - essa comporta che la traiettoria dei proiettili è influenzata da variabili come la temperatura dell'aria, pressione atmosferica, umidità, gravità, il tipo di munizione e l'arma da cui è sparata.</Italian> <Italian>Questo modulo abilita la simulazione della Balistica Avanzata - essa comporta che la traiettoria dei proiettili è influenzata da variabili come la temperatura dell'aria, pressione atmosferica, umidità, gravità, il tipo di munizione e l'arma da cui è sparata.</Italian>
<Japanese>高度な弾道計算のシミュレーションを有効化します。 弾道は気温・気圧・湿度・重力・弾薬の種類・発射する武器などの変化による影響を受けるようになります。</Japanese> <Japanese>アドバンスド弾道計算のシミュレーションを有効化します。 弾道は気温・気圧・湿度・重力・弾薬の種類・発射する武器などの変化による影響を受けるようになります。</Japanese>
<Korean>이 모듈은 고급 탄도학을 적용시킵니다 - 이는 발사체의 궤적이 기온, 대기압, 습도, 중력, 탄환의 종류와 어느 무기에서 발사되는지에 따라 영향을 받습니다.</Korean> <Korean>이 모듈은 고급 탄도학을 적용시킵니다 - 이는 발사체의 궤적이 기온, 대기압, 습도, 중력, 탄환의 종류와 어느 무기에서 발사되는지에 따라 영향을 받습니다.</Korean>
<Chinese>該模塊實現先進的彈道仿真 - 這意味著子彈的軌跡是由空氣溫度、大氣壓力、濕度、重力、彈藥類型以及射擊的武器所影響</Chinese> <Chinese>該模塊實現先進的彈道仿真 - 這意味著子彈的軌跡是由空氣溫度、大氣壓力、濕度、重力、彈藥類型以及射擊的武器所影響</Chinese>
<Chinesesimp>该模块实现增强的弹道模拟—子弹的轨迹由空气温度、大气压力、湿度、重力、弹药类型和射击的武器等变量所影响</Chinesesimp> <Chinesesimp>该模块实现增强的弹道模拟—子弹的轨迹由空气温度、大气压力、湿度、重力、弹药类型和射击的武器等变量所影响</Chinesesimp>

View File

@ -9,5 +9,3 @@ PREP(handleStaminaBar);
PREP(mainLoop); PREP(mainLoop);
PREP(moduleSettings); PREP(moduleSettings);
PREP(removeDutyFactor); PREP(removeDutyFactor);
PREP(renderDebugLines);
PREP(updateStaminaBar);

View File

@ -2,10 +2,6 @@
if (!hasInterface) exitWith {}; if (!hasInterface) exitWith {};
#ifdef DEBUG_MODE_FULL
call FUNC(renderDebugLines);
#endif
// recheck weapon inertia after weapon swap, change of attachments or switching unit // recheck weapon inertia after weapon swap, change of attachments or switching unit
["weapon", {[ACE_player] call FUNC(getWeaponInertia)}, true] call CBA_fnc_addPlayerEventHandler; ["weapon", {[ACE_player] call FUNC(getWeaponInertia)}, true] call CBA_fnc_addPlayerEventHandler;
["loadout", {[ACE_player] call FUNC(getWeaponInertia)}, true] call CBA_fnc_addPlayerEventHandler; ["loadout", {[ACE_player] call FUNC(getWeaponInertia)}, true] call CBA_fnc_addPlayerEventHandler;
@ -14,8 +10,6 @@ call FUNC(renderDebugLines);
["CBA_settingsInitialized", { ["CBA_settingsInitialized", {
if (!GVAR(enabled)) exitWith {}; if (!GVAR(enabled)) exitWith {};
[QEGVAR(ui,hideHud), LINKFUNC(updateStaminaBar)] call CBA_fnc_addEventHandler;
["baseline", { ["baseline", {
private _fatigue = ACE_player getVariable [QGVAR(aimFatigue), 0]; private _fatigue = ACE_player getVariable [QGVAR(aimFatigue), 0];
switch (stance ACE_player) do { switch (stance ACE_player) do {
@ -39,23 +33,25 @@ call FUNC(renderDebugLines);
GVAR(ppeBlackout) ppEffectCommit 0.4; GVAR(ppeBlackout) ppEffectCommit 0.4;
// - GVAR updating and initialization ----------------------------------------- // - GVAR updating and initialization -----------------------------------------
["unit", LINKFUNC(handlePlayerChanged)] call CBA_fnc_addPlayerEventHandler; ["unit", LINKFUNC(handlePlayerChanged), true] call CBA_fnc_addPlayerEventHandler;
["visibleMap", { ["visibleMap", {
params ["", "_visibleMap"]; // command visibleMap is updated one frame later params ["", "_visibleMap"]; // command visibleMap is updated one frame later
(uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull]) ctrlShow (!_visibleMap && isNull objectParent ACE_player); private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull];
_staminaBarContainer ctrlShow ((!_visibleMap) && {(vehicle ACE_player) == ACE_player});
}, true] call CBA_fnc_addPlayerEventHandler; }, true] call CBA_fnc_addPlayerEventHandler;
["vehicle", { ["vehicle", {
(uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull]) ctrlShow (!visibleMap && isNull objectParent ACE_player); private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull];
_staminaBarContainer ctrlShow ((!visibleMap) && {(vehicle ACE_player) == ACE_player});
}, true] call CBA_fnc_addPlayerEventHandler; }, true] call CBA_fnc_addPlayerEventHandler;
// - Duty factors ------------------------------------------------------------- // - Duty factors -------------------------------------------------------------
if (GETEGVAR(medical,enabled,false)) then { if (GVAR(medicalLoaded)) then {
[QEGVAR(medical,pain), { // 0->1.0, 0.5->1.05, 1->1.1 [QEGVAR(medical,pain), { // 0->1.0, 0.5->1.05, 1->1.1
linearConversion [0, 1, _this getVariable [QEGVAR(medical,pain), 0], 1, 1.1, true]; linearConversion [0, 1, (_this getVariable [QEGVAR(medical,pain), 0]), 1, 1.1, true];
}] call FUNC(addDutyFactor); }] call FUNC(addDutyFactor);
[QEGVAR(medical,bloodVolume), { // 6->1.0, 5->1.167, 4->1.33 [QEGVAR(medical,bloodVolume), { // 6->1.0, 5->1.167, 4->1.33
linearConversion [6, 0, _this getVariable [QEGVAR(medical,bloodVolume), 6], 1, 2, true]; linearConversion [6, 0, (_this getVariable [QEGVAR(medical,bloodVolume), 6]), 1, 2, true];
}] call FUNC(addDutyFactor); }] call FUNC(addDutyFactor);
}; };
if (["ace_dragging"] call EFUNC(common,isModLoaded)) then { if (["ace_dragging"] call EFUNC(common,isModLoaded)) then {
@ -66,7 +62,7 @@ call FUNC(renderDebugLines);
// Weather has an off switch, Dragging & Medical don't. // Weather has an off switch, Dragging & Medical don't.
if (missionNamespace getVariable [QEGVAR(weather,enabled), false]) then { if (missionNamespace getVariable [QEGVAR(weather,enabled), false]) then {
[QEGVAR(weather,temperature), { // 35->1, 45->2 [QEGVAR(weather,temperature), { // 35->1, 45->2
linearConversion [35, 45, missionNamespace getVariable [QEGVAR(weather,currentTemperature), 25], 1, 2, true]; linearConversion [35, 45, (missionNamespace getVariable [QEGVAR(weather,currentTemperature), 25]), 1, 2, true];
}] call FUNC(addDutyFactor); }] call FUNC(addDutyFactor);
}; };

View File

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

View File

@ -1,7 +1,7 @@
#include "..\script_component.hpp" #include "..\script_component.hpp"
/* /*
* Author: BaerMitUmlaut * Author: BaerMitUmlaut
* Calculates the duty ('postureWeight') of the current animation. * Calculates the duty of the current animation.
* *
* Arguments: * Arguments:
* 0: Unit <OBJECT> * 0: Unit <OBJECT>

View File

@ -1,74 +1,54 @@
#include "..\script_component.hpp" #include "..\script_component.hpp"
/* /*
* Author: BaerMitUmlaut, ulteq * Author: BaerMitUmlaut
* Calculates the current metabolic costs. * Calculates the current metabolic costs for a unit.
* Calculation is done according to the Pandolf/Wojtowicz formulas. * Calculation is done according to the Pandolf/Wojtowicz formulas.
* *
* Arguments: * Arguments:
* 0: Duty of animation * 0: Unit <OBJECT>
* 1: Mass of unit <NUMBER> * 1: Speed <NUMBER>
* 2: Terrain gradient <NUMBER>
* 3: Terrain factor <NUMBER>
* 4: Speed <NUMBER>
* *
* Return Value: * Return Value:
* Metabolic cost <NUMBER> * Metabolic cost <NUMBER>
* *
* Example: * Example:
* [1, 840, 20, 1, 4] call ace_advanced_fatigue_fnc_getMetabolicCosts * [player, 3.3] call ace_advanced_fatigue_fnc_getMetabolicCosts
* *
* Public: No * Public: No
*/ */
params ["_unit", "_velocity"];
params ["_duty", "_gearMass", "_terrainGradient", "_terrainFactor", "_speed"]; private _gearMass = ((_unit getVariable [QEGVAR(movement,totalLoad), loadAbs _unit]) / 22.046) * GVAR(loadFactor);
private _terrainAngle = asin (1 - ((surfaceNormal getPosASL _unit) select 2));
private _terrainGradient = (_terrainAngle / 45 min 1) * 5 * GVAR(terrainGradientFactor);
private _duty = GVAR(animDuty);
{
if (_x isEqualType 0) then {
_duty = _duty * _x;
} else {
_duty = _duty * (_unit call _x);
};
} forEach (values GVAR(dutyList));
if (GVAR(isSwimming)) then {
_terrainGradient = 0;
};
// Metabolic cost for walking and running is different // Metabolic cost for walking and running is different
if (_speed > 2) then { if (_velocity > 2) then {
// Running // Running
#ifdef DEBUG_MODE_FULL
private _baseline = 2.1 * SIM_BODYMASS + 4 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + (SIM_BODYMASS + _gearMass) * 0.9 * (_speed ^ 2);
private _graded = 2.1 * SIM_BODYMASS + 4 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + _terrainFactor * (SIM_BODYMASS + _gearMass) * (0.9 * (_speed ^ 2) + 0.66 * _speed * _terrainGradient);
private _terrainImpact = abs ((_graded / _baseline) - 1);
hintSilent format ["FwdAngle: %1 | SideAngle: %2 \n TerrainFactor: %3 | TerrainGradient: %4 \n TerrainImpact: %5 \n Speed: %6 | CarriedLoad: %7 \n Duty: %8 | Work: %9",
_fwdAngle toFixed 1,
_sideAngle toFixed 1,
_terrainFactor toFixed 2,
_terrainGradient toFixed 1,
_terrainImpact toFixed 2,
_speed toFixed 2,
_gearMass toFixed 1,
_duty toFixed 2,
round (_graded * BIOMECH_EFFICIENCY * _duty)
];
#endif
( (
2.1 * SIM_BODYMASS 2.10 * SIM_BODYMASS
+ 4 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + 4 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2)
+ _terrainFactor * (SIM_BODYMASS + _gearMass) * (0.9 * (_speed ^ 2) + 0.66 * _speed * _terrainGradient) + (SIM_BODYMASS + _gearMass) * (0.9 * (_velocity ^ 2) + 0.66 * _velocity * _terrainGradient)
) * BIOMECH_EFFICIENCY * _duty ) * 0.23 * _duty
} else { } else {
// Walking // Walking
#ifdef DEBUG_MODE_FULL
private _baseline = 1.05 * SIM_BODYMASS + 2 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + (SIM_BODYMASS + _gearMass) * 1.15 * (_speed ^ 2);
private _graded = 1.05 * SIM_BODYMASS + 2 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + _terrainFactor * (SIM_BODYMASS + _gearMass) * (1.15 * (_speed ^ 2) + 0.66 * _speed * _terrainGradient);
private _terrainImpact = abs ((_graded / _baseline) - 1);
hintSilent format ["FwdAngle: %1 | SideAngle: %2 \n TerrainFactor: %3 | TerrainGradient: %4 \n TerrainImpact: %5 \n Speed: %6 | CarriedLoad: %7 \n Duty: %8 | Work: %9",
_fwdAngle toFixed 1,
_sideAngle toFixed 1,
_terrainFactor toFixed 2,
_terrainGradient toFixed 1,
_terrainImpact toFixed 2,
_speed toFixed 2,
_gearMass toFixed 1,
_duty toFixed 2,
round (_graded * BIOMECH_EFFICIENCY * _duty)
];
#endif
( (
1.05 * SIM_BODYMASS 1.05 * SIM_BODYMASS
+ 2 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + 2 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2)
+ _terrainFactor * (SIM_BODYMASS + _gearMass) * (1.15 * (_speed ^ 2) + 0.66 * _speed * _terrainGradient) + (SIM_BODYMASS + _gearMass) * (1.15 * (_velocity ^ 2) + 0.66 * _velocity * _terrainGradient)
) * BIOMECH_EFFICIENCY * _duty ) * 0.23 * _duty
}; };

View File

@ -1,44 +1,44 @@
#include "..\script_component.hpp" #include "..\script_component.hpp"
/* /*
* Author: BaerMitUmlaut, ulteq * Author: BaerMitUmlaut
* Handles any audible, visual and physical effects of fatigue. * Handles any audible, visual and physical effects of fatigue.
* *
* Arguments: * Arguments:
* 0: Unit <OBJECT> * 0: Unit <OBJECT>
* 1: Fatigue <NUMBER> * 1: Fatigue <NUMBER>
* 2: Overexhausted <BOOL> * 2: Speed <NUMBER>
* 3: Forward Angle <NUMBER> * 3: Overexhausted <BOOL>
* 4: Side Angle <NUMBER>
* *
* Return Value: * Return Value:
* None * None
* *
* Example: * Example:
* [_player, 0.5, 3.3, true, 0, 0] call ace_advanced_fatigue_fnc_handleEffects * [_player, 0.5, 3.3, true] call ace_advanced_fatigue_fnc_handleEffects
* *
* Public: No * Public: No
*/ */
params ["_unit", "_fatigue", "_speed", "_overexhausted"];
params ["_unit", "_fatigue", "_overexhausted", "_fwdAngle", "_sideAngle"]; #ifdef DEBUG_MODE_FULL
systemChat str _fatigue;
systemChat str vectorMagnitude velocity _unit;
#endif
// - Audible effects ---------------------------------------------------------- // - Audible effects ----------------------------------------------------------
GVAR(lastBreath) = GVAR(lastBreath) + 1; GVAR(lastBreath) = GVAR(lastBreath) + 1;
if (_fatigue > 0.4 && {GVAR(lastBreath) > (_fatigue * -10 + 9)} && {!underwater _unit}) then { if (_fatigue > 0.4 && {GVAR(lastBreath) > (_fatigue * -10 + 9)} && {!underwater _unit}) then {
if (!isGameFocused) exitWith {}; if (!isGameFocused) exitWith {};
switch (true) do { switch (true) do {
case (_fatigue < 0.6): { case (_fatigue < 0.6): {
playSound (QGVAR(breathLow) + str (floor random 6)); playSound (QGVAR(breathLow) + str(floor random 6));
}; };
case (_fatigue < 0.85): { case (_fatigue < 0.85): {
playSound (QGVAR(breathMid) + str (floor random 6)); playSound (QGVAR(breathMid) + str(floor random 6));
}; };
default { default {
playSound (QGVAR(breathMax) + str (floor random 6)); playSound (QGVAR(breathMax) + str(floor random 6));
}; };
}; };
GVAR(lastBreath) = 0; GVAR(lastBreath) = 0;
}; };
@ -62,35 +62,31 @@ if (GVAR(isSwimming)) exitWith {
if (GVAR(setAnimExclusions) isEqualTo []) then { if (GVAR(setAnimExclusions) isEqualTo []) then {
_unit setAnimSpeedCoef linearConversion [0.7, 0.9, _fatigue, 1, 0.5, true]; _unit setAnimSpeedCoef linearConversion [0.7, 0.9, _fatigue, 1, 0.5, true];
}; };
if ((isSprintAllowed _unit) && {_fatigue > 0.7}) then {
if (isSprintAllowed _unit && _fatigue > 0.7) then { // small checks like these are faster without lazy eval
[_unit, "blockSprint", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); [_unit, "blockSprint", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
} else { } else {
if (!isSprintAllowed _unit && _fatigue < 0.7) then { if ((!isSprintAllowed _unit) && {_fatigue < 0.7}) then {
[_unit, "blockSprint", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); [_unit, "blockSprint", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
}; };
}; };
}; };
if ((getAnimSpeedCoef _unit) != 1) then {
// If other components are setting setAnimSpeedCoef, do not change animSpeedCoef if (GVAR(setAnimExclusions) isEqualTo []) then {
if (getAnimSpeedCoef _unit != 1 && {GVAR(setAnimExclusions) isEqualTo []}) then {
TRACE_1("reset",getAnimSpeedCoef _unit); TRACE_1("reset",getAnimSpeedCoef _unit);
_unit setAnimSpeedCoef 1; _unit setAnimSpeedCoef 1;
};
}; };
if (!isForcedWalk _unit && _fatigue >= 1) then { // small checks like these are faster without lazy eval if (_overexhausted) then {
[_unit, "forceWalk", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); [_unit, "forceWalk", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
[_unit, "blockSprint", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
} else { } else {
if (isForcedWalk _unit && _fatigue < 0.7) then { if (isForcedWalk _unit && {_fatigue < 0.7}) then {
[_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); [_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
[_unit, "blockSprint", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
} else { } else {
// Forward angle is the slope of the terrain, side angle simulates the unevenness/roughness of the terrain if ((isSprintAllowed _unit) && {_fatigue > 0.7}) then {
if (isSprintAllowed _unit && {_fatigue > 0.7 || abs _fwdAngle > 20 || abs _sideAngle > 20}) then {
[_unit, "blockSprint", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); [_unit, "blockSprint", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
} else { } else {
if (!isSprintAllowed _unit && _fatigue < 0.6 && abs _fwdAngle < 20 && abs _sideAngle < 20) then { if ((!isSprintAllowed _unit) && {_fatigue < 0.6}) then {
[_unit, "blockSprint", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); [_unit, "blockSprint", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
}; };
}; };

View File

@ -1,7 +1,7 @@
#include "..\script_component.hpp" #include "..\script_component.hpp"
/* /*
* Author: BaerMitUmlaut, ulteq * Author: BaerMitUmlaut
* Handles switching units (once on init and afterwards via Zeus). Also handles CBA setting change for performance factor. * Handles switching units (once on init and afterwards via Zeus).
* *
* Arguments: * Arguments:
* 0: New Unit <OBJECT> * 0: New Unit <OBJECT>
@ -15,24 +15,20 @@
* *
* Public: No * Public: No
*/ */
params ["_newUnit", "_oldUnit"]; params ["_newUnit", "_oldUnit"];
TRACE_2("unit changed",_newUnit,_oldUnit); TRACE_2("unit changed",_newUnit,_oldUnit);
if (!isNull _oldUnit) then { if !(isNull _oldUnit) then {
TRACE_1("remove old",_oldUnit getVariable QGVAR(animHandler));
_oldUnit enableStamina true; _oldUnit enableStamina true;
_oldUnit removeEventHandler ["AnimChanged", _oldUnit getVariable [QGVAR(animHandler), -1]]; _oldUnit removeEventHandler ["AnimChanged", _oldUnit getVariable [QGVAR(animHandler), -1]];
_oldUnit setVariable [QGVAR(animHandler), nil]; _oldUnit setVariable [QGVAR(animHandler), nil];
TRACE_1("remove old",_oldUnit getVariable QGVAR(animHandler));
_oldUnit setVariable [QGVAR(ae1Reserve), GVAR(ae1Reserve)]; _oldUnit setVariable [QGVAR(ae1Reserve), GVAR(ae1Reserve)];
_oldUnit setVariable [QGVAR(ae2Reserve), GVAR(ae2Reserve)]; _oldUnit setVariable [QGVAR(ae2Reserve), GVAR(ae2Reserve)];
_oldUnit setVariable [QGVAR(anReserve), GVAR(anReserve)]; _oldUnit setVariable [QGVAR(anReserve), GVAR(anReserve)];
_oldUnit setVariable [QGVAR(anFatigue), GVAR(anFatigue)]; _oldUnit setVariable [QGVAR(anFatigue), GVAR(anFatigue)];
_oldUnit setVariable [QGVAR(muscleDamage), GVAR(muscleDamage)]; _oldUnit setVariable [QGVAR(muscleDamage), GVAR(muscleDamage)];
_oldUnit setVariable [QGVAR(respiratoryRate), GVAR(respiratoryRate)];
}; };
_newUnit enableStamina false; _newUnit enableStamina false;
@ -42,7 +38,6 @@ if (_newUnit getVariable [QGVAR(animHandler), -1] == -1) then {
private _animHandler = _newUnit addEventHandler ["AnimChanged", { private _animHandler = _newUnit addEventHandler ["AnimChanged", {
GVAR(animDuty) = _this call FUNC(getAnimDuty); GVAR(animDuty) = _this call FUNC(getAnimDuty);
}]; }];
TRACE_1("add new",_animHandler); TRACE_1("add new",_animHandler);
_newUnit setVariable [QGVAR(animHandler), _animHandler]; _newUnit setVariable [QGVAR(animHandler), _animHandler];
}; };
@ -52,27 +47,18 @@ GVAR(ae2Reserve) = _newUnit getVariable [QGVAR(ae2Reserve), AE2_MAXRESERVE]
GVAR(anReserve) = _newUnit getVariable [QGVAR(anReserve), AN_MAXRESERVE]; GVAR(anReserve) = _newUnit getVariable [QGVAR(anReserve), AN_MAXRESERVE];
GVAR(anFatigue) = _newUnit getVariable [QGVAR(anFatigue), 0]; GVAR(anFatigue) = _newUnit getVariable [QGVAR(anFatigue), 0];
GVAR(muscleDamage) = _newUnit getVariable [QGVAR(muscleDamage), 0]; GVAR(muscleDamage) = _newUnit getVariable [QGVAR(muscleDamage), 0];
GVAR(respiratoryRate) = _newUnit getVariable [QGVAR(respiratoryRate), 0];
// Clean variables for respawning units // Clean variables for respawning units
{ {
_newUnit setVariable [_x, nil]; _newUnit setVariable [_x, nil];
} forEach [QGVAR(ae1Reserve), QGVAR(ae2Reserve), QGVAR(anReserve), QGVAR(anFatigue), QGVAR(muscleDamage), QGVAR(respiratoryRate)]; } forEach [QGVAR(ae1Reserve), QGVAR(ae2Reserve), QGVAR(anReserve), QGVAR(anFatigue), QGVAR(muscleDamage)];
GVAR(VO2Max) = 35 + 20 * (_newUnit getVariable [QGVAR(performanceFactor), GVAR(performanceFactor)]); GVAR(VO2Max) = 35 + 20 * (_newUnit getVariable [QGVAR(performanceFactor), GVAR(performanceFactor)]);
GVAR(VO2MaxPower) = GVAR(VO2Max) * SIM_BODYMASS * BIOMECH_EFFICIENCY * JOULES_PER_ML_O2 / 60; GVAR(VO2MaxPower) = GVAR(VO2Max) * SIM_BODYMASS * 0.23 * JOULES_PER_ML_O2 / 60;
GVAR(peakPower) = VO2MAX_STRENGTH * GVAR(VO2MaxPower); GVAR(peakPower) = VO2MAX_STRENGTH * GVAR(VO2MaxPower);
GVAR(ae1PathwayPower) = GVAR(peakPower) / (AE1_ATP_RELEASE_RATE + AE2_ATP_RELEASE_RATE + AN_ATP_RELEASE_RATE) * AE1_ATP_RELEASE_RATE * ANTPERCENT ^ 1.28 * 1.362; GVAR(ae1PathwayPower) = GVAR(peakPower) / (13.3 + 16.7 + 113.3) * 13.3 * ANTPERCENT ^ 1.28 * 1.362;
GVAR(ae2PathwayPower) = GVAR(peakPower) / (AE1_ATP_RELEASE_RATE + AE2_ATP_RELEASE_RATE + AN_ATP_RELEASE_RATE) * AE2_ATP_RELEASE_RATE * ANTPERCENT ^ 1.28 * 1.362; GVAR(ae2PathwayPower) = GVAR(peakPower) / (13.3 + 16.7 + 113.3) * 16.7 * ANTPERCENT ^ 1.28 * 1.362;
GVAR(aePathwayPower) = GVAR(ae1PathwayPower) + GVAR(ae2PathwayPower);
GVAR(anPathwayPower) = GVAR(peakPower) - GVAR(aePathwayPower);
GVAR(aeWattsPerATP) = GVAR(ae1PathwayPower) / AE1_ATP_RELEASE_RATE;
GVAR(anWattsPerATP) = GVAR(anPathwayPower) / AN_ATP_RELEASE_RATE;
GVAR(respiratoryBufferDivisor) = (RESPIRATORY_BUFFER - 1) / RESPIRATORY_BUFFER;
GVAR(maxPowerFatigueRatio) = 0.057 / GVAR(peakPower);
GVAR(ppeBlackoutLast) = 100; GVAR(ppeBlackoutLast) = 100;
GVAR(lastBreath) = 0; GVAR(lastBreath) = 0;

View File

@ -1,6 +1,6 @@
#include "..\script_component.hpp" #include "..\script_component.hpp"
/* /*
* Author: BaerMitUmlaut, ulteq * Author: BaerMitUmlaut
* Main looping function that updates fatigue values. * Main looping function that updates fatigue values.
* *
* Arguments: * Arguments:
@ -17,131 +17,73 @@
// Dead people don't breathe, will also handle null (map intros) // Dead people don't breathe, will also handle null (map intros)
if (!alive ACE_player) exitWith { if (!alive ACE_player) exitWith {
[LINKFUNC(mainLoop), [], 1] call CBA_fnc_waitAndExecute; [FUNC(mainLoop), [], 1] call CBA_fnc_waitAndExecute;
private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull]; private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull];
_staminaBarContainer ctrlSetFade 1; _staminaBarContainer ctrlSetFade 1;
_staminaBarContainer ctrlCommit 1; _staminaBarContainer ctrlCommit 1;
}; };
private _velocity = velocity ACE_player;
private _normal = surfaceNormal (getPosWorld ACE_player); private _oxygen = 0.9; // Default AF oxygen saturation
private _movementVector = vectorNormalized _velocity; if (GVAR(medicalLoaded) && {EGVAR(medical_vitals,simulateSpo2)}) then {
private _sideVector = vectorNormalized (_movementVector vectorCrossProduct _normal); _oxygen = (ACE_player getVariable [QEGVAR(medical,spo2), 97]) / 100;
private _fwdAngle = asin (_movementVector select 2); };
private _sideAngle = asin (_sideVector select 2);
private _currentWork = REE; private _currentWork = REE;
private _currentSpeed = (vectorMagnitude _velocity) min 6; private _currentSpeed = (vectorMagnitude (velocity ACE_player)) min 6;
// fix #4481. Diving to the ground is recorded as PRONE stance with running speed velocity. Cap maximum speed to fix. // fix #4481. Diving to the ground is recorded as PRONE stance with running speed velocity. Cap maximum speed to fix.
if (GVAR(isProne)) then { if (GVAR(isProne)) then {
_currentSpeed = _currentSpeed min 1.5; _currentSpeed = _currentSpeed min 1.5;
}; };
// Get the current duty if ((vehicle ACE_player == ACE_player) && {_currentSpeed > 0.1} && {isTouchingGround ACE_player || {underwater ACE_player}}) then {
private _duty = GVAR(animDuty); _currentWork = [ACE_player, _currentSpeed] call FUNC(getMetabolicCosts);
{
if (_x isEqualType 0) then {
_duty = _duty * _x;
} else {
_duty = _duty * (ACE_player call _x);
};
} forEach (values GVAR(dutyList));
private _terrainGradient = abs _fwdAngle;
private _terrainFactor = 1;
private _gearMass = 0 max (((ACE_player getVariable [QEGVAR(movement,totalLoad), loadAbs ACE_player]) / 22.046 - UNDERWEAR_WEIGHT) * GVAR(loadFactor));
if (isNull objectParent ACE_player && {_currentSpeed > 0.1} && {isTouchingGround ACE_player || {underwater ACE_player}}) then {
if (!GVAR(isSwimming)) then {
// If the unit is going downhill, it's much less demanding
if (_fwdAngle < 0) then {
_terrainGradient = 0.15 * _terrainGradient;
};
// Used to simulate the unevenness/roughness of the terrain
if ((getPosATL ACE_player) select 2 < 0.01) then {
private _sideGradient = abs (_sideAngle / 45) min 1;
_terrainFactor = 1 + _sideGradient ^ 4;
};
};
_currentWork = [_duty, _gearMass, _terrainGradient * GVAR(terrainGradientFactor), _terrainFactor, _currentSpeed] call FUNC(getMetabolicCosts);
_currentWork = _currentWork max REE; _currentWork = _currentWork max REE;
}; };
// Oxygen calculation
private _oxygen = if (GETEGVAR(medical,enabled,false) && {EGVAR(medical_vitals,simulateSpo2)}) then { // Defer to medical
(ACE_player getVariable [QEGVAR(medical,spo2), 97]) / 100
} else {
1 - 0.131 * GVAR(respiratoryRate) ^ 2 // Default AF oxygen saturation
};
// Calculate muscle damage increase // Calculate muscle damage increase
GVAR(muscleDamage) = GVAR(muscleDamage) + (_currentWork / GVAR(peakPower)) ^ 3.2 * MUSCLE_TEAR_RATE; // Note: Muscle damage recovery is ignored as it takes multiple days
GVAR(muscleDamage) = (GVAR(muscleDamage) + (_currentWork / GVAR(peakPower)) ^ 3.2 * 0.00004) min 1;
// Calculate muscle damage recovery private _muscleIntegritySqrt = sqrt (1 - GVAR(muscleDamage));
GVAR(muscleDamage) = 0 max (GVAR(muscleDamage) - MUSCLE_RECOVERY * GVAR(recoveryFactor)) min 1;
private _muscleIntegrity = 1 - GVAR(muscleDamage);
private _muscleFactor = sqrt _muscleIntegrity;
// Calculate available power // Calculate available power
private _ae1PathwayPowerFatigued = GVAR(ae1PathwayPower) * sqrt (GVAR(ae1Reserve) / AE1_MAXRESERVE) * _oxygen * _muscleFactor; private _ae1PathwayPowerFatigued = GVAR(ae1PathwayPower) * sqrt (GVAR(ae1Reserve) / AE1_MAXRESERVE) * _oxygen * _muscleIntegritySqrt;
private _ae2PathwayPowerFatigued = GVAR(ae2PathwayPower) * sqrt (GVAR(ae2Reserve) / AE2_MAXRESERVE) * _oxygen * _muscleFactor; private _ae2PathwayPowerFatigued = GVAR(ae2PathwayPower) * sqrt (GVAR(ae2Reserve) / AE2_MAXRESERVE) * _oxygen * _muscleIntegritySqrt;
private _aePathwayPowerFatigued = _ae1PathwayPowerFatigued + _ae2PathwayPowerFatigued;
private _anPathwayPowerFatigued = GVAR(anPathwayPower) * sqrt (GVAR(anReserve) / AN_MAXRESERVE) * _oxygen * _muscleIntegrity;
// Calculate how much power is consumed from each reserve // Calculate how much power is consumed from each reserve
private _ae1Power = _currentWork min _ae1PathwayPowerFatigued; private _ae1Power = _currentWork min _ae1PathwayPowerFatigued;
private _ae2Power = (_currentWork - _ae1Power) min _ae2PathwayPowerFatigued; private _ae2Power = ((_currentWork - _ae1Power) max 0) min _ae2PathwayPowerFatigued;
private _anPower = 0 max (_currentWork - _ae1Power - _ae2Power); private _anPower = (_currentWork - _ae1Power - _ae2Power) max 0;
// Remove ATP from reserves for current work // Remove ATP from reserves for current work
GVAR(ae1Reserve) = 0 max (GVAR(ae1Reserve) - _ae1Power / GVAR(aeWattsPerATP)); GVAR(ae1Reserve) = GVAR(ae1Reserve) - _ae1Power / WATTSPERATP;
GVAR(ae2Reserve) = 0 max (GVAR(ae2Reserve) - _ae2Power / GVAR(aeWattsPerATP)); GVAR(ae2Reserve) = GVAR(ae2Reserve) - _ae2Power / WATTSPERATP;
GVAR(anReserve) = 0 max (GVAR(anReserve) - _anPower / GVAR(anWattsPerATP)); GVAR(anReserve) = GVAR(anReserve) - _anPower / WATTSPERATP;
// Increase anearobic fatigue
// Acidosis accumulation GVAR(anFatigue) = GVAR(anFatigue) + _anPower * (0.057 / GVAR(peakPower)) * 1.1;
GVAR(anFatigue) = GVAR(anFatigue) + _anPower * GVAR(maxPowerFatigueRatio) * 1.1;
// Aerobic ATP reserve recovery // Aerobic ATP reserve recovery
GVAR(ae1Reserve) = (GVAR(ae1Reserve) + _oxygen * GVAR(recoveryFactor) * AE1_ATP_RECOVERY * (GVAR(ae1PathwayPower) - _ae1Power) / GVAR(ae1PathwayPower)) min AE1_MAXRESERVE; GVAR(ae1Reserve) = ((GVAR(ae1Reserve) + _oxygen * 6.60 * (GVAR(ae1PathwayPower) - _ae1Power) / GVAR(ae1PathwayPower) * GVAR(recoveryFactor)) min AE1_MAXRESERVE) max 0;
GVAR(ae2Reserve) = (GVAR(ae2Reserve) + _oxygen * GVAR(recoveryFactor) * AE2_ATP_RECOVERY * (GVAR(ae2PathwayPower) - _ae2Power) / GVAR(ae2PathwayPower)) min AE2_MAXRESERVE; GVAR(ae2Reserve) = ((GVAR(ae2Reserve) + _oxygen * 5.83 * (GVAR(ae2PathwayPower) - _ae2Power) / GVAR(ae2PathwayPower) * GVAR(recoveryFactor)) min AE2_MAXRESERVE) max 0;
private _aeSurplus = _ae1PathwayPowerFatigued + _ae2PathwayPowerFatigued - _ae1Power - _ae2Power; // Anaerobic ATP reserver and fatigue recovery
GVAR(anReserve) = ((GVAR(anReserve)
+ (_ae1PathwayPowerFatigued + _ae2PathwayPowerFatigued - _ae1Power - _ae2Power) / GVAR(VO2MaxPower) * 56.7 * GVAR(anFatigue) ^ 2 * GVAR(recoveryFactor)
) min AN_MAXRESERVE) max 0;
// Anaerobic ATP reserve recovery GVAR(anFatigue) = ((GVAR(anFatigue)
GVAR(anReserve) = 0 max (GVAR(anReserve) + _aeSurplus / GVAR(VO2MaxPower) * AN_ATP_RECOVERY * GVAR(recoveryFactor) * (GVAR(anFatigue) max linearConversion [AN_MAXRESERVE, 0, GVAR(anReserve), 0, 0.75, true]) ^ 2) min AN_MAXRESERVE; // max linearConversion ensures that if GVAR(anFatigue) is very low, it will still regenerate reserves - (_ae1PathwayPowerFatigued + _ae2PathwayPowerFatigued - _ae1Power - _ae2Power) * (0.057 / GVAR(peakPower)) * GVAR(anFatigue) ^ 2 * GVAR(recoveryFactor)
// Acidosis recovery ) min 1) max 0;
GVAR(anFatigue) = 0 max (GVAR(anFatigue) - _aeSurplus * GVAR(maxPowerFatigueRatio) * GVAR(recoveryFactor) * GVAR(anFatigue) ^ 2) min 1;
// Respiratory rate decrease
GVAR(respiratoryRate) = GVAR(respiratoryRate) * GVAR(respiratoryBufferDivisor);
// Respiratory rate increase
private _aePowerRatio = (GVAR(aePathwayPower) / _aePathwayPowerFatigued) min 2;
private _respiratorySampleDivisor = 1 / (RESPIRATORY_BUFFER * 4.72 * GVAR(VO2Max));
GVAR(respiratoryRate) = (GVAR(respiratoryRate) + _currentWork * _respiratorySampleDivisor * _aePowerRatio) min 1;
// Calculate a pseudo-perceived fatigue, which is used for effects
GVAR(aeReservePercentage) = (GVAR(ae1Reserve) / AE1_MAXRESERVE + GVAR(ae2Reserve) / AE2_MAXRESERVE) / 2; GVAR(aeReservePercentage) = (GVAR(ae1Reserve) / AE1_MAXRESERVE + GVAR(ae2Reserve) / AE2_MAXRESERVE) / 2;
GVAR(anReservePercentage) = GVAR(anReserve) / AN_MAXRESERVE; GVAR(anReservePercentage) = GVAR(anReserve) / AN_MAXRESERVE;
private _perceivedFatigue = 1 - (GVAR(anReservePercentage) min GVAR(aeReservePercentage)); private _perceivedFatigue = 1 - (GVAR(anReservePercentage) min GVAR(aeReservePercentage));
#ifdef DEBUG_MODE_FULL [ACE_player, _perceivedFatigue, _currentSpeed, GVAR(anReserve) == 0] call FUNC(handleEffects);
systemChat format ["---- muscleDamage: %1 ----", GVAR(muscleDamage) toFixed 8];
systemChat format ["---- ae2: %1 - an: %2 ----", (GVAR(ae2Reserve) / AE2_MAXRESERVE) toFixed 2, (GVAR(anReserve) / AN_MAXRESERVE) toFixed 2];
systemChat format ["---- anFatigue: %1 - perceivedFatigue: %2 ----", GVAR(anFatigue) toFixed 2, _perceivedFatigue toFixed 2];
systemChat format ["---- velocity %1 - respiratoryRate: %2 ----", (vectorMagnitude _velocity) toFixed 2, GVAR(respiratoryRate) toFixed 2];
// systemChat format ["---- aePower: %1 ----", _aePathwayPowerFatigued toFixed 1];
#endif
[ACE_player, _perceivedFatigue, GVAR(anReserve) == 0, _fwdAngle, _sideAngle] call FUNC(handleEffects); if (GVAR(enableStaminaBar)) then {
if (GVAR(enableStaminaBarRealized)) then {
[GVAR(anReserve) / AN_MAXRESERVE] call FUNC(handleStaminaBar); [GVAR(anReserve) / AN_MAXRESERVE] call FUNC(handleStaminaBar);
}; };
[LINKFUNC(mainLoop), [], 1] call CBA_fnc_waitAndExecute; [FUNC(mainLoop), [], 1] call CBA_fnc_waitAndExecute;

View File

@ -1,40 +0,0 @@
#include "..\script_component.hpp"
/*
* Author: ulteq
* Draw lines for debugging.
*
* Arguments:
* None
*
* Return Value:
* None
*
* Example:
* call ace_advanced_fatigue_fnc_renderDebugLines
*
* Public: No
*/
addMissionEventHandler ["Draw3D", {
private _normal = surfaceNormal (getPosWorld ACE_player);
private _beg = (getPosWorld ACE_player) vectorAdd (_normal vectorMultiply 0.5);
private _end = _beg vectorAdd (_normal vectorMultiply 2);
drawLine3D [ASLToATL _beg, ASLToATL _end, [0, 1, 0, 1]];
private _side = vectorNormalized (_normal vectorCrossProduct [0, 0, 1]);
private _end = _beg vectorAdd (_side vectorMultiply 2);
drawLine3D [ASLToATL _beg, ASLToATL _end, [0, 0, 1, 1]];
private _up = vectorNormalized (_normal vectorCrossProduct _side);
private _end = _beg vectorAdd (_up vectorMultiply 2);
drawLine3D [ASLToATL _beg, ASLToATL _end, [1, 0, 0, 1]];
private _movementVector = vectorNormalized (velocity ACE_player);
private _end = _beg vectorAdd (_movementVector vectorMultiply 2);
drawLine3D [ASLToATL _beg, ASLToATL _end, [1, 1, 0, 1]];
private _sideVector = vectorNormalized (_movementVector vectorCrossProduct _normal);
_sideVector set [2, 0];
private _end = _beg vectorAdd (_sideVector vectorMultiply 2);
drawLine3D [ASLToATL _beg, ASLToATL _end, [0, 1, 1, 1]];
}];

View File

@ -1,25 +0,0 @@
#include "..\script_component.hpp"
/*
* Author: PabstMirror
* Updates the stamina bar state
*
* Arguments:
* None
*
* Return Value:
* None
*
* Example:
* [] call ace_advanced_fatigue_fnc_updateStaminaBar
*
* Public: No
*/
GVAR(enableStaminaBarRealized) = GVAR(enabled) && GVAR(enableStaminaBar) && {!(missionNamespace getVariable [QEGVAR(ui,hideHud), false])};
TRACE_1("updateStaminaBar",GVAR(enableStaminaBarRealized));
private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull];
if (isNull _staminaBarContainer) exitWith {};
_staminaBarContainer ctrlSetFade ([1, 0] select GVAR(enableStaminaBarRealized));
_staminaBarContainer ctrlCommit 0;

View File

@ -4,9 +4,12 @@
[LSTRING(Enabled), LSTRING(Enabled_Description)], [LSTRING(Enabled), LSTRING(Enabled_Description)],
LSTRING(DisplayName), LSTRING(DisplayName),
true, true,
1, true, {
{ if (!_this) then {
call FUNC(updateStaminaBar); private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull];
_staminaBarContainer ctrlSetFade 1;
_staminaBarContainer ctrlCommit 0;
};
[QGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged) [QGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged)
}, },
true // Needs mission restart true // Needs mission restart
@ -18,8 +21,13 @@
[LSTRING(EnableStaminaBar), LSTRING(EnableStaminaBar_Description)], [LSTRING(EnableStaminaBar), LSTRING(EnableStaminaBar_Description)],
LSTRING(DisplayName), LSTRING(DisplayName),
true, true,
1, true, {
{call FUNC(updateStaminaBar)} if (!_this) then {
private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull];
_staminaBarContainer ctrlSetFade 1;
_staminaBarContainer ctrlCommit 0;
};
}
] call CBA_fnc_addSetting; ] call CBA_fnc_addSetting;
[ [
@ -28,8 +36,7 @@
[LSTRING(FadeStaminaBar), LSTRING(FadeStaminaBar_Description)], [LSTRING(FadeStaminaBar), LSTRING(FadeStaminaBar_Description)],
LSTRING(DisplayName), LSTRING(DisplayName),
true, true,
0, false, {
{
if (!_this && GVAR(enabled) && GVAR(enableStaminaBar)) then { if (!_this && GVAR(enabled) && GVAR(enableStaminaBar)) then {
private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull]; private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull];
_staminaBarContainer ctrlSetFade 0; _staminaBarContainer ctrlSetFade 0;
@ -43,14 +50,8 @@
"SLIDER", "SLIDER",
[LSTRING(PerformanceFactor), LSTRING(PerformanceFactor_Description)], [LSTRING(PerformanceFactor), LSTRING(PerformanceFactor_Description)],
LSTRING(DisplayName), LSTRING(DisplayName),
[0, 10, 1, 2], [0, 5, 1, 1],
1, true
{
// Recalculate values if the setting is changed mid-mission
if (GVAR(enabled) && hasInterface && !isNull ACE_player) then {
[ACE_player, ACE_player] call FUNC(handlePlayerChanged);
};
}
] call CBA_fnc_addSetting; ] call CBA_fnc_addSetting;
[ [
@ -58,8 +59,8 @@
"SLIDER", "SLIDER",
[LSTRING(RecoveryFactor), LSTRING(RecoveryFactor_Description)], [LSTRING(RecoveryFactor), LSTRING(RecoveryFactor_Description)],
LSTRING(DisplayName), LSTRING(DisplayName),
[0, 10, 1, 2], [0, 5, 1, 1],
1 true
] call CBA_fnc_addSetting; ] call CBA_fnc_addSetting;
[ [
@ -67,8 +68,8 @@
"SLIDER", "SLIDER",
[LSTRING(LoadFactor), LSTRING(LoadFactor_Description)], [LSTRING(LoadFactor), LSTRING(LoadFactor_Description)],
LSTRING(DisplayName), LSTRING(DisplayName),
[0, 5, 1, 2], [0, 5, 1, 1],
1 true
] call CBA_fnc_addSetting; ] call CBA_fnc_addSetting;
[ [
@ -76,6 +77,6 @@
"SLIDER", "SLIDER",
[LSTRING(TerrainGradientFactor), LSTRING(TerrainGradientFactor_Description)], [LSTRING(TerrainGradientFactor), LSTRING(TerrainGradientFactor_Description)],
LSTRING(DisplayName), LSTRING(DisplayName),
[0, 5, 1, 2], [0, 5, 1, 1],
1 true
] call CBA_fnc_addSetting; ] call CBA_fnc_addSetting;

View File

@ -16,28 +16,14 @@
#include "\z\ace\addons\main\script_macros.hpp" #include "\z\ace\addons\main\script_macros.hpp"
#define UNDERWEAR_WEIGHT 3.5
#define ANTPERCENT 0.8 #define ANTPERCENT 0.8
#define SIM_BODYMASS 70 #define SIM_BODYMASS 70
#define JOULES_PER_ML_O2 20.9 #define JOULES_PER_ML_O2 20.9
#define VO2MAX_STRENGTH 4.1 #define VO2MAX_STRENGTH 4.1
#define BIOMECH_EFFICIENCY 0.23 #define REE 18.83 //((0.5617 * SIM_BODYMASS + 42.57) * 0.23)
#define REE 18.83 // ((0.5617 * SIM_BODYMASS + 42.57) * BIOMECH_EFFICIENCY) #define OXYGEN 0.9
#define WATTSPERATP 7
#define RESPIRATORY_BUFFER 60 #define AE1_MAXRESERVE 4000000
#define AE2_MAXRESERVE 84000
#define MUSCLE_TEAR_RATE 0.00004 #define AN_MAXRESERVE 2300
#define MUSCLE_RECOVERY 0.00000386
#define AE1_ATP_RELEASE_RATE 13.3 // mmol
#define AE2_ATP_RELEASE_RATE 16.7 // mmol
#define AN_ATP_RELEASE_RATE 113.3 // mmol
#define AE1_ATP_RECOVERY 6.60 // mmol
#define AE2_ATP_RECOVERY 5.83 // mmol
#define AN_ATP_RECOVERY 56.70 // mmol
#define AE1_MAXRESERVE 4000000 // mmol
#define AE2_MAXRESERVE 84000 // mmol
#define AN_MAXRESERVE 2300 // mmol

View File

@ -7,7 +7,7 @@
<German>ACE Erweiterte Ausdauer</German> <German>ACE Erweiterte Ausdauer</German>
<Chinese>ACE 進階疲勞</Chinese> <Chinese>ACE 進階疲勞</Chinese>
<Chinesesimp>ACE 进阶体力</Chinesesimp> <Chinesesimp>ACE 进阶体力</Chinesesimp>
<Japanese>ACE 高度な疲労</Japanese> <Japanese>ACE アドバンスド疲労</Japanese>
<Italian>ACE Fatica Avanzata</Italian> <Italian>ACE Fatica Avanzata</Italian>
<Korean>ACE 고급 피로도</Korean> <Korean>ACE 고급 피로도</Korean>
<French>ACE Fatigue avancée</French> <French>ACE Fatigue avancée</French>
@ -173,7 +173,7 @@
<English>Enables/disables Advanced Fatigue.</English> <English>Enables/disables Advanced Fatigue.</English>
<Spanish>Activa/desactiva la fatiga avanzada</Spanish> <Spanish>Activa/desactiva la fatiga avanzada</Spanish>
<German>Aktiviert/deaktiviert Advanced Fatigue.</German> <German>Aktiviert/deaktiviert Advanced Fatigue.</German>
<Japanese>高度な疲労を有効/無効化します。</Japanese> <Japanese>アドバンスド疲労は高度な疲労管理システムを有効化します。</Japanese>
<Polish>Włącza/wyłącza zaawansowaną wytrzymałość</Polish> <Polish>Włącza/wyłącza zaawansowaną wytrzymałość</Polish>
<Korean>고급 피로도 활성화/비활성화</Korean> <Korean>고급 피로도 활성화/비활성화</Korean>
<French>Active/Désactive la fatigue avancée.</French> <French>Active/Désactive la fatigue avancée.</French>

View File

@ -10,10 +10,21 @@ if (!hasInterface) exitWith {};
// Temporary Wind Info indication // Temporary Wind Info indication
GVAR(tempWindInfo) = false; GVAR(tempWindInfo) = false;
// Ammo/Magazines look-up hash for correctness of initSpeed
GVAR(ammoMagLookup) = call CBA_fnc_createNamespace;
{
{
private _ammo = getText (configFile >> "CfgMagazines" >> _x >> "ammo");
if (_ammo != "") then { GVAR(ammoMagLookup) setVariable [_ammo, _x]; };
} count (getArray (configFile >> "CfgWeapons" >> "Throw" >> _x >> "magazines"));
nil
} count getArray (configFile >> "CfgWeapons" >> "Throw" >> "muzzles");
// Add keybinds // Add keybinds
["ACE3 Weapons", QGVAR(prepare), localize LSTRING(Prepare), { ["ACE3 Weapons", QGVAR(prepare), localize LSTRING(Prepare), {
// Condition // Condition
if !([ACE_player] call FUNC(canPrepare)) exitWith {false}; if (!([ACE_player] call FUNC(canPrepare))) exitWith {false};
if (EGVAR(common,isReloading)) exitWith {true}; if (EGVAR(common,isReloading)) exitWith {true};
// Statement // Statement

View File

@ -1,21 +1,3 @@
#include "script_component.hpp" #include "script_component.hpp"
#include "XEH_PREP.hpp" #include "XEH_PREP.hpp"
// Ammo/Magazines look-up hash for correctness of initSpeed
private _cfgMagazines = configFile >> "CfgMagazines";
private _cfgAmmo = configFile >> "CfgAmmo";
private _cfgThrow = configFile >> "CfgWeapons" >> "Throw";
private _ammoMagLookup = createHashMap;
{
{
private _ammo = getText (_cfgMagazines >> _x >> "ammo");
if (_ammo != "") then {
_ammoMagLookup set [configName (_cfgAmmo >> _ammo), _x];
};
} forEach (getArray (_cfgThrow >> _x >> "magazines"));
} forEach (getArray (_cfgThrow >> "muzzles"));
uiNamespace setVariable [QGVAR(ammoMagLookup), compileFinal _ammoMagLookup];

View File

@ -43,10 +43,13 @@ if ((!_primed) && {!((_throwableMag in (uniformItems ACE_player)) || {_throwable
// Get correct throw power for primed grenade // Get correct throw power for primed grenade
if (_primed) then { if (_primed) then {
// If ammo type is not found: private _ammoType = typeOf _activeThrowable;
_throwableMag = GVAR(ammoMagLookup) getVariable _ammoType;
if (isNil "_throwableMag") then {
// What we're trying to throw must not be a normal throwable because it is not in our lookup hash (e.g. 40mm smoke) // What we're trying to throw must not be a normal throwable because it is not in our lookup hash (e.g. 40mm smoke)
// Just use HandGrenade as it has an average initSpeed value // Just use HandGrenade as it has an average initSpeed value
_throwableMag = (uiNamespace getVariable QGVAR(ammoMagLookup)) getOrDefault [typeOf _activeThrowable, "HandGrenade"]; _throwableMag = "HandGrenade";
};
}; };
// Some throwables have different classname for magazine and ammo // Some throwables have different classname for magazine and ammo

View File

@ -18,10 +18,19 @@
params ["_unit"]; params ["_unit"];
TRACE_1("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 // Select next throwable if one already in hand
if (_unit getVariable [QGVAR(inHand), false]) exitWith { if (_unit getVariable [QGVAR(inHand), false]) exitWith {
TRACE_1("inHand",_unit); TRACE_1("inHand",_unit);
if !(_unit getVariable [QGVAR(primed), false]) then { if (!(_unit getVariable [QGVAR(primed), false])) then {
TRACE_1("not primed",_unit); TRACE_1("not primed",_unit);
// Restore muzzle ammo (setAmmo 1 has no impact if no appliccable throwable in inventory) // Restore muzzle ammo (setAmmo 1 has no impact if no appliccable throwable in inventory)
// selectNextGrenade relies on muzzles array (setAmmo 0 removes the muzzle from the array and current can't be found, cycles between 0 and 1 muzzles) // selectNextGrenade relies on muzzles array (setAmmo 0 removes the muzzle from the array and current can't be found, cycles between 0 and 1 muzzles)
@ -35,11 +44,6 @@ if (isNull (_unit getVariable [QGVAR(activeThrowable), objNull]) && {(currentThr
TRACE_1("no throwables",_unit); TRACE_1("no throwables",_unit);
}; };
// Temporarily enable wind info, to aid in throwing smoke grenades effectively
if (GVAR(enableTempWindInfo) && {!(missionNamespace getVariable [QEGVAR(weather,WindInfo), false])}) then {
[] call EFUNC(weather,displayWindInfo);
GVAR(tempWindInfo) = true;
};
_unit setVariable [QGVAR(inHand), true]; _unit setVariable [QGVAR(inHand), true];

View File

@ -44,7 +44,8 @@
_addedPickUpHelpers pushBack _pickUpHelper; _addedPickUpHelpers pushBack _pickUpHelper;
_throwablesHelped pushBack _x; _throwablesHelped pushBack _x;
}; };
} forEach _nearThrowables; nil
} count _nearThrowables;
_args set [0, getPosASL ACE_player]; _args set [0, getPosASL ACE_player];
_args set [3, _nearThrowables]; _args set [3, _nearThrowables];
@ -55,10 +56,11 @@
{ {
// Only handling with attachTo works nicely // Only handling with attachTo works nicely
_x attachTo [_x getVariable [QGVAR(throwable), objNull], [0, 0, 0]]; _x attachTo [_x getVariable [QGVAR(throwable), objNull], [0, 0, 0]];
} forEach _addedPickUpHelpers; nil
} count _addedPickUpHelpers;
} else { } else {
TRACE_1("Cleaning Pick Up Helpers",count _addedPickUpHelpers); TRACE_1("Cleaning Pick Up Helpers",count _addedPickUpHelpers);
{deleteVehicle _x} forEach _addedPickUpHelpers; {deleteVehicle _x} count _addedPickUpHelpers;
[_idPFH] call CBA_fnc_removePerFrameHandler; [_idPFH] call CBA_fnc_removePerFrameHandler;
}; };
}, 0, [(getPosASL ACE_player) vectorAdd [-100, 0, 0], [], [], []]] call CBA_fnc_addPerFrameHandler; }, 0, [(getPosASL ACE_player) vectorAdd [-100, 0, 0], [], [], []]] call CBA_fnc_addPerFrameHandler;

View File

@ -20,7 +20,7 @@ TRACE_1("params",_unit);
// Prime the throwable if it hasn't been cooking already // Prime the throwable if it hasn't been cooking already
// Next to proper simulation this also has to happen before delay for orientation of the throwable to be set // Next to proper simulation this also has to happen before delay for orientation of the throwable to be set
if !(_unit getVariable [QGVAR(primed), false]) then { if (!(_unit getVariable [QGVAR(primed), false])) then {
[_unit] call FUNC(prime); [_unit] call FUNC(prime);
}; };

View File

@ -5,7 +5,7 @@
<English>Advanced Throwing</English> <English>Advanced Throwing</English>
<Spanish>Lanzamiento Avanzado</Spanish> <Spanish>Lanzamiento Avanzado</Spanish>
<Russian>Улучшенный бросок гранат</Russian> <Russian>Улучшенный бросок гранат</Russian>
<Japanese>高度な投擲</Japanese> <Japanese>アドバンスド投擲</Japanese>
<Polish>Zaawansowane rzucanie</Polish> <Polish>Zaawansowane rzucanie</Polish>
<German>Erweitertes Wurfsystem</German> <German>Erweitertes Wurfsystem</German>
<Korean>고급 투척</Korean> <Korean>고급 투척</Korean>
@ -21,7 +21,7 @@
<English>Allows changing advanced throwing behaviour.</English> <English>Allows changing advanced throwing behaviour.</English>
<Spanish>Permite modificar el comportamiento del lanzamiento avanzado</Spanish> <Spanish>Permite modificar el comportamiento del lanzamiento avanzado</Spanish>
<Russian>Позволяет настраивать поведение улучшенного броска гранат.</Russian> <Russian>Позволяет настраивать поведение улучшенного броска гранат.</Russian>
<Japanese>高度な投擲挙動への変更を可能にします。</Japanese> <Japanese>アドバンスド投擲は投擲の高度な動作挙動を変更可能にします。</Japanese>
<Polish>Zezwala na zmianę zachowania zaawansowanego trybu rzucania.</Polish> <Polish>Zezwala na zmianę zachowania zaawansowanego trybu rzucania.</Polish>
<German>Erlaubt es, das Verhalten des erweiterten Wurfsystems zu ändern.</German> <German>Erlaubt es, das Verhalten des erweiterten Wurfsystems zu ändern.</German>
<Korean>고급 투척 행위를 허가합니다</Korean> <Korean>고급 투척 행위를 허가합니다</Korean>
@ -36,7 +36,7 @@
<English>Enable Advanced Throwing</English> <English>Enable Advanced Throwing</English>
<Spanish>Activar Lanzamiento Avanzado</Spanish> <Spanish>Activar Lanzamiento Avanzado</Spanish>
<Russian>Вкл. улучшенный бросок</Russian> <Russian>Вкл. улучшенный бросок</Russian>
<Japanese>高度な投擲を有効化</Japanese> <Japanese>アドバンスド投擲を有効化</Japanese>
<Polish>Aktywuj zaawansowane rzucanie</Polish> <Polish>Aktywuj zaawansowane rzucanie</Polish>
<German>Aktiviere erweitertes Wurfsystem</German> <German>Aktiviere erweitertes Wurfsystem</German>
<Korean>고급 투척 활성화 </Korean> <Korean>고급 투척 활성화 </Korean>
@ -52,7 +52,7 @@
<English>Enables advanced throwing system.</English> <English>Enables advanced throwing system.</English>
<Spanish>Activa el Lanzamiento Avanzado</Spanish> <Spanish>Activa el Lanzamiento Avanzado</Spanish>
<Russian>Включает систему улучшенного броска.</Russian> <Russian>Включает систему улучшенного броска.</Russian>
<Japanese>高度な投擲システムを有効化します。</Japanese> <Japanese>アドバンスド投擲は高度な投擲システムを有効化します。</Japanese>
<Polish>Aktywuje system zaawansowanego rzucania.</Polish> <Polish>Aktywuje system zaawansowanego rzucania.</Polish>
<German>Aktiviert das erweiterte Wurfsystem.</German> <German>Aktiviert das erweiterte Wurfsystem.</German>
<Korean>고급 투척을 활성화 합니다</Korean> <Korean>고급 투척을 활성화 합니다</Korean>
@ -144,7 +144,7 @@
<English>Enables ability to pick up throwables from the ground.</English> <English>Enables ability to pick up throwables from the ground.</English>
<Spanish>Activa la habilidad de coger objetos lanzados del suelo</Spanish> <Spanish>Activa la habilidad de coger objetos lanzados del suelo</Spanish>
<Russian>Включает возможность подбирать гранаты с земли.</Russian> <Russian>Включает возможность подбирать гранаты с земли.</Russian>
<Japanese>地面に落ちている投擲物を拾機能を有効化します。</Japanese> <Japanese>地面に落ちている投擲物を拾い上げる機能を有効化します。</Japanese>
<Polish>Umożliwia podnoszenie obiektów miotanych z ziemi.</Polish> <Polish>Umożliwia podnoszenie obiektów miotanych z ziemi.</Polish>
<German>Aktiviert die Möglichkeit, geworfene Objekte wieder vom Boden aufzuheben.</German> <German>Aktiviert die Möglichkeit, geworfene Objekte wieder vom Boden aufzuheben.</German>
<Korean>땅에 떨어진 투척물을 주울 수 있게 해줍니다.</Korean> <Korean>땅에 떨어진 투척물을 주울 수 있게 해줍니다.</Korean>
@ -174,7 +174,7 @@
<English>Enables ability to pick up throwables from attached objects.</English> <English>Enables ability to pick up throwables from attached objects.</English>
<Spanish>Activa la habilidad de lanzar objetos enganchados</Spanish> <Spanish>Activa la habilidad de lanzar objetos enganchados</Spanish>
<Russian>Включает возможность подбирать гранаты, прикрепленные к объектам.</Russian> <Russian>Включает возможность подбирать гранаты, прикрепленные к объектам.</Russian>
<Japanese>オブジェクトに装着された投擲物を拾う機能を有効化します。</Japanese> <Japanese>オブジェクトに装着された投擲可能物を拾い上げる機能を有効化します。</Japanese>
<Polish>Umożliwia podnoszenie obiektów miotanych przyczepionych do innych obiektów.</Polish> <Polish>Umożliwia podnoszenie obiektów miotanych przyczepionych do innych obiektów.</Polish>
<German>Aktiviert die Möglichkeit, befestigte Wurfobjekte erneut aufzunehmen.</German> <German>Aktiviert die Möglichkeit, befestigte Wurfobjekte erneut aufzunehmen.</German>
<Korean>부착된 투척물을 주울 수 있게 해줍니다.</Korean> <Korean>부착된 투척물을 주울 수 있게 해줍니다.</Korean>
@ -191,9 +191,6 @@
<Italian>Mostra informazioni sul vento temporaneamente</Italian> <Italian>Mostra informazioni sul vento temporaneamente</Italian>
<Japanese>一時的に風の情報を表示</Japanese> <Japanese>一時的に風の情報を表示</Japanese>
<Korean>바람 정보 임시로 표시</Korean> <Korean>바람 정보 임시로 표시</Korean>
<French>Afficher temporairement les informations sur le vent</French>
<Russian>Временно показать информацию о ветре</Russian>
<Spanish>Mostrar información del viento temporalmente</Spanish>
</Key> </Key>
<Key ID="STR_ACE_Advanced_Throwing_EnableTempWindInfo_Description"> <Key ID="STR_ACE_Advanced_Throwing_EnableTempWindInfo_Description">
<English>Temporarily display Wind Info while throwing, to aid in placing smoke grenades effectively.</English> <English>Temporarily display Wind Info while throwing, to aid in placing smoke grenades effectively.</English>
@ -201,9 +198,6 @@
<Italian>Mostra le informazioni sul vento durante il lancio di granate, facilitando il piazzamento ottimale di fumogeni.</Italian> <Italian>Mostra le informazioni sul vento durante il lancio di granate, facilitando il piazzamento ottimale di fumogeni.</Italian>
<Japanese>投擲行動中に風向きの情報を一時的に表示し、発煙手榴弾の煙幕を効果的に展開しやすくします。</Japanese> <Japanese>投擲行動中に風向きの情報を一時的に表示し、発煙手榴弾の煙幕を効果的に展開しやすくします。</Japanese>
<Korean>연막탄을 효과적으로 배치하는 데 도움이 되도록 투척하는 동안 일시적으로 바람 정보를 표시합니다.</Korean> <Korean>연막탄을 효과적으로 배치하는 데 도움이 되도록 투척하는 동안 일시적으로 바람 정보를 표시합니다.</Korean>
<French>Affiche les informations sur le vent pendant le lancement pour placer les grenades fumigènes plus efficacement.</French>
<Russian>Временно отображайте информацию о ветре во время броска, чтобы помочь эффективно разместить дымовые шашки.</Russian>
<Spanish>Mostrar información del viento temporalmente mientras se lanza, para ayudar a lanzar las granadas de humo de forma efectiva.</Spanish>
</Key> </Key>
<Key ID="STR_ACE_Advanced_Throwing_Prepare"> <Key ID="STR_ACE_Advanced_Throwing_Prepare">
<English>Prepare/Change Throwable</English> <English>Prepare/Change Throwable</English>
@ -254,7 +248,7 @@
<English>Primed</English> <English>Primed</English>
<Spanish>Preparado</Spanish> <Spanish>Preparado</Spanish>
<Russian>Подготовлена</Russian> <Russian>Подготовлена</Russian>
<Japanese>点火した</Japanese> <Japanese>点火</Japanese>
<Polish>Odbezpieczony</Polish> <Polish>Odbezpieczony</Polish>
<German>Scharf gemacht</German> <German>Scharf gemacht</German>
<Korean>뇌관 작동</Korean> <Korean>뇌관 작동</Korean>

View File

@ -33,7 +33,7 @@ if (_startingPos isEqualTo [0,0,0]) exitWith {
[LSTRING(GarrisonInvalidPosition)] call EFUNC(common,displayTextStructured); [LSTRING(GarrisonInvalidPosition)] call EFUNC(common,displayTextStructured);
}; };
if (_unitsArray isEqualTo [] || {isNull (_unitsArray select 0)}) exitWith { if (count _unitsArray == 0 || {isNull (_unitsArray select 0)}) exitWith {
TRACE_1("fnc_garrison: Units error",_unitsArray); TRACE_1("fnc_garrison: Units error",_unitsArray);
[LSTRING(GarrisonNoUnits)] call EFUNC(common,displayTextStructured); [LSTRING(GarrisonNoUnits)] call EFUNC(common,displayTextStructured);
}; };
@ -43,7 +43,7 @@ if (_fillingRadius >= 50) then {
_buildings = [_buildings] call CBA_fnc_shuffle; _buildings = [_buildings] call CBA_fnc_shuffle;
}; };
if (_buildings isEqualTo []) exitWith { if (count _buildings == 0) exitWith {
TRACE_1("fnc_garrison: Building error",_buildings); TRACE_1("fnc_garrison: Building error",_buildings);
[LSTRING(GarrisonNoBuilding)] call EFUNC(common,displayTextStructured); [LSTRING(GarrisonNoBuilding)] call EFUNC(common,displayTextStructured);
}; };

View File

@ -91,7 +91,6 @@
<Portuguese>Equipar NVGs automaticamente</Portuguese> <Portuguese>Equipar NVGs automaticamente</Portuguese>
<Japanese>暗視装置の自動装備</Japanese> <Japanese>暗視装置の自動装備</Japanese>
<Russian>Автоматическое оснащение ПНВ</Russian> <Russian>Автоматическое оснащение ПНВ</Russian>
<Spanish>Auto equipar gafas de visión nocturna</Spanish>
</Key> </Key>
<Key ID="STR_ACE_AI_AssignNVG_Description"> <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> <English>Equips NVG in inventory during night time and unequips it during day time.\nDoes not add NVGs to inventory!</English>
@ -103,7 +102,6 @@
<Portuguese>Equipa o NVG do inventário durante a noite e desequipa durante o dia.\nNão adiciona NVGs ao inventário!</Portuguese> <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> <Japanese>インベントリ内の暗視装置を夜間に装備し、日中は解除し収納します。\nこれはNVGをインベントリに追加しません。</Japanese>
<Russian>Экипирует ПНВ в ночное время и отключает его в дневное время.\nНе добавляет ПНВ в инвентарь!</Russian> <Russian>Экипирует ПНВ в ночное время и отключает его в дневное время.\nНе добавляет ПНВ в инвентарь!</Russian>
<Spanish>Equipa las gafas de visión nocturna en el inventario cuando es de noche, y las desequipa cuando es de día.\nNo añade las gafas al inventario!</Spanish>
</Key> </Key>
</Package> </Package>
</Project> </Project>

View File

@ -30,6 +30,6 @@ _vehicle == vehicle _unit
if (_unit == _x select FULLCREW_UNIT) exitWith { if (_unit == _x select FULLCREW_UNIT) exitWith {
_ejectVarName = format [QGVAR(ejectAction_%1_%2), _x select FULLCREW_ROLE, _x select FULLCREW_TURRETPATH]; _ejectVarName = format [QGVAR(ejectAction_%1_%2), _x select FULLCREW_ROLE, _x select FULLCREW_TURRETPATH];
}; };
} forEach fullCrew _vehicle; } count fullCrew _vehicle;
_vehicle getVariable [_ejectVarName, false] _vehicle getVariable [_ejectVarName, false]
} }

View File

@ -22,7 +22,7 @@ if (!alive _vehicle) exitWith {};
if (_vehicle getVariable [QGVAR(droneActionsAdded), false]) exitWith {}; if (_vehicle getVariable [QGVAR(droneActionsAdded), false]) exitWith {};
_vehicle setVariable [QGVAR(droneActionsAdded), true]; _vehicle setVariable [QGVAR(droneActionsAdded), true];
// Move to location // move to location
private _condition = { private _condition = {
params ["_vehicle"]; params ["_vehicle"];
(missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]} (missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]}
@ -37,58 +37,9 @@ private _action = [QGVAR(droneSetWaypointMove), localize "$STR_AC_MOVE",
"\a3\3DEN\Data\CfgWaypoints\Move_ca.paa", _statement, _condition] call EFUNC(interact_menu,createAction); "\a3\3DEN\Data\CfgWaypoints\Move_ca.paa", _statement, _condition] call EFUNC(interact_menu,createAction);
[_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject); [_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject);
// Follow unit/vehicle at turret location
_condition = {
params ["_vehicle"];
private _target = cursorTarget;
(missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]} && {!isNull _target} && {["CAManBase", "LandVehicle", "Ship"] findIf {_target isKindOf _x} != -1}
};
_statement = {
params ["_vehicle"];
private _group = group driver _vehicle;
private _pos = ([_vehicle, [0]] call FUNC(droneGetTurretTargetPos)) select 0;
[QGVAR(droneSetWaypoint), [_vehicle, _group, _pos, "FOLLOW", cursorTarget], _group] call CBA_fnc_targetEvent;
private _followDistance = _vehicle getVariable [QGVAR(wpFollowDistance), 0];
[[LLSTRING(DroneFollowHint), _followDistance], 3] call EFUNC(common,displayTextStructured);
};
_action = [QGVAR(droneSetWaypointFollow), localize "$STR_AC_FOLLOW", "\a3\3DEN\Data\CfgWaypoints\Follow_ca.paa", _statement, _condition] call EFUNC(interact_menu,createAction);
[_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject);
// Set drone follow distance
_condition = {
params ["_vehicle"];
private _group = group driver _vehicle;
private _index = (currentWaypoint _group) min count waypoints _group;
private _waypoint = [_group, _index];
(missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]} && {(waypointType _waypoint) == "HOLD"}
};
_statement = {
params ["_vehicle", "", "_value"];
_vehicle setVariable [QGVAR(wpFollowDistance), _value];
[[LLSTRING(DroneFollowHint), _value], 3] call EFUNC(common,displayTextStructured);
};
_action = [QGVAR(droneSetFollowDistance), LLSTRING(DroneFollowDistance), "", {}, _condition] call EFUNC(interact_menu,createAction);
private _base = [_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject);
private _followDistances = if (_vehicle isKindOf "Car_F") then {
[0, 25, 50, 100, 200]
} else {
[0, 100, 200, 300, 400, 500]
};
{
_action = [
QGVAR(droneSetFollowDistance_) + str _x,
str _x,
"",
_statement,
{true},
{},
_x
] call EFUNC(interact_menu,createAction);
[_vehicle, 1, _base, _action] call EFUNC(interact_menu,addActionToObject);
} forEach _followDistances;
if (_vehicle isKindOf "Air") then { if (_vehicle isKindOf "Air") then {
// Loiter at location // loiter at location
_condition = { _condition = {
params ["_vehicle"]; params ["_vehicle"];
(missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]} (missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]}
@ -104,7 +55,7 @@ if (_vehicle isKindOf "Air") then {
[_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject); [_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject);
// Set height // set height
_condition = { _condition = {
params ["_vehicle"]; params ["_vehicle"];
(missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]} (missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]}
@ -123,7 +74,7 @@ if (_vehicle isKindOf "Air") then {
} forEach [20, 50, 200, 500, 2000]; } forEach [20, 50, 200, 500, 2000];
// Set loiter radius // set loiter radius
_condition = { _condition = {
params ["_vehicle"]; params ["_vehicle"];
private _group = group driver _vehicle; private _group = group driver _vehicle;
@ -146,7 +97,7 @@ if (_vehicle isKindOf "Air") then {
} forEach [500, 750, 1000, 1250, 1500]; } forEach [500, 750, 1000, 1250, 1500];
// Set loiter direction // set loiter direction
_condition = { _condition = {
params ["_vehicle", "", "_args"]; params ["_vehicle", "", "_args"];
private _group = group driver _vehicle; private _group = group driver _vehicle;

View File

@ -8,7 +8,6 @@
* 1: Group <GROUP> * 1: Group <GROUP>
* 2: Pos 2D <ARRAY> * 2: Pos 2D <ARRAY>
* 3: Type <STRING> * 3: Type <STRING>
* 4: Target to follow <OBJECT> (default: objNull)
* *
* Return Value: * Return Value:
* None * None
@ -19,7 +18,7 @@
* Public: No * Public: No
*/ */
params ["_vehicle", "_group", "_pos", "_type", ["_target", objNull]]; params ["_vehicle", "_group", "_pos", "_type"];
TRACE_4("droneSetWaypoint",_vehicle,_group,_pos,_type); TRACE_4("droneSetWaypoint",_vehicle,_group,_pos,_type);
private _index = (currentWaypoint _group) min count waypoints _group; private _index = (currentWaypoint _group) min count waypoints _group;
@ -35,34 +34,9 @@ _pos set [
[0, _currentHeight] select (_currentHeight >= 50) [0, _currentHeight] select (_currentHeight >= 50)
]; ];
// [_group] call CBA_fnc_clearWaypoints;
_waypoint = _group addWaypoint [_pos, 0]; _waypoint = _group addWaypoint [_pos, 0];
// The Vanilla "FOLLOW"-type waypoint is not used directly, due to 2 main issues (as of v2.16): _waypoint setWaypointType _type;
// - It does not work at all for UGVs, which is a known issue https://feedback.bistudio.com/T126283;
// - No clear scripting way was found to mimic the UAV Terminal's "Follow Distance" functionality;
// Instead, the solution for both UAV and UGV following consists of a CBA PFH that moves a "HOLD"-type Waypoint every 3 seconds.
// Either on the target itself, or on the Drone's current position if the target is within the desired follow distance.
if (_type == "FOLLOW" && {["CAManBase", "LandVehicle", "Ship"] findIf {_target isKindOf _x} != -1}) then {
_waypoint setWaypointType "HOLD";
[{
params ["_args", "_handle"];
_args params ["_vehicle", "_group", "_waypoint", "_target"];
if ( // Abort PFH if a new waypoint is created via UAV Terminal or ACE Interaction
_waypoint select 1 != currentWaypoint _group ||
{!alive _vehicle} || {isNull _target}
) exitWith {
deleteWaypoint _waypoint;
[_handle] call CBA_fnc_removePerFrameHandler;
};
private _followDistance = _vehicle getVariable [QGVAR(wpFollowDistance), 0];
if ((_vehicle distance2D _target) < _followDistance) then {
_waypoint setWaypointPosition [getPosASL _vehicle, -1];
} else {
_waypoint setWaypointPosition [getPosASL _target, -1];
};
}, 3, [_vehicle, _group, _waypoint, _target]] call CBA_fnc_addPerFrameHandler;
};
TRACE_3("",_currentHeight,_currentLoiterRadius,_currentLoiterType); TRACE_3("",_currentHeight,_currentLoiterRadius,_currentLoiterType);
if (_currentHeight > 1) then { _vehicle flyInHeight _currentHeight; }; if (_currentHeight > 1) then { _vehicle flyInHeight _currentHeight; };

View File

@ -129,7 +129,7 @@
<Japanese>30mm コンバット ミックス 4:1 劣化ウラン徹甲弾:焼夷榴弾</Japanese> <Japanese>30mm コンバット ミックス 4:1 劣化ウラン徹甲弾:焼夷榴弾</Japanese>
<Czech>30mm Bojový Mix 4:1 DU:HEI</Czech> <Czech>30mm Bojový Mix 4:1 DU:HEI</Czech>
<Russian>30мм Смешанное боепитание 4:1 ОУ:ОФЗ</Russian> <Russian>30мм Смешанное боепитание 4:1 ОУ:ОФЗ</Russian>
<Korean>30mm 열화우라늄:고폭소이 4:1 혼합</Korean> <Korean>30mm 4:1 열화:고폭소이</Korean>
<Portuguese>30mm Mix de Combate 4:1 DU:AEI</Portuguese> <Portuguese>30mm Mix de Combate 4:1 DU:AEI</Portuguese>
</Key> </Key>
<Key ID="STR_ACE_Aircraft_GatlingDescriptionShortCM41"> <Key ID="STR_ACE_Aircraft_GatlingDescriptionShortCM41">
@ -145,7 +145,7 @@
<Japanese>30mm CM 4:1</Japanese> <Japanese>30mm CM 4:1</Japanese>
<Czech>30mm BM 4:1</Czech> <Czech>30mm BM 4:1</Czech>
<Russian>30мм СБ 4:1</Russian> <Russian>30мм СБ 4:1</Russian>
<Korean>30mm 4:1 혼합</Korean> <Korean>30mm CM 4:1</Korean>
</Key> </Key>
<Key ID="STR_ACE_Aircraft_GatlingDescriptionCM51"> <Key ID="STR_ACE_Aircraft_GatlingDescriptionCM51">
<English>30mm Combat Mix 5:1 DU:HEI</English> <English>30mm Combat Mix 5:1 DU:HEI</English>
@ -160,7 +160,7 @@
<Japanese>30mm コンバット ミックス 5:1 劣化ウラン徹甲弾:焼夷榴弾</Japanese> <Japanese>30mm コンバット ミックス 5:1 劣化ウラン徹甲弾:焼夷榴弾</Japanese>
<Czech>30mm Bojový Mix 5:1 DU:HEI</Czech> <Czech>30mm Bojový Mix 5:1 DU:HEI</Czech>
<Russian>30мм Смешанное боепитание 5:1 ОУ:ОФЗ</Russian> <Russian>30мм Смешанное боепитание 5:1 ОУ:ОФЗ</Russian>
<Korean>30mm 열화우라늄:고폭소이 5:1 혼합</Korean> <Korean>30mm 5:1 열화:고폭소이</Korean>
</Key> </Key>
<Key ID="STR_ACE_Aircraft_GatlingDescriptionShortCM51"> <Key ID="STR_ACE_Aircraft_GatlingDescriptionShortCM51">
<English>30mm CM 5:1</English> <English>30mm CM 5:1</English>
@ -175,23 +175,7 @@
<Japanese>30mm CM 5:1</Japanese> <Japanese>30mm CM 5:1</Japanese>
<Czech>30mm BM 5:1</Czech> <Czech>30mm BM 5:1</Czech>
<Russian>30мм СБ 5:1</Russian> <Russian>30мм СБ 5:1</Russian>
<Korean>30mm 5:1 혼합</Korean> <Korean>30mm CM 5:1</Korean>
</Key>
<Key ID="STR_ACE_Aircraft_DroneFollowDistance">
<English>Follow Distance</English>
<Italian>Distanza di seguimento</Italian>
<German>Folge-Entfernung</German>
<Korean>따라가는 거리</Korean>
<French>Distance de suivi</French>
<Japanese>追跡距離</Japanese>
</Key>
<Key ID="STR_ACE_Aircraft_DroneFollowHint">
<English>Following unit within %1m</English>
<Italian>Seguendo unità entro %1m</Italian>
<German>Folgt Einheit bis zu %1m</German>
<Korean>%1m 이내로 유닛을 따라갑니다</Korean>
<French>Suivre l'unité jusqu'à %1m</French>
<Japanese>%1m 間隔で 目標を追跡します</Japanese>
</Key> </Key>
</Package> </Package>
</Project> </Project>

View File

@ -78,7 +78,6 @@ PREP(removeStat);
PREP(removeVirtualItems); PREP(removeVirtualItems);
PREP(renameDefaultLoadout); PREP(renameDefaultLoadout);
PREP(replaceUniqueItemsLoadout); PREP(replaceUniqueItemsLoadout);
PREP(saveLoadout);
PREP(scanConfig); PREP(scanConfig);
PREP(showItem); PREP(showItem);
PREP(sortPanel); PREP(sortPanel);

View File

@ -85,10 +85,10 @@ private _insigniaCondition = toString {
// Ref fnc_addListBoxItem, 0/nil = configFile, 1 = campaignConfigFile, 2 = missionConfigFile // Ref fnc_addListBoxItem, 0/nil = configFile, 1 = campaignConfigFile, 2 = missionConfigFile
{ {
GVAR(insigniaCache) set [configName _x, 1]; GVAR(insigniaCache) set [_x, 1];
} forEach (_insigniaCondition configClasses (campaignConfigFile >> "CfgUnitInsignia")); } forEach (_insigniaCondition configClasses (campaignConfigFile >> "CfgUnitInsignia"));
{ {
GVAR(insigniaCache) set [configName _x, 2]; GVAR(insigniaCache) set [_x, 2];
} forEach (_insigniaCondition configClasses (missionConfigFile >> "CfgUnitInsignia")); } forEach (_insigniaCondition configClasses (missionConfigFile >> "CfgUnitInsignia"));
ADDON = true; ADDON = true;

View File

@ -26,14 +26,6 @@ private _cfgWeapons = configfile >> "CfgWeapons";
private _config = _cfgWeapons >> _item; private _config = _cfgWeapons >> _item;
_item = configName _config; _item = configName _config;
// If the switch config entries are inherited, ignore
if (
(inheritsFrom (_config >> "MRT_SwitchItemNextClass") isNotEqualTo _config) ||
{inheritsFrom (_config >> "MRT_SwitchItemPrevClass") isNotEqualTo _config}
) exitWith {
_item // return
};
while { while {
_config = _cfgWeapons >> getText (_config >> "MRT_SwitchItemNextClass"); _config = _cfgWeapons >> getText (_config >> "MRT_SwitchItemNextClass");
isClass _config && {_switchableClasses pushBackUnique configName _config != -1} isClass _config && {_switchableClasses pushBackUnique configName _config != -1}

View File

@ -26,27 +26,28 @@ if (GVAR(shiftState)) then {
switch (true) do { switch (true) do {
// Beginning // Beginning
case (_index == -1): { case (_index == -1): {
"ace" callExtension ["clipboard:append", [format ["[%1", endl]]]; "ace_clipboard" callExtension (format ["[%1", endl]);
}; };
// End // End
case (_index == _listLength): { case (_index == _listLength): {
"ace" callExtension ["clipboard:append", ["];"]]; "ace_clipboard" callExtension "];";
}; };
// Rest // Rest
default { default {
"ace" callExtension ["clipboard:append", [[" ", str (GVAR(defaultLoadoutsList) select _index), [",", ""] select (_index == _listLength - 1), endl] joinString ""]]; "ace_clipboard" callExtension ([" ", str (GVAR(defaultLoadoutsList) select _index), [",", ""] select (_index == _listLength - 1), endl] joinString "");
}; };
}; };
}; };
"ace" callExtension ["clipboard:complete", []]; "ace_clipboard" callExtension "--COMPLETE--";
[_display, LLSTRING(exportDefault)] call FUNC(message); [_display, LLSTRING(exportDefault)] call FUNC(message);
} else { } else {
// Export singular loadout // Export singular loadout
private _export = str (GVAR(center) call CBA_fnc_getLoadout); private _export = str (GVAR(center) call CBA_fnc_getLoadout);
"ace" callExtension ["clipboard:append", [_export]];
"ace" callExtension ["clipboard:complete", []]; "ace_clipboard" callExtension (_export + ";");
"ace_clipboard" callExtension "--COMPLETE--";
[_display, LLSTRING(exportCurrent)] call FUNC(message); [_display, LLSTRING(exportCurrent)] call FUNC(message);
}; };

View File

@ -16,13 +16,7 @@
params ["_display"]; params ["_display"];
// Can be either a singular loadout or an array of loadouts // Can be either a singular loadout or an array of loadouts
private _extendedLoadout = if (isMultiplayer) then { private _extendedLoadout = call compile copyFromClipboard;
("ace" callExtension ["clipboard:loadout", []]) params ["_loadout", "_code"];
if (_code != 0) exitWith {};
parseSimpleArray _loadout
} else {
call compile copyFromClipboard
};
// If error, exit // If error, exit
if (isNil "_extendedLoadout" || {!(_extendedLoadout isEqualType [])}) exitWith { if (isNil "_extendedLoadout" || {!(_extendedLoadout isEqualType [])}) exitWith {

View File

@ -18,7 +18,7 @@
(_this select 1) params ["", "_exitCode"]; (_this select 1) params ["", "_exitCode"];
[QGVAR(displayClosed), []] call CBA_fnc_localEvent; [QGVAR(displayClosed), []] call CBA_fnc_localEvent;
removeMissionEventHandler ["Draw3D", GVAR(camPosUpdateHandle)]; removeMissionEventHandler ["draw3D", GVAR(camPosUpdateHandle)];
if (is3DEN) then { if (is3DEN) then {
private _centerOriginParent = objectParent GVAR(centerOrigin); private _centerOriginParent = objectParent GVAR(centerOrigin);

View File

@ -138,6 +138,14 @@ _actionsBoxCtrl ctrlSetPosition [
]; ];
_actionsBoxCtrl ctrlCommit 0; _actionsBoxCtrl ctrlCommit 0;
// Disable import in MP
if (isMultiplayer) then {
private _importButtonCtrl = _display displayCtrl IDC_buttonImport;
_importButtonCtrl ctrlEnable false;
_importButtonCtrl ctrlSetFade 0.6;
_importButtonCtrl ctrlCommit 0;
};
//--------------- Camera prep //--------------- Camera prep
cutText ["", "PLAIN"]; cutText ["", "PLAIN"];
showCommandingMenu ""; showCommandingMenu "";
@ -270,4 +278,4 @@ showCinemaBorder false;
//--------------- Reset camera pos //--------------- Reset camera pos
[nil, [controlNull, 0, 0]] call FUNC(handleMouse); [nil, [controlNull, 0, 0]] call FUNC(handleMouse);
GVAR(camPosUpdateHandle) = addMissionEventHandler ["Draw3D", {call FUNC(updateCamPos)}]; GVAR(camPosUpdateHandle) = addMissionEventHandler ["draw3D", {call FUNC(updateCamPos)}];

View File

@ -94,8 +94,8 @@ if (!isNull _loadoutsDisplay) then {
}; };
} params ["_className"]; } params ["_className"];
"ace" callExtension ["clipboard:append", [_className]]; "ace_clipboard" callExtension (_className + ";");
"ace" callExtension ["clipboard:complete", []]; "ace_clipboard" callExtension "--COMPLETE--";
[_display, LLSTRING(exportedClassnameText)] call FUNC(message); [_display, LLSTRING(exportedClassnameText)] call FUNC(message);
} else { } else {

View File

@ -382,9 +382,6 @@ switch (GVAR(currentLeftPanel)) do {
}; };
GVAR(currentItems) set [IDX_CURR_VEST, _item]; GVAR(currentItems) set [IDX_CURR_VEST, _item];
[GVAR(center), ""] call BIS_fnc_setUnitInsignia;
[GVAR(center), GVAR(currentInsignia)] call BIS_fnc_setUnitInsignia;
}; };
TOGGLE_RIGHT_PANEL_CONTAINER TOGGLE_RIGHT_PANEL_CONTAINER
@ -423,9 +420,6 @@ switch (GVAR(currentLeftPanel)) do {
}; };
GVAR(currentItems) set [IDX_CURR_BACKPACK, _item]; GVAR(currentItems) set [IDX_CURR_BACKPACK, _item];
[GVAR(center), ""] call BIS_fnc_setUnitInsignia;
[GVAR(center), GVAR(currentInsignia)] call BIS_fnc_setUnitInsignia;
}; };
TOGGLE_RIGHT_PANEL_CONTAINER TOGGLE_RIGHT_PANEL_CONTAINER

View File

@ -69,14 +69,7 @@ switch (_currentItemsIndex) do {
// Secondary weapon // Secondary weapon
case IDX_CURR_SECONDARY_WEAPON_ITEMS: { case IDX_CURR_SECONDARY_WEAPON_ITEMS: {
private _currentItemInSlot = (GVAR(currentItems) select IDX_CURR_SECONDARY_WEAPON_ITEMS) select _itemIndex; private _currentItemInSlot = (GVAR(currentItems) select IDX_CURR_SECONDARY_WEAPON_ITEMS) select _itemIndex;
private _isDisposable = CBA_disposable_replaceDisposableLauncher && {!isNil "CBA_disposable_loadedLaunchers"} && private _isDisposable = CBA_disposable_replaceDisposableLauncher && {!isNil {CBA_disposable_loadedLaunchers getVariable (secondaryWeapon GVAR(center))}};
{
if (CBA_disposable_loadedLaunchers isEqualType createHashMap) then { // after CBA 3.18
(secondaryWeapon GVAR(center)) in CBA_disposable_loadedLaunchers
} else {
!isNil {CBA_disposable_loadedLaunchers getVariable (secondaryWeapon player)}
}
};
// If removal // If removal
if (_item == "") then { if (_item == "") then {

View File

@ -1,37 +0,0 @@
#include "..\script_component.hpp"
/*
* Author: DartRuffian
* Saves a given loadout to the client's profile.
*
* Arguments:
* 0: Name of loadout <STRING>
* 1: CBA extended loadout or getUnitLoadout array <ARRAY>
* 2: Replace existing loadout <BOOL> (default: false)
*
* Return Value:
* True if loadout was saved, otherwise false <BOOL>
*
* Example:
* ["Current Loadout", getUnitLoadout ACE_player] call ace_arsenal_fnc_saveLoadout
*
* Public: Yes
*/
params [["_name", "", [""]], ["_loadout", [], [[]]], ["_replaceExisting", false, [false]]];
if (_name == "" || {_loadout isEqualTo []}) exitWith { false };
private _loadouts = profileNamespace getVariable [QGVAR(saved_loadouts), []];
private _loadoutIndex = _loadouts findIf {(_x#0) == _name};
// If a loadout with same name already exists and no overwriting enabled, quit
if (!_replaceExisting && {_loadoutIndex != -1}) exitWith { false };
if (_loadoutIndex == -1) then {
_loadouts pushBack [_name, _loadout];
} else {
_loadouts set [_loadoutIndex, [_name, _loadout]];
};
profileNamespace setVariable [QGVAR(saved_loadouts), _loadouts];
true

View File

@ -72,6 +72,6 @@ if (_nextAction != GVAR(currentAction)) then {
GVAR(currentAction) = _nextAction; GVAR(currentAction) = _nextAction;
}; };
if !(GVAR(currentAction) in ["Civil", "Salute"]) then { if (!(GVAR(currentAction) in ["Civil", "Salute"])) then {
GVAR(center) selectWeapon ([primaryWeapon GVAR(center), secondaryWeapon GVAR(center), handgunWeapon GVAR(center), binocular GVAR(center)] select GVAR(selectedWeaponType)); // select correct weapon, prevents floating weapons GVAR(center) selectWeapon ([primaryWeapon GVAR(center), secondaryWeapon GVAR(center), handgunWeapon GVAR(center), binocular GVAR(center)] select GVAR(selectedWeaponType)); // select correct weapon, prevents floating weapons
}; };

View File

@ -14,9 +14,4 @@
params ["_config"]; params ["_config"];
private _addon = _config call EFUNC(common,getAddon); (modParams [_config call EFUNC(common,getAddon), ["name"]]) param [0, ""]
// Calling modParams with "" prints 'ModParams - Undefined or empty mod directory' in RPT
if (_addon == "") exitWith {""};
(modParams [_addon, ["name"]]) param [0, ""]

View File

@ -22,10 +22,6 @@ private _extendedInfo = createHashMap;
// Check if the provided loadout is a CBA extended loadout // Check if the provided loadout is a CBA extended loadout
if (count _loadout == 2) then { if (count _loadout == 2) then {
_extendedInfo = +(_loadout select 1); // Copy the hashmap to prevent events from modifiyng the profileNamespace extendedInfo _extendedInfo = +(_loadout select 1); // Copy the hashmap to prevent events from modifiyng the profileNamespace extendedInfo
if (_extendedInfo isEqualType []) then { // Hashmaps are serialized as arrays, convert back to hashmap
_extendedInfo = createHashMapFromArray _extendedInfo;
_loadout set [1, _extendedInfo]; // Also fix source variable, technically not needed but doesn't hurt
};
_loadout = _loadout select 0; _loadout = _loadout select 0;
}; };

View File

@ -63,7 +63,7 @@ _target switchMove "amovpercmstpslowwrfldnon";
_target setVariable ["origin", _position]; _target setVariable ["origin", _position];
// When killed, respawn AI // When killed, respawn AI
_target addEventHandler ["Killed", { _target addEventHandler ["killed", {
params ["_target"]; params ["_target"];
// Killed may fire twice, 2nd will be null - https://github.com/acemod/ACE3/pull/7561 // Killed may fire twice, 2nd will be null - https://github.com/acemod/ACE3/pull/7561

View File

@ -23,7 +23,7 @@
<French>Masque l'interface</French> <French>Masque l'interface</French>
<German>Oberfläche verstecken</German> <German>Oberfläche verstecken</German>
<Polish>Ukryj interfejs</Polish> <Polish>Ukryj interfejs</Polish>
<Japanese>インタフェースを隠す</Japanese> <Japanese>インタフェースを隠す</Japanese>
<Italian>Nascondi interfaccia</Italian> <Italian>Nascondi interfaccia</Italian>
<Korean>인터페이스 숨기기</Korean> <Korean>인터페이스 숨기기</Korean>
<Chinese>隱藏介面</Chinese> <Chinese>隱藏介面</Chinese>
@ -1244,9 +1244,6 @@
<Japanese>熱画像装置内蔵</Japanese> <Japanese>熱画像装置内蔵</Japanese>
<Russian>Интегрирован тепловизор.</Russian> <Russian>Интегрирован тепловизор.</Russian>
<Korean>열화상 내장</Korean> <Korean>열화상 내장</Korean>
<French>Thermique intégrée</French>
<German>Thermal integriert</German>
<Spanish>Térmica integrada</Spanish>
</Key> </Key>
<Key ID="STR_ACE_Arsenal_statVisionMode_intPrimTi"> <Key ID="STR_ACE_Arsenal_statVisionMode_intPrimTi">
<English>Thermal &amp; Primary integrated</English> <English>Thermal &amp; Primary integrated</English>
@ -1254,9 +1251,6 @@
<Japanese>熱画像装置内蔵・プライマリに内蔵</Japanese> <Japanese>熱画像装置内蔵・プライマリに内蔵</Japanese>
<Russian>Интегрирован тепловизор и осн.прицел.</Russian> <Russian>Интегрирован тепловизор и осн.прицел.</Russian>
<Korean>열화상과 주무기 내장</Korean> <Korean>열화상과 주무기 내장</Korean>
<French>Thermique et primaire intégrés</French>
<German>Thermal und in Primärwaffe integriert</German>
<Spanish>Térmica y Primaria integrada</Spanish>
</Key> </Key>
<Key ID="STR_ACE_Arsenal_statVisionMode_NoSup"> <Key ID="STR_ACE_Arsenal_statVisionMode_NoSup">
<English>Not Supported</English> <English>Not Supported</English>
@ -1613,7 +1607,6 @@
<French>Décroissant</French> <French>Décroissant</French>
<Portuguese>Decrescente</Portuguese> <Portuguese>Decrescente</Portuguese>
<Russian>Нисходящий</Russian> <Russian>Нисходящий</Russian>
<Spanish>Descendiente</Spanish>
</Key> </Key>
<Key ID="STR_ACE_Arsenal_sortAscending"> <Key ID="STR_ACE_Arsenal_sortAscending">
<English>Ascending</English> <English>Ascending</English>
@ -1625,7 +1618,6 @@
<French>Croissant</French> <French>Croissant</French>
<Portuguese>Crescente</Portuguese> <Portuguese>Crescente</Portuguese>
<Russian>Восходящий</Russian> <Russian>Восходящий</Russian>
<Spanish>Ascendiente</Spanish>
</Key> </Key>
<Key ID="STR_ACE_Arsenal_toolsTab"> <Key ID="STR_ACE_Arsenal_toolsTab">
<English>Tools</English> <English>Tools</English>
@ -1653,7 +1645,6 @@
<French>Nombre de munitions</French> <French>Nombre de munitions</French>
<Portuguese>Quantidade de munição</Portuguese> <Portuguese>Quantidade de munição</Portuguese>
<Russian>Количество боеприпасов</Russian> <Russian>Количество боеприпасов</Russian>
<Spanish>Cantidad de munición</Spanish>
</Key> </Key>
<Key ID="STR_ACE_Arsenal_statIlluminators"> <Key ID="STR_ACE_Arsenal_statIlluminators">
<English>Illuminators</English> <English>Illuminators</English>
@ -1664,7 +1655,6 @@
<Portuguese>Iluminadores</Portuguese> <Portuguese>Iluminadores</Portuguese>
<Japanese>イルミネーター</Japanese> <Japanese>イルミネーター</Japanese>
<Russian>Осветители</Russian> <Russian>Осветители</Russian>
<Spanish>Iluminadores</Spanish>
</Key> </Key>
<Key ID="STR_ACE_Arsenal_defaultToFavoritesSetting"> <Key ID="STR_ACE_Arsenal_defaultToFavoritesSetting">
<English>Default to Favorites</English> <English>Default to Favorites</English>
@ -1676,7 +1666,6 @@
<French>Favoris par défaut</French> <French>Favoris par défaut</French>
<Portuguese>Favoritos por padrão</Portuguese> <Portuguese>Favoritos por padrão</Portuguese>
<Russian>По умолчанию - Избранное</Russian> <Russian>По умолчанию - Избранное</Russian>
<Spanish>Favoritos por defecto</Spanish>
</Key> </Key>
<Key ID="STR_ACE_Arsenal_defaultToFavoritesTooltip"> <Key ID="STR_ACE_Arsenal_defaultToFavoritesTooltip">
<English>Controls whether the ACE Arsenal defaults to showing all items or favorites.</English> <English>Controls whether the ACE Arsenal defaults to showing all items or favorites.</English>
@ -1688,7 +1677,6 @@
<French>Contrôle si l'arsenal ACE affiche par défaut tous les éléments ou les favoris.</French> <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> <Portuguese>Controla se o Arsenal ACE exibe por padrão todos os itens ou favoritos.</Portuguese>
<Russian>Определяет, будет ли в арсенале ACE по умолчанию отображаться все предметы или избранное.</Russian> <Russian>Определяет, будет ли в арсенале ACE по умолчанию отображаться все предметы или избранное.</Russian>
<Spanish>Controla si el Arsenal de ACE muestra por defecto todos los objetos o sólo los favoritos</Spanish>
</Key> </Key>
<Key ID="STR_ACE_Arsenal_favoritesColorSetting"> <Key ID="STR_ACE_Arsenal_favoritesColorSetting">
<English>Favorites Color</English> <English>Favorites Color</English>
@ -1700,7 +1688,6 @@
<French>Couleurs favorites</French> <French>Couleurs favorites</French>
<Portuguese>Cor dos favoritos</Portuguese> <Portuguese>Cor dos favoritos</Portuguese>
<Russian>Избранный цвет</Russian> <Russian>Избранный цвет</Russian>
<Spanish>Color de Favoritos</Spanish>
</Key> </Key>
<Key ID="STR_ACE_Arsenal_favoritesColorTooltip"> <Key ID="STR_ACE_Arsenal_favoritesColorTooltip">
<English>Highlight color for favorited items.</English> <English>Highlight color for favorited items.</English>
@ -1712,7 +1699,6 @@
<French>Met en surbrillance les éléments favoris.</French> <French>Met en surbrillance les éléments favoris.</French>
<Portuguese>Cor de destaque para itens favoritados.</Portuguese> <Portuguese>Cor de destaque para itens favoritados.</Portuguese>
<Russian>Выделите цветом любимые предметы.</Russian> <Russian>Выделите цветом любимые предметы.</Russian>
<Spanish>Color de marcado para los objetos favoritos</Spanish>
</Key> </Key>
<Key ID="STR_ACE_Arsenal_buttonFavoritesTooltip"> <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> <English>Switch between displaying all items or your favorites.\nDouble click while holding Shift to add or remove an item.</English>
@ -1724,7 +1710,6 @@
<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> <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> <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> <Russian>Переключайтесь между отображением всех элементов или ваших избранных.\nДважды щелкните, удерживая Shift, чтобы добавить или удалить элемент.</Russian>
<Spanish>Alterna entre mostrar todos los objetos o sólo los favoritos.\nDoble click mientras se pulsa Shift para añadir o quitar un objeto.</Spanish>
</Key> </Key>
<Key ID="STR_ACE_Arsenal_buttonSearchTooltip"> <Key ID="STR_ACE_Arsenal_buttonSearchTooltip">
<English>Search\nCTRL + Click to enable live results</English> <English>Search\nCTRL + Click to enable live results</English>
@ -1733,8 +1718,6 @@
<Japanese>検索\nCTRL + クリックで検索結果の即時表示を有効化</Japanese> <Japanese>検索\nCTRL + クリックで検索結果の即時表示を有効化</Japanese>
<Korean>검색\nCtrl + 클릭으로 실시간 검색 결과를 활성화</Korean> <Korean>검색\nCtrl + 클릭으로 실시간 검색 결과를 활성화</Korean>
<Russian>Поиск\nCtrl + Click для включения результатов в реальном времени</Russian> <Russian>Поиск\nCtrl + Click для включения результатов в реальном времени</Russian>
<French>Recherche\nCTRL + clic pour modifier les résultats tout en écrivant</French>
<Spanish>Buscar\nCTRL + Click habilita los objetos en directo</Spanish>
</Key> </Key>
</Package> </Package>
</Project> </Project>

View File

@ -1,14 +1,8 @@
TRACE_1("prep",_this); TRACE_1("prep",_this);
PREP(adjustFire);
PREP(calculateElevation);
PREP(calculateMaxAngle);
PREP(calculateMuzzleVelocity);
PREP(calculateSolution);
PREP(firedEH); PREP(firedEH);
PREP(interactMenuOpened); PREP(interactMenuOpened);
PREP(rangeTableOpen); PREP(rangeTableOpen);
PREP(rangeTableUpdate); PREP(rangeTableUpdate);
PREP(simulateShot);
PREP(turretChanged); PREP(turretChanged);
PREP(turretPFEH); PREP(turretPFEH);

View File

@ -4,13 +4,10 @@
TRACE_2("CBA_settingsInitialized",GVAR(advancedCorrections),GVAR(disableArtilleryComputer)); TRACE_2("CBA_settingsInitialized",GVAR(advancedCorrections),GVAR(disableArtilleryComputer));
if (hasInterface) then { if (hasInterface) then {
// Add hud overlay for actual azimuth and elevation: // Add hud overlay for actuall azimuth and elevation:
GVAR(pfID) = -1; GVAR(pfID) = -1;
["turret", LINKFUNC(turretChanged), true] call CBA_fnc_addPlayerEventHandler; ["turret", LINKFUNC(turretChanged), true] call CBA_fnc_addPlayerEventHandler;
// Handles being teleported from one vehicle to another
["vehicle", {[_this select 0, (_this select 1) unitTurret (_this select 0)] call FUNC(turretChanged)}] call CBA_fnc_addPlayerEventHandler;
// Add ability to dynamically open rangetables: // Add ability to dynamically open rangetables:
["ace_interactMenuOpened", LINKFUNC(interactMenuOpened)] call CBA_fnc_addEventHandler; ["ace_interactMenuOpened", LINKFUNC(interactMenuOpened)] call CBA_fnc_addEventHandler;
}; };
@ -33,33 +30,6 @@
}; };
}] call CBA_fnc_addEventHandler; }] call CBA_fnc_addEventHandler;
addMissionEventHandler ["ExtensionCallback", {
params ["_name", "_function", "_data"];
if (_name == "ace:artillery" && {_function == "calculate_table"}) then {
(parseSimpleArray _data) params ["_line", "_data"];
if (_data isEqualType []) then {
GVAR(tableData) set [_line, _data];
};
GVAR(tableSizeReceived) = GVAR(tableSizeReceived) + 1;
if (GVAR(tableSizeReceived) == GVAR(tableSizeActual)) then {
private _dialog = uiNamespace getVariable [QGVAR(rangeTableDialog), displayNull];
private _ctrlRangeTable = _dialog displayCtrl IDC_TABLE;
if (isNull _dialog) exitWith {true};
for "_i" from 0 to GVAR(tableSizeActual) do {
private _row = GVAR(tableData) getOrDefault [_i, []];
if (count _row == 12) then {
_ctrlRangeTable lnbAddRow _row;
};
};
private _dialog = uiNamespace getVariable [QGVAR(rangeTableDialog), displayNull];
private _ctrlRangeTable = _dialog displayCtrl IDC_TABLE;
if (isNull _dialog) exitWith {TRACE_1("dialog closed",_this);};
_ctrlRangeTable lnbAddRow ["", "", "", "", "", "", "", "", "", "", ""];
TRACE_1("table filled",_ctrlRangeTable);
};
};
}];
#ifdef DEBUG_MODE_FULL #ifdef DEBUG_MODE_FULL
#include "dev\showShotInfo.inc.sqf" #include "dev\showShotInfo.inc.sqf"
#include "dev\checkConfigs.inc.sqf" #include "dev\checkConfigs.inc.sqf"

View File

@ -14,6 +14,13 @@ class CfgPatches {
}; };
}; };
class ACE_Extensions {
class ace_artillerytables {
windows = 1;
client = 1;
};
};
#include "CfgEventHandlers.hpp" #include "CfgEventHandlers.hpp"
#include "CfgMagazines.hpp" #include "CfgMagazines.hpp"
#include "CfgVehicles.hpp" #include "CfgVehicles.hpp"

View File

@ -1,41 +0,0 @@
#include "..\script_component.hpp"
/*
* Author: LorenLuke
* Adjusts a target point north and east, and recalculates a solution in air based on atmospheric conditions
*
* Arguments:
* 0: Gun Position ASL <ARRAY>
* 1: Target Position ASL <ARRAY>
* 2: Adjustment to the East (negative is West); meters <NUMBER>
* 3: Adjustment to the North (negative is South); meters <NUMBER>
* 4: Adjustment vertically (negative is Down); meters <NUMBER>
* 5: Muzzle velocity; meters/second <NUMBER>
* 6: Air Friction; meters^-1 (m/s^2)/(m^2/s^2) <NUMBER>
* 7: High angle boolean (true is high angle) <BOOL>
* 8: Temperature; degrees Celsius <NUMBER>
* 9: Atmospheric Density; kg/(meters^3) <NUMBER>
* 10: Direction of wind; degrees clockwise from north <NUMBER>
* 11: Speed of wind; meters/second <NUMBER>
*
* Return Value:
* Array of returns <ARRAY>
* 0: Angle of shot; Milliradians <NUMBER>
* 1: Angle adjust left or right; Milliradians <NUMBER>
* 2: Time of flight; seconds <NUMBER>
*
* Example:
* [getposASL vehicle player, targetPos, 20, 50, 0, 200, -0.0001, true, 15, 1.225, 225, 5] call ace_artilleryTables_fnc_adjustFire
*
* Public: No
*/
params ["_gunPos", "_targetPos", "_adjustEast", "_adjustNorth", "_adjustUp", "_muzzleVelocity", "_airFriction", ["_highAngle", true], ["_temperature", 15], ["_airDensity", 1.225], ["_windDir", 0], ["_windSpeed", 0]];
//DEFAULT_AIR_FRICTION == -0.00006
//MK6_82mm_AIR_FRICTION == -0.0001
private _resultPos = [_adjustEast + _targetPos select 0, _adjustNorth + _targetPos select 1, _adjustUp + _targetPos select 2];
private _returns = ["_gunPos", "_resultPos", "_muzzleVelocity", "_highAngle", "_airFriction", "_temperature", "_airDensity", "_windDir", "_windSpeed"] call FUNC(calculateSolution);
_returns

View File

@ -1,71 +0,0 @@
#include "..\script_component.hpp"
/*
* Author: LorenLuke
* Adjusts a target point north and east, and recalculates a solution in air based on atmospheric conditions
*
* Arguments:
* 0: Distance to Target; meters <NUMBER>
* 1: Height of target; meters, relative to gun altitude (positive means target higher than gun) <NUMBER>
* 2: Muzzle velocity; meters/second <NUMBER>
* 3: High angle boolean (true is high angle) <BOOL>
* 4: Air Friction; meters^-1 [(m/s^2)/(m^2/s^2)] <NUMBER>
* 5: Temperature; degrees Celsius <NUMBER>
* 6: Atmospheric Density; kg/(meters^3) <NUMBER>
* 7: Cross wind; meters/second (negative is Right to Left) <NUMBER>
* 8: Tail wind; meters/second (negative is flying against the wind) <NUMBER>
*
* Return Value:
* Array of returns <ARRAY>
* 0: Angle of shot; Milliradians <NUMBER>
* 1: Angle adjust left or right; Milliradians <NUMBER>
* 2: Time of flight; seconds <NUMBER>
*
* Example:
* [myPos, 0, 200, true, -0.0001, 15, 1.225, 5, -10] call ace_artilleryTables_fnc_calculateElevation
*
* Public: No
*/
params ["_targetDistance", "_targetHeight", "_muzzleVelocity", ["_highArc", true], ["_airFriction", 0], ["_temperature", 15], ["_airDensity", 1.225], ["_crossWind", 0], ["_tailWind", 0]];
//DEFAULT_AIR_FRICTION == -0.00006
//MK6_82mm_AIR_FRICTION == -0.0001
if (_airFriction != 0) then {
_muzzleVelocity = [_muzzleVelocity, _temperature, _atmosphericDensity] call FUNC(calculateMuzzleVelocity);
};
private _maxResults = [_muzzleVelocity, _airFriction] call FUNC(calculateMaxAngle);
private _testShot = [_maxResults select 0, _targetHeight, _muzzleVelocity, _airFriction, _crossWind, _tailWind, _temperature, _airDensity] call FUNC(simulateShot);
if (_testShot select 1 < _targetDistance) exitWith {
//No way we can hit it so don't bother;
[-1, -1, -1]
};
private _useDistance = _targetDistance;
private _useAngle = 0;
private _resultDistance = 0;
private _xDeviation = 0;
private _tof = 0;
while {abs(_resultDistance - _targetDistance) > 0.5} do {
TRACE_7("callExtension:artillery:simulate_find_solution",_useDistance,_targetHeight,_muzzleVelocity,_airFriction,_higharc,DEFAULT_MIN_ELEV,DEFAULT_MAX_ELEV);
(
"ace" callExtension ["artillery:simulate_find_solution", [_useDistance, _targetHeight, _muzzleVelocity, _airFriction, _higharc, DEFAULT_MIN_ELEV, DEFAULT_MAX_ELEV]]
) params ["_data", "_code"];
TRACE_1("",_code);
(parseSimpleArray _data) params ["", "_useAngleRad", ""];
_useAngle = deg(_useAngleRad) * DEGTOMILS;
private _shotResults = [_useAngle, _targetHeight, _muzzleVelocity, _airFriction, _crossWind, _tailWind, _temperature, _airDensity] call FUNC(simulateShot);
_xDeviation = _shotResults select 0;
_resultDistance = _shotResults select 1;
_tof = _shotResults select 2;
_useDistance = (2 * _targetDistance) - _resultDistance;
};
private _angleOffsetDeg = _xDeviation atan2 _resultDistance;
private _angleOffset = _angleOffsetDeg * DEGTOMILS;
[_useAngle, -_angleOffset, _tof]

View File

@ -1,31 +0,0 @@
#include "..\script_component.hpp"
/*
* Author: LorenLuke
* Calculates the best possible angle to shoot farthest based on muzzle velocity and air friction.
*
* Arguments:
* 0: Initial Muzzle Velocity; meters/second <NUMBER>
* 1: Air Friction; meters^-1 (m/s^2)/(m^2/s^2) <NUMBER>
*
* Return Values: <ARRAY>
* 1: Best Angle; Milliradians <NUMBER>
* 2: Furthest Distance; Meters <NUMBER>
*
* Example:
* [200, -0.00006] call ace_artilleryTables_fnc_calculateMaxAngle
*
* Public: No
*/
params ["_muzzleVelocity", "_airFriction"];
TRACE_2("callExtension:artillery:find_max_angle",_muzzleVelocity,_airFriction);
(
"ace" callExtension ["artillery:find_max_angle", [_muzzleVelocity, _airFriction]]
) params ["_data", "_code"];
TRACE_1("",_code);
(parseSimpleArray _data) params ["_bestAngle", "_bestDistance", ""];
_returns = [deg _bestAngle * 6400 / 360, _bestDistance];
_returns params ["_bestAngle", "_bestDistance"];
_returns

View File

@ -1,28 +0,0 @@
#include "..\script_component.hpp"
/*
* Author: LorenLuke
* Calculates the muzzleVelocity change with advanced calculations.
*
* Arguments:
* 0: Initial Muzzle velocity; meters/second <NUMBER>
* 1: Temperature; degrees Celsius <NUMBER>
* 2: Atmospheric Density; kg/(meters^3) <NUMBER>
*
* Return Value:
* Adjusted Muzzle Velocity; Meters <NUMBER>
*
* Example:
* [200, 15, 1.225] call ace_artilleryTables_fnc_calculateMuzzleVelocity
*
* Public: No
*/
params ["_muzzleVelocity", "_temperature", "_airDensity"];
// Calculate air density
private _relativeDensity = _airDensity / 1.225;
private _newMuzzleVelocityCoefficient = (((_temperature + 273.13) / 288.13 - 1) / 40 + 1);
private _newMuzzleVelocity = _muzzleVelocity * _newMuzzleVelocityCoefficient;
_newMuzzleVelocity

View File

@ -1,44 +0,0 @@
#include "..\script_component.hpp"
/*
* Author: LorenLuke
* Provides fire angle and deflection solutions on a target of set distance and height, including accounting for drag and atmospheric wind conditions.
*
* Arguments:
* 0: Gun Position ASL; <ARRAY>
* 1: Target Position ASL; <ARRAY>
* 2: Muzzle Velocity; meters/second <NUMBER>
* 3: High angle boolean (true is high angle) <BOOL>
* 4: Air Friction; meters^-1 [(m/s^2)/(m^2/s^2)] <NUMBER>
* 5: Temperature; degrees Celsius <NUMBER>
* 6: Atmospheric Density; kg/(meters^3) <NUMBER>
* 7: Direction of wind; degrees clockwise from north <NUMBER>
* 8: Speed of wind; meters/second <NUMBER>
*
* Return Value:
* array of returns <ARRAY>
* 0: Angle of shot; Milliradians <NUMBER>
* 1: Angle adjust left or right; Milliradians <NUMBER>
* 2: Time of flight; seconds <NUMBER>
*
* Example:
* [myPos, targetPos, 200, true, -0.0001, 15, 1.225, 225, 5] call ace_artilleryTables_fnc_calculateSolution
*
* Public: No
*/
params ["_ownPos", "_targetPos", "_muzzleVelocity", ["_highAngle", true], ["_airFriction", 0], ["_temperature", 15], ["_airDensity", 1.225], ["_windDir", 0], ["_windSpeed", 0]];
//DEFAULT_AIR_FRICTION == -0.00006
//MK6_82mm_AIR_FRICTION == -0.0001
private _relPos = _targetPos vectorDiff _ownPos;
private _targetDir = (_relpos select 0) atan2 (_relPos select 1);
private _targetDist = sqrt( (_relPos select 0)^2 + (_relpos select 1)^2 );
private _heightDif = _relPos select 2;
private _crossWind = sin(_targetDir - _windDir) * _windSpeed;
private _tailWind = -cos(_targetDir - _windDir) * _windSpeed;
private _solutionReturns = [_targetDist, _heightDif, _muzzleVelocity, _highAngle, _airFriction, _crossWind, _tailWind, _temperature, _airDensity] call FUNC(calculateElevation);
_solutionReturns

View File

@ -25,7 +25,7 @@
params ["_vehicle", "", "", "", "", "_magazine", "_projectile", "_gunner"]; params ["_vehicle", "", "", "", "", "_magazine", "_projectile", "_gunner"];
TRACE_4("firedEH",_vehicle,_magazine,_projectile,_gunner); TRACE_4("firedEH",_vehicle,_magazine,_projectile,_gunner);
if !([_gunner] call EFUNC(common,isPlayer)) exitWith {}; // AI don't know how to use (this does give them more range than a player) if (!([_gunner] call EFUNC(common,isPlayer))) exitWith {}; // AI don't know how to use (this does give them more range than a player)
if ((gunner _vehicle) != _gunner) exitWith {}; // check if primaryGunner if ((gunner _vehicle) != _gunner) exitWith {}; // check if primaryGunner
@ -35,7 +35,7 @@ if (isNumber (configFile >> "CfgMagazines" >> _magazine >> QGVAR(airFriction)))
_airFriction = getNumber (configFile >> "CfgMagazines" >> _magazine >> QGVAR(airFriction)); _airFriction = getNumber (configFile >> "CfgMagazines" >> _magazine >> QGVAR(airFriction));
}; };
TRACE_1("",_airFriction); TRACE_1("",_airFriction);
if (_airFriction == 0) exitWith {}; // 0 disables everything if (_airFriction >= 0) exitWith {}; // 0 disables everything, >0 makes no sense
BEGIN_COUNTER(adjustmentsCalc); BEGIN_COUNTER(adjustmentsCalc);
@ -60,7 +60,6 @@ if (_newMuzzleVelocityCoefficent != 1) then {
_projectile setVelocity _bulletVelocity; _projectile setVelocity _bulletVelocity;
}; };
if (_airFriction > 0) exitWith {}; // positive value indicates it has vanilla airFriction, so we can just exit
[{ [{
params ["_projectile", "_kFactor", "_time"]; params ["_projectile", "_kFactor", "_time"];

View File

@ -19,7 +19,7 @@ params ["_menuType"];
TRACE_1("interactMenuOpened",_menuType); TRACE_1("interactMenuOpened",_menuType);
if (_menuType != 1) exitWith {}; if (_menuType != 1) exitWith {};
if !("ACE_artilleryTable" in (ace_player call EFUNC(common,uniqueItems))) exitWith {}; if (!("ACE_artilleryTable" in (ace_player call EFUNC(common,uniqueItems)))) exitWith {};
private _vehicleAdded = ace_player getVariable [QGVAR(vehiclesAdded), []]; private _vehicleAdded = ace_player getVariable [QGVAR(vehiclesAdded), []];
private _rangeTablesShown = ace_player getVariable [QGVAR(rangeTablesShown), []]; private _rangeTablesShown = ace_player getVariable [QGVAR(rangeTablesShown), []];

View File

@ -34,22 +34,15 @@ TRACE_2("created dialog",_dialog,_ctrlChargeList);
// Get Mags: // Get Mags:
private _mags = [_weaponName] call CBA_fnc_compatibleMagazines; private _mags = [_weaponName] call CBA_fnc_compatibleMagazines;
if (_mags isEqualTo []) exitWith {WARNING_1("No Mags %1",_weaponName);}; if (_mags isEqualTo []) exitWith {WARNING_1("No Mags",_weaponName);};
private _magCfg = configFile >> "CfgMagazines"; private _magCfg = configFile >> "CfgMagazines";
private _magParamsArray = []; private _magParamsArray = [];
_mags = _mags apply { _mags = _mags apply {
private _initSpeed = getNumber (_magCfg >> _x >> "initSpeed"); private _initSpeed = getNumber (_magCfg >> _x >> "initSpeed");
_magParamsArray pushBackUnique _initSpeed; _magParamsArray pushBackUnique _initSpeed;
private _airFriction = 0; private _airFriction = 0;
private _magAirFriction = getNumber (_magCfg >> _x >> QGVAR(airFriction));
if (_magAirFriction <= 0) then {
if (_advCorrection) then { if (_advCorrection) then {
_airFriction = [DEFAULT_AIR_FRICTION, _magAirFriction] select (isNumber (_magCfg >> _x >> QGVAR(airFriction))); _airFriction = if (isNumber (_magCfg >> _x >> QGVAR(airFriction))) then { getNumber (_magCfg >> _x >> QGVAR(airFriction)) } else { DEFAULT_AIR_FRICTION };
};
} else {
// positive value, use ammo's airFriction (regardless of setting)
private _ammo = getText (_magCfg >> _x >> "ammo");
_airFriction = getNumber (configFile >> "CfgAmmo" >> _ammo >> "airFriction");
}; };
_magParamsArray pushBackUnique _airFriction; _magParamsArray pushBackUnique _airFriction;
[getText (_magCfg >> _x >> "displayNameShort"), getText (_magCfg >> _x >> "displayName"), _initSpeed, _airFriction] [getText (_magCfg >> _x >> "displayNameShort"), getText (_magCfg >> _x >> "displayName"), _initSpeed, _airFriction]

View File

@ -34,12 +34,31 @@ _ctrlElevationLow ctrlSetTextColor ([[1,1,1,1],[0.25,0.25,0.25,1]] select GVAR(l
lnbClear _ctrlRangeTable; lnbClear _ctrlRangeTable;
// Call extension with current data and start workers // Call extension with current data and start workers
TRACE_5("callExtension:artillery:calculate_table",_muzzleVelocity,_airFriction,_elevMin,_elevMax,GVAR(lastElevationMode)); TRACE_5("callExtension:start",_muzzleVelocity,_airFriction,_elevMin,_elevMax,GVAR(lastElevationMode));
( private _ret = "ace_artillerytables" callExtension ["start", [_muzzleVelocity,_airFriction,_elevMin,_elevMax,GVAR(lastElevationMode)]];
"ace" callExtension ["artillery:calculate_table", [_muzzleVelocity, _airFriction, _elevMin, _elevMax, GVAR(lastElevationMode)]] TRACE_1("",_ret);
) params ["_data", "_code"];
TRACE_1("",_code);
GVAR(tableData) = createHashMap; // Non-blocking read data out of extension as it becomes availiable
GVAR(tableSizeActual) = (parseSimpleArray _data) select 1; [{
GVAR(tableSizeReceived) = 0; private _dialog = uiNamespace getVariable [QGVAR(rangeTableDialog), displayNull];
private _ctrlRangeTable = _dialog displayCtrl IDC_TABLE;
if (isNull _dialog) exitWith {true};
private _status = 1; // 1 = data on line, 2 - data not ready, 3 - done
while {_status == 1} do {
private _ret = ("ace_artillerytables" callExtension ["getline", []]);
// TRACE_1("callExtension:getline",_ret);
_status = _ret select 1;
if (_status == 1) then { _ctrlRangeTable lnbAddRow parseSimpleArray (_ret select 0) };
};
(_status == 3) // exit loop when all data read
}, {
// put dummy line at end because scrolling is problematic and can't see last line
private _dialog = uiNamespace getVariable [QGVAR(rangeTableDialog), displayNull];
private _ctrlRangeTable = _dialog displayCtrl IDC_TABLE;
if (isNull _dialog) exitWith {TRACE_1("dialog closed",_this);};
_ctrlRangeTable lnbAddRow ["", "", "", "", "", "", "", "", "", "", ""];
TRACE_1("table filled",_ctrlRangeTable);
}, []] call CBA_fnc_waitUntilAndExecute;

View File

@ -1,47 +0,0 @@
#include "..\script_component.hpp"
/*
* Author: LorenLuke
* Simulates an indirect shot on a target of known height with given drag, wind, and atmospheric conditions
*
* Arguments:
* 0: Gun Elevation Angle; milliradians <NUMBER>
* 1: Relative Target Height; meters, relative to gun altitude (positive means target higher than gun) <NUMBER>
* 2: Muzzle Velocity; meters/second <NUMBER>
* 3: Air Friction; meters^-1 [(m/s^2)/(m^2/s^2)] <NUMBER>
* 4: Cross wind; meters/second (negative is Right to Left) <NUMBER>
* 5: Tail wind; meters/second (negative is flying against the wind) <NUMBER>
* 6: Temperature; degrees Celsius <NUMBER>
* 7: Atmospheric Density; kg/(meters^3) <NUMBER>
*
* Return Value:
* array of returns <ARRAY>
* 0: Deflection Adjustment To Hit; Milliradians (negative is Left) <NUMBER>
* 1: Distance of Shot; meters <NUMBER>
* 2: Time of Flight; seconds <NUMBER>
*
* Example:
* [900, 10, 200, -0.0001, 4, 0, 15, 1.225] call ace_artilleryTables_fnc_simulateShot
*
* Public: No
*/
params ["_angle", "_targetHeight", "_muzzleVelocity", ["_airFriction", 0], ["_crossWind", 0], ["_tailWind", 0], ["_temperature", 15], ["_atmosphericDensity", 1.225]];
//DEFAULT_AIR_FRICTION == -0.00006
//MK6_82mm_AIR_FRICTION == -0.0001
if (_airFriction != 0) then {
_muzzleVelocity = [_muzzleVelocity, _temperature, _atmosphericDensity] call FUNC(calculateMuzzleVelocity);
};
private _atmosphericDensityRatio = _atmosphericDensity / 1.225;
private _radAngle = rad(_angle / DEGTOMILS);
TRACE_8("callExtension:artillery:simulate_shot",_radAngle,_targetHeight,_muzzleVelocity,_airFriction,_crossWind,_tailWind,_temperature,_atmosphericDensityRatio);
(
"ace" callExtension ["artillery:simulate_shot", [_radAngle, _targetHeight, _muzzleVelocity, _airFriction, _crossWind, _tailWind, _temperature, _atmosphericDensityRatio]]
) params ["_data", "_code"];
TRACE_1("",_code);
//[xDeviation, yDistance, timeOfFlight]
parseSimpleArray _data

View File

@ -30,10 +30,7 @@ if (isNull (uiNamespace getVariable [QGVAR(display), displayNull])) then {
}; };
private _ctrlGroup = (uiNamespace getVariable [QGVAR(display), displayNull]) displayCtrl 1000; private _ctrlGroup = (uiNamespace getVariable [QGVAR(display), displayNull]) displayCtrl 1000;
if (cameraView != "GUNNER") exitWith { // need to be in gunner mode, so we can check where the optics are aiming at
// Need to be in gunner mode, so we can check where the optics are aiming at
// However, if there are no optics, ignore the above
if (!_invalidGunnerMem && {cameraView != "GUNNER"}) exitWith {
_ctrlGroup ctrlShow false; _ctrlGroup ctrlShow false;
}; };
_ctrlGroup ctrlShow true; _ctrlGroup ctrlShow true;

View File

@ -15,5 +15,7 @@ private _categoryName = [format ["ACE %1", localize "str_a3_cfgmarkers_nato_art"
[LSTRING(disableArtilleryComputer_displayName), LSTRING(disableArtilleryComputer_description)], [LSTRING(disableArtilleryComputer_displayName), LSTRING(disableArtilleryComputer_description)],
_categoryName, _categoryName,
false, // default value false, // default value
true // isGlobal true, // isGlobal
{[QGVAR(disableArtilleryComputer), _this] call EFUNC(common,cbaSettings_settingChanged)},
false // Needs mission restart
] call CBA_fnc_addSetting; ] call CBA_fnc_addSetting;

View File

@ -12,10 +12,6 @@
// This is a good fit for most large artillery, but a little low for lighter mortars // This is a good fit for most large artillery, but a little low for lighter mortars
#define DEFAULT_AIR_FRICTION -0.00006 #define DEFAULT_AIR_FRICTION -0.00006
#define DEFAULT_MIN_ELEV 0
// 90 degrees in radians
#define DEFAULT_MAX_ELEV 1.5708
#define DEGTOMILS 17.7777778 #define DEGTOMILS 17.7777778
#define IDC_MODECONTROLGROUP 1000 #define IDC_MODECONTROLGROUP 1000

View File

@ -6,7 +6,7 @@ class CfgPatches {
units[] = {"ACE_Item_ATragMX"}; units[] = {"ACE_Item_ATragMX"};
weapons[] = {"ACE_ATragMX"}; weapons[] = {"ACE_ATragMX"};
requiredVersion = REQUIRED_VERSION; requiredVersion = REQUIRED_VERSION;
requiredAddons[] = {"ace_advanced_ballistics", "ace_common", "ace_weather"}; requiredAddons[] = {"ACE_Advanced_Ballistics", "ACE_common", "ACE_weather"};
author = ECSTRING(common,ACETeam); author = ECSTRING(common,ACETeam);
authors[] = {"Ruthberg"}; authors[] = {"Ruthberg"};
url = ECSTRING(main,URL); url = ECSTRING(main,URL);

View File

@ -30,16 +30,9 @@ while {_velocity > _thresholdVelocity} do {
private _bc = GVAR(targetSolutionInput) select 14; private _bc = GVAR(targetSolutionInput) select 14;
private _dragModel = GVAR(targetSolutionInput) select 15; private _dragModel = GVAR(targetSolutionInput) select 15;
private _temperature = GVAR(targetSolutionInput) select 5; private _temperature = GVAR(targetSolutionInput) select 5;
private _drag = parseNumber(("ace_advanced_ballistics" callExtension format["retard:%1:%2:%3:%4", _dragModel, _bc, _velocity, _temperature]));
_distance = _distance + _velocity * __DELTA_T; _distance = _distance + _velocity * __DELTA_T;
private _data = ( _velocity = _velocity - (_drag * __DELTA_T);
"ace" callExtension ["ballistics:retard", [
_dragModel,
_bc,
_velocity,
_temperature
]]
) select 0;
_velocity = _velocity - ((parseNumber _data) * __DELTA_T);
}; };
_distance _distance

View File

@ -90,14 +90,7 @@ private _wind1 = [cos(270 - _windDirection * 30) * _windSpeed1, sin(270 - _windD
private _wind2 = [cos(270 - _windDirection * 30) * _windSpeed2, sin(270 - _windDirection * 30) * _windSpeed2, 0]; private _wind2 = [cos(270 - _windDirection * 30) * _windSpeed2, sin(270 - _windDirection * 30) * _windSpeed2, 0];
private _windDrift = 0; private _windDrift = 0;
if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then {
_bc = parseNumber (("ace" callExtension ["ballistics:atmospheric_correction", [ _bc = parseNumber(("ace_advanced_ballistics" callExtension format["atmosphericCorrection:%1:%2:%3:%4:%5", _bc, _temperature, _barometricPressure, _relativeHumidity, _atmosphereModel]));
_bc,
_temperature,
_barometricPressure,
_relativeHumidity,
_atmosphereModel
]]
) select 0);
}; };
private _eoetvoesMultiplier = 0; private _eoetvoesMultiplier = 0;
@ -120,15 +113,8 @@ while {_TOF < 15 && (_bulletPos select 1) < _targetRange} do {
_trueSpeed = vectorMagnitude _trueVelocity; _trueSpeed = vectorMagnitude _trueVelocity;
if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then {
private _data = ( private _drag = parseNumber(("ace_advanced_ballistics" callExtension format["retard:%1:%2:%3:%4", _dragModel, _bc, _trueSpeed, _temperature]));
"ace" callExtension ["ballistics:retard", [ _bulletAccel = (vectorNormalized _trueVelocity) vectorMultiply (-1 * _drag);
_dragModel,
_bc,
_trueSpeed,
_temperature
]]
) select 0;
_bulletAccel = (vectorNormalized _trueVelocity) vectorMultiply (-1 * (parseNumber _data));
} else { } else {
_bulletAccel = _trueVelocity vectorMultiply (_trueSpeed * _airFriction); _bulletAccel = _trueVelocity vectorMultiply (_trueSpeed * _airFriction);
}; };

View File

@ -23,7 +23,7 @@ if ((profileNamespace getVariable ["ACE_ATragMX_profileNamespaceVersion", 0]) ==
_resetGunList = false; _resetGunList = false;
{ {
// Verify each gun has correct param type // Verify each gun has correct param type
if !(_x isEqualTypeArray ["", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", [], [], false]) exitWith { if (!(_x isEqualTypeArray ["", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", [], [], false])) exitWith {
_resetGunList = true; _resetGunList = true;
}; };
} forEach GVAR(gunList); } forEach GVAR(gunList);

View File

@ -74,7 +74,7 @@ private _validate_preset = {
ERROR(_errorMsg); ERROR(_errorMsg);
_valid = false; _valid = false;
}; };
if !((_this select 17) in ["ASM", "ICAO"]) then { if (!((_this select 17) in ["ASM", "ICAO"])) then {
private _errorMsg = format ["Invalid atmosphere model: %1", _this select 17]; private _errorMsg = format ["Invalid atmosphere model: %1", _this select 17];
ERROR(_errorMsg); ERROR(_errorMsg);
_valid = false; _valid = false;

View File

@ -26,7 +26,7 @@ if !(ctrlVisible 9000) then {
params ["_args"]; params ["_args"];
_args params ["_startTime"]; _args params ["_startTime"];
if !(GVAR(speedAssistTimer)) exitWith { if (!(GVAR(speedAssistTimer))) exitWith {
GVAR(speedAssistTimer) = true; GVAR(speedAssistTimer) = true;
ctrlSetText [8006, Str(Round((CBA_missionTime - _startTime) * 10) / 10)]; ctrlSetText [8006, Str(Round((CBA_missionTime - _startTime) * 10) / 10)];

View File

@ -15,7 +15,7 @@
* Public: No * Public: No
*/ */
if !(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) exitWith {}; if (!(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false])) exitWith {};
if (ctrlVisible 17000) then { if (ctrlVisible 17000) then {
false call FUNC(show_c1_ballistic_coefficient_data); false call FUNC(show_c1_ballistic_coefficient_data);

View File

@ -15,7 +15,7 @@
* Public: No * Public: No
*/ */
if !(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) exitWith {}; if (!(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false])) exitWith {};
if (ctrlVisible 16000) then { if (ctrlVisible 16000) then {
false call FUNC(show_muzzle_velocity_data); false call FUNC(show_muzzle_velocity_data);

View File

@ -15,7 +15,7 @@
* Public: No * Public: No
*/ */
if !(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) exitWith {}; if (!(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false])) exitWith {};
if (ctrlVisible 18000) then { if (ctrlVisible 18000) then {
false call FUNC(show_truing_drop); false call FUNC(show_truing_drop);

View File

@ -35,26 +35,12 @@ if (!GVAR(atmosphereModeTBH)) then {
_relativeHumidity = 0.5; _relativeHumidity = 0.5;
}; };
private _scopeBaseAngle = if !(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { private _scopeBaseAngle = if (!(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false])) then {
parseNumber (("ace" callExtension ["ballistics:zero_vanilla", [ private _zeroAngle = "ace_advanced_ballistics" callExtension format ["calcZero:%1:%2:%3:%4", _zeroRange, _muzzleVelocity, _airFriction, _boreHeight];
_zeroRange, (parseNumber _zeroAngle)
_muzzleVelocity,
_airFriction,
_boreHeight
]]) select 0)
} else { } else {
parseNumber (("ace" callExtension ["ballistics:zero_advanced", [ private _zeroAngle = "ace_advanced_ballistics" callExtension format ["calcZeroAB:%1:%2:%3:%4:%5:%6:%7:%8:%9", _zeroRange, _muzzleVelocity, _boreHeight, _temperature, _barometricPressure, _relativeHumidity, _bc, _dragModel, _atmosphereModel];
_zeroRange, (parseNumber _zeroAngle)
_muzzleVelocity,
_airFriction,
_boreHeight,
_temperature,
_barometricPressure,
_relativeHumidity,
_bc,
_dragModel,
_atmosphereModel
]]) select 0)
}; };
GVAR(workingMemory) set [2, _zeroRange]; GVAR(workingMemory) set [2, _zeroRange];

View File

@ -50,8 +50,8 @@ if (_unit == _attachToVehicle) then { //Self Attachment
} else { } else {
GVAR(placeAction) = PLACE_WAITING; GVAR(placeAction) = PLACE_WAITING;
[_unit, "forceWalk", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); [_unit, "forceWalk", "ACE_Attach", true] call EFUNC(common,statusEffect_set);
[_unit, "blockThrow", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); [_unit, "blockThrow", "ACE_Attach", true] call EFUNC(common,statusEffect_set);
[{[localize LSTRING(PlaceAction), ""] call EFUNC(interaction,showMouseHint)}, []] call CBA_fnc_execNextFrame; [{[localize LSTRING(PlaceAction), ""] call EFUNC(interaction,showMouseHint)}, []] call CBA_fnc_execNextFrame;
_unit setVariable [QGVAR(placeActionEH), [_unit, "DefaultAction", {true}, {GVAR(placeAction) = PLACE_APPROVE;}] call EFUNC(common,AddActionEventHandler)]; _unit setVariable [QGVAR(placeActionEH), [_unit, "DefaultAction", {true}, {GVAR(placeAction) = PLACE_APPROVE;}] call EFUNC(common,AddActionEventHandler)];
@ -88,8 +88,8 @@ if (_unit == _attachToVehicle) then { //Self Attachment
{!([_attachToVehicle, _unit, _itemClassname] call FUNC(canAttach))}) then { {!([_attachToVehicle, _unit, _itemClassname] call FUNC(canAttach))}) then {
[_idPFH] call CBA_fnc_removePerFrameHandler; [_idPFH] call CBA_fnc_removePerFrameHandler;
[_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); [_unit, "forceWalk", "ACE_Attach", false] call EFUNC(common,statusEffect_set);
[_unit, "blockThrow", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); [_unit, "blockThrow", "ACE_Attach", false] call EFUNC(common,statusEffect_set);
[] call EFUNC(interaction,hideMouseHint); [] call EFUNC(interaction,hideMouseHint);
[_unit, "DefaultAction", (_unit getVariable [QGVAR(placeActionEH), -1])] call EFUNC(common,removeActionEventHandler); [_unit, "DefaultAction", (_unit getVariable [QGVAR(placeActionEH), -1])] call EFUNC(common,removeActionEventHandler);
_unit removeAction _actionID; _unit removeAction _actionID;

View File

@ -28,7 +28,7 @@ if (_attachedList isEqualTo []) exitWith {};
TRACE_2("detaching",_xObject,_deadUnit); TRACE_2("detaching",_xObject,_deadUnit);
detach _xObject; detach _xObject;
//If it's a vehicle, also delete the attached //If it's a vehicle, also delete the attached
if !(_deadUnit isKindOf "CAManBase") then { if (!(_deadUnit isKindOf "CAManBase")) then {
_xObject setPos ((getPos _deadUnit) vectorAdd [0, 0, -1000]); _xObject setPos ((getPos _deadUnit) vectorAdd [0, 0, -1000]);
[{deleteVehicle (_this select 0)}, [_xObject], 2] call CBA_fnc_waitAndExecute; [{deleteVehicle (_this select 0)}, [_xObject], 2] call CBA_fnc_waitAndExecute;
}; };

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