From 697710d40d4e3f06efe60f366eeda0527a35c670 Mon Sep 17 00:00:00 2001 From: ulteq Date: Thu, 28 May 2015 19:17:29 +0200 Subject: [PATCH 1/9] Initial draft of the range card implementation. --- addons/rangecard/$PBOPREFIX$ | 1 + addons/rangecard/CfgEventHandlers.hpp | 11 + addons/rangecard/CfgVehicles.hpp | 60 +++++ addons/rangecard/CfgWeapons.hpp | 19 ++ addons/rangecard/README.md | 10 + addons/rangecard/RscTitles.hpp | 198 ++++++++++++++++ addons/rangecard/UI/RangeCard.paa | Bin 0 -> 41222 bytes addons/rangecard/UI/RangeCard_Icon.paa | Bin 0 -> 30512 bytes addons/rangecard/XEH_postInit.sqf | 11 + addons/rangecard/XEH_preInit.sqf | 14 ++ addons/rangecard/config.cpp | 17 ++ .../functions/fnc_calculateSolution.sqf | 218 ++++++++++++++++++ addons/rangecard/functions/fnc_canCopy.sqf | 18 ++ addons/rangecard/functions/fnc_canShow.sqf | 18 ++ .../rangecard/functions/fnc_canShowCopy.sqf | 18 ++ .../rangecard/functions/fnc_onCloseDialog.sqf | 4 + .../rangecard/functions/fnc_openRangeCard.sqf | 36 +++ .../functions/fnc_updateClassNames.sqf | 43 ++++ .../functions/fnc_updateRangeCard.sqf | 118 ++++++++++ .../rangecard/functions/script_component.hpp | 1 + addons/rangecard/initKeybinds.sqf | 31 +++ addons/rangecard/script_component.hpp | 12 + addons/rangecard/stringtable.xml | 26 +++ 23 files changed, 884 insertions(+) create mode 100644 addons/rangecard/$PBOPREFIX$ create mode 100644 addons/rangecard/CfgEventHandlers.hpp create mode 100644 addons/rangecard/CfgVehicles.hpp create mode 100644 addons/rangecard/CfgWeapons.hpp create mode 100644 addons/rangecard/README.md create mode 100644 addons/rangecard/RscTitles.hpp create mode 100644 addons/rangecard/UI/RangeCard.paa create mode 100644 addons/rangecard/UI/RangeCard_Icon.paa create mode 100644 addons/rangecard/XEH_postInit.sqf create mode 100644 addons/rangecard/XEH_preInit.sqf create mode 100644 addons/rangecard/config.cpp create mode 100644 addons/rangecard/functions/fnc_calculateSolution.sqf create mode 100644 addons/rangecard/functions/fnc_canCopy.sqf create mode 100644 addons/rangecard/functions/fnc_canShow.sqf create mode 100644 addons/rangecard/functions/fnc_canShowCopy.sqf create mode 100644 addons/rangecard/functions/fnc_onCloseDialog.sqf create mode 100644 addons/rangecard/functions/fnc_openRangeCard.sqf create mode 100644 addons/rangecard/functions/fnc_updateClassNames.sqf create mode 100644 addons/rangecard/functions/fnc_updateRangeCard.sqf create mode 100644 addons/rangecard/functions/script_component.hpp create mode 100644 addons/rangecard/initKeybinds.sqf create mode 100644 addons/rangecard/script_component.hpp create mode 100644 addons/rangecard/stringtable.xml diff --git a/addons/rangecard/$PBOPREFIX$ b/addons/rangecard/$PBOPREFIX$ new file mode 100644 index 0000000000..b319ce4b0d --- /dev/null +++ b/addons/rangecard/$PBOPREFIX$ @@ -0,0 +1 @@ +z\ace\addons\rangecard \ No newline at end of file diff --git a/addons/rangecard/CfgEventHandlers.hpp b/addons/rangecard/CfgEventHandlers.hpp new file mode 100644 index 0000000000..3996e3371d --- /dev/null +++ b/addons/rangecard/CfgEventHandlers.hpp @@ -0,0 +1,11 @@ +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) ); + }; +}; \ No newline at end of file diff --git a/addons/rangecard/CfgVehicles.hpp b/addons/rangecard/CfgVehicles.hpp new file mode 100644 index 0000000000..b3c75c62ec --- /dev/null +++ b/addons/rangecard/CfgVehicles.hpp @@ -0,0 +1,60 @@ +class CfgVehicles { + class Man; + class CAManBase: Man { + class ACE_Actions { + class ACE_Weapon { + class GVAR(copyRangeCard) { + displayName = "$STR_ACE_RangeCard_CopyRangeCard"; + distance = 2.0; + condition = QUOTE(_target call FUNC(canCopy)); + statement = QUOTE(_target call FUNC(updateClassNames)); + icon = QUOTE(PATHTOF(UI\RangeCard_Icon.paa)); + }; + }; + }; + class ACE_SelfActions { + class ACE_Equipment { + class GVAR(open) { + displayName = "$STR_ACE_RangeCard_OpenRangeCard"; + condition = QUOTE(call FUNC(canShow) && !GVAR(RangeCardOpened)); + statement = QUOTE(false call FUNC(openRangeCard)); + showDisabled = 0; + priority = 0.1; + icon = QUOTE(PATHTOF(UI\RangeCard_Icon.paa)); + exceptions[] = {"notOnMap"}; + }; + class GVAR(openCopy) { + displayName = "$STR_ACE_RangeCard_OpenRangeCardCopy"; + condition = QUOTE(call FUNC(canShowCopy) && !GVAR(RangeCardOpened)); + statement = QUOTE(true call FUNC(openRangeCard)); + showDisabled = 0; + priority = 0.1; + icon = QUOTE(PATHTOF(UI\RangeCard_Icon.paa)); + exceptions[] = {"notOnMap"}; + }; + }; + }; + }; + + class Item_Base_F; + class ACE_Item_RangeCard: Item_Base_F { + author = "Ruthberg"; + scope = 2; + scopeCurator = 2; + displayName = "Range Card"; + vehicleClass = "Items"; + class TransportItems { + class ACE_RangeCard { + name = "ACE_RangeCard"; + count = 1; + }; + }; + }; + + class Box_NATO_Support_F; + class ACE_Box_Misc: Box_NATO_Support_F { + class TransportItems { + MACRO_ADDITEM(ACE_RangeCard,6); + }; + }; +}; diff --git a/addons/rangecard/CfgWeapons.hpp b/addons/rangecard/CfgWeapons.hpp new file mode 100644 index 0000000000..0bd3e7daf6 --- /dev/null +++ b/addons/rangecard/CfgWeapons.hpp @@ -0,0 +1,19 @@ + +class CfgWeapons { + class ACE_ItemCore; + class InventoryItem_Base_F; + + class ACE_RangeCard: ACE_ItemCore { + author[] = {"Ruthberg"}; + scope = 2; + displayName = "$STR_ACE_RangeCard_Name"; + descriptionShort = "$STR_ACE_RangeCard_Description"; + picture = PATHTOF(UI\RangeCard_Icon.paa); + icon = "iconObject_circle"; + mapSize = 0.034; + + class ItemInfo: InventoryItem_Base_F { + mass = 1; + }; + }; +}; diff --git a/addons/rangecard/README.md b/addons/rangecard/README.md new file mode 100644 index 0000000000..c96e151869 --- /dev/null +++ b/addons/rangecard/README.md @@ -0,0 +1,10 @@ +ace_rangecards +=============== + +Adds range cards + +## Maintainers + +The people responsible for merging changes to this component or answering potential questions. + +- [Ruthberg] (http://github.com/Ulteq) \ No newline at end of file diff --git a/addons/rangecard/RscTitles.hpp b/addons/rangecard/RscTitles.hpp new file mode 100644 index 0000000000..c4da1862ca --- /dev/null +++ b/addons/rangecard/RscTitles.hpp @@ -0,0 +1,198 @@ +#define ST_LEFT 0 +#define ST_RIGHT 1 +#define ST_CENTER 2 + +class RscListNBox; +class ScrollBar; + +class RangeCard_RscText { + idc=-1; + type=0; + style=ST_CENTER; + colorDisabled[]={0,0,0,0.0}; + colorBackground[]={0,0,0,0}; + colorText[]={0,0,0,1}; + text=""; + x=0; + y=0; + h=0.028; + w=0.06; + font="TahomaB"; + SizeEx=0.025; + shadow=0; +}; + +class RangeCard_RscListNBox: RscListNBox { + idc=-1; + type=102; + style=0; + font="TahomaB"; + sizeEx=0.026; + rowHeight=0.027; + colorDisabled[]={0,0,0,0.0}; + colorBackground[]={1,1,1,1}; + colorText[]={0,0,0,1}; + colorScrollbar[]={0.95,0.95,0.95,1}; + colorSelect[]={0,0,0,1}; + colorSelect2[]={0,0,0,1}; + colorSelectBackground[]={1,1,1,0}; + colorSelectBackground2[]={1,1,1,0}; + period=0; + LineSpacing=0; + maxHistoryDelay=1.0; + autoScrollSpeed=-1; + autoScrollDelay=5; + autoScrollRewind=0; + soundSelect[]={"",0.09,1}; + drawSideArrows=0; + idcLeft=-1; + idcRight=-1; + + class ScrollBar { + color[]={1,1,1,0.6}; + colorActive[]={1,1,1,1}; + colorDisabled[]={1,1,1,0.3}; + }; + + class ListScrollBar : ScrollBar { + }; +}; + +class ACE_RangeCard_Dialog { + idd = -1; + movingEnable = 1; + onLoad = "uiNamespace setVariable ['RangleCard_Display', (_this select 0)]"; + onUnload = QUOTE(_this call FUNC(onCloseDialog)); + objects[] = {}; + + class controls { + class BACKGROUND { + moving=1; + type=0; + font="TahomaB"; + SizeEX=0.025; + idc=-1; + style=48; + x="safezoneX"; + y="safezoneY+0.181889"; + w="1.62727*3/4"; + h="1.62727"; + colorBackground[]={1,1,1,1}; + colorText[]={1,1,1,1}; + text=QUOTE(PATHTOF(UI\RangeCard.paa)); + }; + class CAPTION_TEXT_1: RangeCard_RscText { + idc=770000; + style=ST_LEFT; + x="safezoneX+0.18"; + y="safezoneY+0.181889+0.0"; + w="0.56*1.62727*3/4"; + text=".408 CheyTac - 410 gr Predator Projectiles"; + }; + class CAPTION_TEXT_2: CAPTION_TEXT_1 { + idc=770001; + SizeEx=0.022; + y="safezoneY+0.181889+0.03"; + text="Drop Tables for B.P.: 1013.25mb; Corrected for MVV at Air/Ammo Temperatures -15-35 °C"; + }; + class CAPTION_TEXT_3: CAPTION_TEXT_2 { + idc=770002; + y="safezoneY+0.181889+0.06"; + text="CheyTac Intervention - 29'' 1:13'' twist (M-200)"; + }; + class ZERO_RANGE_TEXT: RangeCard_RscText { + idc=77003; + style=ST_LEFT; + SizeEx=0.028; + x="safezoneX+0.885"; + y="safezoneY+0.181889+0.01"; + w="0.125*1.62727*3/4"; + text="100m ZERO"; + }; + class BAROMETRIC_PRESSURE_TEXT: ZERO_RANGE_TEXT { + idc=77004; + colorText[]={1,0,0,0.8}; + y="safezoneY+0.181889+0.05"; + text="B.P.: 1013.25mb"; + }; + class TARGET_RANGE_TEXT_1: RangeCard_RscText { + idc=770010; + colorText[]={1,1,1,1}; + x="safezoneX+0.185"; + y="safezoneY+0.181889+0.098"; + text="Target"; + }; + class TARGET_RANGE_TEXT_2: TARGET_RANGE_TEXT_1 { + idc=770011; + SizeEx=0.03; + y="safezoneY+0.181889+0.125"; + text="Range"; + }; + class TARGET_RANGE_TEXT_3: TARGET_RANGE_TEXT_1 { + idc=770012; + y="safezoneY+0.181889+0.152"; + text="(m)"; + }; + class BULLET_DROP_TEXT_1: RangeCard_RscText { + idc=770013; + x="safezoneX+0.25"; + y="safezoneY+0.181889+0.095"; + w="0.405*1.62727*3/4"; + text="Bullet Drop (MRADs)"; + }; + class WIND_LEAD_CAPTION_LIST: RangeCard_RscListNBox { + idc=770100; + sizeEx=0.021; + x="safezoneX+0.728"; + y="safezoneY+0.181889+0.091"; + w="0.25*1.62727*3/4"; + h="0.0909445"; + columns[]={(0.03/2), (0.985/2)}; + idcLeft=770101; + idcRight=770102; + }; + class TEMPERATURE_CAPTION_LIST_1: RangeCard_RscListNBox { + idc=770200; + x="safezoneX+0.24"; + y="safezoneY+0.181889+0.125"; + w="0.405*1.62727*3/4"; + h="0.0909445"; + columns[]={(0/9), (1/9), (2/9), (3/9), (4/9), (5/9), (5.9/9), (6.9/9), (7.8/9)}; + idcLeft=770201; + idcRight=770202; + }; + class TEMPERATURE_CAPTION_LIST_2: RangeCard_RscListNBox { + idc=770300; + x="safezoneX+0.728"; + y="safezoneY+0.181889+0.15"; + w="0.25*1.62727*3/4"; + h="0.0909445"; + columns[]={(0/6), (0.9/6), (1.8/6), (2.9/6), (3.8/6), (4.8/6)}; + idcLeft=770301; + idcRight=770302; + }; + class RANGE_CARD_DATA: RangeCard_RscListNBox { + idc=770400; + x="safezoneX+0.182"; + y="safezoneY+0.181889+0.194"; + w="0.72*1.62727*3/4"; + h="1.62727"; + columns[]={(0/16), (1.2/16), (2.2/16), (3.2/16), (4.2/16), (5.1/16), (6.1/16), (7.1/16), (8.1/16), + (9/16), (10.2/16), (11/16), (11.9/16), (12.8/16), (13.7/16), (14.6/16)}; + idcLeft=770401; + idcRight=770402; + }; + class FOOTNOTE_TEXT_1: CAPTION_TEXT_1 { + idc=770020; + SizeEx=0.022; + y="safezoneY+1.72431"; + w="0.705*1.62727*3/4"; + text="For best results keep ammunition at ambient air temperature. Tables calculated for the above listed barrel"; + }; + class FOOTNOTE_TEXT_2: FOOTNOTE_TEXT_1 { + idc=770021; + y="safezoneY+1.72431+0.024"; + text="and load with optic mounted 1.5'' above line of bore."; + }; + }; +}; diff --git a/addons/rangecard/UI/RangeCard.paa b/addons/rangecard/UI/RangeCard.paa new file mode 100644 index 0000000000000000000000000000000000000000..56f0bfd30c3695d1b6a8847023dd14c3123d55a2 GIT binary patch literal 41222 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 literal 0 HcmV?d00001 diff --git a/addons/rangecard/XEH_postInit.sqf b/addons/rangecard/XEH_postInit.sqf new file mode 100644 index 0000000000..2b11b574e1 --- /dev/null +++ b/addons/rangecard/XEH_postInit.sqf @@ -0,0 +1,11 @@ +#include "script_component.hpp" + +#include "initKeybinds.sqf" + +GVAR(RangeCardOpened) = false; + +GVAR(ammoClass) = "B_65x39_Caseless"; +GVAR(weaponClass) = "arifle_MXM_F"; + +GVAR(ammoClassCopy) = "";//"ACE_762x51_Ball_M118LR"; +GVAR(weaponClassCopy) = "";//srifle_DMR_06_olive_F"; diff --git a/addons/rangecard/XEH_preInit.sqf b/addons/rangecard/XEH_preInit.sqf new file mode 100644 index 0000000000..5e5685d30f --- /dev/null +++ b/addons/rangecard/XEH_preInit.sqf @@ -0,0 +1,14 @@ +#include "script_component.hpp" + +ADDON = false; + +PREP(calculateSolution); +PREP(canCopy); +PREP(canShow); +PREP(canShowCopy); +PREP(onCloseDialog); +PREP(openRangeCard); +PREP(updateClassNames); +PREP(updateRangeCard); + +ADDON = true; diff --git a/addons/rangecard/config.cpp b/addons/rangecard/config.cpp new file mode 100644 index 0000000000..abe4e859f2 --- /dev/null +++ b/addons/rangecard/config.cpp @@ -0,0 +1,17 @@ +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + units[] = {"ACE_Item_RangeCard"}; + weapons[] = {"ACE_RangeCard"}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = {"ACE_Advanced_Ballistics"}; + author = "Ruthberg"; + VERSION_CONFIG; + }; +}; + +#include "CfgEventHandlers.hpp" +#include "CfgVehicles.hpp" +#include "CfgWeapons.hpp" +#include "RscTitles.hpp" \ No newline at end of file diff --git a/addons/rangecard/functions/fnc_calculateSolution.sqf b/addons/rangecard/functions/fnc_calculateSolution.sqf new file mode 100644 index 0000000000..68189ac36b --- /dev/null +++ b/addons/rangecard/functions/fnc_calculateSolution.sqf @@ -0,0 +1,218 @@ +/* + * Author: Ruthberg + * Calculates the range card data + * + * Arguments: + * 0: Scope base angle + * 1: Bullet mass + * 2: Bore height + * 3: air friction + * 4: muzzle velocity + * 5: temperature + * 6: barometric pressure + * 7: relative humidity + * 8: simulation steps + * 9: wind speed + * 10: wind direction + * 11: inclination angle + * 12: target speed + * 13: target range + * 14: ballistic coefficient + * 15: drag model + * 16: atmosphere model + * 17: Store range card data? + * 18: Stability factor + * 19: Twist Direction + * 20: Latitude + * 21: Range Card Slot + * + * Return Value: + * 0: Elevation (MOA) + * 1: Windage (MOA) + * 2: Lead (MOA) + * 3: Time of fligth (SECONDS) + * 4: Remaining velocity (m/s) + * 5: Remaining kinetic energy (ft·lb) + * 6: Vertical coriolis drift (MOA) + * 7: Horizontal coriolis drift (MOA) + * 8: Spin drift (MOA) + * + * Example: + * call ace_rangecard_calculate_range_card_data + * + * Public: No + */ +#include "script_component.hpp" + +private ["_scopeBaseAngle", "_bulletMass", "_boreHeight", "_airFriction", "_muzzleVelocity", "_temperature", "_barometricPressure", "_relativeHumidity", "_simSteps", "_windSpeed1", "_windSpeed2", "_windDirection", "_inclinationAngle", "_targetSpeed", "_targetRange", "_drag", "_bc", "_dragModel", "_atmosphereModel", "_storeRangeCardData", "_stabilityFactor", "_twistDirection", "_latitude", "_directionOfFire", "_rangeCardSlot"]; +_scopeBaseAngle = _this select 0; +_bulletMass = _this select 1; +_boreHeight = _this select 2; +_airFriction = _this select 3; +_muzzleVelocity = _this select 4; +_temperature = _this select 5; +_barometricPressure = _this select 6; +_relativeHumidity = _this select 7; +_simSteps = _this select 8; +_windSpeed1 = (_this select 9) select 0; +_windSpeed2 = (_this select 9) select 1; +_windDirection = _this select 10; +_inclinationAngle = _this select 11; +_targetSpeed = _this select 12; +_targetRange = _this select 13; +_bc = _this select 14; +_dragModel = _this select 15; +_atmosphereModel = _this select 16; +_storeRangeCardData = _this select 17; +_stabilityFactor = _this select 18; +_twistDirection = _this select 19; +_latitude = _this select 20; +_directionOfFire = _this select 21; +_rangeCardSlot = _this select 22; + +if (_storeRangeCardData) then { + GVAR(rangeCardDataMVs) pushBack format[" %1", round(_muzzleVelocity)]; +}; + +private ["_bulletPos", "_bulletVelocity", "_bulletAccel", "_bulletSpeed", "_gravity", "_deltaT"]; +_bulletPos = [0, 0, 0]; +_bulletVelocity = [0, 0, 0]; +_bulletAccel = [0, 0, 0]; +_bulletSpeed = 0; +_gravity = [0, sin(_scopeBaseAngle + _inclinationAngle) * -9.80665, cos(_scopeBaseAngle + _inclinationAngle) * -9.80665]; +_deltaT = 1 / _simSteps; + +private ["_elevation", "_windage1", "_windage2", "_lead", "_TOF", "_trueVelocity", "_trueSpeed", "_kineticEnergy", "_verticalCoriolis", "_verticalDeflection", "_horizontalCoriolis", "_horizontalDeflection", "_spinDrift", "_spinDeflection"]; +_elevation = 0; +_windage1 = 0; +_windage2 = 0; +_lead = 0; +_TOF = 0; +_trueVelocity = [0, 0, 0]; +_trueSpeed = 0; +_verticalCoriolis = 0; +_verticalDeflection = 0; +_horizontalCoriolis = 0; +_horizontalDeflection = 0; +_spinDrift = 0; +_spinDeflection = 0; + +private ["_n", "_range", "_rangeFactor"]; +_n = 0; +_range = 0; +_rangeFactor = 1; +if (_storeRangeCardData) then { + if (GVAR(currentUnit) == 1) then { + _rangeFactor = 1.0936133; + }; +}; + +private ["_wind1", "_wind2", "_windDrift"]; +_wind1 = [cos(270 - _windDirection * 30) * _windSpeed1, sin(270 - _windDirection * 30) * _windSpeed1, 0]; +_wind2 = [cos(270 - _windDirection * 30) * _windSpeed2, sin(270 - _windDirection * 30) * _windSpeed2, 0]; +_windDrift = 0; +if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { + _bc = [_bc, _temperature, _barometricPressure, _relativeHumidity, _atmosphereModel] call EFUNC(advanced_ballistics,calculateAtmosphericCorrection); +}; + +private ["_speedTotal", "_stepsTotal", "_speedAverage"]; +_speedTotal = 0; +_stepsTotal = 0; +_speedAverage = 0; + +private ["_eoetvoesMultiplier"]; +_eoetvoesMultiplier = 0; +if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { + _eoetvoesMultiplier = 2 * (0.0000729 * _muzzleVelocity / -9.80665) * cos(_latitude) * sin(_directionOfFire); +}; + +_TOF = 0; + +_bulletPos set [0, 0]; +_bulletPos set [1, 0]; +_bulletPos set [2, -(_boreHeight / 100)]; + +_bulletVelocity set [0, 0]; +_bulletVelocity set [1, Cos(_scopeBaseAngle) * _muzzleVelocity]; +_bulletVelocity set [2, Sin(_scopeBaseAngle) * _muzzleVelocity]; + +while {_TOF < 6 && (_bulletPos select 1) < _targetRange} do { + _bulletSpeed = vectorMagnitude _bulletVelocity; + + _speedTotal = _speedTotal + _bulletSpeed; + _stepsTotal = _stepsTotal + 1; + _speedAverage = (_speedTotal / _stepsTotal); + + if (_speedAverage > 400 && _bulletSpeed < 340) exitWith {}; + if (atan((_bulletPos select 2) / (abs(_bulletPos select 1) + 1)) < -2.25) exitWith {}; + + _trueVelocity = _bulletVelocity vectorDiff _wind1; + _trueSpeed = vectorMagnitude _trueVelocity; + + if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { + _drag = if (missionNamespace getVariable [QEGVAR(advanced_ballistics,extensionAvailable), false]) then { + parseNumber(("ace_advanced_ballistics" callExtension format["retard:%1:%2:%3", _dragModel, _bc, _trueSpeed])) + } else { + ([_dragModel, _bc, _trueSpeed] call EFUNC(advanced_ballistics,calculateRetardation)) + }; + _bulletAccel = (vectorNormalized _trueVelocity) vectorMultiply (-1 * _drag); + } else { + _bulletAccel = _trueVelocity vectorMultiply (_trueSpeed * _airFriction); + }; + + _bulletAccel = _bulletAccel vectorAdd _gravity; + + _bulletVelocity = _bulletVelocity vectorAdd (_bulletAccel vectorMultiply _deltaT); + _bulletPos = _bulletPos vectorAdd (_bulletVelocity vectorMultiply _deltaT); + + _TOF = _TOF + _deltaT; + + if (_storeRangeCardData) then { + _range = GVAR(rangeCardStartRange) + _n * GVAR(rangeCardIncrement); + if ((_bulletPos select 1) * _rangeFactor >= _range && _range <= GVAR(rangeCardEndRange)) then { + if ((_bulletPos select 1) > 0) then { + _elevation = - atan((_bulletPos select 2) / (_bulletPos select 1)); + _windage1 = - atan((_bulletPos select 0) / (_bulletPos select 1)); + }; + if (_range != 0) then { + _lead = (_targetSpeed * _TOF) / (Tan(3.38 / 60) * _range); + }; + private ["_elevationString", "_windageString", "_leadString"]; + _elevationString = Str(round(-_elevation * 60 / 3.38 * 10) / 10); + if (_elevationString == "0") then { + _elevationString = "-0.0"; + }; + if (_elevationString find "." == -1) then { + _elevationString = _elevationString + ".0"; + }; + _windageString = Str(round(_windage1 * 60 / 3.38 * 10) / 10); + if (_windageString find "." == -1) then { + _windageString = _windageString + ".0"; + }; + _leadString = Str(round(_lead * 10) / 10); + if (_leadString find "." == -1) then { + _leadString = _leadString + ".0"; + }; + (GVAR(rangeCardDataElevation) select _rangeCardSlot) set [_n, _elevationString]; + (GVAR(rangeCardDataWindage) select _rangeCardSlot) set [_n, _windageString]; + (GVAR(rangeCardDataLead) select _rangeCardSlot) set [_n, _leadString]; + _n = _n + 1; + }; + }; +}; + +if ((_bulletPos select 1) > 0) then { + _elevation = - atan((_bulletPos select 2) / (_bulletPos select 1)); + _windage1 = - atan((_bulletPos select 0) / (_bulletPos select 1)); + _windDrift = (_wind2 select 0) * (_TOF - _targetRange / _muzzleVelocity); + _windage2 = - atan(_windDrift / (_bulletPos select 1)); +}; + +if (_targetRange != 0) then { + _lead = (_targetSpeed * _TOF) / (Tan(3.38 / 60) * _targetRange); +}; + +_kineticEnergy = 0.5 * (_bulletMass / 1000 * (_bulletSpeed ^ 2)); +_kineticEnergy = _kineticEnergy * 0.737562149; + +[_elevation * 60, [_windage1 * 60, _windage2 * 60], _lead, _TOF, _bulletSpeed, _kineticEnergy, _verticalCoriolis * 60, _horizontalCoriolis * 60, _spinDrift * 60] \ No newline at end of file diff --git a/addons/rangecard/functions/fnc_canCopy.sqf b/addons/rangecard/functions/fnc_canCopy.sqf new file mode 100644 index 0000000000..c9e0a05d0e --- /dev/null +++ b/addons/rangecard/functions/fnc_canCopy.sqf @@ -0,0 +1,18 @@ +/* + * Authors: Ruthberg + * Checks if the target has a copyable range card + * + * Arguments: + * unit + * + * Return Value: + * canShow (bool) + * + * Example: + * [] call ace_rangecard_fnc_canCopy + * + * Public: No + */ +#include "script_component.hpp" + +((primaryWeapon _this) != "" && [_this] call EFUNC(common,isPlayer) && [_this, "ACE_RangeCard"] call EFUNC(common,hasItem)) diff --git a/addons/rangecard/functions/fnc_canShow.sqf b/addons/rangecard/functions/fnc_canShow.sqf new file mode 100644 index 0000000000..d069048acb --- /dev/null +++ b/addons/rangecard/functions/fnc_canShow.sqf @@ -0,0 +1,18 @@ +/* + * Authors: Ruthberg + * Tests if the Range Card can be shown + * + * Arguments: + * Nothing + * + * Return Value: + * canShow (bool) + * + * Example: + * [] call ace_rangecard_fnc_canShow + * + * Public: No + */ +#include "script_component.hpp" + +(GVAR(ammoClass) != "" && GVAR(weaponClass) != "" && !GVAR(RangeCardOpened) && !(underwater ACE_player) && ("ACE_RangeCard" in (uniformItems ACE_player)) || ("ACE_RangeCard" in (vestItems ACE_player))) diff --git a/addons/rangecard/functions/fnc_canShowCopy.sqf b/addons/rangecard/functions/fnc_canShowCopy.sqf new file mode 100644 index 0000000000..1dd1318764 --- /dev/null +++ b/addons/rangecard/functions/fnc_canShowCopy.sqf @@ -0,0 +1,18 @@ +/* + * Authors: Ruthberg + * Tests if the Range Card copy can be shown + * + * Arguments: + * Nothing + * + * Return Value: + * canShow (bool) + * + * Example: + * [] call ace_rangecard_fnc_canShowCopy + * + * Public: No + */ +#include "script_component.hpp" + +(GVAR(ammoClassCopy) != "" && GVAR(weaponClassCopy) != "" && !GVAR(RangeCardOpened) && !(underwater ACE_player) && ("ACE_RangeCard" in (uniformItems ACE_player)) || ("ACE_RangeCard" in (vestItems ACE_player))) diff --git a/addons/rangecard/functions/fnc_onCloseDialog.sqf b/addons/rangecard/functions/fnc_onCloseDialog.sqf new file mode 100644 index 0000000000..f5d971f22f --- /dev/null +++ b/addons/rangecard/functions/fnc_onCloseDialog.sqf @@ -0,0 +1,4 @@ +#include "script_component.hpp" + +uiNamespace setVariable ['RangleCard_Display', nil]; +GVAR(RangeCardOpened) = false; diff --git a/addons/rangecard/functions/fnc_openRangeCard.sqf b/addons/rangecard/functions/fnc_openRangeCard.sqf new file mode 100644 index 0000000000..2c59ef1da1 --- /dev/null +++ b/addons/rangecard/functions/fnc_openRangeCard.sqf @@ -0,0 +1,36 @@ +/* + * Authors: Ruthberg + * Opens the range card dialog + * + * Arguments: + * Open copy? + * + * Return Value: + * Nothing + * + * Example: + * call ace_rangecard_fnc_openRangeCard + * + * Public: No + */ +#include "script_component.hpp" + +if (GVAR(RangeCardOpened)) exitWith {}; + +if (_this) then { + if (GVAR(ammoClassCopy) != "" && GVAR(weaponClassCopy) != "") then { + GVAR(RangeCardOpened) = true; + + createDialog "ACE_RangeCard_Dialog"; + + [GVAR(ammoClassCopy), GVAR(weaponClassCopy)] call FUNC(updateRangeCard); + }; +} else { + if (ACE_player call FUNC(updateClassNames)) then { + GVAR(RangeCardOpened) = true; + + createDialog "ACE_RangeCard_Dialog"; + + [GVAR(ammoClass), GVAR(weaponClass)] call FUNC(updateRangeCard); + }; +}; diff --git a/addons/rangecard/functions/fnc_updateClassNames.sqf b/addons/rangecard/functions/fnc_updateClassNames.sqf new file mode 100644 index 0000000000..203b2db926 --- /dev/null +++ b/addons/rangecard/functions/fnc_updateClassNames.sqf @@ -0,0 +1,43 @@ +/* + * Authors: Ruthberg + * Updates the ammo and weapon class names + * + * Arguments: + * unit + * + * Return Value: + * Update successful? + * + * Example: + * unit call ace_rangecard_fnc_updateClassNames + * + * Public: No + */ +#include "script_component.hpp" + +private ["_unit", "_ammoClass", "_weaponClass", "_ammo", "_ammoConfig", "_parentClasses"]; +_unit = _this; + +_ammoClass = ""; +_weaponClass = primaryWeapon _unit; + +if (_weaponClass == "") exitWith { (GVAR(ammoClass) != "" && GVAR(weaponClass) != "") }; + +{ + _ammo = getText (configFile >> "CfgMagazines" >> _x >> "ammo"); + _ammoConfig = (configFile >> "CfgAmmo" >> _ammo); + _parentClasses = [_ammoConfig, true] call BIS_fnc_returnParents; + if ("BulletBase" in _parentClasses) exitWith { _ammoClass = _ammo; }; +} forEach (primaryWeaponMagazine _unit); + +if (_ammoClass == "") exitWith { (GVAR(ammoClass) != "" && GVAR(weaponClass) != "") }; + +if (_unit == ACE_player) then { + GVAR(ammoClass) = _ammoClass; + GVAR(weaponClass) = _weaponClass; +} else { + GVAR(ammoClassCopy) = _ammoClass; + GVAR(weaponClassCopy) = _weaponClass; +}; + +true diff --git a/addons/rangecard/functions/fnc_updateRangeCard.sqf b/addons/rangecard/functions/fnc_updateRangeCard.sqf new file mode 100644 index 0000000000..a01b82af91 --- /dev/null +++ b/addons/rangecard/functions/fnc_updateRangeCard.sqf @@ -0,0 +1,118 @@ +/* + * Authors: Ruthberg + * Updates the range card data + * + * Arguments: + * 0: ammo class + * 1: weapon class + * + * Return Value: + * Nothing + * + * Example: + * [mode] call ace_rangecard_fnc_openRangeCard + * + * Public: No + */ +#include "script_component.hpp" + +PARAMS_2(_ammoClass,_weaponClass); + +if (_ammoClass == "" || _weaponClass == "") exitWith {}; + +lnbClear 770100; +lnbClear 770200; +lnbClear 770300; +lnbClear 770400; + +lnbAddRow [770100, ["4mps Wind(MRADs)", "1mps LEAD(MRADs)"]]; +lnbAddRow [770100, ["Air/Ammo Temp", "Air/Ammo Temp"]]; + +lnbAddRow [770200, ["-15°C", " -5°C", " 5°C", " 10°C", " 15°C", " 20°C", " 25°C", " 30°C", " 35°C"]]; +lnbAddRow [770300, ["-15°C", " 10°C", " 35°C", "-15°C", " 10°C", " 35°C"]]; + +GVAR(rangeCardDataElevation) = [[], [], [], [], [], [], [], [], []]; +GVAR(rangeCardDataWindage) = [[], [], [], [], [], [], [], [], []]; +GVAR(rangeCardDataLead) = [[], [], [], [], [], [], [], [], []]; +GVAR(rangeCardDataMVs) = []; +GVAR(lastValidRow) = []; + +GVAR(currentUnit) = 2; +GVAR(rangeCardStartRange) = 100; +GVAR(rangeCardIncrement) = 50; +GVAR(rangeCardEndRange) = GVAR(rangeCardStartRange) + 49 * GVAR(rangeCardIncrement); + +_ammoConfig = _ammoClass call EFUNC(advanced_ballistics,readAmmoDataFromConfig); +_weaponConfig = _weaponClass call EFUNC(advanced_ballistics,readWeaponDataFromConfig); +_airFriction = _ammoConfig select 0; +_barrelTwist = _weaponConfig select 0; +_barrelLength = _weaponConfig select 2; +_muzzleVelocity = [_barrelLength, _ammoConfig select 10, _ammoConfig select 11, 0] call EFUNC(advanced_ballistics,calculateBarrelLengthVelocityShift); + +ctrlSetText [770000, format["%1'' - %2 gr (%3)", round((_ammoConfig select 1) * 39.3700787) / 1000, round((_ammoConfig select 3) * 15.4323584), _ammoClass]]; +ctrlSetText [770002, format["Barrel: %1'' 1:%2'' twist", round(_barrelLength * 0.0393700787), round(_barrelTwist * 0.0393700787)]]; + +_bc = (_ammoConfig select 6) select 0; +_dragModel = _ammoConfig select 5; +_atmosphereModel = _ammoConfig select 8; +_boreHeight = 3.81; +_zeroRange = 100; + +_barometricPressure = EGVAR(weather,altitude) call EFUNC(weather,calculateBarometricPressure); +_relativeHumidity = 0.5; + +ctrlSetText [770001, format["Drop Tables for B.P.: %1mb; Corrected for MVV at Air/Ammo Temperatures -15-35 °C", round(_barometricPressure * 100) / 100]]; +ctrlSetText [77004 , format["B.P.: %1mb", round(_barometricPressure * 100) / 100]]; + +_cacheEntry = missionNamespace getVariable format[QGVAR(%1_%2), _ammoClass, _weaponClass]; +if (isNil {_cacheEntry}) then { + { + _mvShift = [_ammoConfig select 9, _x] call EFUNC(advanced_ballistics,calculateAmmoTemperatureVelocityShift); + _mv = _muzzleVelocity + _mvShift; + + _result = [0, 0, _boreHeight, _airFriction, _mv, _x, 1013.25, 0.5, 1000, [0, 0], 0, 0, 0, _zeroRange, _bc, _dragModel, _atmosphereModel, false, 1.5, 0, 0, 0] call FUNC(calculateSolution); + _scopeBaseAngle = (_result select 0) / 60; + + [_scopeBaseAngle,27,_boreHeight,_airFriction,_mv,_x,_barometricPressure,_relativeHumidity,1000,[4,0],3,0,4,GVAR(rangeCardEndRange),_bc,_dragModel,_atmosphereModel,true,1.5,1,46,23,_forEachIndex] call FUNC(calculateSolution); + } forEach [-15, -5, 5, 10, 15, 20, 25, 30, 35]; + + for "_i" from 0 to 9 do { + GVAR(lastValidRow) pushBack count (GVAR(rangeCardDataElevation) select _i); + while {count (GVAR(rangeCardDataElevation) select _i) < 50} do { + (GVAR(rangeCardDataElevation) select _i) pushBack "###"; + (GVAR(rangeCardDataWindage) select _i) pushBack "##"; + (GVAR(rangeCardDataLead) select _i) pushBack "##"; + }; + }; + + missionNamespace setVariable [format[QGVAR(%1_%2), _ammoClass, _weaponClass], [GVAR(rangeCardDataElevation), GVAR(rangeCardDataWindage), GVAR(rangeCardDataLead), GVAR(rangeCardDataMVs), GVAR(lastValidRow)]]; +} else { + GVAR(rangeCardDataElevation) = _cacheEntry select 0; + GVAR(rangeCardDataWindage) = _cacheEntry select 1; + GVAR(rangeCardDataLead) = _cacheEntry select 2; + GVAR(rangeCardDataMVs) = _cacheEntry select 3; + GVAR(lastValidRow) = _cacheEntry select 4; +}; + +lnbAddRow [770200, GVAR(rangeCardDataMVs)]; + +for "_i" from 0 to 49 do { + lnbAddRow [770400, [Str(GVAR(rangeCardStartRange) + GVAR(rangeCardIncrement) * _i), (GVAR(rangeCardDataElevation) select 0) select _i, (GVAR(rangeCardDataElevation) select 1) select _i, (GVAR(rangeCardDataElevation) select 2) select _i, + (GVAR(rangeCardDataElevation) select 3) select _i, (GVAR(rangeCardDataElevation) select 4) select _i, (GVAR(rangeCardDataElevation) select 5) select _i, + (GVAR(rangeCardDataElevation) select 6) select _i, (GVAR(rangeCardDataElevation) select 7) select _i, (GVAR(rangeCardDataElevation) select 8) select _i, + (GVAR(rangeCardDataWindage) select 0) select _i, (GVAR(rangeCardDataWindage) select 3) select _i, (GVAR(rangeCardDataWindage) select 8) select _i, + (GVAR(rangeCardDataLead) select 0) select _i, (GVAR(rangeCardDataLead) select 3) select _i, (GVAR(rangeCardDataLead) select 8) select _i]]; +}; + +#define __dsp (uiNamespace getVariable "RangleCard_Display") +#define __ctrlListNBox (__dsp displayCtrl 770400) + +{ + __ctrlListNBox lnbSetColor [[_x, 0], [1, 1, 1, 1]]; +} forEach [0, 8, 18, 28, 38, 48]; + +{ + for "_i" from (GVAR(lastValidRow) select _x) to 49 do { + __ctrlListNBox lnbSetColor [[_i, _forEachIndex + 1], [0, 0, 0, 0.6]]; + }; +} forEach [0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 3, 8, 0, 3, 8]; diff --git a/addons/rangecard/functions/script_component.hpp b/addons/rangecard/functions/script_component.hpp new file mode 100644 index 0000000000..fdc4a3d486 --- /dev/null +++ b/addons/rangecard/functions/script_component.hpp @@ -0,0 +1 @@ +#include "\z\ace\addons\rangecard\script_component.hpp" \ No newline at end of file diff --git a/addons/rangecard/initKeybinds.sqf b/addons/rangecard/initKeybinds.sqf new file mode 100644 index 0000000000..519b4730cc --- /dev/null +++ b/addons/rangecard/initKeybinds.sqf @@ -0,0 +1,31 @@ +["ACE3 Equipment", QGVAR(RangeCardDialogKey), localize "STR_ACE_RangeCard_RangeCardDialogKey", +{ + // Conditions: canInteract, canShow + if !([ACE_player, objNull, []] call EFUNC(common,canInteractWith)) exitWith {false}; + if (GVAR(RangeCardOpened)) exitWith { + closeDialog 0; + false + }; + if !(call FUNC(canShow)) exitWith {false}; + // Statement + false call FUNC(openRangeCard); + true +}, +{false}, +[0, [false, false, false]], false, 0] call CBA_fnc_addKeybind; // (empty default key) + +["ACE3 Equipment", QGVAR(RangeCardCopyDialogKey), localize "STR_ACE_RangeCard_RangeCardCopyDialogKey", +{ + // Conditions: canInteract, canShowCopy + if !([ACE_player, objNull, []] call EFUNC(common,canInteractWith)) exitWith {false}; + if (GVAR(RangeCardOpened)) exitWith { + closeDialog 0; + false + }; + if !(call FUNC(canShowCopy)) exitWith {false}; + // Statement + true call FUNC(openRangeCard); + true +}, +{false}, +[0, [false, false, false]], false, 0] call CBA_fnc_addKeybind; // (empty default key) \ No newline at end of file diff --git a/addons/rangecard/script_component.hpp b/addons/rangecard/script_component.hpp new file mode 100644 index 0000000000..8281f77eb3 --- /dev/null +++ b/addons/rangecard/script_component.hpp @@ -0,0 +1,12 @@ +#define COMPONENT rangecard +#include "\z\ace\addons\main\script_mod.hpp" + +#ifdef DEBUG_ENABLED_RANGECARD + #define DEBUG_MODE_FULL +#endif + +#ifdef DEBUG_SETTINGS_RANGECARD + #define DEBUG_SETTINGS DEBUG_SETTINGS_RANGECARD +#endif + +#include "\z\ace\addons\main\script_macros.hpp" diff --git a/addons/rangecard/stringtable.xml b/addons/rangecard/stringtable.xml new file mode 100644 index 0000000000..63bcbda13f --- /dev/null +++ b/addons/rangecard/stringtable.xml @@ -0,0 +1,26 @@ + + + + + Range Card + + + 50 METER increments -- MRAD/MRAD (reticle/turrets) + + + Open Range Card + + + Open Range Card Copy + + + Open Range Card + + + Open Range Card Copy + + + Copy Range Card + + + \ No newline at end of file From 4ad82d9629edf24d8614a62c8e785a076cce14cb Mon Sep 17 00:00:00 2001 From: ulteq Date: Thu, 28 May 2015 20:13:22 +0200 Subject: [PATCH 2/9] Switched to ctrlCreate to avoid aspect ratio problems with the listbox. --- addons/rangecard/XEH_postInit.sqf | 2 + .../functions/fnc_updateRangeCard.sqf | 94 +++++++++++++++---- 2 files changed, 77 insertions(+), 19 deletions(-) diff --git a/addons/rangecard/XEH_postInit.sqf b/addons/rangecard/XEH_postInit.sqf index 2b11b574e1..7d475c86f3 100644 --- a/addons/rangecard/XEH_postInit.sqf +++ b/addons/rangecard/XEH_postInit.sqf @@ -4,6 +4,8 @@ GVAR(RangeCardOpened) = false; +GVAR(controls) = []; + GVAR(ammoClass) = "B_65x39_Caseless"; GVAR(weaponClass) = "arifle_MXM_F"; diff --git a/addons/rangecard/functions/fnc_updateRangeCard.sqf b/addons/rangecard/functions/fnc_updateRangeCard.sqf index a01b82af91..fb0995e107 100644 --- a/addons/rangecard/functions/fnc_updateRangeCard.sqf +++ b/addons/rangecard/functions/fnc_updateRangeCard.sqf @@ -16,10 +16,64 @@ */ #include "script_component.hpp" +disableSerialization; +#define __dsp (uiNamespace getVariable "RangleCard_Display") + +private ["_airFriction", "_ammoConfig", "_atmosphereModel", "_barometricPressure", "_barrelLength", "_barrelTwist", "_bc", "_boreHeight", "_cacheEntry", "_column", "_control", "_dragModel", "_i", "_muzzleVelocity", "_mv", "_mvShift", "_offset", "_relativeHumidity", "_result", "_row", "_scopeBaseAngle", "_weaponConfig", "_zeroRange"]; + PARAMS_2(_ammoClass,_weaponClass); if (_ammoClass == "" || _weaponClass == "") exitWith {}; +{ + ctrlDelete _x; +} forEach GVAR(controls); +GVAR(controls) = []; + +for "_row" from 0 to 49 do { + _offset = if (_row < 5) then {0} else {0.003}; + _control = (__dsp ctrlCreate ["RangeCard_RscText", 790000 + _row]); + _control ctrlSetPosition [safeZoneX + 0.183, safeZoneY + 0.374 + 0.027 * _row + _offset, 0.062, 0.025]; + if (_row in [0, 8, 18, 28, 38, 48]) then { + _control ctrlSetTextColor [1, 1, 1, 1]; + } else { + _control ctrlSetTextColor [0, 0, 0, 1]; + }; + _control ctrlCommit 0; + _control ctrlSetText Str(100 + _row * 50); + GVAR(controls) pushBack _control; +}; +for "_column" from 0 to 8 do { + for "_row" from 0 to 49 do { + _offset = if (_row < 5) then {0} else {0.003}; + _control = (__dsp ctrlCreate ["RangeCard_RscText", 90000 + _column * 100 + _row]); + _control ctrlSetPosition [safeZoneX + 0.249 + _column * 0.055, safeZoneY + 0.374 + 0.027 * _row + _offset, 0.052, 0.025]; + _control ctrlCommit 0; + _control ctrlSetText "-0.0"; + GVAR(controls) pushBack _control; + }; +}; +for "_column" from 0 to 2 do { + for "_row" from 0 to 49 do { + _offset = if (_row < 5) then {0} else {0.003}; + _control = (__dsp ctrlCreate ["RangeCard_RscText", 90000 + (9 +_column) * 100 + _row]); + _control ctrlSetPosition [safeZoneX + 0.743 + _column * 0.049, safeZoneY + 0.374 + 0.027 * _row + _offset, 0.047, 0.025]; + _control ctrlCommit 0; + _control ctrlSetText "-0.0"; + GVAR(controls) pushBack _control; + }; +}; +for "_column" from 0 to 2 do { + for "_row" from 0 to 49 do { + _offset = if (_row < 5) then {0} else {0.003}; + _control = (__dsp ctrlCreate ["RangeCard_RscText", 90000 + (12 +_column) * 100 + _row]); + _control ctrlSetPosition [safeZoneX + 0.892 + _column * 0.049, safeZoneY + 0.374 + 0.027 * _row + _offset, 0.047, 0.025]; + _control ctrlCommit 0; + _control ctrlSetText "-0.0"; + GVAR(controls) pushBack _control; + }; +}; + lnbClear 770100; lnbClear 770200; lnbClear 770300; @@ -96,23 +150,25 @@ if (isNil {_cacheEntry}) then { lnbAddRow [770200, GVAR(rangeCardDataMVs)]; -for "_i" from 0 to 49 do { - lnbAddRow [770400, [Str(GVAR(rangeCardStartRange) + GVAR(rangeCardIncrement) * _i), (GVAR(rangeCardDataElevation) select 0) select _i, (GVAR(rangeCardDataElevation) select 1) select _i, (GVAR(rangeCardDataElevation) select 2) select _i, - (GVAR(rangeCardDataElevation) select 3) select _i, (GVAR(rangeCardDataElevation) select 4) select _i, (GVAR(rangeCardDataElevation) select 5) select _i, - (GVAR(rangeCardDataElevation) select 6) select _i, (GVAR(rangeCardDataElevation) select 7) select _i, (GVAR(rangeCardDataElevation) select 8) select _i, - (GVAR(rangeCardDataWindage) select 0) select _i, (GVAR(rangeCardDataWindage) select 3) select _i, (GVAR(rangeCardDataWindage) select 8) select _i, - (GVAR(rangeCardDataLead) select 0) select _i, (GVAR(rangeCardDataLead) select 3) select _i, (GVAR(rangeCardDataLead) select 8) select _i]]; -}; - -#define __dsp (uiNamespace getVariable "RangleCard_Display") -#define __ctrlListNBox (__dsp displayCtrl 770400) - -{ - __ctrlListNBox lnbSetColor [[_x, 0], [1, 1, 1, 1]]; -} forEach [0, 8, 18, 28, 38, 48]; - -{ - for "_i" from (GVAR(lastValidRow) select _x) to 49 do { - __ctrlListNBox lnbSetColor [[_i, _forEachIndex + 1], [0, 0, 0, 0.6]]; +for "_column" from 0 to 8 do { + for "_row" from 0 to 49 do { + _control = (__dsp displayCtrl (90000 + _column * 100 + _row)); + _control ctrlSetText ((GVAR(rangeCardDataElevation) select _column) select _row); + _control ctrlCommit 0; }; -} forEach [0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 3, 8, 0, 3, 8]; +}; +{ + for "_row" from 0 to 49 do { + _control = (__dsp displayCtrl (90000 + (9 + _forEachIndex) * 100 + _row)); + _control ctrlSetText ((GVAR(rangeCardDataWindage) select _x) select _row); + _control ctrlCommit 0; + }; +} forEach [0, 3, 8]; + +{ + for "_row" from 0 to 49 do { + _control = (__dsp displayCtrl (90000 + (12 + _forEachIndex) * 100 + _row)); + _control ctrlSetText ((GVAR(rangeCardDataLead) select _x) select _row); + _control ctrlCommit 0; + }; +} forEach [0, 3, 8]; From 01810b8723cdf9e09d80b99bc6d75918776cc9a6 Mon Sep 17 00:00:00 2001 From: ulteq Date: Fri, 29 May 2015 09:49:07 +0200 Subject: [PATCH 3/9] - Altitude is only taken into account when AB is enabled - Separate solution caches for Vanilla and AB ballistics --- addons/rangecard/functions/fnc_updateRangeCard.sqf | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/addons/rangecard/functions/fnc_updateRangeCard.sqf b/addons/rangecard/functions/fnc_updateRangeCard.sqf index fb0995e107..35a7552ef8 100644 --- a/addons/rangecard/functions/fnc_updateRangeCard.sqf +++ b/addons/rangecard/functions/fnc_updateRangeCard.sqf @@ -112,13 +112,16 @@ _atmosphereModel = _ammoConfig select 8; _boreHeight = 3.81; _zeroRange = 100; -_barometricPressure = EGVAR(weather,altitude) call EFUNC(weather,calculateBarometricPressure); +_barometricPressure = 1013.25; +if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { + _barometricPressure = EGVAR(weather,altitude) call EFUNC(weather,calculateBarometricPressure); +}; _relativeHumidity = 0.5; ctrlSetText [770001, format["Drop Tables for B.P.: %1mb; Corrected for MVV at Air/Ammo Temperatures -15-35 °C", round(_barometricPressure * 100) / 100]]; ctrlSetText [77004 , format["B.P.: %1mb", round(_barometricPressure * 100) / 100]]; -_cacheEntry = missionNamespace getVariable format[QGVAR(%1_%2), _ammoClass, _weaponClass]; +_cacheEntry = missionNamespace getVariable format[QGVAR(%1_%2_%3), _ammoClass, _weaponClass, missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]]; if (isNil {_cacheEntry}) then { { _mvShift = [_ammoConfig select 9, _x] call EFUNC(advanced_ballistics,calculateAmmoTemperatureVelocityShift); @@ -139,7 +142,7 @@ if (isNil {_cacheEntry}) then { }; }; - missionNamespace setVariable [format[QGVAR(%1_%2), _ammoClass, _weaponClass], [GVAR(rangeCardDataElevation), GVAR(rangeCardDataWindage), GVAR(rangeCardDataLead), GVAR(rangeCardDataMVs), GVAR(lastValidRow)]]; + missionNamespace setVariable [format[QGVAR(%1_%2_%3), _ammoClass, _weaponClass, missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]], [GVAR(rangeCardDataElevation), GVAR(rangeCardDataWindage), GVAR(rangeCardDataLead), GVAR(rangeCardDataMVs), GVAR(lastValidRow)]]; } else { GVAR(rangeCardDataElevation) = _cacheEntry select 0; GVAR(rangeCardDataWindage) = _cacheEntry select 1; From ade2cc1c56bda34683cf23b81d89c960f625e7af Mon Sep 17 00:00:00 2001 From: ulteq Date: Fri, 29 May 2015 12:55:16 +0200 Subject: [PATCH 4/9] Refined the reference barometric pressure calculation --- addons/rangecard/functions/fnc_updateRangeCard.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/rangecard/functions/fnc_updateRangeCard.sqf b/addons/rangecard/functions/fnc_updateRangeCard.sqf index 35a7552ef8..9f828157bf 100644 --- a/addons/rangecard/functions/fnc_updateRangeCard.sqf +++ b/addons/rangecard/functions/fnc_updateRangeCard.sqf @@ -114,7 +114,7 @@ _zeroRange = 100; _barometricPressure = 1013.25; if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { - _barometricPressure = EGVAR(weather,altitude) call EFUNC(weather,calculateBarometricPressure); + _barometricPressure = 1013.25 * (1 - (0.0065 * EGVAR(weather,altitude)) / 288.15) ^ 5.255754495; }; _relativeHumidity = 0.5; From a5a96052b82657e9fae00f14d67216ffb62ce2a6 Mon Sep 17 00:00:00 2001 From: ulteq Date: Fri, 29 May 2015 13:34:34 +0200 Subject: [PATCH 5/9] Made use of the newly implemented speed of sound calculation --- addons/rangecard/functions/fnc_calculateSolution.sqf | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/addons/rangecard/functions/fnc_calculateSolution.sqf b/addons/rangecard/functions/fnc_calculateSolution.sqf index 68189ac36b..f92d8eccb9 100644 --- a/addons/rangecard/functions/fnc_calculateSolution.sqf +++ b/addons/rangecard/functions/fnc_calculateSolution.sqf @@ -44,7 +44,7 @@ */ #include "script_component.hpp" -private ["_scopeBaseAngle", "_bulletMass", "_boreHeight", "_airFriction", "_muzzleVelocity", "_temperature", "_barometricPressure", "_relativeHumidity", "_simSteps", "_windSpeed1", "_windSpeed2", "_windDirection", "_inclinationAngle", "_targetSpeed", "_targetRange", "_drag", "_bc", "_dragModel", "_atmosphereModel", "_storeRangeCardData", "_stabilityFactor", "_twistDirection", "_latitude", "_directionOfFire", "_rangeCardSlot"]; +private ["_scopeBaseAngle", "_bulletMass", "_boreHeight", "_airFriction", "_muzzleVelocity", "_temperature", "_barometricPressure", "_relativeHumidity", "_simSteps", "_windSpeed1", "_windSpeed2", "_windDirection", "_inclinationAngle", "_targetSpeed", "_targetRange", "_drag", "_bc", "_dragModel", "_atmosphereModel", "_storeRangeCardData", "_stabilityFactor", "_twistDirection", "_latitude", "_directionOfFire", "_rangeCardSlot", "_speedOfSound"]; _scopeBaseAngle = _this select 0; _bulletMass = _this select 1; _boreHeight = _this select 2; @@ -136,6 +136,8 @@ _bulletVelocity set [0, 0]; _bulletVelocity set [1, Cos(_scopeBaseAngle) * _muzzleVelocity]; _bulletVelocity set [2, Sin(_scopeBaseAngle) * _muzzleVelocity]; +_speedOfSound = _temperature call EFUNC(weather,calculateSpeedOfSound); + while {_TOF < 6 && (_bulletPos select 1) < _targetRange} do { _bulletSpeed = vectorMagnitude _bulletVelocity; @@ -143,7 +145,7 @@ while {_TOF < 6 && (_bulletPos select 1) < _targetRange} do { _stepsTotal = _stepsTotal + 1; _speedAverage = (_speedTotal / _stepsTotal); - if (_speedAverage > 400 && _bulletSpeed < 340) exitWith {}; + if (_speedAverage > 400 && _bulletSpeed < _speedOfSound) exitWith {}; if (atan((_bulletPos select 2) / (abs(_bulletPos select 1) + 1)) < -2.25) exitWith {}; _trueVelocity = _bulletVelocity vectorDiff _wind1; From 6d1e8eebce959e7fbe867f6c5530f3245cb918ba Mon Sep 17 00:00:00 2001 From: ulteq Date: Fri, 29 May 2015 15:07:30 +0200 Subject: [PATCH 6/9] Reworked the range card output when AB is disabled --- addons/rangecard/XEH_postInit.sqf | 2 + .../functions/fnc_calculateSolution.sqf | 14 +-- addons/rangecard/functions/fnc_canShow.sqf | 2 +- .../rangecard/functions/fnc_canShowCopy.sqf | 2 +- .../rangecard/functions/fnc_openRangeCard.sqf | 6 +- .../functions/fnc_updateClassNames.sqf | 22 +++-- .../functions/fnc_updateRangeCard.sqf | 97 ++++++++++++++----- 7 files changed, 101 insertions(+), 44 deletions(-) diff --git a/addons/rangecard/XEH_postInit.sqf b/addons/rangecard/XEH_postInit.sqf index 7d475c86f3..8396d76b39 100644 --- a/addons/rangecard/XEH_postInit.sqf +++ b/addons/rangecard/XEH_postInit.sqf @@ -7,7 +7,9 @@ GVAR(RangeCardOpened) = false; GVAR(controls) = []; GVAR(ammoClass) = "B_65x39_Caseless"; +GVAR(magazineClass) = "30Rnd_65x39_caseless_mag"; GVAR(weaponClass) = "arifle_MXM_F"; GVAR(ammoClassCopy) = "";//"ACE_762x51_Ball_M118LR"; +GVAR(magazineClassCopy) = "";//"ACE_20Rnd_762x51_M118LR_Mag"; GVAR(weaponClassCopy) = "";//srifle_DMR_06_olive_F"; diff --git a/addons/rangecard/functions/fnc_calculateSolution.sqf b/addons/rangecard/functions/fnc_calculateSolution.sqf index f92d8eccb9..3a171c4517 100644 --- a/addons/rangecard/functions/fnc_calculateSolution.sqf +++ b/addons/rangecard/functions/fnc_calculateSolution.sqf @@ -44,7 +44,7 @@ */ #include "script_component.hpp" -private ["_scopeBaseAngle", "_bulletMass", "_boreHeight", "_airFriction", "_muzzleVelocity", "_temperature", "_barometricPressure", "_relativeHumidity", "_simSteps", "_windSpeed1", "_windSpeed2", "_windDirection", "_inclinationAngle", "_targetSpeed", "_targetRange", "_drag", "_bc", "_dragModel", "_atmosphereModel", "_storeRangeCardData", "_stabilityFactor", "_twistDirection", "_latitude", "_directionOfFire", "_rangeCardSlot", "_speedOfSound"]; +private ["_scopeBaseAngle", "_bulletMass", "_boreHeight", "_airFriction", "_muzzleVelocity", "_temperature", "_barometricPressure", "_relativeHumidity", "_simSteps", "_windSpeed1", "_windSpeed2", "_windDirection", "_inclinationAngle", "_targetSpeed", "_targetRange", "_drag", "_bc", "_dragModel", "_atmosphereModel", "_storeRangeCardData", "_stabilityFactor", "_twistDirection", "_latitude", "_directionOfFire", "_rangeCardSlot"]; _scopeBaseAngle = _this select 0; _bulletMass = _this select 1; _boreHeight = _this select 2; @@ -71,16 +71,20 @@ _directionOfFire = _this select 21; _rangeCardSlot = _this select 22; if (_storeRangeCardData) then { - GVAR(rangeCardDataMVs) pushBack format[" %1", round(_muzzleVelocity)]; + GVAR(rangeCardDataMVs) set [_rangeCardSlot, format[" %1", round(_muzzleVelocity)]]; }; -private ["_bulletPos", "_bulletVelocity", "_bulletAccel", "_bulletSpeed", "_gravity", "_deltaT"]; +private ["_bulletPos", "_bulletVelocity", "_bulletAccel", "_bulletSpeed", "_gravity", "_deltaT", "_speedOfSound"]; _bulletPos = [0, 0, 0]; _bulletVelocity = [0, 0, 0]; _bulletAccel = [0, 0, 0]; _bulletSpeed = 0; _gravity = [0, sin(_scopeBaseAngle + _inclinationAngle) * -9.80665, cos(_scopeBaseAngle + _inclinationAngle) * -9.80665]; _deltaT = 1 / _simSteps; +_speedOfSound = 0; +if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { + _speedOfSound = _temperature call EFUNC(weather,calculateSpeedOfSound); +}; private ["_elevation", "_windage1", "_windage2", "_lead", "_TOF", "_trueVelocity", "_trueSpeed", "_kineticEnergy", "_verticalCoriolis", "_verticalDeflection", "_horizontalCoriolis", "_horizontalDeflection", "_spinDrift", "_spinDeflection"]; _elevation = 0; @@ -136,8 +140,6 @@ _bulletVelocity set [0, 0]; _bulletVelocity set [1, Cos(_scopeBaseAngle) * _muzzleVelocity]; _bulletVelocity set [2, Sin(_scopeBaseAngle) * _muzzleVelocity]; -_speedOfSound = _temperature call EFUNC(weather,calculateSpeedOfSound); - while {_TOF < 6 && (_bulletPos select 1) < _targetRange} do { _bulletSpeed = vectorMagnitude _bulletVelocity; @@ -146,7 +148,7 @@ while {_TOF < 6 && (_bulletPos select 1) < _targetRange} do { _speedAverage = (_speedTotal / _stepsTotal); if (_speedAverage > 400 && _bulletSpeed < _speedOfSound) exitWith {}; - if (atan((_bulletPos select 2) / (abs(_bulletPos select 1) + 1)) < -2.25) exitWith {}; + if (atan((_bulletPos select 2) / (abs(_bulletPos select 1) + 1)) < -2.254) exitWith {}; _trueVelocity = _bulletVelocity vectorDiff _wind1; _trueSpeed = vectorMagnitude _trueVelocity; diff --git a/addons/rangecard/functions/fnc_canShow.sqf b/addons/rangecard/functions/fnc_canShow.sqf index d069048acb..f7450e10e3 100644 --- a/addons/rangecard/functions/fnc_canShow.sqf +++ b/addons/rangecard/functions/fnc_canShow.sqf @@ -15,4 +15,4 @@ */ #include "script_component.hpp" -(GVAR(ammoClass) != "" && GVAR(weaponClass) != "" && !GVAR(RangeCardOpened) && !(underwater ACE_player) && ("ACE_RangeCard" in (uniformItems ACE_player)) || ("ACE_RangeCard" in (vestItems ACE_player))) +(GVAR(ammoClass) != "" && GVAR(magazineClass) != "" && GVAR(weaponClass) != "" && !GVAR(RangeCardOpened) && !(underwater ACE_player) && ("ACE_RangeCard" in (uniformItems ACE_player)) || ("ACE_RangeCard" in (vestItems ACE_player))) diff --git a/addons/rangecard/functions/fnc_canShowCopy.sqf b/addons/rangecard/functions/fnc_canShowCopy.sqf index 1dd1318764..49fd891953 100644 --- a/addons/rangecard/functions/fnc_canShowCopy.sqf +++ b/addons/rangecard/functions/fnc_canShowCopy.sqf @@ -15,4 +15,4 @@ */ #include "script_component.hpp" -(GVAR(ammoClassCopy) != "" && GVAR(weaponClassCopy) != "" && !GVAR(RangeCardOpened) && !(underwater ACE_player) && ("ACE_RangeCard" in (uniformItems ACE_player)) || ("ACE_RangeCard" in (vestItems ACE_player))) +(GVAR(ammoClassCopy) != "" && GVAR(magazineClassCopy) != "" && GVAR(weaponClassCopy) != "" && !GVAR(RangeCardOpened) && !(underwater ACE_player) && ("ACE_RangeCard" in (uniformItems ACE_player)) || ("ACE_RangeCard" in (vestItems ACE_player))) diff --git a/addons/rangecard/functions/fnc_openRangeCard.sqf b/addons/rangecard/functions/fnc_openRangeCard.sqf index 2c59ef1da1..3e886eb97a 100644 --- a/addons/rangecard/functions/fnc_openRangeCard.sqf +++ b/addons/rangecard/functions/fnc_openRangeCard.sqf @@ -18,12 +18,12 @@ if (GVAR(RangeCardOpened)) exitWith {}; if (_this) then { - if (GVAR(ammoClassCopy) != "" && GVAR(weaponClassCopy) != "") then { + if (GVAR(ammoClassCopy) != "" && GVAR(magazineClassCopy) != "" && GVAR(weaponClassCopy) != "") then { GVAR(RangeCardOpened) = true; createDialog "ACE_RangeCard_Dialog"; - [GVAR(ammoClassCopy), GVAR(weaponClassCopy)] call FUNC(updateRangeCard); + [GVAR(ammoClassCopy), GVAR(magazineClassCopy), GVAR(weaponClassCopy)] call FUNC(updateRangeCard); }; } else { if (ACE_player call FUNC(updateClassNames)) then { @@ -31,6 +31,6 @@ if (_this) then { createDialog "ACE_RangeCard_Dialog"; - [GVAR(ammoClass), GVAR(weaponClass)] call FUNC(updateRangeCard); + [GVAR(ammoClass), GVAR(magazineClass), GVAR(weaponClass)] call FUNC(updateRangeCard); }; }; diff --git a/addons/rangecard/functions/fnc_updateClassNames.sqf b/addons/rangecard/functions/fnc_updateClassNames.sqf index 203b2db926..70cf25825e 100644 --- a/addons/rangecard/functions/fnc_updateClassNames.sqf +++ b/addons/rangecard/functions/fnc_updateClassNames.sqf @@ -15,29 +15,35 @@ */ #include "script_component.hpp" -private ["_unit", "_ammoClass", "_weaponClass", "_ammo", "_ammoConfig", "_parentClasses"]; +private ["_unit", "_ammoClass", "_magazineClass", "_weaponClass", "_ammo", "_ammoConfig", "_parentClasses"]; _unit = _this; _ammoClass = ""; +_magazineClass = ""; _weaponClass = primaryWeapon _unit; -if (_weaponClass == "") exitWith { (GVAR(ammoClass) != "" && GVAR(weaponClass) != "") }; +if (_weaponClass == "") exitWith { (GVAR(ammoClass) != "" && GVAR(magazineClass) != "" && GVAR(weaponClass) != "") }; { _ammo = getText (configFile >> "CfgMagazines" >> _x >> "ammo"); _ammoConfig = (configFile >> "CfgAmmo" >> _ammo); _parentClasses = [_ammoConfig, true] call BIS_fnc_returnParents; - if ("BulletBase" in _parentClasses) exitWith { _ammoClass = _ammo; }; + if ("BulletBase" in _parentClasses) exitWith { + _ammoClass = _ammo; + _magazineClass = _x; + }; } forEach (primaryWeaponMagazine _unit); -if (_ammoClass == "") exitWith { (GVAR(ammoClass) != "" && GVAR(weaponClass) != "") }; +if (_ammoClass == "") exitWith { (GVAR(ammoClass) != "" && GVAR(magazineClass) != "" && GVAR(weaponClass) != "") }; if (_unit == ACE_player) then { - GVAR(ammoClass) = _ammoClass; - GVAR(weaponClass) = _weaponClass; + GVAR(ammoClass) = _ammoClass; + GVAR(magazineClass) = _magazineClass; + GVAR(weaponClass) = _weaponClass; } else { - GVAR(ammoClassCopy) = _ammoClass; - GVAR(weaponClassCopy) = _weaponClass; + GVAR(ammoClassCopy) = _ammoClass; + GVAR(magazineClassCopy) = _magazineClass; + GVAR(weaponClassCopy) = _weaponClass; }; true diff --git a/addons/rangecard/functions/fnc_updateRangeCard.sqf b/addons/rangecard/functions/fnc_updateRangeCard.sqf index 9f828157bf..c33587a185 100644 --- a/addons/rangecard/functions/fnc_updateRangeCard.sqf +++ b/addons/rangecard/functions/fnc_updateRangeCard.sqf @@ -4,7 +4,8 @@ * * Arguments: * 0: ammo class - * 1: weapon class + * 1: magazine class + * 2: weapon class * * Return Value: * Nothing @@ -19,11 +20,11 @@ disableSerialization; #define __dsp (uiNamespace getVariable "RangleCard_Display") -private ["_airFriction", "_ammoConfig", "_atmosphereModel", "_barometricPressure", "_barrelLength", "_barrelTwist", "_bc", "_boreHeight", "_cacheEntry", "_column", "_control", "_dragModel", "_i", "_muzzleVelocity", "_mv", "_mvShift", "_offset", "_relativeHumidity", "_result", "_row", "_scopeBaseAngle", "_weaponConfig", "_zeroRange"]; +private ["_airFriction", "_ammoConfig", "_atmosphereModel", "_barometricPressure", "_barrelLength", "_barrelTwist", "_bc", "_boreHeight", "_cacheEntry", "_column", "_control", "_dragModel", "_i", "_muzzleVelocity", "_mv", "_mvShift", "_offset", "_relativeHumidity", "_result", "_row", "_scopeBaseAngle", "_weaponConfig", "_zeroRange", "_initSpeed", "_initSpeedCoef"]; -PARAMS_2(_ammoClass,_weaponClass); +PARAMS_3(_ammoClass,_magazineClass,_weaponClass); -if (_ammoClass == "" || _weaponClass == "") exitWith {}; +if (_ammoClass == "" || _magazineClass == "" || _weaponClass == "") exitWith {}; { ctrlDelete _x; @@ -45,7 +46,7 @@ for "_row" from 0 to 49 do { }; for "_column" from 0 to 8 do { for "_row" from 0 to 49 do { - _offset = if (_row < 5) then {0} else {0.003}; + _offset = if (_row < 5) then {0} else {0.003}; _control = (__dsp ctrlCreate ["RangeCard_RscText", 90000 + _column * 100 + _row]); _control ctrlSetPosition [safeZoneX + 0.249 + _column * 0.055, safeZoneY + 0.374 + 0.027 * _row + _offset, 0.052, 0.025]; _control ctrlCommit 0; @@ -80,15 +81,17 @@ lnbClear 770300; lnbClear 770400; lnbAddRow [770100, ["4mps Wind(MRADs)", "1mps LEAD(MRADs)"]]; -lnbAddRow [770100, ["Air/Ammo Temp", "Air/Ammo Temp"]]; +if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { + lnbAddRow [770100, ["Air/Ammo Temp", "Air/Ammo Temp"]]; -lnbAddRow [770200, ["-15°C", " -5°C", " 5°C", " 10°C", " 15°C", " 20°C", " 25°C", " 30°C", " 35°C"]]; -lnbAddRow [770300, ["-15°C", " 10°C", " 35°C", "-15°C", " 10°C", " 35°C"]]; + lnbAddRow [770200, ["-15°C", " -5°C", " 5°C", " 10°C", " 15°C", " 20°C", " 25°C", " 30°C", " 35°C"]]; + lnbAddRow [770300, ["-15°C", " 10°C", " 35°C", "-15°C", " 10°C", " 35°C"]]; +}; GVAR(rangeCardDataElevation) = [[], [], [], [], [], [], [], [], []]; GVAR(rangeCardDataWindage) = [[], [], [], [], [], [], [], [], []]; GVAR(rangeCardDataLead) = [[], [], [], [], [], [], [], [], []]; -GVAR(rangeCardDataMVs) = []; +GVAR(rangeCardDataMVs) = ["", "", "", "", "", "", "", "", ""]; GVAR(lastValidRow) = []; GVAR(currentUnit) = 2; @@ -101,10 +104,28 @@ _weaponConfig = _weaponClass call EFUNC(advanced_ballistics,readWeaponDataFromCo _airFriction = _ammoConfig select 0; _barrelTwist = _weaponConfig select 0; _barrelLength = _weaponConfig select 2; -_muzzleVelocity = [_barrelLength, _ammoConfig select 10, _ammoConfig select 11, 0] call EFUNC(advanced_ballistics,calculateBarrelLengthVelocityShift); +_muzzleVelocity = 0; +if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { + _muzzleVelocity = [_barrelLength, _ammoConfig select 10, _ammoConfig select 11, 0] call EFUNC(advanced_ballistics,calculateBarrelLengthVelocityShift); +} else { + _initSpeed = getNumber (configFile >> "CfgMagazines" >> _magazineClass >> "initSpeed"); + _initSpeedCoef = getNumber (configFile >> "CfgWeapons" >> _weaponClass >> "initSpeed"); + if (_initSpeedCoef < 0) then { + _initSpeed = _initSpeed * -_initSpeedCoef; + }; + if (_initSpeedCoef > 0) then { + _initSpeed = _initSpeedCoef; + }; + _muzzleVelocity = _initSpeed; +}; -ctrlSetText [770000, format["%1'' - %2 gr (%3)", round((_ammoConfig select 1) * 39.3700787) / 1000, round((_ammoConfig select 3) * 15.4323584), _ammoClass]]; -ctrlSetText [770002, format["Barrel: %1'' 1:%2'' twist", round(_barrelLength * 0.0393700787), round(_barrelTwist * 0.0393700787)]]; +if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { + ctrlSetText [770000, format["%1'' - %2 gr (%3)", round((_ammoConfig select 1) * 39.3700787) / 1000, round((_ammoConfig select 3) * 15.4323584), _ammoClass]]; + ctrlSetText [770002, format["Barrel: %1'' 1:%2'' twist", round(_barrelLength * 0.0393700787), round(_barrelTwist * 0.0393700787)]]; +} else { + ctrlSetText [770000, getText (configFile >> "CfgMagazines" >> _magazineClass >> "displayNameShort")]; + ctrlSetText [770002, ""]; +}; _bc = (_ammoConfig select 6) select 0; _dragModel = _ammoConfig select 5; @@ -118,27 +139,45 @@ if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) t }; _relativeHumidity = 0.5; -ctrlSetText [770001, format["Drop Tables for B.P.: %1mb; Corrected for MVV at Air/Ammo Temperatures -15-35 °C", round(_barometricPressure * 100) / 100]]; -ctrlSetText [77004 , format["B.P.: %1mb", round(_barometricPressure * 100) / 100]]; +if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { + ctrlSetText [770001, format["Drop Tables for B.P.: %1mb; Corrected for MVV at Air/Ammo Temperatures -15-35 °C", round(_barometricPressure * 100) / 100]]; + ctrlSetText [77004 , format["B.P.: %1mb", round(_barometricPressure * 100) / 100]]; +} else { + ctrlSetText [770001, getText (configFile >> "CfgWeapons" >> _weaponClass >> "displayName")]; + ctrlSetText [77004 , ""]; +}; _cacheEntry = missionNamespace getVariable format[QGVAR(%1_%2_%3), _ammoClass, _weaponClass, missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]]; if (isNil {_cacheEntry}) then { - { - _mvShift = [_ammoConfig select 9, _x] call EFUNC(advanced_ballistics,calculateAmmoTemperatureVelocityShift); - _mv = _muzzleVelocity + _mvShift; - - _result = [0, 0, _boreHeight, _airFriction, _mv, _x, 1013.25, 0.5, 1000, [0, 0], 0, 0, 0, _zeroRange, _bc, _dragModel, _atmosphereModel, false, 1.5, 0, 0, 0] call FUNC(calculateSolution); + if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { + { + _mvShift = [_ammoConfig select 9, _x] call EFUNC(advanced_ballistics,calculateAmmoTemperatureVelocityShift); + _mv = _muzzleVelocity + _mvShift; + + _result = [0, 0, _boreHeight, _airFriction, _mv, _x, 1013.25, 0.5, 1000, [0, 0], 0, 0, 0, _zeroRange, _bc, _dragModel, _atmosphereModel, false, 1.5, 0, 0, 0] call FUNC(calculateSolution); + _scopeBaseAngle = (_result select 0) / 60; + + [_scopeBaseAngle,27,_boreHeight,_airFriction,_mv,_x,_barometricPressure,_relativeHumidity,1000,[4,0],3,0,1,GVAR(rangeCardEndRange),_bc,_dragModel,_atmosphereModel,true,1.5,1,46,23,_forEachIndex] call FUNC(calculateSolution); + } forEach [-15, -5, 5, 10, 15, 20, 25, 30, 35]; + } else { + _result = [0, 0, _boreHeight, _airFriction, _muzzleVelocity, _x, 1013.25, 0.5, 1000, [0, 0], 0, 0, 0, _zeroRange, _bc, _dragModel, _atmosphereModel, false, 1.5, 0, 0, 0] call FUNC(calculateSolution); _scopeBaseAngle = (_result select 0) / 60; - [_scopeBaseAngle,27,_boreHeight,_airFriction,_mv,_x,_barometricPressure,_relativeHumidity,1000,[4,0],3,0,4,GVAR(rangeCardEndRange),_bc,_dragModel,_atmosphereModel,true,1.5,1,46,23,_forEachIndex] call FUNC(calculateSolution); - } forEach [-15, -5, 5, 10, 15, 20, 25, 30, 35]; - + [_scopeBaseAngle,27,_boreHeight,_airFriction,_muzzleVelocity,_x,_barometricPressure,_relativeHumidity,1000,[4,0],3,0,1,GVAR(rangeCardEndRange),_bc,_dragModel,_atmosphereModel,true,1.5,1,46,23,3] call FUNC(calculateSolution); + }; + for "_i" from 0 to 9 do { GVAR(lastValidRow) pushBack count (GVAR(rangeCardDataElevation) select _i); while {count (GVAR(rangeCardDataElevation) select _i) < 50} do { - (GVAR(rangeCardDataElevation) select _i) pushBack "###"; - (GVAR(rangeCardDataWindage) select _i) pushBack "##"; - (GVAR(rangeCardDataLead) select _i) pushBack "##"; + if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { + (GVAR(rangeCardDataElevation) select _i) pushBack "###"; + (GVAR(rangeCardDataWindage) select _i) pushBack "##"; + (GVAR(rangeCardDataLead) select _i) pushBack "##"; + } else { + (GVAR(rangeCardDataElevation) select _i) pushBack ""; + (GVAR(rangeCardDataWindage) select _i) pushBack ""; + (GVAR(rangeCardDataLead) select _i) pushBack ""; + }; }; }; @@ -175,3 +214,11 @@ for "_column" from 0 to 8 do { _control ctrlCommit 0; }; } forEach [0, 3, 8]; + +if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { + ctrlSetText [770020, "For best results keep ammunition at ambient air temperature. Tables calculated for the above listed barrel"]; + ctrlSetText [770021, "and load with optic mounted 1.5'' above line of bore."]; +} else { + ctrlSetText [770020, ""]; + ctrlSetText [770021, ""]; +}; \ No newline at end of file From d0e1af6e47a8515b61ee48dd871925999b86c6c9 Mon Sep 17 00:00:00 2001 From: ulteq Date: Fri, 29 May 2015 19:39:54 +0200 Subject: [PATCH 7/9] Improved missing config error handling --- .../functions/fnc_updateRangeCard.sqf | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/addons/rangecard/functions/fnc_updateRangeCard.sqf b/addons/rangecard/functions/fnc_updateRangeCard.sqf index c33587a185..d58e7ff6bb 100644 --- a/addons/rangecard/functions/fnc_updateRangeCard.sqf +++ b/addons/rangecard/functions/fnc_updateRangeCard.sqf @@ -105,7 +105,7 @@ _airFriction = _ammoConfig select 0; _barrelTwist = _weaponConfig select 0; _barrelLength = _weaponConfig select 2; _muzzleVelocity = 0; -if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { +if (_barrelLength > 0 && missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { _muzzleVelocity = [_barrelLength, _ammoConfig select 10, _ammoConfig select 11, 0] call EFUNC(advanced_ballistics,calculateBarrelLengthVelocityShift); } else { _initSpeed = getNumber (configFile >> "CfgMagazines" >> _magazineClass >> "initSpeed"); @@ -121,7 +121,11 @@ if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) t if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { ctrlSetText [770000, format["%1'' - %2 gr (%3)", round((_ammoConfig select 1) * 39.3700787) / 1000, round((_ammoConfig select 3) * 15.4323584), _ammoClass]]; - ctrlSetText [770002, format["Barrel: %1'' 1:%2'' twist", round(_barrelLength * 0.0393700787), round(_barrelTwist * 0.0393700787)]]; + if (_barrelLength > 0 && _barrelTwist > 0) then { + ctrlSetText [770002, format["Barrel: %1'' 1:%2'' twist", round(_barrelLength * 0.0393700787), round(_barrelTwist * 0.0393700787)]]; + } else { + ctrlSetText [770002, ""]; + }; } else { ctrlSetText [770000, getText (configFile >> "CfgMagazines" >> _magazineClass >> "displayNameShort")]; ctrlSetText [770002, ""]; @@ -196,6 +200,11 @@ for "_column" from 0 to 8 do { for "_row" from 0 to 49 do { _control = (__dsp displayCtrl (90000 + _column * 100 + _row)); _control ctrlSetText ((GVAR(rangeCardDataElevation) select _column) select _row); + if (_row >= (GVAR(lastValidRow) select _column)) then { + _control ctrlSetTextColor [0, 0, 0, 0.6]; + } else { + _control ctrlSetTextColor [0, 0, 0, 1.0]; + }; _control ctrlCommit 0; }; }; @@ -203,6 +212,11 @@ for "_column" from 0 to 8 do { for "_row" from 0 to 49 do { _control = (__dsp displayCtrl (90000 + (9 + _forEachIndex) * 100 + _row)); _control ctrlSetText ((GVAR(rangeCardDataWindage) select _x) select _row); + if (_row >= (GVAR(lastValidRow) select _x)) then { + _control ctrlSetTextColor [0, 0, 0, 0.6]; + } else { + _control ctrlSetTextColor [0, 0, 0, 1.0]; + }; _control ctrlCommit 0; }; } forEach [0, 3, 8]; @@ -211,6 +225,11 @@ for "_column" from 0 to 8 do { for "_row" from 0 to 49 do { _control = (__dsp displayCtrl (90000 + (12 + _forEachIndex) * 100 + _row)); _control ctrlSetText ((GVAR(rangeCardDataLead) select _x) select _row); + if (_row >= (GVAR(lastValidRow) select _x)) then { + _control ctrlSetTextColor [0, 0, 0, 0.6]; + } else { + _control ctrlSetTextColor [0, 0, 0, 1.0]; + }; _control ctrlCommit 0; }; } forEach [0, 3, 8]; From 65b9e67991f545e41a4806b37d898d86ebf20dd7 Mon Sep 17 00:00:00 2001 From: ulteq Date: Fri, 29 May 2015 20:11:07 +0200 Subject: [PATCH 8/9] Refined the abort condition for the range card calculation --- addons/rangecard/functions/fnc_calculateSolution.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/rangecard/functions/fnc_calculateSolution.sqf b/addons/rangecard/functions/fnc_calculateSolution.sqf index 3a171c4517..baaaf8506a 100644 --- a/addons/rangecard/functions/fnc_calculateSolution.sqf +++ b/addons/rangecard/functions/fnc_calculateSolution.sqf @@ -147,7 +147,7 @@ while {_TOF < 6 && (_bulletPos select 1) < _targetRange} do { _stepsTotal = _stepsTotal + 1; _speedAverage = (_speedTotal / _stepsTotal); - if (_speedAverage > 400 && _bulletSpeed < _speedOfSound) exitWith {}; + if (_speedAverage > 450 && _bulletSpeed < _speedOfSound) exitWith {}; if (atan((_bulletPos select 2) / (abs(_bulletPos select 1) + 1)) < -2.254) exitWith {}; _trueVelocity = _bulletVelocity vectorDiff _wind1; From a57d8486ca23ed955fc5240ae9d7e84d37dc5572 Mon Sep 17 00:00:00 2001 From: ulteq Date: Fri, 29 May 2015 20:51:20 +0200 Subject: [PATCH 9/9] Removed some unneeded code --- .../functions/fnc_calculateSolution.sqf | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/addons/rangecard/functions/fnc_calculateSolution.sqf b/addons/rangecard/functions/fnc_calculateSolution.sqf index baaaf8506a..d8f0fe0cac 100644 --- a/addons/rangecard/functions/fnc_calculateSolution.sqf +++ b/addons/rangecard/functions/fnc_calculateSolution.sqf @@ -101,15 +101,9 @@ _horizontalDeflection = 0; _spinDrift = 0; _spinDeflection = 0; -private ["_n", "_range", "_rangeFactor"]; +private ["_n", "_range"]; _n = 0; _range = 0; -_rangeFactor = 1; -if (_storeRangeCardData) then { - if (GVAR(currentUnit) == 1) then { - _rangeFactor = 1.0936133; - }; -}; private ["_wind1", "_wind2", "_windDrift"]; _wind1 = [cos(270 - _windDirection * 30) * _windSpeed1, sin(270 - _windDirection * 30) * _windSpeed1, 0]; @@ -124,14 +118,6 @@ _speedTotal = 0; _stepsTotal = 0; _speedAverage = 0; -private ["_eoetvoesMultiplier"]; -_eoetvoesMultiplier = 0; -if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { - _eoetvoesMultiplier = 2 * (0.0000729 * _muzzleVelocity / -9.80665) * cos(_latitude) * sin(_directionOfFire); -}; - -_TOF = 0; - _bulletPos set [0, 0]; _bulletPos set [1, 0]; _bulletPos set [2, -(_boreHeight / 100)]; @@ -173,7 +159,7 @@ while {_TOF < 6 && (_bulletPos select 1) < _targetRange} do { if (_storeRangeCardData) then { _range = GVAR(rangeCardStartRange) + _n * GVAR(rangeCardIncrement); - if ((_bulletPos select 1) * _rangeFactor >= _range && _range <= GVAR(rangeCardEndRange)) then { + if ((_bulletPos select 1) >= _range && _range <= GVAR(rangeCardEndRange)) then { if ((_bulletPos select 1) > 0) then { _elevation = - atan((_bulletPos select 2) / (_bulletPos select 1)); _windage1 = - atan((_bulletPos select 0) / (_bulletPos select 1));