Merge remote-tracking branch 'upstream/master' into corpse-carry-continued2

This commit is contained in:
LinkIsGrim 2024-01-08 03:47:11 -03:00
commit 68f9ea2d2f
37 changed files with 1423 additions and 192 deletions

View File

@ -41,7 +41,11 @@ if (_initSpeedCoef > 0) then {
};
private _abAdjustText = "";
if (_magIsForCurrentWeapon && {["ace_advanced_ballistics"] call EFUNC(common,isModLoaded)}) then {
if (
_magIsForCurrentWeapon &&
{missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]} &&
{missionNamespace getVariable [QEGVAR(advanced_ballistics,barrelLengthInfluenceEnabled), false]} // this can be on while AB is off or vice-versa
) then {
private _configAmmo = (configFile >> "CfgAmmo" >> (getText (_configMagazine >> "ammo")));
private _barrelLength = getNumber (_configWeapon >> "ACE_barrelLength");
private _muzzleVelocityTable = getArray (_configAmmo >> "ACE_muzzleVelocities");

View File

@ -37,7 +37,10 @@ if (_magazine isEqualTo "") then {
};
private _abAdjustText = "";
if (["ace_advanced_ballistics"] call EFUNC(common,isModLoaded)) then {
if (
missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false] &&
{missionNamespace getVariable [QEGVAR(advanced_ballistics,barrelLengthInfluenceEnabled), false]} // this can be on while AB is off or vice-versa
) then {
private _configAmmo = (configFile >> "CfgAmmo" >> (getText (_configMagazine >> "ammo")));
private _barrelLength = getNumber (_configWeapon >> "ACE_barrelLength");
private _muzzleVelocityTable = getArray (_configAmmo >> "ACE_muzzleVelocities");

View File

@ -1,7 +1,8 @@
#include "..\script_component.hpp"
#include "\a3\ui_f_curator\ui\defineResinclDesign.inc"
#include "\a3\ui_f\hpp\defineDIKCodes.inc"
/*
* Author: commy2
* Author: commy2, johnb43
* Disables key input. ESC can still be pressed to open the menu.
*
* Arguments:
@ -27,7 +28,7 @@ if (_state) then {
if (!isNull (uiNamespace getVariable [QGVAR(dlgDisableMouse), displayNull])) exitWith {};
if (!isNil QGVAR(disableInputPFH)) exitWith {};
// end TFAR and ACRE2 radio transmissions
// End TFAR and ACRE2 radio transmissions
call FUNC(endRadioTransmission);
// Close map
@ -45,38 +46,120 @@ if (_state) then {
private _map = _display displayCtrl 101;
_map ctrlMapCursor ["", QGVAR(blank)];
GVAR(keyboardInputMain) = createHashMap;
GVAR(keyboardInputCombo) = createHashMap;
_display displayAddEventHandler ["KeyDown", {
// If input is enabled again, ignore
if (isNil QGVAR(keyboardInputMain)) exitWith {};
params ["", "_key"];
if (_key == 1 && {alive player}) then {
createDialog (["RscDisplayInterrupt", "RscDisplayMPInterrupt"] select isMultiplayer);
// Get key info; Stored as [isPressed, pressedCount]
private _keyPressedInfo = GVAR(keyboardInputMain) getOrDefault [_key, [false, 0], true];
_keyPressedInfo params ["_keyPressed", "_keyPressedCount"];
// For regular keys: If pressed, set to release and remove one key press
if (!_keyPressed) then {
_keyPressedInfo set [0, true];
_keyPressedInfo set [1, _keyPressedCount + 1];
};
// For combo keys, register only if pushed or released (no keypress count)
if !(GVAR(keyboardInputCombo) getOrDefault [_key, false]) then {
GVAR(keyboardInputCombo) set [_key, true];
};
// Look if keybinds of various actions have been pressed
private _action = "";
private _comboDikPressed = false;
private _return = false;
// This technique has a limitation: It can't process the Escape key properly (KeyUp EH does not fire)
(["TeamSwitch", "CuratorInterface", "ShowMap", "DefaultAction", "Throw", "Chat", "PrevChannel", "NextChannel"] apply {
_action = _x;
{
_x params ["_mainKeyArray", "_comboKeyArray", "_isDoubleTap"];
_mainKeyArray params ["_mainDik", "_mainDevice"];
// If keybind doesn't contain key combo, it returns empty array; Therefore, return true
_comboDikPressed = if (_comboKeyArray isEqualTo []) then {
true
} else {
_comboKeyArray params ["_comboDik", "_comboDevice"];
_comboDevice == "KEYBOARD" && {GVAR(keyboardInputCombo) getOrDefault [_comboDik, false]}
};
// Check if the necessary keys were pressed for a keybind
_return = _comboDikPressed &&
{_mainDevice == "KEYBOARD"} &&
{((GVAR(keyboardInputMain) getOrDefault [_mainDik, [false, 0]]) select 1) > ([0, 1] select _isDoubleTap)}; // check how many times the main key was pressed
// Keybind was detected
if (_return) exitWith {
TRACE_1("Action triggered: ",_action);
};
} forEach (actionKeysEx _action);
_return
}) params ["_teamSwitch", "_curatorInterface", "_showMap", "_defaultAction", "_throw", "_chat", "_prevChannel", "_nextChannel"];
// Handle Escape separately because of limitation mentioned above
if (_key == DIK_ESCAPE && {alive player}) then {
disableSerialization;
private _isMultiplayer = isMultiplayer;
private _is3DENPreview = is3DENPreview;
createDialog (["RscDisplayInterrupt", "RscDisplayMPInterrupt"] select _isMultiplayer);
private _dlg = findDisplay 49;
for "_index" from 100 to 2000 do {
(_dlg displayCtrl _index) ctrlEnable false;
};
private _ctrl = _dlg displayctrl 103;
_ctrl ctrlSetEventHandler ["buttonClick", QUOTE(while {!isNull (uiNamespace getVariable [ARR_2(QUOTE(QGVAR(dlgDisableMouse)),displayNull)])} do {closeDialog 0}; failMission 'LOSER'; [false] call DFUNC(disableUserInput))];
_ctrl ctrlEnable true;
_ctrl ctrlSetText "ABORT";
_ctrl ctrlSetTooltip "Abort.";
private _ctrl = _dlg displayCtrl 103;
_ctrl ctrlSetEventHandler ["ButtonClick", toString {
while {!isNull (uiNamespace getVariable [QGVAR(dlgDisableMouse), displayNull])} do {
closeDialog 0
};
_ctrl = _dlg displayctrl ([104, 1010] select isMultiplayer);
if (["ace_medical"] call FUNC(isModLoaded)) then {
_ctrl ctrlSetEventHandler ["buttonClick", 'closeDialog 0; [player, "respawn_button"] call EFUNC(medical_status,setDead); [false] call DFUNC(disableUserInput);'];
} else {
_ctrl ctrlSetEventHandler ["buttonClick", QUOTE(closeDialog 0; player setDamage 1; [false] call DFUNC(disableUserInput))];
};
_ctrl ctrlEnable ((getMissionConfigValue ["respawnButton", -1]) != 0); // handles 3den attribute or description.ext
_ctrl ctrlSetText localize "$str_3den_multiplayer_attributecategory_respawn_displayname";
_ctrl ctrlSetTooltip "Respawn.";
failMission "LOSER";
[false] call FUNC(disableUserInput);
}];
_ctrl ctrlEnable true;
_ctrl ctrlSetText localize (["str_disp_int_abort", "STR_3DEN_RscDisplayInterrupt_ButtonAbort_3DEN_text"] select (_is3DENPreview && !_isMultiplayer));
_ctrl ctrlSetTooltip localize ([
"STR_TOOLTIP_MAIN_ABORT_CAMPAIGN",
"STR_3DEN_RscDisplayInterrupt_ButtonAbort_3DEN_tooltip",
"STR_TOOLTIP_MAIN_ABORT"
] select (([_is3DENPreview, _isMultiplayer] call FUNC(toBitmask)) min 2));
_ctrl = _dlg displayCtrl ([104, 1010] select _isMultiplayer);
_ctrl ctrlSetEventHandler ["ButtonClick", toString {
closeDialog 0;
if (["ace_medical"] call FUNC(isModLoaded)) then {
[player, "respawn_button"] call EFUNC(medical_status,setDead);
} else {
player setDamage 1;
};
[false] call FUNC(disableUserInput);
}];
private _respawnEnabled = (getMissionConfigValue ["respawnButton", -1]) != 0;
_ctrl ctrlEnable _respawnEnabled; // handles 3den attribute or description.ext
_ctrl ctrlSetText localize "str_disp_int_respawn";
_ctrl ctrlSetTooltip localize (["str_3den_attributes_respawn_none_tooltip", "str_disp_int_respawn"] select _respawnEnabled);
};
if (_key in actionKeys "TeamSwitch" && {teamSwitchEnabled}) then {
if (_teamSwitch && teamSwitchEnabled) then {
(uiNamespace getVariable [QGVAR(dlgDisableMouse), displayNull]) closeDisplay 0;
private _acc = accTime;
@ -84,18 +167,20 @@ if (_state) then {
setAccTime _acc;
};
if (_key in actionKeys "CuratorInterface" && {getAssignedCuratorLogic player in allCurators}) then {
if (_curatorInterface && {!isNull getAssignedCuratorLogic player}) then {
(uiNamespace getVariable [QGVAR(dlgDisableMouse), displayNull]) closeDisplay 0;
openCuratorInterface;
};
if (_key in actionKeys "ShowMap" && {player getVariable ["ACE_canSwitchUnits", false]}) then {
if (_showMap && {player getVariable ["ACE_canSwitchUnits", false]}) then {
(uiNamespace getVariable [QGVAR(dlgDisableMouse), displayNull]) closeDisplay 0;
openMap true;
};
if (isServer || {serverCommandAvailable "#kick"}) then {
if (!(_key in (actionKeys "DefaultAction" + actionKeys "Throw")) && {_key in (actionKeys "Chat" + actionKeys "PrevChannel" + actionKeys "NextChannel")}) then {
if (isMultiplayer && {isServer || {serverCommandAvailable "#kick"}}) then {
if (!(_defaultAction || _throw) && {_chat || _prevChannel || _nextChannel}) then {
_key = 0;
};
};
@ -103,7 +188,41 @@ if (_state) then {
_key > 0
}];
_display displayAddEventHandler ["KeyUp", {true}];
_display displayAddEventHandler ["KeyUp", {
// If input is enabled again, ignore
if (isNil QGVAR(keyboardInputMain)) exitWith {};
params ["", "_key"];
// For combo keys: If pressed, release
if (GVAR(keyboardInputCombo) getOrDefault [_key, false]) then {
GVAR(keyboardInputCombo) deleteAt _key;
};
private _keyPressedInfo = GVAR(keyboardInputMain) getOrDefault [_key, [false, 0]];
// If pressed, release it
if (_keyPressedInfo select 0) then {
_keyPressedInfo set [0, false];
};
// Cache keystrokes of regular keys for a small amount of time
[{
// If input is enabled again, ignore
if (isNil QGVAR(keyboardInputMain)) exitWith {};
params ["_key"];
private _keyPressedInfo = GVAR(keyboardInputMain) getOrDefault [_key, [false, 0]];
// Release it
_keyPressedInfo set [1, ((_keyPressedInfo select 1) - 1) max 0];
if (_keyPressedInfo isEqualTo [false, 0]) then {
GVAR(keyboardInputMain) deleteAt _key,
};
}, _key, 0.5] call CBA_fnc_waitAndExecute;
}];
};
GVAR(disableInputPFH) = [{
@ -133,4 +252,7 @@ if (_state) then {
};
(uiNamespace getVariable [QGVAR(dlgDisableMouse), displayNull]) closeDisplay 0;
GVAR(keyboardInputMain) = nil;
GVAR(keyboardInputCombo) = nil;
};

View File

@ -15,6 +15,8 @@
* Public: No
*/
#define TEMPERATURE_SLOT_INDEX 5
private _playerDir = getDir ACE_player;
private _playerAltitude = (getPosASL ACE_player) select 2;
private _temperature = _playerAltitude call EFUNC(weather,calculateTemperatureAtHeight);
@ -41,9 +43,10 @@ if (isNil QGVAR(MIN) || isNil QGVAR(MAX)) then {
[0, _playerDir] call FUNC(updateMemory);
if (GVAR(MinAvgMaxMode) == 1) then {
private _useAB = missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false];
{
GVAR(ENTRIES) set [_x, (GVAR(ENTRIES) select _x) + 1];
} count [2, 3, 4];
} forEach [2, 3, 4];
// Wind SPD
private _windSpeed = call FUNC(measureWindSpeed);
@ -51,7 +54,7 @@ if (GVAR(MinAvgMaxMode) == 1) then {
// CROSSWIND
private _crosswind = 0;
if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then {
if (_useAB) then {
_crosswind = abs(sin(GVAR(RefHeading) - _playerDir) * _windSpeed);
} else {
_crosswind = abs(sin(GVAR(RefHeading)) * _windSpeed);
@ -60,7 +63,7 @@ if (GVAR(MinAvgMaxMode) == 1) then {
// HEADWIND
private _headwind = 0;
if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then {
if (_useAB) then {
_headwind = cos(GVAR(RefHeading) - _playerDir) * _windSpeed;
} else {
_headwind = cos(GVAR(RefHeading)) * _windSpeed;
@ -74,4 +77,18 @@ if (GVAR(MinAvgMaxMode) == 1) then {
GVAR(TOTAL) set [4, (GVAR(TOTAL) select 4) + _headwind];
};
{ _x call FUNC(updateMemory); true } count [[5, _temperature],[6, _chill],[7, _humidity],[8, _heatIndex],[9, _dewPoint],[10, _wetBulb],[11, _barometricPressure],[12, _altitude],[13, _densityAltitude]];
private _data = [
_temperature,
_chill,
_humidity,
_heatIndex,
_dewPoint,
_wetBulb,
_barometricPressure,
_altitude,
_densityAltitude
];
{
[TEMPERATURE_SLOT_INDEX + _forEachIndex, _x] call FUNC(updateMemory);
} forEach _data;

View File

@ -99,7 +99,11 @@
#define TYPE_SCUBA 604 // not implemented
#define TYPE_HEADGEAR 605
#define TYPE_FACTOR 607
#define TYPE_MAP 608
#define TYPE_COMPASS 609
#define TYPE_WATCH 610
#define TYPE_RADIO 611
#define TYPE_GPS 612
#define TYPE_HMD 616
#define TYPE_BINOCULAR 617
#define TYPE_MEDIKIT 619

View File

@ -1,62 +1,204 @@
#define EXCEPTIONS exceptions[] = {"isNotDragging", "notOnMap", "isNotInside", "isNotSitting"}
class CfgVehicles {
class Man;
class CAManBase: Man {
class ACE_SelfActions {
class ACE_MapGpsShow {
displayName = CSTRING(MapGpsShow);
condition = QUOTE((!GVAR(mapGpsShow)) && {call FUNC(canUseMapGPS)});
statement = QUOTE(GVAR(mapGpsShow) = true;);
exceptions[] = {"isNotDragging", "notOnMap", "isNotInside", "isNotSitting"};
condition = QUOTE(!GVAR(mapGpsShow) && {call FUNC(canUseMapGPS)});
statement = QUOTE(GVAR(mapGpsShow) = true);
EXCEPTIONS;
showDisabled = 0;
};
class ACE_MapGpsHide {
displayName = CSTRING(MapGpsHide);
condition = QUOTE((GVAR(mapGpsShow)) && {call FUNC(canUseMapGPS)});
statement = QUOTE(GVAR(mapGpsShow) = false;);
exceptions[] = {"isNotDragging", "notOnMap", "isNotInside", "isNotSitting"};
condition = QUOTE(GVAR(mapGpsShow) && {call FUNC(canUseMapGPS)});
statement = QUOTE(GVAR(mapGpsShow) = false);
EXCEPTIONS;
showDisabled = 0;
};
class ACE_MapTools {
displayName = CSTRING(MapTools_Menu);
condition = QUOTE(call FUNC(canUseMapTools));
statement = "";
exceptions[] = {"isNotDragging", "notOnMap", "isNotInside", "isNotSitting"};
EXCEPTIONS;
showDisabled = 0;
class ACE_MapToolsHide {
displayName = CSTRING(MapToolsHide);
condition = QUOTE(GVAR(mapTool_Shown) != 0);
statement = QUOTE(GVAR(mapTool_Shown) = 0;);
exceptions[] = {"isNotDragging", "notOnMap", "isNotInside", "isNotSitting"};
statement = QUOTE(GVAR(mapTool_Shown) = 0);
EXCEPTIONS;
showDisabled = 1;
};
class ACE_MapToolsShowNormal {
displayName = CSTRING(MapToolsShowNormal);
condition = QUOTE(GVAR(mapTool_Shown) != 1);
statement = QUOTE(if (GVAR(mapTool_Shown) == 0) then {GVAR(mapTool_moveToMouse) = true}; GVAR(mapTool_Shown) = 1;);
exceptions[] = {"isNotDragging", "notOnMap", "isNotInside", "isNotSitting"};
statement = QUOTE(if (GVAR(mapTool_Shown) == 0) then {GVAR(mapTool_moveToMouse) = true}; GVAR(mapTool_Shown) = 1);
EXCEPTIONS;
showDisabled = 1;
};
class ACE_MapToolsShowSmall {
displayName = CSTRING(MapToolsShowSmall);
condition = QUOTE(GVAR(mapTool_Shown) != 2);
statement = QUOTE(if (GVAR(mapTool_Shown) == 0) then {GVAR(mapTool_moveToMouse) = true}; GVAR(mapTool_Shown) = 2;);
exceptions[] = {"isNotDragging", "notOnMap", "isNotInside", "isNotSitting"};
statement = QUOTE(if (GVAR(mapTool_Shown) == 0) then {GVAR(mapTool_moveToMouse) = true}; GVAR(mapTool_Shown) = 2);
EXCEPTIONS;
showDisabled = 1;
};
class ACE_MapToolsAlignNorth {
displayName = CSTRING(MapToolsAlignNorth);
class ACE_MapToolsAlign {
displayName = CSTRING(AlignTo);
condition = QUOTE(GVAR(mapTool_Shown) != 0);
statement = QUOTE(GVAR(mapTool_angle) = 0;);
exceptions[] = {"isNotDragging", "notOnMap", "isNotInside", "isNotSitting"};
statement = "";
EXCEPTIONS;
showDisabled = 0;
class ACE_MapToolsAlignToPlottingBoardRuler {
displayName = CSTRING(ToPlottingBoardRulerLabel);
condition = QUOTE(GVAR(mapTool_Shown) != 0 && GVAR(plottingBoard_Shown) == 2);
statement = QUOTE(GVAR(mapTool_angle) = GVAR(plottingBoard_rulerAngle));
EXCEPTIONS;
showDisabled = 1;
};
class ACE_MapToolsAlignToPlottingBoardAcrylic {
displayName = CSTRING(ToPlottingBoardAcrylicLabel);
condition = QUOTE(GVAR(mapTool_Shown) != 0 && GVAR(plottingBoard_Shown) != 0);
statement = QUOTE(GVAR(mapTool_angle) = GVAR(plottingBoard_acrylicAngle));
EXCEPTIONS;
showDisabled = 1;
};
class ACE_MapToolsAlignToPlottingBoard {
displayName = CSTRING(ToPlottingBoardLabel);
condition = QUOTE(GVAR(mapTool_Shown) != 0 && GVAR(plottingBoard_Shown) != 0);
statement = QUOTE(GVAR(mapTool_angle) = GVAR(plottingBoard_angle));
EXCEPTIONS;
showDisabled = 1;
};
class ACE_MapToolsAlignCompass {
displayName = CSTRING(ToCompassLabel);
condition = QUOTE(GVAR(mapTool_Shown) != 0 && {ACE_player getSlotItemName TYPE_COMPASS != ''});
statement = QUOTE(GVAR(mapTool_angle) = getDir ACE_player);
EXCEPTIONS;
showDisabled = 1;
};
class ACE_MapToolsAlignNorth {
displayName = CSTRING(ToNorthLabel);
condition = QUOTE(GVAR(mapTool_Shown) != 0);
statement = QUOTE(GVAR(mapTool_angle) = 0);
EXCEPTIONS;
showDisabled = 1;
};
};
};
class ACE_PlottingBoard {
displayName = CSTRING(ShowPlottingBoard);
condition = QUOTE(GVAR(plottingBoard_Shown) < 1 && {call FUNC(canUsePlottingBoard)});
statement = QUOTE(GVAR(plottingBoard_Shown) = 1);
EXCEPTIONS;
showDisabled = 0;
};
class ACE_PlottingBoardHide {
displayName = CSTRING(HidePlottingBoard);
condition = QUOTE(GVAR(plottingBoard_Shown) != 0 && {call FUNC(canUsePlottingBoard)});
statement = QUOTE(GVAR(plottingBoard_Shown) = 0);
EXCEPTIONS;
showDisabled = 0;
class ACE_PlottingBoardRulerShow {
displayName = CSTRING(TogglePlottingBoardRuler);
condition = QUOTE(GVAR(plottingBoard_Shown) == 1);
statement = QUOTE(GVAR(plottingBoard_Shown) = 2);
EXCEPTIONS;
showDisabled = 1;
};
class ACE_MapToolsAlignCompass {
displayName = CSTRING(MapToolsAlignCompass);
condition = QUOTE(GVAR(mapTool_Shown) != 0 && {getUnitLoadout ACE_player param [ARR_2(9,[])] param [ARR_2(3,'')] != ''});
statement = QUOTE(GVAR(mapTool_angle) = getDir ACE_player;);
exceptions[] = {"isNotDragging", "notOnMap", "isNotInside", "isNotSitting"};
class ACE_PlottingBoardRulerHide {
displayName = CSTRING(TogglePlottingBoardRuler);
condition = QUOTE(GVAR(plottingBoard_Shown) == 2);
statement = QUOTE(GVAR(plottingBoard_Shown) = 1);
EXCEPTIONS;
showDisabled = 1;
};
class ACE_PlottingBoardWipe {
displayName = CSTRING(WipeBoard);
condition = QUOTE(GVAR(plottingBoard_markers) isNotEqualTo createHashMap);
statement = QUOTE(call FUNC(wipeMarkers));
EXCEPTIONS;
showDisabled = 1;
};
class ACE_PlottingBoardAlign {
displayName = CSTRING(AlignTo);
condition = QUOTE(GVAR(plottingBoard_Shown) > 0);
statement = "";
EXCEPTIONS;
showDisabled = 0;
class ACE_PlottingBoardAlignBoard {
displayName = CSTRING(PlottingBoardLabel);
condition = QUOTE(true);
statement = "";
EXCEPTIONS;
showDisabled = 0;
class ACE_PlottingBoardAlignBoardMaptool {
displayName = CSTRING(Name);
condition = QUOTE(GVAR(mapTool_Shown) > 0 && GVAR(plottingBoard_angle) != GVAR(mapTool_angle));
statement = QUOTE(GVAR(plottingBoard_angle) = GVAR(mapTool_angle));
EXCEPTIONS;
showDisabled = 0;
};
class ACE_PlottingBoardAlignBoardUp {
displayName = CSTRING(ToUpLabel);
condition = QUOTE(GVAR(plottingBoard_angle) != 0);
statement = QUOTE(GVAR(plottingBoard_angle) = 0);
EXCEPTIONS;
showDisabled = 0;
};
};
class ACE_PlottingBoardAlignAcrylic {
displayName = CSTRING(PlottingBoardAcrylicLabel);
condition = QUOTE(true);
statement = "";
EXCEPTIONS;
showDisabled = 0;
class ACE_PlottingBoardAlignAcrylicMaptool {
displayName = CSTRING(Name);
condition = QUOTE(GVAR(mapTool_Shown) > 0 && GVAR(plottingBoard_acrylicAngle) != GVAR(mapTool_angle));
statement = QUOTE(GVAR(plottingBoard_acrylicAngle) = GVAR(mapTool_angle));
EXCEPTIONS;
showDisabled = 0;
};
class ACE_PlottingBoardAlignAcrylicUp {
displayName = CSTRING(ToUpLabel);
condition = QUOTE(GVAR(plottingBoard_acrylicAngle) != 0);
statement = QUOTE(GVAR(plottingBoard_acrylicAngle) = 0);
EXCEPTIONS;
showDisabled = 0;
};
};
class ACE_PlottingBoardAlignRuler {
displayName = CSTRING(PlottingBoardRulerLabel);
condition = QUOTE(GVAR(plottingBoard_Shown) == 2);
statement = "";
EXCEPTIONS;
showDisabled = 0;
class ACE_PlottingBoardAlignRulerMaptool {
displayName = CSTRING(Name);
condition = QUOTE(GVAR(mapTool_Shown) > 0 && GVAR(plottingBoard_rulerAngle) != GVAR(mapTool_angle));
statement = QUOTE(GVAR(plottingBoard_rulerAngle) = GVAR(mapTool_angle));
EXCEPTIONS;
showDisabled = 0;
};
class ACE_PlottingBoardAlignRulerUp {
displayName = CSTRING(ToUpLabel);
condition = QUOTE(GVAR(plottingBoard_rulerAngle) != 0);
statement = QUOTE(GVAR(plottingBoard_rulerAngle) = 0);
EXCEPTIONS;
showDisabled = 0;
};
};
};
};
};
};
@ -69,30 +211,35 @@ class CfgVehicles {
class Box_NATO_Support_F: NATO_Box_Base {
class TransportItems {
MACRO_ADDITEM(ACE_MapTools,12);
MACRO_ADDITEM(ACE_PlottingBoard,12);
};
};
class Box_East_Support_F: EAST_Box_Base {
class TransportItems {
MACRO_ADDITEM(ACE_MapTools,12);
MACRO_ADDITEM(ACE_PlottingBoard,12);
};
};
class Box_IND_Support_F: IND_Box_Base {
class TransportItems {
MACRO_ADDITEM(ACE_MapTools,12);
MACRO_ADDITEM(ACE_PlottingBoard,12);
};
};
class Box_FIA_Support_F: FIA_Box_Base_F {
class TransportItems {
MACRO_ADDITEM(ACE_MapTools,12);
MACRO_ADDITEM(ACE_PlottingBoard,12);
};
};
class ACE_Box_Misc: Box_NATO_Support_F {
class TransportItems {
MACRO_ADDITEM(ACE_MapTools,12);
MACRO_ADDITEM(ACE_PlottingBoard,12);
};
};
};

View File

@ -14,4 +14,17 @@ class CfgWeapons {
mass = 0.2;
};
};
class ACE_PlottingBoard: ACE_ItemCore {
displayName = CSTRING(PlottingBoard_Name);
author = ECSTRING(common,ACETeam);
descriptionShort = CSTRING(Description);
model = QPATHTOF(data\ace_MapTools.p3d);
picture = QPATHTOF(UI\plottingboard_item.paa);
scope = 2;
ACE_isTool = 1;
class ItemInfo: CBA_MiscItem_ItemInfo {
mass = 0.5;
};
};
};

View File

@ -5,3 +5,4 @@ Adds the following map tools:
- Roamer
- Map drawing
- Showing GPS on map
- Plotting Board

Binary file not shown.

View File

@ -7,3 +7,8 @@ PREP(handleMouseMove);
PREP(isInsideMapTool);
PREP(openMapGpsUpdate);
PREP(updateMapToolMarkers);
PREP(canUsePlottingBoard);
PREP(isInsidePlottingBoard);
PREP(handlePlottingBoardMarkers);
PREP(wipeMarkers);

View File

@ -1,4 +1,4 @@
// by esteldunedain
// by esteldunedain, LorenLuke
#include "script_component.hpp"
@ -9,12 +9,22 @@ GVAR(mapGpsShow) = true;
GVAR(mapGpsNextUpdate) = -1;
GVAR(mapTool_Shown) = 0;
GVAR(mapTool_pos) = [0,0];
GVAR(mapTool_pos) = [0, 0];
GVAR(mapTool_angle) = 0;
GVAR(mapTool_isDragging) = false;
GVAR(mapTool_isRotating) = false;
GVAR(mapTool_moveToMouse) = true; // used to display it in center of screen when opened
GVAR(plottingBoard_Shown) = 0;
GVAR(plottingBoard_pos) = [0, 0];
GVAR(plottingBoard_angle) = 0;
GVAR(plottingBoard_acrylicAngle) = 0;
GVAR(plottingBoard_rulerAngle) = 0;
GVAR(plottingBoard_isDragging) = false;
GVAR(plottingBoard_isRotating) = -1;
GVAR(plottingBoard_moveToMouse) = true; // used to display it in center of screen when opened
GVAR(plottingBoard_markers) = createHashMap;
//Install the event handers for the map tools on the main in-game map
[{!isNull findDisplay 12},
{
@ -32,7 +42,13 @@ GVAR(mapTool_moveToMouse) = true; // used to display it in center of screen whe
};
}] call CBA_fnc_addPlayerEventHandler;
addMissionEventHandler ["MarkerCreated", {
[_this, false] call FUNC(handlePlottingBoardMarkers);
}];
addMissionEventHandler ["MarkerDeleted", {
[[_this select 0, -1, objNull, _this select 1], true] call FUNC(handlePlottingBoardMarkers);
}];
GVAR(freeDrawingData) = [];
GVAR(freedrawing) = false;

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,22 @@
#include "..\script_component.hpp"
/*
* Author: LorenLuke
* Returns if the plotting board can be used.
*
* Arguments:
* None
*
* Return Value:
* Plotting board can be used <BOOL>
*
* Example:
* call ace_maptools_fnc_canUsePlottingBoard
*
* Public: No
*/
visibleMap &&
{alive ACE_player} &&
{[ACE_player, "ACE_PlottingBoard"] call EFUNC(common,hasItem)} &&
{!GVAR(plottingBoard_isDragging)} &&
{GVAR(plottingBoard_isRotating) == -1}

View File

@ -1,17 +1,17 @@
#include "..\script_component.hpp"
/*
* Author: esteldunedain
* Author: esteldunedain, LorenLuke
* Handle mouse buttons.
*
* Arguments:
* 0: 1 if mouse down down, 0 if mouse button up <Number>
* 0: 1 if mouse down down, 0 if mouse button up <NUMBER>
* 1: Parameters of the mouse button event <ARRAY>
*
* Return Value:
* true if event was handled <BOOL>
* True if event was handled <BOOL>
*
* Example:
* [0, [array]] call ACE_maptools_fnc_handleMouseButton
* [0, []] call ace_maptools_fnc_handleMouseButton
*
* Public: No
*/
@ -24,20 +24,27 @@ TRACE_2("params",_dir,_params);
if ((_button == 0) && {GVAR(freedrawing) || _ctrlKey}) exitWith {
if (GVAR(freedrawing) && {_dir == 0}) then {
GVAR(freedrawing) = false;
if (_shiftKey) exitWith {
TRACE_1("using vanilla straight line",_shiftKey);
};
TRACE_2("Ending Line",GVAR(freedrawing),GVAR(freeDrawingData));
[{
if (allMapMarkers isEqualTo []) exitWith {};
private _markerName = allMapMarkers select (count allMapMarkers - 1);
if (GVAR(freeDrawingData) isEqualTo []) exitWith {TRACE_1("never touched roamer",GVAR(freeDrawingData))};
private _allMarkers = allMapMarkers;
if (_allMarkers isEqualTo []) exitWith {};
private _markerName = _allMarkers select -1;
private _markerPos = getMarkerPos _markerName;
private _distanceCheck = _markerPos distance2d GVAR(drawPosStart);
private _distanceCheck = _markerPos distance2D GVAR(drawPosStart);
TRACE_3("Line Drawn",_markerName,_markerPos,_distanceCheck);
if (_distanceCheck > 1) exitWith {WARNING("Wrong Marker!");};
if ((count GVAR(freeDrawingData)) != 3) exitWith {TRACE_1("never touched roamer",GVAR(freeDrawingData));};
if (_distanceCheck > 1) exitWith {WARNING("Wrong Marker!")};
GVAR(freeDrawingData) params ["", "_startStraightPos", "_endStraightPos"];
@ -54,17 +61,20 @@ if ((_button == 0) && {GVAR(freedrawing) || _ctrlKey}) exitWith {
TRACE_2("Starting Line",GVAR(freedrawing),GVAR(drawPosStart));
} else {
GVAR(freedrawing) = false;
TRACE_1("weird - reseting",GVAR(freedrawing));
TRACE_1("weird - resetting",GVAR(freedrawing));
};
};
false
false // return
};
// If it's not a left button event, exit
if (_button != 0) exitWith {
false // return
};
private _handled = false;
// If it's not a left button event, exit
if (_button != 0) exitWith {_handled};
// If releasing
if (_dir != 1) then {
if (GVAR(mapTool_isDragging) || GVAR(mapTool_isRotating)) then {
@ -72,44 +82,98 @@ if (_dir != 1) then {
GVAR(mapTool_isRotating) = false;
_handled = true;
};
if (GVAR(plottingBoard_isDragging) || GVAR(plottingBoard_isRotating) > -1) then {
GVAR(plottingBoard_isDragging) = false;
GVAR(plottingBoard_isRotating) = -1;
_handled = true;
};
} else {
// If clicking
if !(call FUNC(canUseMapTools)) exitWith {};
if (call FUNC(canUseMapTools)) then {
GVAR(mapTool_isDragging) = false;
GVAR(mapTool_isRotating) = false;
// Transform mouse screen position to coordinates
private _pos = _control ctrlMapScreenToWorld [_screenPosX, _screenPosY];
_pos set [count _pos, 0];
// If no map tool marker then exit
if (GVAR(mapTool_Shown) != 0) then {
// Transform mouse screen position to coordinates
private _pos = _control ctrlMapScreenToWorld [_screenPosX, _screenPosY];
GVAR(mapTool_isDragging) = false;
GVAR(mapTool_isRotating) = false;
// Check if clicking the maptool
if (_pos call FUNC(isInsideMapTool)) then {
// Store data for dragging
GVAR(mapTool_startPos) = +GVAR(mapTool_pos);
GVAR(mapTool_startDragPos) = _pos;
// If no map tool marker then exit
if (GVAR(mapTool_Shown) == 0) exitWith {};
private _rotateKeyPressed = switch (GVAR(rotateModifierKey)) do {
case 1: {_altKey};
case 2: {_ctrlKey};
case 3: {_shiftKey};
default {false};
};
// Check if clicking the maptool
if (_pos call FUNC(isInsideMapTool)) exitWith {
// Store data for dragging
GVAR(mapTool_startPos) = + GVAR(mapTool_pos);
GVAR(mapTool_startDragPos) = + _pos;
if (_rotateKeyPressed) then {
// Store data for rotating
GVAR(mapTool_startAngle) = GVAR(mapTool_angle);
private _rotateKeyPressed = switch (GVAR(rotateModifierKey)) do {
case (1): {_altKey};
case (2): {_ctrlKey};
case (3): {_shiftKey};
default {false};
private _pos = GVAR(mapTool_startDragPos) vectorDiff GVAR(mapTool_startPos);
GVAR(mapTool_startDragAngle) = ((_pos select 0) atan2 (_pos select 1) + 360) % 360;
// Start rotating
GVAR(mapTool_isRotating) = true;
} else {
// Start dragging
GVAR(mapTool_isDragging) = true;
};
_handled = true;
};
};
};
if (_rotateKeyPressed) then {
// Store data for rotating
GVAR(mapTool_startAngle) = + GVAR(mapTool_angle);
GVAR(mapTool_startDragAngle) = (180 + ((GVAR(mapTool_startDragPos) select 0) - (GVAR(mapTool_startPos) select 0)) atan2 ((GVAR(mapTool_startDragPos) select 1) - (GVAR(mapTool_startPos) select 1)) mod 360);
// Start rotating
GVAR(mapTool_isRotating) = true;
} else {
// Start dragging
GVAR(mapTool_isDragging) = true;
if (call FUNC(canUsePlottingBoard)) then {
GVAR(plottingBoard_isDragging) = false;
GVAR(plottingBoard_isRotating) = -1;
if (GVAR(plottingBoard_Shown) != 0) then {
// Transform mouse screen position to coordinates
private _pos = _control ctrlMapScreenToWorld [_screenPosX, _screenPosY];
private _click = _pos call FUNC(isInsidePlottingBoard);
if (_click > -1) then {
GVAR(plottingBoard_startPos) = +GVAR(plottingBoard_pos);
GVAR(plottingBoard_startDragPos) = _pos;
private _rotateKeyPressed = switch (GVAR(rotateModifierKey)) do {
case 1: {_altKey};
case 2: {_ctrlKey};
case 3: {_shiftKey};
default {false};
};
if (_rotateKeyPressed) then {
// Store data for rotating
private _ang = switch (_click) do {
case 1: {GVAR(plottingBoard_acrylicAngle)};
case 2: {GVAR(plottingBoard_rulerAngle)};
default {GVAR(plottingBoard_angle)};
};
GVAR(plottingBoard_startAngle) = _ang;
private _pos = GVAR(plottingBoard_startDragPos) vectorDiff GVAR(plottingBoard_startPos);
GVAR(plottingBoard_startDragAngle) = ((_pos select 0) atan2 (_pos select 1) + 360) % 360;
// Start rotating
GVAR(plottingBoard_isRotating) = _click;
} else {
// Start dragging
GVAR(plottingBoard_isDragging) = true;
};
_handled = true;
};
};
_handled = true;
};
};

View File

@ -1,47 +1,75 @@
#include "..\script_component.hpp"
/*
* Author: esteldunedain
* Handle mouse movement over the map tool.
* Author: esteldunedain, LorenLuke
* Handle mouse movement over the map tool and plotting board.
*
* Arguments:
* 0: Map Control <CONTROL>
* 0: Map control <CONTROL>
* 1: Mouse position on screen coordinates <ARRAY>
*
* Return Value:
* true if event was handled <BOOL>
* If the event was handled <BOOL>
*
* Example:
* [CONTROL, [0, 5, 1]] call ACE_maptools_fnc_handleMouseMove
* [CONTROL, [0, 5]] call ace_maptools_fnc_handleMouseMove
*
* Public: No
*/
params ["_control", "_mousePosX", "_mousePosY"];
TRACE_3("params",_control,_mousePosX,_mousePosY);
params ["_mapCtrl", "_mousePosX", "_mousePosY"];
TRACE_3("params",_mapCtrl,_mousePosX,_mousePosY);
// If have no map tools, then exit
if (((isNull ACE_player) || {!("ACE_MapTools" in (ACE_player call EFUNC(common,uniqueItems)))})) exitWith {
if (isNull ACE_player || {
private _uniqueItems = ACE_player call EFUNC(common,uniqueItems);
!(("ACE_MapTools" in _uniqueItems) || {"ACE_PlottingBoard" in _uniqueItems})
}) exitWith {
false
};
// If map tools not shown, then exit
if (GVAR(mapTool_Shown) == 0) exitWith {false};
if (GVAR(mapTool_Shown) == 0 && {GVAR(plottingBoard_Shown) == 0}) exitWith {false};
private _mousePosition = _control ctrlMapScreenToWorld [_mousePosX, _mousePosY];
private _mousePosition = _mapCtrl ctrlMapScreenToWorld [_mousePosX, _mousePosY];
// Translation
// Map tools - translation
if (GVAR(mapTool_isDragging)) exitWith {
GVAR(mapTool_pos) set [0, (GVAR(mapTool_startPos) select 0) + (_mousePosition select 0) - (GVAR(mapTool_startDragPos) select 0)];
GVAR(mapTool_pos) set [1, (GVAR(mapTool_startPos) select 1) + (_mousePosition select 1) - (GVAR(mapTool_startDragPos) select 1)];
GVAR(mapTool_pos) = GVAR(mapTool_startPos) vectorAdd _mousePosition vectorDiff GVAR(mapTool_startDragPos);
true
};
// Rotation
// Map tools - rotation
if (GVAR(mapTool_isRotating)) exitWith {
// Get new angle
private _angle = (180 + ((_mousePosition select 0) - (GVAR(mapTool_startPos) select 0)) atan2 ((_mousePosition select 1) - (GVAR(mapTool_startPos) select 1)) mod 360);
GVAR(mapTool_angle) = GVAR(mapTool_startAngle) + _angle - GVAR(mapTool_startDragAngle);
private _pos = _mousePosition vectorDiff GVAR(mapTool_startPos);
private _angle = (_pos select 0) atan2 (_pos select 1);
GVAR(mapTool_angle) = ((GVAR(mapTool_startAngle) + _angle - GVAR(mapTool_startDragAngle)) % 360 + 360) % 360;
true
};
// Plotting board - translation
if (GVAR(plottingBoard_isDragging)) exitWith {
GVAR(plottingBoard_pos) = GVAR(plottingBoard_startPos) vectorAdd _mousePosition vectorDiff GVAR(plottingBoard_startDragPos);
true
};
// Plotting board - rotation
if (GVAR(plottingBoard_isRotating) > -1) exitWith {
// Get new angle
private _pos = _mousePosition vectorDiff GVAR(plottingBoard_startPos);
private _angle = (_pos select 0) atan2 (_pos select 1);
private _returnAngle = ((GVAR(plottingBoard_startAngle) + _angle - GVAR(plottingBoard_startDragAngle)) % 360 + 360) % 360;
switch (GVAR(plottingBoard_isRotating)) do {
case 0: {GVAR(plottingBoard_angle) = _returnAngle};
case 1: {GVAR(plottingBoard_acrylicAngle) = _returnAngle};
case 2: {GVAR(plottingBoard_rulerAngle) = _returnAngle};
};
true
};

View File

@ -0,0 +1,219 @@
#include "..\script_component.hpp"
/*
* Author: LorenLuke, johnb43
* Handle map marker creation.
* If a marker is (partially) on the plotting board, the parts on the plotting board are attached to the plotting board
* and move with the board accordingly.
*
* Arguments:
* 0: Arguments <ARRAY>
* - 0: Marker name <STRING>
* - 1: Chat channel number <NUMBER>
* - 2: Marker owner <OBJECT>
* - 3: Local origin <BOOL>
* 1: Deleted <BOOL>
*
* Return Value:
* None
*
* Example:
* [CONTROL, [0, 5]] call ace_maptools_fnc_handlePlottingBoardMarkers
*
* Public: No
*/
params ["_args", "_deleted"];
_args params ["_marker", "_channelNumber", "_owner", "_local"];
if (_deleted) exitWith {
GVAR(plottingBoard_markers) deleteAt _marker;
};
// Do not process non-local or already processed markers, don't check if the plotting board isn't shown
if (!_local || {GVAR(plottingBoard_Shown) < 1} || {QUOTE(ADDON) in _marker}) exitWith {};
// Check if the channel the marker was made in can be marked on the plotting board
private _continue = true;
if (isMultiplayer) then {
switch (GVAR(plottingBoardAllowChannelDrawing)) do {
case 0: {
if (_channelNumber != 5) then {_continue = false};
};
case 1: {
if !(_channelNumber in [3, 5]) then {_continue = false};
};
};
};
if (!_continue) exitWith {};
private _boardPos = GVAR(plottingBoard_pos);
private _boardAng = GVAR(plottingBoard_acrylicAngle);
private _markerPolyline = markerPolyline _marker;
private _count = count _markerPolyline;
// If the marker is not a polyline marker
if (_count == 0) exitWith {
private _diffPos = (getMarkerPos _marker) vectorDiff _boardPos;
// If the marker is on the acrylic or ruler of the plotting board, save it
if (vectorMagnitude _diffPos < PLOTTINGBOARD_DRAWRANGE) then {
private _relPos = [[0, 0], _diffPos, _boardAng] call CBA_fnc_vectRotate2D;
GVAR(plottingBoard_markers) set [_marker, [_relPos, [], _boardAng, +_boardPos, 1]];
};
};
// If the marker is a polyline marker, but doesn't have enough components (happens when you ctrl-left click on the map), ignore
if (_count <= 4) exitWith {};
// Polyine markers (lines)
private _startPos = [];
private _endPos = [];
private _dir = [];
private _diffPos = [];
private _a = 0;
private _b = 0;
private _c = 0;
private _t1 = nil;
private _t2 = nil;
private _delta = 0;
private _intersectionValid1 = false;
private _intersectionValid2 = false;
private _intersectPoint1 = [];
private _intersectPoint2 = [];
private _intersectClose = [];
private _intersectFar = [];
private _polylineIndex = 0;
private _markerArray = [[]];
private _insideArray = [];
for "_i" from 0 to _count - 1 - 2 step 2 do {
_startPos = [_markerPolyline select _i, _markerPolyline select (_i + 1)];
_endPos = [_markerPolyline select (_i + 2), _markerPolyline select (_i + 3)];
_dir = _endPos vectorDiff _startPos;
_diffPos = _startPos vectorDiff _boardPos;
// Circle-line intersection: Check for intersections between plotting board and current piece of polyline
// https://stackoverflow.com/a/1084899
_a = _dir vectorDotProduct _dir;
_b = 2 * (_diffPos vectorDotProduct _dir);
_c = (_diffPos vectorDotProduct _diffPos) - PLOTTINGBOARD_DRAWRANGE^2;
_delta = _b^2 - 4 * _a * _c;
// Stretch factors
_t1 = nil;
_t2 = nil;
if (_delta > 0) then {
_t1 = (-_b + sqrt _delta) / (2 * _a);
_t2 = (-_b - sqrt _delta) / (2 * _a);
// Don't look for intersection points beyond the start or end points
if (_t1 < 0 || _t1 > 1) then {
_t1 = nil;
};
if (_t2 < 0 || _t2 > 1) then {
_t2 = nil;
};
};
// The current point is always part of a polyline
(_markerArray param [_polylineIndex, []]) append _startPos;
_insideArray set [_polylineIndex, vectorMagnitude _diffPos < PLOTTINGBOARD_DRAWRANGE]; // keep track if point is within plotting board
_intersectionValid1 = !isNil "_t1";
_intersectionValid2 = !isNil "_t2";
// If no valid intersection points, continue
if (!_intersectionValid1 && {!_intersectionValid2}) then {
continue;
};
// Extremely rare case if the marker is tangential to the plotting board: Ignore
if (_intersectionValid1 && {_intersectionValid2} && {_t1 == _t2}) then {
continue;
};
if (_intersectionValid1) then {
_intersectPoint1 = _startPos vectorAdd (_dir vectorMultiply _t1);
};
if (_intersectionValid2) then {
_intersectPoint2 = _startPos vectorAdd (_dir vectorMultiply _t2);
};
// When a marker crosses the plotting board entirely (one straight line through the plotting board)
if (_intersectionValid1 && {_intersectionValid2}) then {
// Take the closer point first
_intersectClose = [_intersectPoint1, _intersectPoint2] select (_t1 > _t2);
// Finish previous polyline with the last point being the intersection
(_markerArray select _polylineIndex) append _intersectClose;
// Create a new polyline, with the first point being the closest intersection
_polylineIndex = _polylineIndex + 1;
_markerArray set [_polylineIndex, _intersectClose];
// Now take the point further away
_intersectFar = [_intersectPoint1, _intersectPoint2] select (_t1 < _t2);
// Make a polyline between the intersection points
(_markerArray select _polylineIndex) append _intersectClose;
(_markerArray select _polylineIndex) append _intersectFar;
_insideArray set [_polylineIndex, true]; // with 2 intersections, this part of the polyline must be inside
// Create a new polyline, with the first point being the furthest intersection
_polylineIndex = _polylineIndex + 1;
_markerArray set [_polylineIndex, _intersectFar];
} else {
// Only 1 intersection (either point 1 or 2, exclusive or)
if (_intersectionValid2) then {
_intersectPoint1 = _intersectPoint2;
};
// Finish previous polyline with the last point being the intersection
(_markerArray select _polylineIndex) append _intersectPoint1;
// Create a new polyline, with the first point being the intersection
_polylineIndex = _polylineIndex + 1;
_markerArray set [_polylineIndex, _intersectPoint1];
};
};
// If there were no polyline intersections and the marker was not on the plotting board, don't create new markers
if (_insideArray isEqualTo [false]) exitWith {};
private _color = getMarkerColor _marker;
private _name = "";
private _polylineRelative = [];
private _relPos = [];
{
_name = format ["%1-%2-%3", _marker, _forEachIndex, QUOTE(ADDON)]; // adding an identifier allow to check if marker was already processed
createMarkerLocal [_name, [0, 0], _channelNumber, _owner];
_name setMarkerColorLocal _color;
_name setMarkerPolyline _x; // global marker broadcast
// If the marker was on the plotting board, take it's unrotated position and store it
if (_insideArray select _forEachIndex) then {
_polylineRelative = [];
for "_i" from 0 to count _x - 1 step 2 do {
_relPos = [[0, 0], [_x select _i, _x select (_i + 1)] vectorDiff _boardPos, _boardAng] call CBA_fnc_vectRotate2D;
_polylineRelative append _relPos;
};
GVAR(plottingBoard_markers) set [_name, [[0, 0], +_polylineRelative, _boardAng, +_boardPos, 1]];
};
} forEach _markerArray;
// Delete original marker
deleteMarker _marker;

View File

@ -0,0 +1,54 @@
#include "..\script_component.hpp"
/*
* Author: LorenLuke
* Return if the position is inside the map marker (to allow dragging) or not.
*
* Arguments:
* 0: x Position (in meters) <NUMBER>
* 1: y Position (in meters) <NUMBER>
*
* Return Value:
* Where in the plotting board it is <NUMBER>
* -1 - Nowhere, 0 - In the Board, 1 - In the Acrylic, 2 - In the Ruler
*
* Example:
* [0, 5] call ace_maptools_fnc_isInsidePlottingBoard
*
* Public: No
*/
if (GVAR(plottingBoard_Shown) == 0) exitWith {-1};
private _relPos = _this vectorDiff GVAR(plottingBoard_pos);
private _dist = vectorMagnitude _relPos;
private _isRuler = if (GVAR(plottingBoard_Shown) == 2) then {
// If it's within these bounds, it's going to be on the ruler
if (_dist <= PLOTTINGBOARD_RULERCENTER) exitWith {true};
private _rulerVector = [sin GVAR(plottingBoard_rulerAngle), cos GVAR(plottingBoard_rulerAngle)];
private _dirRightVector = [_dirVector select 1, -(_dirVector select 0)];
private _rulerAng = acos (_rulerVector vectorCos _relPos);
if (cos _rulerAng > 0 && {tan (_rulerAng) * _dist < PLOTTINGBOARD_RULERHALFWIDTH}) exitWith {true};
_dist > PLOTTINGBOARD_RULERINNERCIRCLE && {_dist < PLOTTINGBOARD_RULEROUTERCIRCLE && {abs (_rulerAng * DEGTOMILS) < PLOTTINGBOAR_RULEROUTERHALFANGLE}}
};
if (_isRuler) exitWith {2};
// If it's within 3000 meters, it's going to be on the acrylic
if (_dist < PLOTTINGBOARD_RULEROUTERCIRCLE) exitWith {1};
private _dirVector = [sin GVAR(plottingBoard_angle), cos GVAR(plottingBoard_angle)];
private _dirRightVector = [_dirVector select 1, -(_dirVector select 0)];
// Projection of the relative position over the longitudinal axis of the map tool
private _ang = _dirVector vectorCos _relPos;
private _ang2 = _dirRightVector vectorCos _relPos;
private _relPosAdjusted = [_ang2 * _dist / PLOTTINGBOARD_DRAWRANGE, _ang * _dist / PLOTTINGBOARD_DRAWRANGE];
if ((_relPosAdjusted select 0 > 0) && (_relPosAdjusted select 0 < 1) && (abs (_relPosAdjusted select 1) < 1)) exitWith {0};
-1

View File

@ -1,56 +1,136 @@
#include "..\script_component.hpp"
/*
* Author: esteldunedain
* Update the map tool markers, position, size, rotation and visibility.
* Author: esteldunedain, LorenLuke
* Update the map tool and plotting board markers. Update their position, size, rotation and visibility.
*
* Arguments:
* 0: The Map <CONTROL>
* 0: Map control <CONTROL>
*
* Return Value:
* None
*
* Example:
* [CONTROL] call ACE_maptools_fnc_updateMapToolMarkers
* [CONTROL] call ace_maptools_fnc_updateMapToolMarkers
*
* Public: No
*/
params ["_theMap"];
params ["_mapCtrl"];
if ((GVAR(mapTool_Shown) == 0) || {!("ACE_MapTools" in (ACE_player call EFUNC(common,uniqueItems)))}) exitWith {};
// open map tools in center of screen when toggled to be shown
if (GVAR(mapTool_moveToMouse)) then {
private _mousePosition = _theMap ctrlMapScreenToWorld getMousePosition;
GVAR(mapTool_pos) = _mousePosition;
GVAR(mapTool_moveToMouse) = false; // we only need to do this once after opening the map tool
if (GVAR(plottingBoard_Shown) == 0) then {
// Hide all plotting board markers when board is put away
{
if (_y select 4 != 0) then {
_x setMarkerAlpha 0;
_y set [4, 0];
};
} forEach GVAR(plottingBoard_markers);
};
private _rotatingTexture = "";
private _textureWidth = 0;
if (GVAR(mapTool_Shown) == 1) then {
_rotatingTexture = QPATHTOF(data\mapToolRotatingNormal.paa);
_textureWidth = TEXTURE_WIDTH_IN_M;
} else {
_rotatingTexture = QPATHTOF(data\mapToolRotatingSmall.paa);
_textureWidth = TEXTURE_WIDTH_IN_M / 2;
if (((GVAR(mapTool_Shown) == 0) && {GVAR(plottingBoard_Shown) == 0}) || {
private _uniqueItems = ACE_player call EFUNC(common,uniqueItems);
!(("ACE_MapTools" in _uniqueItems) || {"ACE_PlottingBoard" in _uniqueItems})
}) exitWith {};
if (GVAR(plottingBoard_Shown) > 0) then {
if (GVAR(plottingBoard_moveToMouse)) then {
GVAR(plottingBoard_pos) = _mapCtrl ctrlMapScreenToWorld getMousePosition;
GVAR(plottingBoard_moveToMouse) = false; // we only need to do this once after opening the map tool
};
getResolution params ["_resWidth", "_resHeight", "", "", "_aspectRatio"];
private _scaleX = 32 * PLOTTINGBOARD_TEXTUREWIDTH * CONSTANT_SCALE * (call FUNC(calculateMapScale));
private _scaleY = _scaleX * ((_resWidth / _resHeight) / _aspectRatio); // handle bad aspect ratios
_mapCtrl drawIcon [QPATHTOF(data\plottingBoardBack.paa), [1, 1, 1, 1], GVAR(plottingBoard_pos), _scaleX, _scaleY, GVAR(plottingBoard_angle), "", 0];
_mapCtrl drawIcon [QPATHTOF(data\plottingBoardAcrylic.paa), [1, 1, 1, 1], GVAR(plottingBoard_pos), _scaleX, _scaleY, GVAR(plottingBoard_acrylicAngle), "", 0];
// Show ruler
if (GVAR(plottingBoard_Shown) == 2) then {
_mapCtrl drawIcon [QPATHTOF(data\plottingBoardRuler.paa), [1, 1, 1, 1], GVAR(plottingBoard_pos), _scaleX, _scaleY, GVAR(plottingBoard_rulerAngle), "", 0];
};
private _marker = "";
private _angle = GVAR(plottingBoard_acrylicAngle);
private _boardPos = GVAR(plottingBoard_pos);
private _count = -1;
private _rotatedPolyPos = [];
private _rotatedPos = [];
{
_marker = _x;
_y params ["_markerPos", "_polyline", "_lastAngle", "_lastBoardPos", "_lastAlpha"];
// Show all plotting board markers when the board is shown
if (_lastAlpha != 1) then {
_marker setMarkerAlpha 1;
_y set [4, 1];
};
// If nothing has changed, don't update marker
if (_angle == _lastAngle && {_boardPos isEqualTo _lastBoardPos}) then {
continue;
};
_count = count _polyline;
// Rotate all points of polyline
if (_count >= 4) then { // polylines need at least 2 points (2 components per point)
_rotatedPolyline = [];
for "_i" from 0 to _count - 1 step 2 do {
_rotatedPolyPos = [[0, 0], [_polyline select _i, _polyline select (_i + 1)], -_angle] call CBA_fnc_vectRotate2D;
_rotatedPolyline append (_rotatedPolyPos vectorAdd _boardPos);
};
_marker setMarkerPolyline _rotatedPolyline;
};
// Rotate marker position, regardless of marker type
_rotatedPos = [[0, 0], _markerPos, -_angle] call CBA_fnc_vectRotate2D;
_marker setMarkerPos (_boardPos vectorAdd _rotatedPos);
_y set [2, _angle];
_y set [3, +_boardPos];
} forEach GVAR(plottingBoard_markers);
};
if (GVAR(freedrawing)) then {[_theMap, _textureWidth] call FUNC(drawLinesOnRoamer);};
if (GVAR(mapTool_Shown) > 0) then {
// Open map tools in center of screen when toggled to be shown
if (GVAR(mapTool_moveToMouse)) then {
GVAR(mapTool_pos) = _mapCtrl ctrlMapScreenToWorld getMousePosition;
GVAR(mapTool_moveToMouse) = false; // we only need to do this once after opening the map tool
};
// Update scale of both parts
getResolution params ["_resWidth", "_resHeight", "", "", "_aspectRatio"];
private _scaleX = 32 * _textureWidth * CONSTANT_SCALE * (call FUNC(calculateMapScale));
private _scaleY = _scaleX;
private _rotatingTexture = "";
private _textureWidth = 0;
// Position of the fixed part
private _xPos = GVAR(mapTool_pos) select 0;
private _yPos = (GVAR(mapTool_pos) select 1) + _textureWidth * CENTER_OFFSET_Y_PERC;
if (GVAR(mapTool_Shown) == 1) then {
_rotatingTexture = QPATHTOF(data\mapToolRotatingNormal.paa);
_textureWidth = TEXTURE_WIDTH_IN_M;
} else {
_rotatingTexture = QPATHTOF(data\mapToolRotatingSmall.paa);
_textureWidth = TEXTURE_WIDTH_IN_M / 2;
};
_theMap drawIcon [QPATHTOF(data\mapToolFixed.paa), [1,1,1,1], [_xPos,_yPos], _scaleX, _scaleY, 0, "", 0];
if (GVAR(freedrawing)) then {
[_mapCtrl, _textureWidth] call FUNC(drawLinesOnRoamer);
};
// Position and rotation of the rotating part
_xPos = (GVAR(mapTool_pos) select 0) + sin(GVAR(mapTool_angle)) * _textureWidth * CENTER_OFFSET_Y_PERC;
_yPos = (GVAR(mapTool_pos) select 1) + cos(GVAR(mapTool_angle)) * _textureWidth * CENTER_OFFSET_Y_PERC;
// Update scale of both parts
getResolution params ["_resWidth", "_resHeight", "", "", "_aspectRatio"];
private _scaleX = 32 * _textureWidth * CONSTANT_SCALE * (call FUNC(calculateMapScale));
private _scaleY = _scaleX * ((_resWidth / _resHeight) / _aspectRatio); // handle bad aspect ratios
_theMap drawIcon [_rotatingTexture, [1,1,1,1], [_xPos,_yPos], _scaleX, _scaleY, GVAR(mapTool_angle), "", 0];
// Position of the fixed part
private _pos = GVAR(mapTool_pos) vectorAdd [0, _textureWidth * CENTER_OFFSET_Y_PERC];
_mapCtrl drawIcon [QPATHTOF(data\mapToolFixed.paa), [1, 1, 1, 1], _pos, _scaleX, _scaleY, 0, "", 0];
// Position and rotation of the rotating part
_pos = GVAR(mapTool_pos) vectorAdd ([sin GVAR(mapTool_angle), cos GVAR(mapTool_angle)] vectorMultiply (_textureWidth * CENTER_OFFSET_Y_PERC));
_mapCtrl drawIcon [_rotatingTexture, [1, 1, 1, 1], _pos, _scaleX, _scaleY, GVAR(mapTool_angle), "", 0];
};

View File

@ -0,0 +1,23 @@
#include "../script_component.hpp"
/*
* Author: LorenLuke
* Delete all markers on the plotting board.
*
* Arguments:
* None
*
* Return Value:
* None
*
* Example:
* call ace_maptools_fnc_wipeMarkers
*
* Public: No
*/
{
deleteMarker _x;
} forEach (keys GVAR(plottingBoard_markers));
// Reset list
GVAR(plottingBoard_markers) = createHashMap;

View File

@ -15,3 +15,11 @@ private _category = format ["ACE %1", localize LSTRING(Name)];
true,
0
] call CBA_fnc_addSetting;
[
QGVAR(plottingBoardAllowChannelDrawing), "LIST",
[LSTRING(allowChannelDrawing_displayName), LSTRING(allowChannelDrawing_description)],
_category,
[[0, 1], [LSTRING(allowDirectCommsOnly), LSTRING(allowDirectGroupComms)], 1],
0
] call CBA_fnc_addSetting;

View File

@ -16,9 +16,19 @@
#include "\z\ace\addons\main\script_macros.hpp"
#define DEGTOMILS 17.7777778
#define TEXTURE_WIDTH_IN_M 6205
#define CENTER_OFFSET_Y_PERC 0.1606
#define CONSTANT_SCALE 0.2
#define DIST_BOTTOM_TO_CENTER_PERC -0.33
#define DIST_TOP_TO_CENTER_PERC 0.65
#define DIST_LEFT_TO_CENTER_PERC 0.30
#define PLOTTINGBOARD_DRAWRANGE 3000
#define PLOTTINGBOARD_TEXTUREWIDTH 6000
#define PLOTTINGBOARD_RULERCENTER 450
#define PLOTTINGBOARD_RULERHALFWIDTH 100
#define PLOTTINGBOARD_RULERINNERCIRCLE 2900
#define PLOTTINGBOARD_RULEROUTERCIRCLE 3000
#define PLOTTINGBOARD_RULEROUTERHALFANGLE 100

View File

@ -35,6 +35,12 @@
<Chinese>地圖工具能夠讓你在地圖上測量距離與角度</Chinese>
<Turkish>Harita Araçları, haritadaki mesafeleri ve açıları ölçmenize olanak tanır.</Turkish>
</Key>
<Key ID="STR_ACE_MapTools_PlottingBoard_Name">
<English>Plotting Board</English>
</Key>
<Key ID="STR_ACE_MapTools_PlottingBoard_Description">
<English>The Plotting Board is a map tool designed for use in the directing of short range indirect fires.</English>
</Key>
<Key ID="STR_ACE_MapTools_MapTools_Menu">
<English>Map Tools</English>
<Spanish>Herramientas de mapa</Spanish>
@ -252,5 +258,89 @@
<Turkish>Düz çizgiler çizmek için maptools'un kenarına çizin. Not: Silmek için orta noktada fareyle üzerine gelmeniz gerekir.</Turkish>
<Spanish>Dibujar sobre el borde de las herramientas de mapa para dibujar líneas rectas. Nota: Debe situarse en el punto intermedio para eliminarla.</Spanish>
</Key>
<Key ID="STR_ACE_MapTools_allowChannelDrawing_displayName">
<English>Allow Plotting Board Drawing channels</English>
</Key>
<Key ID="STR_ACE_MapTools_allowChannelDrawing_description">
<English>Channels in which plotting board drawing is enabled.</English>
</Key>
<Key ID="STR_ACE_MapTools_allowDirectCommsOnly">
<English>Allow Direct Comms Only (Polylines Only)</English>
</Key>
<Key ID="STR_ACE_MapTools_allowDirectGroupComms">
<English>Allow Direct/Group Comms (Polylines and Group Markers)</English>
</Key>
<Key ID="STR_ACE_MapTools_PlottingBoardLabel">
<English>Plotting Board</English>
</Key>
<Key ID="STR_ACE_MapTools_PlottingBoardAcrylicLabel">
<English>Plotting Board Acrylic</English>
</Key>
<Key ID="STR_ACE_MapTools_PlottingBoardRulerLabel">
<English>Plotting Board Ruler</English>
</Key>
<Key ID="STR_ACE_MapTools_ToPlottingBoardLabel">
<English>To Plotting Board</English>
</Key>
<Key ID="STR_ACE_MapTools_ToPlottingBoardAcrylicLabel">
<English>To Plotting Board Acrylic</English>
</Key>
<Key ID="STR_ACE_MapTools_ToPlottingBoardRulerLabel">
<English>To Plotting Board Ruler</English>
</Key>
<Key ID="STR_ACE_MapTools_WipeBoard">
<English>Wipe all markers off Plotting Board</English>
</Key>
<Key ID="STR_ACE_MapTools_ShowPlottingBoard">
<English>Show Plotting Board</English>
</Key>
<Key ID="STR_ACE_MapTools_HidePlottingBoard">
<English>Hide Plotting Board</English>
</Key>
<Key ID="STR_ACE_MapTools_TogglePlottingBoardRuler">
<English>Toggle Plotting Board Ruler</English>
</Key>
<Key ID="STR_ACE_MapTools_AlignTo">
<English>Align</English>
<German>Ausrichten</German>
<Spanish>Alinear</Spanish>
<French>Aligner</French>
<Italian>Allinea</Italian>
<Portuguese>Alinhar</Portuguese>
<Hungarian>Állítása</Hungarian>
<Polish>Wyrównaj</Polish>
<Czech>Srovnat</Czech>
<Russian>Выровнять</Russian>
</Key>
<Key ID="STR_ACE_MapTools_ToNorthLabel">
<English>To North</English>
<German>Nach Norden</German>
<Spanish>Al norte</Spanish>
<French>Sur le nord</French>
<Italian>Con il Nord</Italian>
<Portuguese>Com o Norte</Portuguese>
<Hungarian>Északhoz</Hungarian>
<Polish>Do północy</Polish>
<Czech>Na sever</Czech>
<Russian>На север</Russian>
</Key>
<Key ID="STR_ACE_MapTools_ToCompassLabel">
<English>To Compass</English>
<German>Am Kompass</German>
<Spanish>A la brújula</Spanish>
<French>Sur la boussole</French>
<Italian>Con la bussola</Italian>
<Portuguese>Com a Bússola</Portuguese>
<Hungarian>Iránytűhöz</Hungarian>
<Polish>Do kompasu</Polish>
<Czech>Ke kompasu</Czech>
<Russian>По компасу</Russian>
</Key>
<Key ID="STR_ACE_MapTools_ToUpLabel">
<English>Up</English>
</Key>
<Key ID="STR_ACE_MapTools_ToMapToolLabel">
<English>To Maptool</English>
</Key>
</Package>
</Project>

View File

@ -1,6 +1,6 @@
#include "..\script_component.hpp"
/*
* Author: Freddo
* Author: Freddo, Daniël H., johnb43
* When the confirm button is pressed.
*
* Arguments:
@ -14,40 +14,100 @@
*
* Public: No
*/
params ["_buttonOk"];
private _display = ctrlParent _buttonOk;
private _description = _display displayctrl IDC_INSERT_MARKER;
private _description = _display displayCtrl IDC_INSERT_MARKER;
private _aceTimestamp = _display displayCtrl IDC_ACE_INSERT_MARKER_TIMESTAMP;
// handle timestamp
// Handle timestamp
if (cbChecked _aceTimestamp && {ACE_player call FUNC(canTimestamp)}) then {
private _time = daytime;
// Determine marker timestamp based on time settings
private _time = switch (GVAR(timestampTimezone)) do {
case 1: {
systemTime select [3]
};
case 2: {
systemTimeUTC params ["", "", "", "_hour", "_min", "_sec", "_msec"];
// add timestamp suffix
private _hourOffset = round GVAR(timestampUTCOffset);
_hour = _hour + _hourOffset;
// Add or subtract minutes offset based on the negative or positive timezone
if (GVAR(timestampUTCMinutesOffset) != 0) then {
_min = if (_hourOffset < 0) then { _min - GVAR(timestampUTCMinutesOffset) } else { _min + GVAR(timestampUTCMinutesOffset) };
// Add/remove extra hours from minutes
_hour = _hour + floor (_min / 60);
_min = (_min % 60 + 60) % 60; // ensure that minutes are between 0 and 59 (included)
};
[(_hour % 24 + 24) % 24, _min, _sec, _msec] // ensure that hours are between 0 and 23 (included)
};
default {
private _daytime = dayTime;
private _hour = floor _daytime;
private _min = floor ((_daytime - _hour) * 60);
private _sec = floor ((((_daytime - _hour) * 60) - _min) * 60);
private _msec = floor ((((((_daytime - _hour) * 60) - _min) * 60) - _sec) * 1000);
[_hour, _min, _sec, _msec]
};
};
_time params ["_hour", "_min", "_sec", "_msec"];
// Add timestamp suffix
private _periodPostfix = "";
if (GVAR(timestampHourFormat) == 12) then {
if (floor _time == 0) exitWith {
_time = _time + 12;
if (_hour == 0) exitWith {
_hour = _hour + 12;
_periodPostfix = " am";
};
if (floor _time == 12) exitWith {
if (_hour == 12) exitWith {
_periodPostfix = " pm";
};
if (_time < 12) then {
if (_hour < 12) then {
_periodPostfix = " am";
} else {
_time = _time - 12;
_hour = _hour - 12;
_periodPostfix = " pm";
};
};
private _format = switch (GVAR(timestampFormat)) do {
case "HH": {"%1"};
case "HH:MM": {"%1:%2"};
case "HH:MM:SS": {"%1:%2:%3"};
case "HH:MM:SS:MM": { // milliseconds are displayed as 0 to 59
_msec = [_msec * 60 / 1000, 2] call CBA_fnc_formatNumber;
"%1:%2:%3:%4"
};
case "HH:MM:SS.mmm": { // milliseconds are displayed as 0 to 999
_msec = [_msec, 3] call CBA_fnc_formatNumber;
"%1:%2:%3.%4"
};
};
_time = format [
_format,
[_hour, 2] call CBA_fnc_formatNumber,
[_min, 2] call CBA_fnc_formatNumber,
[_sec, 2] call CBA_fnc_formatNumber,
_msec
];
_description ctrlSetText format [
"%1 [%2%3]",
ctrlText _description,
[_time, GVAR(timestampFormat)] call BIS_fnc_timeToString,
_time,
_periodPostfix
];
};

View File

@ -32,6 +32,37 @@ private _categoryName = format ["ACE %1", localize ELSTRING(map,Module_DisplayNa
true
] call CBA_fnc_addSetting;
[
QGVAR(timestampTimezone), "LIST",
[LSTRING(TimestampTimezone), LSTRING(TimestampTimezoneDescription)],
[_categoryName, LLSTRING(Module_DisplayName)],
[
[0, 1, 2],
[LSTRING(TimestampTimezoneIngameTime), LSTRING(TimestampTimezoneSystemTime), LSTRING(TimestampTimezoneUTCTime)],
0
],
true
] call CBA_fnc_addSetting;
[
QGVAR(timestampUTCOffset), "SLIDER",
[LSTRING(TimestampUTCOffset), LSTRING(TimestampUTCOffsetDescription)],
[_categoryName, LLSTRING(Module_DisplayName)],
[-12, 14, 0, 0],
true
] call CBA_fnc_addSetting;
[
QGVAR(TimestampUTCMinutesOffset), "LIST",
[LSTRING(TimestampUTCMinutesOffset), LSTRING(TimestampUTCMinutesOffsetDescription)],
[_categoryName, LLSTRING(Module_DisplayName)],
[
[0, 15, 30, 45],
[0, 15, 30, 45],
0
]
] call CBA_fnc_addSetting;
[
QGVAR(timestampHourFormat), "LIST",
[LSTRING(TimestampHourFormat), LSTRING(TimestampHourFormatDescription)],
@ -48,7 +79,8 @@ private _formatDescription = [
LLSTRING(TimestampFormatDescription1),
LLSTRING(TimestampFormatDescription2),
LLSTRING(TimestampFormatDescription3),
LLSTRING(TimestampFormatDescription4)
LLSTRING(TimestampFormatDescription4),
LLSTRING(TimestampFormatDescription5)
] joinString endl;
[
@ -56,8 +88,8 @@ private _formatDescription = [
[LSTRING(timestampFormat), _formatDescription],
[_categoryName, LLSTRING(Module_DisplayName)],
[
["HH", "HH:MM", "HH:MM:SS", "HH:MM:SS:MM"],
["HH", "HH:MM", "HH:MM:SS", "HH:MM:SS:MM"],
["HH", "HH:MM", "HH:MM:SS", "HH:MM:SS:MM", "HH:MM:SS.mmm"],
["HH", "HH:MM", "HH:MM:SS", "HH:MM:SS:MM", "HH:MM:SS.mmm"],
1
]
] call CBA_fnc_addSetting;

View File

@ -239,6 +239,105 @@
<Korean>시계 필요함</Korean>
<Portuguese>Relógio necessário</Portuguese>
</Key>
<Key ID="STR_ACE_Markers_TimestampTimezone">
<English>Time Zone</English>
<Russian>Часовой пояс</Russian>
<French>Fuseau horaire</French>
<Japanese>時間帯</Japanese>
<Spanish>Zona horaria</Spanish>
<Polish>Strefa czasowa</Polish>
<German>Zeitzone</German>
<Chinesesimp>时区</Chinesesimp>
<Korean>시간대</Korean>
</Key>
<Key ID="STR_ACE_Markers_TimestampTimezoneDescription">
<English>Changes the time zone for the timestamp</English>
<Russian>Измените часовой пояс для метки времени</Russian>
<French>Modifiez le fuseau horaire pour l'horodatage</French>
<Japanese>タイムスタンプの時間帯を変更します</Japanese>
<Spanish>Cambie la zona horaria para la marca de tiempo</Spanish>
<Polish>Zmień strefę czasową dla znaczników czasu</Polish>
<German>Ändern Sie die Zeitzone für den Zeitstempel</German>
<Chinesesimp>更改时间戳的时区</Chinesesimp>
<Korean>타임스탬프의 시간대를 변경하십시오</Korean>
</Key>
<Key ID="STR_ACE_Markers_TimestampTimezoneIngameTime">
<English>In-game Time</English>
<Russian>Время в игре</Russian>
<French>Heure de jeu</French>
<Japanese>ゲーム内時刻</Japanese>
<Spanish>Hora del juego</Spanish>
<Polish>Czas gry</Polish>
<German>Ingame-Zeit</German>
<Chinesesimp>游戏内时间</Chinesesimp>
<Korean>게임 시간</Korean>
</Key>
<Key ID="STR_ACE_Markers_TimestampTimezoneSystemTime">
<English>System Time</English>
<Russian>Системное время</Russian>
<French>Heure système</French>
<Japanese>システム時刻</Japanese>
<Spanish>Hora del sistema</Spanish>
<Polish>Czas systemowy</Polish>
<German>Systemzeit</German>
<Chinesesimp>系统时间</Chinesesimp>
<Korean>시스템 시간</Korean>
</Key>
<Key ID="STR_ACE_Markers_TimestampTimezoneUTCTime">
<English>UTC Time</English>
<Russian>Время UTC</Russian>
<French>Heure UTC</French>
<Japanese>UTC時刻</Japanese>
<Spanish>Hora UTC</Spanish>
<Polish>Czas UTC</Polish>
<German>UTC-Zeit</German>
<Chinesesimp>UTC时间</Chinesesimp>
<Korean>UTC 시간</Korean>
</Key>
<Key ID="STR_ACE_Markers_TimestampUTCOffset">
<English>UTC Offset</English>
<Russian>Смещение UTC</Russian>
<French>Décalage UTC</French>
<Japanese>UTCオフセット</Japanese>
<Spanish>Desplazamiento UTC</Spanish>
<Polish>Przesunięcie UTC</Polish>
<German>UTC-Verschiebung</German>
<Chinesesimp>UTC偏移量</Chinesesimp>
<Korean>UTC 오프셋</Korean>
</Key>
<Key ID="STR_ACE_Markers_TimestampUTCOffsetDescription">
<English>Changes the time offset for the UTC timestamp</English>
<Russian>Измените смещение времени для метки времени UTC</Russian>
<French>Modifier le décalage horaire pour l'horodatage UTC</French>
<Japanese>UTCタイムスタンプの時差を変更する</Japanese>
<Spanish>Cambiar el desplazamiento horario para la marca de tiempo UTC</Spanish>
<Polish>Zmień przesunięcie czasu dla sygnatury czasowej UTC</Polish>
<German>Ändere die Zeitverschiebung für den UTC-Zeitstempel</German>
<Chinesesimp>更改UTC时间戳的时间偏移量</Chinesesimp>
<Korean>UTC 타임 스탬프의 시간 오프셋을 변경하십시오</Korean>
</Key>
<Key ID="STR_ACE_Markers_TimestampUTCMinutesOffset">
<English>UTC Minutes Offset</English>
<Russian>UTC Минутное Смещение</Russian>
<French>Décalage des minutes UTC</French>
<Japanese>UTC分オフセット</Japanese>
<Spanish>Desplazamiento de minutos UTC</Spanish>
<Polish>Przesunięcie minut UTC</Polish>
<German>UTC-Minutenversatz</German>
<Chinesesimp>UTC分钟偏移量</Chinesesimp>
<Korean>UTC 분 오프셋</Korean>
</Key>
<Key ID="STR_ACE_Markers_TimestampUTCMinutesOffsetDescription">
<English>Change the minute offset for the UTC timestamp</English>
<Russian>Изменить минутное смещение для времени UTC</Russian>
<French>Modifier le décalage des minutes pour l'horodatage UTC</French>
<Japanese>UTCタイムスタンプの分差を変更する</Japanese>
<Spanish>Cambiar el desplazamiento de minutos para la marca de tiempo UTC</Spanish>
<Polish>Zmień przesunięcie minut dla sygnatury czasowej UTC</Polish>
<German>Ändere den Minutenversatz für den UTC-Zeitstempel</German>
<Chinesesimp>更改UTC时间戳的分钟偏移量</Chinesesimp>
<Korean>UTC 타임 스탬프의 분 오프셋을 변경하십시오</Korean>
</Key>
<Key ID="STR_ACE_Markers_TimestampFormat">
<English>Timestamp Format</English>
<Russian>Формат времени</Russian>
@ -305,17 +404,16 @@
<Portuguese>SS - Segundos</Portuguese>
</Key>
<Key ID="STR_ACE_Markers_TimestampFormatDescription4">
<English>"MM" - Milliseconds</English>
<Russian>"МС" - Миллисекунда</Russian>
<French>"MM" - Millisecondes</French>
<Japanese>"MM" - ミリ秒</Japanese>
<Spanish>"MM" - Milisegundos</Spanish>
<Polish>"MM" - Milisekundy</Polish>
<German>"MS" - Milisekunden</German>
<Italian>"MS" - Millisecondi</Italian>
<Chinesesimp>"MS"—毫秒</Chinesesimp>
<Korean>"MS" - 밀리초</Korean>
<Portuguese>MM - Milisegundos</Portuguese>
<English>"MM" - Milliseconds (from 0 to 59)</English>
<French>"MM" - Millisecondes (de 0 à 59)</French>
<German>"MS" - Milisekunden (von 0 bis 59)</German>
<Portuguese>"MS" - Milissegundos (de 0 a 59)</Portuguese>
</Key>
<Key ID="STR_ACE_Markers_TimestampFormatDescription5">
<English>"mmm" - Milliseconds (from 0 to 999)</English>
<French>"mmm" - Millisecondes (de 0 à 999)</French>
<German>"mmm" - Milisekunden (von 0 bis 999)</German>
<Portuguese>"mmm" - Milissegundos (de 0 a 999)</Portuguese>
</Key>
<Key ID="STR_ACE_Markers_TimestampHourFormat">
<English>Timestamp Hour Format</English>

View File

@ -0,0 +1,21 @@
class EGVAR(arsenal,stats) {
class statBase;
class ACE_allowSwapBarrel: statBase {
scope = 2;
priority = -1;
stats[] = {QGVAR(allowSwapBarrel)};
displayName = CSTRING(statBarrelType);
showText = 1;
textStatement = QUOTE(call FUNC(statTextStatement_allowSwapBarrel));
tabs[] = {{0,1}, {}};
};
class ACE_boltType: statBase {
scope = 2;
priority = -1.1;
stats[] = {QGVAR(closedBolt)};
displayName = CSTRING(statBoltType);
showText = 1;
textStatement = QUOTE(call FUNC(statTextStatement_boltType));
tabs[] = {{0,1}, {}};
};
};

View File

@ -25,6 +25,8 @@ PREP(overheat);
PREP(sendSpareBarrelsTemperaturesHint);
PREP(setAmmoTemperature);
PREP(setWeaponTemperature);
PREP(statTextStatement_boltType);
PREP(statTextStatement_allowSwapBarrel);
PREP(swapBarrel);
PREP(swapBarrelAssistant);
PREP(swapBarrelCallback);

View File

@ -26,6 +26,8 @@ class CfgPatches {
#include "ACE_Settings.hpp"
#include "ACE_Arsenal_Stats.hpp"
class CfgMovesBasic {
class ManActions {
GVAR(GestureMountMuzzle) = QGVAR(GestureMountMuzzle);

View File

@ -0,0 +1,21 @@
#include "..\script_component.hpp"
/*
* Author: drofseh
* Barrel Type statement.
*
* Arguments:
* 0: Not used
* 1: Item config path <CONFIG>
*
* Return Value:
* Stat Text <STRING>
*
* Public: No
*/
params ["", "_config"];
TRACE_1("statTextStatement_allowSwapBarrel",_config);
if ((getNumber (_config >> QGVAR(allowSwapBarrel))) == 1) exitWith {LLSTRING(statBarrelType_removeable)};
LLSTRING(statBarrelType_nonRemoveable)

View File

@ -0,0 +1,21 @@
#include "..\script_component.hpp"
/*
* Author: drofseh
* Bolt Type statement.
*
* Arguments:
* 0: Not used
* 1: Item config path <CONFIG>
*
* Return Value:
* Stat Text <STRING>
*
* Public: No
*/
params ["", "_config"];
TRACE_1("statTextStatement_boltType",_config);
if ((getNumber (_config >> QGVAR(closedBolt))) == 1) exitWith {LLSTRING(statBoltType_closedBolt)};
LLSTRING(statBoltType_openBolt)

View File

@ -875,5 +875,23 @@
<Chinesesimp>备用枪管温度非常热</Chinesesimp>
<Chinese>備用槍管溫度超級熱</Chinese>
</Key>
<Key ID="STR_ACE_Overheating_statBoltType">
<English>Bolt Type</English>
</Key>
<Key ID="STR_ACE_Overheating_statBoltType_openBolt">
<English>Open Bolt</English>
</Key>
<Key ID="STR_ACE_Overheating_statBoltType_closedBolt">
<English>Closed Bolt</English>
</Key>
<Key ID="STR_ACE_Overheating_statBarrelType">
<English>Barrel Type</English>
</Key>
<Key ID="STR_ACE_Overheating_statBarrelType_nonRemoveable">
<English>Non-Removeable</English>
</Key>
<Key ID="STR_ACE_Overheating_statBarrelType_removeable">
<English>Quick Change</English>
</Key>
</Package>
</Project>

View File

@ -49,7 +49,8 @@ private _bulletSpeed = 0;
private _gravity = [0, sin(_scopeBaseAngle) * -GRAVITY, cos(_scopeBaseAngle) * -GRAVITY];
private _deltaT = 1 / _simSteps;
private _speedOfSound = 0;
if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then {
private _isABenabled = missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false];
if (_isABenabled) then {
_speedOfSound = _temperature call EFUNC(weather,calculateSpeedOfSound);
};
@ -68,7 +69,7 @@ if (_useABConfig) then {
};
private _airFrictionCoef = 1;
if (!_useABConfig && (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false])) then {
if (!_useABConfig && _isABenabled) then {
private _airDensity = [_temperature, _barometricPressure, _relativeHumidity] call EFUNC(weather,calculateAirDensity);
_airFrictionCoef = _airDensity / 1.22498;
};

View File

@ -107,12 +107,17 @@ private _transonicStabilityCoef = _ammoConfig select 4;
private _dragModel = _ammoConfig select 5;
private _atmosphereModel = _ammoConfig select 8;
private _useABConfig = (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]);
if (_bc == 0) then {
_useABConfig = false;
};
private _isABenabled = (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) && (_bc != 0);
private _useBarrelLengthInfluence = (
_isABenabled &&
{missionNamespace getVariable [QEGVAR(advanced_ballistics,barrelLengthInfluenceEnabled), false]}
);
private _useAmmoTemperatureInfluence = (
_isABenabled &&
{missionNamespace getVariable [QEGVAR(advanced_ballistics,ammoTemperatureEnabled), false]}
);
if (_barrelLength > 0 && _useABConfig) then {
if (_barrelLength > 0 && _useBarrelLengthInfluence) then {
_muzzleVelocity = [_barrelLength, _ammoConfig select 10, _ammoConfig select 11, 0] call EFUNC(advanced_ballistics,calculateBarrelLengthVelocityShift);
} else {
private _initSpeed = getNumber (configFile >> "CfgMagazines" >> _magazineClass >> "initSpeed");
@ -128,7 +133,7 @@ if (_barrelLength > 0 && _useABConfig) then {
ctrlSetText [770000, format["%1'' - %2 gr (%3)", round((_ammoConfig select 1) * 39.3700787) / 1000, round((_ammoConfig select 3) * 15.4323584), _ammoClass]];
if (_barrelLength > 0) then {
if (_useABConfig && _barrelTwist > 0) then {
if (_useBarrelLengthInfluence && _barrelTwist > 0) then {
ctrlSetText [770002, format["Barrel: %1'' 1:%2'' twist", round(2 * _barrelLength * 0.0393700787) / 2, round(_barrelTwist * 0.0393700787)]];
} else {
ctrlSetText [770002, format["Barrel: %1''", round(2 * _barrelLength * 0.0393700787) / 2]];
@ -136,7 +141,7 @@ if (_barrelLength > 0) then {
};
lnbAddRow [770100, ["4mps Wind(MRADs)", "1mps LEAD(MRADs)"]];
if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then {
if (_isABenabled) then {
lnbAddRow [770100, ["Air/Ammo Temp", "Air/Ammo Temp"]];
lnbAddRow [770200, ["-15°C", " -5°C", " 5°C", " 10°C", " 15°C", " 20°C", " 25°C", " 30°C", " 35°C"]];
@ -145,7 +150,7 @@ if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) t
ctrlSetText [77003, format["%1m ZERO", round(_zeroRange)]];
if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then {
if (_isABenabled) then {
ctrlSetText [770001, format["Drop Tables for B.P.: %1mb; Corrected for MVV at Air/Ammo Temperatures -15-35 °C", round(EGVAR(scopes,zeroReferenceBarometricPressure) * 100) / 100]];
ctrlSetText [77004 , format["B.P.: %1mb", round(EGVAR(scopes,zeroReferenceBarometricPressure) * 100) / 100]];
} else {
@ -153,30 +158,30 @@ if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) t
ctrlSetText [77004 , ""];
};
private _cacheEntry = missionNamespace getVariable format[QGVAR(%1_%2_%3_%4_%5), _zeroRange, _boreHeight, _ammoClass, _weaponClass, missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]];
if (isNil {_cacheEntry}) then {
private _scopeBaseAngle = if (!_useABConfig) then {
private _cacheEntry = missionNamespace getVariable format [QGVAR(%1_%2_%3_%4_%5_%6_%7), _zeroRange, _boreHeight, _ammoClass, _weaponClass, _isABenabled, _useBarrelLengthInfluence, _useAmmoTemperatureInfluence];
if (isNil "_cacheEntry") then {
private _scopeBaseAngle = if (!_isABenabled) then {
private _zeroAngle = "ace_advanced_ballistics" callExtension format ["calcZero:%1:%2:%3:%4", _zeroRange, _muzzleVelocity, _airFriction, _boreHeight];
(parseNumber _zeroAngle)
} else {
private _zeroAngle = "ace_advanced_ballistics" callExtension format ["calcZeroAB:%1:%2:%3:%4:%5:%6:%7:%8:%9", _zeroRange, _muzzleVelocity, _boreHeight, EGVAR(scopes,zeroReferenceTemperature), EGVAR(scopes,zeroReferenceBarometricPressure), EGVAR(scopes,zeroReferenceHumidity), _bc, _dragModel, _atmosphereModel];
(parseNumber _zeroAngle)
};
if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false] && missionNamespace getVariable [QEGVAR(advanced_ballistics,ammoTemperatureEnabled), false]) then {
if (_useAmmoTemperatureInfluence) then {
{
private _mvShift = [_ammoConfig select 9, _x] call EFUNC(advanced_ballistics,calculateAmmoTemperatureVelocityShift);
private _mv = _muzzleVelocity + _mvShift;
[_scopeBaseAngle,_boreHeight,_airFriction,_mv,_x,EGVAR(scopes,zeroReferenceBarometricPressure),EGVAR(scopes,zeroReferenceHumidity),200,4,1,GVAR(rangeCardEndRange),_bc,_dragModel,_atmosphereModel,_transonicStabilityCoef,_forEachIndex,_useABConfig] call FUNC(calculateRangeCard);
[_scopeBaseAngle,_boreHeight,_airFriction,_mv,_x,EGVAR(scopes,zeroReferenceBarometricPressure),EGVAR(scopes,zeroReferenceHumidity),200,4,1,GVAR(rangeCardEndRange),_bc,_dragModel,_atmosphereModel,_transonicStabilityCoef,_forEachIndex,_isABenabled] call FUNC(calculateRangeCard);
} forEach [-15, -5, 5, 10, 15, 20, 25, 30, 35];
} else {
[_scopeBaseAngle,_boreHeight,_airFriction,_muzzleVelocity,15,EGVAR(scopes,zeroReferenceBarometricPressure),EGVAR(scopes,zeroReferenceHumidity),200,4,1,GVAR(rangeCardEndRange),_bc,_dragModel,_atmosphereModel,_transonicStabilityCoef,3,_useABConfig] call FUNC(calculateRangeCard);
[_scopeBaseAngle,_boreHeight,_airFriction,_muzzleVelocity,15,EGVAR(scopes,zeroReferenceBarometricPressure),EGVAR(scopes,zeroReferenceHumidity),200,4,1,GVAR(rangeCardEndRange),_bc,_dragModel,_atmosphereModel,_transonicStabilityCoef,3,_isABenabled] call FUNC(calculateRangeCard);
};
for "_i" from 0 to 9 do {
GVAR(lastValidRow) pushBack count (GVAR(rangeCardDataElevation) select _i);
while {count (GVAR(rangeCardDataElevation) select _i) < 50} do {
if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then {
if (_isABenabled) then {
(GVAR(rangeCardDataElevation) select _i) pushBack "###";
(GVAR(rangeCardDataWindage) select _i) pushBack "##";
(GVAR(rangeCardDataLead) select _i) pushBack "##";
@ -188,7 +193,7 @@ if (isNil {_cacheEntry}) then {
};
};
missionNamespace setVariable [format[QGVAR(%1_%2_%3_%4_%5), _zeroRange, _boreHeight, _ammoClass, _weaponClass, missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]], [GVAR(rangeCardDataElevation), GVAR(rangeCardDataWindage), GVAR(rangeCardDataLead), GVAR(rangeCardDataMVs), GVAR(lastValidRow)]];
missionNamespace setVariable [format [QGVAR(%1_%2_%3_%4_%5_%6_%7), _zeroRange, _boreHeight, _ammoClass, _weaponClass, _isABenabled, _useBarrelLengthInfluence, _useAmmoTemperatureInfluence], [GVAR(rangeCardDataElevation), GVAR(rangeCardDataWindage), GVAR(rangeCardDataLead), GVAR(rangeCardDataMVs), GVAR(lastValidRow)]];
} else {
GVAR(rangeCardDataElevation) = _cacheEntry select 0;
GVAR(rangeCardDataWindage) = _cacheEntry select 1;

View File

@ -24,7 +24,6 @@ private _key = format ["weaponInfoCache-%1-%2-%3",_weaponClass,_magazineClass,_a
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);
@ -35,8 +34,14 @@ if ((_weaponInfo isEqualTo []) && {_magazineClass != ""}) then {
_weaponConfig params ["_barrelTwist", "_twistDirection", "_barrelLength"];
private _bc = if (_ballisticCoefficients isEqualTo []) then { 0 } else { _ballisticCoefficients # 0 };
private _useAB = (
missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false] &&
{missionNamespace getVariable [QEGVAR(advanced_ballistics,barrelLengthInfluenceEnabled), false]} &&
{_bc != 0}
);
// Get Muzzle Velocity
private _muzzleVelocity = if (_barrelLength > 0 && _useABConfig && {_bc != 0}) then {
private _muzzleVelocity = if (_barrelLength > 0 && _useAB) then {
[_barrelLength, _muzzleVelocityTable, _barrelLengthTable, 0] call EFUNC(advanced_ballistics,calculateBarrelLengthVelocityShift)
} else {
private _initSpeed = getNumber (configFile >> "CfgMagazines" >> _magazineClass >> "initSpeed");

View File

@ -21,7 +21,10 @@ This adds the possibility to draw accurate lines on the map screen.
### 1.2 Map tools
This adds map tools that can be used to measure distances between two points or bearings on the map.
### 1.3 GPS on map
### 1.3 Plotting Board
This adds a plotting board that can be used to aid in the rapid usage and adjustment of short-ranged indirect fires, as well as quick measurements of directions and distances between points, and general land-navigation.
### 1.4 GPS on map
If you are equipped with a vanilla GPS it will be shown on the map. (You don't need the `Map Tools` item in your inventory for this.)
## 2. Usage
@ -39,3 +42,15 @@ If you are equipped with a vanilla GPS it will be shown on the map. (You don't n
- Press <kbd>ALT</kbd> + <kbd>LMB</kbd> to start the line, left click again to end it.
- To delete a line press <kbd>Del</kbd> around the center of the line.
- Note that you can change the color of the lines by clicking on one of the coloured column on top of the screen (While the map is opened).
### 2.3 Using the plotting board
- To use map tools the `Plotting Board` item is required.
- Open the map <kbd>M</kbd> (Arma 3 default key bind `Map`).
- Press the self interaction key <kbd>Ctrl</kbd> + <kbd>&nbsp;Win</kbd> (ACE3 default key bind `Self Interaction Key`).
- Select `Show Plotting Board`.
- Note that you can drag the Plotting Board around with <kbd>LMB</kbd> and rotate the different parts of the Plotting Board, each independently from each other, with <kbd>Ctrl</kbd> + <kbd>LMB</kbd>.
### 2.4 Drawing lines
- You can draw lines on the plotting board.
- These lines are removed from the map once the plotting board is hidden, but they restored when the plotting board is shown again.
- These lines are moved along with the plotting board when the plotting board is dragged.