diff --git a/addons/common/stringtable.xml b/addons/common/stringtable.xml index d7808e29d..a8720fbcf 100644 --- a/addons/common/stringtable.xml +++ b/addons/common/stringtable.xml @@ -246,6 +246,9 @@ 目標 목표 + + Cursor + Selected Unit Ausgewählte Einheit @@ -335,6 +338,12 @@ 固定式 고정 + + Weapon + + + Magazine + Nearest Le plus proche diff --git a/addons/modules/CfgVehicles.hpp b/addons/modules/CfgVehicles.hpp index 0f4fac29c..5965e98a9 100644 --- a/addons/modules/CfgVehicles.hpp +++ b/addons/modules/CfgVehicles.hpp @@ -22,6 +22,10 @@ class CfgVehicles { scopeCurator = 1; }; + class ModuleTracers_F: Module_F { + scopeCurator = 1; + }; + class ModuleCAS_F; class ModuleCASGun_F: ModuleCAS_F { scopeCurator = 1; @@ -428,6 +432,13 @@ class CfgVehicles { function = QFUNC(moduleToggleLamps); icon = QPATHTOF(ui\street_lamp_ca.paa); }; + class GVAR(moduleTracers): GVAR(moduleBase) { + category = "Effects"; + displayName = "$STR_a3_cfgvehicles_moduletracers_f_0"; + curatorInfoType = QGVAR(RscTracers); + icon = "\a3\modules_f_curator\Data\iconTracers_ca.paa"; + portrait = "\a3\modules_f_curator\Data\portraitTracers_ca.paa"; + }; class GVAR(moduleTurretOptics): GVAR(moduleBase) { curatorCanAttach = 1; category = QGVAR(Equipment); diff --git a/addons/modules/XEH_PREP.hpp b/addons/modules/XEH_PREP.hpp index e613aa852..748115c6d 100644 --- a/addons/modules/XEH_PREP.hpp +++ b/addons/modules/XEH_PREP.hpp @@ -8,6 +8,7 @@ PREP(compileEffects); PREP(compileFlags); PREP(compileMines); PREP(compileReinforcements); +PREP(compileTracers); PREP(gui_ambientFlyby); PREP(gui_cas); PREP(gui_damageBuildings); @@ -18,6 +19,7 @@ PREP(gui_globalHint); PREP(gui_setDate); PREP(gui_sideRelations); PREP(gui_spawnReinforcements); +PREP(gui_tracers); PREP(initDisplay); PREP(initModule); PREP(moduleAddFullArsenal); @@ -81,6 +83,7 @@ PREP(moduleTeleportPlayers); PREP(moduleToggleFlashlights); PREP(moduleToggleIRLasers); PREP(moduleToggleLamps); +PREP(moduleTracers); PREP(moduleTurretOptics); PREP(moduleUnGarrison); PREP(moduleVisibility); diff --git a/addons/modules/XEH_postInit.sqf b/addons/modules/XEH_postInit.sqf index f0eee5eaf..a80c1bcfe 100644 --- a/addons/modules/XEH_postInit.sqf +++ b/addons/modules/XEH_postInit.sqf @@ -6,6 +6,7 @@ if (isServer) then { [QGVAR(moduleCAS), LINKFUNC(moduleCAS)] call CBA_fnc_addEventHandler; [QGVAR(moduleEditableObjects), LINKFUNC(moduleEditableObjects)] call CBA_fnc_addEventHandler; [QGVAR(moduleSpawnReinforcements), LINKFUNC(moduleSpawnReinforcements)] call CBA_fnc_addEventHandler; + [QGVAR(moduleTracers), LINKFUNC(moduleTracers)] call CBA_fnc_addEventHandler; // Public variable to track created teleporter objects missionNamespace setVariable [QGVAR(teleporters), [], true]; diff --git a/addons/modules/XEH_preStart.sqf b/addons/modules/XEH_preStart.sqf index b5d9dd3ef..adb11dde3 100644 --- a/addons/modules/XEH_preStart.sqf +++ b/addons/modules/XEH_preStart.sqf @@ -8,3 +8,4 @@ call FUNC(compileEffects); call FUNC(compileFlags); call FUNC(compileMines); call FUNC(compileReinforcements); +call FUNC(compileTracers); diff --git a/addons/modules/config.cpp b/addons/modules/config.cpp index 185538cc8..6150f0717 100644 --- a/addons/modules/config.cpp +++ b/addons/modules/config.cpp @@ -66,6 +66,7 @@ class CfgPatches { QGVAR(moduleToggleFlashlights), QGVAR(moduleToggleIRLasers), QGVAR(moduleToggleLamps), + QGVAR(moduleTracers), QGVAR(moduleTurretOptics), QGVAR(moduleUnGarrison), QGVAR(moduleVisibility), diff --git a/addons/modules/functions/fnc_compileTracers.sqf b/addons/modules/functions/fnc_compileTracers.sqf new file mode 100644 index 000000000..083d74c8c --- /dev/null +++ b/addons/modules/functions/fnc_compileTracers.sqf @@ -0,0 +1,52 @@ +#include "script_component.hpp" +/* + * Author: Ampersand, mharis001 + * Compiles a list of weapons that have compatible tracer magazines. + * + * Arguments: + * None + * + * Return Value: + * None + * + * Example: + * [] call zen_modules_fnc_compileTracers + * + * Public: No + */ + +private _tracersCache = createHashMap; +private _cfgMagazines = configFile >> "CfgMagazines"; +private _cfgMagazineWells = configFile >> "CfgMagazineWells"; + +{ + if ( + getNumber (_x >> "scope") == 2 + && {getNumber (_x >> "type") == TYPE_WEAPON_PRIMARY} + && {count getArray (_x >> "muzzles") == 1} + ) then { + private _weapon = configName _x; + + if (getText (_x >> "baseWeapon") == _weapon) then { + private _magazines = getArray (_x >> "magazines"); + + { + { + _magazines insert [-1, getArray _x, true]; + } forEach configProperties [_cfgMagazineWells >> _x, "isArray _x", false]; + } forEach getArray (_x >> "magazineWell"); + + private _tracerMagazines = _magazines select { + getNumber (_cfgMagazines >> _x >> "tracersEvery") == 1 + } apply { + configName (_cfgMagazines >> _x) + }; + + if (_tracerMagazines isNotEqualTo []) then { + _tracersCache set [_weapon, _tracerMagazines]; + }; + }; + }; +} forEach configProperties [configFile >> "CfgWeapons", "isClass _x"]; + +uiNamespace setVariable [QGVAR(tracersCache), _tracersCache]; diff --git a/addons/modules/functions/fnc_gui_tracers.sqf b/addons/modules/functions/fnc_gui_tracers.sqf new file mode 100644 index 000000000..6bd1a234d --- /dev/null +++ b/addons/modules/functions/fnc_gui_tracers.sqf @@ -0,0 +1,191 @@ +#include "script_component.hpp" +/* + * Author: Ampersand, mharis001 + * Initializes the "Tracers" Zeus module display. + * + * Arguments: + * 0: Display + * 1: Logic + * + * Return Value: + * None + * + * Example: + * [DISPLAY, LOGIC] call zen_modules_fnc_gui_tracers + * + * Public: No + */ + +params ["_display", "_logic"]; + +// Get the current tracer parameters (use default if module has not been initialized yet) +private _params = _logic getVariable QGVAR(tracersParams); +private _isInit = isNil "_params"; + +if (_isInit) then { + _params = ["LMG_Mk200_F", "200Rnd_65x39_cased_Box_Tracer_Red", [5, 10, 15], 2, objNull]; +}; + +_params params ["_weapon", "_magazine", "_delay", "_dispersion", "_target"]; + +// Store the logic and target (in case the target is not changed) +_display setVariable [QGVAR(params), [_logic, _target]]; + +// Populate the weapons list +private _ctrlWeapon = _display displayCtrl IDC_TRACERS_WEAPON; +private _cfgWeapons = configFile >> "CfgWeapons"; + +{ + private _config = _cfgWeapons >> _x; + private _name = getText (_config >> "displayName"); + private _icon = getText (_config >> "picture"); + + private _index = _ctrlWeapon lnbAddRow ["", _name]; + _ctrlWeapon lnbSetTooltip [[_index, 0], format ["%1\n%2", _name, _x]]; + _ctrlWeapon lnbSetPicture [[_index, 0], _icon]; + _ctrlWeapon lnbSetData [[_index, 0], _x]; +} forEach keys (uiNamespace getVariable QGVAR(tracersCache)); + +_ctrlWeapon lnbSort [1]; + +// Refresh the magazines list when a weapon is selected +_ctrlWeapon ctrlAddEventHandler ["LBSelChanged", { + params ["_ctrlWeapon", "_index"]; + + private _display = ctrlParent _ctrlWeapon; + private _weapon = _ctrlWeapon lnbData [_index, 0]; + + private _ctrlMagazine = _display displayCtrl IDC_TRACERS_MAGAZINE; + private _cfgMagazines = configFile >> "CfgMagazines"; + + lnbClear _ctrlMagazine; + + { + private _config = _cfgMagazines >> _x; + private _name = getText (_config >> "displayName"); + private _icon = getText (_config >> "picture"); + + private _index = _ctrlMagazine lnbAddRow ["", _name]; + _ctrlMagazine lnbSetTooltip [[_index, 0], format ["%1\n%2", _name, _x]]; + _ctrlMagazine lnbSetPicture [[_index, 0], _icon]; + _ctrlMagazine lnbSetData [[_index, 0], _x]; + } forEach (uiNamespace getVariable QGVAR(tracersCache) get _weapon); + + _ctrlMagazine lnbSort [1]; + _ctrlMagazine lnbSetCurSelRow 0; +}]; + +// Select the current weapon in the list (also initially populates magazines list) +for "_i" from 0 to (lnbSize _ctrlWeapon select 0) - 1 do { + if (_ctrlWeapon lnbData [_i, 0] == _weapon) exitWith { + _ctrlWeapon lnbSetCurSelRow _i; + }; +}; + +// Select the current magazine in the list +private _ctrlMagazine = _display displayCtrl IDC_TRACERS_MAGAZINE; + +for "_i" from 0 to (lnbSize _ctrlMagazine select 0) - 1 do { + if (_ctrlMagazine lnbData [_i, 0] == _magazine) exitWith { + _ctrlMagazine lnbSetCurSelRow _i; + }; +}; + +// Populate the burst delay edit boxes with the current values +{ + private _ctrlDelay = _display displayCtrl _x; + _ctrlDelay ctrlSetText str parseNumber (_delay select _forEachIndex toFixed 3); +} forEach [IDC_TRACERS_DELAY_MIN, IDC_TRACERS_DELAY_MID, IDC_TRACERS_DELAY_MAX]; + +// Select the current dispersion value +private _ctrlDispersion = _display displayCtrl IDC_TRACERS_DISPERSION; +_ctrlDispersion lbSetCurSel _dispersion; + +// Initialize the target toolbox based on if the module has been initialized already +private _ctrlTarget = _display displayCtrl IDC_TRACERS_TARGET; +private _ctrlChange = _display displayCtrl IDC_TRACERS_CHANGE; + +if (_isInit) then { + // Hide the change target checkbox if the module has not been initialized + // In this situation, the user must select a target + _ctrlChange cbSetChecked true; + _ctrlChange ctrlShow false; +} else { + // Enable the target toolbox when change target checkbox is checked + _ctrlChange ctrlAddEventHandler ["CheckedChanged", { + params ["_ctrlChange", "_checked"]; + + private _display = ctrlParent _ctrlChange; + private _enabled = _checked == 1; + + private _ctrlTarget = _display displayCtrl IDC_TRACERS_TARGET; + _ctrlTarget ctrlEnable _enabled; + + private _ctrlOverlay = _display getVariable QGVAR(overlay); + _ctrlOverlay ctrlShow !_enabled; + }]; + + // Disable the target toolbox to leave the target unchanged by default + _ctrlTarget ctrlEnable false; + + // Toolbox control by default does not look different when disabled + // Using an overlay control to better convey when the toolbox is disabled + private _ctrlOverlay = _display ctrlCreate ["RscText", -1, ctrlParentControlsGroup _ctrlTarget]; + _ctrlOverlay ctrlSetBackgroundColor [0, 0, 0, 0.5]; + _ctrlOverlay ctrlSetPosition ctrlPosition _ctrlTarget; + _ctrlOverlay ctrlCommit 0; + + _display setVariable [QGVAR(overlay), _ctrlOverlay]; +}; + +// Confirm options when the OK button is clicked +private _ctrlButtonOK = _display displayCtrl IDC_OK; +_ctrlButtonOK ctrlAddEventHandler ["ButtonClick", { + params ["_ctrlButtonOK"]; + + private _display = ctrlParent _ctrlButtonOK; + (_display getVariable QGVAR(params)) params ["_logic", "_target"]; + + private _ctrlWeapon = _display displayCtrl IDC_TRACERS_WEAPON; + private _weapon = _ctrlWeapon lnbData [lnbCurSelRow _ctrlWeapon, 0]; + + private _ctrlMagazine = _display displayCtrl IDC_TRACERS_MAGAZINE; + private _magazine = _ctrlMagazine lnbData [lnbCurSelRow _ctrlMagazine, 0]; + + private _delay = [IDC_TRACERS_DELAY_MIN, IDC_TRACERS_DELAY_MID, IDC_TRACERS_DELAY_MAX] apply { + parseNumber ctrlText (_display displayCtrl _x) + }; + + private _dispersion = lbCurSel (_display displayCtrl IDC_TRACERS_DISPERSION); + + // Select tracers target based on checkbox and toolbox state + private _targetType = if (cbChecked (_display displayCtrl IDC_TRACERS_CHANGE)) then { + lbCurSel (_display displayCtrl IDC_TRACERS_TARGET) + } else { + -1 // Unchanged + }; + + if (_targetType == 2) exitWith { + [_logic, { + params ["_successful", "_logic", "_position", "_args"]; + _args params ["_weapon", "_magazine", "_delay", "_dispersion"]; + + if (_successful) then { + curatorMouseOver params ["_type", "_entity"]; + + private _target = [_position, _entity] select (_type == "OBJECT"); + [QGVAR(moduleTracers), [_logic, _weapon, _magazine, _delay, _dispersion, _target]] call CBA_fnc_serverEvent; + }; + }, [_weapon, _magazine, _delay, _dispersion], LSTRING(Tracers_TracersTarget)] call EFUNC(common,selectPosition); + }; + + if (_targetType == 1) then { + _target = AGLToASL positionCameraToWorld [0, 0, 0]; + }; + + if (_targetType == 0) then { + _target = objNull; + }; + + [QGVAR(moduleTracers), [_logic, _weapon, _magazine, _delay, _dispersion, _target]] call CBA_fnc_serverEvent; +}]; diff --git a/addons/modules/functions/fnc_moduleTracers.sqf b/addons/modules/functions/fnc_moduleTracers.sqf new file mode 100644 index 000000000..cbde38d93 --- /dev/null +++ b/addons/modules/functions/fnc_moduleTracers.sqf @@ -0,0 +1,124 @@ +#include "script_component.hpp" +/* + * Author: Ampersand + * Zeus module function create a tracers effect. + * + * Arguments: + * 0: Logic + * 1: Weapon + * 2: Magazine + * 3: Burst Delay + * 4: Dispersion + * 5: Target + * + * Return Value: + * None + * + * Example: + * [LOGIC, _weapon, _magazine, _delay, _dispersion, _target] call zen_modules_fnc_moduleTracers + * + * Public: No + */ + +params ["_logic", "_weapon", "_magazine", "_delay", "_dispersion", "_target"]; + +// Broadcast tracer parameters so they available if the module is edited +_logic setVariable [QGVAR(tracersParams), [_weapon, _magazine, _delay, _dispersion, _target], true]; + +// Create random dispersion array from dispersion index +_dispersion = [0.001, 0.01, 0.05, 0.15, 0.3] select _dispersion; +_dispersion = [-_dispersion, 0, _dispersion]; + +// Delete any already created gunner +private _gunner = _logic getVariable [QGVAR(tracersGunner), objNull]; +deleteVehicle _gunner; + +// Create a new gunner and add the specified weapon and magazine to it +_gunner = createAgent ["B_Soldier_F", [0, 0, 0], [], 0, "NONE"]; +_gunner attachTo [_logic, [0, 0, 0]]; +_gunner hideObjectGlobal true; +_gunner allowDamage false; +_gunner setCaptive true; +_gunner switchMove "AmovPercMstpSrasWrflDnon"; +_gunner disableAI "ANIM"; +_gunner disableAI "MOVE"; +_gunner disableAI "TARGET"; +_gunner disableAI "AUTOTARGET"; +_gunner setBehaviour "CARELESS"; +_gunner setCombatMode "BLUE"; + +_gunner setUnitLoadout (configFile >> "EmptyLoadout"); +_gunner addWeapon _weapon; +_gunner selectWeapon _weapon; +_gunner addWeaponItem [_weapon, _magazine, true]; + +_logic setVariable [QGVAR(tracersGunner), _gunner]; + +[{ + params ["_args", "_pfhID"]; + _args params ["_logic", "_gunner", "_target", "_weapon", "_delay", "_dispersion", "_nextBurstTime"]; + + if (!alive _logic || {!alive _gunner}) exitWith { + [_pfhID] call CBA_fnc_removePerFrameHandler; + deleteVehicle _gunner; + }; + + if (CBA_missionTime >= _nextBurstTime && {allPlayers findIf {_gunner distance _x < 100} == -1}) then { + private "_targetVector"; + + if (_target isNotEqualTo objNull) then { + // Set vector to target if one is specified + if (_target isEqualType objNull) then { + _target = getPosASLVisual _target; + }; + + // Randomize target vector based on dispersion + _targetVector = getPosASLVisual _logic vectorFromTo _target; + _targetVector = vectorNormalized (_targetVector vectorAdd [random _dispersion, random _dispersion, random _dispersion]); + _logic setVectorDirAndUp [_targetVector, _targetVector vectorCrossProduct [-(_targetVector select 1), _targetVector select 0, 0]]; + } else { + // No specific target, fire randomly in the air + _gunner setDir random 360; + [_gunner, 30 + random 60, 0] call BIS_fnc_setPitchBank; + }; + + private _burstLength = 0.1 + random 0.9; + + // Wait until gunner is on-target before starting burst + [{ + params ["_logic", "_gunner", "_targetVector"]; + + !alive _logic + || {!alive _gunner} + || {isNil "_targetVector"} + || {vectorDirVisual _gunner vectorDotProduct _targetVector > 0.95} + }, { + params ["_logic", "_gunner", "", "_weapon", "_burstLength", "_startTime"]; + + // Exit if aligning to target took too long + private _timeout = _burstLength - (CBA_missionTime - _startTime); + if (_timeout <= 0) exitWith {}; + + [{ + params ["_logic", "_gunner", "_weapon", "_nextShotTime"]; + + if (!alive _logic || {!alive _gunner}) exitWith { + true + }; + + if (CBA_missionTime >= _nextShotTime) then { + _gunner setAmmo [_weapon, 999]; + [_gunner, _weapon] call BIS_fnc_fire; + + private _shotDelay = 0.05 + random 0.1; + _this set [3, CBA_missionTime + _shotDelay]; + }; + + false + }, {}, [_logic, _gunner, _weapon, 0], _timeout] call CBA_fnc_waitUntilAndExecute; + }, [_logic, _gunner, _targetVector, _weapon, _burstLength, CBA_missionTime], _burstLength] call CBA_fnc_waitUntilAndExecute; + + // Ensure a new burst is not started until this one finishes + _args set [6, CBA_missionTime + (random _delay max _burstLength)]; + }; +}, 0.1, [_logic, _gunner, _target, _weapon, _delay, _dispersion, 0]] call CBA_fnc_addPerFrameHandler; diff --git a/addons/modules/gui.hpp b/addons/modules/gui.hpp index 6c6bea5f1..070a6c13f 100644 --- a/addons/modules/gui.hpp +++ b/addons/modules/gui.hpp @@ -1192,3 +1192,141 @@ class GVAR(RscSpawnReinforcements): GVAR(RscDisplay) { class ButtonCancel: ButtonCancel {}; }; }; + +class GVAR(RscTracers): GVAR(RscDisplay) { + function = QFUNC(gui_tracers); + checkLogic = 1; + class controls: controls { + class Title: Title {}; + class Background: Background {}; + class Content: Content { + h = POS_H(19.4); + class controls { + class WeaponLabel: EGVAR(common,RscLabel) { + text = ECSTRING(common,Weapon); + w = POS_W(26); + }; + class WeaponBackground: EGVAR(common,RscBackground) { + x = 0; + y = POS_H(1); + w = POS_W(26); + h = POS_H(5); + }; + class Weapon: ctrlListNBox { + idc = IDC_TRACERS_WEAPON; + x = 0; + y = POS_H(1); + w = POS_W(26); + h = POS_H(5); + rowHeight = POS_H(1.2); + columns[] = {0.05, 0.15}; + tooltipPerColumn = 0; + }; + class MagazineLabel: WeaponLabel { + text = ECSTRING(common,Magazine); + y = POS_H(6.1); + }; + class MagazineBackground: WeaponBackground { + y = POS_H(7.1); + }; + class Magazine: Weapon { + idc = IDC_TRACERS_MAGAZINE; + y = POS_H(7.1); + }; + class DelayLabel: WeaponLabel { + text = CSTRING(Tracers_BurstDelay); + tooltip = CSTRING(Tracers_BurstDelay_Tooltip); + y = POS_H(12.2); + }; + class DelayBackground: WeaponBackground { + y = POS_H(13.2); + h = POS_H(2); + }; + class DelayMinLabel: RscText { + style = ST_RIGHT; + text = "$STR_3DEN_Attributes_Timeout_TitleMin_text"; + font = "RobotoCondensedLight"; + x = POS_W(4); + y = POS_H(13.7); + w = POS_W(2); + h = POS_H(1); + shadow = 0; + }; + class DelayMin: EGVAR(common,RscEdit) { + idc = IDC_TRACERS_DELAY_MIN; + font = "EtelkaMonospacePro"; + x = POS_W(6); + y = POS_H(13.7); + w = POS_W(4); + h = POS_H(1); + sizeEx = POS_H(0.8); + }; + class DelayMidLabel: DelayMinLabel { + text = "$STR_3DEN_Attributes_Timeout_TitleMid_text"; + x = POS_W(10); + }; + class DelayMid: DelayMin { + idc = IDC_TRACERS_DELAY_MID; + x = POS_W(12); + }; + class DelayMaxLabel: DelayMinLabel { + text = "$STR_3DEN_Attributes_Timeout_TitleMax_text"; + x = POS_W(16); + }; + class DelayMax: DelayMin { + idc = IDC_TRACERS_DELAY_MAX; + x = POS_W(18); + }; + class DispersionLabel: WeaponLabel { + text = CSTRING(Tracers_Dispersion); + tooltip = CSTRING(Tracers_Dispersion_Tooltip); + y = POS_H(15.3); + }; + class Dispersion: ctrlToolbox { + idc = IDC_TRACERS_DISPERSION; + x = 0; + y = POS_H(16.3); + w = POS_W(26); + h = POS_H(1); + rows = 1; + columns = 5; + strings[] = { + ECSTRING(common,VeryLow), + ECSTRING(common,Low), + ECSTRING(common,Medium), + ECSTRING(common,High), + ECSTRING(common,VeryHigh) + }; + }; + class TargetLabel: WeaponLabel { + text = "$STR_A3_CfgVehicles_ModuleAI_F_Arguments_Target_0"; + y = POS_H(17.4); + }; + class Target: Dispersion { + idc = IDC_TRACERS_TARGET; + y = POS_H(18.4); + columns = 3; + strings[] = { + "$STR_A3_RscDisplayArsenal_ButtonRandom", + "$STR_3DEN_Camera_textSingular", + ECSTRING(common,Cursor) + }; + tooltips[] = { + CSTRING(Tracers_Random_Tooltip), + CSTRING(Tracers_Camera_Tooltip), + CSTRING(Tracers_Cursor_Tooltip) + }; + }; + class Change: ctrlCheckbox { + idc = IDC_TRACERS_CHANGE; + x = POS_W(25); + y = POS_H(17.4); + w = POS_W(1); + h = POS_H(1); + }; + }; + }; + class ButtonOK: ButtonOK {}; + class ButtonCancel: ButtonCancel {}; + }; +}; diff --git a/addons/modules/script_component.hpp b/addons/modules/script_component.hpp index 13fafffc8..31e87de1c 100644 --- a/addons/modules/script_component.hpp +++ b/addons/modules/script_component.hpp @@ -126,6 +126,15 @@ #define IDC_SPAWNREINFORCEMENTS_UNIT_RP 62315 #define IDC_SPAWNREINFORCEMENTS_UNIT_BEHAVIOUR 62316 +#define IDC_TRACERS_WEAPON 62400 +#define IDC_TRACERS_MAGAZINE 62401 +#define IDC_TRACERS_DELAY_MIN 62402 +#define IDC_TRACERS_DELAY_MID 62403 +#define IDC_TRACERS_DELAY_MAX 62404 +#define IDC_TRACERS_DISPERSION 62405 +#define IDC_TRACERS_TARGET 62406 +#define IDC_TRACERS_CHANGE 62407 + #define ICON_HOSTILE "\a3\ui_f\data\igui\cfg\simpletasks\types\attack_ca.paa" #define ICON_FRIENDLY "\a3\ui_f\data\igui\cfg\simpletasks\types\help_ca.paa" diff --git a/addons/modules/stringtable.xml b/addons/modules/stringtable.xml index 77c79c459..e8f8396a5 100644 --- a/addons/modules/stringtable.xml +++ b/addons/modules/stringtable.xml @@ -2047,6 +2047,30 @@ 전등이 켜질때 부러진 것들을 수리합니다. Napraw zepsute lampy przed włączeniem. + + Burst Delay + + + The delay, in seconds, between bursts of tracers.\nSelected randomly in a range from min to max, gravitating towards mid. + + + Dispersion + + + The dispersion of the fired tracer rounds. + + + Tracers are fired randomly in the air. + + + Tracers are fired at the current camera position. + + + Tracers target is selected using the cursor after closing the dialog. + + + Tracers Target + Custom Fire Benutzerdefiniertes Feuer diff --git a/docs/user_guide/modules_list.md b/docs/user_guide/modules_list.md index 2c1b52e47..a8393267d 100644 --- a/docs/user_guide/modules_list.md +++ b/docs/user_guide/modules_list.md @@ -271,6 +271,10 @@ Toggles the simulation of the attached object. Toggles the visibility of the attached object. +## Tracers + +Creates an invisible unit that shoots customizable tracer bursts at a specified target when no players are within 100 m of the module. + ## Un-Garrison Group Un-garrisons units from the attached group.