diff --git a/.github/workflows/extensions.yml b/.github/workflows/extensions.yml index 62b3ee69615..65f0a29eb94 100644 --- a/.github/workflows/extensions.yml +++ b/.github/workflows/extensions.yml @@ -20,6 +20,7 @@ jobs: - name: Checkout the source code uses: actions/checkout@master - name: Build + shell: cmd run: | cd extensions/build cmake .. && cmake --build . diff --git a/ace_artillerytables.dll b/ace_artillerytables.dll new file mode 100644 index 00000000000..2f5855c81a3 Binary files /dev/null and b/ace_artillerytables.dll differ diff --git a/ace_artillerytables_x64.dll b/ace_artillerytables_x64.dll new file mode 100644 index 00000000000..97a061c2570 Binary files /dev/null and b/ace_artillerytables_x64.dll differ diff --git a/addons/artillerytables/$PBOPREFIX$ b/addons/artillerytables/$PBOPREFIX$ new file mode 100644 index 00000000000..090539769ec --- /dev/null +++ b/addons/artillerytables/$PBOPREFIX$ @@ -0,0 +1 @@ +z\ace\addons\artillerytables diff --git a/addons/artillerytables/CfgEventHandlers.hpp b/addons/artillerytables/CfgEventHandlers.hpp new file mode 100644 index 00000000000..e90bed419e7 --- /dev/null +++ b/addons/artillerytables/CfgEventHandlers.hpp @@ -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)); + }; +}; diff --git a/addons/artillerytables/CfgMagazines.hpp b/addons/artillerytables/CfgMagazines.hpp new file mode 100644 index 00000000000..e6abdcf06e1 --- /dev/null +++ b/addons/artillerytables/CfgMagazines.hpp @@ -0,0 +1,6 @@ +class CfgMagazines { + class 32Rnd_155mm_Mo_shells; + class 8Rnd_82mm_Mo_shells: 32Rnd_155mm_Mo_shells { + GVAR(airFriction) = -0.0001; + }; +}; diff --git a/addons/artillerytables/CfgVehicles.hpp b/addons/artillerytables/CfgVehicles.hpp new file mode 100644 index 00000000000..04424e6079f --- /dev/null +++ b/addons/artillerytables/CfgVehicles.hpp @@ -0,0 +1,7 @@ +class CfgVehicles { + class StaticWeapon; + class StaticMortar: StaticWeapon { + // Small mortars seem to need the alternate elevation calculations, + GVAR(showGunLaying) = 2; + }; +}; diff --git a/addons/artillerytables/CfgWeapons.hpp b/addons/artillerytables/CfgWeapons.hpp new file mode 100644 index 00000000000..7c4d408673a --- /dev/null +++ b/addons/artillerytables/CfgWeapons.hpp @@ -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; + }; + }; +}; diff --git a/addons/artillerytables/README.md b/addons/artillerytables/README.md new file mode 100644 index 00000000000..3e52ba9946b --- /dev/null +++ b/addons/artillerytables/README.md @@ -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) diff --git a/addons/artillerytables/RscRangeTable.hpp b/addons/artillerytables/RscRangeTable.hpp new file mode 100644 index 00000000000..8c673537d60 --- /dev/null +++ b/addons/artillerytables/RscRangeTable.hpp @@ -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"; + }; + }; +}; diff --git a/addons/artillerytables/RscTitles.hpp b/addons/artillerytables/RscTitles.hpp new file mode 100644 index 00000000000..0da1131bc89 --- /dev/null +++ b/addons/artillerytables/RscTitles.hpp @@ -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)"; + }; + }; + }; + + }; + }; +}; diff --git a/addons/artillerytables/UI/RangeTable_background.paa b/addons/artillerytables/UI/RangeTable_background.paa new file mode 100644 index 00000000000..bf4b5ee0440 Binary files /dev/null and b/addons/artillerytables/UI/RangeTable_background.paa differ diff --git a/addons/artillerytables/UI/icon_rangeTable.paa b/addons/artillerytables/UI/icon_rangeTable.paa new file mode 100644 index 00000000000..9273b849d73 Binary files /dev/null and b/addons/artillerytables/UI/icon_rangeTable.paa differ diff --git a/addons/artillerytables/XEH_PREP.hpp b/addons/artillerytables/XEH_PREP.hpp new file mode 100644 index 00000000000..7ef48b61dd8 --- /dev/null +++ b/addons/artillerytables/XEH_PREP.hpp @@ -0,0 +1,8 @@ +TRACE_1("prep",_this); + +PREP(firedEH); +PREP(interactMenuOpened); +PREP(rangeTableOpen); +PREP(rangeTableUpdate); +PREP(turretChanged); +PREP(turretPFEH); diff --git a/addons/artillerytables/XEH_postInit.sqf b/addons/artillerytables/XEH_postInit.sqf new file mode 100644 index 00000000000..2f31655814f --- /dev/null +++ b/addons/artillerytables/XEH_postInit.sqf @@ -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 diff --git a/addons/artillerytables/XEH_preInit.sqf b/addons/artillerytables/XEH_preInit.sqf new file mode 100644 index 00000000000..9361d05015e --- /dev/null +++ b/addons/artillerytables/XEH_preInit.sqf @@ -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; diff --git a/addons/artillerytables/XEH_preStart.sqf b/addons/artillerytables/XEH_preStart.sqf new file mode 100644 index 00000000000..022888575ed --- /dev/null +++ b/addons/artillerytables/XEH_preStart.sqf @@ -0,0 +1,3 @@ +#include "script_component.hpp" + +#include "XEH_PREP.hpp" diff --git a/addons/artillerytables/config.cpp b/addons/artillerytables/config.cpp new file mode 100644 index 00000000000..4f5048e5ae3 --- /dev/null +++ b/addons/artillerytables/config.cpp @@ -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" + diff --git a/addons/artillerytables/dev/checkConfigs.sqf b/addons/artillerytables/dev/checkConfigs.sqf new file mode 100644 index 00000000000..91627edbf62 --- /dev/null +++ b/addons/artillerytables/dev/checkConfigs.sqf @@ -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 "-------------------------------------------"; diff --git a/addons/artillerytables/dev/showShotInfo.sqf b/addons/artillerytables/dev/showShotInfo.sqf new file mode 100644 index 00000000000..81a29dca22c --- /dev/null +++ b/addons/artillerytables/dev/showShotInfo.sqf @@ -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; diff --git a/addons/artillerytables/functions/fnc_firedEH.sqf b/addons/artillerytables/functions/fnc_firedEH.sqf new file mode 100644 index 00000000000..b2053136e89 --- /dev/null +++ b/addons/artillerytables/functions/fnc_firedEH.sqf @@ -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 + * 1: weapon - Fired weapon + * 2: muzzle - Muzzle that was used + * 3: mode - Current mode of the fired weapon + * 4: ammo - Ammo used + * 5: magazine - magazine name which was used + * 6: projectile - Object of the projectile that was shot + * 7: gunner - Gunner + * + * 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); diff --git a/addons/artillerytables/functions/fnc_interactMenuOpened.sqf b/addons/artillerytables/functions/fnc_interactMenuOpened.sqf new file mode 100644 index 00000000000..849be932ce9 --- /dev/null +++ b/addons/artillerytables/functions/fnc_interactMenuOpened.sqf @@ -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) + * + * Return Value: + * Can Open + * + * 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]); diff --git a/addons/artillerytables/functions/fnc_rangeTableOpen.sqf b/addons/artillerytables/functions/fnc_rangeTableOpen.sqf new file mode 100644 index 00000000000..754c10356c9 --- /dev/null +++ b/addons/artillerytables/functions/fnc_rangeTableOpen.sqf @@ -0,0 +1,87 @@ +#include "script_component.hpp" +/* + * Author: PabstMirror + * Opens the rangetable and fills the charge listbox. + * + * Arguments: + * 0: Weapon configname + * 1: Elevation Min (Deg) + * 2: Elevation Max (Deg) + * 3: Advanced Corrections Enabled + * + * 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) diff --git a/addons/artillerytables/functions/fnc_rangeTableUpdate.sqf b/addons/artillerytables/functions/fnc_rangeTableUpdate.sqf new file mode 100644 index 00000000000..4f0a3d61565 --- /dev/null +++ b/addons/artillerytables/functions/fnc_rangeTableUpdate.sqf @@ -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) + * + * 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; diff --git a/addons/artillerytables/functions/fnc_turretChanged.sqf b/addons/artillerytables/functions/fnc_turretChanged.sqf new file mode 100644 index 00000000000..1975f65c73a --- /dev/null +++ b/addons/artillerytables/functions/fnc_turretChanged.sqf @@ -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 + * 1: Turret + * + * 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 +}; diff --git a/addons/artillerytables/functions/fnc_turretPFEH.sqf b/addons/artillerytables/functions/fnc_turretPFEH.sqf new file mode 100644 index 00000000000..5ab7c499b04 --- /dev/null +++ b/addons/artillerytables/functions/fnc_turretPFEH.sqf @@ -0,0 +1,92 @@ +#include "script_component.hpp" +/* + * Author: PabstMirror + * Shows real azimuth and elevation on hud + * + * Arguments: + * 0: PFEH Args + * + * 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); diff --git a/addons/artillerytables/functions/script_component.hpp b/addons/artillerytables/functions/script_component.hpp new file mode 100644 index 00000000000..d85f88930ab --- /dev/null +++ b/addons/artillerytables/functions/script_component.hpp @@ -0,0 +1 @@ +#include "\z\ace\addons\artillerytables\script_component.hpp" diff --git a/addons/artillerytables/initSettings.sqf b/addons/artillerytables/initSettings.sqf new file mode 100644 index 00000000000..7069e0ef50a --- /dev/null +++ b/addons/artillerytables/initSettings.sqf @@ -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; diff --git a/addons/artillerytables/script_component.hpp b/addons/artillerytables/script_component.hpp new file mode 100644 index 00000000000..128c3c17ff1 --- /dev/null +++ b/addons/artillerytables/script_component.hpp @@ -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 diff --git a/addons/artillerytables/stringtable.xml b/addons/artillerytables/stringtable.xml new file mode 100644 index 00000000000..1ac88416e63 --- /dev/null +++ b/addons/artillerytables/stringtable.xml @@ -0,0 +1,49 @@ + + + + + Artillery Rangetable + + + Universal Artillery Rangetable + + + Air Resistance + Opór powietrza + Resistencia al aire + Luftwiderstand + Odpor vzduchu + Resistência do Ar + Résistance de l'air + Légellenállás + Сопротивление воздуха + Resistenza dell'Aria + 空気抵抗 + 공기저항 + 空气阻力 + 空氣阻力 + + + For Player Shots, Model Air Resistance and Wind Effects + Modeluj opór powietrza oraz wpływ wiatru na tor lotu pocisku dla strzałów z moździerza Mk6 przez graczy + Para disparos del jugador, modelo de resistencia al aire y efectos de viento + Für Spielerschüsse, Luftwiderstand und Windeffekte + Pro hráčovu střelbu, Model odporu vzduchu a povětrných podmínek + Para disparos do jogador, modelo de resistência de ar e efeitos de vento + Pour les tirs de joueurs, modèle de résistance à l'air et d'effet du vent + Játékos általi lövésekhez, legyen-e számított légellenállás és szélhatás + Для выстрелов игрока. Моделирует сопротивление воздуха и эффект ветра + Per Proiettili dei Giocatori, simula la Resistenza dell'Aria e gli Effetti del Vento + プレイヤが射撃すると、空気抵抗モデルと風による影響をあたえます。 + 플레이어 사격시 공기저항과 바람에 영향을 받습니다 + 设定由玩家射击的迫击炮,将会受到空气阻力与风力的影响 + 設定由玩家射擊的迫擊砲,將會受到空氣阻力與風力的影響 + + + Artillery Computer Disabled + + + Disable the vanilla artillery computers + + + diff --git a/addons/common/functions/fnc_checkFiles.sqf b/addons/common/functions/fnc_checkFiles.sqf index 3d5adc101c4..b4a1fbbf74a 100644 --- a/addons/common/functions/fnc_checkFiles.sqf +++ b/addons/common/functions/fnc_checkFiles.sqf @@ -105,6 +105,9 @@ if (!isServer && {_platform in ["linux", "osx"]}) then { }; } forEach ("true" configClasses (configFile >> "ACE_Extensions")); }; +if (isArray (configFile >> "ACE_Extensions" >> "extensions")) then { + WARNING("extensions[] array no longer supported"); +}; /////////////// // check server version/addons diff --git a/addons/mk6mortar/ACE_Settings.hpp b/addons/mk6mortar/ACE_Settings.hpp index 5fb88aa23b2..9c3a1a33e8c 100644 --- a/addons/mk6mortar/ACE_Settings.hpp +++ b/addons/mk6mortar/ACE_Settings.hpp @@ -1,35 +1,14 @@ class ACE_Settings { - //These settings effect gameplay difficutly: defaults will leave the mortar the same as vanilla class GVAR(airResistanceEnabled) { - category = CSTRING(DisplayName); - displayName = CSTRING(airResistanceEnabled_DisplayName); - description = CSTRING(airResistanceEnabled_Description); - value = 0; - typeName = "BOOL"; - isClientSetable = 0; + movedToSQF = 1; }; class GVAR(allowComputerRangefinder) { - category = CSTRING(DisplayName); - displayName = CSTRING(allowComputerRangefinder_DisplayName); - description = CSTRING(allowComputerRangefinder_Description); - value = 1; - typeName = "BOOL"; - isClientSetable = 0; + movedToSQF = 1; }; class GVAR(allowCompass) { - category = CSTRING(DisplayName); - displayName = CSTRING(allowCompass_DisplayName); - description = CSTRING(allowCompass_Description); - value = 1; - typeName = "BOOL"; - isClientSetable = 0; + movedToSQF = 1; }; class GVAR(useAmmoHandling) { - category = CSTRING(DisplayName); - displayName = CSTRING(useAmmoHandling_DisplayName); - description = CSTRING(useAmmoHandling_Description); - value = 0; - typeName = "BOOL"; - isClientSetable = 0; + movedToSQF = 1; }; }; diff --git a/addons/mk6mortar/CfgEventHandlers.hpp b/addons/mk6mortar/CfgEventHandlers.hpp index 957fefb7367..becf3950523 100644 --- a/addons/mk6mortar/CfgEventHandlers.hpp +++ b/addons/mk6mortar/CfgEventHandlers.hpp @@ -16,11 +16,3 @@ class Extended_PostInit_EventHandlers { init = QUOTE(call COMPILE_FILE(XEH_postInit)); }; }; - -class Extended_FiredBIS_EventHandlers { - class Mortar_01_base_F { - class ADDON { - firedBIS = QUOTE(_this call FUNC(handleFired)); - }; - }; -}; diff --git a/addons/mk6mortar/RscInGameUI.hpp b/addons/mk6mortar/RscInGameUI.hpp index 3c2a1da5348..4145bc091f2 100644 --- a/addons/mk6mortar/RscInGameUI.hpp +++ b/addons/mk6mortar/RscInGameUI.hpp @@ -4,16 +4,8 @@ class RscInGameUI { }; 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;); - controls[] = {"ACE_ChargeDisplay", "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)"; - }; + controls[] = {"ACE_MILS_GROUP", "CA_IGUI_elements_group","CA_RangeElements_group"}; + class ACE_MILS_GROUP: CA_IGUI_elements_group { idc = 80170; class controls { diff --git a/addons/mk6mortar/XEH_PREP.hpp b/addons/mk6mortar/XEH_PREP.hpp index 03d6bd6051a..dd052a993e5 100644 --- a/addons/mk6mortar/XEH_PREP.hpp +++ b/addons/mk6mortar/XEH_PREP.hpp @@ -1,18 +1,9 @@ -PREP(dev_buildTable); -PREP(dev_formatNumber); -PREP(dev_simulateCalcRangeTableLine); -PREP(dev_simulateFindSolution); -PREP(dev_simulateShot); - PREP(csw_getProxyWeapon); - PREP(handleFired); PREP(handlePlayerVehicleChanged); PREP(moduleInit); PREP(rangeTableCanUse); PREP(rangeTableOpen); -PREP(rangeTablePageChange); -PREP(rangeTablePreCalculatedValues); PREP(toggleMils); PREP(turretDisplayLoaded); diff --git a/addons/mk6mortar/XEH_postInit.sqf b/addons/mk6mortar/XEH_postInit.sqf index 338f8597677..3ea99118932 100644 --- a/addons/mk6mortar/XEH_postInit.sqf +++ b/addons/mk6mortar/XEH_postInit.sqf @@ -5,7 +5,12 @@ if (hasInterface) then { }; ["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; + + 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; diff --git a/addons/mk6mortar/XEH_preInit.sqf b/addons/mk6mortar/XEH_preInit.sqf index b47cf6628db..9361d05015e 100644 --- a/addons/mk6mortar/XEH_preInit.sqf +++ b/addons/mk6mortar/XEH_preInit.sqf @@ -6,4 +6,6 @@ PREP_RECOMPILE_START; #include "XEH_PREP.hpp" PREP_RECOMPILE_END; +#include "initSettings.sqf" + ADDON = true; diff --git a/addons/mk6mortar/config.cpp b/addons/mk6mortar/config.cpp index 79fd0436198..6104f571aa0 100644 --- a/addons/mk6mortar/config.cpp +++ b/addons/mk6mortar/config.cpp @@ -7,7 +7,7 @@ class CfgPatches { "ACE_Box_82mm_Mo_Illum","ACE_Box_82mm_Mo_Combo"}; weapons[] = {"ACE_RangeTable_82mm","ace_mortar_82mm"}; requiredVersion = REQUIRED_VERSION; - requiredAddons[] = {"ace_csw"}; + requiredAddons[] = {"ace_csw", "ace_artillerytables"}; author = ECSTRING(common,ACETeam); authors[] = {"PabstMirror","Grey","VKing"}; url = ECSTRING(main,URL); @@ -33,4 +33,3 @@ class RscActiveText; class RscStructuredText; #include "RscInGameUI.hpp" -#include "RscRangeTable.hpp" diff --git a/addons/mk6mortar/functions/fnc_csw_getProxyWeapon.sqf b/addons/mk6mortar/functions/fnc_csw_getProxyWeapon.sqf index 04ed2a00148..f6d11334b31 100644 --- a/addons/mk6mortar/functions/fnc_csw_getProxyWeapon.sqf +++ b/addons/mk6mortar/functions/fnc_csw_getProxyWeapon.sqf @@ -61,7 +61,7 @@ if (_proxyWeaponNeeded || GVAR(useAmmoHandling)) then { } forEach (magazinesAllTurrets _mortar); // remove orignal mags and add 1rnd versions: - { _staticWeapon removeMagazinesTurret _x; } forEach _magsToRemove; + { _mortar removeMagazinesTurret _x; } forEach _magsToRemove; { _mortar addMagazineTurret _x; } forEach _convertedMags; }; diff --git a/addons/mk6mortar/functions/fnc_dev_buildTable.sqf b/addons/mk6mortar/functions/fnc_dev_buildTable.sqf deleted file mode 100644 index 6141314eead..00000000000 --- a/addons/mk6mortar/functions/fnc_dev_buildTable.sqf +++ /dev/null @@ -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 - * 1: Air Friction - * - * Return Value: - * None - * - * 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"; diff --git a/addons/mk6mortar/functions/fnc_dev_formatNumber.sqf b/addons/mk6mortar/functions/fnc_dev_formatNumber.sqf deleted file mode 100644 index a24f456037f..00000000000 --- a/addons/mk6mortar/functions/fnc_dev_formatNumber.sqf +++ /dev/null @@ -1,76 +0,0 @@ -#include "script_component.hpp" -/* - * Author: Pabst Mirror - * Converts numbers into nicely formated strings. - * - * Arguments: - * 0: Input number - * 1: Output type (see case statement) - * 2: If output type is mil, convert input type from deg->mil - * - * Return Value: - * Formatted number - * - * 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) diff --git a/addons/mk6mortar/functions/fnc_dev_simulateCalcRangeTableLine.sqf b/addons/mk6mortar/functions/fnc_dev_simulateCalcRangeTableLine.sqf deleted file mode 100644 index 2bdfe56c225..00000000000 --- a/addons/mk6mortar/functions/fnc_dev_simulateCalcRangeTableLine.sqf +++ /dev/null @@ -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 - * 1: Air Friction - * 2: Range To Hit - * - * Return Value: - * Range Table Line Data (see return line) - * - * 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] diff --git a/addons/mk6mortar/functions/fnc_dev_simulateFindSolution.sqf b/addons/mk6mortar/functions/fnc_dev_simulateFindSolution.sqf deleted file mode 100644 index 3c509d5a19e..00000000000 --- a/addons/mk6mortar/functions/fnc_dev_simulateFindSolution.sqf +++ /dev/null @@ -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) - * 1: Height To Hit (Meters) - * 2: Muzzle Velocity (M/S) - * 3: Air Friction - * 4: Time Step (seconds) (eg 1/50 will simulate 50 cycles per second) - * - * Return Value: - * [NUMBER - Elevation In Degrees, NUMBER - Shot Durration] - * - * 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)] diff --git a/addons/mk6mortar/functions/fnc_dev_simulateShot.sqf b/addons/mk6mortar/functions/fnc_dev_simulateShot.sqf deleted file mode 100644 index 7974526ff63..00000000000 --- a/addons/mk6mortar/functions/fnc_dev_simulateShot.sqf +++ /dev/null @@ -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) - * 1: Muzzle Velocity (m/s) - * 2: Air Friction - * 3: Tempeture (degres celcius) - * 4: Relative Air Denisty - * 5: Tail Wind (m/s) - * 6: Cross Wind (m/s) - * 7: Height Of Target (M) - * 8: Time Step (fraction of a second) - * - * Return Value: - * [Distance Traveled, Shot Time, Offset (degrees)] - * - * 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] diff --git a/addons/mk6mortar/functions/fnc_handleFired.sqf b/addons/mk6mortar/functions/fnc_handleFired.sqf index 550ae05f8a3..5224aa09a09 100644 --- a/addons/mk6mortar/functions/fnc_handleFired.sqf +++ b/addons/mk6mortar/functions/fnc_handleFired.sqf @@ -21,15 +21,13 @@ * Public: No */ -params ["_vehicle", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile"]; - -if (!GVAR(airResistanceEnabled)) exitWith {}; +params ["_vehicle", "", "", "", "", "", "_projectile"]; // Large enough distance to not simulate any wind deflection if (_vehicle distance ACE_player > 8000) exitWith {false}; //AI will have no clue how to use: -_shooterMan = gunner _vehicle; +private _shooterMan = gunner _vehicle; if (!([_shooterMan] call EFUNC(common,isPlayer))) exitWith {false}; //Calculate air density: @@ -45,8 +43,8 @@ TRACE_5("FiredWeather",_temperature,_pressure,_relativeHumidity,_airDensity,_rel //powder effects: private _newMuzzleVelocityCoefficent = (((_temperature + 273.13) / 288.13 - 1) / 40 + 1); if (_newMuzzleVelocityCoefficent != 1) then { - _bulletVelocity = velocity _projectile; - _bulletSpeed = vectorMagnitude _bulletVelocity; + private _bulletVelocity = velocity _projectile; + private _bulletSpeed = vectorMagnitude _bulletVelocity; _bulletVelocity = (vectorNormalized _bulletVelocity) vectorMultiply (_bulletSpeed * _newMuzzleVelocityCoefficent); _projectile setVelocity _bulletVelocity; }; @@ -64,7 +62,6 @@ if (_newMuzzleVelocityCoefficent != 1) then { _args set[2, CBA_missionTime]; private _bulletVelocity = velocity _shell; - private _bulletSpeed = vectorMagnitude _bulletVelocity; private _trueVelocity = _bulletVelocity vectorDiff wind; private _trueSpeed = vectorMagnitude _trueVelocity; diff --git a/addons/mk6mortar/functions/fnc_handlePlayerVehicleChanged.sqf b/addons/mk6mortar/functions/fnc_handlePlayerVehicleChanged.sqf index 6e0b9b17941..5628ef88b0c 100644 --- a/addons/mk6mortar/functions/fnc_handlePlayerVehicleChanged.sqf +++ b/addons/mk6mortar/functions/fnc_handlePlayerVehicleChanged.sqf @@ -56,40 +56,13 @@ if (_lastFireMode != -1) then { private _display = uiNamespace getVariable ["ACE_Mk6_RscWeaponRangeArtillery", displayNull]; if (isNull _display) exitWith {}; //It may be null for the first frame - private _chargeText = format ["%1: %2 ", (localize LSTRING(rangetable_charge)), _currentChargeMode, QPATHTOF(UI\ui_charges.paa)]; - //Hud should hidden in 3rd person private _notGunnerView = cameraView != "GUNNER"; - //Calc real azimuth/elevation - //(looking at the sky VS looking at ground will radicaly change fire direction because BIS) - private _realAzimuth = -1; - private _realElevation = -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; - }; + // Get aiming values from ace_artillerytables + // Note: it also handles displaying the "charge" level + private _realAzimuth = missionNamespace getVariable [QEGVAR(artillerytables,predictedAzimuth), -1]; + private _realElevation = missionNamespace getVariable [QEGVAR(artillerytables,predictedElevation), -1]; //Update Heading Display: if (_notGunnerView || (!GVAR(allowCompass))) then { @@ -102,13 +75,10 @@ if (_lastFireMode != -1) then { }; }; - //Update CurrentElevation Display and "charge" text + //Update CurrentElevation Display if (_notGunnerView) then { - (_display displayCtrl 80085) ctrlSetStructuredText parseText ""; (_display displayCtrl 80175) ctrlSetText ""; } else { - (_display displayCtrl 80085) ctrlSetStructuredText parseText _chargeText; - if (_useMils) then { (_display displayCtrl 80175) ctrlSetText str ((round (_realElevation * 6400 / 360)) % 6400); } else { diff --git a/addons/mk6mortar/functions/fnc_moduleInit.sqf b/addons/mk6mortar/functions/fnc_moduleInit.sqf index 31582368592..a0186dfb3d9 100644 --- a/addons/mk6mortar/functions/fnc_moduleInit.sqf +++ b/addons/mk6mortar/functions/fnc_moduleInit.sqf @@ -17,7 +17,7 @@ * Public: No */ -params ["_logic", "_syncedUnits", "_activated"]; +params ["_logic", "", "_activated"]; if (!_activated) exitWith {WARNING("Module - placed but not active");}; diff --git a/addons/mk6mortar/functions/fnc_rangeTableOpen.sqf b/addons/mk6mortar/functions/fnc_rangeTableOpen.sqf index f55e2bcd99b..56ef6a32c52 100644 --- a/addons/mk6mortar/functions/fnc_rangeTableOpen.sqf +++ b/addons/mk6mortar/functions/fnc_rangeTableOpen.sqf @@ -15,32 +15,6 @@ * 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 - -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; +["mortar_82mm", 45, 88, GVAR(airResistanceEnabled) || EGVAR(artillerytables,advancedCorrections)] call EFUNC(artillerytables,rangeTableOpen); diff --git a/addons/mk6mortar/functions/fnc_rangeTablePageChange.sqf b/addons/mk6mortar/functions/fnc_rangeTablePageChange.sqf deleted file mode 100644 index 84bb2fba056..00000000000 --- a/addons/mk6mortar/functions/fnc_rangeTablePageChange.sqf +++ /dev/null @@ -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 ["", "", "", "", "", "", "", "", "", "", ""]; diff --git a/addons/mk6mortar/functions/fnc_rangeTablePreCalculatedValues.sqf b/addons/mk6mortar/functions/fnc_rangeTablePreCalculatedValues.sqf deleted file mode 100644 index 7a219e55359..00000000000 --- a/addons/mk6mortar/functions/fnc_rangeTablePreCalculatedValues.sqf +++ /dev/null @@ -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 - * 1: Air Friction - * - * Return Value: - * 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"); - [] - }; -}; diff --git a/addons/mk6mortar/functions/fnc_toggleMils.sqf b/addons/mk6mortar/functions/fnc_toggleMils.sqf index a2c2a29789f..f010848acf7 100644 --- a/addons/mk6mortar/functions/fnc_toggleMils.sqf +++ b/addons/mk6mortar/functions/fnc_toggleMils.sqf @@ -5,7 +5,6 @@ * * Arguments: * 0: Vehicle - * 1: Player * * Return Value: * None @@ -16,7 +15,8 @@ * Public: No */ -params ["_mortarVeh", "_unit"]; +params ["_mortarVeh"]; +TRACE_1("toggleMils",_mortarVeh); private _currentSetting = _mortarVeh getVariable [QGVAR(useMils), true]; _mortarVeh setVariable [QGVAR(useMils), (!_currentSetting)]; diff --git a/addons/mk6mortar/functions/fnc_turretDisplayLoaded.sqf b/addons/mk6mortar/functions/fnc_turretDisplayLoaded.sqf index aa2e9f2823e..0a7ad4b928d 100644 --- a/addons/mk6mortar/functions/fnc_turretDisplayLoaded.sqf +++ b/addons/mk6mortar/functions/fnc_turretDisplayLoaded.sqf @@ -19,7 +19,7 @@ disableSerialization; params ["_display", "_rscType"]; -TRACE_2("params",_display,_rscType); +TRACE_2("turretDisplayLoaded",_display,_rscType); if (_rscType != "Mk6Mortar") exitWith {}; if (isNull _display) exitWith {}; diff --git a/addons/mk6mortar/initSettings.sqf b/addons/mk6mortar/initSettings.sqf new file mode 100644 index 00000000000..1e48575b972 --- /dev/null +++ b/addons/mk6mortar/initSettings.sqf @@ -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; diff --git a/extensions/CMakeLists.txt b/extensions/CMakeLists.txt index 0ac2fa50616..74f22ef9c38 100644 --- a/extensions/CMakeLists.txt +++ b/extensions/CMakeLists.txt @@ -99,8 +99,8 @@ endif() string(TIMESTAMP ACE_BUILDSTAMP "%Y-%m-%dT%H:%M:%SZ") set(ACE_VERSION_MAJOR 3) -set(ACE_VERSION_MINOR 12) -set(ACE_VERSION_REVISION 3) +set(ACE_VERSION_MINOR 13) +set(ACE_VERSION_REVISION 0) EXECUTE_PROCESS(COMMAND git rev-parse --verify HEAD OUTPUT_VARIABLE T_ACE_VERSION_BUILD OUTPUT_STRIP_TRAILING_WHITESPACE @@ -137,6 +137,7 @@ add_subdirectory(clipboard) add_subdirectory(advanced_ballistics) add_subdirectory(medical) add_subdirectory(parse_imagepath) +add_subdirectory(artillerytables) # Test Extension for dynamically loading/unloading built extensions; does not build in release if (DEVEL) diff --git a/extensions/artillerytables/CMakeLists.txt b/extensions/artillerytables/CMakeLists.txt new file mode 100644 index 00000000000..5b6d3863c9d --- /dev/null +++ b/extensions/artillerytables/CMakeLists.txt @@ -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) diff --git a/extensions/artillerytables/artillerytables.cpp b/extensions/artillerytables/artillerytables.cpp new file mode 100644 index 00000000000..7a73f066a8c --- /dev/null +++ b/extensions/artillerytables/artillerytables.cpp @@ -0,0 +1,283 @@ +/* + * artillerytables.hpp + * Author: PabstMirror + */ + +#include +#include +#include + +#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 gravityAccl(0, 0, -1 * gravityABS); + +// Globals: +std::vector> fWorkers; +unsigned int getLineIndex = 0; + +std::tuple 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 currentPosition(0, 0, 0); + ace::vector3 lastPosition(currentPosition); + ace::vector3 currentVelocity(0, powderEffects * _muzzleVelocity * cos(_fireAngleRad), powderEffects * _muzzleVelocity * sin(_fireAngleRad)); + const ace::vector3 wind(_crossWind, _tailWind, 0); + + while ((currentVelocity.z() > 0) || (currentPosition.z() >= _heightOfTarget)) { + lastPosition = currentPosition; + ace::vector3 apparentWind = wind - currentVelocity; + ace::vector3 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 finalPos = lastPosition.lerp(currentPosition, lastCurrentRatio); + + return { finalPos.x(), finalPos.y(), currentTime }; +} + +std::tuple 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 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 +} diff --git a/extensions/artillerytables/artillerytables.hpp b/extensions/artillerytables/artillerytables.hpp new file mode 100644 index 00000000000..038c1ae5c5b --- /dev/null +++ b/extensions/artillerytables/artillerytables.hpp @@ -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 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 findMaxAngle(const double _muzzleVelocity, const double _airFriction); +std::tuple 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); diff --git a/extensions/artillerytables/tests/tester.cpp b/extensions/artillerytables/tests/tester.cpp new file mode 100644 index 00000000000..2dfabe4566e --- /dev/null +++ b/extensions/artillerytables/tests/tester.cpp @@ -0,0 +1,100 @@ +#include +#include +#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(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(t3 - t2).count(), lines); + + std::printf("callExtensions finished in %1.1f ms\n", std::chrono::duration(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(); +}