mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
XM157 (NGSW-FC Smart Scope) Framework (#8897)
* XM157 (NGSW-FC Smart Scope) * Update addons/common/functions/fnc_rscObjectHelper.sqf Co-authored-by: Jouni Järvinen <rautamiekka@users.noreply.github.com> * Update addons/xm157/functions/fnc_weaponInfo_draw.sqf Co-authored-by: Jouni Järvinen <rautamiekka@users.noreply.github.com> * Headers * Handle prone-deploy weapon bank * Disable Reticle picker for now * some localizations * Change font looks like CUP modifies EtelkaMonospaceProBold for some reason?? * Create xm157-framework.md * Formating Co-authored-by: Jouni Järvinen <rautamiekka@users.noreply.github.com>
This commit is contained in:
parent
77cf716e8b
commit
cc3bad3c56
@ -143,6 +143,7 @@ PREP(removeSpecificMagazine);
|
||||
PREP(requestCallback);
|
||||
PREP(resetAllDefaults);
|
||||
PREP(restoreVariablesJIP);
|
||||
PREP(rscObjectHelper);
|
||||
PREP(runAfterSettingsInit);
|
||||
PREP(runTests);
|
||||
PREP(sanitizeString);
|
||||
|
64
addons/common/functions/fnc_rscObjectHelper.sqf
Normal file
64
addons/common/functions/fnc_rscObjectHelper.sqf
Normal file
@ -0,0 +1,64 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: PabstMirror
|
||||
* Convert between screen and 3d object coordinates
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Function <STRING>
|
||||
* 1: Input array <CODE>
|
||||
* 2: Scale (optional: 1) <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* Value <ARRAY>
|
||||
*
|
||||
* 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
|
1
addons/xm157/$PBOPREFIX$
Normal file
1
addons/xm157/$PBOPREFIX$
Normal file
@ -0,0 +1 @@
|
||||
z\ace\addons\xm157
|
15
addons/xm157/CfgEventHandlers.hpp
Normal file
15
addons/xm157/CfgEventHandlers.hpp
Normal file
@ -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));
|
||||
};
|
||||
};
|
6
addons/xm157/CfgSounds.hpp
Normal file
6
addons/xm157/CfgSounds.hpp
Normal file
@ -0,0 +1,6 @@
|
||||
class CfgSounds {
|
||||
class GVAR(click) {
|
||||
sound[] = {QPATHTOF(sounds\click.wav), db-30, 3};
|
||||
titles[] = {};
|
||||
};
|
||||
};
|
48
addons/xm157/CfgWeapons.hpp
Normal file
48
addons/xm157/CfgWeapons.hpp
Normal file
@ -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 = "";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
2
addons/xm157/README.md
Normal file
2
addons/xm157/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
ace_xm157
|
||||
==========
|
79
addons/xm157/RscInGameUI.hpp
Normal file
79
addons/xm157/RscInGameUI.hpp
Normal file
@ -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;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
8
addons/xm157/XEH_PREP.hpp
Normal file
8
addons/xm157/XEH_PREP.hpp
Normal file
@ -0,0 +1,8 @@
|
||||
LOG("prep");
|
||||
|
||||
PREP(ballistics_calculator);
|
||||
PREP(ballistics_getData);
|
||||
PREP(keyPress);
|
||||
PREP(weaponInfo_draw);
|
||||
PREP(weaponInfo_drawMenu);
|
||||
PREP(weaponInfo_onLoad);
|
66
addons/xm157/XEH_postInit.sqf
Normal file
66
addons/xm157/XEH_postInit.sqf
Normal file
@ -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
|
9
addons/xm157/XEH_preInit.sqf
Normal file
9
addons/xm157/XEH_preInit.sqf
Normal file
@ -0,0 +1,9 @@
|
||||
#include "script_component.hpp"
|
||||
|
||||
ADDON = false;
|
||||
|
||||
PREP_RECOMPILE_START;
|
||||
#include "XEH_PREP.hpp"
|
||||
PREP_RECOMPILE_END;
|
||||
|
||||
ADDON = true;
|
3
addons/xm157/XEH_preStart.sqf
Normal file
3
addons/xm157/XEH_preStart.sqf
Normal file
@ -0,0 +1,3 @@
|
||||
#include "script_component.hpp"
|
||||
|
||||
#include "XEH_PREP.hpp"
|
27
addons/xm157/config.cpp
Normal file
27
addons/xm157/config.cpp
Normal file
@ -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;
|
||||
};
|
||||
};
|
BIN
addons/xm157/data/ace_vector_body_co.paa
Normal file
BIN
addons/xm157/data/ace_vector_body_co.paa
Normal file
Binary file not shown.
BIN
addons/xm157/data/mrad_10_ca.paa
Normal file
BIN
addons/xm157/data/mrad_10_ca.paa
Normal file
Binary file not shown.
BIN
addons/xm157/data/mrad_20_ca.paa
Normal file
BIN
addons/xm157/data/mrad_20_ca.paa
Normal file
Binary file not shown.
BIN
addons/xm157/data/mrad_40_ca.paa
Normal file
BIN
addons/xm157/data/mrad_40_ca.paa
Normal file
Binary file not shown.
178
addons/xm157/dev/generate_reticle.py
Normal file
178
addons/xm157/dev/generate_reticle.py
Normal file
@ -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}")
|
101
addons/xm157/functions/fnc_ballistics_calculator.sqf
Normal file
101
addons/xm157/functions/fnc_ballistics_calculator.sqf
Normal file
@ -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 <NUMBER>
|
||||
* 1: Direction of Fire (deg) - Yaw <NUMBER>
|
||||
* 2: Inlination (deg) - Pitch <NUMBER>
|
||||
* 3: Bank (deg) - Roll <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* Elevation and Windage in MRAD <ARRAY>
|
||||
*
|
||||
* 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
|
62
addons/xm157/functions/fnc_ballistics_getData.sqf
Normal file
62
addons/xm157/functions/fnc_ballistics_getData.sqf
Normal file
@ -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 <ARRAY>
|
||||
*
|
||||
* 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
|
67
addons/xm157/functions/fnc_keyPress.sqf
Normal file
67
addons/xm157/functions/fnc_keyPress.sqf
Normal file
@ -0,0 +1,67 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: PabstMirror
|
||||
* Handles key presses
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Type <STRING>
|
||||
* 1: IsKeyDown <BOOL>
|
||||
*
|
||||
* Return Value:
|
||||
* Handled <BOOL>
|
||||
*
|
||||
* 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
|
144
addons/xm157/functions/fnc_weaponInfo_draw.sqf
Normal file
144
addons/xm157/functions/fnc_weaponInfo_draw.sqf
Normal file
@ -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);
|
81
addons/xm157/functions/fnc_weaponInfo_drawMenu.sqf
Normal file
81
addons/xm157/functions/fnc_weaponInfo_drawMenu.sqf
Normal file
@ -0,0 +1,81 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: PabstMirror
|
||||
* Updates the menu display
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Display <DISPLAY>
|
||||
* 1: Menu Item Needs Updating <BOOL>
|
||||
*
|
||||
* 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];
|
83
addons/xm157/functions/fnc_weaponInfo_onLoad.sqf
Normal file
83
addons/xm157/functions/fnc_weaponInfo_onLoad.sqf
Normal file
@ -0,0 +1,83 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: PabstMirror
|
||||
* Creates UI
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Display <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]];
|
1
addons/xm157/functions/script_component.hpp
Normal file
1
addons/xm157/functions/script_component.hpp
Normal file
@ -0,0 +1 @@
|
||||
#include "\z\ace\addons\xm157\script_component.hpp"
|
24
addons/xm157/script_component.hpp
Normal file
24
addons/xm157/script_component.hpp
Normal file
@ -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
|
||||
|
BIN
addons/xm157/sounds/click.wav
Normal file
BIN
addons/xm157/sounds/click.wav
Normal file
Binary file not shown.
5
addons/xm157/stringtable.xml
Normal file
5
addons/xm157/stringtable.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project name="ACE">
|
||||
<Package name="XM157">
|
||||
</Package>
|
||||
</Project>
|
56
docs/wiki/framework/xm157-framework.md
Normal file
56
docs/wiki/framework/xm157-framework.md
Normal file
@ -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="";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
```
|
Loading…
Reference in New Issue
Block a user