mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
Merge branch 'missile_guidance_rewrite' into missile_gbu
This commit is contained in:
commit
a22714cbc3
@ -11,5 +11,8 @@ trim_trailing_whitespace = true
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.yml]
|
||||
indent_size = 2
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
|
9
.github/workflows/arma.yml
vendored
9
.github/workflows/arma.yml
vendored
@ -27,15 +27,6 @@ jobs:
|
||||
- name: Validate function headers
|
||||
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:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
68
.github/workflows/extensions.yml
vendored
68
.github/workflows/extensions.yml
vendored
@ -1,29 +1,65 @@
|
||||
name: Extensions
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
paths:
|
||||
- 'extensions/**'
|
||||
- 'extension/**'
|
||||
- 'Cargo.toml'
|
||||
- 'Cargo.lock'
|
||||
- '.github/workflows/extensions.yml'
|
||||
|
||||
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:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows-latest]
|
||||
|
||||
arrays: [
|
||||
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:
|
||||
- name: Checkout the source code
|
||||
uses: actions/checkout@v4
|
||||
- name: Build
|
||||
shell: cmd
|
||||
run: |
|
||||
cd extensions
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. && cmake --build .
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
- name: Install stable Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
name: ace3_extensions-${{ matrix.os }}-debug
|
||||
path: extensions/build
|
||||
target: ${{ matrix.arrays.os.target }}
|
||||
toolchain: stable
|
||||
default: true
|
||||
- name: Rust Cache
|
||||
uses: Swatinem/rust-cache@v2
|
||||
- name: Build
|
||||
run: cargo build --verbose
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ${{ matrix.arrays.os.target }}
|
||||
path: target/debug/ace.dll
|
||||
if-no-files-found: error
|
||||
retention-days: 30
|
||||
|
2
.github/workflows/hemtt.yml
vendored
2
.github/workflows/hemtt.yml
vendored
@ -33,6 +33,8 @@ jobs:
|
||||
xcopy /e /h /q pullrequest\addons addons\
|
||||
xcopy /e /h /q pullrequest\optionals optionals\
|
||||
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
|
||||
run: hemtt build
|
||||
- name: Rename build folder
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -2,8 +2,6 @@
|
||||
*.zip
|
||||
release/*
|
||||
releases/*
|
||||
extensions/vcproj32/*
|
||||
extensions/vcproj64/*
|
||||
.vscode/*
|
||||
hemtt
|
||||
hemtt.exe
|
||||
@ -20,4 +18,5 @@ CHANGELOG.md
|
||||
sqfvm.exe
|
||||
ArmaScriptCompiler.exe
|
||||
*.sqfc
|
||||
target/
|
||||
!extras/**/*.zip
|
||||
|
@ -34,32 +34,26 @@ workshop = [
|
||||
]
|
||||
|
||||
[hemtt.launch.spe]
|
||||
workshop = [
|
||||
"450814997", # CBA_A3
|
||||
]
|
||||
extends = "default"
|
||||
dlc = [
|
||||
"spe"
|
||||
]
|
||||
|
||||
[hemtt.launch.vn]
|
||||
workshop = [
|
||||
"450814997", # CBA_A3's Workshop ID
|
||||
]
|
||||
extends = "default"
|
||||
dlc = [
|
||||
"S.O.G. Prairie Fire",
|
||||
]
|
||||
|
||||
[hemtt.launch.ws]
|
||||
workshop = [
|
||||
"450814997", # CBA_A3's Workshop ID
|
||||
]
|
||||
extends = "default"
|
||||
dlc = [
|
||||
"Western Sahara",
|
||||
]
|
||||
|
||||
[hemtt.launch.rhs]
|
||||
extends = "default"
|
||||
workshop = [
|
||||
"450814997", # CBA_A3's Workshop ID
|
||||
"843425103", # RHS AFRF Workshop ID
|
||||
"843577117", # RHS USAF Workshop ID
|
||||
"843593391", # RHS GREF Workshop ID
|
||||
|
1364
Cargo.lock
generated
Normal file
1364
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
11
Cargo.toml
Normal file
11
Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
"extension"
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
opt-level = "z"
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
strip = true
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
ace_fcs.dll
BIN
ace_fcs.dll
Binary file not shown.
BIN
ace_fcs_x64.dll
BIN
ace_fcs_x64.dll
Binary file not shown.
BIN
ace_x64.dll
Normal file
BIN
ace_x64.dll
Normal file
Binary file not shown.
@ -1,10 +1,10 @@
|
||||
#include "script_component.hpp"
|
||||
|
||||
GVAR(currentbulletID) = -1;
|
||||
#include "initKeybinds.inc.sqf"
|
||||
|
||||
GVAR(Protractor) = false;
|
||||
GVAR(ProtractorStart) = CBA_missionTime;
|
||||
GVAR(allBullets) = [];
|
||||
GVAR(allBullets) = createHashMap;
|
||||
GVAR(currentGrid) = 0;
|
||||
|
||||
if (!hasInterface) exitWith {};
|
||||
@ -24,22 +24,6 @@ if (!hasInterface) exitWith {};
|
||||
|
||||
// Register Perframe Handler
|
||||
[LINKFUNC(handleFirePFH), GVAR(simulationInterval)] call CBA_fnc_addPerFrameHandler;
|
||||
|
||||
//Add warnings for missing compat PBOs (only if AB is on)
|
||||
{
|
||||
_x params ["_modPBO", "_compatPBO"];
|
||||
if ([_modPBO] call EFUNC(common,isModLoaded) && {!([_compatPBO] call EFUNC(common,isModLoaded))}) then {
|
||||
WARNING_2("Weapon Mod [%1] missing ace compat pbo [%2] (from @ace\optionals)",_modPBO,_compatPBO);
|
||||
};
|
||||
} forEach [
|
||||
["RH_acc","ace_compat_rh_acc"],
|
||||
["RH_de_cfg","ace_compat_rh_de"],
|
||||
["RH_m4_cfg","ace_compat_rh_m4"],
|
||||
["RH_PDW","ace_compat_rh_pdw"],
|
||||
["RKSL_PMII","ace_compat_rksl_pm_ii"],
|
||||
["iansky_opt","ace_compat_sma3_iansky"],
|
||||
["R3F_Armes","ace_compat_r3f"]
|
||||
];
|
||||
}] call CBA_fnc_addEventHandler;
|
||||
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
|
@ -18,10 +18,3 @@ class CfgPatches {
|
||||
#include "CfgVehicles.hpp"
|
||||
#include "RscTitles.hpp"
|
||||
#include "ACE_Settings.hpp"
|
||||
|
||||
class ACE_Extensions {
|
||||
class ace_advanced_ballistics {
|
||||
windows = 1;
|
||||
client = 1;
|
||||
};
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "..\script_component.hpp"
|
||||
/*
|
||||
* Author: Glowbal, Ruthberg, joko // Jonas
|
||||
* Author: Glowbal, Ruthberg, joko // Jonas, Brett Mayson
|
||||
* Handle the PFH for Bullets
|
||||
*
|
||||
* Arguments:
|
||||
@ -17,7 +17,7 @@
|
||||
|
||||
private _deleted = false;
|
||||
{
|
||||
_x params ["_bullet","_caliber","_bulletTraceVisible","_index"];
|
||||
_y params ["_bullet","_caliber","_bulletTraceVisible"];
|
||||
|
||||
if (alive _bullet) then {
|
||||
private _bulletVelocity = velocity _bullet;
|
||||
@ -27,13 +27,21 @@ 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,"","",""];
|
||||
};
|
||||
|
||||
_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 {
|
||||
GVAR(allBullets) set [_forEachIndex, objNull];
|
||||
_deleted = true;
|
||||
GVAR(allBullets) deleteAt _x;
|
||||
"ace" callExtension ["ballistics:bullet:delete", [_x]];
|
||||
};
|
||||
} forEach GVAR(allBullets);
|
||||
|
||||
if (_deleted) then {
|
||||
GVAR(allBullets) = GVAR(allBullets) - [objNull];
|
||||
};
|
||||
} forEach GVAR(allBullets)
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "..\script_component.hpp"
|
||||
/*
|
||||
* Author: Glowbal, Ruthberg
|
||||
* Author: Glowbal, Ruthberg, Brett Mayson
|
||||
*
|
||||
* 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"];
|
||||
TRACE_10("firedEH:",_unit,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile,_vehicle,_gunner,_turret);
|
||||
|
||||
if (!(_ammo isKindOf "BulletBase")) exitWith {};
|
||||
if !(_ammo isKindOf "BulletBase") exitWith {};
|
||||
if (!alive _projectile) exitWith {};
|
||||
if (underwater _unit) exitWith {};
|
||||
|
||||
@ -62,11 +62,11 @@ if (_abort) exitWith {};
|
||||
// Get Weapon and Ammo Configurations
|
||||
private _AmmoCacheEntry = uiNamespace getVariable format[QGVAR(%1), _ammo];
|
||||
if (isNil "_AmmoCacheEntry") then {
|
||||
_AmmoCacheEntry = _ammo call FUNC(readAmmoDataFromConfig);
|
||||
_AmmoCacheEntry = _ammo call FUNC(readAmmoDataFromConfig);
|
||||
};
|
||||
private _WeaponCacheEntry = uiNamespace getVariable format[QGVAR(%1), _weapon];
|
||||
if (isNil "_WeaponCacheEntry") then {
|
||||
_WeaponCacheEntry = _weapon call FUNC(readWeaponDataFromConfig);
|
||||
_WeaponCacheEntry = _weapon call FUNC(readWeaponDataFromConfig);
|
||||
};
|
||||
|
||||
_AmmoCacheEntry params ["_airFriction", "_caliber", "_bulletLength", "_bulletMass", "_transonicStabilityCoef", "_dragModel", "_ballisticCoefficients", "_velocityBoundaries", "_atmosphereModel", "_ammoTempMuzzleVelocityShifts", "_muzzleVelocityTable", "_barrelLengthTable", "_muzzleVelocityVariationSD"];
|
||||
@ -120,8 +120,26 @@ if (_caliber * _bulletLength * _bulletMass * _barrelTwist > 0) then {
|
||||
_stabilityFactor = [_caliber, _bulletLength, _bulletMass, _barrelTwist, _muzzleVelocity, _temperature, _barometricPressure] call FUNC(calculateStabilityFactor);
|
||||
};
|
||||
|
||||
GVAR(currentbulletID) = (GVAR(currentbulletID) + 1) % 10000;
|
||||
|
||||
"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];
|
||||
|
||||
GVAR(allBullets) pushBack [_projectile, _caliber, _bulletTraceVisible, GVAR(currentbulletID)];
|
||||
("ace" callExtension [
|
||||
"ballistics:bullet:new", [
|
||||
_ammoCount,
|
||||
_airFriction,
|
||||
_ballisticCoefficients,
|
||||
_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]];
|
||||
};
|
||||
|
@ -21,7 +21,14 @@ if (!GVAR(enabled)) exitWith {};
|
||||
private _initStartTime = diag_tickTime;
|
||||
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);
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
systemChat "AdvancedBallistics: Terrain already initialized";
|
||||
@ -53,8 +60,7 @@ INFO_2("Starting Terrain Extension [cells: %1] [world: %2]",_gridCells,worldName
|
||||
private _gridCenter = [_x + 25, _y + 25];
|
||||
private _gridHeight = round(getTerrainHeightASL _gridCenter);
|
||||
private _gridNumObjects = count (_gridCenter nearObjects ["Building", 50]);
|
||||
private _gridSurfaceIsWater = parseNumber (surfaceIsWater _gridCenter);
|
||||
"ace_advanced_ballistics" callExtension format["set:%1:%2:%3", _gridHeight, _gridNumObjects, _gridSurfaceIsWater];
|
||||
"ace" callExtension ["ballistics:map:set", [GVAR(currentGrid), _gridHeight, _gridNumObjects, surfaceIsWater _gridCenter]];
|
||||
GVAR(currentGrid) = GVAR(currentGrid) + 1;
|
||||
if (GVAR(currentGrid) >= _gridCells) exitWith {};
|
||||
};
|
||||
|
@ -40,7 +40,7 @@ if (_transonicStabilityCoef == 0) then {
|
||||
_transonicStabilityCoef = 0.5;
|
||||
};
|
||||
private _dragModel = getNumber(_ammoConfig >> "ACE_dragModel");
|
||||
if (!(_dragModel in [1, 2, 5, 6, 7, 8])) then {
|
||||
if !(_dragModel in [1, 2, 5, 6, 7, 8]) then {
|
||||
_dragModel = 1;
|
||||
};
|
||||
private _ballisticCoefficients = getArray(_ammoConfig >> "ACE_ballisticCoefficients");
|
||||
|
@ -5,7 +5,9 @@ private _category = format ["ACE %1", localize LSTRING(DisplayName)];
|
||||
[LSTRING(enabled_DisplayName), LSTRING(enabled_Description)],
|
||||
_category,
|
||||
false,
|
||||
1
|
||||
1,
|
||||
{[QGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged)},
|
||||
true // Needs mission restart
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
[
|
||||
@ -45,5 +47,7 @@ private _category = format ["ACE %1", localize LSTRING(DisplayName)];
|
||||
[LSTRING(simulationInterval_DisplayName), LSTRING(simulationInterval_Description)],
|
||||
_category,
|
||||
[0, 0.2, 0.05, 2],
|
||||
1
|
||||
1,
|
||||
{[QGVAR(simulationInterval), _this] call EFUNC(common,cbaSettings_settingChanged)},
|
||||
true // Needs mission restart
|
||||
] call CBA_fnc_addSetting;
|
||||
|
@ -9,3 +9,5 @@ PREP(handleStaminaBar);
|
||||
PREP(mainLoop);
|
||||
PREP(moduleSettings);
|
||||
PREP(removeDutyFactor);
|
||||
PREP(renderDebugLines);
|
||||
PREP(updateStaminaBar);
|
||||
|
@ -2,6 +2,10 @@
|
||||
|
||||
if (!hasInterface) exitWith {};
|
||||
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
call FUNC(renderDebugLines);
|
||||
#endif
|
||||
|
||||
// recheck weapon inertia after weapon swap, change of attachments or switching unit
|
||||
["weapon", {[ACE_player] call FUNC(getWeaponInertia)}, true] call CBA_fnc_addPlayerEventHandler;
|
||||
["loadout", {[ACE_player] call FUNC(getWeaponInertia)}, true] call CBA_fnc_addPlayerEventHandler;
|
||||
@ -10,6 +14,8 @@ if (!hasInterface) exitWith {};
|
||||
["CBA_settingsInitialized", {
|
||||
if (!GVAR(enabled)) exitWith {};
|
||||
|
||||
[QEGVAR(ui,hideHud), LINKFUNC(updateStaminaBar)] call CBA_fnc_addEventHandler;
|
||||
|
||||
["baseline", {
|
||||
private _fatigue = ACE_player getVariable [QGVAR(aimFatigue), 0];
|
||||
switch (stance ACE_player) do {
|
||||
@ -33,25 +39,23 @@ if (!hasInterface) exitWith {};
|
||||
GVAR(ppeBlackout) ppEffectCommit 0.4;
|
||||
|
||||
// - GVAR updating and initialization -----------------------------------------
|
||||
["unit", LINKFUNC(handlePlayerChanged), true] call CBA_fnc_addPlayerEventHandler;
|
||||
["unit", LINKFUNC(handlePlayerChanged)] call CBA_fnc_addPlayerEventHandler;
|
||||
|
||||
["visibleMap", {
|
||||
params ["", "_visibleMap"]; // command visibleMap is updated one frame later
|
||||
private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull];
|
||||
_staminaBarContainer ctrlShow ((!_visibleMap) && {(vehicle ACE_player) == ACE_player});
|
||||
(uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull]) ctrlShow (!_visibleMap && isNull objectParent ACE_player);
|
||||
}, true] call CBA_fnc_addPlayerEventHandler;
|
||||
["vehicle", {
|
||||
private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull];
|
||||
_staminaBarContainer ctrlShow ((!visibleMap) && {(vehicle ACE_player) == ACE_player});
|
||||
(uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull]) ctrlShow (!visibleMap && isNull objectParent ACE_player);
|
||||
}, true] call CBA_fnc_addPlayerEventHandler;
|
||||
|
||||
// - Duty factors -------------------------------------------------------------
|
||||
if (GVAR(medicalLoaded)) then {
|
||||
if (GETEGVAR(medical,enabled,false)) then {
|
||||
[QEGVAR(medical,pain), { // 0->1.0, 0.5->1.05, 1->1.1
|
||||
linearConversion [0, 1, (_this getVariable [QEGVAR(medical,pain), 0]), 1, 1.1, true];
|
||||
linearConversion [0, 1, _this getVariable [QEGVAR(medical,pain), 0], 1, 1.1, true];
|
||||
}] call FUNC(addDutyFactor);
|
||||
[QEGVAR(medical,bloodVolume), { // 6->1.0, 5->1.167, 4->1.33
|
||||
linearConversion [6, 0, (_this getVariable [QEGVAR(medical,bloodVolume), 6]), 1, 2, true];
|
||||
linearConversion [6, 0, _this getVariable [QEGVAR(medical,bloodVolume), 6], 1, 2, true];
|
||||
}] call FUNC(addDutyFactor);
|
||||
};
|
||||
if (["ace_dragging"] call EFUNC(common,isModLoaded)) then {
|
||||
@ -62,7 +66,7 @@ if (!hasInterface) exitWith {};
|
||||
// Weather has an off switch, Dragging & Medical don't.
|
||||
if (missionNamespace getVariable [QEGVAR(weather,enabled), false]) then {
|
||||
[QEGVAR(weather,temperature), { // 35->1, 45->2
|
||||
linearConversion [35, 45, (missionNamespace getVariable [QEGVAR(weather,currentTemperature), 25]), 1, 2, true];
|
||||
linearConversion [35, 45, missionNamespace getVariable [QEGVAR(weather,currentTemperature), 25], 1, 2, true];
|
||||
}] call FUNC(addDutyFactor);
|
||||
};
|
||||
|
||||
|
@ -13,6 +13,5 @@ GVAR(dutyList) = createHashMap;
|
||||
GVAR(setAnimExclusions) = [];
|
||||
GVAR(inertia) = 0;
|
||||
GVAR(inertiaCache) = createHashMap;
|
||||
GVAR(medicalLoaded) = ["ace_medical"] call EFUNC(common,isModLoaded);
|
||||
|
||||
ADDON = true;
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "..\script_component.hpp"
|
||||
/*
|
||||
* Author: BaerMitUmlaut
|
||||
* Calculates the duty of the current animation.
|
||||
* Calculates the duty ('postureWeight') of the current animation.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Unit <OBJECT>
|
||||
|
@ -1,54 +1,74 @@
|
||||
#include "..\script_component.hpp"
|
||||
/*
|
||||
* Author: BaerMitUmlaut
|
||||
* Calculates the current metabolic costs for a unit.
|
||||
* Author: BaerMitUmlaut, ulteq
|
||||
* Calculates the current metabolic costs.
|
||||
* Calculation is done according to the Pandolf/Wojtowicz formulas.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Unit <OBJECT>
|
||||
* 1: Speed <NUMBER>
|
||||
* 0: Duty of animation
|
||||
* 1: Mass of unit <NUMBER>
|
||||
* 2: Terrain gradient <NUMBER>
|
||||
* 3: Terrain factor <NUMBER>
|
||||
* 4: Speed <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* Metabolic cost <NUMBER>
|
||||
*
|
||||
* Example:
|
||||
* [player, 3.3] call ace_advanced_fatigue_fnc_getMetabolicCosts
|
||||
* [1, 840, 20, 1, 4] call ace_advanced_fatigue_fnc_getMetabolicCosts
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
params ["_unit", "_velocity"];
|
||||
|
||||
private _gearMass = ((_unit getVariable [QEGVAR(movement,totalLoad), loadAbs _unit]) / 22.046) * GVAR(loadFactor);
|
||||
|
||||
private _terrainAngle = asin (1 - ((surfaceNormal getPosASL _unit) select 2));
|
||||
private _terrainGradient = (_terrainAngle / 45 min 1) * 5 * GVAR(terrainGradientFactor);
|
||||
private _duty = GVAR(animDuty);
|
||||
|
||||
{
|
||||
if (_x isEqualType 0) then {
|
||||
_duty = _duty * _x;
|
||||
} else {
|
||||
_duty = _duty * (_unit call _x);
|
||||
};
|
||||
} forEach (values GVAR(dutyList));
|
||||
|
||||
if (GVAR(isSwimming)) then {
|
||||
_terrainGradient = 0;
|
||||
};
|
||||
params ["_duty", "_gearMass", "_terrainGradient", "_terrainFactor", "_speed"];
|
||||
|
||||
// Metabolic cost for walking and running is different
|
||||
if (_velocity > 2) then {
|
||||
if (_speed > 2) then {
|
||||
// Running
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
private _baseline = 2.1 * SIM_BODYMASS + 4 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + (SIM_BODYMASS + _gearMass) * 0.9 * (_speed ^ 2);
|
||||
private _graded = 2.1 * SIM_BODYMASS + 4 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + _terrainFactor * (SIM_BODYMASS + _gearMass) * (0.9 * (_speed ^ 2) + 0.66 * _speed * _terrainGradient);
|
||||
private _terrainImpact = abs ((_graded / _baseline) - 1);
|
||||
hintSilent format ["FwdAngle: %1 | SideAngle: %2 \n TerrainFactor: %3 | TerrainGradient: %4 \n TerrainImpact: %5 \n Speed: %6 | CarriedLoad: %7 \n Duty: %8 | Work: %9",
|
||||
_fwdAngle toFixed 1,
|
||||
_sideAngle toFixed 1,
|
||||
_terrainFactor toFixed 2,
|
||||
_terrainGradient toFixed 1,
|
||||
_terrainImpact toFixed 2,
|
||||
_speed toFixed 2,
|
||||
_gearMass toFixed 1,
|
||||
_duty toFixed 2,
|
||||
round (_graded * BIOMECH_EFFICIENCY * _duty)
|
||||
];
|
||||
#endif
|
||||
|
||||
(
|
||||
2.10 * SIM_BODYMASS
|
||||
2.1 * SIM_BODYMASS
|
||||
+ 4 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2)
|
||||
+ (SIM_BODYMASS + _gearMass) * (0.9 * (_velocity ^ 2) + 0.66 * _velocity * _terrainGradient)
|
||||
) * 0.23 * _duty
|
||||
+ _terrainFactor * (SIM_BODYMASS + _gearMass) * (0.9 * (_speed ^ 2) + 0.66 * _speed * _terrainGradient)
|
||||
) * BIOMECH_EFFICIENCY * _duty
|
||||
} else {
|
||||
// Walking
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
private _baseline = 1.05 * SIM_BODYMASS + 2 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + (SIM_BODYMASS + _gearMass) * 1.15 * (_speed ^ 2);
|
||||
private _graded = 1.05 * SIM_BODYMASS + 2 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + _terrainFactor * (SIM_BODYMASS + _gearMass) * (1.15 * (_speed ^ 2) + 0.66 * _speed * _terrainGradient);
|
||||
private _terrainImpact = abs ((_graded / _baseline) - 1);
|
||||
hintSilent format ["FwdAngle: %1 | SideAngle: %2 \n TerrainFactor: %3 | TerrainGradient: %4 \n TerrainImpact: %5 \n Speed: %6 | CarriedLoad: %7 \n Duty: %8 | Work: %9",
|
||||
_fwdAngle toFixed 1,
|
||||
_sideAngle toFixed 1,
|
||||
_terrainFactor toFixed 2,
|
||||
_terrainGradient toFixed 1,
|
||||
_terrainImpact toFixed 2,
|
||||
_speed toFixed 2,
|
||||
_gearMass toFixed 1,
|
||||
_duty toFixed 2,
|
||||
round (_graded * BIOMECH_EFFICIENCY * _duty)
|
||||
];
|
||||
#endif
|
||||
|
||||
(
|
||||
1.05 * SIM_BODYMASS
|
||||
+ 2 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2)
|
||||
+ (SIM_BODYMASS + _gearMass) * (1.15 * (_velocity ^ 2) + 0.66 * _velocity * _terrainGradient)
|
||||
) * 0.23 * _duty
|
||||
+ _terrainFactor * (SIM_BODYMASS + _gearMass) * (1.15 * (_speed ^ 2) + 0.66 * _speed * _terrainGradient)
|
||||
) * BIOMECH_EFFICIENCY * _duty
|
||||
};
|
||||
|
@ -1,44 +1,44 @@
|
||||
#include "..\script_component.hpp"
|
||||
/*
|
||||
* Author: BaerMitUmlaut
|
||||
* Author: BaerMitUmlaut, ulteq
|
||||
* Handles any audible, visual and physical effects of fatigue.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Unit <OBJECT>
|
||||
* 1: Fatigue <NUMBER>
|
||||
* 2: Speed <NUMBER>
|
||||
* 3: Overexhausted <BOOL>
|
||||
* 2: Overexhausted <BOOL>
|
||||
* 3: Forward Angle <NUMBER>
|
||||
* 4: Side Angle <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [_player, 0.5, 3.3, true] call ace_advanced_fatigue_fnc_handleEffects
|
||||
* [_player, 0.5, 3.3, true, 0, 0] call ace_advanced_fatigue_fnc_handleEffects
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
params ["_unit", "_fatigue", "_speed", "_overexhausted"];
|
||||
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
systemChat str _fatigue;
|
||||
systemChat str vectorMagnitude velocity _unit;
|
||||
#endif
|
||||
params ["_unit", "_fatigue", "_overexhausted", "_fwdAngle", "_sideAngle"];
|
||||
|
||||
// - Audible effects ----------------------------------------------------------
|
||||
GVAR(lastBreath) = GVAR(lastBreath) + 1;
|
||||
|
||||
if (_fatigue > 0.4 && {GVAR(lastBreath) > (_fatigue * -10 + 9)} && {!underwater _unit}) then {
|
||||
if (!isGameFocused) exitWith {};
|
||||
|
||||
switch (true) do {
|
||||
case (_fatigue < 0.6): {
|
||||
playSound (QGVAR(breathLow) + str(floor random 6));
|
||||
playSound (QGVAR(breathLow) + str (floor random 6));
|
||||
};
|
||||
case (_fatigue < 0.85): {
|
||||
playSound (QGVAR(breathMid) + str(floor random 6));
|
||||
playSound (QGVAR(breathMid) + str (floor random 6));
|
||||
};
|
||||
default {
|
||||
playSound (QGVAR(breathMax) + str(floor random 6));
|
||||
playSound (QGVAR(breathMax) + str (floor random 6));
|
||||
};
|
||||
};
|
||||
|
||||
GVAR(lastBreath) = 0;
|
||||
};
|
||||
|
||||
@ -62,31 +62,35 @@ if (GVAR(isSwimming)) exitWith {
|
||||
if (GVAR(setAnimExclusions) isEqualTo []) then {
|
||||
_unit setAnimSpeedCoef linearConversion [0.7, 0.9, _fatigue, 1, 0.5, true];
|
||||
};
|
||||
if ((isSprintAllowed _unit) && {_fatigue > 0.7}) then {
|
||||
|
||||
if (isSprintAllowed _unit && _fatigue > 0.7) then { // small checks like these are faster without lazy eval
|
||||
[_unit, "blockSprint", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
|
||||
} else {
|
||||
if ((!isSprintAllowed _unit) && {_fatigue < 0.7}) then {
|
||||
if (!isSprintAllowed _unit && _fatigue < 0.7) then {
|
||||
[_unit, "blockSprint", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
|
||||
};
|
||||
};
|
||||
};
|
||||
if ((getAnimSpeedCoef _unit) != 1) then {
|
||||
if (GVAR(setAnimExclusions) isEqualTo []) then {
|
||||
TRACE_1("reset",getAnimSpeedCoef _unit);
|
||||
_unit setAnimSpeedCoef 1;
|
||||
};
|
||||
|
||||
// If other components are setting setAnimSpeedCoef, do not change animSpeedCoef
|
||||
if (getAnimSpeedCoef _unit != 1 && {GVAR(setAnimExclusions) isEqualTo []}) then {
|
||||
TRACE_1("reset",getAnimSpeedCoef _unit);
|
||||
_unit setAnimSpeedCoef 1;
|
||||
};
|
||||
|
||||
if (_overexhausted) then {
|
||||
if (!isForcedWalk _unit && _fatigue >= 1) then { // small checks like these are faster without lazy eval
|
||||
[_unit, "forceWalk", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "blockSprint", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
|
||||
} else {
|
||||
if (isForcedWalk _unit && {_fatigue < 0.7}) then {
|
||||
if (isForcedWalk _unit && _fatigue < 0.7) then {
|
||||
[_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "blockSprint", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
|
||||
} else {
|
||||
if ((isSprintAllowed _unit) && {_fatigue > 0.7}) then {
|
||||
// Forward angle is the slope of the terrain, side angle simulates the unevenness/roughness of the terrain
|
||||
if (isSprintAllowed _unit && {_fatigue > 0.7 || abs _fwdAngle > 20 || abs _sideAngle > 20}) then {
|
||||
[_unit, "blockSprint", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
|
||||
} else {
|
||||
if ((!isSprintAllowed _unit) && {_fatigue < 0.6}) then {
|
||||
if (!isSprintAllowed _unit && _fatigue < 0.6 && abs _fwdAngle < 20 && abs _sideAngle < 20) then {
|
||||
[_unit, "blockSprint", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
|
||||
};
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "..\script_component.hpp"
|
||||
/*
|
||||
* Author: BaerMitUmlaut
|
||||
* Handles switching units (once on init and afterwards via Zeus).
|
||||
* Author: BaerMitUmlaut, ulteq
|
||||
* Handles switching units (once on init and afterwards via Zeus). Also handles CBA setting change for performance factor.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: New Unit <OBJECT>
|
||||
@ -15,20 +15,24 @@
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params ["_newUnit", "_oldUnit"];
|
||||
|
||||
TRACE_2("unit changed",_newUnit,_oldUnit);
|
||||
|
||||
if !(isNull _oldUnit) then {
|
||||
if (!isNull _oldUnit) then {
|
||||
TRACE_1("remove old",_oldUnit getVariable QGVAR(animHandler));
|
||||
|
||||
_oldUnit enableStamina true;
|
||||
_oldUnit removeEventHandler ["AnimChanged", _oldUnit getVariable [QGVAR(animHandler), -1]];
|
||||
_oldUnit setVariable [QGVAR(animHandler), nil];
|
||||
TRACE_1("remove old",_oldUnit getVariable QGVAR(animHandler));
|
||||
|
||||
_oldUnit setVariable [QGVAR(ae1Reserve), GVAR(ae1Reserve)];
|
||||
_oldUnit setVariable [QGVAR(ae2Reserve), GVAR(ae2Reserve)];
|
||||
_oldUnit setVariable [QGVAR(anReserve), GVAR(anReserve)];
|
||||
_oldUnit setVariable [QGVAR(anFatigue), GVAR(anFatigue)];
|
||||
_oldUnit setVariable [QGVAR(muscleDamage), GVAR(muscleDamage)];
|
||||
_oldUnit setVariable [QGVAR(respiratoryRate), GVAR(respiratoryRate)];
|
||||
};
|
||||
|
||||
_newUnit enableStamina false;
|
||||
@ -38,6 +42,7 @@ if (_newUnit getVariable [QGVAR(animHandler), -1] == -1) then {
|
||||
private _animHandler = _newUnit addEventHandler ["AnimChanged", {
|
||||
GVAR(animDuty) = _this call FUNC(getAnimDuty);
|
||||
}];
|
||||
|
||||
TRACE_1("add new",_animHandler);
|
||||
_newUnit setVariable [QGVAR(animHandler), _animHandler];
|
||||
};
|
||||
@ -47,18 +52,27 @@ GVAR(ae2Reserve) = _newUnit getVariable [QGVAR(ae2Reserve), AE2_MAXRESERVE]
|
||||
GVAR(anReserve) = _newUnit getVariable [QGVAR(anReserve), AN_MAXRESERVE];
|
||||
GVAR(anFatigue) = _newUnit getVariable [QGVAR(anFatigue), 0];
|
||||
GVAR(muscleDamage) = _newUnit getVariable [QGVAR(muscleDamage), 0];
|
||||
GVAR(respiratoryRate) = _newUnit getVariable [QGVAR(respiratoryRate), 0];
|
||||
|
||||
// Clean variables for respawning units
|
||||
{
|
||||
_newUnit setVariable [_x, nil];
|
||||
} forEach [QGVAR(ae1Reserve), QGVAR(ae2Reserve), QGVAR(anReserve), QGVAR(anFatigue), QGVAR(muscleDamage)];
|
||||
} forEach [QGVAR(ae1Reserve), QGVAR(ae2Reserve), QGVAR(anReserve), QGVAR(anFatigue), QGVAR(muscleDamage), QGVAR(respiratoryRate)];
|
||||
|
||||
GVAR(VO2Max) = 35 + 20 * (_newUnit getVariable [QGVAR(performanceFactor), GVAR(performanceFactor)]);
|
||||
GVAR(VO2MaxPower) = GVAR(VO2Max) * SIM_BODYMASS * 0.23 * JOULES_PER_ML_O2 / 60;
|
||||
GVAR(VO2MaxPower) = GVAR(VO2Max) * SIM_BODYMASS * BIOMECH_EFFICIENCY * JOULES_PER_ML_O2 / 60;
|
||||
GVAR(peakPower) = VO2MAX_STRENGTH * GVAR(VO2MaxPower);
|
||||
|
||||
GVAR(ae1PathwayPower) = GVAR(peakPower) / (13.3 + 16.7 + 113.3) * 13.3 * ANTPERCENT ^ 1.28 * 1.362;
|
||||
GVAR(ae2PathwayPower) = GVAR(peakPower) / (13.3 + 16.7 + 113.3) * 16.7 * ANTPERCENT ^ 1.28 * 1.362;
|
||||
GVAR(ae1PathwayPower) = GVAR(peakPower) / (AE1_ATP_RELEASE_RATE + AE2_ATP_RELEASE_RATE + AN_ATP_RELEASE_RATE) * AE1_ATP_RELEASE_RATE * ANTPERCENT ^ 1.28 * 1.362;
|
||||
GVAR(ae2PathwayPower) = GVAR(peakPower) / (AE1_ATP_RELEASE_RATE + AE2_ATP_RELEASE_RATE + AN_ATP_RELEASE_RATE) * AE2_ATP_RELEASE_RATE * ANTPERCENT ^ 1.28 * 1.362;
|
||||
GVAR(aePathwayPower) = GVAR(ae1PathwayPower) + GVAR(ae2PathwayPower);
|
||||
GVAR(anPathwayPower) = GVAR(peakPower) - GVAR(aePathwayPower);
|
||||
|
||||
GVAR(aeWattsPerATP) = GVAR(ae1PathwayPower) / AE1_ATP_RELEASE_RATE;
|
||||
GVAR(anWattsPerATP) = GVAR(anPathwayPower) / AN_ATP_RELEASE_RATE;
|
||||
|
||||
GVAR(respiratoryBufferDivisor) = (RESPIRATORY_BUFFER - 1) / RESPIRATORY_BUFFER;
|
||||
GVAR(maxPowerFatigueRatio) = 0.057 / GVAR(peakPower);
|
||||
|
||||
GVAR(ppeBlackoutLast) = 100;
|
||||
GVAR(lastBreath) = 0;
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "..\script_component.hpp"
|
||||
/*
|
||||
* Author: BaerMitUmlaut
|
||||
* Author: BaerMitUmlaut, ulteq
|
||||
* Main looping function that updates fatigue values.
|
||||
*
|
||||
* Arguments:
|
||||
@ -17,73 +17,131 @@
|
||||
|
||||
// Dead people don't breathe, will also handle null (map intros)
|
||||
if (!alive ACE_player) exitWith {
|
||||
[FUNC(mainLoop), [], 1] call CBA_fnc_waitAndExecute;
|
||||
[LINKFUNC(mainLoop), [], 1] call CBA_fnc_waitAndExecute;
|
||||
|
||||
private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull];
|
||||
_staminaBarContainer ctrlSetFade 1;
|
||||
_staminaBarContainer ctrlCommit 1;
|
||||
};
|
||||
|
||||
|
||||
private _oxygen = 0.9; // Default AF oxygen saturation
|
||||
if (GVAR(medicalLoaded) && {EGVAR(medical_vitals,simulateSpo2)}) then {
|
||||
_oxygen = (ACE_player getVariable [QEGVAR(medical,spo2), 97]) / 100;
|
||||
};
|
||||
private _velocity = velocity ACE_player;
|
||||
private _normal = surfaceNormal (getPosWorld ACE_player);
|
||||
private _movementVector = vectorNormalized _velocity;
|
||||
private _sideVector = vectorNormalized (_movementVector vectorCrossProduct _normal);
|
||||
private _fwdAngle = asin (_movementVector select 2);
|
||||
private _sideAngle = asin (_sideVector select 2);
|
||||
|
||||
private _currentWork = REE;
|
||||
private _currentSpeed = (vectorMagnitude (velocity ACE_player)) min 6;
|
||||
private _currentSpeed = (vectorMagnitude _velocity) min 6;
|
||||
|
||||
// fix #4481. Diving to the ground is recorded as PRONE stance with running speed velocity. Cap maximum speed to fix.
|
||||
if (GVAR(isProne)) then {
|
||||
_currentSpeed = _currentSpeed min 1.5;
|
||||
};
|
||||
|
||||
if ((vehicle ACE_player == ACE_player) && {_currentSpeed > 0.1} && {isTouchingGround ACE_player || {underwater ACE_player}}) then {
|
||||
_currentWork = [ACE_player, _currentSpeed] call FUNC(getMetabolicCosts);
|
||||
// Get the current duty
|
||||
private _duty = GVAR(animDuty);
|
||||
|
||||
{
|
||||
if (_x isEqualType 0) then {
|
||||
_duty = _duty * _x;
|
||||
} else {
|
||||
_duty = _duty * (ACE_player call _x);
|
||||
};
|
||||
} forEach (values GVAR(dutyList));
|
||||
|
||||
private _terrainGradient = abs _fwdAngle;
|
||||
private _terrainFactor = 1;
|
||||
private _gearMass = 0 max (((ACE_player getVariable [QEGVAR(movement,totalLoad), loadAbs ACE_player]) / 22.046 - UNDERWEAR_WEIGHT) * GVAR(loadFactor));
|
||||
|
||||
if (isNull objectParent ACE_player && {_currentSpeed > 0.1} && {isTouchingGround ACE_player || {underwater ACE_player}}) then {
|
||||
if (!GVAR(isSwimming)) then {
|
||||
// If the unit is going downhill, it's much less demanding
|
||||
if (_fwdAngle < 0) then {
|
||||
_terrainGradient = 0.15 * _terrainGradient;
|
||||
};
|
||||
|
||||
// Used to simulate the unevenness/roughness of the terrain
|
||||
if ((getPosATL ACE_player) select 2 < 0.01) then {
|
||||
private _sideGradient = abs (_sideAngle / 45) min 1;
|
||||
|
||||
_terrainFactor = 1 + _sideGradient ^ 4;
|
||||
};
|
||||
};
|
||||
|
||||
_currentWork = [_duty, _gearMass, _terrainGradient * GVAR(terrainGradientFactor), _terrainFactor, _currentSpeed] call FUNC(getMetabolicCosts);
|
||||
_currentWork = _currentWork max REE;
|
||||
};
|
||||
|
||||
// Oxygen calculation
|
||||
private _oxygen = if (GETEGVAR(medical,enabled,false) && {EGVAR(medical_vitals,simulateSpo2)}) then { // Defer to medical
|
||||
(ACE_player getVariable [QEGVAR(medical,spo2), 97]) / 100
|
||||
} else {
|
||||
1 - 0.131 * GVAR(respiratoryRate) ^ 2 // Default AF oxygen saturation
|
||||
};
|
||||
// Calculate muscle damage increase
|
||||
// Note: Muscle damage recovery is ignored as it takes multiple days
|
||||
GVAR(muscleDamage) = (GVAR(muscleDamage) + (_currentWork / GVAR(peakPower)) ^ 3.2 * 0.00004) min 1;
|
||||
private _muscleIntegritySqrt = sqrt (1 - GVAR(muscleDamage));
|
||||
GVAR(muscleDamage) = GVAR(muscleDamage) + (_currentWork / GVAR(peakPower)) ^ 3.2 * MUSCLE_TEAR_RATE;
|
||||
|
||||
// Calculate muscle damage recovery
|
||||
GVAR(muscleDamage) = 0 max (GVAR(muscleDamage) - MUSCLE_RECOVERY * GVAR(recoveryFactor)) min 1;
|
||||
private _muscleIntegrity = 1 - GVAR(muscleDamage);
|
||||
private _muscleFactor = sqrt _muscleIntegrity;
|
||||
|
||||
// Calculate available power
|
||||
private _ae1PathwayPowerFatigued = GVAR(ae1PathwayPower) * sqrt (GVAR(ae1Reserve) / AE1_MAXRESERVE) * _oxygen * _muscleIntegritySqrt;
|
||||
private _ae2PathwayPowerFatigued = GVAR(ae2PathwayPower) * sqrt (GVAR(ae2Reserve) / AE2_MAXRESERVE) * _oxygen * _muscleIntegritySqrt;
|
||||
private _ae1PathwayPowerFatigued = GVAR(ae1PathwayPower) * sqrt (GVAR(ae1Reserve) / AE1_MAXRESERVE) * _oxygen * _muscleFactor;
|
||||
private _ae2PathwayPowerFatigued = GVAR(ae2PathwayPower) * sqrt (GVAR(ae2Reserve) / AE2_MAXRESERVE) * _oxygen * _muscleFactor;
|
||||
private _aePathwayPowerFatigued = _ae1PathwayPowerFatigued + _ae2PathwayPowerFatigued;
|
||||
private _anPathwayPowerFatigued = GVAR(anPathwayPower) * sqrt (GVAR(anReserve) / AN_MAXRESERVE) * _oxygen * _muscleIntegrity;
|
||||
|
||||
// Calculate how much power is consumed from each reserve
|
||||
private _ae1Power = _currentWork min _ae1PathwayPowerFatigued;
|
||||
private _ae2Power = ((_currentWork - _ae1Power) max 0) min _ae2PathwayPowerFatigued;
|
||||
private _anPower = (_currentWork - _ae1Power - _ae2Power) max 0;
|
||||
private _ae2Power = (_currentWork - _ae1Power) min _ae2PathwayPowerFatigued;
|
||||
private _anPower = 0 max (_currentWork - _ae1Power - _ae2Power);
|
||||
|
||||
// Remove ATP from reserves for current work
|
||||
GVAR(ae1Reserve) = GVAR(ae1Reserve) - _ae1Power / WATTSPERATP;
|
||||
GVAR(ae2Reserve) = GVAR(ae2Reserve) - _ae2Power / WATTSPERATP;
|
||||
GVAR(anReserve) = GVAR(anReserve) - _anPower / WATTSPERATP;
|
||||
// Increase anearobic fatigue
|
||||
GVAR(anFatigue) = GVAR(anFatigue) + _anPower * (0.057 / GVAR(peakPower)) * 1.1;
|
||||
GVAR(ae1Reserve) = 0 max (GVAR(ae1Reserve) - _ae1Power / GVAR(aeWattsPerATP));
|
||||
GVAR(ae2Reserve) = 0 max (GVAR(ae2Reserve) - _ae2Power / GVAR(aeWattsPerATP));
|
||||
GVAR(anReserve) = 0 max (GVAR(anReserve) - _anPower / GVAR(anWattsPerATP));
|
||||
|
||||
// Acidosis accumulation
|
||||
GVAR(anFatigue) = GVAR(anFatigue) + _anPower * GVAR(maxPowerFatigueRatio) * 1.1;
|
||||
|
||||
// Aerobic ATP reserve recovery
|
||||
GVAR(ae1Reserve) = ((GVAR(ae1Reserve) + _oxygen * 6.60 * (GVAR(ae1PathwayPower) - _ae1Power) / GVAR(ae1PathwayPower) * GVAR(recoveryFactor)) min AE1_MAXRESERVE) max 0;
|
||||
GVAR(ae2Reserve) = ((GVAR(ae2Reserve) + _oxygen * 5.83 * (GVAR(ae2PathwayPower) - _ae2Power) / GVAR(ae2PathwayPower) * GVAR(recoveryFactor)) min AE2_MAXRESERVE) max 0;
|
||||
GVAR(ae1Reserve) = (GVAR(ae1Reserve) + _oxygen * GVAR(recoveryFactor) * AE1_ATP_RECOVERY * (GVAR(ae1PathwayPower) - _ae1Power) / GVAR(ae1PathwayPower)) min AE1_MAXRESERVE;
|
||||
GVAR(ae2Reserve) = (GVAR(ae2Reserve) + _oxygen * GVAR(recoveryFactor) * AE2_ATP_RECOVERY * (GVAR(ae2PathwayPower) - _ae2Power) / GVAR(ae2PathwayPower)) min AE2_MAXRESERVE;
|
||||
|
||||
// Anaerobic ATP reserver and fatigue recovery
|
||||
GVAR(anReserve) = ((GVAR(anReserve)
|
||||
+ (_ae1PathwayPowerFatigued + _ae2PathwayPowerFatigued - _ae1Power - _ae2Power) / GVAR(VO2MaxPower) * 56.7 * GVAR(anFatigue) ^ 2 * GVAR(recoveryFactor)
|
||||
) min AN_MAXRESERVE) max 0;
|
||||
private _aeSurplus = _ae1PathwayPowerFatigued + _ae2PathwayPowerFatigued - _ae1Power - _ae2Power;
|
||||
|
||||
GVAR(anFatigue) = ((GVAR(anFatigue)
|
||||
- (_ae1PathwayPowerFatigued + _ae2PathwayPowerFatigued - _ae1Power - _ae2Power) * (0.057 / GVAR(peakPower)) * GVAR(anFatigue) ^ 2 * GVAR(recoveryFactor)
|
||||
) min 1) max 0;
|
||||
// Anaerobic ATP reserve recovery
|
||||
GVAR(anReserve) = 0 max (GVAR(anReserve) + _aeSurplus / GVAR(VO2MaxPower) * AN_ATP_RECOVERY * GVAR(recoveryFactor) * (GVAR(anFatigue) max linearConversion [AN_MAXRESERVE, 0, GVAR(anReserve), 0, 0.75, true]) ^ 2) min AN_MAXRESERVE; // max linearConversion ensures that if GVAR(anFatigue) is very low, it will still regenerate reserves
|
||||
// Acidosis recovery
|
||||
GVAR(anFatigue) = 0 max (GVAR(anFatigue) - _aeSurplus * GVAR(maxPowerFatigueRatio) * GVAR(recoveryFactor) * GVAR(anFatigue) ^ 2) min 1;
|
||||
|
||||
// Respiratory rate decrease
|
||||
GVAR(respiratoryRate) = GVAR(respiratoryRate) * GVAR(respiratoryBufferDivisor);
|
||||
|
||||
// Respiratory rate increase
|
||||
private _aePowerRatio = (GVAR(aePathwayPower) / _aePathwayPowerFatigued) min 2;
|
||||
private _respiratorySampleDivisor = 1 / (RESPIRATORY_BUFFER * 4.72 * GVAR(VO2Max));
|
||||
GVAR(respiratoryRate) = (GVAR(respiratoryRate) + _currentWork * _respiratorySampleDivisor * _aePowerRatio) min 1;
|
||||
|
||||
// Calculate a pseudo-perceived fatigue, which is used for effects
|
||||
GVAR(aeReservePercentage) = (GVAR(ae1Reserve) / AE1_MAXRESERVE + GVAR(ae2Reserve) / AE2_MAXRESERVE) / 2;
|
||||
GVAR(anReservePercentage) = GVAR(anReserve) / AN_MAXRESERVE;
|
||||
private _perceivedFatigue = 1 - (GVAR(anReservePercentage) min GVAR(aeReservePercentage));
|
||||
|
||||
[ACE_player, _perceivedFatigue, _currentSpeed, GVAR(anReserve) == 0] call FUNC(handleEffects);
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
systemChat format ["---- muscleDamage: %1 ----", GVAR(muscleDamage) toFixed 8];
|
||||
systemChat format ["---- ae2: %1 - an: %2 ----", (GVAR(ae2Reserve) / AE2_MAXRESERVE) toFixed 2, (GVAR(anReserve) / AN_MAXRESERVE) toFixed 2];
|
||||
systemChat format ["---- anFatigue: %1 - perceivedFatigue: %2 ----", GVAR(anFatigue) toFixed 2, _perceivedFatigue toFixed 2];
|
||||
systemChat format ["---- velocity %1 - respiratoryRate: %2 ----", (vectorMagnitude _velocity) toFixed 2, GVAR(respiratoryRate) toFixed 2];
|
||||
// systemChat format ["---- aePower: %1 ----", _aePathwayPowerFatigued toFixed 1];
|
||||
#endif
|
||||
|
||||
if (GVAR(enableStaminaBar)) then {
|
||||
[ACE_player, _perceivedFatigue, GVAR(anReserve) == 0, _fwdAngle, _sideAngle] call FUNC(handleEffects);
|
||||
|
||||
if (GVAR(enableStaminaBarRealized)) then {
|
||||
[GVAR(anReserve) / AN_MAXRESERVE] call FUNC(handleStaminaBar);
|
||||
};
|
||||
|
||||
[FUNC(mainLoop), [], 1] call CBA_fnc_waitAndExecute;
|
||||
[LINKFUNC(mainLoop), [], 1] call CBA_fnc_waitAndExecute;
|
||||
|
40
addons/advanced_fatigue/functions/fnc_renderDebugLines.sqf
Normal file
40
addons/advanced_fatigue/functions/fnc_renderDebugLines.sqf
Normal file
@ -0,0 +1,40 @@
|
||||
#include "..\script_component.hpp"
|
||||
/*
|
||||
* Author: ulteq
|
||||
* Draw lines for debugging.
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* call ace_advanced_fatigue_fnc_renderDebugLines
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
addMissionEventHandler ["Draw3D", {
|
||||
private _normal = surfaceNormal (getPosWorld ACE_player);
|
||||
private _beg = (getPosWorld ACE_player) vectorAdd (_normal vectorMultiply 0.5);
|
||||
private _end = _beg vectorAdd (_normal vectorMultiply 2);
|
||||
drawLine3D [ASLToATL _beg, ASLToATL _end, [0, 1, 0, 1]];
|
||||
|
||||
private _side = vectorNormalized (_normal vectorCrossProduct [0, 0, 1]);
|
||||
private _end = _beg vectorAdd (_side vectorMultiply 2);
|
||||
drawLine3D [ASLToATL _beg, ASLToATL _end, [0, 0, 1, 1]];
|
||||
|
||||
private _up = vectorNormalized (_normal vectorCrossProduct _side);
|
||||
private _end = _beg vectorAdd (_up vectorMultiply 2);
|
||||
drawLine3D [ASLToATL _beg, ASLToATL _end, [1, 0, 0, 1]];
|
||||
|
||||
private _movementVector = vectorNormalized (velocity ACE_player);
|
||||
private _end = _beg vectorAdd (_movementVector vectorMultiply 2);
|
||||
drawLine3D [ASLToATL _beg, ASLToATL _end, [1, 1, 0, 1]];
|
||||
|
||||
private _sideVector = vectorNormalized (_movementVector vectorCrossProduct _normal);
|
||||
_sideVector set [2, 0];
|
||||
private _end = _beg vectorAdd (_sideVector vectorMultiply 2);
|
||||
drawLine3D [ASLToATL _beg, ASLToATL _end, [0, 1, 1, 1]];
|
||||
}];
|
25
addons/advanced_fatigue/functions/fnc_updateStaminaBar.sqf
Normal file
25
addons/advanced_fatigue/functions/fnc_updateStaminaBar.sqf
Normal file
@ -0,0 +1,25 @@
|
||||
#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;
|
@ -4,12 +4,9 @@
|
||||
[LSTRING(Enabled), LSTRING(Enabled_Description)],
|
||||
LSTRING(DisplayName),
|
||||
true,
|
||||
true, {
|
||||
if (!_this) then {
|
||||
private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull];
|
||||
_staminaBarContainer ctrlSetFade 1;
|
||||
_staminaBarContainer ctrlCommit 0;
|
||||
};
|
||||
1,
|
||||
{
|
||||
call FUNC(updateStaminaBar);
|
||||
[QGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged)
|
||||
},
|
||||
true // Needs mission restart
|
||||
@ -21,13 +18,8 @@
|
||||
[LSTRING(EnableStaminaBar), LSTRING(EnableStaminaBar_Description)],
|
||||
LSTRING(DisplayName),
|
||||
true,
|
||||
true, {
|
||||
if (!_this) then {
|
||||
private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull];
|
||||
_staminaBarContainer ctrlSetFade 1;
|
||||
_staminaBarContainer ctrlCommit 0;
|
||||
};
|
||||
}
|
||||
1,
|
||||
{call FUNC(updateStaminaBar)}
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
[
|
||||
@ -36,7 +28,8 @@
|
||||
[LSTRING(FadeStaminaBar), LSTRING(FadeStaminaBar_Description)],
|
||||
LSTRING(DisplayName),
|
||||
true,
|
||||
false, {
|
||||
0,
|
||||
{
|
||||
if (!_this && GVAR(enabled) && GVAR(enableStaminaBar)) then {
|
||||
private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull];
|
||||
_staminaBarContainer ctrlSetFade 0;
|
||||
@ -50,8 +43,14 @@
|
||||
"SLIDER",
|
||||
[LSTRING(PerformanceFactor), LSTRING(PerformanceFactor_Description)],
|
||||
LSTRING(DisplayName),
|
||||
[0, 5, 1, 1],
|
||||
true
|
||||
[0, 10, 1, 2],
|
||||
1,
|
||||
{
|
||||
// Recalculate values if the setting is changed mid-mission
|
||||
if (GVAR(enabled) && hasInterface && !isNull ACE_player) then {
|
||||
[ACE_player, ACE_player] call FUNC(handlePlayerChanged);
|
||||
};
|
||||
}
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
[
|
||||
@ -59,8 +58,8 @@
|
||||
"SLIDER",
|
||||
[LSTRING(RecoveryFactor), LSTRING(RecoveryFactor_Description)],
|
||||
LSTRING(DisplayName),
|
||||
[0, 5, 1, 1],
|
||||
true
|
||||
[0, 10, 1, 2],
|
||||
1
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
[
|
||||
@ -68,8 +67,8 @@
|
||||
"SLIDER",
|
||||
[LSTRING(LoadFactor), LSTRING(LoadFactor_Description)],
|
||||
LSTRING(DisplayName),
|
||||
[0, 5, 1, 1],
|
||||
true
|
||||
[0, 5, 1, 2],
|
||||
1
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
[
|
||||
@ -77,6 +76,6 @@
|
||||
"SLIDER",
|
||||
[LSTRING(TerrainGradientFactor), LSTRING(TerrainGradientFactor_Description)],
|
||||
LSTRING(DisplayName),
|
||||
[0, 5, 1, 1],
|
||||
true
|
||||
[0, 5, 1, 2],
|
||||
1
|
||||
] call CBA_fnc_addSetting;
|
||||
|
@ -16,14 +16,28 @@
|
||||
|
||||
#include "\z\ace\addons\main\script_macros.hpp"
|
||||
|
||||
#define UNDERWEAR_WEIGHT 3.5
|
||||
|
||||
#define ANTPERCENT 0.8
|
||||
#define SIM_BODYMASS 70
|
||||
#define JOULES_PER_ML_O2 20.9
|
||||
#define VO2MAX_STRENGTH 4.1
|
||||
#define REE 18.83 //((0.5617 * SIM_BODYMASS + 42.57) * 0.23)
|
||||
#define OXYGEN 0.9
|
||||
#define WATTSPERATP 7
|
||||
#define BIOMECH_EFFICIENCY 0.23
|
||||
#define REE 18.83 // ((0.5617 * SIM_BODYMASS + 42.57) * BIOMECH_EFFICIENCY)
|
||||
|
||||
#define AE1_MAXRESERVE 4000000
|
||||
#define AE2_MAXRESERVE 84000
|
||||
#define AN_MAXRESERVE 2300
|
||||
#define RESPIRATORY_BUFFER 60
|
||||
|
||||
#define MUSCLE_TEAR_RATE 0.00004
|
||||
#define MUSCLE_RECOVERY 0.00000386
|
||||
|
||||
#define AE1_ATP_RELEASE_RATE 13.3 // mmol
|
||||
#define AE2_ATP_RELEASE_RATE 16.7 // mmol
|
||||
#define AN_ATP_RELEASE_RATE 113.3 // mmol
|
||||
|
||||
#define AE1_ATP_RECOVERY 6.60 // mmol
|
||||
#define AE2_ATP_RECOVERY 5.83 // mmol
|
||||
#define AN_ATP_RECOVERY 56.70 // mmol
|
||||
|
||||
#define AE1_MAXRESERVE 4000000 // mmol
|
||||
#define AE2_MAXRESERVE 84000 // mmol
|
||||
#define AN_MAXRESERVE 2300 // mmol
|
||||
|
@ -10,20 +10,10 @@ if (!hasInterface) exitWith {};
|
||||
// Temporary Wind Info indication
|
||||
GVAR(tempWindInfo) = false;
|
||||
|
||||
// Ammo/Magazines look-up hash for correctness of initSpeed
|
||||
GVAR(ammoMagLookup) = call CBA_fnc_createNamespace;
|
||||
{
|
||||
{
|
||||
private _ammo = getText (configFile >> "CfgMagazines" >> _x >> "ammo");
|
||||
if (_ammo != "") then { GVAR(ammoMagLookup) setVariable [_ammo, _x]; };
|
||||
} forEach (getArray (configFile >> "CfgWeapons" >> "Throw" >> _x >> "magazines"));
|
||||
} forEach getArray (configFile >> "CfgWeapons" >> "Throw" >> "muzzles");
|
||||
|
||||
|
||||
// Add keybinds
|
||||
["ACE3 Weapons", QGVAR(prepare), localize LSTRING(Prepare), {
|
||||
// Condition
|
||||
if (!([ACE_player] call FUNC(canPrepare))) exitWith {false};
|
||||
if !([ACE_player] call FUNC(canPrepare)) exitWith {false};
|
||||
if (EGVAR(common,isReloading)) exitWith {true};
|
||||
|
||||
// Statement
|
||||
|
@ -1,3 +1,21 @@
|
||||
#include "script_component.hpp"
|
||||
|
||||
#include "XEH_PREP.hpp"
|
||||
|
||||
// Ammo/Magazines look-up hash for correctness of initSpeed
|
||||
private _cfgMagazines = configFile >> "CfgMagazines";
|
||||
private _cfgAmmo = configFile >> "CfgAmmo";
|
||||
private _cfgThrow = configFile >> "CfgWeapons" >> "Throw";
|
||||
|
||||
private _ammoMagLookup = createHashMap;
|
||||
|
||||
{
|
||||
{
|
||||
private _ammo = getText (_cfgMagazines >> _x >> "ammo");
|
||||
if (_ammo != "") then {
|
||||
_ammoMagLookup set [configName (_cfgAmmo >> _ammo), _x];
|
||||
};
|
||||
} forEach (getArray (_cfgThrow >> _x >> "magazines"));
|
||||
} forEach (getArray (_cfgThrow >> "muzzles"));
|
||||
|
||||
uiNamespace setVariable [QGVAR(ammoMagLookup), compileFinal _ammoMagLookup];
|
||||
|
@ -43,13 +43,10 @@ if ((!_primed) && {!((_throwableMag in (uniformItems ACE_player)) || {_throwable
|
||||
|
||||
// Get correct throw power for primed grenade
|
||||
if (_primed) then {
|
||||
private _ammoType = typeOf _activeThrowable;
|
||||
_throwableMag = GVAR(ammoMagLookup) getVariable _ammoType;
|
||||
if (isNil "_throwableMag") then {
|
||||
// What we're trying to throw must not be a normal throwable because it is not in our lookup hash (e.g. 40mm smoke)
|
||||
// Just use HandGrenade as it has an average initSpeed value
|
||||
_throwableMag = "HandGrenade";
|
||||
};
|
||||
// If ammo type is not found:
|
||||
// What we're trying to throw must not be a normal throwable because it is not in our lookup hash (e.g. 40mm smoke)
|
||||
// Just use HandGrenade as it has an average initSpeed value
|
||||
_throwableMag = (uiNamespace getVariable QGVAR(ammoMagLookup)) getOrDefault [typeOf _activeThrowable, "HandGrenade"];
|
||||
};
|
||||
|
||||
// Some throwables have different classname for magazine and ammo
|
||||
|
@ -21,7 +21,7 @@ TRACE_1("params",_unit);
|
||||
// Select next throwable if one already in hand
|
||||
if (_unit getVariable [QGVAR(inHand), false]) exitWith {
|
||||
TRACE_1("inHand",_unit);
|
||||
if (!(_unit getVariable [QGVAR(primed), false])) then {
|
||||
if !(_unit getVariable [QGVAR(primed), false]) then {
|
||||
TRACE_1("not primed",_unit);
|
||||
// Restore muzzle ammo (setAmmo 1 has no impact if no appliccable throwable in inventory)
|
||||
// selectNextGrenade relies on muzzles array (setAmmo 0 removes the muzzle from the array and current can't be found, cycles between 0 and 1 muzzles)
|
||||
|
@ -20,7 +20,7 @@ TRACE_1("params",_unit);
|
||||
|
||||
// Prime the throwable if it hasn't been cooking already
|
||||
// Next to proper simulation this also has to happen before delay for orientation of the throwable to be set
|
||||
if (!(_unit getVariable [QGVAR(primed), false])) then {
|
||||
if !(_unit getVariable [QGVAR(primed), false]) then {
|
||||
[_unit] call FUNC(prime);
|
||||
};
|
||||
|
||||
|
@ -144,7 +144,7 @@
|
||||
<English>Enables ability to pick up throwables from the ground.</English>
|
||||
<Spanish>Activa la habilidad de coger objetos lanzados del suelo</Spanish>
|
||||
<Russian>Включает возможность подбирать гранаты с земли.</Russian>
|
||||
<Japanese>地面に落ちている投擲物を拾い上げる機能を有効化します。</Japanese>
|
||||
<Japanese>地面に落ちている投擲物を拾う機能を有効化します。</Japanese>
|
||||
<Polish>Umożliwia podnoszenie obiektów miotanych z ziemi.</Polish>
|
||||
<German>Aktiviert die Möglichkeit, geworfene Objekte wieder vom Boden aufzuheben.</German>
|
||||
<Korean>땅에 떨어진 투척물을 주울 수 있게 해줍니다.</Korean>
|
||||
@ -174,7 +174,7 @@
|
||||
<English>Enables ability to pick up throwables from attached objects.</English>
|
||||
<Spanish>Activa la habilidad de lanzar objetos enganchados</Spanish>
|
||||
<Russian>Включает возможность подбирать гранаты, прикрепленные к объектам.</Russian>
|
||||
<Japanese>オブジェクトに装着された投擲可能物を拾い上げる機能を有効化します。</Japanese>
|
||||
<Japanese>オブジェクトに装着された投擲物を拾う機能を有効化します。</Japanese>
|
||||
<Polish>Umożliwia podnoszenie obiektów miotanych przyczepionych do innych obiektów.</Polish>
|
||||
<German>Aktiviert die Möglichkeit, befestigte Wurfobjekte erneut aufzunehmen.</German>
|
||||
<Korean>부착된 투척물을 주울 수 있게 해줍니다.</Korean>
|
||||
@ -254,7 +254,7 @@
|
||||
<English>Primed</English>
|
||||
<Spanish>Preparado</Spanish>
|
||||
<Russian>Подготовлена</Russian>
|
||||
<Japanese>点火</Japanese>
|
||||
<Japanese>を点火した</Japanese>
|
||||
<Polish>Odbezpieczony</Polish>
|
||||
<German>Scharf gemacht</German>
|
||||
<Korean>뇌관 작동</Korean>
|
||||
|
@ -22,7 +22,7 @@ if (!alive _vehicle) exitWith {};
|
||||
if (_vehicle getVariable [QGVAR(droneActionsAdded), false]) exitWith {};
|
||||
_vehicle setVariable [QGVAR(droneActionsAdded), true];
|
||||
|
||||
// move to location
|
||||
// Move to location
|
||||
private _condition = {
|
||||
params ["_vehicle"];
|
||||
(missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]}
|
||||
@ -37,14 +37,63 @@ private _action = [QGVAR(droneSetWaypointMove), localize "$STR_AC_MOVE",
|
||||
"\a3\3DEN\Data\CfgWaypoints\Move_ca.paa", _statement, _condition] call EFUNC(interact_menu,createAction);
|
||||
[_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject);
|
||||
|
||||
// Follow unit/vehicle at turret location
|
||||
_condition = {
|
||||
params ["_vehicle"];
|
||||
private _target = cursorTarget;
|
||||
(missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]} && {!isNull _target} && {["CAManBase", "LandVehicle", "Ship"] findIf {_target isKindOf _x} != -1}
|
||||
};
|
||||
_statement = {
|
||||
params ["_vehicle"];
|
||||
private _group = group driver _vehicle;
|
||||
private _pos = ([_vehicle, [0]] call FUNC(droneGetTurretTargetPos)) select 0;
|
||||
[QGVAR(droneSetWaypoint), [_vehicle, _group, _pos, "FOLLOW", cursorTarget], _group] call CBA_fnc_targetEvent;
|
||||
private _followDistance = _vehicle getVariable [QGVAR(wpFollowDistance), 0];
|
||||
[[LLSTRING(DroneFollowHint), _followDistance], 3] call EFUNC(common,displayTextStructured);
|
||||
};
|
||||
_action = [QGVAR(droneSetWaypointFollow), localize "$STR_AC_FOLLOW", "\a3\3DEN\Data\CfgWaypoints\Follow_ca.paa", _statement, _condition] call EFUNC(interact_menu,createAction);
|
||||
[_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject);
|
||||
|
||||
// Set drone follow distance
|
||||
_condition = {
|
||||
params ["_vehicle"];
|
||||
private _group = group driver _vehicle;
|
||||
private _index = (currentWaypoint _group) min count waypoints _group;
|
||||
private _waypoint = [_group, _index];
|
||||
(missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]} && {(waypointType _waypoint) == "HOLD"}
|
||||
};
|
||||
_statement = {
|
||||
params ["_vehicle", "", "_value"];
|
||||
_vehicle setVariable [QGVAR(wpFollowDistance), _value];
|
||||
[[LLSTRING(DroneFollowHint), _value], 3] call EFUNC(common,displayTextStructured);
|
||||
};
|
||||
_action = [QGVAR(droneSetFollowDistance), LLSTRING(DroneFollowDistance), "", {}, _condition] call EFUNC(interact_menu,createAction);
|
||||
private _base = [_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject);
|
||||
private _followDistances = if (_vehicle isKindOf "Car_F") then {
|
||||
[0, 25, 50, 100, 200]
|
||||
} else {
|
||||
[0, 100, 200, 300, 400, 500]
|
||||
};
|
||||
{
|
||||
_action = [
|
||||
QGVAR(droneSetFollowDistance_) + str _x,
|
||||
str _x,
|
||||
"",
|
||||
_statement,
|
||||
{true},
|
||||
{},
|
||||
_x
|
||||
] call EFUNC(interact_menu,createAction);
|
||||
[_vehicle, 1, _base, _action] call EFUNC(interact_menu,addActionToObject);
|
||||
} forEach _followDistances;
|
||||
|
||||
if (_vehicle isKindOf "Air") then {
|
||||
// loiter at location
|
||||
// Loiter at location
|
||||
_condition = {
|
||||
params ["_vehicle"];
|
||||
(missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]}
|
||||
};
|
||||
_statement = {
|
||||
_statement = {
|
||||
params ["_vehicle"];
|
||||
private _group = group driver _vehicle;
|
||||
private _pos = ([_vehicle, [0]] call FUNC(droneGetTurretTargetPos)) select 0;
|
||||
@ -55,7 +104,7 @@ if (_vehicle isKindOf "Air") then {
|
||||
[_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject);
|
||||
|
||||
|
||||
// set height
|
||||
// Set height
|
||||
_condition = {
|
||||
params ["_vehicle"];
|
||||
(missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]}
|
||||
@ -74,7 +123,7 @@ if (_vehicle isKindOf "Air") then {
|
||||
} forEach [20, 50, 200, 500, 2000];
|
||||
|
||||
|
||||
// set loiter radius
|
||||
// Set loiter radius
|
||||
_condition = {
|
||||
params ["_vehicle"];
|
||||
private _group = group driver _vehicle;
|
||||
@ -97,7 +146,7 @@ if (_vehicle isKindOf "Air") then {
|
||||
} forEach [500, 750, 1000, 1250, 1500];
|
||||
|
||||
|
||||
// set loiter direction
|
||||
// Set loiter direction
|
||||
_condition = {
|
||||
params ["_vehicle", "", "_args"];
|
||||
private _group = group driver _vehicle;
|
||||
|
@ -8,6 +8,7 @@
|
||||
* 1: Group <GROUP>
|
||||
* 2: Pos 2D <ARRAY>
|
||||
* 3: Type <STRING>
|
||||
* 4: Target to follow <OBJECT> (default: objNull)
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
@ -18,7 +19,7 @@
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params ["_vehicle", "_group", "_pos", "_type"];
|
||||
params ["_vehicle", "_group", "_pos", "_type", ["_target", objNull]];
|
||||
TRACE_4("droneSetWaypoint",_vehicle,_group,_pos,_type);
|
||||
|
||||
private _index = (currentWaypoint _group) min count waypoints _group;
|
||||
@ -34,9 +35,34 @@ _pos set [
|
||||
[0, _currentHeight] select (_currentHeight >= 50)
|
||||
];
|
||||
|
||||
// [_group] call CBA_fnc_clearWaypoints;
|
||||
_waypoint = _group addWaypoint [_pos, 0];
|
||||
_waypoint setWaypointType _type;
|
||||
// The Vanilla "FOLLOW"-type waypoint is not used directly, due to 2 main issues (as of v2.16):
|
||||
// - It does not work at all for UGVs, which is a known issue https://feedback.bistudio.com/T126283;
|
||||
// - No clear scripting way was found to mimic the UAV Terminal's "Follow Distance" functionality;
|
||||
// Instead, the solution for both UAV and UGV following consists of a CBA PFH that moves a "HOLD"-type Waypoint every 3 seconds.
|
||||
// Either on the target itself, or on the Drone's current position if the target is within the desired follow distance.
|
||||
if (_type == "FOLLOW" && {["CAManBase", "LandVehicle", "Ship"] findIf {_target isKindOf _x} != -1}) then {
|
||||
_waypoint setWaypointType "HOLD";
|
||||
[{
|
||||
params ["_args", "_handle"];
|
||||
_args params ["_vehicle", "_group", "_waypoint", "_target"];
|
||||
|
||||
if ( // Abort PFH if a new waypoint is created via UAV Terminal or ACE Interaction
|
||||
_waypoint select 1 != currentWaypoint _group ||
|
||||
{!alive _vehicle} || {isNull _target}
|
||||
) exitWith {
|
||||
deleteWaypoint _waypoint;
|
||||
[_handle] call CBA_fnc_removePerFrameHandler;
|
||||
};
|
||||
|
||||
private _followDistance = _vehicle getVariable [QGVAR(wpFollowDistance), 0];
|
||||
if ((_vehicle distance2D _target) < _followDistance) then {
|
||||
_waypoint setWaypointPosition [getPosASL _vehicle, -1];
|
||||
} else {
|
||||
_waypoint setWaypointPosition [getPosASL _target, -1];
|
||||
};
|
||||
}, 3, [_vehicle, _group, _waypoint, _target]] call CBA_fnc_addPerFrameHandler;
|
||||
};
|
||||
|
||||
TRACE_3("",_currentHeight,_currentLoiterRadius,_currentLoiterType);
|
||||
if (_currentHeight > 1) then { _vehicle flyInHeight _currentHeight; };
|
||||
|
@ -129,7 +129,7 @@
|
||||
<Japanese>30mm コンバット ミックス 4:1 劣化ウラン徹甲弾:焼夷榴弾</Japanese>
|
||||
<Czech>30mm Bojový Mix 4:1 DU:HEI</Czech>
|
||||
<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>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Aircraft_GatlingDescriptionShortCM41">
|
||||
@ -145,7 +145,7 @@
|
||||
<Japanese>30mm CM 4:1</Japanese>
|
||||
<Czech>30mm BM 4:1</Czech>
|
||||
<Russian>30мм СБ 4:1</Russian>
|
||||
<Korean>30mm CM 4:1</Korean>
|
||||
<Korean>30mm 4:1 혼합</Korean>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Aircraft_GatlingDescriptionCM51">
|
||||
<English>30mm Combat Mix 5:1 DU:HEI</English>
|
||||
@ -160,7 +160,7 @@
|
||||
<Japanese>30mm コンバット ミックス 5:1 劣化ウラン徹甲弾:焼夷榴弾</Japanese>
|
||||
<Czech>30mm Bojový Mix 5:1 DU:HEI</Czech>
|
||||
<Russian>30мм Смешанное боепитание 5:1 ОУ:ОФЗ</Russian>
|
||||
<Korean>30mm 5:1 열화:고폭소이</Korean>
|
||||
<Korean>30mm 열화우라늄:고폭소이 5:1 혼합</Korean>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Aircraft_GatlingDescriptionShortCM51">
|
||||
<English>30mm CM 5:1</English>
|
||||
@ -175,7 +175,23 @@
|
||||
<Japanese>30mm CM 5:1</Japanese>
|
||||
<Czech>30mm BM 5:1</Czech>
|
||||
<Russian>30мм СБ 5:1</Russian>
|
||||
<Korean>30mm CM 5:1</Korean>
|
||||
<Korean>30mm 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>
|
||||
</Package>
|
||||
</Project>
|
||||
|
@ -78,6 +78,7 @@ PREP(removeStat);
|
||||
PREP(removeVirtualItems);
|
||||
PREP(renameDefaultLoadout);
|
||||
PREP(replaceUniqueItemsLoadout);
|
||||
PREP(saveLoadout);
|
||||
PREP(scanConfig);
|
||||
PREP(showItem);
|
||||
PREP(sortPanel);
|
||||
|
@ -85,10 +85,10 @@ private _insigniaCondition = toString {
|
||||
|
||||
// Ref fnc_addListBoxItem, 0/nil = configFile, 1 = campaignConfigFile, 2 = missionConfigFile
|
||||
{
|
||||
GVAR(insigniaCache) set [_x, 1];
|
||||
GVAR(insigniaCache) set [configName _x, 1];
|
||||
} forEach (_insigniaCondition configClasses (campaignConfigFile >> "CfgUnitInsignia"));
|
||||
{
|
||||
GVAR(insigniaCache) set [_x, 2];
|
||||
GVAR(insigniaCache) set [configName _x, 2];
|
||||
} forEach (_insigniaCondition configClasses (missionConfigFile >> "CfgUnitInsignia"));
|
||||
|
||||
ADDON = true;
|
||||
|
@ -26,28 +26,27 @@ if (GVAR(shiftState)) then {
|
||||
switch (true) do {
|
||||
// Beginning
|
||||
case (_index == -1): {
|
||||
"ace_clipboard" callExtension (format ["[%1", endl]);
|
||||
"ace" callExtension ["clipboard:append", [format ["[%1", endl]]];
|
||||
};
|
||||
// End
|
||||
case (_index == _listLength): {
|
||||
"ace_clipboard" callExtension "];";
|
||||
"ace" callExtension ["clipboard:append", ["];"]];
|
||||
};
|
||||
// Rest
|
||||
default {
|
||||
"ace_clipboard" callExtension ([" ", str (GVAR(defaultLoadoutsList) select _index), [",", ""] select (_index == _listLength - 1), endl] joinString "");
|
||||
"ace" callExtension ["clipboard:append", [[" ", str (GVAR(defaultLoadoutsList) select _index), [",", ""] select (_index == _listLength - 1), endl] joinString ""]];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
"ace_clipboard" callExtension "--COMPLETE--";
|
||||
"ace" callExtension ["clipboard:complete", []];
|
||||
|
||||
[_display, LLSTRING(exportDefault)] call FUNC(message);
|
||||
} else {
|
||||
// Export singular loadout
|
||||
private _export = str (GVAR(center) call CBA_fnc_getLoadout);
|
||||
|
||||
"ace_clipboard" callExtension (_export + ";");
|
||||
"ace_clipboard" callExtension "--COMPLETE--";
|
||||
"ace" callExtension ["clipboard:append", [_export]];
|
||||
"ace" callExtension ["clipboard:complete", []];
|
||||
|
||||
[_display, LLSTRING(exportCurrent)] call FUNC(message);
|
||||
};
|
||||
|
@ -16,7 +16,13 @@
|
||||
params ["_display"];
|
||||
|
||||
// Can be either a singular loadout or an array of loadouts
|
||||
private _extendedLoadout = call compile copyFromClipboard;
|
||||
private _extendedLoadout = if (isMultiplayer) then {
|
||||
("ace" callExtension ["clipboard:loadout", []]) params ["_loadout", "_code"];
|
||||
if (_code != 0) exitWith {};
|
||||
parseSimpleArray _loadout
|
||||
} else {
|
||||
call compile copyFromClipboard
|
||||
};
|
||||
|
||||
// If error, exit
|
||||
if (isNil "_extendedLoadout" || {!(_extendedLoadout isEqualType [])}) exitWith {
|
||||
|
@ -18,7 +18,7 @@
|
||||
(_this select 1) params ["", "_exitCode"];
|
||||
|
||||
[QGVAR(displayClosed), []] call CBA_fnc_localEvent;
|
||||
removeMissionEventHandler ["draw3D", GVAR(camPosUpdateHandle)];
|
||||
removeMissionEventHandler ["Draw3D", GVAR(camPosUpdateHandle)];
|
||||
|
||||
if (is3DEN) then {
|
||||
private _centerOriginParent = objectParent GVAR(centerOrigin);
|
||||
|
@ -138,14 +138,6 @@ _actionsBoxCtrl ctrlSetPosition [
|
||||
];
|
||||
_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
|
||||
cutText ["", "PLAIN"];
|
||||
showCommandingMenu "";
|
||||
@ -278,4 +270,4 @@ showCinemaBorder false;
|
||||
|
||||
//--------------- Reset camera pos
|
||||
[nil, [controlNull, 0, 0]] call FUNC(handleMouse);
|
||||
GVAR(camPosUpdateHandle) = addMissionEventHandler ["draw3D", {call FUNC(updateCamPos)}];
|
||||
GVAR(camPosUpdateHandle) = addMissionEventHandler ["Draw3D", {call FUNC(updateCamPos)}];
|
||||
|
@ -94,8 +94,8 @@ if (!isNull _loadoutsDisplay) then {
|
||||
};
|
||||
} params ["_className"];
|
||||
|
||||
"ace_clipboard" callExtension (_className + ";");
|
||||
"ace_clipboard" callExtension "--COMPLETE--";
|
||||
"ace" callExtension ["clipboard:append", [_className]];
|
||||
"ace" callExtension ["clipboard:complete", []];
|
||||
|
||||
[_display, LLSTRING(exportedClassnameText)] call FUNC(message);
|
||||
} else {
|
||||
|
@ -382,6 +382,9 @@ switch (GVAR(currentLeftPanel)) do {
|
||||
};
|
||||
|
||||
GVAR(currentItems) set [IDX_CURR_VEST, _item];
|
||||
|
||||
[GVAR(center), ""] call BIS_fnc_setUnitInsignia;
|
||||
[GVAR(center), GVAR(currentInsignia)] call BIS_fnc_setUnitInsignia;
|
||||
};
|
||||
|
||||
TOGGLE_RIGHT_PANEL_CONTAINER
|
||||
@ -420,6 +423,9 @@ switch (GVAR(currentLeftPanel)) do {
|
||||
};
|
||||
|
||||
GVAR(currentItems) set [IDX_CURR_BACKPACK, _item];
|
||||
|
||||
[GVAR(center), ""] call BIS_fnc_setUnitInsignia;
|
||||
[GVAR(center), GVAR(currentInsignia)] call BIS_fnc_setUnitInsignia;
|
||||
};
|
||||
|
||||
TOGGLE_RIGHT_PANEL_CONTAINER
|
||||
|
37
addons/arsenal/functions/fnc_saveLoadout.sqf
Normal file
37
addons/arsenal/functions/fnc_saveLoadout.sqf
Normal file
@ -0,0 +1,37 @@
|
||||
#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
|
@ -72,6 +72,6 @@ if (_nextAction != GVAR(currentAction)) then {
|
||||
GVAR(currentAction) = _nextAction;
|
||||
};
|
||||
|
||||
if (!(GVAR(currentAction) in ["Civil", "Salute"])) then {
|
||||
if !(GVAR(currentAction) in ["Civil", "Salute"]) then {
|
||||
GVAR(center) selectWeapon ([primaryWeapon GVAR(center), secondaryWeapon GVAR(center), handgunWeapon GVAR(center), binocular GVAR(center)] select GVAR(selectedWeaponType)); // select correct weapon, prevents floating weapons
|
||||
};
|
||||
|
@ -14,4 +14,9 @@
|
||||
|
||||
params ["_config"];
|
||||
|
||||
(modParams [_config call EFUNC(common,getAddon), ["name"]]) param [0, ""]
|
||||
private _addon = _config call EFUNC(common,getAddon);
|
||||
|
||||
// Calling modParams with "" prints 'ModParams - Undefined or empty mod directory' in RPT
|
||||
if (_addon == "") exitWith {""};
|
||||
|
||||
(modParams [_addon, ["name"]]) param [0, ""]
|
||||
|
@ -63,7 +63,7 @@ _target switchMove "amovpercmstpslowwrfldnon";
|
||||
_target setVariable ["origin", _position];
|
||||
|
||||
// When killed, respawn AI
|
||||
_target addEventHandler ["killed", {
|
||||
_target addEventHandler ["Killed", {
|
||||
params ["_target"];
|
||||
|
||||
// Killed may fire twice, 2nd will be null - https://github.com/acemod/ACE3/pull/7561
|
||||
|
@ -23,7 +23,7 @@
|
||||
<French>Masque l'interface</French>
|
||||
<German>Oberfläche verstecken</German>
|
||||
<Polish>Ukryj interfejs</Polish>
|
||||
<Japanese>インターフェースを隠す</Japanese>
|
||||
<Japanese>インタフェースを隠す</Japanese>
|
||||
<Italian>Nascondi interfaccia</Italian>
|
||||
<Korean>인터페이스 숨기기</Korean>
|
||||
<Chinese>隱藏介面</Chinese>
|
||||
@ -1245,6 +1245,7 @@
|
||||
<Russian>Интегрирован тепловизор.</Russian>
|
||||
<Korean>열화상 내장</Korean>
|
||||
<French>Thermique intégrée</French>
|
||||
<German>Thermal integriert</German>
|
||||
<Spanish>Térmica integrada</Spanish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Arsenal_statVisionMode_intPrimTi">
|
||||
@ -1254,6 +1255,7 @@
|
||||
<Russian>Интегрирован тепловизор и осн.прицел.</Russian>
|
||||
<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 ID="STR_ACE_Arsenal_statVisionMode_NoSup">
|
||||
|
@ -1,8 +1,14 @@
|
||||
TRACE_1("prep",_this);
|
||||
|
||||
PREP(adjustFire);
|
||||
PREP(calculateElevation);
|
||||
PREP(calculateMaxAngle);
|
||||
PREP(calculateMuzzleVelocity);
|
||||
PREP(calculateSolution);
|
||||
PREP(firedEH);
|
||||
PREP(interactMenuOpened);
|
||||
PREP(rangeTableOpen);
|
||||
PREP(rangeTableUpdate);
|
||||
PREP(simulateShot);
|
||||
PREP(turretChanged);
|
||||
PREP(turretPFEH);
|
||||
|
@ -4,10 +4,13 @@
|
||||
TRACE_2("CBA_settingsInitialized",GVAR(advancedCorrections),GVAR(disableArtilleryComputer));
|
||||
|
||||
if (hasInterface) then {
|
||||
// Add hud overlay for actuall azimuth and elevation:
|
||||
// Add hud overlay for actual azimuth and elevation:
|
||||
GVAR(pfID) = -1;
|
||||
["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:
|
||||
["ace_interactMenuOpened", LINKFUNC(interactMenuOpened)] call CBA_fnc_addEventHandler;
|
||||
};
|
||||
@ -30,6 +33,33 @@
|
||||
};
|
||||
}] 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
|
||||
#include "dev\showShotInfo.inc.sqf"
|
||||
#include "dev\checkConfigs.inc.sqf"
|
||||
|
@ -14,13 +14,6 @@ class CfgPatches {
|
||||
};
|
||||
};
|
||||
|
||||
class ACE_Extensions {
|
||||
class ace_artillerytables {
|
||||
windows = 1;
|
||||
client = 1;
|
||||
};
|
||||
};
|
||||
|
||||
#include "CfgEventHandlers.hpp"
|
||||
#include "CfgMagazines.hpp"
|
||||
#include "CfgVehicles.hpp"
|
||||
|
41
addons/artillerytables/functions/fnc_adjustFire.sqf
Normal file
41
addons/artillerytables/functions/fnc_adjustFire.sqf
Normal file
@ -0,0 +1,41 @@
|
||||
#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
|
71
addons/artillerytables/functions/fnc_calculateElevation.sqf
Normal file
71
addons/artillerytables/functions/fnc_calculateElevation.sqf
Normal file
@ -0,0 +1,71 @@
|
||||
#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]
|
31
addons/artillerytables/functions/fnc_calculateMaxAngle.sqf
Normal file
31
addons/artillerytables/functions/fnc_calculateMaxAngle.sqf
Normal file
@ -0,0 +1,31 @@
|
||||
#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
|
@ -0,0 +1,28 @@
|
||||
#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
|
44
addons/artillerytables/functions/fnc_calculateSolution.sqf
Normal file
44
addons/artillerytables/functions/fnc_calculateSolution.sqf
Normal file
@ -0,0 +1,44 @@
|
||||
#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
|
@ -25,7 +25,7 @@
|
||||
params ["_vehicle", "", "", "", "", "_magazine", "_projectile", "_gunner"];
|
||||
TRACE_4("firedEH",_vehicle,_magazine,_projectile,_gunner);
|
||||
|
||||
if (!([_gunner] call EFUNC(common,isPlayer))) exitWith {}; // AI don't know how to use (this does give them more range than a player)
|
||||
if !([_gunner] call EFUNC(common,isPlayer)) exitWith {}; // AI don't know how to use (this does give them more range than a player)
|
||||
if ((gunner _vehicle) != _gunner) exitWith {}; // check if primaryGunner
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ if (isNumber (configFile >> "CfgMagazines" >> _magazine >> QGVAR(airFriction)))
|
||||
_airFriction = getNumber (configFile >> "CfgMagazines" >> _magazine >> QGVAR(airFriction));
|
||||
};
|
||||
TRACE_1("",_airFriction);
|
||||
if (_airFriction >= 0) exitWith {}; // 0 disables everything, >0 makes no sense
|
||||
if (_airFriction == 0) exitWith {}; // 0 disables everything
|
||||
|
||||
BEGIN_COUNTER(adjustmentsCalc);
|
||||
|
||||
@ -60,6 +60,7 @@ if (_newMuzzleVelocityCoefficent != 1) then {
|
||||
_projectile setVelocity _bulletVelocity;
|
||||
};
|
||||
|
||||
if (_airFriction > 0) exitWith {}; // positive value indicates it has vanilla airFriction, so we can just exit
|
||||
|
||||
[{
|
||||
params ["_projectile", "_kFactor", "_time"];
|
||||
|
@ -19,7 +19,7 @@ params ["_menuType"];
|
||||
TRACE_1("interactMenuOpened",_menuType);
|
||||
|
||||
if (_menuType != 1) exitWith {};
|
||||
if (!("ACE_artilleryTable" in (ace_player call EFUNC(common,uniqueItems)))) exitWith {};
|
||||
if !("ACE_artilleryTable" in (ace_player call EFUNC(common,uniqueItems))) exitWith {};
|
||||
|
||||
private _vehicleAdded = ace_player getVariable [QGVAR(vehiclesAdded), []];
|
||||
private _rangeTablesShown = ace_player getVariable [QGVAR(rangeTablesShown), []];
|
||||
|
@ -41,8 +41,15 @@ _mags = _mags apply {
|
||||
private _initSpeed = getNumber (_magCfg >> _x >> "initSpeed");
|
||||
_magParamsArray pushBackUnique _initSpeed;
|
||||
private _airFriction = 0;
|
||||
if (_advCorrection) then {
|
||||
_airFriction = if (isNumber (_magCfg >> _x >> QGVAR(airFriction))) then { getNumber (_magCfg >> _x >> QGVAR(airFriction)) } else { DEFAULT_AIR_FRICTION };
|
||||
private _magAirFriction = getNumber (_magCfg >> _x >> QGVAR(airFriction));
|
||||
if (_magAirFriction <= 0) then {
|
||||
if (_advCorrection) then {
|
||||
_airFriction = [DEFAULT_AIR_FRICTION, _magAirFriction] select (isNumber (_magCfg >> _x >> QGVAR(airFriction)));
|
||||
};
|
||||
} else {
|
||||
// positive value, use ammo's airFriction (regardless of setting)
|
||||
private _ammo = getText (_magCfg >> _x >> "ammo");
|
||||
_airFriction = getNumber (configFile >> "CfgAmmo" >> _ammo >> "airFriction");
|
||||
};
|
||||
_magParamsArray pushBackUnique _airFriction;
|
||||
[getText (_magCfg >> _x >> "displayNameShort"), getText (_magCfg >> _x >> "displayName"), _initSpeed, _airFriction]
|
||||
|
@ -34,31 +34,12 @@ _ctrlElevationLow ctrlSetTextColor ([[1,1,1,1],[0.25,0.25,0.25,1]] select GVAR(l
|
||||
|
||||
lnbClear _ctrlRangeTable;
|
||||
// Call extension with current data and start workers
|
||||
TRACE_5("callExtension:start",_muzzleVelocity,_airFriction,_elevMin,_elevMax,GVAR(lastElevationMode));
|
||||
private _ret = "ace_artillerytables" callExtension ["start", [_muzzleVelocity,_airFriction,_elevMin,_elevMax,GVAR(lastElevationMode)]];
|
||||
TRACE_1("",_ret);
|
||||
TRACE_5("callExtension:artillery:calculate_table",_muzzleVelocity,_airFriction,_elevMin,_elevMax,GVAR(lastElevationMode));
|
||||
(
|
||||
"ace" callExtension ["artillery:calculate_table", [_muzzleVelocity, _airFriction, _elevMin, _elevMax, GVAR(lastElevationMode)]]
|
||||
) params ["_data", "_code"];
|
||||
TRACE_1("",_code)
|
||||
|
||||
// Non-blocking read data out of extension as it becomes availiable
|
||||
[{
|
||||
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;
|
||||
GVAR(tableData) = createHashMap;
|
||||
GVAR(tableSizeActual) = (parseSimpleArray _data) select 1;
|
||||
GVAR(tableSizeReceived) = 0;
|
||||
|
47
addons/artillerytables/functions/fnc_simulateShot.sqf
Normal file
47
addons/artillerytables/functions/fnc_simulateShot.sqf
Normal file
@ -0,0 +1,47 @@
|
||||
#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
|
@ -30,7 +30,10 @@ if (isNull (uiNamespace getVariable [QGVAR(display), displayNull])) then {
|
||||
};
|
||||
|
||||
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 true;
|
||||
|
@ -15,7 +15,5 @@ private _categoryName = [format ["ACE %1", localize "str_a3_cfgmarkers_nato_art"
|
||||
[LSTRING(disableArtilleryComputer_displayName), LSTRING(disableArtilleryComputer_description)],
|
||||
_categoryName,
|
||||
false, // default value
|
||||
true, // isGlobal
|
||||
{[QGVAR(disableArtilleryComputer), _this] call EFUNC(common,cbaSettings_settingChanged)},
|
||||
false // Needs mission restart
|
||||
true // isGlobal
|
||||
] call CBA_fnc_addSetting;
|
||||
|
@ -12,6 +12,10 @@
|
||||
// This is a good fit for most large artillery, but a little low for lighter mortars
|
||||
#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 IDC_MODECONTROLGROUP 1000
|
||||
|
@ -6,7 +6,7 @@ class CfgPatches {
|
||||
units[] = {"ACE_Item_ATragMX"};
|
||||
weapons[] = {"ACE_ATragMX"};
|
||||
requiredVersion = REQUIRED_VERSION;
|
||||
requiredAddons[] = {"ACE_Advanced_Ballistics", "ACE_common", "ACE_weather"};
|
||||
requiredAddons[] = {"ace_advanced_ballistics", "ace_common", "ace_weather"};
|
||||
author = ECSTRING(common,ACETeam);
|
||||
authors[] = {"Ruthberg"};
|
||||
url = ECSTRING(main,URL);
|
||||
|
@ -30,9 +30,16 @@ while {_velocity > _thresholdVelocity} do {
|
||||
private _bc = GVAR(targetSolutionInput) select 14;
|
||||
private _dragModel = GVAR(targetSolutionInput) select 15;
|
||||
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;
|
||||
_velocity = _velocity - (_drag * __DELTA_T);
|
||||
private _data = (
|
||||
"ace" callExtension ["ballistics:retard", [
|
||||
_dragModel,
|
||||
_bc,
|
||||
_velocity,
|
||||
_temperature
|
||||
]]
|
||||
) select 0;
|
||||
_velocity = _velocity - ((parseNumber _data) * __DELTA_T);
|
||||
};
|
||||
|
||||
_distance
|
||||
|
@ -90,7 +90,14 @@ private _wind1 = [cos(270 - _windDirection * 30) * _windSpeed1, sin(270 - _windD
|
||||
private _wind2 = [cos(270 - _windDirection * 30) * _windSpeed2, sin(270 - _windDirection * 30) * _windSpeed2, 0];
|
||||
private _windDrift = 0;
|
||||
if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then {
|
||||
_bc = parseNumber(("ace_advanced_ballistics" callExtension format["atmosphericCorrection:%1:%2:%3:%4:%5", _bc, _temperature, _barometricPressure, _relativeHumidity, _atmosphereModel]));
|
||||
_bc = parseNumber (("ace" callExtension ["ballistics:atmospheric_correction", [
|
||||
_bc,
|
||||
_temperature,
|
||||
_barometricPressure,
|
||||
_relativeHumidity,
|
||||
_atmosphereModel
|
||||
]]
|
||||
) select 0);
|
||||
};
|
||||
|
||||
private _eoetvoesMultiplier = 0;
|
||||
@ -113,8 +120,15 @@ while {_TOF < 15 && (_bulletPos select 1) < _targetRange} do {
|
||||
_trueSpeed = vectorMagnitude _trueVelocity;
|
||||
|
||||
if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then {
|
||||
private _drag = parseNumber(("ace_advanced_ballistics" callExtension format["retard:%1:%2:%3:%4", _dragModel, _bc, _trueSpeed, _temperature]));
|
||||
_bulletAccel = (vectorNormalized _trueVelocity) vectorMultiply (-1 * _drag);
|
||||
private _data = (
|
||||
"ace" callExtension ["ballistics:retard", [
|
||||
_dragModel,
|
||||
_bc,
|
||||
_trueSpeed,
|
||||
_temperature
|
||||
]]
|
||||
) select 0;
|
||||
_bulletAccel = (vectorNormalized _trueVelocity) vectorMultiply (-1 * (parseNumber _data));
|
||||
} else {
|
||||
_bulletAccel = _trueVelocity vectorMultiply (_trueSpeed * _airFriction);
|
||||
};
|
||||
|
@ -23,7 +23,7 @@ if ((profileNamespace getVariable ["ACE_ATragMX_profileNamespaceVersion", 0]) ==
|
||||
_resetGunList = false;
|
||||
{
|
||||
// Verify each gun has correct param type
|
||||
if (!(_x isEqualTypeArray ["", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", [], [], false])) exitWith {
|
||||
if !(_x isEqualTypeArray ["", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", [], [], false]) exitWith {
|
||||
_resetGunList = true;
|
||||
};
|
||||
} forEach GVAR(gunList);
|
||||
|
@ -74,7 +74,7 @@ private _validate_preset = {
|
||||
ERROR(_errorMsg);
|
||||
_valid = false;
|
||||
};
|
||||
if (!((_this select 17) in ["ASM", "ICAO"])) then {
|
||||
if !((_this select 17) in ["ASM", "ICAO"]) then {
|
||||
private _errorMsg = format ["Invalid atmosphere model: %1", _this select 17];
|
||||
ERROR(_errorMsg);
|
||||
_valid = false;
|
||||
|
@ -26,7 +26,7 @@ if !(ctrlVisible 9000) then {
|
||||
params ["_args"];
|
||||
_args params ["_startTime"];
|
||||
|
||||
if (!(GVAR(speedAssistTimer))) exitWith {
|
||||
if !(GVAR(speedAssistTimer)) exitWith {
|
||||
GVAR(speedAssistTimer) = true;
|
||||
|
||||
ctrlSetText [8006, Str(Round((CBA_missionTime - _startTime) * 10) / 10)];
|
||||
|
@ -15,7 +15,7 @@
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
if (!(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false])) exitWith {};
|
||||
if !(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) exitWith {};
|
||||
|
||||
if (ctrlVisible 17000) then {
|
||||
false call FUNC(show_c1_ballistic_coefficient_data);
|
||||
|
@ -15,7 +15,7 @@
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
if (!(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false])) exitWith {};
|
||||
if !(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) exitWith {};
|
||||
|
||||
if (ctrlVisible 16000) then {
|
||||
false call FUNC(show_muzzle_velocity_data);
|
||||
|
@ -15,7 +15,7 @@
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
if (!(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false])) exitWith {};
|
||||
if !(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) exitWith {};
|
||||
|
||||
if (ctrlVisible 18000) then {
|
||||
false call FUNC(show_truing_drop);
|
||||
|
@ -35,12 +35,26 @@ if (!GVAR(atmosphereModeTBH)) then {
|
||||
_relativeHumidity = 0.5;
|
||||
};
|
||||
|
||||
private _scopeBaseAngle = if (!(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false])) then {
|
||||
private _zeroAngle = "ace_advanced_ballistics" callExtension format ["calcZero:%1:%2:%3:%4", _zeroRange, _muzzleVelocity, _airFriction, _boreHeight];
|
||||
(parseNumber _zeroAngle)
|
||||
private _scopeBaseAngle = if !(missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then {
|
||||
parseNumber (("ace" callExtension ["ballistics:zero_vanilla", [
|
||||
_zeroRange,
|
||||
_muzzleVelocity,
|
||||
_airFriction,
|
||||
_boreHeight
|
||||
]]) select 0)
|
||||
} else {
|
||||
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];
|
||||
(parseNumber _zeroAngle)
|
||||
parseNumber (("ace" callExtension ["ballistics:zero_advanced", [
|
||||
_zeroRange,
|
||||
_muzzleVelocity,
|
||||
_airFriction,
|
||||
_boreHeight,
|
||||
_temperature,
|
||||
_barometricPressure,
|
||||
_relativeHumidity,
|
||||
_bc,
|
||||
_dragModel,
|
||||
_atmosphereModel
|
||||
]]) select 0)
|
||||
};
|
||||
|
||||
GVAR(workingMemory) set [2, _zeroRange];
|
||||
|
@ -50,8 +50,8 @@ if (_unit == _attachToVehicle) then { //Self Attachment
|
||||
} else {
|
||||
GVAR(placeAction) = PLACE_WAITING;
|
||||
|
||||
[_unit, "forceWalk", "ACE_Attach", true] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "blockThrow", "ACE_Attach", true] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "forceWalk", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "blockThrow", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
|
||||
|
||||
[{[localize LSTRING(PlaceAction), ""] call EFUNC(interaction,showMouseHint)}, []] call CBA_fnc_execNextFrame;
|
||||
_unit setVariable [QGVAR(placeActionEH), [_unit, "DefaultAction", {true}, {GVAR(placeAction) = PLACE_APPROVE;}] call EFUNC(common,AddActionEventHandler)];
|
||||
@ -88,8 +88,8 @@ if (_unit == _attachToVehicle) then { //Self Attachment
|
||||
{!([_attachToVehicle, _unit, _itemClassname] call FUNC(canAttach))}) then {
|
||||
|
||||
[_idPFH] call CBA_fnc_removePerFrameHandler;
|
||||
[_unit, "forceWalk", "ACE_Attach", false] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "blockThrow", "ACE_Attach", false] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "blockThrow", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
|
||||
[] call EFUNC(interaction,hideMouseHint);
|
||||
[_unit, "DefaultAction", (_unit getVariable [QGVAR(placeActionEH), -1])] call EFUNC(common,removeActionEventHandler);
|
||||
_unit removeAction _actionID;
|
||||
|
@ -28,7 +28,7 @@ if (_attachedList isEqualTo []) exitWith {};
|
||||
TRACE_2("detaching",_xObject,_deadUnit);
|
||||
detach _xObject;
|
||||
//If it's a vehicle, also delete the attached
|
||||
if (!(_deadUnit isKindOf "CAManBase")) then {
|
||||
if !(_deadUnit isKindOf "CAManBase") then {
|
||||
_xObject setPos ((getPos _deadUnit) vectorAdd [0, 0, -1000]);
|
||||
[{deleteVehicle (_this select 0)}, [_xObject], 2] call CBA_fnc_waitAndExecute;
|
||||
};
|
||||
|
@ -1505,7 +1505,7 @@
|
||||
<Portuguese>Carregador de 10 cartuchos 9.3 mm traçantes IR-DIM</Portuguese>
|
||||
<Hungarian>9,3 mm 10-lövedékes infravörös nyomkövető tár</Hungarian>
|
||||
<Japanese>9.3mm 10Rnd IR-DIM トレーサー マガジン</Japanese>
|
||||
<Korean>10발들이 9.3mm IR-DIM 예광탄 탄창</Korean>
|
||||
<Korean>10발 들이 9.3mm IR-DIM 예광탄 탄창</Korean>
|
||||
<Chinese>9.3毫米 10發 低視度紅外線曳光彈 彈匣</Chinese>
|
||||
<Chinesesimp>9.3 mm 10发 弹匣(红外曳光)</Chinesesimp>
|
||||
<Turkish>9.3 mm 10Rnd Tracer IR-DIM Mag</Turkish>
|
||||
@ -1608,7 +1608,7 @@
|
||||
<Portuguese>Cinto de munição traçante 9.3 mm IR-DIM com 150 cartuchos</Portuguese>
|
||||
<Hungarian>9,3 mm 150-lövedékes infravörös nyomkövető heveder</Hungarian>
|
||||
<Japanese>9.3mm 150Rnd IR-DIM トレーサー ベルト</Japanese>
|
||||
<Korean>150발들이 9.3mm IR-DIM 예광탄 벨트</Korean>
|
||||
<Korean>150발 들이 9.3mm IR-DIM 예광탄 벨트</Korean>
|
||||
<Chinese>9.3毫米 150發 低視度紅外線曳光彈 彈鏈</Chinese>
|
||||
<Chinesesimp>9.3 mm 150发 弹链(红外曳光)</Chinesesimp>
|
||||
<Turkish>9.3 mm 150Rnd Tracer IR-DIM Belt</Turkish>
|
||||
@ -1659,7 +1659,7 @@
|
||||
<Portuguese>Cinto de munição 9.3 mm AP com 150 cartuchos</Portuguese>
|
||||
<Hungarian>9,3 mm 150-lövedékes páncéltörő heveder</Hungarian>
|
||||
<Japanese>9.3mm 150Rnd 徹甲弾 ベルト</Japanese>
|
||||
<Korean>150발들이 9.3mm 철갑탄 벨트</Korean>
|
||||
<Korean>150발 들이 9.3mm 철갑탄 벨트</Korean>
|
||||
<Chinese>9.3毫米 150發 穿甲彈 彈鏈</Chinese>
|
||||
<Chinesesimp>9.3 mm 150发 弹链(穿甲)</Chinesesimp>
|
||||
<Turkish>9.3 mm 150Rnd AP Belt</Turkish>
|
||||
@ -1710,7 +1710,7 @@
|
||||
<Portuguese>Carregador de 16 cartuchos 9x19 mm</Portuguese>
|
||||
<Hungarian>9x19 mm 16-lövedékes tár</Hungarian>
|
||||
<Japanese>9x19 mm 16Rnd マガジン</Japanese>
|
||||
<Korean>17발들이 9x19mm 탄창</Korean>
|
||||
<Korean>16발 들이 9x19mm 탄창</Korean>
|
||||
<Chinese>9x19毫米 16發 彈匣</Chinese>
|
||||
<Chinesesimp>9x19 mm 16发 弹匣</Chinesesimp>
|
||||
<Turkish>9x19 mm 16Rnd Mag</Turkish>
|
||||
@ -2016,7 +2016,7 @@
|
||||
<Portuguese>Carregador 5.56 mm com 30 cartuchos (Mk318)</Portuguese>
|
||||
<Hungarian>5,56 mm 30-lövedékes tár (Mk318)</Hungarian>
|
||||
<Japanese>5.56mm 30Rnd マガジン (Mk318)</Japanese>
|
||||
<Korean>30발들이 5.56mm 탄창 (Mk.318)</Korean>
|
||||
<Korean>30발 들이 5.56mm 탄창 (Mk.318)</Korean>
|
||||
<Chinese>5.56毫米 30發 彈匣 (Mk318 特戰專用彈)</Chinese>
|
||||
<Chinesesimp>5.56 mm 30发 弹匣(Mk318)</Chinesesimp>
|
||||
<Turkish>5.56 mm 30Rnd Mag (Mk318)</Turkish>
|
||||
@ -2322,7 +2322,7 @@
|
||||
<Portuguese>Carregador 7.62 mm com 10 cartuchos (Mk319 Mod 0)</Portuguese>
|
||||
<Hungarian>7,62 mm 10-lövedékes tár (Mk319 Mod 0)</Hungarian>
|
||||
<Japanese>7.62mm 10Rnd マガジン (Mk319 Mod 0)</Japanese>
|
||||
<Korean>10발들이 7.62mm 탄창 (Mk.319 Mod 0)</Korean>
|
||||
<Korean>10발 들이 7.62mm 탄창 (Mk.319 Mod 0)</Korean>
|
||||
<Chinese>7.62毫米 10發 彈匣 (Mk319 Mod 0 特戰專用彈)</Chinese>
|
||||
<Chinesesimp>7.62 mm 10发 弹匣(Mk319 Mod 0)</Chinesesimp>
|
||||
<Turkish>7.62 mm 10Rnd Mag (Mk319 Mod 0)</Turkish>
|
||||
@ -3344,7 +3344,7 @@
|
||||
<Portuguese>Carregador 12.7x99 mm (AMAX) com 5 cartuchos </Portuguese>
|
||||
<Hungarian>12,7x99 mm 5-lövedékes tár (AMAX)</Hungarian>
|
||||
<Japanese>12.7x99mm 5Rnd マガジン (AMAX)</Japanese>
|
||||
<Korean>5발들이 12.7x99mm 탄창 (AMAX)</Korean>
|
||||
<Korean>5발 들이 12.7x99mm 탄창 (AMAX)</Korean>
|
||||
<Chinese>12.7x99毫米 5發 彈匣 (AMAX 比賽專用彈)</Chinese>
|
||||
<Chinesesimp>12.7x99 mm 5发 弹匣(AMAX)</Chinesesimp>
|
||||
<Turkish>12.7x99 mm 5Rnd Şarjör (AMAX)</Turkish>
|
||||
@ -3378,7 +3378,7 @@
|
||||
<Portuguese>Carregador 12.7x99 mm (AMAX) com 10 cartuchos </Portuguese>
|
||||
<Hungarian>12,7x99 mm 10-lövedékes tár (AMAX)</Hungarian>
|
||||
<Japanese>12.7x99mm 10Rnd マガジン (AMAX)</Japanese>
|
||||
<Korean>10발들이 12.7x99mm 탄창 (AMAX)</Korean>
|
||||
<Korean>10발 들이 12.7x99mm 탄창 (AMAX)</Korean>
|
||||
<Chinese>12.7x99毫米 10發 彈匣 (AMAX 比賽專用彈)</Chinese>
|
||||
<Chinesesimp>12.7x99 mm 10发 弹匣(AMAX)</Chinesesimp>
|
||||
<Turkish>12.7x99 mm 10Rnd Şarjör (AMAX)</Turkish>
|
||||
|
@ -24,7 +24,7 @@ if (isServer) then {
|
||||
}];
|
||||
};
|
||||
|
||||
["unit", FUNC(handlePlayerChanged)] call CBA_fnc_addPlayerEventHandler;
|
||||
["unit", LINKFUNC(handlePlayerChanged)] call CBA_fnc_addPlayerEventHandler;
|
||||
[QGVAR(moveInCaptive), LINKFUNC(vehicleCaptiveMoveIn)] call CBA_fnc_addEventHandler;
|
||||
[QGVAR(moveOutCaptive), LINKFUNC(vehicleCaptiveMoveOut)] call CBA_fnc_addEventHandler;
|
||||
|
||||
|
@ -21,7 +21,6 @@ params ["_unit", "_target"];
|
||||
|
||||
(_target getVariable [QGVAR(isHandcuffed), false]) &&
|
||||
{isNull (attachedTo _target)} &&
|
||||
{alive _target} &&
|
||||
{!(_target getVariable ["ACE_isUnconscious", false])} &&
|
||||
{_target call EFUNC(common,isAwake)} &&
|
||||
{(vehicle _unit) == _unit} &&
|
||||
{(vehicle _target) == _target}
|
||||
|
@ -20,7 +20,7 @@
|
||||
params ["_unit", "_target", "_vehicle"];
|
||||
|
||||
// Don't show "Load Captive" if unit is unconscious (already has "Load Patient")
|
||||
if (_target getVariable ["ACE_isUnconscious", false]) exitWith {false};
|
||||
if !(_target call EFUNC(common,isAwake)) exitWith {false};
|
||||
|
||||
if ((isNull _target) && {_unit getVariable [QGVAR(isEscorting), false]}) then {
|
||||
//Looking at a vehicle while escorting, get target from attached objects:
|
||||
|
@ -39,12 +39,12 @@ if (_state) then {
|
||||
_args params ["_unit", "_target", "_actionID"];
|
||||
|
||||
if (_unit getVariable [QGVAR(isEscorting), false]) then {
|
||||
if (!alive _target || {!alive _unit} || {!canStand _target} || {!canStand _unit} || {_target getVariable ["ACE_isUnconscious", false]} || {_unit getVariable ["ACE_isUnconscious", false]} || {!isNull (attachedTo _unit)}) then {
|
||||
if (!canStand _target || {!canStand _unit} || {!(_target call EFUNC(common,isAwake))} || {!(_unit call EFUNC(common,isAwake))} || {!isNull (attachedTo _unit)}) then {
|
||||
_unit setVariable [QGVAR(isEscorting), false, true];
|
||||
};
|
||||
};
|
||||
|
||||
if (!(_unit getVariable [QGVAR(isEscorting), false])) then {
|
||||
if !(_unit getVariable [QGVAR(isEscorting), false]) then {
|
||||
[(_this select 1)] call CBA_fnc_removePerFrameHandler;
|
||||
[objNull, _target, false] call EFUNC(common,claim);
|
||||
detach _target;
|
||||
|
@ -19,7 +19,7 @@
|
||||
params ["_unit", "_newAnimation"];
|
||||
TRACE_2("AnimChanged",_unit,_newAnimation);
|
||||
if (_unit == (vehicle _unit)) then {
|
||||
if ((_newAnimation != "ACE_AmovPercMstpSsurWnonDnon") && {!(_unit getVariable ["ACE_isUnconscious", false])}) then {
|
||||
if ((_newAnimation != "ACE_AmovPercMstpSsurWnonDnon") && {_unit call EFUNC(common,isAwake)}) then {
|
||||
TRACE_1("Handcuff animation interrupted",_newAnimation);
|
||||
[_unit, "ACE_AmovPercMstpScapWnonDnon", 1] call EFUNC(common,doAnimation);
|
||||
};
|
||||
|
@ -19,7 +19,7 @@
|
||||
params ["_unit", "_newAnimation"];
|
||||
|
||||
TRACE_2("AnimChanged",_unit,_newAnimation);
|
||||
if ((_newAnimation != "ACE_AmovPercMstpSsurWnonDnon") && {!(_unit getVariable ["ACE_isUnconscious", false])}) then {
|
||||
if ((_newAnimation != "ACE_AmovPercMstpSsurWnonDnon") && {_unit call EFUNC(common,isAwake)}) then {
|
||||
TRACE_1("Surrender animation interrupted",_newAnimation);
|
||||
[_unit, "ACE_AmovPercMstpSsurWnonDnon", 1] call EFUNC(common,doAnimation);
|
||||
};
|
||||
|
@ -40,12 +40,12 @@ if (_respawn > 3) then {
|
||||
if (_unit getVariable [QGVAR(isHandcuffed), false]) then {
|
||||
[_unit, false] call FUNC(setHandcuffed);
|
||||
};
|
||||
[_unit, "setCaptive", QGVAR(Handcuffed), false] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "setCaptive", QGVAR(handcuffed), false] call EFUNC(common,statusEffect_set);
|
||||
|
||||
if (_unit getVariable [QGVAR(isSurrendering), false]) then {
|
||||
[_unit, false] call FUNC(setSurrendered);
|
||||
};
|
||||
[_unit, "setCaptive", QGVAR(Surrendered), false] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "setCaptive", QGVAR(surrendered), false] call EFUNC(common,statusEffect_set);
|
||||
|
||||
if (_unit getVariable [QGVAR(isEscorting), false]) then {
|
||||
_unit setVariable [QGVAR(isEscorting), false, true];
|
||||
|
@ -41,8 +41,8 @@ if ((_unit getVariable [QGVAR(isHandcuffed), false]) isEqualTo _state) exitWith
|
||||
|
||||
if (_state) then {
|
||||
_unit setVariable [QGVAR(isHandcuffed), true, true];
|
||||
[_unit, "setCaptive", QGVAR(Handcuffed), true] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "blockRadio", QGVAR(Handcuffed), true] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "setCaptive", QGVAR(handcuffed), true] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "blockRadio", QGVAR(handcuffed), true] call EFUNC(common,statusEffect_set);
|
||||
|
||||
if (_unit getVariable [QGVAR(isSurrendering), false]) then { //If surrendering, stop
|
||||
[_unit, false] call FUNC(setSurrendered);
|
||||
@ -58,7 +58,7 @@ if (_state) then {
|
||||
// fix anim on mission start (should work on dedicated servers)
|
||||
[{
|
||||
params ["_unit"];
|
||||
if (!(_unit getVariable [QGVAR(isHandcuffed), false])) exitWith {};
|
||||
if !(_unit getVariable [QGVAR(isHandcuffed), false]) exitWith {};
|
||||
|
||||
if ((vehicle _unit) == _unit) then {
|
||||
[_unit] call EFUNC(common,fixLoweredRifleAnimation);
|
||||
@ -82,8 +82,8 @@ if (_state) then {
|
||||
}, [_unit], 0.01] call CBA_fnc_waitAndExecute;
|
||||
} else {
|
||||
_unit setVariable [QGVAR(isHandcuffed), false, true];
|
||||
[_unit, "setCaptive", QGVAR(Handcuffed), false] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "blockRadio", QGVAR(Handcuffed), false] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "setCaptive", QGVAR(handcuffed), false] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "blockRadio", QGVAR(handcuffed), false] call EFUNC(common,statusEffect_set);
|
||||
|
||||
//remove AnimChanged EH
|
||||
private _animChangedEHID = _unit getVariable [QGVAR(handcuffAnimEHID), -1];
|
||||
@ -91,7 +91,7 @@ if (_state) then {
|
||||
_unit removeEventHandler ["AnimChanged", _animChangedEHID];
|
||||
_unit setVariable [QGVAR(handcuffAnimEHID), -1];
|
||||
|
||||
if (((vehicle _unit) == _unit) && {!(_unit getVariable ["ACE_isUnconscious", false])}) then {
|
||||
if (((vehicle _unit) == _unit) && {_unit call EFUNC(common,isAwake)}) then {
|
||||
//Break out of hands up animation loop
|
||||
[_unit, "ACE_AmovPercMstpScapWnonDnon_AmovPercMstpSnonWnonDnon", 2] call EFUNC(common,doAnimation);
|
||||
};
|
||||
|
@ -44,8 +44,8 @@ if (_state) then {
|
||||
|
||||
_unit setVariable [QGVAR(isSurrendering), true, true];
|
||||
|
||||
[_unit, "setCaptive", QGVAR(Surrendered), true] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "blockRadio", QGVAR(Surrendered), true] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "setCaptive", QGVAR(surrendered), true] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "blockRadio", QGVAR(surrendered), true] call EFUNC(common,statusEffect_set);
|
||||
|
||||
if (_unit == ACE_player) then {
|
||||
["captive", [false, false, false, false, false, false, false, false, false, true]] call EFUNC(common,showHud);
|
||||
@ -71,8 +71,8 @@ if (_state) then {
|
||||
}, [_unit], 0.01] call CBA_fnc_waitAndExecute;
|
||||
} else {
|
||||
_unit setVariable [QGVAR(isSurrendering), false, true];
|
||||
[_unit, "setCaptive", QGVAR(Surrendered), false] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "blockRadio", QGVAR(Surrendered), false] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "setCaptive", QGVAR(surrendered), false] call EFUNC(common,statusEffect_set);
|
||||
[_unit, "blockRadio", QGVAR(surrendered), false] call EFUNC(common,statusEffect_set);
|
||||
|
||||
//remove AnimChanged EH
|
||||
private _animChangedEHID = _unit getVariable [QGVAR(surrenderAnimEHID), -1];
|
||||
@ -81,13 +81,12 @@ if (_state) then {
|
||||
|
||||
if (_unit == ACE_player) then {
|
||||
//only re-enable HUD if not handcuffed
|
||||
if (!(_unit getVariable [QGVAR(isHandcuffed), false])) then {
|
||||
if !(_unit getVariable [QGVAR(isHandcuffed), false]) then {
|
||||
["captive", []] call EFUNC(common,showHud); //same as showHud true;
|
||||
};
|
||||
};
|
||||
|
||||
if (!alive _unit) exitWith {};
|
||||
if (_unit getVariable ["ACE_isUnconscious", false]) exitWith {}; //don't touch animations if unconscious
|
||||
if !(_unit call EFUNC(common,isAwake)) exitWith {}; //don't touch animations if unconscious
|
||||
|
||||
//if we are in "hands up" animationState, crack it now
|
||||
if (((vehicle _unit) == _unit) && {(animationState _unit) == "ACE_AmovPercMstpSsurWnonDnon"}) then {
|
||||
@ -99,7 +98,7 @@ if (_state) then {
|
||||
params ["_args", "_pfID"];
|
||||
_args params ["_unit", "_maxTime"];
|
||||
//If waited long enough or they re-surrendered or they are unconscious, exit loop
|
||||
if ((CBA_missionTime > _maxTime) || {_unit getVariable [QGVAR(isSurrendering), false]} || {_unit getVariable ["ACE_isUnconscious", false]}) exitWith {
|
||||
if ((CBA_missionTime > _maxTime) || {_unit getVariable [QGVAR(isSurrendering), false]} || {!(_unit call EFUNC(common,isAwake))}) exitWith {
|
||||
[_pfID] call CBA_fnc_removePerFrameHandler;
|
||||
};
|
||||
//Only break animation if they are actualy the "hands up" animation (because we are using switchmove there won't be an transition)
|
||||
|
@ -158,6 +158,7 @@
|
||||
<Japanese>目隠しを外す</Japanese>
|
||||
<Russian>Снять повязку с глаз</Russian>
|
||||
<Spanish>Quitar vendas de los ojos</Spanish>
|
||||
<Portuguese>Remover a venda</Portuguese>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Captives_CableTie">
|
||||
<English>Cable Tie</English>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user