diff --git a/addons/api/CfgFunctions.hpp b/addons/api/CfgFunctions.hpp index a202bd0ca..5eb452c5d 100644 --- a/addons/api/CfgFunctions.hpp +++ b/addons/api/CfgFunctions.hpp @@ -67,7 +67,9 @@ class CfgFunctions { PATHTO_FNC(initVehicleRacks); PATHTO_FNC(isRackRadioRemovable); PATHTO_FNC(mountRackRadio); + PATHTO_FNC(removeAllRacksFromVehicle); PATHTO_FNC(removeRackFromVehicle); + PATHTO_FNC(replaceRacksOnVehicle); PATHTO_FNC(unmountRackRadio); }; diff --git a/addons/api/fnc_addRackToVehicle.sqf b/addons/api/fnc_addRackToVehicle.sqf index ee7105bf0..29debef8f 100644 --- a/addons/api/fnc_addRackToVehicle.sqf +++ b/addons/api/fnc_addRackToVehicle.sqf @@ -132,6 +132,8 @@ private _selectPlayer = { [{ params ["_selectPlayer", "_condition", "_vehicle"]; + if !([_vehicle] call FUNC(areVehicleRacksInitialized)) exitWith {false}; + private _player = [_condition, _vehicle] call _selectPlayer; !isNil "_player" diff --git a/addons/api/fnc_removeAllRacksFromVehicle.sqf b/addons/api/fnc_removeAllRacksFromVehicle.sqf new file mode 100644 index 000000000..929aab688 --- /dev/null +++ b/addons/api/fnc_removeAllRacksFromVehicle.sqf @@ -0,0 +1,65 @@ +#include "script_component.hpp" +/* + * Author: mrschick + * Removes all Racks from a vehicle. Must be executed on the server. + * + * Arguments: + * 0: Vehicle (default: objNull) + * + * Return Value: + * Racks removed successfully + * + * Example: + * [cursorTarget] call acre_api_fnc_removeAllRacksFromVehicle + * + * Public: Yes + */ + +params [ + ["_vehicle", objNull, [objNull]] +]; + +if (!isServer) exitWith { + WARNING("Function must be called on the server."); + false +}; + +if (isNull _vehicle) exitWith { + WARNING_1("Trying to remove a rack from an undefined vehicle %1",_vehicle); + false +}; + +private _success = true; + +if (!([_vehicle] call FUNC(areVehicleRacksInitialized))) then { + WARNING_1("Forcing initialisation of vehicle %1 in order to remove all racks",_vehicle); + _success = [_vehicle] call EFUNC(api,initVehicleRacks); +}; + +if (!_success) exitWith { + WARNING_1("Vehicle %1 failed to initialise",_vehicle); +}; + +// A player must do the action of removing a rack +private _player = objNull; + +if (isDedicated) then { + // Pick the first player + _player = (allPlayers - entities "HeadlessClient_F") select 0; +} else { + _player = acre_player; +}; + +[{ + params ["_vehicle", "_player"]; + [_vehicle] call FUNC(areVehicleRacksInitialized) +}, { + params ["_vehicle", "_player"]; + + private _racks = [_vehicle] call FUNC(getVehicleRacks); + for "_i" from (count _racks) - 1 to 0 step -1 do { + [QEGVAR(sys_rack,removeVehicleRacks), [_vehicle, _racks select _i], _player] call CBA_fnc_targetEvent; + }; +}, [_vehicle, _player]] call CBA_fnc_waitUntilAndExecute; + +true diff --git a/addons/api/fnc_removeRackFromVehicle.sqf b/addons/api/fnc_removeRackFromVehicle.sqf index 01bb33d2c..c71c77f1b 100644 --- a/addons/api/fnc_removeRackFromVehicle.sqf +++ b/addons/api/fnc_removeRackFromVehicle.sqf @@ -1,7 +1,7 @@ #include "script_component.hpp" /* * Author: ACRE2Team - * Initialises all racks in the vehicle. Must be executed in the server. + * Removes a specific Rack from a vehicle. Must be executed on the server. * * Arguments: * 0: Vehicle (default: objNull) @@ -54,4 +54,3 @@ if (isDedicated) then { [QEGVAR(sys_rack,removeVehicleRacks), [_vehicle, _rackId], _player] call CBA_fnc_targetEvent; true - diff --git a/addons/api/fnc_replaceRacksOnVehicle.sqf b/addons/api/fnc_replaceRacksOnVehicle.sqf new file mode 100644 index 000000000..e62ce033a --- /dev/null +++ b/addons/api/fnc_replaceRacksOnVehicle.sqf @@ -0,0 +1,74 @@ +#include "script_component.hpp" +/* + * Author: mrschick + * Replaces all config-defined Racks on a vehicle with a different class of Rack, while keeping the same name, allowedPositions, etc. + * Must be executed on the server. + * + * Arguments: + * 0: Vehicle (default: objNull) + * 1: Rack classname to remove (default: "") + * 2: Rack classname to add (default: "") + * 3: Condition called with argument "_unit" for rack init. If a longer function is given, it should be precompiled. (default: {}) + * + * Return Value: + * Racks replaced successfully + * + * Example: + * [cursorTarget, "ACRE_VRC103", "ACRE_VRC64", {}] call acre_api_fnc_replaceRacksOnVehicle + * + * Public: Yes + */ + +params [ + ["_vehicle", objNull, [objNull]], + ["_fromRack", "", [""]], + ["_toRack", "", [""]], + ["_condition", {}, [{}]] +]; + +if (!isServer) exitWith { + WARNING("Function must be called on the server."); + false +}; + +if (isNull _vehicle) exitWith { + WARNING_1("Trying to remove a rack from an undefined vehicle %1",_vehicle); + false +}; + +if (_fromRack == "" || {_toRack == ""}) exitWith { + WARNING_1("Racks to replace on vehicle %1 were not defined",_vehicle); + false +}; + +if (_fromRack == _toRack) exitWith { + WARNING_1("Racks on vehicle %1 and intended replacements are the same",_vehicle); + false +}; + +// Store the desired Rack replacement as an object var which will be handled by sys_rack/fnc_initVehicle on the next initialization +_vehicle setVariable [QEGVAR(sys_rack,replaceRacks), [_fromRack, _toRack], true]; + +if ([_vehicle] call FUNC(areVehicleRacksInitialized)) then { + // If Racks have already been initialized, revert the initialization to run this function again + [_vehicle] call FUNC(removeAllRacksFromVehicle); + + [{ + params ["_vehicle"]; + (_vehicle getVariable [QEGVAR(sys_rack,vehicleRacks), []]) isEqualTo [] + }, { + params ["_vehicle"]; + + _vehicle setVariable [QEGVAR(sys_rack,initialized), false, true]; + + private _success = true; + WARNING_1("Forcing initialisation of vehicle %1 in order to alter all racks",_vehicle); + _success = [_vehicle, _condition] call EFUNC(api,initVehicleRacks); + + if (!_success) exitWith { + WARNING_1("Vehicle %1 failed to initialise",_vehicle); + }; + }, [_vehicle]] call CBA_fnc_waitUntilAndExecute; +}; + +true diff --git a/addons/api/fnc_setMultiPushToTalkAssignment.sqf b/addons/api/fnc_setMultiPushToTalkAssignment.sqf index f59d21837..9c43a2eaa 100644 --- a/addons/api/fnc_setMultiPushToTalkAssignment.sqf +++ b/addons/api/fnc_setMultiPushToTalkAssignment.sqf @@ -35,6 +35,12 @@ private _index = _var findIf { if (_index != -1) exitWith { false }; +// Save Rack PTT Assignments to vehicle +private _vehicle = objectParent acre_player; +if (!isNull _vehicle) then { + _vehicle setVariable [QEGVAR(sys_rack,MPTTAssignment), _var]; +}; + if (acre_player isEqualTo player) then { // using zeus player voice ACRE_ASSIGNED_PTT_RADIOS = _var; } else { // using zeus remote voice diff --git a/addons/sys_gui/RscTitles.hpp b/addons/sys_gui/RscTitles.hpp index 2e51e0b5e..65c851dc6 100644 --- a/addons/sys_gui/RscTitles.hpp +++ b/addons/sys_gui/RscTitles.hpp @@ -50,7 +50,7 @@ class RscTitles { }; class VehicleInfoText: RscStructuredText { idc = 2; - w = QUOTE(10 * VEHICLE_INFO_DEFAULT_W); // Must be specifically widened + w = QUOTE(VEHICLE_INFO_DEFAULT_W); }; }; }; diff --git a/addons/sys_gui/fnc_updateVehicleInfo.sqf b/addons/sys_gui/fnc_updateVehicleInfo.sqf index 8b537dc91..e664decd5 100644 --- a/addons/sys_gui/fnc_updateVehicleInfo.sqf +++ b/addons/sys_gui/fnc_updateVehicleInfo.sqf @@ -30,7 +30,7 @@ _ctrlText ctrlSetStructuredText parseText _str; // Calculate new height (3 elements per row) private _rows = ceil ((1 max _elements) / 3); -private _newBaseH = (((safeZoneW / safeZoneH) min 1.2) / 1.2) / 25; +private _newBaseH = (((safeZoneW / safeZoneH) min 1.2) / 1.2) / 23; private _newH = _newBaseH * _rows; private _newContainerH = (0.8 * _newH) + 0.001; TRACE_4("vehicle info height",_elements,_rows,_newH,_newContainerH); diff --git a/addons/sys_intercom/fnc_getStationVariableName.sqf b/addons/sys_intercom/fnc_getStationVariableName.sqf index 9a25a514e..e95ef9961 100644 --- a/addons/sys_intercom/fnc_getStationVariableName.sqf +++ b/addons/sys_intercom/fnc_getStationVariableName.sqf @@ -6,6 +6,7 @@ * Arguments: * 0: Vehicle with intercom * 1: Unit to be checked + * 2: Component prefix for the variable name (default: "acre_sys_intercom_station_%1") * * Return Value: * Variable name, string of length 0 if not found @@ -16,14 +17,14 @@ * Public: No */ -params ["_vehicle", "_unit"]; +params ["_vehicle", "_unit", ["_prefix", QGVAR(station_%1)]]; private _found = false; private _varName = ""; { if (_unit isEqualTo (_x select 0)) exitWith { private _role = toLower (_x select 1); - _varName = format [QGVAR(station_%1), _role]; + _varName = format [_prefix, _role]; if (_role in ["cargo", "turret"]) then { if (_role isEqualTo "cargo") then { _varName = format ["%1_%2", _varName, _x select 2]; diff --git a/addons/sys_rack/fnc_addRackOnReturn.sqf b/addons/sys_rack/fnc_addRackOnReturn.sqf index 24c4e8fd5..264438af6 100644 --- a/addons/sys_rack/fnc_addRackOnReturn.sqf +++ b/addons/sys_rack/fnc_addRackOnReturn.sqf @@ -59,6 +59,10 @@ if (_idx != -1) then { _vehicle setVariable [QGVAR(queue), _queue]; }; +if (_queue isEqualTo []) then { + _vehicle setVariable [QGVAR(initialized), true, true]; +}; + if (!_handled) then { WARNING_2("Recieved new rack ID (%1) for vehicle (%2) but no entry in queue rack.",_rackId,typeOf _vehicle); }; diff --git a/addons/sys_rack/fnc_enterVehicle.sqf b/addons/sys_rack/fnc_enterVehicle.sqf index ce30b54dc..e40c722cd 100644 --- a/addons/sys_rack/fnc_enterVehicle.sqf +++ b/addons/sys_rack/fnc_enterVehicle.sqf @@ -18,31 +18,22 @@ params ["_vehicle", "_unit"]; -if (_unit != _vehicle && {isNull remoteControlled _unit}) then { - private _initialized = _vehicle getVariable [QGVAR(initialized), false]; - - if (!_initialized) then { - // Only initialize if we are first in the crew array - This helps prevent multiple requests if multiple players enter a vehicle around the same time. - private _crew = [_vehicle] call EFUNC(sys_core,getPlayersInVehicle); - private _firstPlayer = objNull; - { - if (!isNull _x) exitWith { - _firstPlayer = _x; - }; - } forEach _crew; - - if (!isNull _firstPlayer) then { - if (_unit == _firstPlayer) then { - [_vehicle] call FUNC(initVehicle); - - // Give some time for the racks to initialise properly - [{ - [_this select 0] call FUNC(configureRackIntercom); - // Update the display - [_this select 0, _this select 1] call EFUNC(sys_intercom,updateVehicleInfoText); - }, [_vehicle, _unit], 0.5] call CBA_fnc_waitAndExecute; - }; - } else { // No other players. +if (_unit == _vehicle || {!(isNull remoteControlled _unit)}) exitWith {}; + +private _initialized = _vehicle getVariable [QGVAR(initialized), false]; + +if (!_initialized) then { + // Only initialize if we are first in the crew array - This helps prevent multiple requests if multiple players enter a vehicle around the same time. + private _crew = [_vehicle] call EFUNC(sys_core,getPlayersInVehicle); + private _firstPlayer = objNull; + { + if (!isNull _x) exitWith { + _firstPlayer = _x; + }; + } forEach _crew; + + if (!isNull _firstPlayer) then { + if (_unit == _firstPlayer) then { [_vehicle] call FUNC(initVehicle); // Give some time for the racks to initialise properly @@ -52,11 +43,35 @@ if (_unit != _vehicle && {isNull remoteControlled _unit}) then { [_this select 0, _this select 1] call EFUNC(sys_intercom,updateVehicleInfoText); }, [_vehicle, _unit], 0.5] call CBA_fnc_waitAndExecute; }; - }; + } else { // No other players. + [_vehicle] call FUNC(initVehicle); - // Enable the PFH if it is not active (can only be active if the unit is using an external radio before entering the vehicle) - if (GVAR(rackPFH) == -1) then { - GVAR(rackPFH) = [DFUNC(rackPFH), 1, [_unit, _vehicle]] call CBA_fnc_addPerFrameHandler; - TRACE_1("rack PFH",GVAR(rackPFH)); + // Give some time for the racks to initialise properly + [{ + [_this select 0] call FUNC(configureRackIntercom); + // Update the display + [_this select 0, _this select 1] call EFUNC(sys_intercom,updateVehicleInfoText); + }, [_vehicle, _unit], 0.5] call CBA_fnc_waitAndExecute; }; }; + +// Enable the PFH if it is not active (can only be active if the unit is using an external radio before entering the vehicle) +if (GVAR(rackPFH) == -1) then { + GVAR(rackPFH) = [DFUNC(rackPFH), 1, [_unit, _vehicle]] call CBA_fnc_addPerFrameHandler; + TRACE_1("rack PFH",GVAR(rackPFH)); +}; + +// Re-Use stored radios for the current position +private _varName = [_vehicle, _unit, QGVAR(usedRacks_%1)] call EFUNC(sys_intercom,getStationVariableName); +if (_varName isNotEqualTo "") then { + private _usedRacks = _vehicle getVariable [_varName, []]; + { + [_vehicle, _unit, _x] call FUNC(startUsingMountedRadio); + } forEach _usedRacks; +}; + +// Load saved PTT assignments of previously used Racks +private _vehiclePTTs = _vehicle getVariable [QGVAR(MPTTAssignment), []]; +if (_vehiclePTTs isNotEqualTo []) then { + [_vehiclePTTs] call EFUNC(api,setMultiPushToTalkAssignment); +}; diff --git a/addons/sys_rack/fnc_initVehicle.sqf b/addons/sys_rack/fnc_initVehicle.sqf index 25faf5787..05bba18eb 100644 --- a/addons/sys_rack/fnc_initVehicle.sqf +++ b/addons/sys_rack/fnc_initVehicle.sqf @@ -19,16 +19,45 @@ params ["_vehicle"]; private _initialized = _vehicle getVariable [QGVAR(initialized), false]; if (!_initialized) then { - private _racks = configOf _vehicle >> "AcreRacks"; + private _racks = configProperties [(configOf _vehicle >> "AcreRacks"), "isClass _x", true]; + + // Set initialized flag if vehicle config has no defined Racks + if (_racks isEqualTo []) exitWith { + _vehicle setVariable [QGVAR(initialized), true, true]; + }; + + // Handle acre_api_fnc_replaceRacksOnVehicle having defined a Rack class to replace + private _replaceVar = _vehicle getVariable [QGVAR(replaceRacks), false]; + private ["_fromRack", "_toRack"]; + if (_replaceVar isEqualType []) then { + _fromRack = _replaceVar select 0; + _toRack = _replaceVar select 1; + _vehicle setVariable [QGVAR(replaceRacks), false, true]; + }; { private _componentName = getText (_x >> "componentName"); + + private ["_componentName", "_components", "_mountedRadio"]; + if (!isNil "_toRack" && {_componentName == _fromRack}) then { + private _toRackConfig = configFile >> "CfgAcreRacks" >> _toRack; + _componentName = _toRack; + _components = getArray (_toRackConfig >> "defaultComponents"); + _mountedRadio = switch (_toRack) do { + case "ACRE_VRC64": { "ACRE_PRC77" }; + case "ACRE_VRC103": { "ACRE_PRC117F" }; + case "ACRE_SEM90": { "ACRE_SEM70" }; + default { "" }; + }; + } else { + _components = getArray (_x >> "defaultComponents"); + _mountedRadio = getText (_x >> "mountedRadio"); + }; + private _displayName = getText (_x >> "displayName"); private _shortName = getText (_x >> "shortName"); private _allowed = [_vehicle, getArray (_x >> "allowedPositions")] call EFUNC(sys_core,processVehicleSystemAccessArray); private _disabled = [_vehicle, getArray (_x >> "disabledPositions")] call EFUNC(sys_core,processVehicleSystemAccessArray); - private _components = getArray (_x >> "defaultComponents"); - private _mountedRadio = getText (_x >> "mountedRadio"); private _isRadioRemovable = getNumber (_x >> "isRadioRemovable") == 1; private _intercoms = [_vehicle, _x] call FUNC(configWiredIntercoms); @@ -37,7 +66,5 @@ if (!_initialized) then { }; [_vehicle, _componentName, _displayName, _shortName, _isRadioRemovable, _allowed, _disabled, _mountedRadio, _components, _intercoms] call FUNC(addRack); - } forEach (configProperties [_racks, "isClass _x", true]); - - _vehicle setVariable [QGVAR(initialized), true, true]; + } forEach _racks; }; diff --git a/addons/sys_rack/fnc_rackChildrenActions.sqf b/addons/sys_rack/fnc_rackChildrenActions.sqf index 8454a7777..aadf6ac02 100644 --- a/addons/sys_rack/fnc_rackChildrenActions.sqf +++ b/addons/sys_rack/fnc_rackChildrenActions.sqf @@ -41,7 +41,7 @@ if (_mountedRadio == "") then { // Empty } else { private _class = configFile >> "CfgWeapons" >> _mountedRadio; private _currentChannel = [_mountedRadio] call EFUNC(api,getRadioChannel); - private _displayName = format [localize ELSTRING(ace_interact,channelShort), getText (_class >> "displayName"), _currentChannel]; + private _displayName = [_mountedRadio] call EFUNC(sys_core,getDescriptiveName); private _icon = getText (_class >> "picture"); // General radio diff --git a/addons/sys_rack/fnc_startUsingMountedRadio.sqf b/addons/sys_rack/fnc_startUsingMountedRadio.sqf index c34b624ff..05e48cc69 100644 --- a/addons/sys_rack/fnc_startUsingMountedRadio.sqf +++ b/addons/sys_rack/fnc_startUsingMountedRadio.sqf @@ -36,5 +36,13 @@ if (GVAR(rackPFH) == -1) then { GVAR(rackPFH) = [DFUNC(rackPFH), 1.1, [_unit, _vehicle]] call CBA_fnc_addPerFrameHandler; }; +// Locally store radio use status for the current position in vehicle +private _varName = [_vehicle, _unit, QGVAR(usedRacks_%1)] call EFUNC(sys_intercom,getStationVariableName); +if (_varName isNotEqualTo "") then { + private _usedRacks = _vehicle getVariable [_varName, []]; + _usedRacks pushBackUnique _radioId; + _vehicle setVariable [_varName, _usedRacks]; +}; + // Update the display [_vehicle, _unit] call EFUNC(sys_intercom,updateVehicleInfoText); diff --git a/addons/sys_rack/fnc_stopUsingMountedRadio.sqf b/addons/sys_rack/fnc_stopUsingMountedRadio.sqf index ff54472ad..8606ba7be 100644 --- a/addons/sys_rack/fnc_stopUsingMountedRadio.sqf +++ b/addons/sys_rack/fnc_stopUsingMountedRadio.sqf @@ -25,5 +25,13 @@ if (_radioId in ACRE_ACCESSIBLE_RACK_RADIOS) then { [_radioId] call EFUNC(sys_radio,stopUsingRadio); +// Remove radio use status for the current position in vehicle +private _varName = [_vehicle, _unit, QGVAR(usedRacks_%1)] call EFUNC(sys_intercom,getStationVariableName); +if (_varName isNotEqualTo "") then { + private _usedRacks = _vehicle getVariable [_varName, []]; + _usedRacks deleteAt (_usedRacks find _radioId); + _vehicle setVariable [_varName, _usedRacks]; +}; + // Update the display [_vehicle, _unit] call EFUNC(sys_intercom,updateVehicleInfoText); diff --git a/addons/sys_rack/stringtable.xml b/addons/sys_rack/stringtable.xml index 0a10229a3..776b59db8 100644 --- a/addons/sys_rack/stringtable.xml +++ b/addons/sys_rack/stringtable.xml @@ -153,13 +153,13 @@ Dash - Cruscotto + Crus. DB 儀器版面 下 仪器版面 下 Panel Panneau - Anschluss + An. Панель Painel Panel @@ -187,7 +187,7 @@ 仪器.下 P.Inf P. inf - Unten + An.U Н-я панель P. Inf. A.Pan @@ -215,7 +215,7 @@ 仪器.上 P.Sup P. sup - Oben + An.O В-я панель P. Sup. Ü.Pan diff --git a/docs/_includes/custom/functions-list-api.html b/docs/_includes/custom/functions-list-api.html index 725621f99..fa9ef2fd7 100644 --- a/docs/_includes/custom/functions-list-api.html +++ b/docs/_includes/custom/functions-list-api.html @@ -1641,7 +1641,7 @@ ### acre_api_fnc_removeRackFromVehicle __Description__ -Initialises all racks in the vehicle. Must be executed in the server. +Removes a specific Rack from a vehicle. Must be executed on the server. __Parameters__ @@ -1663,6 +1663,62 @@ ``` +--- + +### acre_api_fnc_removeAllRacksFromVehicle +__Description__ + +Removes all Racks from a vehicle. Must be executed on the server. + +__Parameters__ + +Index | Description | Datatype(s) | Default Value +--- | --- | --- | --- +0 | Vehicle | OBJECT | objNull + +__Return Value__ + +Description | Datatype(s) +--- | --- +Racks removed successfully | BOOL + +__Example__ + +```sqf +[cursorTarget] call acre_api_fnc_removeAllRacksFromVehicle +``` + + +--- + +### acre_api_fnc_replaceRacksOnVehicle +__Description__ + +Replaces all config-defined Racks on a vehicle with a different class of Rack, while keeping the same name, allowedPositions, etc. +Must be executed on the server. + +__Parameters__ + +Index | Description | Datatype(s) | Default Value +--- | --- | --- | --- +0 | Vehicle | OBJECT | objNull +1 | Rack classname to remove | STRING | "" +2 | Rack classname to add | STRING | "" +3 | Condition called with argument "_unit" for rack init. If a longer function is given, it should be precompiled. | CODE | {} + +__Return Value__ + +Description | Datatype(s) +--- | --- +Racks replaced successfully | BOOL + +__Example__ + +```sqf +[cursorTarget, "ACRE_VRC103", "ACRE_VRC64", {}] call acre_api_fnc_replaceRacksOnVehicle +``` + + --- ### acre_api_fnc_getBaseRadio diff --git a/docs/wiki/frameworks/vehicle-racks.md b/docs/wiki/frameworks/vehicle-racks.md index ab1599516..1da22a726 100644 --- a/docs/wiki/frameworks/vehicle-racks.md +++ b/docs/wiki/frameworks/vehicle-racks.md @@ -227,4 +227,6 @@ Racks can also be dynamically added, removed or initialised using API functions. It is possible through this API function to add and initialise a rack on non-enterable objects like drones or communication tables. - `acre_api_fnc_removeRackFromVehicle` allows removing a rack with a unique ID from a vehicle. +- `acre_api_fnc_removeAllRacksFromVehicle` removes all racks from a vehicle. - `acre_api_fnc_initVehicleRacks` initialises all racks in a vehicle. This API function can be used to initialise racks on non-enterable vehicles. +- `acre_api_fnc_replaceRacksOnVehicle` can be used to replace the config-defined racks of a vehicle with a different rack class.