diff --git a/addons/sys_core/CfgVehicles.hpp b/addons/sys_core/CfgVehicles.hpp new file mode 100644 index 000000000..1c48c4a0c --- /dev/null +++ b/addons/sys_core/CfgVehicles.hpp @@ -0,0 +1,25 @@ +class CfgNonAIVehicles { + class GVAR(connectorWireSegment) { + scope = 2; + displayName = "Connector Wire"; + simulation = "ropesegment"; + autocenter = 0; + animated = 0; + model = QPATHTOF(data\wire.p3d); + }; +}; + +class CfgVehicles { + class Rope; + class GVAR(connectorWire): Rope { + segmentType = QGVAR(connectorWireSegment); + model = QPATHTOF(data\wire.p3d); + }; + + class Car; + class GVAR(connectorHelper): Car { + displayName = "Connector Rope Helper"; + model = "core\default\default.p3d"; + scope = 2; + }; +}; diff --git a/addons/sys_core/XEH_PREP.hpp b/addons/sys_core/XEH_PREP.hpp index ad378e033..b2220f32e 100644 --- a/addons/sys_core/XEH_PREP.hpp +++ b/addons/sys_core/XEH_PREP.hpp @@ -18,6 +18,7 @@ PREP(getLanguageName); PREP(getPlayersInVehicle); PREP(getSpeakingLanguageId); PREP(getSpokenLanguages); +PREP(handleConnectorRope); PREP(handleGetClientID); PREP(handleGetHeadVector); PREP(handleGetPluginVersion); diff --git a/addons/sys_core/XEH_preInit.sqf b/addons/sys_core/XEH_preInit.sqf index e85653d18..2e2b0be49 100644 --- a/addons/sys_core/XEH_preInit.sqf +++ b/addons/sys_core/XEH_preInit.sqf @@ -9,6 +9,15 @@ PREP_RECOMPILE_END; // CBA Settings #include "initSettings.inc.sqf" +if (isServer) then { + [QGVAR(hideConnectorRopeHelpers), { + params ["_ropeHelpers"]; + { hideObjectGlobal _x; } forEach _ropeHelpers; + }] call CBA_fnc_addEventHandler; +}; + +[QGVAR(handleConnectorRopeEvent), FUNC(handleConnectorRope)] call CBA_fnc_addEventHandler; + if (!hasInterface) exitWith { ADDON = true; }; @@ -46,6 +55,9 @@ DGVAR(pttKeyDown) = false; DGVAR(speaking_cache_valid) = false; +DGVAR(connectorRope) = objNull; +DGVAR(connectorRopeHelpers) = [objNull, objNull]; + DVAR(ACRE_SPIT_VERSION) = false; DVAR(ACRE_IS_SYNCING) = false; DVAR(ACRE_SPECTATORS_LIST) = []; diff --git a/addons/sys_core/config.cpp b/addons/sys_core/config.cpp index ece4e535f..bcb54e52c 100644 --- a/addons/sys_core/config.cpp +++ b/addons/sys_core/config.cpp @@ -14,6 +14,7 @@ class CfgPatches { }; #include "CfgEventHandlers.hpp" #include "CfgSounds.hpp" +#include "CfgVehicles.hpp" class CfgAcreWorlds { diff --git a/addons/sys_core/data/wire.cfg b/addons/sys_core/data/wire.cfg new file mode 100644 index 000000000..8b31f5e83 --- /dev/null +++ b/addons/sys_core/data/wire.cfg @@ -0,0 +1,7 @@ +class CfgModels { + class wire { + sectionsInherit = ""; + sections[] = {"rope"}; + skeletonName = ""; + }; +}; diff --git a/addons/sys_core/data/wire.p3d b/addons/sys_core/data/wire.p3d new file mode 100644 index 000000000..920f10c89 Binary files /dev/null and b/addons/sys_core/data/wire.p3d differ diff --git a/addons/sys_core/fnc_handleConnectorRope.sqf b/addons/sys_core/fnc_handleConnectorRope.sqf new file mode 100644 index 000000000..24b64f452 --- /dev/null +++ b/addons/sys_core/fnc_handleConnectorRope.sqf @@ -0,0 +1,90 @@ +#include "script_component.hpp" +/* + * Author: mrschick + * Handles PhysX Ropes to represent "connector wires" for infantry phone, GSA, radio sharing, etc. + * + * Arguments: + * 0: State: true to create rope, false to remove + * 1: Type of object to connect to: 0 = Infantry Phone, 1 = GSA, 2 = Shared radio (default: 0) + * 2: Vehicle or object the rope starts from (default: objNull) + * 3: Unit the rope should be attached to (default: objNull) + * 4: Relative position offset for where the rope starts from (default: [0,0,0]) + * + * Return Value: + * None + * + * Example: + * [true, _vehicle, _player, _infantryPhonePosition] call acre_sys_intercom_fnc_handleConnectorRope + * [false] call acre_sys_intercom_fnc_handleConnectorRope + * + * Public: No + */ + +params ["_state", ["_type", 0], ["_fromObject", objNull], ["_toObject", objNull], ["_fromPoint", [0, 0, 0]]]; + +if (!EGVAR(sys_gestures,showConnectorRopes)) exitWith {}; + +if (_state) then { + // Destroy any previous connector rope and helpers + if (!isNull GVAR(connectorRope) || {GVAR(connectorRopeHelpers) isNotEqualTo [objNull, objNull]}) then { + [false] call FUNC(handleConnectorRope); + }; + + private _connectorRopeHelpers = []; + private _connectorRope = objNull; + + switch (_type) do { + case 0: { // Connect rope to Infantry Phone + // If _fromPoint could not be provided by the intercom passing action, fetch it again from config + if (_fromPoint isEqualTo [-1]) then { + private _positionConfig = configFile >> "CfgVehicles" >> typeOf _fromObject >> "acre_infantryPhonePosition"; + if (isText _positionConfig) then { + _fromPoint = _target selectionPosition (getText _positionConfig); // Convert to coordinates for sys_core intercomPFH checks + }; + if (isArray _positionConfig) then { + _fromPoint = getArray _positionConfig; + }; + }; + + // Create Rope + _connectorRope = ropeCreate [_fromObject, _fromPoint, 3, nil, nil, QGVAR(connectorWire)]; + + // Create helper object on player pelvis + _connectorRopeHelpers set [0, ROPE_HELPER createVehicle position _toObject]; + (_connectorRopeHelpers select 0) ropeAttachTo _connectorRope; + (_connectorRopeHelpers select 0) attachTo [_toObject, [-0.1, 0.1, 0.25], "Pelvis"]; + (_connectorRopeHelpers select 0) allowDamage false; + + // Hide Helper Object + [QGVAR(hideConnectorRopeHelpers), [_connectorRopeHelpers]] call CBA_fnc_serverEvent; + }; + case 1: { // Connect rope to Ground Spike Antenna + // Create helper object on GSA + _connectorRopeHelpers set [0, ROPE_HELPER createVehicle position _fromObject]; + (_connectorRopeHelpers select 0) disableCollisionWith _fromObject; + (_connectorRopeHelpers select 0) setPos (position _fromObject); + (_connectorRopeHelpers select 0) allowDamage false; + + // Create helper object on player pelvis + _connectorRopeHelpers set [1, ROPE_HELPER createVehicle position _toObject]; + (_connectorRopeHelpers select 1) attachTo [_toObject, [-0.1, 0.1, 0.15], "Pelvis"]; + (_connectorRopeHelpers select 1) allowDamage false; + + // Hide Helper Objects + [QGVAR(hideConnectorRopeHelpers), [_connectorRopeHelpers]] call CBA_fnc_serverEvent; + + // Create Rope between helper objects + _connectorRope = ropeCreate [_connectorRopeHelpers select 0, _fromPoint, 5, nil, nil, QGVAR(connectorWire)]; + (_connectorRopeHelpers select 1) ropeAttachTo _connectorRope; + }; + }; + + GVAR(connectorRope) = _connectorRope; + GVAR(connectorRopeHelpers) = _connectorRopeHelpers; +} else { + // Destroy rope + ropeDestroy GVAR(connectorRope); + GVAR(connectorRope) = objNull; + { deleteVehicle _x } forEach GVAR(connectorRopeHelpers); + GVAR(connectorRopeHelpers) = [objNull, objNull]; +}; diff --git a/addons/sys_core/script_component.hpp b/addons/sys_core/script_component.hpp index 10e5b6de5..bb58cccb5 100644 --- a/addons/sys_core/script_component.hpp +++ b/addons/sys_core/script_component.hpp @@ -25,3 +25,5 @@ #define NEAR_RADIO_RANGE 150 #define ZEUS_INTERFACE_DISPLAY 312 + +#define ROPE_HELPER QGVAR(connectorHelper) diff --git a/addons/sys_gestures/initSettings.inc.sqf b/addons/sys_gestures/initSettings.inc.sqf index 4aa798eea..2a9e9510d 100644 --- a/addons/sys_gestures/initSettings.inc.sqf +++ b/addons/sys_gestures/initSettings.inc.sqf @@ -19,3 +19,14 @@ {}, true ] call CBA_fnc_addSetting; + +[ + QGVAR(showConnectorRopes), + "CHECKBOX", + [LLSTRING(showConnectorRopes), LLSTRING(showConnectorRopes_description)], + LLSTRING(category), + true, + true, + {}, + true +] call CBA_fnc_addSetting; diff --git a/addons/sys_gestures/stringtable.xml b/addons/sys_gestures/stringtable.xml index cb47bf264..538ba2ac0 100644 --- a/addons/sys_gestures/stringtable.xml +++ b/addons/sys_gestures/stringtable.xml @@ -46,5 +46,15 @@ Telsiz kullanırken nişan almayı engeller Usar rádios irá impedir a mira + + Show Connector Wires + Zeige verbindungskabel + Mostra cavi di collegamento + + + Connections to infantry phones, GSAs and shared radios will be visualized with connector wires. + Verbindungen zu Gegensprechanlage, BBA und Geteilten Funkgeräten werden mit Kabeln visualisiert. + Connessioni a telefoni di fanteria, antenne a pavimento e radio condivise verranno visualizzate con cavi. + diff --git a/addons/sys_gsa/fnc_connectServer.sqf b/addons/sys_gsa/fnc_connectServer.sqf index 107d7806b..2fedd0211 100644 --- a/addons/sys_gsa/fnc_connectServer.sqf +++ b/addons/sys_gsa/fnc_connectServer.sqf @@ -38,6 +38,7 @@ _gsa setVariable [QGVAR(connectedRadio), _radioId, true]; [_radioId, "setState", ["externalAntennaConnected", [true, _gsa]]] call EFUNC(sys_data,dataEvent); [QGVAR(notifyPlayer), [localize LSTRING(connected)], _player] call CBA_fnc_targetEvent; +[QEGVAR(sys_core,handleConnectorRopeEvent), [true, 1, _gsa, _player], _player] call CBA_fnc_targetEvent; // Support for having several radios connected to GSA private _pfh = [DFUNC(externalAntennaPFH), 1.0, [_gsa, _radioId]] call CBA_fnc_addPerFrameHandler; diff --git a/addons/sys_gsa/fnc_disconnectServer.sqf b/addons/sys_gsa/fnc_disconnectServer.sqf index a5789d58a..67e9f3ca2 100644 --- a/addons/sys_gsa/fnc_disconnectServer.sqf +++ b/addons/sys_gsa/fnc_disconnectServer.sqf @@ -60,9 +60,11 @@ private _parentComponentClass = configFile >> "CfgAcreComponents" >> BASE_CLASS_ if (_connectedUnit isKindOf "CAManBase" || {crew _connectedUnit isNotEqualTo []}) then { if (_connectedUnit isKindOf "CAManBase") then { [QGVAR(notifyPlayer), [localize LSTRING(disconnected)], _connectedUnit] call CBA_fnc_targetEvent; + [QEGVAR(sys_core,handleConnectorRopeEvent), [false], _connectedUnit] call CBA_fnc_targetEvent; } else { { [QGVAR(notifyPlayer), [localize LSTRING(disconnected)], _connectedUnit] call CBA_fnc_targetEvent; + [QEGVAR(sys_core,handleConnectorRopeEvent), [false], _connectedUnit] call CBA_fnc_targetEvent; } forEach (crew _connectedUnit); }; }; @@ -71,6 +73,7 @@ private _parentComponentClass = configFile >> "CfgAcreComponents" >> BASE_CLASS_ // The unit that disconnected the antenna is different from the unit that was connected to it private _text = format [localize LSTRING(disconnectedUnit), name _connectedUnit]; [QGVAR(notifyPlayer), [_text], _unit] call CBA_fnc_targetEvent; + [QEGVAR(sys_core,handleConnectorRopeEvent), [false], _unit] call CBA_fnc_targetEvent; }; }; }; diff --git a/addons/sys_gsa/fnc_externalAntennaPFH.sqf b/addons/sys_gsa/fnc_externalAntennaPFH.sqf index ef247c3d8..ba4b37ff2 100644 --- a/addons/sys_gsa/fnc_externalAntennaPFH.sqf +++ b/addons/sys_gsa/fnc_externalAntennaPFH.sqf @@ -35,4 +35,5 @@ if ( || {(_unit distance _gsa) > ANTENNA_MAXDISTANCE} ) then { [QGVAR(disconnectGsa), [_gsa, _unit, _radioId]] call CBA_fnc_localEvent; + [QEGVAR(sys_core,handleConnectorRopeEvent), [false]] call CBA_fnc_localEvent; }; diff --git a/addons/sys_gsa/fnc_handleMast.sqf b/addons/sys_gsa/fnc_handleMast.sqf index 7e1a6005f..c7fc35ebf 100644 --- a/addons/sys_gsa/fnc_handleMast.sqf +++ b/addons/sys_gsa/fnc_handleMast.sqf @@ -21,9 +21,11 @@ if (_connectedRadio isEqualTo "") then { _connectedRadio = _gsa getVariable [QGVAR(connectedRadio), ""]; }; +private _connectedPlayer = [_connectedRadio] call EFUNC(sys_radio,getRadioObject); + // Temporarily disconnect the GSA from the radio if (_connectedRadio != "") then { - [_player, _gsa] call FUNC(disconnect); + [_connectedPlayer, _gsa] call FUNC(disconnect); }; // Delete the antenna @@ -43,5 +45,5 @@ if (_mountMast) then { // Reconnect the GSA to the radio if (_connectedRadio != "") then { - [_gsa, _connectedRadio] call FUNC(connect); + [QGVAR(connectGsa), [_gsa, _connectedRadio, _connectedPlayer]] call CBA_fnc_serverEvent; }; diff --git a/addons/sys_intercom/XEH_postInit.sqf b/addons/sys_intercom/XEH_postInit.sqf index f3d781baa..f18d22828 100644 --- a/addons/sys_intercom/XEH_postInit.sqf +++ b/addons/sys_intercom/XEH_postInit.sqf @@ -69,9 +69,9 @@ if (!hasInterface) exitWith {}; }, true] call CBA_fnc_addPlayerEventHandler; [QGVAR(giveInfantryPhone), { - params ["_vehicle", "_unit", "_action", "_message", ["_intercomNetwork", INTERCOM_DISCONNECTED]]; + params ["_vehicle", "_unit", "_action", "_message", ["_intercomNetwork", INTERCOM_DISCONNECTED], ["_position", [0, 0, 0]]]; [[ICON_RADIO_CALL], [_message]] call CBA_fnc_notify; - [_vehicle, _unit, _action, _intercomNetwork] call FUNC(updateInfantryPhoneStatus); + [_vehicle, _unit, _action, _intercomNetwork, objNull, _position] call FUNC(updateInfantryPhoneStatus); }] call CBA_fnc_addEventHandler; #ifdef DRAW_INFANTRYPHONE_INFO diff --git a/addons/sys_intercom/fnc_infantryPhoneChildrenActions.sqf b/addons/sys_intercom/fnc_infantryPhoneChildrenActions.sqf index aef13cf96..43aaa24b8 100644 --- a/addons/sys_intercom/fnc_infantryPhoneChildrenActions.sqf +++ b/addons/sys_intercom/fnc_infantryPhoneChildrenActions.sqf @@ -4,7 +4,9 @@ * Generates a list of actions for using vehicle intercoms externally. * * Arguments: - * 0: Vehicle/Unit + * 0: Vehicle/Unit target of interaction + * 1: Unit interacting with target + * 2: Relative position of the infantry phone interaction on the vehicle (default: [0, 0, 0]) * * Return Value: * Array of actions @@ -15,11 +17,12 @@ * Public: No */ -params ["_target"]; +params ["_target", "_unit", "_position"]; private _actions = []; (acre_player getVariable [QGVAR(vehicleInfantryPhone), [objNull, INTERCOM_DISCONNECTED]]) params ["_vehicleInfantryPhone", "_infantryPhoneNetwork"]; +(_target getVariable [QGVAR(unitInfantryPhone), [objNull, INTERCOM_DISCONNECTED]]) params ["_unitInfantryPhone", "_unitInfantryPhoneNetwork"]; private _intercomNames = _target getVariable [QGVAR(intercomNames), []]; @@ -36,7 +39,7 @@ if (_target isKindOf "CAManBase") then { _params params ["_intercomNetwork"]; //USES_VARIABLES ["_target", "_player"]; - [_player getVariable [QGVAR(vehicleInfantryPhone), [objNull, INTERCOM_DISCONNECTED]] select 0, _target, 2, _intercomNetwork, _player] call FUNC(updateInfantryPhoneStatus) + [_player getVariable [QGVAR(vehicleInfantryPhone), [objNull, INTERCOM_DISCONNECTED]] select 0, _target, 2, _intercomNetwork, _player, [-1]] call FUNC(updateInfantryPhoneStatus) }, {true}, {}, @@ -47,7 +50,7 @@ if (_target isKindOf "CAManBase") then { } else { if (vehicle acre_player != _target) then { // Pointing at a vehicle. Get or return the infantry telephone - if (isNull _vehicleInfantryPhone) then { + if (isNull _vehicleInfantryPhone && (isNull _unitInfantryPhone)) then { { private _action = [ format [QGVAR(takeInfantryPhone_%1), _x], @@ -55,8 +58,8 @@ if (_target isKindOf "CAManBase") then { "", { params ["_target", "_player", "_params"]; - _params params ["_intercomNetwork"]; - [_target, _player, 1, _intercomNetwork] call FUNC(updateInfantryPhoneStatus) + _params params ["_intercomNetwork", "_position"]; + [_target, _player, 1, _intercomNetwork, objNull, _position] call FUNC(updateInfantryPhoneStatus); }, { params ["_target", "_player", "_params"]; @@ -65,7 +68,7 @@ if (_target isKindOf "CAManBase") then { !(_isCalling select 0) || ((_isCalling select 0) && ((_isCalling select 1) == _intercomNetwork)) }, {}, - _forEachIndex + [_forEachIndex, _position] ] call ace_interact_menu_fnc_createAction; _actions pushBack [_action, [], _target]; } forEach (_intercomNames select {_x in (_target getVariable [QGVAR(infantryPhoneIntercom), []])}); @@ -79,7 +82,7 @@ if (_target isKindOf "CAManBase") then { { params ["_target", "_player", ""]; //USES_VARIABLES ["_target", "_player"]; - [_target, _player, 0, INTERCOM_DISCONNECTED] call FUNC(updateInfantryPhoneStatus) + [_target, _player, 0, INTERCOM_DISCONNECTED] call FUNC(updateInfantryPhoneStatus); }, {true}, {}, @@ -111,6 +114,18 @@ if (_target isKindOf "CAManBase") then { ] call ace_interact_menu_fnc_createAction; _actions pushBack [_action, [], _target]; } forEach (_intercomNames select {_x in (_target getVariable [QGVAR(infantryPhoneIntercom), []])}); + } else { + // Generate empty action to show that the infantry phone is being used by someone else + private _action = [ + QGVAR(infantryPhoneUnavailable), + format [localize LSTRING(infantryPhoneUnavailable)], + "", + {true}, + {true}, + {}, + {} + ] call ace_interact_menu_fnc_createAction; + _actions pushBack [_action, [], _target]; }; }; } else { diff --git a/addons/sys_intercom/fnc_updateInfantryPhoneStatus.sqf b/addons/sys_intercom/fnc_updateInfantryPhoneStatus.sqf index 935dac577..674af4e63 100644 --- a/addons/sys_intercom/fnc_updateInfantryPhoneStatus.sqf +++ b/addons/sys_intercom/fnc_updateInfantryPhoneStatus.sqf @@ -9,6 +9,7 @@ * 2: Type of action * 3: Intercom network * 4: Unit giving the infantry phone (default: objNull) + * 5: Relative position of the infantry phone interaction on the vehicle (default: [0, 0, 0]) * * Return Value: * None @@ -20,7 +21,7 @@ * Public: No */ -params ["_vehicle", "_unit", "_action", "_intercomNetwork", ["_givingUnit", objNull, [objNull]]]; +params ["_vehicle", "_unit", "_action", "_intercomNetwork", ["_givingUnit", objNull, [objNull]], ["_position", [0, 0, 0]]]; private _intercomName = ((_vehicle getVariable [QGVAR(intercomNames), []]) select _intercomNetwork) select 1; private _intercomText = format ["( %1 )", _intercomName]; @@ -31,6 +32,9 @@ switch (_action) do { _vehicle setVariable [QGVAR(unitInfantryPhone), nil, true]; _unit setVariable [QGVAR(vehicleInfantryPhone), nil, true]; + // Destroy connector rope + [QEGVAR(sys_core,handleConnectorRopeEvent), [false]] call CBA_fnc_localEvent; + ACRE_PLAYER_INTERCOM = []; [[ICON_RADIO_CALL], [format [localize LSTRING(infantryPhoneDisconnected), _intercomText]], true] call CBA_fnc_notify; [GVAR(intercomPFH)] call CBA_fnc_removePerFrameHandler; @@ -40,6 +44,9 @@ switch (_action) do { _vehicle setVariable [QGVAR(unitInfantryPhone), [_unit, _intercomNetwork], true]; _unit setVariable [QGVAR(vehicleInfantryPhone), [_vehicle, _intercomNetwork], true]; + // Create connector rope + [QEGVAR(sys_core,handleConnectorRopeEvent), [true, 0, _vehicle, _unit, _position]] call CBA_fnc_localEvent; + [[ICON_RADIO_CALL], [format [localize LSTRING(infantryPhoneConnected), _intercomText]], true] call CBA_fnc_notify; GVAR(intercomPFH) = [DFUNC(intercomPFH), 1.1, [acre_player, _vehicle]] call CBA_fnc_addPerFrameHandler; }; @@ -48,8 +55,11 @@ switch (_action) do { _givingUnit setVariable [QGVAR(vehicleInfantryPhone), nil, true]; [GVAR(intercomPFH)] call CBA_fnc_removePerFrameHandler; + // Destroy connector rope + [QEGVAR(sys_core,handleConnectorRopeEvent), [false]] call CBA_fnc_localEvent; + private _message = format [localize LSTRING(infantryPhoneReceived), _intercomText]; - [QGVAR(giveInfantryPhone), [_vehicle, _unit, 1, _message, _intercomNetwork], _unit] call CBA_fnc_targetEvent; + [QGVAR(giveInfantryPhone), [_vehicle, _unit, 1, _message, _intercomNetwork, _position], _unit] call CBA_fnc_targetEvent; }; case 3: { _vehicle setVariable [QGVAR(unitInfantryPhone), [_unit, _intercomNetwork], true]; diff --git a/addons/sys_intercom/stringtable.xml b/addons/sys_intercom/stringtable.xml index 7d27b4a25..15b9d2886 100644 --- a/addons/sys_intercom/stringtable.xml +++ b/addons/sys_intercom/stringtable.xml @@ -151,6 +151,11 @@ Téléphone d'infanterie reçu %1 Piyade Telefonu Alındı %1 + + Infantry Phone already in use + Hörer wird gerade benutzt + Telefono fanteria preso da qualcuno + Intercom Intercom