mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
Artillery rangletables (universal) (#6853)
* Initial
* Update artillerytables.cpp
* Pass by value, remove c17 features
* Tweak accuracy
* SQF work
- improve compat with a3 mlrs with remote cam (animationSourcePhase)
- handle non [0] turrets (rhs prp)
- add config entries
- use vectorCos to fix fp error (thanks commy)
* Support per mag air friction
* tweak friction
* Integrate with mk6
* more acos fixes
* Handle invalid memPointGunOptic (CUP_BM21_Base)
* Cleanup
* cleanup/tweaks
* Update checkConfigs.sqf
* Finish cleanup of ace_mk6mortar
* Update stringtable.xml
* fix bwc for ACE_RangeTable_82mm
* Update fnc_rangeTableCanUse.sqf
* build 32dll, fix some headers
* strncpy and move testing to seperate file
* Move to sub-category
* Update for ACE_Extensions changes and add warning to ace_common
* Update stringtable.xml
* Update addons/common/functions/fnc_checkFiles.sqf
Co-Authored-By: jonpas <jonpas33@gmail.com>
* Update stringtable.xml
* Update stringtable.xml
* test extension.yml update logical operator
* Revert "test extension.yml update logical operator"
This reverts commit b1871724ad
.
* more guess and test
This commit is contained in:
parent
240c7333e3
commit
8e3fd45500
1
.github/workflows/extensions.yml
vendored
1
.github/workflows/extensions.yml
vendored
@ -20,6 +20,7 @@ jobs:
|
|||||||
- name: Checkout the source code
|
- name: Checkout the source code
|
||||||
uses: actions/checkout@master
|
uses: actions/checkout@master
|
||||||
- name: Build
|
- name: Build
|
||||||
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
cd extensions/build
|
cd extensions/build
|
||||||
cmake .. && cmake --build .
|
cmake .. && cmake --build .
|
||||||
|
BIN
ace_artillerytables.dll
Normal file
BIN
ace_artillerytables.dll
Normal file
Binary file not shown.
BIN
ace_artillerytables_x64.dll
Normal file
BIN
ace_artillerytables_x64.dll
Normal file
Binary file not shown.
1
addons/artillerytables/$PBOPREFIX$
Normal file
1
addons/artillerytables/$PBOPREFIX$
Normal file
@ -0,0 +1 @@
|
|||||||
|
z\ace\addons\artillerytables
|
15
addons/artillerytables/CfgEventHandlers.hpp
Normal file
15
addons/artillerytables/CfgEventHandlers.hpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
class Extended_PreStart_EventHandlers {
|
||||||
|
class ADDON {
|
||||||
|
init = QUOTE(call COMPILE_FILE(XEH_preStart));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
class Extended_PreInit_EventHandlers {
|
||||||
|
class ADDON {
|
||||||
|
init = QUOTE(call COMPILE_FILE(XEH_preInit));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
class Extended_PostInit_EventHandlers {
|
||||||
|
class ADDON {
|
||||||
|
init = QUOTE(call COMPILE_FILE(XEH_postInit));
|
||||||
|
};
|
||||||
|
};
|
6
addons/artillerytables/CfgMagazines.hpp
Normal file
6
addons/artillerytables/CfgMagazines.hpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
class CfgMagazines {
|
||||||
|
class 32Rnd_155mm_Mo_shells;
|
||||||
|
class 8Rnd_82mm_Mo_shells: 32Rnd_155mm_Mo_shells {
|
||||||
|
GVAR(airFriction) = -0.0001;
|
||||||
|
};
|
||||||
|
};
|
7
addons/artillerytables/CfgVehicles.hpp
Normal file
7
addons/artillerytables/CfgVehicles.hpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
class CfgVehicles {
|
||||||
|
class StaticWeapon;
|
||||||
|
class StaticMortar: StaticWeapon {
|
||||||
|
// Small mortars seem to need the alternate elevation calculations,
|
||||||
|
GVAR(showGunLaying) = 2;
|
||||||
|
};
|
||||||
|
};
|
15
addons/artillerytables/CfgWeapons.hpp
Normal file
15
addons/artillerytables/CfgWeapons.hpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
class CfgWeapons {
|
||||||
|
class ACE_ItemCore;
|
||||||
|
class CBA_MiscItem_ItemInfo;
|
||||||
|
|
||||||
|
class ACE_artilleryTable: ACE_ItemCore {
|
||||||
|
author = ECSTRING(common,ACETeam);
|
||||||
|
scope = 2;
|
||||||
|
displayName = CSTRING(rangetable_displayName);
|
||||||
|
descriptionShort = CSTRING(rangetable_description);
|
||||||
|
picture = QPATHTOF(UI\icon_rangeTable.paa);
|
||||||
|
class ItemInfo: CBA_MiscItem_ItemInfo {
|
||||||
|
mass = 0.5;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
14
addons/artillerytables/README.md
Normal file
14
addons/artillerytables/README.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
ace_artillerytables
|
||||||
|
==========
|
||||||
|
|
||||||
|
Universal artillery rangetables.
|
||||||
|
|
||||||
|
#### Items Added:
|
||||||
|
`ACE_artilleryTable`
|
||||||
|
|
||||||
|
|
||||||
|
## Maintainers
|
||||||
|
|
||||||
|
The people responsible for merging changes to this component or answering potential questions.
|
||||||
|
|
||||||
|
- [PabstMirror](https://github.com/PabstMirror)
|
96
addons/artillerytables/RscRangeTable.hpp
Normal file
96
addons/artillerytables/RscRangeTable.hpp
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
class GVAR(rangeTableDialog) {
|
||||||
|
idd = -1;
|
||||||
|
movingEnable = 1;
|
||||||
|
onLoad = QUOTE(with uiNameSpace do { GVAR(rangeTableDialog) = _this select 0 };);
|
||||||
|
objects[] = {};
|
||||||
|
|
||||||
|
class ControlsBackground {
|
||||||
|
class TableBackground: RscPicture {
|
||||||
|
idc = -1;
|
||||||
|
text = QPATHTOF(UI\RangeTable_background.paa);
|
||||||
|
x = "18 *(safeZoneH / 40) + (safezoneX + (safezoneW - safeZoneH) / 2)";
|
||||||
|
y = "1 * ((safeZoneH / 1.2) / 25) + (safezoneY + (safezoneH - (safeZoneH / 1.2)) / 2)";
|
||||||
|
w = "16.2634559672906 * (safeZoneH / 40)";
|
||||||
|
h = "23 * ((safeZoneH / 1.2) / 25)";
|
||||||
|
colorBackground[] = {1,1,1,1};
|
||||||
|
};
|
||||||
|
class LeftSideBackground: RscText {
|
||||||
|
idc = -1;
|
||||||
|
x = "13 *(safeZoneH / 40) + (safezoneX + (safezoneW - safeZoneH) / 2)";
|
||||||
|
y = "1 * ((safeZoneH / 1.2) / 25) + (safezoneY + (safezoneH - (safeZoneH / 1.2)) / 2)";
|
||||||
|
w = "5 * (safeZoneH / 40)";
|
||||||
|
h = "23 * ((safeZoneH / 1.2) / 25)";
|
||||||
|
colorBackground[] = {0,0,0,0.8};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
class controls {
|
||||||
|
class TheTable: RscListNBox {
|
||||||
|
idc = IDC_TABLE;
|
||||||
|
x = "18 *(safeZoneH / 40) + (safezoneX + (safezoneW - safeZoneH) / 2)";
|
||||||
|
y = "3.76 * ((safeZoneH / 1.2) / 25) + (safezoneY + (safezoneH - (safeZoneH / 1.2)) / 2)";
|
||||||
|
w = "16.2634559672906 * (safeZoneH / 40)";
|
||||||
|
h = "20.24 * ((safeZoneH / 1.2) / 25)";
|
||||||
|
columns[] = {(10/867),(86/867),(171/867),(238/867),(320/867),(405/867),(485/867),(546/867),(607/867),(668/867),(729/867),(790/867)};
|
||||||
|
rowHeight = 0.015 * safeZoneH;
|
||||||
|
sizeEx = "0.014 * safeZoneH";
|
||||||
|
font = "EtelkaMonospacePro";
|
||||||
|
drawSideArrows = 1;
|
||||||
|
idcLeft = -1;
|
||||||
|
idcRight = -1;
|
||||||
|
colorText[] = {0, 0, 0, 1};
|
||||||
|
shadow = "0";
|
||||||
|
colorSelectBackground[] = {0, 0, 0, 0.025};
|
||||||
|
colorSelectBackground2[] = {0, 0, 0, 0.025};
|
||||||
|
colorScrollbar[] = {0.95,0,0.95,1};
|
||||||
|
class ListScrollBar: ScrollBar{
|
||||||
|
color[] = {0,0,0,0.6};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
class ChargeListBox: RscListbox {
|
||||||
|
idc = IDC_CHARGELIST;
|
||||||
|
style = ST_RIGHT;
|
||||||
|
x = "13 *(safeZoneH / 40) + (safezoneX + (safezoneW - safeZoneH) / 2)";
|
||||||
|
y = "2 * ((safeZoneH / 1.2) / 25) + (safezoneY + (safezoneH - (safeZoneH / 1.2)) / 2)";
|
||||||
|
w = "5 * (safeZoneH / 40)";
|
||||||
|
h = "22 * ((safeZoneH / 1.2) / 25)";
|
||||||
|
onLBSelChanged = QUOTE([] call FUNC(rangeTableUpdate));
|
||||||
|
};
|
||||||
|
class elevationHigh: ctrlButton {
|
||||||
|
idc = IDC_BUTTON_ELEV_HIGH;
|
||||||
|
text = "High";
|
||||||
|
onButtonClick = QUOTE([true] call FUNC(rangeTableUpdate));
|
||||||
|
x = "13.1 *(safeZoneH / 40) + (safezoneX + (safezoneW - safeZoneH) / 2)";
|
||||||
|
y = "1.1 * ((safeZoneH / 1.2) / 25) + (safezoneY + (safezoneH - (safeZoneH / 1.2)) / 2)";
|
||||||
|
w = "2.3 * (safeZoneH / 40)";
|
||||||
|
h = "0.8 * ((safeZoneH / 1.2) / 25)";
|
||||||
|
};
|
||||||
|
class elevationLow: elevationHigh {
|
||||||
|
idc = IDC_BUTTON_ELEV_LOW;
|
||||||
|
text = "Low";
|
||||||
|
onButtonClick = QUOTE([false] call FUNC(rangeTableUpdate));
|
||||||
|
x = "15.6 *(safeZoneH / 40) + (safezoneX + (safezoneW - safeZoneH) / 2)";
|
||||||
|
};
|
||||||
|
class CloseBackground: RscText {
|
||||||
|
idc = -1;
|
||||||
|
x = "33.7634559672906 *(safeZoneH / 40) + (safezoneX + (safezoneW - safeZoneH) / 2)";
|
||||||
|
y = "1 * ((safeZoneH / 1.2) / 25) + (safezoneY + (safezoneH - (safeZoneH / 1.2)) / 2)";
|
||||||
|
w = "0.5 * (safeZoneH / 40)";
|
||||||
|
h = "0.5 * ((safeZoneH / 1.2) / 25)";
|
||||||
|
colorBackground[] = {0,0,0,0.5};
|
||||||
|
};
|
||||||
|
class CloseActiveText: RscActiveText {
|
||||||
|
idc = -1;
|
||||||
|
style = 48;
|
||||||
|
color[] = {1,1,1,0.7};
|
||||||
|
text = "A3\Ui_f\data\GUI\Rsc\RscDisplayArcadeMap\icon_exit_cross_ca.paa";
|
||||||
|
x = "33.7634559672906 *(safeZoneH / 40) + (safezoneX + (safezoneW - safeZoneH) / 2)";
|
||||||
|
y = "1 * ((safeZoneH / 1.2) / 25) + (safezoneY + (safezoneH - (safeZoneH / 1.2)) / 2)";
|
||||||
|
w = "0.5 * (safeZoneH / 40)";
|
||||||
|
h = "0.5 * ((safeZoneH / 1.2) / 25)";
|
||||||
|
colorText[] = {1,1,1,0.7};
|
||||||
|
colorActive[] = {1,1,1,1};
|
||||||
|
tooltip = "Close";
|
||||||
|
onButtonClick = "closeDialog 0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
42
addons/artillerytables/RscTitles.hpp
Normal file
42
addons/artillerytables/RscTitles.hpp
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
class RscTitles {
|
||||||
|
class GVAR(modeDisplay) {
|
||||||
|
idd = -1;
|
||||||
|
onLoad = QUOTE(with uiNameSpace do { GVAR(display) = _this select 0 };);
|
||||||
|
movingEnable = 0;
|
||||||
|
duration = 60;
|
||||||
|
fadeIn = "false";
|
||||||
|
fadeOut = "false";
|
||||||
|
class controls {
|
||||||
|
class ModeControlGroup: RscControlsGroupNoScrollbars {
|
||||||
|
idc = IDC_MODECONTROLGROUP;
|
||||||
|
x = "3.8 * (((safezoneW / safezoneH) min 1.2) / 40) + (profilenamespace getvariable ['IGUI_GRID_WEAPON_X',((safezoneX + safezoneW) - (10 * (((safezoneW / safezoneH) min 1.2) / 40)) - 4.3 * (((safezoneW / safezoneH) min 1.2) / 40))])";
|
||||||
|
y = "2.5 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (profilenamespace getVariable ['IGUI_GRID_WEAPON_Y', (safezoneY + 0.5 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25))])";
|
||||||
|
w = "10 * (((safezoneW / safezoneH) min 1.2) / 40)";
|
||||||
|
h = "1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)";
|
||||||
|
|
||||||
|
class controls {
|
||||||
|
class Charge: RscText {
|
||||||
|
idc = IDC_CHARGE;
|
||||||
|
colorText[] = {1, 1, 1, 1};
|
||||||
|
colorBackground[] = {0, 0, 0, 0};
|
||||||
|
x = "0";
|
||||||
|
y = "0";
|
||||||
|
w = "(2) * (((safezoneW / safezoneH) min 1.2) / 40)";
|
||||||
|
h = "1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)";
|
||||||
|
sizeEx = "0.8 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)";
|
||||||
|
};
|
||||||
|
class Azimuth: Charge {
|
||||||
|
idc = IDC_AZIMUTH;
|
||||||
|
x = "(2) * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)";
|
||||||
|
w = "(3) * (((safezoneW / safezoneH) min 1.2) / 40)";
|
||||||
|
};
|
||||||
|
class Elevation: Azimuth {
|
||||||
|
idc = IDC_ELEVATION;
|
||||||
|
x = "(5) * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
BIN
addons/artillerytables/UI/RangeTable_background.paa
Normal file
BIN
addons/artillerytables/UI/RangeTable_background.paa
Normal file
Binary file not shown.
BIN
addons/artillerytables/UI/icon_rangeTable.paa
Normal file
BIN
addons/artillerytables/UI/icon_rangeTable.paa
Normal file
Binary file not shown.
8
addons/artillerytables/XEH_PREP.hpp
Normal file
8
addons/artillerytables/XEH_PREP.hpp
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
TRACE_1("prep",_this);
|
||||||
|
|
||||||
|
PREP(firedEH);
|
||||||
|
PREP(interactMenuOpened);
|
||||||
|
PREP(rangeTableOpen);
|
||||||
|
PREP(rangeTableUpdate);
|
||||||
|
PREP(turretChanged);
|
||||||
|
PREP(turretPFEH);
|
36
addons/artillerytables/XEH_postInit.sqf
Normal file
36
addons/artillerytables/XEH_postInit.sqf
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
["ace_settingsInitialized", {
|
||||||
|
TRACE_2("ace_settingsInitialized",GVAR(advancedCorrections),GVAR(disableArtilleryComputer));
|
||||||
|
|
||||||
|
if (hasInterface) then {
|
||||||
|
// Add hud overlay for actuall azimuth and elevation:
|
||||||
|
GVAR(pfID) = -1;
|
||||||
|
["turret", LINKFUNC(turretChanged), true] call CBA_fnc_addPlayerEventHandler;
|
||||||
|
|
||||||
|
// Add ability to dynamically open rangetables:
|
||||||
|
["ace_interactMenuOpened", LINKFUNC(interactMenuOpened)] call CBA_fnc_addEventHandler;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (GVAR(advancedCorrections)) then {
|
||||||
|
["LandVehicle", "init", {
|
||||||
|
params ["_vehicle"];
|
||||||
|
private _vehicleCfg = configFile >> "CfgVehicles" >> typeOf _vehicle;
|
||||||
|
// config "ace_artillerytables_applyCorrections" [0 disabled, 1 enabled] falls back to artilleryScanner
|
||||||
|
private _applyCorrections = if (isNumber (_vehicleCfg >> QGVAR(applyCorrections))) then {
|
||||||
|
getNumber (_vehicleCfg >> QGVAR(applyCorrections))
|
||||||
|
} else {
|
||||||
|
getNumber (_vehicleCfg >> "artilleryScanner")
|
||||||
|
};
|
||||||
|
if (_applyCorrections == 1) then {
|
||||||
|
TRACE_2("adding firedEH",_vehicle,configName _vehicleCfg);
|
||||||
|
_vehicle addEventHandler ["Fired", {call FUNC(firedEH)}];
|
||||||
|
};
|
||||||
|
}, true, [], true] call CBA_fnc_addClassEventHandler;
|
||||||
|
};
|
||||||
|
}] call CBA_fnc_addEventHandler;
|
||||||
|
|
||||||
|
#ifdef DEBUG_MODE_FULL
|
||||||
|
#include "dev\showShotInfo.sqf"
|
||||||
|
#include "dev\checkConfigs.sqf"
|
||||||
|
#endif
|
11
addons/artillerytables/XEH_preInit.sqf
Normal file
11
addons/artillerytables/XEH_preInit.sqf
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
ADDON = false;
|
||||||
|
|
||||||
|
PREP_RECOMPILE_START;
|
||||||
|
#include "XEH_PREP.hpp"
|
||||||
|
PREP_RECOMPILE_END;
|
||||||
|
|
||||||
|
#include "initSettings.sqf"
|
||||||
|
|
||||||
|
ADDON = true;
|
3
addons/artillerytables/XEH_preStart.sqf
Normal file
3
addons/artillerytables/XEH_preStart.sqf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
#include "XEH_PREP.hpp"
|
44
addons/artillerytables/config.cpp
Normal file
44
addons/artillerytables/config.cpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
class CfgPatches {
|
||||||
|
class ADDON {
|
||||||
|
name = COMPONENT_NAME;
|
||||||
|
units[] = {};
|
||||||
|
weapons[] = {};
|
||||||
|
requiredVersion = REQUIRED_VERSION;
|
||||||
|
requiredAddons[] = {"ace_interaction"};
|
||||||
|
author = ECSTRING(common,ACETeam);
|
||||||
|
authors[] = {"PabstMirror"};
|
||||||
|
url = ECSTRING(main,URL);
|
||||||
|
VERSION_CONFIG;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class ACE_Extensions {
|
||||||
|
class ace_artillerytables {
|
||||||
|
windows = 1;
|
||||||
|
client = 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "CfgEventHandlers.hpp"
|
||||||
|
#include "CfgMagazines.hpp"
|
||||||
|
#include "CfgVehicles.hpp"
|
||||||
|
#include "CfgWeapons.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
// Common UI Stuff:
|
||||||
|
class RscText;
|
||||||
|
class RscListbox;
|
||||||
|
class RscListNBox;
|
||||||
|
class RscPicture;
|
||||||
|
class RscControlsGroup;
|
||||||
|
class RscControlsGroupNoScrollbars;
|
||||||
|
class ScrollBar;
|
||||||
|
class RscActiveText;
|
||||||
|
class RscStructuredText;
|
||||||
|
class ctrlButton;
|
||||||
|
|
||||||
|
#include "RscTitles.hpp"
|
||||||
|
#include "RscRangeTable.hpp"
|
||||||
|
|
20
addons/artillerytables/dev/checkConfigs.sqf
Normal file
20
addons/artillerytables/dev/checkConfigs.sqf
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
diag_log text "-------------------------------------------";
|
||||||
|
INFO("Showing entries with custom configs");
|
||||||
|
diag_log text "-------------------------------------------";
|
||||||
|
|
||||||
|
|
||||||
|
private _fnc_showPropertyDefined = {
|
||||||
|
params ["_configBase", "_configProperty"];
|
||||||
|
|
||||||
|
private _customAll = configProperties [_configBase, 'isClass _x && {isNumber (_x >> _configProperty)}', true];
|
||||||
|
private _customExplicit = _customAll select {!([] isEqualTo configProperties [_x, 'configName _x == _configProperty', false])};
|
||||||
|
diag_log text format ["%1 with custom %2: %3 Explicit, %4 Total]", configName _configBase, _configProperty, count _customExplicit, count _customAll];
|
||||||
|
diag_log text format [" - Defined: %1", _customExplicit apply {configName _x}];
|
||||||
|
diag_log text format [" - Inherited: %1", _customAll apply {[configName _x, getNumber (_x >> _configProperty)]}];
|
||||||
|
};
|
||||||
|
|
||||||
|
[configFile >> "CfgMagazines", QGVAR(airFriction)] call _fnc_showPropertyDefined;
|
||||||
|
[configFile >> "CfgVehicles", QGVAR(showGunLaying)] call _fnc_showPropertyDefined;
|
||||||
|
[configFile >> "CfgVehicles", QGVAR(applyCorrections)] call _fnc_showPropertyDefined;
|
||||||
|
|
||||||
|
diag_log text "-------------------------------------------";
|
47
addons/artillerytables/dev/showShotInfo.sqf
Normal file
47
addons/artillerytables/dev/showShotInfo.sqf
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// #include "\z\ace\addons\artillerytables\script_component.hpp"
|
||||||
|
|
||||||
|
INFO("showing shot info");
|
||||||
|
|
||||||
|
["LandVehicle", "fired", {
|
||||||
|
params ["_shooter", "", "", "", "_ammo", "", "_proj"];
|
||||||
|
((velocity _proj) call CBA_fnc_vect2Polar) params ["_mag", "_dir", "_elev"];
|
||||||
|
private _shootPos = getPosASL _shooter;
|
||||||
|
if (_dir < 0) then {_dir = _dir + 360;};
|
||||||
|
|
||||||
|
private _offsetElev = _elev - (missionNamespace getVariable [QGVAR(predictedElevation), -999]);
|
||||||
|
private _offsetAz = _dir - (missionNamespace getVariable [QGVAR(predictedAzimuth), -999]);
|
||||||
|
|
||||||
|
hintSilent format ["%1 m/s\nAz: %2 [%3]\nEl: %4 [%5]\nError Az: %6\nError EL: %7",_mag toFixed 1, _dir toFixed 2, ((6400 / 360) * _dir) toFixed 0, _elev toFixed 2, ((6400 / 360) * _elev) toFixed 0,
|
||||||
|
_offsetAz toFixed 3, _offsetElev toFixed 3];
|
||||||
|
TRACE_2("",_offsetAz,_offsetElev);
|
||||||
|
private _submunitionAmmo = getText (configFile >> "CfgAmmo" >> _ammo >> "submunitionAmmo");
|
||||||
|
|
||||||
|
[{
|
||||||
|
params ["_proj", "_shootPos", "_lastPos", "_submunitionAmmo"];
|
||||||
|
if ((isNull _proj) && {_submunitionAmmo != ""}) then {
|
||||||
|
_proj = nearestObject [_lastPos, _submunitionAmmo];
|
||||||
|
_this set [0, _proj];
|
||||||
|
};
|
||||||
|
if (isNull _proj) exitWith {true};
|
||||||
|
_this set [2, getPosASL _proj];
|
||||||
|
false
|
||||||
|
}, {
|
||||||
|
params ["", "_shootPos", "_lastPos"];
|
||||||
|
private _mkrB = createMarker [format ["shotInfo-%1-%2",_shootPos,_lastPos], _lastPos];
|
||||||
|
_mkrB setMarkerType "mil_dot";
|
||||||
|
_mkrB setMarkerColor "ColorGreen";
|
||||||
|
_mkrB setMarkerSize [0.5,0.5];
|
||||||
|
private _diff = _lastPos vectorDiff _shootPos;
|
||||||
|
_mkrB setMarkerText format ["%1", _diff apply {round _x}];
|
||||||
|
|
||||||
|
private _dist2d = _shootPos distance2d _lastPos;
|
||||||
|
private _dir = _shootPos getDir _lastPos;
|
||||||
|
private _height = (_lastPos select 2) - (_shootPos select 2);
|
||||||
|
_mkrB setMarkerText format ["Dist: %1m Az: %2[%3] Height:%4", _dist2d toFixed 0, _dir toFixed 2, ((6400 / 360) * _dir) toFixed 0, _height toFixed 0];
|
||||||
|
}, [_proj, _shootPos, [0,0,0], _submunitionAmmo]] call CBA_fnc_waitUntilAndExecute;
|
||||||
|
|
||||||
|
private _mkrA = createMarker [format ["shotInfo-%1",_shootPos], _shootPos];
|
||||||
|
_mkrA setMarkerType "mil_dot";
|
||||||
|
_mkrA setMarkerColor "ColorRed";
|
||||||
|
_mkrA setMarkerSize [0.5,0.5];
|
||||||
|
}] call CBA_fnc_addClassEventHandler;
|
88
addons/artillerytables/functions/fnc_firedEH.sqf
Normal file
88
addons/artillerytables/functions/fnc_firedEH.sqf
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: PabstMirror
|
||||||
|
* Called when the mortar is fired.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* 0: mortar - Object the event handler is assigned to <OBJECT>
|
||||||
|
* 1: weapon - Fired weapon <STRING>
|
||||||
|
* 2: muzzle - Muzzle that was used <STRING>
|
||||||
|
* 3: mode - Current mode of the fired weapon <STRING>
|
||||||
|
* 4: ammo - Ammo used <STRING>
|
||||||
|
* 5: magazine - magazine name which was used <STRING>
|
||||||
|
* 6: projectile - Object of the projectile that was shot <OBJECT>
|
||||||
|
* 7: gunner - Gunner <OBJECT>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [bisFiredEH] call ace_artillerytables_fnc_firedEH
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
|
||||||
|
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 _vehicle) != _gunner) exitWith {}; // check if primaryGunner
|
||||||
|
|
||||||
|
|
||||||
|
// Get airFriction
|
||||||
|
private _airFriction = DEFAULT_AIR_FRICTION;
|
||||||
|
if (isNumber (configFile >> "CfgMagazines" >> _magazine >> QGVAR(airFriction))) then {
|
||||||
|
_airFriction = getNumber (configFile >> "CfgMagazines" >> _magazine >> QGVAR(airFriction));
|
||||||
|
};
|
||||||
|
TRACE_1("",_airFriction);
|
||||||
|
if (_airFriction >= 0) exitWith {}; // 0 disables everything, >0 makes no sense
|
||||||
|
|
||||||
|
BEGIN_COUNTER(adjustmentsCalc);
|
||||||
|
|
||||||
|
// Calculate air density
|
||||||
|
private _altitude = (getPosASL _vehicle) select 2;
|
||||||
|
private _temperature = _altitude call EFUNC(weather,calculateTemperatureAtHeight);
|
||||||
|
private _pressure = _altitude call EFUNC(weather,calculateBarometricPressure);
|
||||||
|
private _relativeHumidity = EGVAR(weather,currentHumidity);
|
||||||
|
private _airDensity = [_temperature, _pressure, _relativeHumidity] call EFUNC(weather,calculateAirDensity);
|
||||||
|
private _relativeDensity = _airDensity / 1.225;
|
||||||
|
TRACE_5("Weather",_temperature,_pressure,_relativeHumidity,_airDensity,_relativeDensity);
|
||||||
|
|
||||||
|
private _kFactor = _airFriction * _relativeDensity;
|
||||||
|
private _newMuzzleVelocityCoefficent = (((_temperature + 273.13) / 288.13 - 1) / 40 + 1);
|
||||||
|
TRACE_2("",_kFactor,_newMuzzleVelocityCoefficent);
|
||||||
|
|
||||||
|
// Apply powder effects
|
||||||
|
if (_newMuzzleVelocityCoefficent != 1) then {
|
||||||
|
private _bulletVelocity = velocity _projectile;
|
||||||
|
private _bulletSpeed = vectorMagnitude _bulletVelocity;
|
||||||
|
_bulletVelocity = (vectorNormalized _bulletVelocity) vectorMultiply (_bulletSpeed * _newMuzzleVelocityCoefficent);
|
||||||
|
_projectile setVelocity _bulletVelocity;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
[{
|
||||||
|
params ["_projectile", "_kFactor", "_time"];
|
||||||
|
|
||||||
|
if (isNull _projectile) exitWith {true};
|
||||||
|
|
||||||
|
private _deltaT = CBA_missionTime - _time;
|
||||||
|
_this set[2, CBA_missionTime];
|
||||||
|
|
||||||
|
private _bulletVelocity = velocity _projectile;
|
||||||
|
private _trueVelocity = _bulletVelocity vectorDiff wind;
|
||||||
|
private _trueSpeed = vectorMagnitude _trueVelocity;
|
||||||
|
|
||||||
|
private _drag = _deltaT * _kFactor * _trueSpeed;
|
||||||
|
private _accel = _trueVelocity vectorMultiply _drag;
|
||||||
|
// TRACE_3("",_bulletVelocity,_trueSpeed,_accel);
|
||||||
|
_bulletVelocity = _bulletVelocity vectorAdd _accel;
|
||||||
|
|
||||||
|
_projectile setVelocity _bulletVelocity;
|
||||||
|
|
||||||
|
false
|
||||||
|
}, {
|
||||||
|
// TRACE_1("done",_this);
|
||||||
|
}, [_projectile, _kFactor, CBA_missionTime]] call CBA_fnc_waitUntilAndExecute;
|
||||||
|
|
||||||
|
END_COUNTER(adjustmentsCalc);
|
108
addons/artillerytables/functions/fnc_interactMenuOpened.sqf
Normal file
108
addons/artillerytables/functions/fnc_interactMenuOpened.sqf
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: PabstMirror
|
||||||
|
* Interaction menu opened, search for nearby artillery vehicles.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* 0: Menu Type (1 is self interaction) <NUMBER>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* Can Open <BOOL>
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [1] call ace_artillerytables_fnc_interactMenuOpened
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
|
||||||
|
params ["_menuType"];
|
||||||
|
TRACE_1("interactMenuOpened",_menuType);
|
||||||
|
|
||||||
|
if (_menuType != 1) 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), []];
|
||||||
|
TRACE_2("searching for new vehicles",_vehicleAdded,_rangeTablesShown);
|
||||||
|
|
||||||
|
{
|
||||||
|
private _vehicleCfg = configFile >> "CfgVehicles" >> typeOf _x;
|
||||||
|
// config "ace_artillerytables_showRangetable" [0 disabled, 1 enabled] falls back to artilleryScanner
|
||||||
|
private _showRangetable = if (isNumber (_vehicleCfg >> QGVAR(showRangetable))) then {
|
||||||
|
getNumber (_vehicleCfg >> QGVAR(showRangetable))
|
||||||
|
} else {
|
||||||
|
getNumber (_vehicleCfg >> "artilleryScanner")
|
||||||
|
};
|
||||||
|
if ((_showRangetable == 1) && {!(_x in _vehicleAdded)}) then {
|
||||||
|
private _vehicle = _x;
|
||||||
|
private _turret = [];
|
||||||
|
private _turretCfg = configNull; // find turret with artillery, will be one with primaryGunner = 1 (e.g. RHS PRP-3)
|
||||||
|
{
|
||||||
|
private _xTurretCfg = [_vehicleCfg, _x] call CBA_fnc_getTurret;
|
||||||
|
if ((getNumber (_xTurretCfg >> "primaryGunner")) == 1) exitWith {
|
||||||
|
_turret = _x;
|
||||||
|
_turretCfg = _xTurretCfg;
|
||||||
|
};
|
||||||
|
} forEach allTurrets _vehicle;
|
||||||
|
TRACE_3("",_vehicle,configName _vehicleCfg,_turret);
|
||||||
|
if (isNull _turretCfg) exitWith { ERROR_1("no primaryGunner %1",configName _vehicleCfg); };
|
||||||
|
if ((count _turret) != 1) then { WARNING_2("sub turret %1-%2",_typeOf,_turret); };
|
||||||
|
|
||||||
|
private _weaponsTurret = _vehicle weaponsTurret _turret;
|
||||||
|
if ((count _weaponsTurret) != 1) exitWith { WARNING_1("multiple weapons - %1",_typeOf); };
|
||||||
|
private _weapon = _weaponsTurret select 0;
|
||||||
|
|
||||||
|
private _turretAnimBody = getText (_turretCfg >> "animationSourceBody");
|
||||||
|
private _turretAnimGun = getText (_turretCfg >> "animationSourceGun");
|
||||||
|
|
||||||
|
// For artillery with detached camera (I_Truck_02_MRL_F) need to use animationSourcePhase
|
||||||
|
// But that command won't always work, so fallback to animationPhase
|
||||||
|
private _currentElevRad = _vehicle animationSourcePhase _turretAnimGun;
|
||||||
|
if (isNil "_currentElevRad") then { _currentElevRad = _vehicle animationPhase _turretAnimGun; };
|
||||||
|
private _currentTraverseRad = _vehicle animationSourcePhase _turretAnimBody;
|
||||||
|
if (isNil "_currentTraverseRad") then { _currentTraverseRad = _vehicle animationPhase _turretAnimBody; };
|
||||||
|
|
||||||
|
// Some turrets (MK6) have a neutralX rotation that we need to add to min/max config elevation to get actual limits
|
||||||
|
private _weaponDir = _vehicle weaponDirection _weapon;
|
||||||
|
private _turretRot = [vectorDir _vehicle, vectorUp _vehicle, deg _currentTraverseRad] call CBA_fnc_vectRotate3D;
|
||||||
|
private _neutralX = (acos ((_turretRot vectorCos _weaponDir) min 1)) - (deg _currentElevRad); // vectorCos can return values outside of -1..1
|
||||||
|
_neutralX = (round (_neutralX * 10)) / 10; // minimize floating point errors
|
||||||
|
private _minElev = _neutralX + getNumber (_turretCfg >> "minElev");
|
||||||
|
private _maxElev = _neutralX + getNumber (_turretCfg >> "maxElev");
|
||||||
|
|
||||||
|
private _applyCorrections = if (isNumber (_vehicleCfg >> QGVAR(applyCorrections))) then {
|
||||||
|
getNumber (_vehicleCfg >> QGVAR(applyCorrections))
|
||||||
|
} else {
|
||||||
|
getNumber (_vehicleCfg >> "artilleryScanner")
|
||||||
|
};
|
||||||
|
private _advCorrection = GVAR(advancedCorrections) && {_applyCorrections == 1};
|
||||||
|
if ((missionNamespace getVariable [QEGVAR(mk6Mortar,airResistanceEnabled), false]) && {_vehicle isKindOf "Mortar_01_base_F"}) then {
|
||||||
|
_advCorrection = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// check weapon and limits in case different vehicles use the same weapon (cammo variants should still produce the same array)
|
||||||
|
private _info = [_weapon, _minElev, _maxElev, _advCorrection];
|
||||||
|
|
||||||
|
_vehicleAdded pushBack _vehicle;
|
||||||
|
ace_player setVariable [QGVAR(vehiclesAdded), _vehicleAdded];
|
||||||
|
|
||||||
|
private _index = _rangeTablesShown pushBackUnique _info;
|
||||||
|
TRACE_2("",_info,_index);
|
||||||
|
if (_index != -1) then {
|
||||||
|
private _statement = {
|
||||||
|
params ["", "", "_info"];
|
||||||
|
TRACE_1("interaction statement",_info);
|
||||||
|
[FUNC(rangeTableOpen), _info] call CBA_fnc_execNextFrame; // delay a frame because of interaction menu closing dialogs
|
||||||
|
};
|
||||||
|
private _condition = {
|
||||||
|
//IGNORE_PRIVATE_WARNING ["_player"];
|
||||||
|
("ACE_artilleryTable" in (_player call EFUNC(common,uniqueItems))) && {[_player, objNull, ["notOnMap", "isNotSitting", "isNotInside"]] call EFUNC(common,canInteractWith)}
|
||||||
|
};
|
||||||
|
private _displayName = format ["%1%2", getText (_vehicleCfg >> "displayName"),["","*"] select _advCorrection];
|
||||||
|
private _action = [format ['QGVAR(%1)',_index], _displayName, QPATHTOF(UI\icon_rangeTable.paa), _statement, _condition, {}, _info] call EFUNC(interact_menu,createAction);
|
||||||
|
[ace_player, 1, ["ACE_SelfActions", "ACE_Equipment"], _action] call EFUNC(interact_menu,addActionToObject);
|
||||||
|
TRACE_1("added action",_displayName);
|
||||||
|
ace_player setVariable [QGVAR(rangeTablesShown), _rangeTablesShown];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} forEach (nearestObjects [ace_player, ["LandVehicle"], 25]);
|
87
addons/artillerytables/functions/fnc_rangeTableOpen.sqf
Normal file
87
addons/artillerytables/functions/fnc_rangeTableOpen.sqf
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: PabstMirror
|
||||||
|
* Opens the rangetable and fills the charge listbox.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* 0: Weapon configname <STRING>
|
||||||
|
* 1: Elevation Min (Deg) <NUMBER>
|
||||||
|
* 2: Elevation Max (Deg) <NUMBER>
|
||||||
|
* 3: Advanced Corrections Enabled <BOOL>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* ["mortar_155mm_AMOS", -5, 80, true] call ace_artillerytables_fnc_rangeTableOpen
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
|
||||||
|
params ["_weaponName", "_elevMin", "_elevMax", "_advCorrection"];
|
||||||
|
TRACE_4("rangeTableOpen",_weaponName,_elevMin,_elevMax,_advCorrection);
|
||||||
|
|
||||||
|
BEGIN_COUNTER(rangeTableOpen);
|
||||||
|
|
||||||
|
createDialog QGVAR(rangeTableDialog);
|
||||||
|
private _dialog = uiNamespace getVariable [QGVAR(rangeTableDialog), displayNull];
|
||||||
|
if (isNull _dialog) exitWith{ERROR("Dialog failed to open");};
|
||||||
|
private _ctrlChargeList = _dialog displayCtrl IDC_CHARGELIST;
|
||||||
|
_dialog setVariable [QGVAR(elevMin),_elevMin];
|
||||||
|
_dialog setVariable [QGVAR(elevMax),_elevMax];
|
||||||
|
_dialog setVariable [QGVAR(advCorrection),_advCorrection];
|
||||||
|
TRACE_2("created dialog",_dialog,_ctrlChargeList);
|
||||||
|
|
||||||
|
// Get Mags:
|
||||||
|
private _mags = [_weaponName] call CBA_fnc_compatibleMagazines;
|
||||||
|
if (_mags isEqualTo []) exitWith {WARNING_1("No Mags",_weaponName);};
|
||||||
|
private _magCfg = configFile >> "CfgMagazines";
|
||||||
|
private _magParamsArray = [];
|
||||||
|
_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 };
|
||||||
|
};
|
||||||
|
_magParamsArray pushBackUnique _airFriction;
|
||||||
|
[getText (_magCfg >> _x >> "displayNameShort"), getText (_magCfg >> _x >> "displayName"), _initSpeed, _airFriction]
|
||||||
|
};
|
||||||
|
TRACE_2("",_magParamsArray,_mags);
|
||||||
|
if ((count _magParamsArray) == 2) then { // test if all magazines share the parameters
|
||||||
|
_mags = [["", "All Magazines", (_mags select 0) select 2, (_mags select 0) select 3]]; // simplify
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get Firemodes:
|
||||||
|
private _fireModes = getArray (configFile >> "CfgWeapons" >> _weaponName >> "modes");
|
||||||
|
_fireModes = (_fireModes apply {configFile >> "CfgWeapons" >> _weaponName >> _x}) select {1 == getNumber (_x >> "showToPlayer")};
|
||||||
|
_fireModes = _fireModes apply {[getNumber (_x >> "artilleryCharge"), configName _x]};
|
||||||
|
_fireModes sort true;
|
||||||
|
private _allSameCharge = ((count _fireModes) == 1) && {((_fireModes select 0) select 0) == 1};
|
||||||
|
TRACE_2("",_allSameCharge,_fireModes);
|
||||||
|
|
||||||
|
GVAR(magModeData) = [];
|
||||||
|
{
|
||||||
|
_x params ["_xDisplayNameShort", "_xDisplayName", "_xInitSpeed", "_xAirFriction"];
|
||||||
|
if (_allSameCharge) then {
|
||||||
|
_ctrlChargeList lbAdd format ["%1", _xDisplayNameShort];
|
||||||
|
_ctrlChargeList lbSetTooltip [count GVAR(magModeData), format ["%1\n%2 m/s\n%3", _xDisplayName, _xInitSpeed toFixed 1, _xAirFriction]];
|
||||||
|
GVAR(magModeData) pushBack [_xInitSpeed, _xAirFriction];
|
||||||
|
} else {
|
||||||
|
{
|
||||||
|
_x params ["_xModeCharge"];
|
||||||
|
_ctrlChargeList lbAdd format ["[Charge %1] %2", _forEachIndex, _xDisplayNameShort]; // forEachIndex is from firemodes
|
||||||
|
_ctrlChargeList lbSetTooltip [count GVAR(magModeData), format ["%1\n%2 m/s\n%3", _xDisplayName, (_xInitSpeed * _xModeCharge) toFixed 1, _xAirFriction]];
|
||||||
|
GVAR(magModeData) pushBack [_xInitSpeed * _xModeCharge, _xAirFriction];
|
||||||
|
} forEach _fireModes;
|
||||||
|
};
|
||||||
|
} forEach _mags;
|
||||||
|
|
||||||
|
|
||||||
|
if (isNil QGVAR(lastElevationMode)) then {GVAR(lastElevationMode) = true;};
|
||||||
|
if (isNil QGVAR(lastTablePage)) then {GVAR(lastTablePage) = 0;};
|
||||||
|
if ((GVAR(lastTablePage) >= (count GVAR(magModeData))) || {GVAR(lastTablePage) < 0}) then { GVAR(lastTablePage) = 0; };
|
||||||
|
|
||||||
|
END_COUNTER(rangeTableOpen);
|
||||||
|
TRACE_2("trigger update",GVAR(lastElevationMode),GVAR(lastTablePage));
|
||||||
|
_ctrlChargeList lbSetCurSel GVAR(lastTablePage); // triggers call to FUNC(rangeTableUpdate)
|
64
addons/artillerytables/functions/fnc_rangeTableUpdate.sqf
Normal file
64
addons/artillerytables/functions/fnc_rangeTableUpdate.sqf
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: PabstMirror
|
||||||
|
* Called when listbox selection changes. Updates the rangetable with new values.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* 0: Elevation Mode (true = high,false=low) <BOOL><OPTIONAL>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [] call ace_artillerytables_fnc_rangeTableUpdate
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
|
||||||
|
private _dialog = uiNamespace getVariable [QGVAR(rangeTableDialog), displayNull];
|
||||||
|
private _ctrlRangeTable = _dialog displayCtrl IDC_TABLE;
|
||||||
|
private _ctrlChargeList = _dialog displayCtrl IDC_CHARGELIST;
|
||||||
|
private _ctrlElevationHigh = _dialog displayCtrl IDC_BUTTON_ELEV_HIGH;
|
||||||
|
private _ctrlElevationLow = _dialog displayCtrl IDC_BUTTON_ELEV_LOW;
|
||||||
|
|
||||||
|
GVAR(lastElevationMode) = param [0, GVAR(lastElevationMode)]; // update if passed a new value
|
||||||
|
GVAR(lastCharge) = lbCurSel _ctrlChargeList;
|
||||||
|
|
||||||
|
// get data for currently selected mag/mode combo:
|
||||||
|
(GVAR(magModeData) select GVAR(lastCharge)) params [["_muzzleVelocity", -1], ["_airFriction", 0]];
|
||||||
|
private _elevMin = _dialog getVariable [QGVAR(elevMin), 0];
|
||||||
|
private _elevMax = _dialog getVariable [QGVAR(elevMax), 0];
|
||||||
|
_ctrlElevationHigh ctrlSetTextColor ([[0.25,0.25,0.25,1],[1,1,1,1]] select GVAR(lastElevationMode));
|
||||||
|
_ctrlElevationLow ctrlSetTextColor ([[1,1,1,1],[0.25,0.25,0.25,1]] select GVAR(lastElevationMode));
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// 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;
|
70
addons/artillerytables/functions/fnc_turretChanged.sqf
Normal file
70
addons/artillerytables/functions/fnc_turretChanged.sqf
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: PabstMirror
|
||||||
|
* Turret changed, determine if we are in the gunner seat of an artillery vehicle.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* 0: Player <OBJECT>
|
||||||
|
* 1: Turret <ARRAY>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* Nothing
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [player, [0]] call ace_artillerytables_fnc_turretChanged
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
|
||||||
|
params ["_player", "_turret"];
|
||||||
|
private _vehicle = vehicle _player;
|
||||||
|
private _typeOf = typeOf _vehicle;
|
||||||
|
private _vehicleCfg = configFile >> "CfgVehicles" >> _typeOf;
|
||||||
|
|
||||||
|
// config "ace_artillerytables_showGunLaying" [0 disabled, 1 enabled, 2 enabled w/ alt elevationMode] falls back to artilleryScanner
|
||||||
|
private _showGunLaying = if (isNumber (_vehicleCfg >> QGVAR(showGunLaying))) then {
|
||||||
|
getNumber (_vehicleCfg >> QGVAR(showGunLaying))
|
||||||
|
} else {
|
||||||
|
getNumber (_vehicleCfg >> "artilleryScanner")
|
||||||
|
};
|
||||||
|
TRACE_4("turretChanged",_player,_typeOf,_turret,_showGunLaying);
|
||||||
|
|
||||||
|
if (GVAR(pfID) >= 0) then {
|
||||||
|
TRACE_1("removing pfEH and display",GVAR(pfID));
|
||||||
|
[GVAR(pfID)] call CBA_fnc_removePerFrameHandler;
|
||||||
|
GVAR(pfID) = -1;
|
||||||
|
if (!isNull (uiNamespace getVariable [QGVAR(display), displayNull])) then {
|
||||||
|
([QGVAR(modeDisplay)] call BIS_fnc_rscLayer) cutText ["", "PLAIN"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((alive _player) && {_showGunLaying > 0} && {_player == gunner _vehicle}) then {
|
||||||
|
private _turretCfg = [_typeOf, _turret] call CBA_fnc_getTurret;
|
||||||
|
private _turretAnimBody = getText (_turretCfg >> "animationSourceBody");
|
||||||
|
private _useAltElevation = (_showGunLaying == 2); // StaticMortars need elevation calculated differently, see FUNC(turretPFEH)
|
||||||
|
|
||||||
|
// If the memory point is invalid, then the turret will always use real weapon dir (e.g. CUP BM21)
|
||||||
|
private _memoryPointGunnerOptics = getText (_turretCfg >> "memoryPointGunnerOptics");
|
||||||
|
private _invalidGunnerMem = (_vehicle selectionPosition [_memoryPointGunnerOptics, "Memory"]) isEqualTo [0,0,0];
|
||||||
|
if (_invalidGunnerMem) then { INFO_3("[%1-%2] turret's memoryPointGunnerOptics invalid [%3]",typeOf _vehicle,_turret,_memoryPointGunnerOptics); };
|
||||||
|
|
||||||
|
private _weaponsTurret = _vehicle weaponsTurret _turret;
|
||||||
|
if ((count _weaponsTurret) != 1) then { WARNING_2("not singular weapon in turret - %1 - %2",_typeOf,_turret); };
|
||||||
|
private _weapon = _weaponsTurret param [0, ""];
|
||||||
|
|
||||||
|
private _fireModes = getArray (configFile >> "CfgWeapons" >> _weapon >> "modes");
|
||||||
|
_fireModes = (_fireModes apply {configFile >> "CfgWeapons" >> _weapon >> _x}) select {1 == getNumber (_x >> "showToPlayer")};
|
||||||
|
_fireModes = _fireModes apply {[getNumber (_x >> "artilleryCharge"), configName _x]};
|
||||||
|
_fireModes sort true;
|
||||||
|
_fireModes = _fireModes apply {_x select 1};
|
||||||
|
|
||||||
|
GVAR(pfID) = [LINKFUNC(turretPFEH), 0, [_vehicle, _turret, _fireModes, _useAltElevation, _turretAnimBody, _invalidGunnerMem]] call CBA_fnc_addPerFrameHandler;
|
||||||
|
TRACE_4("added pfEH",GVAR(pfID),_useAltElevation,_turretAnimBody,_invalidGunnerMem);
|
||||||
|
|
||||||
|
#ifdef DEBUG_MODE_FULL
|
||||||
|
private _ballisticsComputer = getNumber (configFile >> "CfgWeapons" >> _weapon >> "ballisticsComputer");
|
||||||
|
private _elevationMode = getNumber (_turretCfg >> "elevationMode");
|
||||||
|
private _discreteDistance = getArray (_turretCfg >> "discreteDistance");
|
||||||
|
TRACE_4("",_weapon,_ballisticsComputer,_elevationMode,_discreteDistance);
|
||||||
|
#endif
|
||||||
|
};
|
92
addons/artillerytables/functions/fnc_turretPFEH.sqf
Normal file
92
addons/artillerytables/functions/fnc_turretPFEH.sqf
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: PabstMirror
|
||||||
|
* Shows real azimuth and elevation on hud
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* 0: PFEH Args <ARRAY>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* Nothing
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [[...]] call ace_artillerytables_fnc_turretPFEH
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
|
||||||
|
(_this select 0) params ["_vehicle", "_turret", "_fireModes", "_useAltElevation", "_turretAnimBody", "_invalidGunnerMem"];
|
||||||
|
|
||||||
|
if (shownArtilleryComputer && {GVAR(disableArtilleryComputer)}) then {
|
||||||
|
// Still Don't like this solution, but it works
|
||||||
|
closeDialog 0;
|
||||||
|
[localize LSTRING(disableArtilleryComputer_displayName)] call EFUNC(common,displayTextStructured);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Restart display if null (not just at start, this will happen periodicly)
|
||||||
|
if (isNull (uiNamespace getVariable [QGVAR(display), displayNull])) then {
|
||||||
|
TRACE_1("creating display",_this);
|
||||||
|
([QGVAR(modeDisplay)] call BIS_fnc_rscLayer) cutRsc [QGVAR(modeDisplay), "PLAIN", 1, false];
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
||||||
|
_ctrlGroup ctrlShow false;
|
||||||
|
};
|
||||||
|
_ctrlGroup ctrlShow true;
|
||||||
|
|
||||||
|
BEGIN_COUNTER(pfeh);
|
||||||
|
|
||||||
|
private _currentFireMode = (weaponState [_vehicle, _turret]) select 2;
|
||||||
|
private _currentChargeMode = _fireModes find _currentFireMode;
|
||||||
|
|
||||||
|
private _lookVector = (AGLtoASL (positionCameraToWorld [0,0,0])) vectorFromTo (AGLtoASL (positionCameraToWorld [0,0,1]));
|
||||||
|
private _weaponDir = _vehicle weaponDirection (currentWeapon _vehicle);
|
||||||
|
|
||||||
|
// Calc real azimuth/elevation
|
||||||
|
// (looking at the sky VS looking at ground will radicaly change fire direction because BIS)
|
||||||
|
private _display = uiNamespace getVariable ["ACE_dlgArtillery", displayNull];
|
||||||
|
private _useRealWeaponDir = if ((isNull (_display displayCtrl 173)) || {(_vehicle ammo (currentWeapon _vehicle)) == 0}) then {
|
||||||
|
// With no ammo, distance display will be empty, but gun will still fire at wonky angle if aimed at ground
|
||||||
|
private _testSeekerPosASL = AGLtoASL (positionCameraToWorld [0,0,0]);
|
||||||
|
private _testPoint = _testSeekerPosASL vectorAdd (_lookVector vectorMultiply viewDistance);
|
||||||
|
!((terrainIntersectASL [_testSeekerPosASL, _testPoint]) || {lineIntersects [_testSeekerPosASL, _testPoint, _vehicle]});
|
||||||
|
} else {
|
||||||
|
((ctrlText (_display displayCtrl 173)) == "--")
|
||||||
|
};
|
||||||
|
|
||||||
|
private _realElevation = asin (_weaponDir select 2);
|
||||||
|
private _realAzimuth = 0;
|
||||||
|
if (_useRealWeaponDir || _invalidGunnerMem) then {
|
||||||
|
// No range (looking at sky), it will follow weaponDir:
|
||||||
|
_realAzimuth = (_weaponDir select 0) atan2 (_weaponDir select 1)
|
||||||
|
} else {
|
||||||
|
// Valid range, will fire at camera dir
|
||||||
|
// Azimuth will still be look dir EVEN IF elevation has flipped over 90! (on steep hills)
|
||||||
|
_realAzimuth = ((_lookVector select 0) atan2 (_lookVector select 1));
|
||||||
|
if (_useAltElevation) then {
|
||||||
|
// Some small mortars have odd launch angles (I think due to the addition of neutral elevation constant with the manual elevation)
|
||||||
|
// This gets very close, (should be less than 0.5deg deviation on a 20deg slope)
|
||||||
|
private _currentTraverseRad = _vehicle animationSourcePhase _turretAnimBody;
|
||||||
|
if (isNil "_currentTraverseRad") then { _currentTraverseRad = _vehicle animationPhase _turretAnimBody; };
|
||||||
|
// Get turret roatation around it's z axis, then calc weapon elev in it's projection
|
||||||
|
private _turretRot = [vectorDir _vehicle, vectorUp _vehicle, deg _currentTraverseRad] call CBA_fnc_vectRotate3D;
|
||||||
|
_realElevation = (acos ((_turretRot vectorCos _weaponDir) min 1)) + ((_turretRot call CBA_fnc_vect2polar) select 2);
|
||||||
|
if (_realElevation > 90) then { _realElevation = 180 - _realElevation; }; // does not flip azimuth!
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (_realAzimuth < 0) then { _realAzimuth = _realAzimuth + 360; }; // mils will be 0-6400
|
||||||
|
|
||||||
|
private _ctrlCharge = (uiNamespace getVariable [QGVAR(display), displayNull]) displayCtrl IDC_CHARGE;
|
||||||
|
private _ctrlAzimuth = (uiNamespace getVariable [QGVAR(display), displayNull]) displayCtrl IDC_AZIMUTH;
|
||||||
|
private _ctrlElevation = (uiNamespace getVariable [QGVAR(display), displayNull]) displayCtrl IDC_ELEVATION;
|
||||||
|
|
||||||
|
_ctrlAzimuth ctrlSetText Format ["AZ: %1", [DEGTOMILS * _realAzimuth, 4, 0] call CBA_fnc_formatNumber];
|
||||||
|
_ctrlElevation ctrlSetText Format ["EL: %1", [DEGTOMILS * _realElevation, 4, 0] call CBA_fnc_formatNumber];
|
||||||
|
_ctrlCharge ctrlSetText format ["CH: %1", _currentChargeMode];
|
||||||
|
|
||||||
|
// avalible for other addons (mk6)
|
||||||
|
GVAR(predictedAzimuth) = _realAzimuth;
|
||||||
|
GVAR(predictedElevation) = _realElevation;
|
||||||
|
|
||||||
|
END_COUNTER(pfeh);
|
1
addons/artillerytables/functions/script_component.hpp
Normal file
1
addons/artillerytables/functions/script_component.hpp
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "\z\ace\addons\artillerytables\script_component.hpp"
|
23
addons/artillerytables/initSettings.sqf
Normal file
23
addons/artillerytables/initSettings.sqf
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// CBA Settings [ADDON: ace_artillerytables]:
|
||||||
|
|
||||||
|
private _categoryName = format ["ACE %1", localize "str_a3_cfgmarkers_nato_art"];
|
||||||
|
|
||||||
|
[
|
||||||
|
QGVAR(advancedCorrections), "CHECKBOX",
|
||||||
|
[LSTRING(advancedCorrections_displayName), LSTRING(advancedCorrections_description)],
|
||||||
|
[_categoryName, QUOTE(COMPONENT_BEAUTIFIED)],
|
||||||
|
false, // default value
|
||||||
|
true, // isGlobal
|
||||||
|
{[QGVAR(advancedCorrections), _this] call EFUNC(common,cbaSettings_settingChanged)},
|
||||||
|
true // Needs mission restart
|
||||||
|
] call CBA_settings_fnc_init;
|
||||||
|
|
||||||
|
[
|
||||||
|
QGVAR(disableArtilleryComputer), "CHECKBOX",
|
||||||
|
[LSTRING(disableArtilleryComputer_displayName), LSTRING(disableArtilleryComputer_description)],
|
||||||
|
[_categoryName, QUOTE(COMPONENT_BEAUTIFIED)],
|
||||||
|
false, // default value
|
||||||
|
true, // isGlobal
|
||||||
|
{[QGVAR(disableArtilleryComputer), _this] call EFUNC(common,cbaSettings_settingChanged)},
|
||||||
|
false // Needs mission restart
|
||||||
|
] call CBA_settings_fnc_init;
|
25
addons/artillerytables/script_component.hpp
Normal file
25
addons/artillerytables/script_component.hpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#define COMPONENT artillerytables
|
||||||
|
#define COMPONENT_BEAUTIFIED ArtilleryTables
|
||||||
|
#include "\z\ace\addons\main\script_mod.hpp"
|
||||||
|
|
||||||
|
// #define DEBUG_MODE_FULL
|
||||||
|
// #define DISABLE_COMPILE_CACHE
|
||||||
|
// #define ENABLE_PERFORMANCE_COUNTERS
|
||||||
|
|
||||||
|
#include "\z\ace\addons\main\script_macros.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
// This is a good fit for most large artillery, but a little low for lighter mortars
|
||||||
|
#define DEFAULT_AIR_FRICTION -0.00006
|
||||||
|
|
||||||
|
#define DEGTOMILS 17.7777778
|
||||||
|
|
||||||
|
#define IDC_MODECONTROLGROUP 1000
|
||||||
|
#define IDC_CHARGE 1001
|
||||||
|
#define IDC_AZIMUTH 1002
|
||||||
|
#define IDC_ELEVATION 1003
|
||||||
|
|
||||||
|
#define IDC_TABLE 2001
|
||||||
|
#define IDC_CHARGELIST 2002
|
||||||
|
#define IDC_BUTTON_ELEV_HIGH 2003
|
||||||
|
#define IDC_BUTTON_ELEV_LOW 2004
|
49
addons/artillerytables/stringtable.xml
Normal file
49
addons/artillerytables/stringtable.xml
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project name="ACE">
|
||||||
|
<Package name="ArtilleryTables">
|
||||||
|
<Key ID="STR_ACE_ArtilleryTables_rangetable_displayName">
|
||||||
|
<English>Artillery Rangetable</English>
|
||||||
|
</Key>
|
||||||
|
<Key ID="STR_ACE_ArtilleryTables_rangetable_description">
|
||||||
|
<English>Universal Artillery Rangetable</English>
|
||||||
|
</Key>
|
||||||
|
<Key ID="STR_ACE_ArtilleryTables_advancedCorrections_displayName">
|
||||||
|
<English>Air Resistance</English>
|
||||||
|
<Polish>Opór powietrza</Polish>
|
||||||
|
<Spanish>Resistencia al aire</Spanish>
|
||||||
|
<German>Luftwiderstand</German>
|
||||||
|
<Czech>Odpor vzduchu</Czech>
|
||||||
|
<Portuguese>Resistência do Ar</Portuguese>
|
||||||
|
<French>Résistance de l'air</French>
|
||||||
|
<Hungarian>Légellenállás</Hungarian>
|
||||||
|
<Russian>Сопротивление воздуха</Russian>
|
||||||
|
<Italian>Resistenza dell'Aria</Italian>
|
||||||
|
<Japanese>空気抵抗</Japanese>
|
||||||
|
<Korean>공기저항</Korean>
|
||||||
|
<Chinesesimp>空气阻力</Chinesesimp>
|
||||||
|
<Chinese>空氣阻力</Chinese>
|
||||||
|
</Key>
|
||||||
|
<Key ID="STR_ACE_ArtilleryTables_advancedCorrections_description">
|
||||||
|
<English>For Player Shots, Model Air Resistance and Wind Effects</English>
|
||||||
|
<Polish>Modeluj opór powietrza oraz wpływ wiatru na tor lotu pocisku dla strzałów z moździerza Mk6 przez graczy</Polish>
|
||||||
|
<Spanish>Para disparos del jugador, modelo de resistencia al aire y efectos de viento</Spanish>
|
||||||
|
<German>Für Spielerschüsse, Luftwiderstand und Windeffekte</German>
|
||||||
|
<Czech>Pro hráčovu střelbu, Model odporu vzduchu a povětrných podmínek</Czech>
|
||||||
|
<Portuguese>Para disparos do jogador, modelo de resistência de ar e efeitos de vento</Portuguese>
|
||||||
|
<French>Pour les tirs de joueurs, modèle de résistance à l'air et d'effet du vent</French>
|
||||||
|
<Hungarian>Játékos általi lövésekhez, legyen-e számított légellenállás és szélhatás</Hungarian>
|
||||||
|
<Russian>Для выстрелов игрока. Моделирует сопротивление воздуха и эффект ветра</Russian>
|
||||||
|
<Italian>Per Proiettili dei Giocatori, simula la Resistenza dell'Aria e gli Effetti del Vento</Italian>
|
||||||
|
<Japanese>プレイヤが射撃すると、空気抵抗モデルと風による影響をあたえます。</Japanese>
|
||||||
|
<Korean>플레이어 사격시 공기저항과 바람에 영향을 받습니다</Korean>
|
||||||
|
<Chinesesimp>设定由玩家射击的迫击炮,将会受到空气阻力与风力的影响</Chinesesimp>
|
||||||
|
<Chinese>設定由玩家射擊的迫擊砲,將會受到空氣阻力與風力的影響</Chinese>
|
||||||
|
</Key>
|
||||||
|
<Key ID="STR_ACE_ArtilleryTables_disableArtilleryComputer_displayName">
|
||||||
|
<English>Artillery Computer Disabled</English>
|
||||||
|
</Key>
|
||||||
|
<Key ID="STR_ACE_ArtilleryTables_disableArtilleryComputer_description">
|
||||||
|
<English>Disable the vanilla artillery computers</English>
|
||||||
|
</Key>
|
||||||
|
</Package>
|
||||||
|
</Project>
|
@ -105,6 +105,9 @@ if (!isServer && {_platform in ["linux", "osx"]}) then {
|
|||||||
};
|
};
|
||||||
} forEach ("true" configClasses (configFile >> "ACE_Extensions"));
|
} forEach ("true" configClasses (configFile >> "ACE_Extensions"));
|
||||||
};
|
};
|
||||||
|
if (isArray (configFile >> "ACE_Extensions" >> "extensions")) then {
|
||||||
|
WARNING("extensions[] array no longer supported");
|
||||||
|
};
|
||||||
|
|
||||||
///////////////
|
///////////////
|
||||||
// check server version/addons
|
// check server version/addons
|
||||||
|
@ -1,35 +1,14 @@
|
|||||||
class ACE_Settings {
|
class ACE_Settings {
|
||||||
//These settings effect gameplay difficutly: defaults will leave the mortar the same as vanilla
|
|
||||||
class GVAR(airResistanceEnabled) {
|
class GVAR(airResistanceEnabled) {
|
||||||
category = CSTRING(DisplayName);
|
movedToSQF = 1;
|
||||||
displayName = CSTRING(airResistanceEnabled_DisplayName);
|
|
||||||
description = CSTRING(airResistanceEnabled_Description);
|
|
||||||
value = 0;
|
|
||||||
typeName = "BOOL";
|
|
||||||
isClientSetable = 0;
|
|
||||||
};
|
};
|
||||||
class GVAR(allowComputerRangefinder) {
|
class GVAR(allowComputerRangefinder) {
|
||||||
category = CSTRING(DisplayName);
|
movedToSQF = 1;
|
||||||
displayName = CSTRING(allowComputerRangefinder_DisplayName);
|
|
||||||
description = CSTRING(allowComputerRangefinder_Description);
|
|
||||||
value = 1;
|
|
||||||
typeName = "BOOL";
|
|
||||||
isClientSetable = 0;
|
|
||||||
};
|
};
|
||||||
class GVAR(allowCompass) {
|
class GVAR(allowCompass) {
|
||||||
category = CSTRING(DisplayName);
|
movedToSQF = 1;
|
||||||
displayName = CSTRING(allowCompass_DisplayName);
|
|
||||||
description = CSTRING(allowCompass_Description);
|
|
||||||
value = 1;
|
|
||||||
typeName = "BOOL";
|
|
||||||
isClientSetable = 0;
|
|
||||||
};
|
};
|
||||||
class GVAR(useAmmoHandling) {
|
class GVAR(useAmmoHandling) {
|
||||||
category = CSTRING(DisplayName);
|
movedToSQF = 1;
|
||||||
displayName = CSTRING(useAmmoHandling_DisplayName);
|
|
||||||
description = CSTRING(useAmmoHandling_Description);
|
|
||||||
value = 0;
|
|
||||||
typeName = "BOOL";
|
|
||||||
isClientSetable = 0;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -16,11 +16,3 @@ class Extended_PostInit_EventHandlers {
|
|||||||
init = QUOTE(call COMPILE_FILE(XEH_postInit));
|
init = QUOTE(call COMPILE_FILE(XEH_postInit));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class Extended_FiredBIS_EventHandlers {
|
|
||||||
class Mortar_01_base_F {
|
|
||||||
class ADDON {
|
|
||||||
firedBIS = QUOTE(_this call FUNC(handleFired));
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
@ -4,16 +4,8 @@ class RscInGameUI {
|
|||||||
};
|
};
|
||||||
class ACE_Mk6_RscWeaponRangeArtillery: RscWeaponRangeArtillery {
|
class ACE_Mk6_RscWeaponRangeArtillery: RscWeaponRangeArtillery {
|
||||||
onLoad = QUOTE(uiNamespace setVariable [ARR_2('ACE_Mk6_RscWeaponRangeArtillery', _this select 0)]; [ARR_2('ace_infoDisplayChanged', [ARR_2(_this select 0, 'Mk6Mortar')])] call CBA_fnc_localEvent;);
|
onLoad = QUOTE(uiNamespace setVariable [ARR_2('ACE_Mk6_RscWeaponRangeArtillery', _this select 0)]; [ARR_2('ace_infoDisplayChanged', [ARR_2(_this select 0, 'Mk6Mortar')])] call CBA_fnc_localEvent;);
|
||||||
controls[] = {"ACE_ChargeDisplay", "ACE_MILS_GROUP", "CA_IGUI_elements_group","CA_RangeElements_group"};
|
controls[] = {"ACE_MILS_GROUP", "CA_IGUI_elements_group","CA_RangeElements_group"};
|
||||||
class ACE_ChargeDisplay: RscStructuredText {
|
|
||||||
idc = 80085;
|
|
||||||
colorText[] = {1, 1, 1, 1};
|
|
||||||
colorBackground[] = {0, 0, 0, 0.1};
|
|
||||||
x = "3.8 * (((safezoneW / safezoneH) min 1.2) / 40) + (profilenamespace getvariable [""IGUI_GRID_WEAPON_X"",((safezoneX + safezoneW) - (10 * (((safezoneW / safezoneH) min 1.2) / 40)) - 4.3 * (((safezoneW / safezoneH) min 1.2) / 40))])";
|
|
||||||
y = "2.5 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (profilenamespace getVariable ['IGUI_GRID_WEAPON_Y', (safezoneY + 0.5 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25))])";
|
|
||||||
w = "10 * (((safezoneW / safezoneH) min 1.2) / 40)";
|
|
||||||
h = "1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)";
|
|
||||||
};
|
|
||||||
class ACE_MILS_GROUP: CA_IGUI_elements_group {
|
class ACE_MILS_GROUP: CA_IGUI_elements_group {
|
||||||
idc = 80170;
|
idc = 80170;
|
||||||
class controls {
|
class controls {
|
||||||
|
@ -1,18 +1,9 @@
|
|||||||
|
|
||||||
PREP(dev_buildTable);
|
|
||||||
PREP(dev_formatNumber);
|
|
||||||
PREP(dev_simulateCalcRangeTableLine);
|
|
||||||
PREP(dev_simulateFindSolution);
|
|
||||||
PREP(dev_simulateShot);
|
|
||||||
|
|
||||||
PREP(csw_getProxyWeapon);
|
PREP(csw_getProxyWeapon);
|
||||||
|
|
||||||
PREP(handleFired);
|
PREP(handleFired);
|
||||||
PREP(handlePlayerVehicleChanged);
|
PREP(handlePlayerVehicleChanged);
|
||||||
PREP(moduleInit);
|
PREP(moduleInit);
|
||||||
PREP(rangeTableCanUse);
|
PREP(rangeTableCanUse);
|
||||||
PREP(rangeTableOpen);
|
PREP(rangeTableOpen);
|
||||||
PREP(rangeTablePageChange);
|
|
||||||
PREP(rangeTablePreCalculatedValues);
|
|
||||||
PREP(toggleMils);
|
PREP(toggleMils);
|
||||||
PREP(turretDisplayLoaded);
|
PREP(turretDisplayLoaded);
|
||||||
|
@ -5,7 +5,12 @@ if (hasInterface) then {
|
|||||||
};
|
};
|
||||||
|
|
||||||
["ace_settingsInitialized", {
|
["ace_settingsInitialized", {
|
||||||
TRACE_1("ace_settingsInitialized",GVAR(useAmmoHandling));
|
TRACE_4("ace_settingsInitialized",GVAR(airResistanceEnabled),GVAR(allowComputerRangefinder),GVAR(allowCompass),GVAR(useAmmoHandling));
|
||||||
|
|
||||||
["vehicle", FUNC(handlePlayerVehicleChanged), true] call CBA_fnc_addPlayerEventHandler;
|
["vehicle", FUNC(handlePlayerVehicleChanged), true] call CBA_fnc_addPlayerEventHandler;
|
||||||
|
|
||||||
|
if (!GVAR(airResistanceEnabled)) exitWith {};
|
||||||
|
if (EGVAR(artillerytables,advancedCorrections)) exitWith { TRACE_1("defer firedEH to artillerytables",_this); };
|
||||||
|
["Mortar_01_base_F", "fired", {call FUNC(handleFired)}] call CBA_fnc_addClassEventHandler;
|
||||||
|
|
||||||
}] call CBA_fnc_addEventHandler;
|
}] call CBA_fnc_addEventHandler;
|
||||||
|
@ -6,4 +6,6 @@ PREP_RECOMPILE_START;
|
|||||||
#include "XEH_PREP.hpp"
|
#include "XEH_PREP.hpp"
|
||||||
PREP_RECOMPILE_END;
|
PREP_RECOMPILE_END;
|
||||||
|
|
||||||
|
#include "initSettings.sqf"
|
||||||
|
|
||||||
ADDON = true;
|
ADDON = true;
|
||||||
|
@ -7,7 +7,7 @@ class CfgPatches {
|
|||||||
"ACE_Box_82mm_Mo_Illum","ACE_Box_82mm_Mo_Combo"};
|
"ACE_Box_82mm_Mo_Illum","ACE_Box_82mm_Mo_Combo"};
|
||||||
weapons[] = {"ACE_RangeTable_82mm","ace_mortar_82mm"};
|
weapons[] = {"ACE_RangeTable_82mm","ace_mortar_82mm"};
|
||||||
requiredVersion = REQUIRED_VERSION;
|
requiredVersion = REQUIRED_VERSION;
|
||||||
requiredAddons[] = {"ace_csw"};
|
requiredAddons[] = {"ace_csw", "ace_artillerytables"};
|
||||||
author = ECSTRING(common,ACETeam);
|
author = ECSTRING(common,ACETeam);
|
||||||
authors[] = {"PabstMirror","Grey","VKing"};
|
authors[] = {"PabstMirror","Grey","VKing"};
|
||||||
url = ECSTRING(main,URL);
|
url = ECSTRING(main,URL);
|
||||||
@ -33,4 +33,3 @@ class RscActiveText;
|
|||||||
class RscStructuredText;
|
class RscStructuredText;
|
||||||
|
|
||||||
#include "RscInGameUI.hpp"
|
#include "RscInGameUI.hpp"
|
||||||
#include "RscRangeTable.hpp"
|
|
||||||
|
@ -61,7 +61,7 @@ if (_proxyWeaponNeeded || GVAR(useAmmoHandling)) then {
|
|||||||
} forEach (magazinesAllTurrets _mortar);
|
} forEach (magazinesAllTurrets _mortar);
|
||||||
|
|
||||||
// remove orignal mags and add 1rnd versions:
|
// remove orignal mags and add 1rnd versions:
|
||||||
{ _staticWeapon removeMagazinesTurret _x; } forEach _magsToRemove;
|
{ _mortar removeMagazinesTurret _x; } forEach _magsToRemove;
|
||||||
{ _mortar addMagazineTurret _x; } forEach _convertedMags;
|
{ _mortar addMagazineTurret _x; } forEach _convertedMags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,84 +0,0 @@
|
|||||||
#include "script_component.hpp"
|
|
||||||
/*
|
|
||||||
* Author: PabstMirror
|
|
||||||
* DEV function to build mortar tables, very cpu intensive (never used durring normal gameplay)
|
|
||||||
*
|
|
||||||
* Arguments:
|
|
||||||
* 0: Muzzle Velocity <NUMBER>
|
|
||||||
* 1: Air Friction <NUMBER>
|
|
||||||
*
|
|
||||||
* Return Value:
|
|
||||||
* None <Data in clipboard>
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
* [100, -0.0001] spawn ace_mk6mortar_fnc_dev_buildTable; //spawn (scheduled) is slower
|
|
||||||
* [100, -0.0001] call ace_mk6mortar_fnc_dev_buildTable; //faster, but will lock while processing
|
|
||||||
*
|
|
||||||
* Public: No
|
|
||||||
*/
|
|
||||||
|
|
||||||
private _muzzleVelocity = _this select 0;
|
|
||||||
private _airFriction = _this select 1;
|
|
||||||
private _stillInRange = true;
|
|
||||||
private _currentRange = 100;
|
|
||||||
private _increasePerRow = 50;
|
|
||||||
private _outputArray = [];
|
|
||||||
|
|
||||||
|
|
||||||
//[_rangeToHit, _lineElevation, _lineHeightElevation, _lineHeightTimeDelta, _lineTimeOfFlight, _lineCrosswindDeg, _lineHeadwindMeters, _lineTailWindMeters, _lineTempDec, _lineTempInc, _lineAirDensDec, _lineAirDensInc]
|
|
||||||
|
|
||||||
while {_stillInRange} do {
|
|
||||||
private _result = [_muzzleVelocity, _currentRange, _airFriction] call FUNC(dev_simulateCalcRangeTableLine);
|
|
||||||
if (_result isEqualTo []) then {
|
|
||||||
_stillInRange = false;
|
|
||||||
} else {
|
|
||||||
if (_airFriction == 0) then {
|
|
||||||
_result set [5, 0];
|
|
||||||
_result set [6, 0];
|
|
||||||
_result set [7, 0];
|
|
||||||
_result set [8, 0];
|
|
||||||
_result set [9, 0];
|
|
||||||
_result set [10, 0];
|
|
||||||
_result set [11, 0];
|
|
||||||
};
|
|
||||||
if ((_result select 1) < 88) then {
|
|
||||||
_outputArray pushBack [
|
|
||||||
([(_result select 0), "meters", false] call FUNC(dev_formatNumber)),
|
|
||||||
([(_result select 1), "mil", true] call FUNC(dev_formatNumber)),
|
|
||||||
([(_result select 2), "mil", true] call FUNC(dev_formatNumber)),
|
|
||||||
([(_result select 3), "sec", false] call FUNC(dev_formatNumber)),
|
|
||||||
([(_result select 4), "sec", false] call FUNC(dev_formatNumber)),
|
|
||||||
([(_result select 5), "milPrecise", true] call FUNC(dev_formatNumber)),
|
|
||||||
([(_result select 6), "metersprecise", false] call FUNC(dev_formatNumber)),
|
|
||||||
([(_result select 7), "metersprecise", false] call FUNC(dev_formatNumber)),
|
|
||||||
([(_result select 8), "metersprecise", false] call FUNC(dev_formatNumber)),
|
|
||||||
([(_result select 9), "metersprecise", false] call FUNC(dev_formatNumber)),
|
|
||||||
([(_result select 10), "metersprecise", false] call FUNC(dev_formatNumber)),
|
|
||||||
([(_result select 11), "metersprecise", false] call FUNC(dev_formatNumber))
|
|
||||||
];
|
|
||||||
};
|
|
||||||
_currentRange = _currentRange + _increasePerRow;
|
|
||||||
};
|
|
||||||
hintSilent str _currentRange;
|
|
||||||
};
|
|
||||||
|
|
||||||
//handle floating point rounding errors
|
|
||||||
private _outputString = format ["case ((abs(_muzzleVelocity - %1) < 0.00001) && {(abs(_airFriction - %2) < 0.00001)}): {
|
|
||||||
[
|
|
||||||
", _muzzleVelocity, _airFriction];
|
|
||||||
|
|
||||||
{
|
|
||||||
if (_forEachIndex < ((count _outputArray) - 1)) then {
|
|
||||||
_outputString = _outputString + format ["%1,
|
|
||||||
", _x];
|
|
||||||
} else {
|
|
||||||
_outputString = _outputString + format ["%1
|
|
||||||
]
|
|
||||||
};", _x];
|
|
||||||
};
|
|
||||||
} forEach _outputArray;
|
|
||||||
|
|
||||||
copyToClipboard _outputString;
|
|
||||||
rangeTableOutput = _outputString;
|
|
||||||
|
|
||||||
hint "done";
|
|
@ -1,76 +0,0 @@
|
|||||||
#include "script_component.hpp"
|
|
||||||
/*
|
|
||||||
* Author: Pabst Mirror
|
|
||||||
* Converts numbers into nicely formated strings.
|
|
||||||
*
|
|
||||||
* Arguments:
|
|
||||||
* 0: Input number <NUMBER>
|
|
||||||
* 1: Output type (see case statement) <STRING>
|
|
||||||
* 2: If output type is mil, convert input type from deg->mil <BOOL>
|
|
||||||
*
|
|
||||||
* Return Value:
|
|
||||||
* Formatted number <STRING>
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
* [45, "mil4", true] call ace_mk6mortar_fnc_dev_formatNumber = "0800"
|
|
||||||
*
|
|
||||||
* Public: No
|
|
||||||
*/
|
|
||||||
|
|
||||||
params ["_theNumber", "_inputType", "_convertToMils"];
|
|
||||||
|
|
||||||
private _decimalPlaces = -1;
|
|
||||||
private _integerPlaces = -1;
|
|
||||||
|
|
||||||
switch (toLower _inputType) do {
|
|
||||||
case ("meters"): {
|
|
||||||
_decimalPlaces = 0;
|
|
||||||
_integerPlaces = 1;
|
|
||||||
};
|
|
||||||
case ("metersprecise"): {
|
|
||||||
_decimalPlaces = 1;
|
|
||||||
_integerPlaces = 1;
|
|
||||||
};
|
|
||||||
case ("meters4"): {
|
|
||||||
_decimalPlaces = 0;
|
|
||||||
_integerPlaces = 4;
|
|
||||||
};
|
|
||||||
case ("deg3precise"): {
|
|
||||||
_decimalPlaces = 2;
|
|
||||||
_integerPlaces = 3;
|
|
||||||
};
|
|
||||||
case ("mil"): {
|
|
||||||
_decimalPlaces = 0;
|
|
||||||
_integerPlaces = 1;
|
|
||||||
if (_convertToMils) then {
|
|
||||||
_theNumber = _theNumber * (6400 / 360);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
case ("mil4"): {
|
|
||||||
_decimalPlaces = 0;
|
|
||||||
_integerPlaces = 4;
|
|
||||||
if (_convertToMils) then {
|
|
||||||
_theNumber = _theNumber * (6400 / 360);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
case ("milprecise"): {
|
|
||||||
_decimalPlaces = 1;
|
|
||||||
_integerPlaces = 1;
|
|
||||||
if (_convertToMils) then {
|
|
||||||
_theNumber = _theNumber * (6400 / 360);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
case ("sec"): {
|
|
||||||
_decimalPlaces = 1;
|
|
||||||
_integerPlaces = 1;
|
|
||||||
};
|
|
||||||
default {systemChat format ["badtype %1", _inputType];};
|
|
||||||
};
|
|
||||||
|
|
||||||
//CBA_fnc_formatNumber is silly: [-9.58545, 1, 1, false] call CBA_fnc_formatNumber == "-9.-6"
|
|
||||||
|
|
||||||
private _prefix = if (_theNumber < 0) then {"-"} else {""};
|
|
||||||
|
|
||||||
private _return = [abs (_theNumber), _integerPlaces, _decimalPlaces, false] call CBA_fnc_formatNumber;
|
|
||||||
|
|
||||||
(_prefix + _return)
|
|
@ -1,77 +0,0 @@
|
|||||||
#include "script_component.hpp"
|
|
||||||
/*
|
|
||||||
* Author: Pabst Mirror
|
|
||||||
* Builds a rangeTable line for a certian range, given muzzle velocity and air friction, returns [] if out of range.
|
|
||||||
*
|
|
||||||
* Arguments:
|
|
||||||
* 0: Muzzle Velocity <NUMBER>
|
|
||||||
* 1: Air Friction <NUMBER>
|
|
||||||
* 2: Range To Hit <NUMBER>
|
|
||||||
*
|
|
||||||
* Return Value:
|
|
||||||
* Range Table Line Data (see return line) <ARRAY>
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
* [300, -0.0001, 3000] call ace_mk6mortar_fnc_simulateCalcRangeTableLine
|
|
||||||
*
|
|
||||||
* Public: No
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define TIME_STEP (1/50)
|
|
||||||
|
|
||||||
params ["_muzzleVelocity", "_rangeToHit", "_airFriction"];
|
|
||||||
|
|
||||||
private _startTime = diag_tickTime;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Run Binary search for correct elevation
|
|
||||||
private _solution = [_rangeToHit, 0, _muzzleVelocity, _airFriction, TIME_STEP] call FUNC(dev_simulateFindSolution);
|
|
||||||
if (_solution isEqualTo []) exitWith {[]};
|
|
||||||
|
|
||||||
//Real Elevation
|
|
||||||
private _lineElevation = _solution select 0;
|
|
||||||
|
|
||||||
//Time Of Flight:
|
|
||||||
private _lineTimeOfFlight = _solution select 1;
|
|
||||||
|
|
||||||
//Height Adjustment for -100m (another binary search)
|
|
||||||
private _solution = [_rangeToHit, -100, _muzzleVelocity, _airFriction, TIME_STEP] call FUNC(dev_simulateFindSolution);
|
|
||||||
if (_solution isEqualTo []) exitWith {[]};//should never be triggered (lower elevation easier to hit)
|
|
||||||
|
|
||||||
private _lineHeightElevation = ((_solution select 0) - _lineElevation);
|
|
||||||
private _lineHeightTimeDelta = (_solution select 1) - _lineTimeOfFlight;
|
|
||||||
|
|
||||||
//Compute for 10x and divide to minimize rounding errors
|
|
||||||
|
|
||||||
//Crosswind
|
|
||||||
private _lastTestResult = [_lineElevation, _muzzleVelocity, _airFriction, 15, 1, 0, 10, 0, TIME_STEP] call FUNC(dev_simulateShot);
|
|
||||||
private _lineCrosswindDeg = (_lastTestResult select 2) / 10;
|
|
||||||
|
|
||||||
//Headwind:
|
|
||||||
_lastTestResult = [_lineElevation, _muzzleVelocity, _airFriction, 15, 1, -10, 0, 0, TIME_STEP] call FUNC(dev_simulateShot);
|
|
||||||
private _lineHeadwindMeters = (_rangeToHit - (_lastTestResult select 0)) / 10;
|
|
||||||
|
|
||||||
//TailWind:
|
|
||||||
_lastTestResult = [_lineElevation, _muzzleVelocity, _airFriction, 15, 1, 10, 0, 0, TIME_STEP] call FUNC(dev_simulateShot);
|
|
||||||
private _lineTailWindMeters = (_rangeToHit - (_lastTestResult select 0)) / 10;
|
|
||||||
|
|
||||||
//Air Temp Dec
|
|
||||||
_lastTestResult = [_lineElevation, _muzzleVelocity, _airFriction, (15 - 10), 1, 0, 0, 0, TIME_STEP] call FUNC(dev_simulateShot);
|
|
||||||
_lineTempDec = (_rangeToHit - (_lastTestResult select 0)) / 10;
|
|
||||||
|
|
||||||
//Air Temp Inc
|
|
||||||
_lastTestResult = [_lineElevation, _muzzleVelocity, _airFriction, (15 + 10), 1, 0, 0, 0, TIME_STEP] call FUNC(dev_simulateShot);
|
|
||||||
_lineTempInc = (_rangeToHit - (_lastTestResult select 0)) / 10;
|
|
||||||
|
|
||||||
//Air Density Dec
|
|
||||||
_lastTestResult = [_lineElevation, _muzzleVelocity, _airFriction, 15, 0.9, 0, 0, 0, TIME_STEP] call FUNC(dev_simulateShot);
|
|
||||||
private _lineAirDensDec = (_rangeToHit - (_lastTestResult select 0)) / 10;
|
|
||||||
|
|
||||||
//Air Density Inc
|
|
||||||
_lastTestResult = [_lineElevation, _muzzleVelocity, _airFriction, 15, 1.1, 0, 0, 0, TIME_STEP] call FUNC(dev_simulateShot);
|
|
||||||
private _lineAirDensInc = (_rangeToHit - (_lastTestResult select 0)) / 10;
|
|
||||||
|
|
||||||
// systemChat format ["debug: Range %1 - in %2 sec", _rangeToHit, (diag_tickTime - _startTime)];
|
|
||||||
|
|
||||||
[_rangeToHit, _lineElevation, _lineHeightElevation, _lineHeightTimeDelta, _lineTimeOfFlight, _lineCrosswindDeg, _lineHeadwindMeters, _lineTailWindMeters, _lineTempDec, _lineTempInc, _lineAirDensDec, _lineAirDensInc]
|
|
@ -1,48 +0,0 @@
|
|||||||
#include "script_component.hpp"
|
|
||||||
/*
|
|
||||||
* Author: PabstMirror
|
|
||||||
* DEV to find a firing solution for a given range
|
|
||||||
*
|
|
||||||
* Arguments:
|
|
||||||
* 0: Range to Hit (Meters) <NUMBER>
|
|
||||||
* 1: Height To Hit (Meters) <NUMBER>
|
|
||||||
* 2: Muzzle Velocity (M/S) <NUMBER>
|
|
||||||
* 3: Air Friction <NUMBER>
|
|
||||||
* 4: Time Step (seconds) (eg 1/50 will simulate 50 cycles per second) <NUMBER>
|
|
||||||
*
|
|
||||||
* Return Value:
|
|
||||||
* [NUMBER - Elevation In Degrees, NUMBER - Shot Durration] <ARRAY>
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
* [_rangeToHit, _heightToHit, _muzzleVelocity, _airFriction, TIME_STEP] call ace_mk6mortar_fnc_dev_simulateFindSolution;
|
|
||||||
*
|
|
||||||
* Public: No
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define MAX_ATTEMPTS 22
|
|
||||||
params ["_rangeToHit", "_heightToHit", "_muzzleVelocity", "_airFriction","_timeStep"];
|
|
||||||
|
|
||||||
private _maxElev = 90;
|
|
||||||
private _minElev = 45; //todo - Low Angle Howitzers???
|
|
||||||
|
|
||||||
private _error = 10000;
|
|
||||||
private _solutionElevation = -1;
|
|
||||||
private _lastTestResult = [];
|
|
||||||
private _numberOfAttempts = 0;
|
|
||||||
|
|
||||||
//(binary search)
|
|
||||||
while {(_numberOfAttempts < MAX_ATTEMPTS) && {(abs _error) > 0.2}} do {
|
|
||||||
_numberOfAttempts = _numberOfAttempts + 1;
|
|
||||||
_solutionElevation = (_maxElev + _minElev) / 2;
|
|
||||||
_lastTestResult = [_solutionElevation, _muzzleVelocity, _airFriction, 15, 1, 0, 0, _heightToHit, _timeStep] call FUNC(dev_simulateShot);
|
|
||||||
_error = _rangeToHit - (_lastTestResult select 0);
|
|
||||||
if (_error > 0) then {
|
|
||||||
_maxElev = _solutionElevation; //test range was short
|
|
||||||
} else {
|
|
||||||
_minElev = _solutionElevation; //test range was long
|
|
||||||
};
|
|
||||||
};
|
|
||||||
if (_numberOfAttempts >= MAX_ATTEMPTS) exitWith {[]};
|
|
||||||
|
|
||||||
//return the elevation and time required
|
|
||||||
[_solutionElevation, (_lastTestResult select 1)]
|
|
@ -1,63 +0,0 @@
|
|||||||
#include "script_component.hpp"
|
|
||||||
/*
|
|
||||||
* Author: PabstMirror
|
|
||||||
* DEV function to build mortar tables, very cpu intensive (never used durring normal gameplay)
|
|
||||||
*
|
|
||||||
* Arguments:
|
|
||||||
* 0: Shot Angle (degrees) <NUMBER>
|
|
||||||
* 1: Muzzle Velocity (m/s) <NUMBER>
|
|
||||||
* 2: Air Friction <NUMBER>
|
|
||||||
* 3: Tempeture (degres celcius) <NUMBER>
|
|
||||||
* 4: Relative Air Denisty <NUMBER>
|
|
||||||
* 5: Tail Wind (m/s) <NUMBER>
|
|
||||||
* 6: Cross Wind (m/s) <NUMBER>
|
|
||||||
* 7: Height Of Target (M) <NUMBER>
|
|
||||||
* 8: Time Step (fraction of a second) <NUMBER>
|
|
||||||
*
|
|
||||||
* Return Value:
|
|
||||||
* <ARRAY> [Distance Traveled<NUMBER>, Shot Time<NUMBER>, Offset (degrees)<NUMBER>]
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
* [45, 180, -0.0001, 15, 1, 10, 0, 0, 1/50] call ace_mk6mortar_fnc_dev_simulateShot;
|
|
||||||
*
|
|
||||||
* Public: No
|
|
||||||
*/
|
|
||||||
|
|
||||||
params ["_angleDeg", "_muzzleVelocity", "_airFriction", "_temp", "_relDensity", "_tailWind", "_crosswind", "_heightOfTarget", "_timeStep"];
|
|
||||||
|
|
||||||
private _wind = [_crosswind, _tailWind, 0];
|
|
||||||
private _gravity = [0,0,-9.8];
|
|
||||||
|
|
||||||
private _currentPos = [0,0,0];
|
|
||||||
private _muzzleVelocity = _muzzleVelocity * (((_temp + 273.13) / 288.13 - 1) / 40 + 1);
|
|
||||||
private _currentVelocity = [0, (_muzzleVelocity * cos _angleDeg), (_muzzleVelocity * sin _angleDeg)];
|
|
||||||
|
|
||||||
private _currentTime = 0;
|
|
||||||
private _lastPos = _currentPos;
|
|
||||||
|
|
||||||
private _kCoefficent = -1 * _relDensity * _airFriction; //save time in the loop and compute once
|
|
||||||
|
|
||||||
while {((_currentVelocity select 2) > 0) || ((_currentPos select 2) >= _heightOfTarget)} do {
|
|
||||||
_lastPos = _currentPos;
|
|
||||||
|
|
||||||
private _aparentWind = _wind vectorDiff _currentVelocity;
|
|
||||||
private _changeInVelocity = _gravity vectorAdd (_aparentWind vectorMultiply ((vectorMagnitude _aparentWind) * _kCoefficent));
|
|
||||||
|
|
||||||
_currentVelocity = _currentVelocity vectorAdd (_changeInVelocity vectorMultiply _timeStep);
|
|
||||||
|
|
||||||
_currentPos = _currentPos vectorAdd (_currentVelocity vectorMultiply _timeStep);
|
|
||||||
_currentTime = _currentTime + _timeStep;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Uses linearConversion to get a weighted average betwen points before and after dropping below target height
|
|
||||||
private _linConversion = linearConversion [(_lastPos select 2), (_currentPos select 2), _heightOfTarget, 0, 1, true];
|
|
||||||
private _middlePos = (_lastPos vectorMultiply (1 - _linConversion)) vectorAdd (_currentPos vectorMultiply (_linConversion));
|
|
||||||
// private _middlePosOld = (_lastPos vectorAdd _currentPos) vectorMultiply 0.5;
|
|
||||||
|
|
||||||
//Same to find travel time
|
|
||||||
private _middleTotalTravelTime = _currentTime - (_timeStep * (1-_linConversion));
|
|
||||||
|
|
||||||
//Find shot offset (from crosswind), in degrees
|
|
||||||
private _offsetDeg = (_middlePos select 0) aTan2 (_middlePos select 1);
|
|
||||||
|
|
||||||
[(_middlePos select 1), _middleTotalTravelTime, _offsetDeg]
|
|
@ -21,15 +21,13 @@
|
|||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
|
|
||||||
params ["_vehicle", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile"];
|
params ["_vehicle", "", "", "", "", "", "_projectile"];
|
||||||
|
|
||||||
if (!GVAR(airResistanceEnabled)) exitWith {};
|
|
||||||
|
|
||||||
// Large enough distance to not simulate any wind deflection
|
// Large enough distance to not simulate any wind deflection
|
||||||
if (_vehicle distance ACE_player > 8000) exitWith {false};
|
if (_vehicle distance ACE_player > 8000) exitWith {false};
|
||||||
|
|
||||||
//AI will have no clue how to use:
|
//AI will have no clue how to use:
|
||||||
_shooterMan = gunner _vehicle;
|
private _shooterMan = gunner _vehicle;
|
||||||
if (!([_shooterMan] call EFUNC(common,isPlayer))) exitWith {false};
|
if (!([_shooterMan] call EFUNC(common,isPlayer))) exitWith {false};
|
||||||
|
|
||||||
//Calculate air density:
|
//Calculate air density:
|
||||||
@ -45,8 +43,8 @@ TRACE_5("FiredWeather",_temperature,_pressure,_relativeHumidity,_airDensity,_rel
|
|||||||
//powder effects:
|
//powder effects:
|
||||||
private _newMuzzleVelocityCoefficent = (((_temperature + 273.13) / 288.13 - 1) / 40 + 1);
|
private _newMuzzleVelocityCoefficent = (((_temperature + 273.13) / 288.13 - 1) / 40 + 1);
|
||||||
if (_newMuzzleVelocityCoefficent != 1) then {
|
if (_newMuzzleVelocityCoefficent != 1) then {
|
||||||
_bulletVelocity = velocity _projectile;
|
private _bulletVelocity = velocity _projectile;
|
||||||
_bulletSpeed = vectorMagnitude _bulletVelocity;
|
private _bulletSpeed = vectorMagnitude _bulletVelocity;
|
||||||
_bulletVelocity = (vectorNormalized _bulletVelocity) vectorMultiply (_bulletSpeed * _newMuzzleVelocityCoefficent);
|
_bulletVelocity = (vectorNormalized _bulletVelocity) vectorMultiply (_bulletSpeed * _newMuzzleVelocityCoefficent);
|
||||||
_projectile setVelocity _bulletVelocity;
|
_projectile setVelocity _bulletVelocity;
|
||||||
};
|
};
|
||||||
@ -64,7 +62,6 @@ if (_newMuzzleVelocityCoefficent != 1) then {
|
|||||||
_args set[2, CBA_missionTime];
|
_args set[2, CBA_missionTime];
|
||||||
|
|
||||||
private _bulletVelocity = velocity _shell;
|
private _bulletVelocity = velocity _shell;
|
||||||
private _bulletSpeed = vectorMagnitude _bulletVelocity;
|
|
||||||
|
|
||||||
private _trueVelocity = _bulletVelocity vectorDiff wind;
|
private _trueVelocity = _bulletVelocity vectorDiff wind;
|
||||||
private _trueSpeed = vectorMagnitude _trueVelocity;
|
private _trueSpeed = vectorMagnitude _trueVelocity;
|
||||||
|
@ -56,40 +56,13 @@ if (_lastFireMode != -1) then {
|
|||||||
private _display = uiNamespace getVariable ["ACE_Mk6_RscWeaponRangeArtillery", displayNull];
|
private _display = uiNamespace getVariable ["ACE_Mk6_RscWeaponRangeArtillery", displayNull];
|
||||||
if (isNull _display) exitWith {}; //It may be null for the first frame
|
if (isNull _display) exitWith {}; //It may be null for the first frame
|
||||||
|
|
||||||
private _chargeText = format ["<t size='0.8'>%1: %2 <img image='%3'/></t>", (localize LSTRING(rangetable_charge)), _currentChargeMode, QPATHTOF(UI\ui_charges.paa)];
|
|
||||||
|
|
||||||
//Hud should hidden in 3rd person
|
//Hud should hidden in 3rd person
|
||||||
private _notGunnerView = cameraView != "GUNNER";
|
private _notGunnerView = cameraView != "GUNNER";
|
||||||
|
|
||||||
//Calc real azimuth/elevation
|
// Get aiming values from ace_artillerytables
|
||||||
//(looking at the sky VS looking at ground will radicaly change fire direction because BIS)
|
// Note: it also handles displaying the "charge" level
|
||||||
private _realAzimuth = -1;
|
private _realAzimuth = missionNamespace getVariable [QEGVAR(artillerytables,predictedAzimuth), -1];
|
||||||
private _realElevation = -1;
|
private _realElevation = missionNamespace getVariable [QEGVAR(artillerytables,predictedElevation), -1];
|
||||||
|
|
||||||
private _useRealWeaponDir = (ctrlText (_display displayCtrl 173)) == "--";
|
|
||||||
if (_useRealWeaponDir && {(_mortarVeh ammo (currentWeapon _mortarVeh)) == 0}) then {
|
|
||||||
// With no ammo, distance display will be empty, but gun will still fire at wonky angle if aimed at ground
|
|
||||||
private _testSeekerPosASL = AGLtoASL (positionCameraToWorld [0,0,0]);
|
|
||||||
private _testSeekerDir = _testSeekerPosASL vectorFromTo (AGLtoASL (positionCameraToWorld [0,0,1]));
|
|
||||||
private _testPoint = _testSeekerPosASL vectorAdd (_testSeekerDir vectorMultiply viewDistance);
|
|
||||||
if ((terrainIntersectASL [_testSeekerPosASL, _testPoint]) || {lineIntersects [_testSeekerPosASL, _testPoint]}) then {
|
|
||||||
_useRealWeaponDir = false; // If we are not looking at infinity (based on viewDistance)
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
if (_useRealWeaponDir) then {
|
|
||||||
//No range (looking at sky), it will follow weaponDir:
|
|
||||||
private _weaponDir = _mortarVeh weaponDirection (currentWeapon _mortarVeh);
|
|
||||||
_realAzimuth = (_weaponDir select 0) atan2 (_weaponDir select 1);
|
|
||||||
_realElevation = asin (_weaponDir select 2);
|
|
||||||
} else {
|
|
||||||
//Valid range, will fire at camera dir
|
|
||||||
private _lookVector = ((positionCameraToWorld [0,0,0]) call EFUNC(common,positionToASL)) vectorFromTo ((positionCameraToWorld [0,0,10]) call EFUNC(common,positionToASL));
|
|
||||||
_realAzimuth = ((_lookVector select 0) atan2 (_lookVector select 1));
|
|
||||||
private _upVectorDir = (((vectorUp _mortarVeh) select 0) atan2 ((vectorUp _mortarVeh) select 1));
|
|
||||||
private _elevationDiff = (cos (_realAzimuth - _upVectorDir)) * acos ((vectorUp _mortarVeh) select 2);
|
|
||||||
_realElevation = ((180 / PI) * (_mortarVeh animationPhase "mainGun")) + 75 - _elevationDiff;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Update Heading Display:
|
//Update Heading Display:
|
||||||
if (_notGunnerView || (!GVAR(allowCompass))) then {
|
if (_notGunnerView || (!GVAR(allowCompass))) then {
|
||||||
@ -102,13 +75,10 @@ if (_lastFireMode != -1) then {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
//Update CurrentElevation Display and "charge" text
|
//Update CurrentElevation Display
|
||||||
if (_notGunnerView) then {
|
if (_notGunnerView) then {
|
||||||
(_display displayCtrl 80085) ctrlSetStructuredText parseText "";
|
|
||||||
(_display displayCtrl 80175) ctrlSetText "";
|
(_display displayCtrl 80175) ctrlSetText "";
|
||||||
} else {
|
} else {
|
||||||
(_display displayCtrl 80085) ctrlSetStructuredText parseText _chargeText;
|
|
||||||
|
|
||||||
if (_useMils) then {
|
if (_useMils) then {
|
||||||
(_display displayCtrl 80175) ctrlSetText str ((round (_realElevation * 6400 / 360)) % 6400);
|
(_display displayCtrl 80175) ctrlSetText str ((round (_realElevation * 6400 / 360)) % 6400);
|
||||||
} else {
|
} else {
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
|
|
||||||
params ["_logic", "_syncedUnits", "_activated"];
|
params ["_logic", "", "_activated"];
|
||||||
|
|
||||||
if (!_activated) exitWith {WARNING("Module - placed but not active");};
|
if (!_activated) exitWith {WARNING("Module - placed but not active");};
|
||||||
|
|
||||||
|
@ -15,32 +15,6 @@
|
|||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define LIST_CHARGE ((uiNamespace getVariable "ACE_82mm_RangeTable_Dialog") displayCtrl 1501)
|
TRACE_1("rangeTableOpen - defer to artillerytables",_this);
|
||||||
|
|
||||||
private _weaponName = "mortar_82mm"; //todo: work on other weapons
|
["mortar_82mm", 45, 88, GVAR(airResistanceEnabled) || EGVAR(artillerytables,advancedCorrections)] call EFUNC(artillerytables,rangeTableOpen);
|
||||||
|
|
||||||
createDialog "ACE_82mm_RangeTable_Dialog";
|
|
||||||
if (isNull (uiNamespace getVariable ["ACE_82mm_RangeTable_Dialog", displayNull])) exitWith {ERROR("Dialog failed to open");};
|
|
||||||
|
|
||||||
//Get Magazine Types
|
|
||||||
private _magazines = getArray (configFile >> "CfgWeapons" >> _weaponName >> "magazines");
|
|
||||||
|
|
||||||
//For now just get settings from first mag, all rounds have same flight characteristics:
|
|
||||||
if ((count _magazines) < 1) exitWith {ERROR("No Magazines for weapon");};
|
|
||||||
private _initSpeed = getNumber (configFile >> "CfgMagazines" >> (_magazines select 0) >> "initSpeed");
|
|
||||||
|
|
||||||
//Get Charge Modes
|
|
||||||
private _fireModes = getArray (configFile >> "CfgWeapons" >> _weaponName >> "modes");
|
|
||||||
|
|
||||||
private _muzzleVelocities = [];
|
|
||||||
{
|
|
||||||
private _showToPlayer = getNumber (configFile >> "CfgWeapons" >> _weaponName >> _x >> "showToPlayer");
|
|
||||||
if (_showToPlayer == 1) then {
|
|
||||||
private _artilleryCharge = getNumber (configFile >> "CfgWeapons" >> _weaponName >> _x >> "artilleryCharge");
|
|
||||||
LIST_CHARGE lbAdd format ["%1: %2", (localize LSTRING(rangetable_charge)), (count _muzzleVelocities)];
|
|
||||||
LIST_CHARGE lbSetData [(count _muzzleVelocities), str (_artilleryCharge * _initSpeed)];
|
|
||||||
_muzzleVelocities pushBack _artilleryCharge;
|
|
||||||
};
|
|
||||||
} forEach _fireModes;
|
|
||||||
|
|
||||||
LIST_CHARGE lbSetCurSel 0;
|
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
#include "script_component.hpp"
|
|
||||||
/*
|
|
||||||
* Author: PabstMirror
|
|
||||||
* Called when listbox selection changes. Updates the rangetable with new values.
|
|
||||||
*
|
|
||||||
* Arguments:
|
|
||||||
* None
|
|
||||||
*
|
|
||||||
* Return Value:
|
|
||||||
* None
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
* [] call ace_mk6mortar_fnc_rangeTablePageChange
|
|
||||||
*
|
|
||||||
* Public: No
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define RANGE_TABLE ((uiNamespace getVariable "ACE_82mm_RangeTable_Dialog") displayCtrl 20001)
|
|
||||||
#define LIST_CHARGE ((uiNamespace getVariable "ACE_82mm_RangeTable_Dialog") displayCtrl 1501)
|
|
||||||
|
|
||||||
private _listBoxData = LIST_CHARGE lbData (lbCurSel LIST_CHARGE);
|
|
||||||
if (isNil "_listBoxData" || {_listBoxData == ""}) exitWith {ERROR("lbCurSel out of bounds or no data");};
|
|
||||||
private _muzzleVelocity = parseNumber _listBoxData;
|
|
||||||
|
|
||||||
private _airFriction = if (GVAR(airResistanceEnabled)) then {MK6_82mm_AIR_FRICTION} else {0};
|
|
||||||
|
|
||||||
private _precalcArray = [_muzzleVelocity, _airFriction] call FUNC(rangeTablePreCalculatedValues);
|
|
||||||
|
|
||||||
lnbClear RANGE_TABLE;
|
|
||||||
{
|
|
||||||
RANGE_TABLE lnbAddRow _x;
|
|
||||||
} forEach _precalcArray;
|
|
||||||
|
|
||||||
//put dummy line at end because scrolling is fucked and can't see last line
|
|
||||||
RANGE_TABLE lnbAddRow ["", "", "", "", "", "", "", "", "", "", ""];
|
|
@ -1,271 +0,0 @@
|
|||||||
#include "script_component.hpp"
|
|
||||||
/*
|
|
||||||
* Author: PabstMirror
|
|
||||||
* Simple Lookup Table for various muzzle velocities and air frictions.
|
|
||||||
* Use ace_mk6mortar_fnc_dev_buildTable to build
|
|
||||||
*
|
|
||||||
* Arguments:
|
|
||||||
* 0: Muzzle Velocity <NUMBER>
|
|
||||||
* 1: Air Friction <NUMBER>
|
|
||||||
*
|
|
||||||
* Return Value:
|
|
||||||
* Array <ARRAY>
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
* [200, 0] call ace_mk6mortar_fnc_rangeTablePreCalculatedValues
|
|
||||||
*
|
|
||||||
* Public: No
|
|
||||||
*/
|
|
||||||
|
|
||||||
params ["_muzzleVelocity", "_airFriction"];
|
|
||||||
|
|
||||||
switch (true) do {
|
|
||||||
|
|
||||||
case ((abs(_muzzleVelocity - 70) < 0.00001) && {(abs(_airFriction - -0.0001) < 0.00001)}): {
|
|
||||||
[
|
|
||||||
["100","1493","9","1.4","14.0","3.7","0.4","-0.3","0.0","0.0","0.0","0.0"],
|
|
||||||
["150","1438","14","1.4","13.9","2.5","0.4","-0.4","0.0","0.0","-0.1","0.0"],
|
|
||||||
["200","1381","20","1.4","13.8","1.9","0.5","-0.4","0.0","0.0","-0.1","0.1"],
|
|
||||||
["250","1321","27","1.5","13.6","1.5","0.5","-0.4","0.0","0.0","-0.1","0.1"],
|
|
||||||
["300","1256","36","1.6","13.3","1.3","0.6","-0.5","0.0","-0.1","-0.1","0.1"],
|
|
||||||
["350","1183","49","1.7","12.9","1.1","0.6","-0.5","0.1","-0.1","-0.1","0.1"],
|
|
||||||
["400","1097","70","1.9","12.4","0.9","0.6","-0.5","0.1","-0.1","-0.2","0.1"],
|
|
||||||
["450","979","113","2.3","11.6","0.8","0.6","-0.5","0.1","-0.1","-0.2","0.2"]
|
|
||||||
]
|
|
||||||
};
|
|
||||||
case ((abs(_muzzleVelocity - 140) < 0.00001) && {(abs(_airFriction - -0.0001) < 0.00001)}): {
|
|
||||||
[
|
|
||||||
["150","1556","1","0.8","27.2","16.3","2.5","-2.4","0.0","0.0","-0.2","0.2"],
|
|
||||||
["200","1541","1","0.8","27.2","12.3","2.5","-2.4","0.0","0.0","-0.3","0.2"],
|
|
||||||
["250","1527","2","0.8","27.2","9.9","2.6","-2.4","0.0","0.0","-0.3","0.3"],
|
|
||||||
["300","1512","2","0.8","27.2","8.3","2.7","-2.4","0.1","0.0","-0.4","0.4"],
|
|
||||||
["350","1497","3","0.8","27.1","7.1","2.7","-2.5","0.0","-0.1","-0.5","0.4"],
|
|
||||||
["400","1482","3","0.8","27.1","6.2","2.7","-2.5","0.1","-0.1","-0.5","0.5"],
|
|
||||||
["450","1467","3","0.8","27.0","5.6","2.8","-2.5","0.1","-0.1","-0.6","0.6"],
|
|
||||||
["500","1451","4","0.8","27.0","5.0","2.9","-2.6","0.1","-0.1","-0.6","0.6"],
|
|
||||||
["550","1436","4","0.8","26.9","4.6","2.9","-2.6","0.1","-0.1","-0.7","0.7"],
|
|
||||||
["600","1420","5","0.8","26.8","4.2","3.0","-2.7","0.1","-0.1","-0.8","0.8"],
|
|
||||||
["650","1404","5","0.8","26.8","3.9","3.0","-2.7","0.1","-0.1","-0.9","0.8"],
|
|
||||||
["700","1388","6","0.8","26.7","3.6","3.1","-2.8","0.1","-0.1","-0.9","0.9"],
|
|
||||||
["750","1372","6","0.8","26.6","3.4","3.2","-2.8","0.1","-0.1","-1.0","1.0"],
|
|
||||||
["800","1355","7","0.8","26.5","3.2","3.2","-2.9","0.1","-0.1","-1.1","1.1"],
|
|
||||||
["850","1338","8","0.8","26.4","3.0","3.3","-2.9","0.1","-0.1","-1.1","1.1"],
|
|
||||||
["900","1321","8","0.8","26.2","2.8","3.4","-3.0","0.1","-0.1","-1.2","1.2"],
|
|
||||||
["950","1303","9","0.9","26.1","2.7","3.4","-3.1","0.1","-0.2","-1.3","1.2"],
|
|
||||||
["1000","1285","10","0.9","26.0","2.6","3.5","-3.1","0.2","-0.1","-1.4","1.3"],
|
|
||||||
["1050","1266","11","0.9","25.8","2.4","3.5","-3.2","0.1","-0.2","-1.4","1.4"],
|
|
||||||
["1100","1247","12","0.9","25.7","2.3","3.6","-3.3","0.1","-0.2","-1.5","1.4"],
|
|
||||||
["1150","1228","13","0.9","25.5","2.2","3.7","-3.3","0.2","-0.2","-1.6","1.5"],
|
|
||||||
["1200","1207","14","1.0","25.3","2.1","3.7","-3.4","0.2","-0.2","-1.7","1.6"],
|
|
||||||
["1250","1186","15","1.0","25.1","2.0","3.8","-3.4","0.2","-0.2","-1.7","1.7"],
|
|
||||||
["1300","1163","17","1.0","24.8","1.9","3.8","-3.5","0.2","-0.2","-1.8","1.7"],
|
|
||||||
["1350","1140","19","1.0","24.6","1.9","3.9","-3.5","0.2","-0.2","-1.9","1.8"],
|
|
||||||
["1400","1115","21","1.1","24.3","1.8","3.9","-3.6","0.2","-0.2","-1.9","1.9"],
|
|
||||||
["1450","1088","24","1.1","23.9","1.7","4.0","-3.6","0.2","-0.2","-2.0","1.9"],
|
|
||||||
["1500","1060","27","1.2","23.6","1.6","4.0","-3.7","0.2","-0.2","-2.1","2.0"],
|
|
||||||
["1550","1028","32","1.3","23.1","1.5","4.0","-3.7","0.2","-0.2","-2.1","2.1"],
|
|
||||||
["1600","991","38","1.4","22.6","1.5","4.0","-3.7","0.2","-0.2","-2.2","2.1"],
|
|
||||||
["1650","947","49","1.7","21.9","1.4","4.0","-3.7","0.2","-0.3","-2.3","2.2"],
|
|
||||||
["1700","888","71","2.1","21.0","1.3","3.9","-3.6","0.3","-0.3","-2.3","2.2"]
|
|
||||||
]
|
|
||||||
};
|
|
||||||
case ((abs(_muzzleVelocity - 200) < 0.00001) && {(abs(_airFriction - -0.0001) < 0.00001)}): {
|
|
||||||
[
|
|
||||||
["250","1559","1","0.6","37.3","23.8","6.1","-5.9","0.0","0.0","-0.6","0.5"],
|
|
||||||
["300","1551","1","0.6","37.3","20.0","6.1","-5.9","0.1","0.0","-0.7","0.7"],
|
|
||||||
["350","1543","1","0.6","37.3","17.2","6.2","-5.9","0.0","-0.1","-0.8","0.7"],
|
|
||||||
["400","1535","1","0.6","37.3","15.1","6.2","-5.9","0.1","0.0","-0.9","0.9"],
|
|
||||||
["450","1527","1","0.6","37.3","13.4","6.3","-6.0","0.1","-0.1","-1.0","1.0"],
|
|
||||||
["500","1519","1","0.6","37.2","12.1","6.3","-6.0","0.1","-0.1","-1.1","1.1"],
|
|
||||||
["550","1510","1","0.6","37.2","11.0","6.4","-6.0","0.1","-0.1","-1.3","1.2"],
|
|
||||||
["600","1502","1","0.6","37.2","10.1","6.4","-6.1","0.1","-0.1","-1.4","1.3"],
|
|
||||||
["650","1494","1","0.6","37.2","9.4","6.5","-6.1","0.1","-0.1","-1.5","1.4"],
|
|
||||||
["700","1485","2","0.6","37.1","8.7","6.5","-6.2","0.1","-0.1","-1.6","1.5"],
|
|
||||||
["750","1477","2","0.6","37.1","8.2","6.6","-6.2","0.1","-0.1","-1.7","1.6"],
|
|
||||||
["800","1468","2","0.6","37.0","7.7","6.7","-6.3","0.1","-0.1","-1.8","1.8"],
|
|
||||||
["850","1460","2","0.6","37.0","7.2","6.7","-6.3","0.1","-0.1","-2.0","1.9"],
|
|
||||||
["900","1451","2","0.6","37.0","6.8","6.8","-6.4","0.1","-0.1","-2.1","2.0"],
|
|
||||||
["950","1443","2","0.6","36.9","6.5","6.9","-6.4","0.1","-0.1","-2.2","2.1"],
|
|
||||||
["1000","1434","2","0.6","36.9","6.2","6.9","-6.5","0.1","-0.1","-2.3","2.2"],
|
|
||||||
["1050","1425","2","0.6","36.8","5.9","7.0","-6.6","0.1","-0.2","-2.5","2.3"],
|
|
||||||
["1100","1417","3","0.6","36.8","5.6","7.1","-6.6","0.1","-0.2","-2.6","2.4"],
|
|
||||||
["1150","1408","3","0.6","36.7","5.4","7.1","-6.7","0.2","-0.2","-2.7","2.5"],
|
|
||||||
["1200","1399","3","0.6","36.6","5.2","7.2","-6.7","0.2","-0.2","-2.8","2.7"],
|
|
||||||
["1250","1390","3","0.6","36.6","5.0","7.3","-6.8","0.2","-0.2","-2.9","2.8"],
|
|
||||||
["1300","1381","3","0.6","36.5","4.8","7.4","-6.9","0.2","-0.2","-3.0","2.9"],
|
|
||||||
["1350","1372","3","0.6","36.4","4.6","7.4","-6.9","0.2","-0.2","-3.2","3.0"],
|
|
||||||
["1400","1362","4","0.6","36.4","4.4","7.5","-7.0","0.2","-0.2","-3.3","3.1"],
|
|
||||||
["1450","1353","4","0.6","36.3","4.3","7.6","-7.1","0.2","-0.2","-3.4","3.2"],
|
|
||||||
["1500","1344","4","0.6","36.2","4.2","7.7","-7.1","0.2","-0.2","-3.5","3.4"],
|
|
||||||
["1550","1334","4","0.6","36.1","4.0","7.7","-7.2","0.2","-0.2","-3.7","3.5"],
|
|
||||||
["1600","1324","4","0.6","36.0","3.9","7.8","-7.3","0.2","-0.2","-3.8","3.6"],
|
|
||||||
["1650","1314","4","0.7","35.9","3.8","7.9","-7.3","0.2","-0.2","-3.9","3.7"],
|
|
||||||
["1700","1304","5","0.7","35.8","3.7","7.9","-7.4","0.2","-0.2","-4.0","3.8"],
|
|
||||||
["1750","1294","5","0.7","35.7","3.6","8.0","-7.5","0.2","-0.2","-4.2","3.9"],
|
|
||||||
["1800","1284","5","0.7","35.6","3.5","8.1","-7.6","0.2","-0.3","-4.3","4.0"],
|
|
||||||
["1850","1274","5","0.7","35.5","3.4","8.2","-7.6","0.2","-0.3","-4.4","4.2"],
|
|
||||||
["1900","1263","6","0.7","35.4","3.3","8.2","-7.7","0.2","-0.3","-4.5","4.3"],
|
|
||||||
["1950","1253","6","0.7","35.2","3.2","8.3","-7.8","0.2","-0.3","-4.7","4.4"],
|
|
||||||
["2000","1242","6","0.7","35.1","3.1","8.4","-7.8","0.3","-0.3","-4.8","4.5"],
|
|
||||||
["2050","1231","7","0.7","35.0","3.0","8.4","-7.9","0.3","-0.3","-4.9","4.7"],
|
|
||||||
["2100","1219","7","0.7","34.8","2.9","8.5","-8.0","0.3","-0.3","-5.0","4.8"],
|
|
||||||
["2150","1208","7","0.7","34.7","2.9","8.5","-8.0","0.3","-0.3","-5.2","4.9"],
|
|
||||||
["2200","1196","8","0.7","34.5","2.8","8.6","-8.1","0.3","-0.3","-5.3","5.0"],
|
|
||||||
["2250","1184","8","0.7","34.3","2.7","8.7","-8.2","0.3","-0.3","-5.4","5.1"],
|
|
||||||
["2300","1171","9","0.8","34.2","2.7","8.7","-8.2","0.3","-0.3","-5.5","5.2"],
|
|
||||||
["2350","1158","9","0.8","34.0","2.6","8.8","-8.3","0.3","-0.3","-5.7","5.4"],
|
|
||||||
["2400","1145","10","0.8","33.8","2.5","8.8","-8.3","0.3","-0.3","-5.8","5.5"],
|
|
||||||
["2450","1132","10","0.8","33.6","2.5","8.9","-8.4","0.3","-0.3","-5.9","5.6"],
|
|
||||||
["2500","1118","11","0.8","33.3","2.4","8.9","-8.4","0.3","-0.3","-6.0","5.7"],
|
|
||||||
["2550","1103","12","0.8","33.1","2.4","9.0","-8.5","0.3","-0.3","-6.1","5.8"],
|
|
||||||
["2600","1088","13","0.9","32.8","2.3","9.0","-8.5","0.4","-0.3","-6.2","5.9"],
|
|
||||||
["2650","1072","14","0.9","32.6","2.2","9.0","-8.6","0.4","-0.4","-6.4","6.0"],
|
|
||||||
["2700","1056","15","0.9","32.3","2.2","9.0","-8.6","0.3","-0.4","-6.5","6.1"],
|
|
||||||
["2750","1038","16","1.0","31.9","2.1","9.1","-8.6","0.4","-0.4","-6.6","6.3"],
|
|
||||||
["2800","1020","18","1.0","31.6","2.1","9.1","-8.6","0.4","-0.4","-6.7","6.4"],
|
|
||||||
["2850","1000","20","1.1","31.2","2.0","9.1","-8.6","0.4","-0.4","-6.8","6.5"],
|
|
||||||
["2900","978","22","1.1","30.8","1.9","9.0","-8.6","0.4","-0.4","-6.9","6.5"],
|
|
||||||
["2950","954","26","1.2","30.3","1.9","9.0","-8.6","0.4","-0.4","-7.0","6.6"],
|
|
||||||
["3000","927","31","1.4","29.7","1.8","8.9","-8.5","0.4","-0.4","-7.1","6.7"],
|
|
||||||
["3050","894","38","1.6","29.0","1.7","8.8","-8.4","0.4","-0.4","-7.2","6.8"],
|
|
||||||
["3100","849","54","2.0","27.9","1.6","8.5","-8.3","0.4","-0.4","-7.2","6.8"]
|
|
||||||
]
|
|
||||||
};
|
|
||||||
case ((abs(_muzzleVelocity - 70) < 0.00001) && {(abs(_airFriction - 0) < 0.00001)}): {
|
|
||||||
[
|
|
||||||
["100","1497","9","1.3","14.2","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["150","1445","14","1.3","14.1","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["200","1390","19","1.4","14.0","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["250","1333","26","1.4","13.8","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["300","1272","34","1.5","13.5","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["350","1204","45","1.6","13.2","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["400","1127","61","1.8","12.8","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["450","1028","91","2.1","12.1","0.0","0.0","0.0","0.0","0.0","0.0","0.0"]
|
|
||||||
]
|
|
||||||
};
|
|
||||||
case ((abs(_muzzleVelocity - 140) < 0.00001) && {(abs(_airFriction - 0) < 0.00001)}): {
|
|
||||||
[
|
|
||||||
["150","1562","1","0.7","28.5","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["200","1549","1","0.7","28.5","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["250","1536","2","0.7","28.5","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["300","1523","2","0.7","28.5","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["350","1510","2","0.7","28.4","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["400","1497","3","0.7","28.4","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["450","1484","3","0.7","28.4","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["500","1471","3","0.7","28.3","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["550","1458","4","0.7","28.3","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["600","1445","4","0.7","28.2","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["650","1431","4","0.7","28.2","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["700","1418","5","0.7","28.1","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["750","1404","5","0.7","28.0","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["800","1390","6","0.7","27.9","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["850","1376","6","0.7","27.9","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["900","1362","6","0.8","27.8","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["950","1348","7","0.8","27.7","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1000","1333","7","0.8","27.6","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1050","1318","8","0.8","27.5","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1100","1303","9","0.8","27.3","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1150","1288","9","0.8","27.2","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1200","1272","10","0.8","27.1","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1250","1256","11","0.8","26.9","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1300","1239","12","0.8","26.8","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1350","1222","13","0.9","26.6","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1400","1205","13","0.9","26.4","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1450","1187","15","0.9","26.2","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1500","1168","16","0.9","26.0","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1550","1148","18","1.0","25.8","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1600","1127","19","1.0","25.5","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1650","1105","21","1.1","25.2","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1700","1082","24","1.1","24.9","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1750","1057","27","1.2","24.6","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1800","1029","31","1.3","24.2","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1850","997","37","1.4","23.7","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1900","960","46","1.6","23.1","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1950","912","63","1.9","22.3","0.0","0.0","0.0","0.0","0.0","0.0","0.0"]
|
|
||||||
]
|
|
||||||
};
|
|
||||||
case ((abs(_muzzleVelocity - 200) < 0.00001) && {(abs(_airFriction - 0) < 0.00001)}): {
|
|
||||||
[
|
|
||||||
["300","1563","0","0.5","40.8","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["350","1556","1","0.5","40.8","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["400","1550","1","0.5","40.7","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["450","1544","1","0.5","40.7","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["500","1537","1","0.5","40.7","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["550","1531","1","0.5","40.7","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["600","1525","1","0.5","40.7","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["650","1519","1","0.5","40.7","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["700","1512","1","0.5","40.6","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["750","1506","1","0.5","40.6","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["800","1499","1","0.5","40.6","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["850","1493","1","0.5","40.6","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["900","1487","1","0.5","40.5","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["950","1480","1","0.5","40.5","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1000","1474","2","0.5","40.5","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1050","1467","2","0.5","40.5","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1100","1461","2","0.5","40.4","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1150","1454","2","0.5","40.4","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1200","1448","2","0.5","40.3","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1250","1441","2","0.5","40.3","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1300","1435","2","0.5","40.3","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1350","1428","2","0.5","40.2","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1400","1422","2","0.5","40.2","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1450","1415","2","0.5","40.1","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1500","1408","2","0.5","40.1","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1550","1402","3","0.5","40.0","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1600","1395","3","0.5","40.0","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1650","1388","3","0.5","39.9","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1700","1381","3","0.5","39.9","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1750","1374","3","0.5","39.8","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1800","1367","3","0.5","39.7","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1850","1360","3","0.5","39.7","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1900","1353","3","0.5","39.6","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["1950","1346","4","0.5","39.5","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["2000","1339","4","0.5","39.5","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["2050","1332","4","0.5","39.4","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["2100","1325","4","0.6","39.3","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["2150","1317","4","0.6","39.2","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["2200","1310","4","0.6","39.2","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["2250","1302","4","0.6","39.1","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["2300","1295","5","0.6","39.0","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["2350","1287","5","0.6","38.9","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["2400","1280","5","0.6","38.8","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["2450","1272","5","0.6","38.7","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["2500","1264","5","0.6","38.6","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["2550","1256","5","0.6","38.5","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["2600","1248","6","0.6","38.4","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["2650","1240","6","0.6","38.3","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["2700","1232","6","0.6","38.2","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["2750","1223","6","0.6","38.0","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["2800","1215","7","0.6","37.9","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["2850","1206","7","0.6","37.8","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["2900","1197","7","0.6","37.6","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["2950","1188","7","0.7","37.5","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["3000","1179","8","0.7","37.4","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["3050","1170","8","0.7","37.2","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["3100","1160","8","0.7","37.1","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["3150","1151","9","0.7","36.9","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["3200","1141","9","0.7","36.7","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["3250","1131","10","0.7","36.5","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["3300","1120","10","0.7","36.3","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["3350","1109","11","0.8","36.2","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["3400","1098","11","0.8","35.9","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["3450","1087","12","0.8","35.7","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["3500","1075","13","0.8","35.5","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["3550","1062","14","0.8","35.2","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["3600","1049","15","0.9","35.0","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["3650","1036","16","0.9","34.7","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["3700","1021","17","0.9","34.4","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["3750","1006","19","1.0","34.1","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["3800","990","21","1.1","33.7","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["3850","971","24","1.1","33.3","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["3900","952","27","1.2","32.8","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["3950","929","32","1.4","32.2","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["4000","900","40","1.6","31.5","0.0","0.0","0.0","0.0","0.0","0.0","0.0"],
|
|
||||||
["4050","861","56","2.1","30.5","0.0","0.0","0.0","0.0","0.0","0.0","0.0"]
|
|
||||||
]
|
|
||||||
};
|
|
||||||
default {
|
|
||||||
ERROR("MuzzleVelocity not found in LUT");
|
|
||||||
[]
|
|
||||||
};
|
|
||||||
};
|
|
@ -5,7 +5,6 @@
|
|||||||
*
|
*
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* 0: Vehicle <OBJECT>
|
* 0: Vehicle <OBJECT>
|
||||||
* 1: Player <OBJECT>
|
|
||||||
*
|
*
|
||||||
* Return Value:
|
* Return Value:
|
||||||
* None
|
* None
|
||||||
@ -16,7 +15,8 @@
|
|||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
|
|
||||||
params ["_mortarVeh", "_unit"];
|
params ["_mortarVeh"];
|
||||||
|
TRACE_1("toggleMils",_mortarVeh);
|
||||||
|
|
||||||
private _currentSetting = _mortarVeh getVariable [QGVAR(useMils), true];
|
private _currentSetting = _mortarVeh getVariable [QGVAR(useMils), true];
|
||||||
_mortarVeh setVariable [QGVAR(useMils), (!_currentSetting)];
|
_mortarVeh setVariable [QGVAR(useMils), (!_currentSetting)];
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
disableSerialization;
|
disableSerialization;
|
||||||
|
|
||||||
params ["_display", "_rscType"];
|
params ["_display", "_rscType"];
|
||||||
TRACE_2("params",_display,_rscType);
|
TRACE_2("turretDisplayLoaded",_display,_rscType);
|
||||||
|
|
||||||
if (_rscType != "Mk6Mortar") exitWith {};
|
if (_rscType != "Mk6Mortar") exitWith {};
|
||||||
if (isNull _display) exitWith {};
|
if (isNull _display) exitWith {};
|
||||||
|
44
addons/mk6mortar/initSettings.sqf
Normal file
44
addons/mk6mortar/initSettings.sqf
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// CBA Settings [ADDON: ace_mk6mortar]:
|
||||||
|
// These settings effect gameplay difficutly: defaults will leave the mortar the same as vanilla
|
||||||
|
|
||||||
|
private _category = [format ["ACE %1", localize "str_a3_cfgmarkers_nato_art"], localize LSTRING(DisplayName)];
|
||||||
|
|
||||||
|
[
|
||||||
|
QGVAR(airResistanceEnabled), "CHECKBOX",
|
||||||
|
[LSTRING(airResistanceEnabled_DisplayName), LSTRING(airResistanceEnabled_Description)],
|
||||||
|
_category,
|
||||||
|
false, // default value
|
||||||
|
true, // isGlobal
|
||||||
|
{[QGVAR(airResistanceEnabled), _this] call EFUNC(common,cbaSettings_settingChanged)},
|
||||||
|
true // Needs mission restart
|
||||||
|
] call CBA_settings_fnc_init;
|
||||||
|
|
||||||
|
[
|
||||||
|
QGVAR(allowComputerRangefinder), "CHECKBOX",
|
||||||
|
[LSTRING(allowComputerRangefinder_DisplayName), LSTRING(allowComputerRangefinder_Description)],
|
||||||
|
_category,
|
||||||
|
true, // default value
|
||||||
|
true, // isGlobal
|
||||||
|
{[QGVAR(allowComputerRangefinder), _this] call EFUNC(common,cbaSettings_settingChanged)},
|
||||||
|
true // Needs mission restart
|
||||||
|
] call CBA_settings_fnc_init;
|
||||||
|
|
||||||
|
[
|
||||||
|
QGVAR(allowCompass), "CHECKBOX",
|
||||||
|
[LSTRING(allowCompass_DisplayName), LSTRING(allowCompass_Description)],
|
||||||
|
_category,
|
||||||
|
true, // default value
|
||||||
|
true, // isGlobal
|
||||||
|
{[QGVAR(allowCompass), _this] call EFUNC(common,cbaSettings_settingChanged)},
|
||||||
|
true // Needs mission restart
|
||||||
|
] call CBA_settings_fnc_init;
|
||||||
|
|
||||||
|
[
|
||||||
|
QGVAR(useAmmoHandling), "CHECKBOX",
|
||||||
|
[LSTRING(useAmmoHandling_DisplayName), LSTRING(useAmmoHandling_Description)],
|
||||||
|
_category,
|
||||||
|
false, // default value
|
||||||
|
true, // isGlobal
|
||||||
|
{[QGVAR(useAmmoHandling), _this] call EFUNC(common,cbaSettings_settingChanged)},
|
||||||
|
true // Needs mission restart
|
||||||
|
] call CBA_settings_fnc_init;
|
@ -99,8 +99,8 @@ endif()
|
|||||||
|
|
||||||
string(TIMESTAMP ACE_BUILDSTAMP "%Y-%m-%dT%H:%M:%SZ")
|
string(TIMESTAMP ACE_BUILDSTAMP "%Y-%m-%dT%H:%M:%SZ")
|
||||||
set(ACE_VERSION_MAJOR 3)
|
set(ACE_VERSION_MAJOR 3)
|
||||||
set(ACE_VERSION_MINOR 12)
|
set(ACE_VERSION_MINOR 13)
|
||||||
set(ACE_VERSION_REVISION 3)
|
set(ACE_VERSION_REVISION 0)
|
||||||
EXECUTE_PROCESS(COMMAND git rev-parse --verify HEAD
|
EXECUTE_PROCESS(COMMAND git rev-parse --verify HEAD
|
||||||
OUTPUT_VARIABLE T_ACE_VERSION_BUILD
|
OUTPUT_VARIABLE T_ACE_VERSION_BUILD
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
@ -137,6 +137,7 @@ add_subdirectory(clipboard)
|
|||||||
add_subdirectory(advanced_ballistics)
|
add_subdirectory(advanced_ballistics)
|
||||||
add_subdirectory(medical)
|
add_subdirectory(medical)
|
||||||
add_subdirectory(parse_imagepath)
|
add_subdirectory(parse_imagepath)
|
||||||
|
add_subdirectory(artillerytables)
|
||||||
|
|
||||||
# Test Extension for dynamically loading/unloading built extensions; does not build in release
|
# Test Extension for dynamically loading/unloading built extensions; does not build in release
|
||||||
if (DEVEL)
|
if (DEVEL)
|
||||||
|
24
extensions/artillerytables/CMakeLists.txt
Normal file
24
extensions/artillerytables/CMakeLists.txt
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
set(ACE_EXTENSION_NAME "ace_artillerytables")
|
||||||
|
|
||||||
|
file(GLOB SOURCES *.h *.hpp *.c *.cpp)
|
||||||
|
add_library( ${ACE_EXTENSION_NAME} SHARED ${SOURCES} ${GLOBAL_SOURCES})
|
||||||
|
target_link_libraries(${ACE_EXTENSION_NAME} ace_common)
|
||||||
|
set_target_properties(${ACE_EXTENSION_NAME} PROPERTIES PREFIX "")
|
||||||
|
set_target_properties(${ACE_EXTENSION_NAME} PROPERTIES FOLDER Extensions)
|
||||||
|
|
||||||
|
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
set_target_properties(${ACE_EXTENSION_NAME} PROPERTIES LINK_SEARCH_START_STATIC 1)
|
||||||
|
set_target_properties(${ACE_EXTENSION_NAME} PROPERTIES LINK_SEARCH_END_STATIC 1)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# enable_testing()
|
||||||
|
# set(ACE_TEST_NAME Test_${ACE_EXTENSION_NAME})
|
||||||
|
|
||||||
|
# add_executable(${ACE_TEST_NAME} tests/tester.cpp ${SOURCES})
|
||||||
|
# target_link_libraries(${ACE_TEST_NAME} ace_common)
|
||||||
|
# target_link_libraries(${ACE_TEST_NAME} ${ACE_EXTENSION_NAME})
|
||||||
|
# target_link_libraries(${ACE_TEST_NAME} gtest_main)
|
||||||
|
# add_test(${ACE_TEST_NAME} ${ACE_TEST_NAME})
|
||||||
|
# set_target_properties(${ACE_TEST_NAME} PROPERTIES FOLDER Tests)
|
283
extensions/artillerytables/artillerytables.cpp
Normal file
283
extensions/artillerytables/artillerytables.cpp
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
/*
|
||||||
|
* artillerytables.hpp
|
||||||
|
* Author: PabstMirror
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
#include <future>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "artillerytables.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
static const double timeStep = 1.0 / 60;
|
||||||
|
static const double rangeSearchErrorMax = 0.001; // ratio * distance
|
||||||
|
static const double rangeSearchAngleConvergance = 0.000025;
|
||||||
|
static const double gravityABS = 9.8066;
|
||||||
|
static const ace::vector3<double> gravityAccl(0, 0, -1 * gravityABS);
|
||||||
|
|
||||||
|
// Globals:
|
||||||
|
std::vector<std::future<std::string>> fWorkers;
|
||||||
|
unsigned int getLineIndex = 0;
|
||||||
|
|
||||||
|
std::tuple<double, double, double> simulateShot(const double _fireAngleRad, const double _muzzleVelocity, const double _heightOfTarget, const double _crossWind, const double _tailWind, const double _temperature, const double _airDensity, double _airFriction) {
|
||||||
|
// returns: dist traveled to the side (crosswind), dist traveled foward (headwind), time of flight
|
||||||
|
// note: if shot never reaches height of target, then results are undefined (use negative)
|
||||||
|
const double kCoefficient = -1.0 * _airDensity * _airFriction;
|
||||||
|
const double powderEffects = (_airFriction) ? ((_temperature + 273.13) / 288.13 - 1) / 40 + 1 : 1.0;
|
||||||
|
|
||||||
|
double currentTime = 0;
|
||||||
|
ace::vector3<double> currentPosition(0, 0, 0);
|
||||||
|
ace::vector3<double> lastPosition(currentPosition);
|
||||||
|
ace::vector3<double> currentVelocity(0, powderEffects * _muzzleVelocity * cos(_fireAngleRad), powderEffects * _muzzleVelocity * sin(_fireAngleRad));
|
||||||
|
const ace::vector3<double> wind(_crossWind, _tailWind, 0);
|
||||||
|
|
||||||
|
while ((currentVelocity.z() > 0) || (currentPosition.z() >= _heightOfTarget)) {
|
||||||
|
lastPosition = currentPosition;
|
||||||
|
ace::vector3<double> apparentWind = wind - currentVelocity;
|
||||||
|
ace::vector3<double> changeInVelocity = gravityAccl + apparentWind * (kCoefficient * apparentWind.magnitude());
|
||||||
|
currentVelocity += changeInVelocity * timeStep;
|
||||||
|
currentPosition += currentVelocity * timeStep;
|
||||||
|
currentTime += timeStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
const double lastCurrentRatio((_heightOfTarget - currentPosition.z()) / (lastPosition.z() - currentPosition.z()));
|
||||||
|
ace::vector3<double> finalPos = lastPosition.lerp(currentPosition, lastCurrentRatio);
|
||||||
|
|
||||||
|
return { finalPos.x(), finalPos.y(), currentTime };
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<double, double> findMaxAngle(const double _muzzleVelocity, const double _airFriction) {
|
||||||
|
// retrns: angle that goes the furthest, max distance traveled
|
||||||
|
if (_airFriction == 0) {
|
||||||
|
return { M_PI_4, _muzzleVelocity * _muzzleVelocity / gravityABS };
|
||||||
|
}
|
||||||
|
// With air resitsnce, max distance angle won't be 45 degrees
|
||||||
|
double bestAngle = M_PI_4;
|
||||||
|
double bestDistance = -1;
|
||||||
|
double testResultDist;
|
||||||
|
for (double testAngle = M_PI_4; testAngle > 0; testAngle -= (M_PI_4 / 100.0)) {
|
||||||
|
std::tie(std::ignore, testResultDist, std::ignore) = simulateShot(testAngle, _muzzleVelocity, 0, 0, 0, 15, 1, _airFriction);
|
||||||
|
if (testResultDist > bestDistance) {
|
||||||
|
bestAngle = testAngle;
|
||||||
|
bestDistance = testResultDist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { bestAngle, bestDistance };
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<double, double, double> simulateFindSolution(const double _rangeToHit, const double _heightToHit, const double _muzzleVelocity, const double _airFriction, const double _minElev, const double _maxElev, const bool _highArc) {
|
||||||
|
// returns: actual distance traveled, elevation, time of flight
|
||||||
|
double searchMin = _minElev;
|
||||||
|
double searchMax = _maxElev;
|
||||||
|
|
||||||
|
if (!_airFriction) {
|
||||||
|
// can do trivial ballistics physics to get angle, could compute tof as well, but run through sim once to ensure consistancy (uses positive value of g)
|
||||||
|
double radicand = pow(_muzzleVelocity, 4) - gravityABS * (gravityABS * pow(_rangeToHit, 2) + 2 * _heightToHit * pow(_muzzleVelocity, 2));
|
||||||
|
if ((!_rangeToHit) || (radicand < 0)) { // radican't
|
||||||
|
return { -1, -1, -1 };
|
||||||
|
}
|
||||||
|
radicand = sqrt(radicand);
|
||||||
|
double angleRoot = atan((pow(_muzzleVelocity, 2) + radicand) / (gravityABS * _rangeToHit));
|
||||||
|
if ((angleRoot > _maxElev) || (angleRoot < _minElev)) {
|
||||||
|
angleRoot = atan((pow(_muzzleVelocity, 2) - radicand) / (gravityABS * _rangeToHit));
|
||||||
|
}
|
||||||
|
if ((angleRoot > _maxElev) || (angleRoot < _minElev)) {
|
||||||
|
return { -1, -1, -1 };
|
||||||
|
};
|
||||||
|
const double tof = _rangeToHit / (_muzzleVelocity * cos(angleRoot));
|
||||||
|
return { _rangeToHit, angleRoot, tof };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int numberOfAttempts = 0;
|
||||||
|
double resultDistance = -1;
|
||||||
|
double resultTime = -1;
|
||||||
|
double currentError = 9999;
|
||||||
|
double currentElevation = -1;
|
||||||
|
do {
|
||||||
|
if (numberOfAttempts++ > 50) break; // for safetey, min/max should converge long before
|
||||||
|
currentElevation = (searchMin + searchMax) / 2.0;
|
||||||
|
std::tie(std::ignore, resultDistance, resultTime) = simulateShot(currentElevation, _muzzleVelocity, _heightToHit, 0, 0, 15, 1, _airFriction);
|
||||||
|
currentError = _rangeToHit - resultDistance;
|
||||||
|
// printf("elev %f [%f, %f]range%f\n goes %f [%f]\n", currentElevation, searchMin, searchMax, (searchMax - searchMin), resultDistance, currentError);
|
||||||
|
if ((currentError > 0) ^ (!_highArc)) {
|
||||||
|
searchMax = currentElevation;
|
||||||
|
} else {
|
||||||
|
searchMin = currentElevation;
|
||||||
|
}
|
||||||
|
} while ((searchMax - searchMin) > rangeSearchAngleConvergance);
|
||||||
|
|
||||||
|
// printf("[%f, %f] Actuall [%f] err [%f of %f]\n", _rangeToHit, _heightToHit, resultDistance, currentError, (_rangeToHit * rangeSearchErrorMax * (_highArc ? 1.0 : 2.0)));
|
||||||
|
// On some low angle shots, it will really struggle to converge because of precision issues
|
||||||
|
if ((abs(currentError) > (_rangeToHit * rangeSearchErrorMax * (_highArc ? 1.0 : 2.0)))) {
|
||||||
|
return { -1, -1, -1 };
|
||||||
|
}
|
||||||
|
return { resultDistance, currentElevation, resultTime };
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeNumber(std::stringstream & ss, double _num, const int _widthInt, const int _widthDec) {
|
||||||
|
if ((_num < 0) && (_num > -0.05)) { // hard coded fix -0.0 rounding errors
|
||||||
|
_num = 0;
|
||||||
|
}
|
||||||
|
if (_widthInt > 1) {
|
||||||
|
ss << std::setfill('0');
|
||||||
|
}
|
||||||
|
ss << std::fixed << std::setw(_widthInt) << std::setprecision(_widthDec) << _num;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string simulateCalcRangeTableLine(const double _rangeToHit, const double _muzzleVelocity, const double _airFriction, const double _minElev, const double _maxElev, const bool _highArc) {
|
||||||
|
double actualDistance, lineElevation, lineTimeOfFlight;
|
||||||
|
std::tie(actualDistance, lineElevation, lineTimeOfFlight) = simulateFindSolution(_rangeToHit, 0, _muzzleVelocity, _airFriction, _minElev, _maxElev, _highArc);
|
||||||
|
if (lineTimeOfFlight < 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
double actualDistanceHeight, lineHeightElevation, lineHeightTimeOfFlight;
|
||||||
|
std::tie(actualDistanceHeight, lineHeightElevation, lineHeightTimeOfFlight) = simulateFindSolution(_rangeToHit, -100, _muzzleVelocity, _airFriction, _minElev, _maxElev, _highArc);
|
||||||
|
|
||||||
|
|
||||||
|
std::stringstream returnSS;
|
||||||
|
|
||||||
|
returnSS << "[\"";
|
||||||
|
writeNumber(returnSS, _rangeToHit, 0, 0);
|
||||||
|
returnSS << "\",\"";
|
||||||
|
writeNumber(returnSS, lineElevation * 3200.0 / M_PI, 0, 0);
|
||||||
|
returnSS << "\",\"";
|
||||||
|
|
||||||
|
if (lineHeightElevation > 0) {
|
||||||
|
const double drElevAdjust = lineHeightElevation - lineElevation;
|
||||||
|
const double drTofAdjust = lineHeightTimeOfFlight - lineTimeOfFlight;
|
||||||
|
writeNumber(returnSS, drElevAdjust * 3200.0 / M_PI, 0, 0);
|
||||||
|
returnSS << "\",\"";
|
||||||
|
writeNumber(returnSS, drTofAdjust, 0, 1);
|
||||||
|
} else {
|
||||||
|
// low angle shots won't be able to adjust down further
|
||||||
|
returnSS << "-\",\"-";
|
||||||
|
}
|
||||||
|
returnSS << "\",\"";
|
||||||
|
writeNumber(returnSS, lineTimeOfFlight, 0, ((lineTimeOfFlight < 99.945) ? 1 : 0)); // round TOF when high
|
||||||
|
returnSS << "\",\"";
|
||||||
|
|
||||||
|
if (_airFriction) {
|
||||||
|
// Calc corrections:
|
||||||
|
double xOffset, yOffset;
|
||||||
|
// Crosswind
|
||||||
|
std::tie(xOffset, std::ignore, std::ignore) = simulateShot(lineElevation, _muzzleVelocity, 0, 10, 0, 15, 1, _airFriction);
|
||||||
|
const double crosswindOffsetRad = atan2(xOffset, actualDistance) / 10;
|
||||||
|
// Headwind
|
||||||
|
std::tie(std::ignore, yOffset, std::ignore) = simulateShot(lineElevation, _muzzleVelocity, 0, 0, -10, 15, 1, _airFriction);
|
||||||
|
const double headwindOffset = (actualDistance - yOffset) / 10;
|
||||||
|
// Tailwind
|
||||||
|
std::tie(std::ignore, yOffset, std::ignore) = simulateShot(lineElevation, _muzzleVelocity, 0, 0, 10, 15, 1, _airFriction);
|
||||||
|
const double tailwindOffset = (actualDistance - yOffset) / 10;
|
||||||
|
// Air Temp Dec
|
||||||
|
std::tie(std::ignore, yOffset, std::ignore) = simulateShot(lineElevation, _muzzleVelocity, 0, 0, 0, 5, 1, _airFriction);
|
||||||
|
const double tempDecOffset = (actualDistance - yOffset) / 10;
|
||||||
|
// Air Temp Inc
|
||||||
|
std::tie(std::ignore, yOffset, std::ignore) = simulateShot(lineElevation, _muzzleVelocity, 0, 0, 0, 25, 1, _airFriction);
|
||||||
|
const double tempIncOffset = (actualDistance - yOffset) / 10;
|
||||||
|
// Air Density Dec
|
||||||
|
std::tie(std::ignore, yOffset, std::ignore) = simulateShot(lineElevation, _muzzleVelocity, 0, 0, 0, 15, 0.9, _airFriction);
|
||||||
|
const double airDensityDecOffset = (actualDistance - yOffset) / 10;
|
||||||
|
// Air Density Inc
|
||||||
|
std::tie(std::ignore, yOffset, std::ignore) = simulateShot(lineElevation, _muzzleVelocity, 0, 0, 0, 15, 1.1, _airFriction);
|
||||||
|
const double airDensityIncOffset = (actualDistance - yOffset) / 10;
|
||||||
|
|
||||||
|
writeNumber(returnSS, crosswindOffsetRad * 3200.0 / M_PI, 1, 1);
|
||||||
|
returnSS << "\",\"";
|
||||||
|
writeNumber(returnSS, headwindOffset, 1, (abs(headwindOffset) > 9.949) ? 0 : 1);
|
||||||
|
returnSS << "\",\"";
|
||||||
|
writeNumber(returnSS, tailwindOffset, 1, (abs(tailwindOffset) > 9.949) ? 0 : 1);
|
||||||
|
returnSS << "\",\"";
|
||||||
|
writeNumber(returnSS, tempDecOffset, 1, (abs(tempDecOffset) > 9.949) ? 0 : 1);
|
||||||
|
returnSS << "\",\"";
|
||||||
|
writeNumber(returnSS, tempIncOffset, 1, (abs(tempIncOffset) > 9.949) ? 0 : 1);
|
||||||
|
returnSS << "\",\"";
|
||||||
|
writeNumber(returnSS, airDensityDecOffset, 1, (abs(airDensityDecOffset) > 9.949) ? 0 : 1);
|
||||||
|
returnSS << "\",\"";
|
||||||
|
writeNumber(returnSS, airDensityIncOffset, 1, (abs(airDensityIncOffset) > 9.949) ? 0 : 1);
|
||||||
|
returnSS << "\"]";
|
||||||
|
} else {
|
||||||
|
returnSS << "-\",\"-\",\"-\",\"-\",\"-\",\"-\",\"-\"]"; // 7 dashes
|
||||||
|
}
|
||||||
|
return (returnSS.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void __stdcall RVExtensionVersion(char* output, int outputSize) {
|
||||||
|
strncpy(output, ACE_FULL_VERSION_STR, outputSize);
|
||||||
|
}
|
||||||
|
void __stdcall RVExtension(char* output, int outputSize, const char* function) {
|
||||||
|
if (!strcmp(function, "version")) {
|
||||||
|
RVExtensionVersion(output, outputSize);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strncpy(output, "error - use args version of callExtension", outputSize);
|
||||||
|
}
|
||||||
|
int __stdcall RVExtensionArgs(char* output, int outputSize, const char* function, const char** args, int argsCnt) {
|
||||||
|
if (!strcmp(function, "version")) {
|
||||||
|
RVExtensionVersion(output, outputSize);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(function, "start")) {
|
||||||
|
if (argsCnt != 5) { return -2; } // Error: not enough args
|
||||||
|
const double muzzleVelocity = strtod(args[0], NULL);
|
||||||
|
const double airFriction = strtod(args[1], NULL);
|
||||||
|
double minElev = (M_PI / 180.0) * strtod(args[2], NULL);
|
||||||
|
double maxElev = (M_PI / 180.0) * strtod(args[3], NULL);
|
||||||
|
const bool highArc = !strcmp(args[4], "true");
|
||||||
|
|
||||||
|
// Reset workers:
|
||||||
|
fWorkers.clear();
|
||||||
|
getLineIndex = 0;
|
||||||
|
|
||||||
|
double bestAngle, bestDistance;
|
||||||
|
std::tie(bestAngle, bestDistance) = findMaxAngle(muzzleVelocity, airFriction);
|
||||||
|
|
||||||
|
minElev = std::max(minElev, 2 * (M_PI / 180.0)); // cap min to 2 degrees (negative elev might get messy)
|
||||||
|
maxElev = std::min(maxElev, 88 * (M_PI / 180.0)); // cap max to 88 degrees (mk6)
|
||||||
|
if (highArc) {
|
||||||
|
minElev = std::max(minElev, bestAngle);
|
||||||
|
} else {
|
||||||
|
maxElev = std::min(maxElev, bestAngle);
|
||||||
|
}
|
||||||
|
const double loopStart = (bestDistance < 4000) ? 50 : 100;
|
||||||
|
const double loopInc = (bestDistance < 5000) ? 50 : 100; // simplify when range gets high
|
||||||
|
const double loopMaxRange = std::min(bestDistance, 30000.0); // with no air resistance, max range could go higher than 60km
|
||||||
|
|
||||||
|
if (maxElev > minElev) { // don't bother if we can't hit anything (e.g. mortar in low mode)
|
||||||
|
for (double range = loopStart; range < loopMaxRange; range += loopInc) {
|
||||||
|
fWorkers.emplace_back(std::async(&simulateCalcRangeTableLine, range, muzzleVelocity, airFriction, minElev, maxElev, highArc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream outputStr; // debug max distance and thead count
|
||||||
|
outputStr << "[" << bestDistance << "," << fWorkers.size() << "]";
|
||||||
|
strncpy(output, outputStr.str().c_str(), outputSize);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(function, "getline")) {
|
||||||
|
// 1 = data on line, 2 - data not ready, 3 - done
|
||||||
|
std::string result = "";
|
||||||
|
std::future_status workerStatus;
|
||||||
|
|
||||||
|
while (result.empty()) {
|
||||||
|
if (getLineIndex >= fWorkers.size()) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
workerStatus = fWorkers[getLineIndex].wait_for(std::chrono::seconds(0));
|
||||||
|
if (workerStatus != std::future_status::ready) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
result = fWorkers[getLineIndex].get();
|
||||||
|
getLineIndex++;
|
||||||
|
}
|
||||||
|
strncpy(output, result.c_str(), outputSize);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(output, "error - invalid function", outputSize);
|
||||||
|
return RETURN_INVALID_FUNCTION; // Error: function not valid
|
||||||
|
}
|
22
extensions/artillerytables/artillerytables.hpp
Normal file
22
extensions/artillerytables/artillerytables.hpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* artillerytables.hpp
|
||||||
|
* Author: PabstMirror
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ace libs:
|
||||||
|
#include "vector.hpp"
|
||||||
|
#include "shared.hpp"
|
||||||
|
#define RETURN_INVALID_FUNCTION -1001
|
||||||
|
#define RETURN_WRONG_ARG_COUNT -1002
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
__declspec(dllexport) void __stdcall RVExtension(char* output, int outputSize, const char* function);
|
||||||
|
__declspec(dllexport) int __stdcall RVExtensionArgs(char* output, int outputSize, const char* function, const char** argv, int argc);
|
||||||
|
__declspec(dllexport) void __stdcall RVExtensionVersion(char* output, int outputSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<double, double, double> simulateShot(const double _fireAngleRad, const double _muzzleVelocity, const double _heightOfTarget, const double _crossWind, const double _tailWind, const double _temperature, const double _airDensity, double _airFriction);
|
||||||
|
std::tuple<double, double> findMaxAngle(const double _muzzleVelocity, const double _airFriction);
|
||||||
|
std::tuple<double, double, double> simulateFindSolution(const double _rangeToHit, const double _heightToHit, const double _muzzleVelocity, const double _airFriction, const double _minElev, const double _maxElev, const bool _highArc);
|
||||||
|
void writeNumber(std::stringstream & ss, double _num, const int _widthInt, const int _widthDec);
|
||||||
|
std::string simulateCalcRangeTableLine(const double _rangeToHit, const double _muzzleVelocity, const double _airFriction, const double _minElev, const double _maxElev, const bool _highArc);
|
100
extensions/artillerytables/tests/tester.cpp
Normal file
100
extensions/artillerytables/tests/tester.cpp
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <chrono>
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "../artillerytables.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
__declspec(dllexport) void __stdcall RVExtension(char* output, int outputSize, const char* function);
|
||||||
|
__declspec(dllexport) int __stdcall RVExtensionArgs(char* output, int outputSize, const char* function, const char** argv, int argc);
|
||||||
|
__declspec(dllexport) void __stdcall RVExtensionVersion(char* output, int outputSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_ace_artillerytables {
|
||||||
|
TEST(Extension, VersionOld) {
|
||||||
|
char output[256];
|
||||||
|
char function[] = "version";
|
||||||
|
RVExtension(output, 256, function);
|
||||||
|
std::cout << "VersionOld: " << output << "\n";
|
||||||
|
ASSERT_STREQ(output, ACE_FULL_VERSION_STR);
|
||||||
|
}
|
||||||
|
TEST(Extension, VersionRVExtensionVersion) {
|
||||||
|
char output[256];
|
||||||
|
RVExtensionVersion(output, 256);
|
||||||
|
std::cout << "VersionExtension: " << output << "\n";
|
||||||
|
ASSERT_STREQ(output, ACE_FULL_VERSION_STR);
|
||||||
|
}
|
||||||
|
TEST(Extension, VersionArray) {
|
||||||
|
char output[256];
|
||||||
|
char function[] = "version";
|
||||||
|
int extReturn = RVExtensionArgs(output, 256, function, NULL, 0);
|
||||||
|
std::cout << "VersionNew: " << output << "\n";
|
||||||
|
ASSERT_EQ(extReturn, 0);
|
||||||
|
ASSERT_STREQ(output, ACE_FULL_VERSION_STR);
|
||||||
|
}
|
||||||
|
TEST(Extension, InvalidFuncOld) {
|
||||||
|
char output[256];
|
||||||
|
char function[] = "blah";
|
||||||
|
RVExtension(output, 256, function);
|
||||||
|
ASSERT_STREQ(output, "error - use args version of callExtension");
|
||||||
|
}
|
||||||
|
TEST(Extension, InvalidFuncArray) {
|
||||||
|
char output[256];
|
||||||
|
char function[] = "blah";
|
||||||
|
int extReturn = RVExtensionArgs(output, 256, function, nullptr, 0);
|
||||||
|
std::cout << "InvalidFunc: " << output << "\n";
|
||||||
|
ASSERT_EQ(extReturn, RETURN_INVALID_FUNCTION);
|
||||||
|
ASSERT_STREQ(output, "error - invalid function");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(Extension, TestRun) {
|
||||||
|
// very basic test that it runs the correct number of lines
|
||||||
|
char output[256];
|
||||||
|
|
||||||
|
// Start:
|
||||||
|
char function1[] = "start";
|
||||||
|
const char* args1[] = { "400", "-0.00005", "-5", "80", "true" };
|
||||||
|
auto t1 = std::chrono::high_resolution_clock::now();
|
||||||
|
int ret1 = RVExtensionArgs(output, 256, function1, args1, 5);
|
||||||
|
auto t2 = std::chrono::high_resolution_clock::now();
|
||||||
|
std::printf("ret: %d - %s\n", ret1, output);
|
||||||
|
std::printf("func %s: %1.1f ms\n", function1, std::chrono::duration<double, std::milli>(t2 - t1).count());
|
||||||
|
ASSERT_STREQ(output, "[10391.8,103]");
|
||||||
|
ASSERT_EQ(ret1, 0);
|
||||||
|
|
||||||
|
int lines = 0;
|
||||||
|
auto t3 = std::chrono::high_resolution_clock::now();
|
||||||
|
char function2[] = "getline";
|
||||||
|
int ret2 = 0;
|
||||||
|
while (ret2 != 3) { // dumb spin
|
||||||
|
ret2 = RVExtensionArgs(output, 256, function2, NULL, 0);
|
||||||
|
if (ret2 == 1) {
|
||||||
|
lines++;
|
||||||
|
// std::printf("ret: %d - %s\n", ret2, output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto t4 = std::chrono::high_resolution_clock::now();
|
||||||
|
std::printf("func %s: %1.1f ms with %d lines\n", function2, std::chrono::duration<double, std::milli>(t3 - t2).count(), lines);
|
||||||
|
|
||||||
|
std::printf("callExtensions finished in %1.1f ms\n", std::chrono::duration<double, std::milli>(t4 - t1).count());
|
||||||
|
|
||||||
|
ASSERT_EQ(lines, 69);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
// Misc Testing code
|
||||||
|
// Determine realistic air firiction values
|
||||||
|
//double mv = 241;
|
||||||
|
//std::printf(" %f m/s\n", mv);
|
||||||
|
//double range;
|
||||||
|
//for (double ar = 0; ar > -0.00015; ar -= 0.00001) {
|
||||||
|
// std::tie(std::ignore, range) = findMaxAngle(mv, ar);
|
||||||
|
// printf("[%f] = %f\n", ar, range);
|
||||||
|
//}
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
std::cout << "Starting tests!\n";
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user