diff --git a/addons/common/XEH_postInit.sqf b/addons/common/XEH_postInit.sqf index 99feea14b..e39145c5f 100644 --- a/addons/common/XEH_postInit.sqf +++ b/addons/common/XEH_postInit.sqf @@ -318,6 +318,31 @@ if (isServer) then { _object enableSimulationGlobal _enable; }] call CBA_fnc_addEventHandler; + [QGVAR(transferOwnership), { + params ["_entities", "_target"]; + if (!(_entities isEqualType [])) then { + _entities = [_entities]; + }; + private _clientID = 0; + if (_target isEqualType 0) then { + _clientID = _target; + }; + if (_target isEqualType objNull) then { + _clientID = owner _target; + }; + { + if (_x isEqualType grpNull) then { + _x setGroupOwner _clientID; + } else { + if (group _x == grpNull) then { + _x setOwner _clientID; + } else { + group _x setGroupOwner _clientID; + }; + }; + } forEach _entities; + }] call CBA_fnc_addEventHandler; + [QGVAR(setFriend), { params ["_side1", "_side2", "_value"]; _side1 setFriend [_side2, _value]; diff --git a/addons/dialog/functions/fnc_close.sqf b/addons/dialog/functions/fnc_close.sqf index 159c4cdc1..3ead79713 100644 --- a/addons/dialog/functions/fnc_close.sqf +++ b/addons/dialog/functions/fnc_close.sqf @@ -38,5 +38,7 @@ if (_confirmed) then { [_values, _args] call _onCancel; }; +[QGVAR(close), [_display, _confirmed]] call CBA_fnc_localEvent; + // Close dialog, returning false to not override engine driven IDC_OK and IDC_CANCEL false diff --git a/addons/editor/XEH_PREP.hpp b/addons/editor/XEH_PREP.hpp index c35e8d435..2c2ca3335 100644 --- a/addons/editor/XEH_PREP.hpp +++ b/addons/editor/XEH_PREP.hpp @@ -1,6 +1,7 @@ PREP(addGroupIcons); PREP(declutterEmptyTree); PREP(fixSideButtons); +PREP(getSelection); PREP(handleKeyDown); PREP(handleLoad); PREP(handleModeButtons); @@ -9,6 +10,8 @@ PREP(handleSearchButton); PREP(handleSearchClick); PREP(handleSearchKeyDown); PREP(handleSearchKeyUp); +PREP(handleSelectionChanged); PREP(handleSideButtons); PREP(handleTreeButtons); PREP(handleUnload); +PREP(toggleSelectionPreview); diff --git a/addons/editor/XEH_preInit.sqf b/addons/editor/XEH_preInit.sqf index 3a9860073..59e6756e0 100644 --- a/addons/editor/XEH_preInit.sqf +++ b/addons/editor/XEH_preInit.sqf @@ -9,6 +9,11 @@ PREP_RECOMPILE_END; #include "initSettings.sqf" #include "initKeybinds.sqf" +GVAR(lastSelection) = []; +GVAR(savedSelection) = []; +GVAR(lastModuleIcon) = ""; +GVAR(savedModuleIcon) = ""; +GVAR(colour) = ["IGUI", "TEXT_RGB"] call BIS_fnc_displayColorGet; GVAR(clipboard) = []; GVAR(includeCrew) = true; @@ -16,6 +21,21 @@ GVAR(includeCrew) = true; params ["_logic"]; _logic addEventHandler ["CuratorObjectPlaced", {call FUNC(handleObjectPlaced)}]; + _logic addEventHandler ["CuratorGroupSelectionChanged", {call FUNC(handleSelectionChanged)}]; + _logic addEventHandler ["CuratorMarkerSelectionChanged", {call FUNC(handleSelectionChanged)}]; + _logic addEventHandler ["CuratorObjectSelectionChanged", {call FUNC(handleSelectionChanged)}]; + _logic addEventHandler ["CuratorWaypointSelectionChanged", {call FUNC(handleSelectionChanged)}]; }, true, [], true] call CBA_fnc_addClassEventHandler; +[QGVAR(ModuleSelChanged), { + params ["_moduleName"]; + + GVAR(savedModuleIcon) = GVAR(lastModuleIcon); + GVAR(lastModuleIcon) = getText (configFile >> "CfgVehicles" >> _moduleName >> "icon"); + + // Toggle selection preview + private _hasSelectionPreview = (getNumber (configFile >> "CfgVehicles" >> _moduleName >> QGVAR(hasSelectionPreview)) isEqualTo 1); + [_hasSelectionPreview] call FUNC(toggleSelectionPreview); +}] call CBA_fnc_addEventHandler; + ADDON = true; diff --git a/addons/editor/functions/fnc_getSelection.sqf b/addons/editor/functions/fnc_getSelection.sqf new file mode 100644 index 000000000..462a05345 --- /dev/null +++ b/addons/editor/functions/fnc_getSelection.sqf @@ -0,0 +1,54 @@ +#include "script_component.hpp" +/* + * Author: Ampersand, Kex + * Retrieves and marks the entities a module is applied to. + * This function is meant to be used inside module functions only. + * + * Arguments: + * None + * + * Return Value: + * 0: List of selected objects + * 1: List of selected groups + * 2: List of selected waypoints + * 3: List of selected markers + * + * Example: + * (call zen_editor_fnc_getSelection) params ["_objects", "_groups"]; + * + * Public: No + */ + +BIS_fnc_curatorObjectPlaced_mouseOver params [["_entityType", ""], ["_entity", nil]]; + +// Retrieve selection +GVAR(lastSelection) = switch (_entityType) do { + case "OBJECT": { + [[_entity], [], [], []]; + }; + case "GROUP": { + [[], [_entity], [], []]; + }; + case "ARRAY": { + [[], [], [_entity], []]; + }; + case "STRING": { + [[], [], [], [_entity]]; + }; + default { + GVAR(savedSelection); + }; +}; + +// Turn on selection preview +GVAR(lastModuleIcon) = GVAR(savedModuleIcon); +[true] call FUNC(toggleSelectionPreview); + +// Turn off selection preview when dialog is colosed +GVAR(endSelectionHandle) = [QEGVAR(dialog,close), { + [false] call FUNC(toggleSelectionPreview); + [QEGVAR(dialog,close), GVAR(endSelectionHandle)] call CBA_fnc_removeEventHandler; + GVAR(endSelectionHandle) = nil; +}] call CBA_fnc_addEventHandler; + +GVAR(lastSelection) diff --git a/addons/editor/functions/fnc_handleLoad.sqf b/addons/editor/functions/fnc_handleLoad.sqf index 079cc9d61..7a7212146 100644 --- a/addons/editor/functions/fnc_handleLoad.sqf +++ b/addons/editor/functions/fnc_handleLoad.sqf @@ -98,15 +98,30 @@ _display displayAddEventHandler ["KeyDown", {call FUNC(handleKeyDown)}]; IDC_RSCDISPLAYCURATOR_MAINMAP ]; +// Add tree selection changed events +private _ctrlTreeModule = _display displayCtrl IDC_RSCDISPLAYCURATOR_CREATE_MODULES; +_ctrlTreeModule ctrlAddEventHandler ["TreeSelChanged", { + params ["_ctrlTreeModule", "_selectedPath"]; + + [QGVAR(ModuleSelChanged), _ctrlTreeModule tvData _selectedPath] call CBA_fnc_localEvent; +}]; + private _ctrlTreeRecent = _display displayCtrl IDC_RSCDISPLAYCURATOR_CREATE_RECENT; _ctrlTreeRecent ctrlAddEventHandler ["TreeSelChanged", { params ["_ctrlTreeRecent", "_selectedPath"]; + private _recentTreeData = _ctrlTreeRecent tvData _selectedPath; // Store data of selected item to allow for deleting the of crew of objects placed through the recent tree - // tvCurSel is unavailable once the selected item has been placed, the empty path check ensures that the + // tvCurSel is unavailable once the selected item has been placed, the empty string check ensures that the // data is not cleared since this event occurs before the object placed event - if !(_selectedPath isEqualTo []) then { - GVAR(recentTreeData) = _ctrlTreeRecent tvData _selectedPath; + if !(_recentTreeData isEqualTo "") then { + GVAR(recentTreeData) = _recentTreeData; + }; + + if (_recentTreeData isKindOf "Module_F") then { + [QGVAR(ModuleSelChanged), _recentTreeData] call CBA_fnc_localEvent; + } else { + [QGVAR(ModuleSelChanged), ""] call CBA_fnc_localEvent; }; }]; diff --git a/addons/editor/functions/fnc_handleSelectionChanged.sqf b/addons/editor/functions/fnc_handleSelectionChanged.sqf new file mode 100644 index 000000000..ddcb944d8 --- /dev/null +++ b/addons/editor/functions/fnc_handleSelectionChanged.sqf @@ -0,0 +1,23 @@ +#include "script_component.hpp" +/* + * Author: Ampersand + * Saves curator selected entities for use by modules. + * + * Arguments: + * 0: Curator + * 0: Entity: group, marker, object, or waypoint + * + * Return Value: + * Handled + * + * Example: + * [CONTROL] call zen_editor_fnc_handleSelectionChanged + * + * Public: No + */ + +params ["_curator", "_entity"]; +GVAR(savedSelection) = GVAR(lastSelection); +GVAR(lastSelection) = curatorSelected; + +false diff --git a/addons/editor/functions/fnc_toggleSelectionPreview.sqf b/addons/editor/functions/fnc_toggleSelectionPreview.sqf new file mode 100644 index 000000000..1deea4cc8 --- /dev/null +++ b/addons/editor/functions/fnc_toggleSelectionPreview.sqf @@ -0,0 +1,38 @@ +#include "script_component.hpp" +/* + * Author: Ampersand, Kex + * Toggle preview of the current selection + * + * Arguments: + * 0: Turn on preview + * + * Return Value: + * None + * + * Example: + * [true] call zen_editor_fnc_toggleSelectionPreview; + * + * Public: No + */ + +params [["_turnOn", true, [true]]]; + +if (_turnOn) then { + if (isNil QGVAR(selectionIconHandler)) then { + GVAR(selectionIconHandler) = addMissionEventHandler ["Draw3D", { + if (curatorMouseOver isEqualTo [""]) then { + { + drawIcon3D [ + GVAR(lastModuleIcon), + GVAR(colour), getPosVisual _x, 1, 1, 0 + ]; + } forEach (GVAR(lastSelection) select 0); + }; + }]; + }; +} else { + if !(isNil QGVAR(selectionIconHandler)) then { + removeMissionEventHandler ["Draw3D", GVAR(selectionIconHandler)]; + GVAR(selectionIconHandler) = nil; + }; +}; diff --git a/addons/modules/CfgVehicles.hpp b/addons/modules/CfgVehicles.hpp index 0f4fac29c..65cbbd193 100644 --- a/addons/modules/CfgVehicles.hpp +++ b/addons/modules/CfgVehicles.hpp @@ -428,6 +428,15 @@ class CfgVehicles { function = QFUNC(moduleToggleLamps); icon = QPATHTOF(ui\street_lamp_ca.paa); }; + class GVAR(moduleTransferOwnership): GVAR(moduleBase) { + curatorCanAttach = 1; + category = QGVAR(DevTools); + displayName = CSTRING(ModuleTransferOwnership); + function = QFUNC(moduleTransferOwnership); + icon = "\a3\ui_f\data\Map\VehicleIcons\iconVirtual_ca.paa"; + portrait = "\a3\ui_f\data\Map\VehicleIcons\iconVirtual_ca.paa"; + EGVAR(editor,hasSelectionPreview) = 1; + }; 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..a216fdf9e 100644 --- a/addons/modules/XEH_PREP.hpp +++ b/addons/modules/XEH_PREP.hpp @@ -81,6 +81,7 @@ PREP(moduleTeleportPlayers); PREP(moduleToggleFlashlights); PREP(moduleToggleIRLasers); PREP(moduleToggleLamps); +PREP(moduleTransferOwnership); PREP(moduleTurretOptics); PREP(moduleUnGarrison); PREP(moduleVisibility); diff --git a/addons/modules/config.cpp b/addons/modules/config.cpp index 185538cc8..e338c068b 100644 --- a/addons/modules/config.cpp +++ b/addons/modules/config.cpp @@ -66,6 +66,7 @@ class CfgPatches { QGVAR(moduleToggleFlashlights), QGVAR(moduleToggleIRLasers), QGVAR(moduleToggleLamps), + QGVAR(ModuleTransferOwnership), QGVAR(moduleTurretOptics), QGVAR(moduleUnGarrison), QGVAR(moduleVisibility), diff --git a/addons/modules/functions/fnc_moduleTransferOwnership.sqf b/addons/modules/functions/fnc_moduleTransferOwnership.sqf new file mode 100644 index 000000000..f7a63ee11 --- /dev/null +++ b/addons/modules/functions/fnc_moduleTransferOwnership.sqf @@ -0,0 +1,101 @@ +#include "script_component.hpp" +/* + * Author: Ampersand + * Zeus module function to transfer ownership of objects and groups. + * + * Arguments: + * 0: Logic + * + * Return Value: + * None + * + * Example: + * [LOGIC] call zen_modules_fnc_moduleTransferOwnership + * + * Public: No + */ + +params ["_logic"]; +deleteVehicle _logic; + +if (!isMultiplayer) exitWith { + [LSTRING(OnlyMultiplayer)] call EFUNC(common,showMessage); +}; + +private _entities = []; +call EFUNC(editor,getSelection) params ["_objects", "_groups"]; +{ + if (isNull group _x) then { + _entities pushBack _x; + } else { + _groups pushBackUnique group _x; + }; +} forEach _objects; +_entities append _groups; + +if (_entities findIf {units _x findIf {isPlayer _x} > -1} != -1) exitWith { + [LSTRING(SelectionCannotIncludePlayers)] call EFUNC(common,showMessage); +}; + +private _targets = [2, clientOwner]; + +private _targetNames = [ + LSTRING(ModuleTransferOwnership_Server), + "str_a3_cfgvehicles_module_f_moduledescription_curator_f_1" +]; + +private _HCs = []; +private _players = []; +{ + if (_x isKindOf "HeadlessClient_F") then { + _HCs pushBack [name _x, _x]; + } else { + _players pushBack [name _x, _x]; + }; +} forEach allPlayers; +_HCs sort true; +_players sort true; +{ + _x params ["_name", "_entity"]; + _targetNames pushBack _name; + _targets pushBack _entity; +} forEach (_HCs + _players); + +// Set default target to curator, server, or HC depending on current locality +private _defaultTarget = [ + 1, + [2, 0] select (_HCs isEqualTo []) +] select (local (_entities select 0)); + +[LSTRING(ModuleTransferOwnership), [ + [ + "COMBO", + ELSTRING(common,Target), + [_targets, _targetNames, _defaultTarget], + true + ], + [ + "TOOLBOX", + [LSTRING(ModuleTransferOwnership_HCScripts), LSTRING(ModuleTransferOwnership_HCScripts_Description)], + [parseNumber (_defaultTarget == 2), 1, 2, [ + ELSTRING(common,Disabled), + ELSTRING(common,Enabled) + ]], + true + ] +], { + params ["_values", "_args"]; + _values params ["_target", "_HCState"]; + _args params ["_entities"]; + + // set headless client script flags + if (_HCState < 2) then { + if (isClass (configFile >> "CfgPatches" >> "acex_headless")) then { + { + _x setVariable ["ace_headless_blacklist", [false, true] select _HCState, true]; + } forEach _entities; + }; + }; + + [QEGVAR(common,transferOwnership), [_entities, _target]] call CBA_fnc_serverEvent; +}, {}, [_entities]] call EFUNC(dialog,create); diff --git a/addons/modules/stringtable.xml b/addons/modules/stringtable.xml index 77c79c459..29a49da5a 100644 --- a/addons/modules/stringtable.xml +++ b/addons/modules/stringtable.xml @@ -590,6 +590,34 @@ CAS - 爆撃 CAS - 폭탄 투하 + + Transfer Ownership + Transférer la propriété + Transferir propiedad + Передать владение + Besitztum verschieben + 所有権を移行 + 转让所有权 + 轉讓所有權 + + + Client + Client + Klient + + + Server + Serveur + Server + + + HC Scripts + Script pour HC + HC Skript + + + Flag the entity to for Headless Client transfer/balancing scripts such as ACEX + Bind Variable To Object Привязать переменную к объекту @@ -2208,6 +2236,16 @@ 소환 + + Selection cannot include players + La sélection ne permet pas de joueurs + Auswahl kann keine Spieler beinhalten + + + Module only available in multiplayer + Module est seulement disponible dans la mode multijoueur + Modul nur im Mehrspieler-Modus verfügbar + Place on a unit Placez sur une unité diff --git a/docs/user_guide/modules_list.md b/docs/user_guide/modules_list.md index 2c1b52e47..02ac50f9b 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. +## Transfer Ownership + +Transfer locality of objects and groups between server and clients. + ## Un-Garrison Group Un-garrisons units from the attached group.