diff --git a/addons/common/XEH_PREP.hpp b/addons/common/XEH_PREP.hpp index ab9756c95e..02eca6d441 100644 --- a/addons/common/XEH_PREP.hpp +++ b/addons/common/XEH_PREP.hpp @@ -143,6 +143,7 @@ PREP(removeSpecificMagazine); PREP(requestCallback); PREP(resetAllDefaults); PREP(restoreVariablesJIP); +PREP(rscObjectHelper); PREP(runAfterSettingsInit); PREP(runTests); PREP(sanitizeString); diff --git a/addons/common/functions/fnc_rscObjectHelper.sqf b/addons/common/functions/fnc_rscObjectHelper.sqf new file mode 100644 index 0000000000..81eb707b3a --- /dev/null +++ b/addons/common/functions/fnc_rscObjectHelper.sqf @@ -0,0 +1,64 @@ +#include "script_component.hpp" +/* + * Author: PabstMirror + * Convert between screen and 3d object coordinates + * + * Arguments: + * 0: Function + * 1: Input array + * 2: Scale (optional: 1) + * + * Return Value: + * Value + * + * Example: + * ["2d", [0,0,0], 1] call ace_common_fnc_rscObjectHelper + * + * Public: Maybe + */ + +params ["_func", "_array", ["_scale", 1]]; + +private _adjustCam = 1; +private _topFOV = getResolution # 6; +private _leftFOV = getResolution # 7; + +private _topLeftX = (_leftFOV-1)*0.5/_leftFOV; +private _bottomRightX = 1-_topLeftX; +private _topLeftY = 0; +private _bottomRightY = 1; + +private _return = []; + +switch (toLower _func) do { + case ("2d"): { + _array params ["_pointX", "_z", "_pointY"]; + + private _scrX = _pointX * (_bottomRightX - _topLeftX) + _topLeftX; + private _vX = _leftFOV * (_scrX - 0.5) * _adjustCam * _z; + + private _scrY = _pointY * (_bottomRightY - _topLeftY) + _topLeftY; + private _vY = _topFOV * (0.5 - _scrY) * _adjustCam * _z; + + _vX = _vX / _scale; + _vY = _vY / _scale; + + _return = [_vX, _vY, _z]; + }; + case ("3d"): { + _array params ["_vX", "_vY", "_z"]; // z is distance from screen + + _vX = _vX * _scale; + _vY = _vY * _scale; + + private _scrX = _vX / (_leftFOV * _adjustCam * _z) + 0.5; + private _pointX = (_scrX - _topLeftX) / (_bottomRightX - _topLeftX); + + private _scrY = 0.5 - _vY / (_topFOV * _adjustCam * _z); + private _pointY = (_scrY - _topLeftY) / (_bottomRightY - _topLeftY); + + _return = [_pointX, _z, _pointY]; + }; +}; + +_return diff --git a/addons/xm157/$PBOPREFIX$ b/addons/xm157/$PBOPREFIX$ new file mode 100644 index 0000000000..2bddd0ac4e --- /dev/null +++ b/addons/xm157/$PBOPREFIX$ @@ -0,0 +1 @@ +z\ace\addons\xm157 \ No newline at end of file diff --git a/addons/xm157/CfgEventHandlers.hpp b/addons/xm157/CfgEventHandlers.hpp new file mode 100644 index 0000000000..2a3f71f852 --- /dev/null +++ b/addons/xm157/CfgEventHandlers.hpp @@ -0,0 +1,15 @@ +class Extended_PreStart_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_SCRIPT(XEH_preStart)); + }; +}; +class Extended_PreInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_SCRIPT(XEH_preInit)); + }; +}; +class Extended_PostInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_SCRIPT(XEH_postInit)); + }; +}; diff --git a/addons/xm157/CfgSounds.hpp b/addons/xm157/CfgSounds.hpp new file mode 100644 index 0000000000..907e710bba --- /dev/null +++ b/addons/xm157/CfgSounds.hpp @@ -0,0 +1,6 @@ +class CfgSounds { + class GVAR(click) { + sound[] = {QPATHTOF(sounds\click.wav), db-30, 3}; + titles[] = {}; + }; +}; diff --git a/addons/xm157/CfgWeapons.hpp b/addons/xm157/CfgWeapons.hpp new file mode 100644 index 0000000000..69abc30bf0 --- /dev/null +++ b/addons/xm157/CfgWeapons.hpp @@ -0,0 +1,48 @@ +class CfgWeapons { + class ItemCore; + class InventoryOpticsItem_Base_F; + + class ace_xm157_prototype: ItemCore { + author = ECSTRING(common,ACETeam); + scope = 1; // hidden + displayName = "XM157 Prototype"; + descriptionShort = ""; + picture = "\a3\Weapons_F\acc\Data\UI\icon_optic_tws_ca.paa"; + model = "\A3\weapons_f\acc\acco_tws_F"; + inertia = 0.3; + + class CBA_ScriptedOptic { + bodyTexture = QPATHTOF(data\ace_vector_body_co.paa); + // bodyTextureNight = ".paa"; // optional + bodyTextureSize = 1; + hideMagnification = 1; // no point, and it flickers at 1x + disableTilt = 0; + }; + + weaponInfoType = QGVAR(info); + class ItemInfo: InventoryOpticsItem_Base_F { + mass = 14; + optics = 1; + modelOptics = "\x\cba\addons\optics\cba_optic_big_100.p3d"; + class OpticsModes { + class lpvo { + opticsID = 1; + useModelOptics = 1; + opticsPPEffects[] = { "OpticsCHAbera1", "OpticsBlur1" }; + opticsZoomMin = "8 call (uiNamespace getVariable 'cba_optics_fnc_setOpticMagnificationHelper')"; + opticsZoomMax = "1 call (uiNamespace getVariable 'cba_optics_fnc_setOpticMagnificationHelper')"; + opticsZoomInit = "1 call (uiNamespace getVariable 'cba_optics_fnc_setOpticMagnificationHelper')"; + discreteDistance[] = {100}; + discreteDistanceInitIndex = 0; + distanceZoomMin = 100; + distanceZoomMax = 100; + memoryPointCamera = "opticView"; + visionMode[] = {"Normal"}; + opticsFlare = 1; + opticsDisablePeripherialVision = 1; + cameraDir = ""; + }; + }; + }; + }; +}; diff --git a/addons/xm157/README.md b/addons/xm157/README.md new file mode 100644 index 0000000000..55a0696216 --- /dev/null +++ b/addons/xm157/README.md @@ -0,0 +1,2 @@ +ace_xm157 +========== diff --git a/addons/xm157/RscInGameUI.hpp b/addons/xm157/RscInGameUI.hpp new file mode 100644 index 0000000000..4e43e1581a --- /dev/null +++ b/addons/xm157/RscInGameUI.hpp @@ -0,0 +1,79 @@ +class RscObject; +class RscControlsGroupNoScrollbars; + +class RscText; +class GVAR(text): RscText { + font = "EtelkaMonospacePro"; + SizeEx = 0.04; + colorText[]={1,0.1,0.05,0.95}; + shadow = 0; +}; +class GVAR(textMenu): GVAR(text) { + SizeEx = 0.09; + style = 2+16; +}; + +class RscInGameUI { + class CBA_ScriptedOptic_zooming; + class GVAR(info): CBA_ScriptedOptic_zooming { + onLoad = QUOTE(call FUNC(weaponInfo_onLoad)); + class objects { + class Optic: RscObject { // first focal plane + idc = IDC_SCOPE_OBJECT; + type = 82; + model = "\A3\Misc_F\Helpers\UserTexture1m.p3d"; + x = 0; + y = 0; + z = 0; + xBack = 0.9; + yBack = 0.9; + zBack = 0.3; + inBack = 0; + enableZoom = 1; + zoomDuration = 0.001; + class Areas { + class usertexture { + selection = "usertexture"; + class controls { + class test: RscControlsGroupNoScrollbars { + idc = IDC_SCOPE_GROUP; + x = 0; + y = 0; + w = 1; + h = 4/3; + }; + }; + }; + }; + }; + class Screen: RscObject { + idc = IDC_SCREEN_OBJECT; + type = 82; + model = "\A3\Misc_F\Helpers\UserTexture1m.p3d"; + x = 0; + y = 0; + z = 0; + xBack = 0.9; + yBack = 0.9; + zBack = 0.3; + inBack = 1; + enableZoom = 1; + zoomDuration = 0.001; + class Areas { + class usertexture { + selection = "usertexture"; + class controls { + class test: RscControlsGroupNoScrollbars { + idc = IDC_SCREEN_GROUP; + x = 0; + y = 0; + w = 1; + h = 4/3; + }; + }; + }; + }; + }; + }; + }; +}; diff --git a/addons/xm157/XEH_PREP.hpp b/addons/xm157/XEH_PREP.hpp new file mode 100644 index 0000000000..56613ffe34 --- /dev/null +++ b/addons/xm157/XEH_PREP.hpp @@ -0,0 +1,8 @@ +LOG("prep"); + +PREP(ballistics_calculator); +PREP(ballistics_getData); +PREP(keyPress); +PREP(weaponInfo_draw); +PREP(weaponInfo_drawMenu); +PREP(weaponInfo_onLoad); diff --git a/addons/xm157/XEH_postInit.sqf b/addons/xm157/XEH_postInit.sqf new file mode 100644 index 0000000000..5f00e3209f --- /dev/null +++ b/addons/xm157/XEH_postInit.sqf @@ -0,0 +1,66 @@ +#include "script_component.hpp" +#include "\a3\ui_f\hpp\defineDIKCodes.inc" + +GVAR(shown) = false; +GVAR(data) = createHashMap; +([worldName] call EFUNC(common,getMapData)) params ["_latitude"]; +GVAR(data) set ["latitude", _latitude]; + + +// Add Keybinds +["ACE3 Equipment", QGVAR(range), [format ["XM157 - %1", localize "str_a3_rscdisplayarsenal_stat_range"]], { + ["range", true] call FUNC(keyPress); +}, { + ["range", false] call FUNC(keyPress); +}, [DIK_TAB, [false, false, false]], false, 0] call CBA_fnc_addKeybind; + +["ACE3 Equipment", QGVAR(left), [format ["XM157 - %1", localize "str_a3_left"]], { + ["right", true] call FUNC(keyPress); +}, { + ["right", false] call FUNC(keyPress); +}, [DIK_END, [false, false, false]], false, 0] call CBA_fnc_addKeybind; + +["ACE3 Equipment", QGVAR(right), [format ["XM157 - %1", localize "str_a3_right"]], { + ["left", true] call FUNC(keyPress); +}, { + ["left", false] call FUNC(keyPress); +}, [DIK_DELETE, [false, false, false]], false, 0] call CBA_fnc_addKeybind; + +["ACE3 Equipment", QGVAR(up), [format ["XM157 - %1", localize "str_a3_rscattributetargetstate_up"]], { + ["up", true] call FUNC(keyPress); +}, { + ["up", false] call FUNC(keyPress); +}, [DIK_PGUP, [false, false, false]], false, 0] call CBA_fnc_addKeybind; + +["ACE3 Equipment", QGVAR(down), [format ["XM157 - %1", localize "str_a3_rscattributetargetstate_down"]], { + ["down", true] call FUNC(keyPress); +}, { + ["down", false] call FUNC(keyPress); +}, [DIK_PGDN, [false, false, false]], false, 0] call CBA_fnc_addKeybind; + + + +#ifdef ENABLE_QUICK_TESTING +player addPrimaryWeaponItem "ace_xm157_prototype"; +[player] call CBA_fnc_addUnitTrackProjectiles; +player addItem "ACE_ATragMX"; +player addItem "ace_rangecard"; + +["recompile", "recompile", "recompile", { + private _start = diag_tickTime; + [] call ACE_PREP_RECOMPILE; + [] call ace_common_fnc_dumpPerformanceCounters; + private _end = diag_tickTime; + systemChat format ["recompile took [%1 ms]", (1000 * (_end - _start)) toFixed 1]; + + if (productVersion #4 == "Diag") then { + call compile "diag_mergeConfigFile ['P:\z\ace\addons\xm157\config.cpp']"; + }; + + private _windSpd = vectorMagnitude wind; + private _windDir = (wind select 0) atan2 (wind select 1); + systemChat format ["Wind %1 @ %2", _windSpd, _windDir + 180]; + + false +}, {false}, [0x21, [false, false, false]], false] call CBA_fnc_addKeybind; // F Key +#endif diff --git a/addons/xm157/XEH_preInit.sqf b/addons/xm157/XEH_preInit.sqf new file mode 100644 index 0000000000..b47cf6628d --- /dev/null +++ b/addons/xm157/XEH_preInit.sqf @@ -0,0 +1,9 @@ +#include "script_component.hpp" + +ADDON = false; + +PREP_RECOMPILE_START; +#include "XEH_PREP.hpp" +PREP_RECOMPILE_END; + +ADDON = true; diff --git a/addons/xm157/XEH_preStart.sqf b/addons/xm157/XEH_preStart.sqf new file mode 100644 index 0000000000..022888575e --- /dev/null +++ b/addons/xm157/XEH_preStart.sqf @@ -0,0 +1,3 @@ +#include "script_component.hpp" + +#include "XEH_PREP.hpp" diff --git a/addons/xm157/config.cpp b/addons/xm157/config.cpp new file mode 100644 index 0000000000..2689764b19 --- /dev/null +++ b/addons/xm157/config.cpp @@ -0,0 +1,27 @@ +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + name = COMPONENT_NAME; + units[] = {}; + weapons[] = {"ace_xm157_prototype"}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = {"ace_advanced_ballistics", "ace_scopes"}; + author = ECSTRING(common,ACETeam); + authors[] = {"PabstMirror"}; + url = ECSTRING(main,URL); + VERSION_CONFIG; + }; +}; + +#include "CfgEventHandlers.hpp" +#include "CfgSounds.hpp" +#include "CfgWeapons.hpp" +#include "RscInGameUI.hpp" + +class asdg_OpticRail; +class asdg_OpticRail1913: asdg_OpticRail { + class compatibleItems { + ace_xm157_prototype = 1; + }; +}; diff --git a/addons/xm157/data/ace_vector_body_co.paa b/addons/xm157/data/ace_vector_body_co.paa new file mode 100644 index 0000000000..71e1984c6e Binary files /dev/null and b/addons/xm157/data/ace_vector_body_co.paa differ diff --git a/addons/xm157/data/mrad_10_ca.paa b/addons/xm157/data/mrad_10_ca.paa new file mode 100644 index 0000000000..293a29debe Binary files /dev/null and b/addons/xm157/data/mrad_10_ca.paa differ diff --git a/addons/xm157/data/mrad_20_ca.paa b/addons/xm157/data/mrad_20_ca.paa new file mode 100644 index 0000000000..99b724a861 Binary files /dev/null and b/addons/xm157/data/mrad_20_ca.paa differ diff --git a/addons/xm157/data/mrad_40_ca.paa b/addons/xm157/data/mrad_40_ca.paa new file mode 100644 index 0000000000..9e097adff1 Binary files /dev/null and b/addons/xm157/data/mrad_40_ca.paa differ diff --git a/addons/xm157/dev/generate_reticle.py b/addons/xm157/dev/generate_reticle.py new file mode 100644 index 0000000000..119b547ab4 --- /dev/null +++ b/addons/xm157/dev/generate_reticle.py @@ -0,0 +1,178 @@ +from PIL import Image, ImageDraw, ImageFont, ImageFilter +import math + +# based on vortex razor hd + +final_scale = 10 + +supersample = 4 +# supersampling helps make rounded circles, does slighly blur text and straight lines +pixels_per_mrad = supersample * final_scale +image_size = supersample * 4096 +image_center = image_size / 2 + +# create an image +out = Image.new("RGBA", (image_size, image_size), (255, 255, 255, 0)) +# get a drawing context +d = ImageDraw.Draw(out) + +line_thin = math.floor(0.07 * pixels_per_mrad) +line_thick = math.floor(0.15 * pixels_per_mrad) +font_size = math.floor(0.55 * pixels_per_mrad) +# source https://fonts.google.com/specimen/Electrolize (Open Font License) +fnt = ImageFont.truetype("Electrolize-Regular.ttf", font_size) + +# draw center dot +d.ellipse([ + (image_center - 0.1 * pixels_per_mrad, image_center - 0.1 * pixels_per_mrad), + (image_center + 0.1 * pixels_per_mrad, image_center + 0.1 * pixels_per_mrad) +], fill=(0, 0, 0)) + +# draw 3 main axis lines +d.line([ + (image_center - 8 * pixels_per_mrad, image_center), + (image_center - 0.5 * pixels_per_mrad, image_center) +], fill=(0, 0, 0), width=line_thin) +d.line([ + (0, image_center), + (image_center - 8.5 * pixels_per_mrad, image_center) +], fill=(0, 0, 0), width=line_thick) +d.line([ + (image_center + 0.5 * pixels_per_mrad, image_center), + (image_center + 8 * pixels_per_mrad, image_center) +], fill=(0, 0, 0), width=line_thin) +d.line([ + (image_center + 8.5 * pixels_per_mrad, image_center), + (image_size, image_center) +], fill=(0, 0, 0), width=line_thick) +d.line([ + (image_center, image_center + 0.5 * pixels_per_mrad), + (image_center, image_center + 11 * pixels_per_mrad) +], fill=(0, 0, 0), width=line_thin) +d.line([ + (image_center, image_center + 11.5 * pixels_per_mrad), + (image_center, image_size) +], fill=(0, 0, 0), width=line_thick) + +# draw big triangle bar things +if (image_center - 15 * pixels_per_mrad > 0): + d.polygon([ + (0, image_center + 2 * pixels_per_mrad), + (image_center - 20 * pixels_per_mrad, image_center + 2 * pixels_per_mrad), + (image_center - 15 * pixels_per_mrad, image_center), + (image_center - 20 * pixels_per_mrad, image_center - 2 * pixels_per_mrad), + (0, image_center - 2 * pixels_per_mrad), + ], fill=(0, 0, 0)) + d.polygon([ + (image_size, image_center + 2 * pixels_per_mrad), + (image_center + 20 * pixels_per_mrad, image_center + 2 * pixels_per_mrad), + (image_center + 15 * pixels_per_mrad, image_center), + (image_center + 20 * pixels_per_mrad, image_center - 2 * pixels_per_mrad), + (image_size, image_center - 2 * pixels_per_mrad), + ], fill=(0, 0, 0)) + d.polygon([ + (image_center - 2 * pixels_per_mrad, image_size), + (image_center - 2 * pixels_per_mrad, image_center + 20 * pixels_per_mrad), + (image_center, image_center + 15 * pixels_per_mrad), + (image_center + 2 * pixels_per_mrad, image_center + 20 * pixels_per_mrad), + (image_center + 2 * pixels_per_mrad, image_size), + ], fill=(0, 0, 0)) + + +# draw windage hash marks and text +for x in range(1, 9): + if (x % 2 == 0): + text = f"{abs(x)}" + # windage odd numbers + d.text((image_center + (x - 0.15) * pixels_per_mrad, image_center - 1.2 * pixels_per_mrad), text, font=fnt, fill=(0, 0, 0)) + d.text((image_center - (x + 0.15) * pixels_per_mrad, image_center - 1.2 * pixels_per_mrad), text, font=fnt, fill=(0, 0, 0)) + # windage mrad hashs + d.line([ + (image_center + x * pixels_per_mrad, image_center + line_thin / 2), + (image_center + x * pixels_per_mrad, image_center - 0.5 * pixels_per_mrad) + ], fill=(0, 0, 0), width=line_thin) + d.line([ + (image_center - x * pixels_per_mrad, image_center + line_thin / 2), + (image_center - x * pixels_per_mrad, image_center - 0.5 * pixels_per_mrad) + ], fill=(0, 0, 0), width=line_thin) + if (x % 2 == 0): + d.line([ + (image_center - x * pixels_per_mrad, image_center + 0.2 * pixels_per_mrad), + (image_center - x * pixels_per_mrad, image_center + 0.7 * pixels_per_mrad) + ], fill=(0, 0, 0), width=line_thick) + d.line([ + (image_center + x * pixels_per_mrad, image_center + 0.2 * pixels_per_mrad), + (image_center + x * pixels_per_mrad, image_center + 0.7 * pixels_per_mrad) + ], fill=(0, 0, 0), width=line_thick) + else: + d.line([ + (image_center - x * pixels_per_mrad, image_center + 0.2 * pixels_per_mrad), + (image_center - x * pixels_per_mrad, image_center + 0.55 * pixels_per_mrad) + ], fill=(0, 0, 0), width=line_thick) + d.line([ + (image_center + x * pixels_per_mrad, image_center + 0.2 * pixels_per_mrad), + (image_center + x * pixels_per_mrad, image_center + 0.55 * pixels_per_mrad) + ], fill=(0, 0, 0), width=line_thick) + + if (x < 8): + # windage half mrad marks + d.line([ + (image_center + (x + .5) * pixels_per_mrad, image_center), + (image_center + (x + .5) * pixels_per_mrad, image_center - 0.25 * pixels_per_mrad) + ], fill=(0, 0, 0), width=line_thin) + d.line([ + (image_center - (x + .5) * pixels_per_mrad, image_center), + (image_center - (x + .5) * pixels_per_mrad, image_center - 0.25 * pixels_per_mrad) + ], fill=(0, 0, 0), width=line_thin) + +# handle 10 mrad thick line +d.multiline_text((image_center + (10 - 0.4) * pixels_per_mrad, image_center - 1.2 * pixels_per_mrad), "10", font=fnt, fill=(0, 0, 0)) +d.line([ + (image_center + 10 * pixels_per_mrad, image_center - 0.5 * pixels_per_mrad), + (image_center + 10 * pixels_per_mrad, image_center + 0.5 * pixels_per_mrad) +], fill=(0, 0, 0), width=line_thick) +d.multiline_text((image_center + (-10 - 0.4) * pixels_per_mrad, image_center - 1.2 * pixels_per_mrad), "10", font=fnt, fill=(0, 0, 0)) +d.line([ + (image_center - 10 * pixels_per_mrad, image_center - 0.5 * pixels_per_mrad), + (image_center - 10 * pixels_per_mrad, image_center + 0.5 * pixels_per_mrad) +], fill=(0, 0, 0), width=line_thick) + +for y in range(1, 12): + line_y = image_center + y * pixels_per_mrad + # elev hash marks + d.line([ + (image_center - 0.5 * pixels_per_mrad, line_y), + (image_center + 0.5 * pixels_per_mrad, line_y) + ], fill=(0, 0, 0), width=line_thin) + if (y < 11): # half marks + d.line([ + (image_center - 0.1 * pixels_per_mrad, line_y + 0.5 * pixels_per_mrad), + (image_center + 0.1 * pixels_per_mrad, line_y + 0.5 * pixels_per_mrad) + ], fill=(0, 0, 0), width=line_thin) + + dot_count = 2 + if (y > 2): dot_count = 3 + if (y > 4): dot_count = 4 + if (y > 6): dot_count = 5 + for dot in range(1, dot_count + 1): + d.ellipse([ + (image_center + (dot - 0.1) * pixels_per_mrad, line_y - 0.1 * pixels_per_mrad), + (image_center + (dot + 0.1) * pixels_per_mrad, line_y + 0.1 * pixels_per_mrad) + ], fill=(0, 0, 0)) + d.ellipse([ + (image_center + (-dot - 0.1) * pixels_per_mrad, line_y - 0.1 * pixels_per_mrad), + (image_center + (-dot + 0.1) * pixels_per_mrad, line_y + 0.1 * pixels_per_mrad) + ], fill=(0, 0, 0)) + if (y % 2 == 0): + d.text((image_center + (dot_count + 0.85) * pixels_per_mrad, line_y - 0.3 * pixels_per_mrad), f"{y}", font=fnt, fill=(0, 0, 0)) + if (y >= 10): dot_count += 0.2 + d.text((image_center - (dot_count + 1.15) * pixels_per_mrad, line_y - 0.3 * pixels_per_mrad), f"{y}", font=fnt, fill=(0, 0, 0)) + +if (supersample > 1): + out = out.resize((4096, 4096)) + + +output_filename = f"mrad_{final_scale}_ca.png" +out.show() +out.save(output_filename) +print(f"written to {output_filename}") diff --git a/addons/xm157/functions/fnc_ballistics_calculator.sqf b/addons/xm157/functions/fnc_ballistics_calculator.sqf new file mode 100644 index 0000000000..41dfbcc530 --- /dev/null +++ b/addons/xm157/functions/fnc_ballistics_calculator.sqf @@ -0,0 +1,101 @@ +#include "script_component.hpp" +/* + * Author: PabstMirror, Ruthberg (Based on ace_atragmx_fnc_calculate_solution) + * Calculates elevation and windage + * + * Arguments: + * 0: Range + * 1: Direction of Fire (deg) - Yaw + * 2: Inlination (deg) - Pitch + * 3: Bank (deg) - Roll + * + * Return Value: + * Elevation and Windage in MRAD + * + * Example: + * [500, 90, 0, 0] call ace_xm157_fnc_ballistics_calculator + * + * Public: No + */ + +params ["_targetRange", "_directionOfFire", "_inclinationAngle", "_bank"]; + +private _weaponInfo = [] call FUNC(ballistics_getData); +if (_weaponInfo isEqualTo []) exitWith { [0,0] }; +_weaponInfo params ["_scopeBaseAngle","_boreHeight","_airFriction","_muzzleVelocity","_bc", + "_dragModel","_atmosphereModel","_barrelTwist","_twistDirection","_caliber","_bulletLength","_bulletMass"]; + +private _latitude = GVAR(data) getOrDefault ["latitude", 0]; + +// Get Wind +private _windSpeed = GVAR(data) getOrDefault ["wind_speed", 0]; +private _windDirection = 22.5 * (GVAR(data) getOrDefault ["wind_dir", 0]); +private _wind = [sin (_directionOfFire-_windDirection) * _windSpeed, -cos (_directionOfFire-_windDirection) * _windSpeed, 0]; + +// Get atmosphere +private _altitude = (getPosASL ace_player) select 2; +private _relativeHumidity = EGVAR(weather,currentHumidity); +private _temperature = _altitude call EFUNC(weather,calculateTemperatureAtHeight); +private _barometricPressure = _altitude call EFUNC(weather,calculateBarometricPressure); + + +private _bulletPos = [0,0,-(_boreHeight / 100)]; +private _lastBulletPos = +_bulletPos; +private _bulletVelocity = [0,Cos(_scopeBaseAngle) * _muzzleVelocity,Sin(_scopeBaseAngle) * _muzzleVelocity]; +private _gravity = [-sin (_bank) * cos(_scopeBaseAngle + _inclinationAngle) * -GRAVITY, + sin(_scopeBaseAngle + _inclinationAngle) * -GRAVITY, + cos (_bank) * cos(_scopeBaseAngle + _inclinationAngle) * -GRAVITY]; + +private _useAB = missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]; +if (_useAB) then { + _bc = parseNumber(("ace_advanced_ballistics" callExtension format["atmosphericCorrection:%1:%2:%3:%4:%5", _bc, _temperature, _barometricPressure, _relativeHumidity, _atmosphereModel])); +}; + +private _deltaT = 1 / 60; +private _TOF = 0; // Limit TOF to 5 seconds! +while {(_TOF < 5) && {(_bulletPos # 1) < _targetRange}} do { + private _trueVelocity = _bulletVelocity vectorDiff _wind; + private _trueSpeed = vectorMagnitude _trueVelocity; + + private _bulletAccel = if (_useAB) then { + private _drag = parseNumber(("ace_advanced_ballistics" callExtension format["retard:%1:%2:%3:%4", _dragModel, _bc, _trueSpeed, _temperature])); + (vectorNormalized _trueVelocity) vectorMultiply (-1 * _drag); + } else { + _trueVelocity vectorMultiply (_trueSpeed * _airFriction); + }; + _bulletAccel = _bulletAccel vectorAdd _gravity; + _lastBulletPos = _bulletPos; + _bulletPos = _bulletPos vectorAdd (_bulletVelocity vectorMultiply (_deltaT * 0.5)); + _bulletVelocity = _bulletVelocity vectorAdd (_bulletAccel vectorMultiply _deltaT); + _bulletPos = _bulletPos vectorAdd (_bulletVelocity vectorMultiply (_deltaT * 0.5)); + + _TOF = _TOF + _deltaT; +}; + +private _tx = (_lastBulletPos select 0) + (_targetRange - (_lastBulletPos select 1)) * ((_bulletPos select 0) - (_lastBulletPos select 0)) / ((_bulletPos select 1) - (_lastBulletPos select 1)); +private _tz = (_lastBulletPos select 2) + (_targetRange - (_lastBulletPos select 1)) * ((_bulletPos select 2) - (_lastBulletPos select 2)) / ((_bulletPos select 1) - (_lastBulletPos select 1)); +private _elevation = - atan(_tz / _targetRange); +private _windage = - atan(_tx / _targetRange); + + +if (_useAB && {(_bulletPos select 1) > 0}) then { + // Coriolis + private _horizontalDeflection = 0.0000729 * (_bulletPos select 1) * _TOF * sin(_latitude); + private _horizontalCoriolis = - atan(_horizontalDeflection / (_bulletPos select 1)); + _windage = _windage + _horizontalCoriolis; + // Eoetvoes + private _eoetvoesMultiplier = 2 * (0.0000729 * _muzzleVelocity / -GRAVITY) * cos(_latitude) * sin(_directionOfFire); + private _verticalDeflection = (_bulletPos select 2) * _eoetvoesMultiplier; + private _verticalCoriolis = - atan(_verticalDeflection / (_bulletPos select 1)); + _elevation = _elevation + _verticalCoriolis; + // Spin drift + private _stabilityFactor = 1.5; + if (_caliber * _bulletLength * _bulletMass * _barrelTwist > 0) then { + _stabilityFactor = [_caliber, _bulletLength, _bulletMass, _barrelTwist, _muzzleVelocity, _temperature, _barometricPressure] call FUNC(calculateStabilityFactor); + }; + private _spinDeflection = _twistDirection * 0.0254 * 1.25 * (_stabilityFactor + 1.2) * _TOF ^ 1.83; + private _spinDrift = - atan(_spinDeflection / (_bulletPos select 1)); + private _windage = _windage + _spinDrift; +}; + +[17.453*_elevation, 17.453*_windage] // Convert to MRAD and return diff --git a/addons/xm157/functions/fnc_ballistics_getData.sqf b/addons/xm157/functions/fnc_ballistics_getData.sqf new file mode 100644 index 0000000000..c0d1eed3bf --- /dev/null +++ b/addons/xm157/functions/fnc_ballistics_getData.sqf @@ -0,0 +1,62 @@ +#include "script_component.hpp" +/* + * Author: PabstMirror, Ruthberg (Based on ace_atragmx) + * Gets ballistic info for a weapon, mag and ammo + * + * Arguments: + * None + * + * Return Value: + * Weapon Info + * + * Example: + * [] call ace_xm157_fnc_ballistics_getData + * + * Public: No + */ + +private _unit = ace_player; +private _weaponClass = primaryWeapon _unit; +private _magazineClass = (primaryWeaponMagazine _unit) param [0, ""]; +private _ammoClass = getText (configFile >> "CfgMagazines" >> _magazineClass >> "ammo"); + +private _key = format ["weaponInfoCache-%1-%2-%3",_weaponClass,_magazineClass,_ammoClass]; +private _weaponInfo = GVAR(data) getOrDefault [_key, []]; +if ((_weaponInfo isEqualTo []) && {_magazineClass != ""}) then { + TRACE_3("new weapon/mag",_weaponClass,_magazineClass,_ammoClass); + private _useABConfig = (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]); + + private _zeroRange = 100; + private _boreHeight = [_unit, 0] call EFUNC(scopes,getBoreHeight); + + private _ammoConfig = _ammoClass call EFUNC(advanced_ballistics,readAmmoDataFromConfig); + _ammoConfig params ["_airFriction","_caliber","_bulletLength","_bulletMass","","_dragModel","_ballisticCoefficients","","_atmosphereModel","","_muzzleVelocityTable","_barrelLengthTable"]; + private _weaponConfig = _weaponClass call EFUNC(advanced_ballistics,readWeaponDataFromConfig); + _weaponConfig params ["_barrelTwist", "_twistDirection", "_barrelLength"]; + private _bc = if (_ballisticCoefficients isEqualTo []) then { 0 } else { _ballisticCoefficients # 0 }; + + // Get Muzzle Velocity + private _muzzleVelocity = if (_barrelLength > 0 && _useABConfig && {_bc != 0}) then { + [_barrelLength, _muzzleVelocityTable, _barrelLengthTable, 0] call EFUNC(advanced_ballistics,calculateBarrelLengthVelocityShift) + } else { + private _initSpeed = getNumber (configFile >> "CfgMagazines" >> _magazineClass >> "initSpeed"); + private _initSpeedCoef = getNumber (configFile >> "CfgWeapons" >> _weaponClass >> "initSpeed"); + if (_initSpeedCoef < 0) then { + _initSpeed = _initSpeed * -_initSpeedCoef; + }; + if (_initSpeedCoef > 0) then { + _initSpeed = _initSpeedCoef; + }; + _initSpeed + }; + + // Scope Base Angle + private _zeroAngle = "ace_advanced_ballistics" callExtension format ["calcZero:%1:%2:%3:%4", _zeroRange, _muzzleVelocity, _airFriction, _boreHeight]; + private _scopeBaseAngle = parseNumber _zeroAngle; + + _weaponInfo = [_scopeBaseAngle,_boreHeight,_airFriction,_muzzleVelocity,_bc,_dragModel,_atmosphereModel,_barrelTwist,_twistDirection,_caliber,_bulletLength,_bulletMass]; + GVAR(data) set [_key, _weaponInfo]; + TRACE_1("setting cache",_weaponInfo); +}; + +_weaponInfo diff --git a/addons/xm157/functions/fnc_keyPress.sqf b/addons/xm157/functions/fnc_keyPress.sqf new file mode 100644 index 0000000000..36220f493c --- /dev/null +++ b/addons/xm157/functions/fnc_keyPress.sqf @@ -0,0 +1,67 @@ +#include "script_component.hpp" +/* + * Author: PabstMirror + * Handles key presses + * + * Arguments: + * 0: Type + * 1: IsKeyDown + * + * Return Value: + * Handled + * + * Example: + * ["range", true] call ace_xm157_fnc_keyPress + * + * Public: No + */ + +params ["_func", "_keyDown"]; + +if (!GVAR(shown)) exitWith { false }; // fast exit if not shown +if (!([ACE_player, objNull, ["isNotInside"]] call EFUNC(common,canInteractWith))) exitWith { false }; +if (!(ACE_player call CBA_fnc_canUseWeapon)) exitWith { false }; + +private _display = uinamespace getVariable [QGVAR(display), displayNull]; +if (isNull _display) exitWith { ERROR("keyPress-no display"); false }; + +if (_keyDown) then { playSound QGVAR(click); }; +GVAR(data) set ["lastInputTime", CBA_missionTime]; + +call { + if (_func == "range") exitWith { + if (_keyDown) then { + GVAR(data) set ["range_keyDownStart", CBA_missionTime]; + } else { + private _holdTime = CBA_missionTime - (GVAR(data) getOrDefault ["range_keyDownStart", 0]); + private _range = 0; + if (_holdTime < 0.5) then { + private _distance = round parseNumber ctrlText (_display displayCtrl 151); + if (_distance > 10 && {_distance < RANGEFINDER_MAX}) then { + _range = _distance; + } else { + _range = -1; // bad return + }; + }; + TRACE_1("Updating range",_range); + GVAR(data) set ["range", _range]; + }; + }; + if (!_keyDown) exitWith {}; + + GVAR(data) set ["menu_updated", true]; + private _index = GVAR(data) getOrDefault ["menu_index", 0]; + if (_func in ["left", "right"]) exitWith { + _index = (_index + ([-1, 1] select (_func == "right")) + count GVAR(menu)) % count GVAR(menu); + GVAR(data) set ["menu_index", _index]; + }; + (GVAR(menu) # _index) params ["", "_var", "_thing", ["_upAction", {}], ["_downAction", {}]]; + if (_func == "up") exitWith { + [_index, _var, _thing] call _upAction; + }; + if (_func == "down") exitWith { + [_index, _var, _thing] call _downAction; + }; +}; + +true diff --git a/addons/xm157/functions/fnc_weaponInfo_draw.sqf b/addons/xm157/functions/fnc_weaponInfo_draw.sqf new file mode 100644 index 0000000000..c6b89712d4 --- /dev/null +++ b/addons/xm157/functions/fnc_weaponInfo_draw.sqf @@ -0,0 +1,144 @@ +#include "script_component.hpp" +/* + * Author: PabstMirror + * Draw3D event handler when scope is active + * + * Arguments: + * None (implicit vars from missionEventHandler) + * + * Return Value: + * None + * + * Example: + * [] call ace_xm157_fnc_weaponInfo_draw + * + * Public: No + */ + +//IGNORE_PRIVATE_WARNING ["_thisArgs", "_thisEventHandler"]; // from missionEventHandler +_thisArgs params ["_display"]; +if (isNull _display) exitWith { + TRACE_1("cleaning up display",_thisEventHandler); + GVAR(shown) = false; + removeMissionEventHandler ["Draw3D", _thisEventHandler]; +}; +private _ctrlScopeObject = _display displayCtrl IDC_SCOPE_OBJECT; +private _ctrlScreenObject = _display displayCtrl IDC_SCREEN_OBJECT; + + +// Hide everything when not in scope +private _isUsingOptic = ctrlShown (_display displayCtrl 154); +if (!_isUsingOptic) exitWith { + _ctrlScopeObject ctrlShow false; + _ctrlScreenObject ctrlShow false; +}; +_ctrlScopeObject ctrlShow true; +_ctrlScreenObject ctrlShow true; +BEGIN_COUNTER(draw); + +// Get common info +private _weaponVec = ace_player weaponDirection currentWeapon ace_player; +(_weaponVec call CBA_fnc_vect2Polar) params ["", "_weaponDir", "_weaponPitch"]; +private _weaponBank = call cba_optics_fnc_gunBank; +private _viewBank = _weaponBank; +if (isWeaponDeployed [player, true]) then { // prone deploy tilting is special (screen doesn't tilt, but player does) + _weaponBank = (((vectorUp ace_player) vectorCrossProduct _weaponVec) call CBA_fnc_vect2Polar) # 2; // I think this is right? +}; + +(0.25 call CBA_fnc_getFov) params ["_fov", "_zoom"]; +private _fovMRAD = 1000 * _fov; // Real MRAD (not mils) +private _nonMagnified = _zoom < 1.1; +private _range = GVAR(data) getOrDefault ["range", 0]; +private _needsUpdate = GVAR(data) getOrDefault ["menu_updated", true]; // Updated when a menu item changed +private _timeSinceLastInput = CBA_missionTime - (GVAR(data) getOrDefault ["lastInputTime", 0]); + + +// Bank-tilt display objects +_ctrlScopeObject ctrlSetModelDirAndUp [[0,1,0],[sin _viewBank,0,cos _viewBank]]; +_ctrlScreenObject ctrlSetModelDirAndUp [[0,1,0],[sin _viewBank,0,cos _viewBank]]; + + +// Scope - Handle etched reticle +private _retTex = QPATHTOF(data\mrad_10_ca.paa); +private _retScale = 4096/10; // texureResolution / (px/MRAD) +switch (true) do { + case (_fovMRAD < 4096/40): { + _retTex = QPATHTOF(data\mrad_40_ca.paa); + _retScale = 4096/40; + }; + case (_fovMRAD < 4096/20): { + _retTex = QPATHTOF(data\mrad_20_ca.paa); + _retScale = 4096/20; + }; +}; +private _scale = 1 / (getResolution # 5); +_scale = 2 * _scale * _retScale / _fovMRAD; +_ctrlScopeObject ctrlSetModelScale _scale; +private _ctrlScopeReticle = _display displayCtrl IDC_SCOPE_RETICLE; +if (_retTex != ctrlText _ctrlScopeReticle) then { _ctrlScopeReticle ctrlSetText _retTex; }; + + +// Screen - Draw menu +[_display, _needsUpdate] call FUNC(weaponInfo_drawMenu); + + +// Screen - Show range info +private _rangeInfo = _range call { + if (_range == 0) exitWith { "" }; + if (_range < 0) exitWith { // range error - blink if recent + if ((_timeSinceLastInput < 3) && {(floor (4*_timeSinceLastInput)) % 2 == 1}) then { "----" } else { "" }; + }; + format ["%1 m", _range toFixed 0] +}; +private _ctrl = _display displayCtrl IDC_SCREEN_TEXT_UPPER_RIGHT; +_ctrl ctrlSetText _rangeInfo; + + +// Screen - Show bearing info +private _bearingInfo = call { + private _bearingSetting = GVAR(data) getOrDefault ["bearing_show", 0]; + if ((_bearingSetting == 2) && {_timeSinceLastInput > 2}) exitWith { "" }; + if ((_bearingSetting == 1)) exitWith { format ["%1", floor (17.777777 * _weaponDir)]; }; // (6400 Mils, not MRAD) + format ["%1°", floor _weaponDir]; +}; +private _ctrl = _display displayCtrl IDC_SCREEN_TEXT_UPPER_LEFT; +_ctrl ctrlSetText _bearingInfo; + + +// Screen - update reticle type based on settings and zoom level +private _ctrl = _display displayCtrl IDC_SCREEN_RETICLE; +private _lastMagnified = GVAR(data) getOrDefault ["reticle_cache_lastMag", true]; +private _size = GVAR(data) getOrDefault ["reticle_cache_size", 1]; +if (_needsUpdate || {_nonMagnified isNotEqualTo _lastMagnified}) then { + private _tex = ""; + if (_nonMagnified) then { + switch (GVAR(data) getOrDefault ["reticle_cqb", 0]) do { + case (0): { _tex = "\a3\weapons_f\acc\data\collimdot_dot_red_ca.paa"; _size = 1; }; + case (1): { _tex = "\a3\weapons_f\acc\data\collimdot_dot_red_ca.paa"; _size = 2; }; + case (2): { _tex = "\a3\weapons_f\acc\data\collimdot_circle_red_ca.paa"; _size = 1; }; + case (3): { _tex = "\a3\weapons_f\acc\data\collimdot_dot_green_ca.paa"; _size = 1; }; + case (4): { _size = 0; }; + }; + } else { + _tex = "\a3\weapons_f\acc\data\collimdot_dot_red_ca.paa"; _size = 1; + }; + _ctrl ctrlSetText _tex; + GVAR(data) set ["reticle_cache_lastMag", _nonMagnified]; + GVAR(data) set ["reticle_cache_size", _size]; +}; + + +// Screen - update reticle position based on ballistics computer +if (_range > 0 && {_size > 0}) then { + BEGIN_COUNTER(ballistics_calculator); + ([_range, _weaponDir, _weaponPitch, _weaponBank] call FUNC(ballistics_calculator)) params ["_elevMRAD", "_windMRAD"]; + END_COUNTER(ballistics_calculator); + _ctrl ctrlSetPosition [-_windMRAD / _fovMRAD + 0.5 - _size / 2, + 4/3 * (_elevMRAD / _fovMRAD + 0.5 - _size/2), _size, _size*4/3]; + _ctrl ctrlCommit 0; +} else { + _ctrl ctrlSetPosition [0.5 - _size / 2, + 4/3 * (0.5 - _size/2), _size, _size*4/3]; + _ctrl ctrlCommit 0; +}; + + +END_COUNTER(draw); diff --git a/addons/xm157/functions/fnc_weaponInfo_drawMenu.sqf b/addons/xm157/functions/fnc_weaponInfo_drawMenu.sqf new file mode 100644 index 0000000000..63ebe540ef --- /dev/null +++ b/addons/xm157/functions/fnc_weaponInfo_drawMenu.sqf @@ -0,0 +1,81 @@ +#include "script_component.hpp" +/* + * Author: PabstMirror + * Updates the menu display + * + * Arguments: + * 0: Display + * 1: Menu Item Needs Updating + * + * Return Value: + * None + * + * Example: + * [display, true] call ace_xm157_fnc_weaponInfo_drawMenu + * + * Public: No + */ + +params ["_display", "_needsUpdate"]; + +if (isNil QGVAR(menu)) then { + private _arrayUp = { + params ["", "_var", "_thing"]; + private _value = GVAR(data) getOrDefault [_var, 0]; + private _value = (_value + 1 + count _thing) % count _thing; + GVAR(data) set [_var, _value]; + }; + private _arrayDown = { + params ["", "_var", "_thing"]; + private _value = GVAR(data) getOrDefault [_var, 0]; + _value = (_value - 1 + count _thing) % count _thing; + GVAR(data) set [_var, _value]; + }; + private _rangeUp = { + private _range = GVAR(data) getOrDefault ["range", -1]; + if (_range < 0) then { _range = 0; }; + _range = RANGEFINDER_MAX min (100 + 100 * floor (_range/100)); + GVAR(data) set ["range", _range]; + }; + private _rangeDown = { + private _range = GVAR(data) getOrDefault ["range", -1]; + if (_range < 0) then { _range = 0; }; + _range = 0 max (-100 + 100 * ceil (_range/100)); + GVAR(data) set ["range", _range]; + }; + private _atmosphereInfo = { + private _altitude = (getPosASL ace_player) select 2; + private _relativeHumidity = EGVAR(weather,currentHumidity); + private _temperature = _altitude call EFUNC(weather,calculateTemperatureAtHeight); + private _barometricPressure = _altitude call EFUNC(weather,calculateBarometricPressure); // hPA + format ["%1%2 %3%4 %5hPA", _temperature toFixed 1, "°C", _relativeHumidity toFixed 1, "%", _barometricPressure toFixed 0] + }; + GVAR(menu) = [ + ["", "", [""], _rangeUp, _rangeDown], + ["Wind Speed (m/s)", "wind_speed", ["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20"], _arrayUp, _arrayDown], + ["Wind Direction", "wind_dir", ["N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"], _arrayUp, _arrayDown], + // ["CQB Reticle", "reticle_cqb", ["2 MOA Red Dot", "4 MOA Red Dot", "Off"], _arrayUp, _arrayDown], + ["Bearing Display", "bearing_show", ["Degrees", "Mils", "Off"], _arrayUp, _arrayDown], + ["Atmosphere", "", _atmosphereInfo, {}, {}] + ]; +}; + + +private _index = GVAR(data) getOrDefault ["menu_index", 0]; +(GVAR(menu) # _index) params ["_title", "_var", "_thing"]; +if ((!_needsUpdate) && {_thing isEqualType []}) exitWith {}; + +private _ctrlMenuText = _display displayCtrl IDC_SCREEN_MENU_TEXT; +private _text = ""; +if (_index != 0) then { + if (_thing isEqualType []) then { + GVAR(data) set ["menu_updated", false]; + private _value = GVAR(data) getOrDefault [_var, 0]; + _text = _title + "\n" + "<" + (_thing param [_value, "#BadIndex"]) + ">"; + } else { + _text = _title + "\n" + ([_var] call _thing); + }; +}; +_ctrlMenuText ctrlSetText _text; + +GVAR(data) set ["menu_updated", false]; diff --git a/addons/xm157/functions/fnc_weaponInfo_onLoad.sqf b/addons/xm157/functions/fnc_weaponInfo_onLoad.sqf new file mode 100644 index 0000000000..3fb82c756e --- /dev/null +++ b/addons/xm157/functions/fnc_weaponInfo_onLoad.sqf @@ -0,0 +1,83 @@ +#include "script_component.hpp" +/* + * Author: PabstMirror + * Creates UI + * + * Arguments: + * 0: Display + * + * Return Value: + * None + * + * Example: + * [display] call ace_xm157_fnc_weaponInfo_onLoad + * + * Public: No + */ + +params ["_display"]; +TRACE_1("weaponInfo_onLoad",_display); + +uinamespace setVariable [QGVAR(display), _display]; +[_display, true] call cba_optics_fnc_loadScriptedOptic; // pass thru to cba + + +// Setup the scope object +private _ctrlScopeObject = _display displayCtrl IDC_SCOPE_OBJECT; +private _scale = 1 / (getResolution # 5); // keep object the same size for any interface size +private _distance = 2.0 * 4/3; +if ((getResolution # 4) < (4/3)) then { _distance = _distance * (getResolution # 7); }; // eg 5x4 +private _base = ["3d", [0,0,_distance], _scale] call EFUNC(common,rscObjectHelper); +_ctrlScopeObject ctrlSetPosition _base; +_ctrlScopeObject ctrlSetModelScale _scale; +_ctrlScopeObject ctrlSetModelDirAndUp [[0,1,0],[0,0,1]]; +_ctrlScopeObject ctrlShow true; + +private _ctrlScopeGroup = _display displayCtrl IDC_SCOPE_GROUP; +// Add reticle +private _ctrlScopeReticle = _display ctrlCreate ["RscPicture", IDC_SCOPE_RETICLE, _ctrlScopeGroup]; +_ctrlScopeReticle ctrlSetPosition [0, 0, 1, 4/3]; +_ctrlScopeReticle ctrlCommit 0; + + +// Setup the screen object +private _ctrlScreenObject = _display displayCtrl IDC_SCREEN_OBJECT; +private _scale = 1 / (getResolution # 5); // keep object the same size for any interface size +private _distance = 4/3; +if ((getResolution # 4) < (4/3)) then { _distance = _distance * (getResolution # 7); }; // eg 5x4 +private _base = ["3d", [0,0,_distance], _scale] call EFUNC(common,rscObjectHelper); +_ctrlScreenObject ctrlSetPosition _base; +_ctrlScreenObject ctrlSetModelScale _scale; +_ctrlScreenObject ctrlSetModelDirAndUp [[0,1,0],[0,0,1]]; +_ctrlScreenObject ctrlShow true; + +private _ctrlScreenGroup = _display displayCtrl IDC_SCREEN_GROUP; +// Info display +private _ctrl = _display ctrlCreate [QGVAR(text), IDC_SCREEN_TEXT_UPPER_LEFT, _ctrlScreenGroup]; +_ctrl ctrlSetPosition [0.3, 0.2, 0.25, 0.25]; +_ctrl ctrlCommit 0; +private _ctrl = _display ctrlCreate [QGVAR(text), IDC_SCREEN_TEXT_UPPER_RIGHT, _ctrlScreenGroup]; +_ctrl ctrlSetPosition [0.7, 0.2, 0.25, 0.25]; +_ctrl ctrlCommit 0; +// Menu +private _ctrlMenuText = _display ctrlCreate [QGVAR(textMenu), IDC_SCREEN_MENU_TEXT, _ctrlScreenGroup]; +_ctrlMenuText ctrlSetPosition [0.1, 0.45, 0.8, 0.7]; +_ctrlMenuText ctrlCommit 0; + + +// Add screen reticle +private _ctrl = _display ctrlCreate ["RscPicture", IDC_SCREEN_RETICLE, _ctrlScreenGroup]; + + +// Add dummy idcs for dist/angle from engine +// 151=Dist, 156=Heading, 182=Pitch, +private _ctrl = _display ctrlCreate ["RscText", 151]; // IDC_IGUI_WEAPON_DISTANCE +_ctrl ctrlSetPosition [-1, -1, 0, 0]; +_ctrl ctrlCommit 0; +private _ctrl = _display displayCtrl 168; // hide ca_zeroing (from cba) +_ctrl ctrlShow false; + + +GVAR(shown) = true; +GVAR(data) set ["menu_updated", true]; +addMissionEventHandler ["Draw3D", LINKFUNC(weaponInfo_draw), [_display]]; diff --git a/addons/xm157/functions/script_component.hpp b/addons/xm157/functions/script_component.hpp new file mode 100644 index 0000000000..3c08948f71 --- /dev/null +++ b/addons/xm157/functions/script_component.hpp @@ -0,0 +1 @@ +#include "\z\ace\addons\xm157\script_component.hpp" diff --git a/addons/xm157/script_component.hpp b/addons/xm157/script_component.hpp new file mode 100644 index 0000000000..432fb05830 --- /dev/null +++ b/addons/xm157/script_component.hpp @@ -0,0 +1,24 @@ +#define COMPONENT xm157 +#define COMPONENT_BEAUTIFIED XM157 Fire Control Scope +#include "\z\ace\addons\main\script_mod.hpp" + +// #define DEBUG_MODE_FULL +// #define DISABLE_COMPILE_CACHE +// #define ENABLE_PERFORMANCE_COUNTERS +// #define ENABLE_QUICK_TESTING + +#include "\z\ace\addons\main\script_macros.hpp" + +#define RANGEFINDER_MAX 5000 + +#define IDC_SCOPE_OBJECT 7000 +#define IDC_SCOPE_GROUP 7001 +#define IDC_SCOPE_RETICLE 7201 + +#define IDC_SCREEN_OBJECT 8000 +#define IDC_SCREEN_GROUP 8001 +#define IDC_SCREEN_MENU_TEXT 8201 +#define IDC_SCREEN_TEXT_UPPER_LEFT 8202 +#define IDC_SCREEN_TEXT_UPPER_RIGHT 8203 +#define IDC_SCREEN_RETICLE 8204 + diff --git a/addons/xm157/sounds/click.wav b/addons/xm157/sounds/click.wav new file mode 100644 index 0000000000..efc08e62d1 Binary files /dev/null and b/addons/xm157/sounds/click.wav differ diff --git a/addons/xm157/stringtable.xml b/addons/xm157/stringtable.xml new file mode 100644 index 0000000000..761d11def9 --- /dev/null +++ b/addons/xm157/stringtable.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/docs/wiki/framework/xm157-framework.md b/docs/wiki/framework/xm157-framework.md new file mode 100644 index 0000000000..350dc55ed7 --- /dev/null +++ b/docs/wiki/framework/xm157-framework.md @@ -0,0 +1,56 @@ +--- +layout: wiki +title: XM157 Framework +description: Explains how to add the XM157 scope framework +group: framework +order: 5 +parent: wiki +mod: ace +version: + major: 5 + minor: 1 + patch: 0 +--- + +## 1. Config Values + + +```cpp +class CfgWeapons { + class ItemCore; + class InventoryOpticsItem_Base_F; + + class your_XM157: ItemCore { + class CBA_ScriptedOptic { + bodyTexture = "\z\ace\addons\xm157\data\ace_vector_body_co.paa"; + bodyTextureSize = 1; + hideMagnification = 1; + disableTilt = 0; + }; + weaponInfoType = "ace_xm157_info"; + class ItemInfo: InventoryOpticsItem_Base_F { + modelOptics = "\x\cba\addons\optics\cba_optic_big_100.p3d"; + class OpticsModes { + class optic { + opticsID=1; + useModelOptics=1; + opticsPPEffects[]={ "OpticsCHAbera1", "OpticsBlur1" }; + opticsZoomMin = "8 call (uiNamespace getVariable 'cba_optics_fnc_setOpticMagnificationHelper')"; + opticsZoomMax = "1 call (uiNamespace getVariable 'cba_optics_fnc_setOpticMagnificationHelper')"; + opticsZoomInit = "1 call (uiNamespace getVariable 'cba_optics_fnc_setOpticMagnificationHelper')"; + discreteDistance[] = {100}; + discreteDistanceInitIndex = 0; + distanceZoomMin=100; + distanceZoomMax=100; + memoryPointCamera="opticView"; + visionMode[] = {"Normal"}; + opticsFlare=1; + opticsDisablePeripherialVision=1; + cameraDir=""; + }; + }; + }; + }; +}; + +```