diff --git a/addons/common/functions/fnc_hasItem.sqf b/addons/common/functions/fnc_hasItem.sqf index f77337a5dd..9d5d79b1a5 100644 --- a/addons/common/functions/fnc_hasItem.sqf +++ b/addons/common/functions/fnc_hasItem.sqf @@ -1,23 +1,21 @@ /* * Author: Glowbal - * Check if unit has item + * Check if unit has item. Note: case-sensitive. * * Arguments: * 0: Unit * 1: Item Classname * * Return Value: - * has Item + * Unit has Item * * Example: - * [[bob, "item"] call ace_common_fnc_hasItem + * [bob, "item"] call ace_common_fnc_hasItem * - * Public: yes - * - * Note: Case sensitive + * Public: Yes */ #include "script_component.hpp" params [["_unit", objNull, [objNull]], ["_item", "", [""]]]; -_item in items _unit // return +_item in items _unit diff --git a/addons/pylons/$PBOPREFIX$ b/addons/pylons/$PBOPREFIX$ new file mode 100644 index 0000000000..4da952ebb7 --- /dev/null +++ b/addons/pylons/$PBOPREFIX$ @@ -0,0 +1 @@ +z\ace\addons\pylons diff --git a/addons/pylons/ACE_Settings.hpp b/addons/pylons/ACE_Settings.hpp new file mode 100644 index 0000000000..696fcc1eeb --- /dev/null +++ b/addons/pylons/ACE_Settings.hpp @@ -0,0 +1,44 @@ +class ACE_Settings { + class GVAR(enabled) { + category = CSTRING(Category_Pylons); + displayName = CSTRING(Enabled); + description = CSTRING(Enabled_description); + value = 1; + typeName = "BOOL"; + }; + class GVAR(rearmNewPylons) { + category = CSTRING(Category_Pylons); + displayName = CSTRING(RearmNewPylons); + description = CSTRING(RearmNewPylons_description); + value = 0; + typeName = "BOOL"; + }; + class GVAR(searchDistance) { + category = CSTRING(Category_Pylons); + displayName = CSTRING(SearchDistance); + description = CSTRING(SearchDistance_description); + value = 15; + typeName = "SCALAR"; + }; + class GVAR(timePerPylon) { + category = CSTRING(Category_Pylons); + displayName = CSTRING(TimePerPylon); + description = CSTRING(TimePerPylon_description); + value = 5; + typeName = "SCALAR"; + }; + class GVAR(requireEngineer) { + category = CSTRING(Category_Pylons); + displayName = CSTRING(RequireEngineer); + description = CSTRING(RequireEngineer_description); + value = 0; + typeName = "BOOL"; + }; + class GVAR(requireToolkit) { + category = CSTRING(Category_Pylons); + displayName = CSTRING(RequireToolkit); + description = CSTRING(RequireToolkit_description); + value = 1; + typeName = "BOOL"; + }; +}; diff --git a/addons/pylons/CfgEventHandlers.hpp b/addons/pylons/CfgEventHandlers.hpp new file mode 100644 index 0000000000..0d3301d6e0 --- /dev/null +++ b/addons/pylons/CfgEventHandlers.hpp @@ -0,0 +1,17 @@ +class Extended_PreStart_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_FILE(XEH_preStart)); + }; +}; + +class Extended_PreInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_FILE(XEH_preInit)); + }; +}; + +class Extended_PostInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_FILE(XEH_postInit)); + }; +}; diff --git a/addons/pylons/README.md b/addons/pylons/README.md new file mode 100644 index 0000000000..b2b6d9d064 --- /dev/null +++ b/addons/pylons/README.md @@ -0,0 +1,11 @@ +ace_pylons +============ + +Adds an interface that allows players to configure aircraft pylons. + + +## Maintainers + +The people responsible for merging changes to this component or answering potential questions. + +- [654wak654](https://github.com/654wak654) diff --git a/addons/pylons/XEH_PREP.hpp b/addons/pylons/XEH_PREP.hpp new file mode 100644 index 0000000000..56388b09b4 --- /dev/null +++ b/addons/pylons/XEH_PREP.hpp @@ -0,0 +1,13 @@ +PREP(canConfigurePylons); +PREP(configurePylons); +PREP(handleDisconnect); +PREP(onButtonApply); +PREP(onButtonClose); +PREP(onButtonDelete); +PREP(onButtonLoad); +PREP(onButtonSave); +PREP(onButtonTurret); +PREP(onComboSelChange); +PREP(onNameChange); +PREP(onPylonMirror); +PREP(showDialog); diff --git a/addons/pylons/XEH_postInit.sqf b/addons/pylons/XEH_postInit.sqf new file mode 100644 index 0000000000..ff3d4f83d6 --- /dev/null +++ b/addons/pylons/XEH_postInit.sqf @@ -0,0 +1,46 @@ +#include "script_component.hpp" + +["ace_settingsInitialized", { + if (!GVAR(enabled)) exitWith {}; + + private _filter = "isClass (_x >> 'Components' >> 'TransportPylonsComponent') && {(getNumber (_x >> 'scope')) > 0}"; + GVAR(aircraftWithPylons) = (_filter configClasses (configFile >> "CfgVehicles")) apply {configName _x}; + { + [_x, "init", { + params ["_aircraft"]; + + private _loadoutAction = [ + QGVAR(loadoutAction), + localize LSTRING(ConfigurePylons), + "", + {[_target] call FUNC(showDialog)}, + { + private _vehicles = _target nearObjects ["LandVehicle", GVAR(searchDistance) + 10]; + private _filter = ["transportAmmo", QEGVAR(rearm,defaultSupply)] select (["ace_rearm"] call EFUNC(common,isModLoaded)); + private _rearmVehicles = {(getNumber (configFile >> "CfgVehicles" >> typeOf _x >> _filter)) > 0} count _vehicles; + + (_rearmVehicles > 0 && {[ace_player, _target] call FUNC(canConfigurePylons)}) + } + ] call EFUNC(interact_menu,createAction); + + [_aircraft, 0, ["ACE_MainActions"], _loadoutAction] call EFUNC(interact_menu,addActionToObject); + }, false, [], true] call CBA_fnc_addClassEventHandler; + } forEach GVAR(aircraftWithPylons); + + [QGVAR(setPylonLoadOutEvent), { + params ["_aircraft", "_pylonIndex", "_pylon", "_turret"]; + _aircraft setPylonLoadOut [_pylonIndex, _pylon, false, _turret]; + }] call CBA_fnc_addEventHandler; + + [QGVAR(setAmmoOnPylonEvent), { + params ["_aircraft", "_pylonIndex", "_count"]; + _aircraft setAmmoOnPylon [_pylonIndex, _count]; + }] call CBA_fnc_addEventHandler; + + if (isServer) then { + GVAR(currentAircraftNamespace) = true call CBA_fnc_createNamespace; + publicVariable QGVAR(currentAircraftNamespace); + + addMissionEventHandler ["HandleDisconnect", LINKFUNC(handleDisconnect)]; + }; +}] call CBA_fnc_addEventHandler; diff --git a/addons/pylons/XEH_preInit.sqf b/addons/pylons/XEH_preInit.sqf new file mode 100644 index 0000000000..b47cf6628d --- /dev/null +++ b/addons/pylons/XEH_preInit.sqf @@ -0,0 +1,9 @@ +#include "script_component.hpp" + +ADDON = false; + +PREP_RECOMPILE_START; +#include "XEH_PREP.hpp" +PREP_RECOMPILE_END; + +ADDON = true; diff --git a/addons/pylons/XEH_preStart.sqf b/addons/pylons/XEH_preStart.sqf new file mode 100644 index 0000000000..022888575e --- /dev/null +++ b/addons/pylons/XEH_preStart.sqf @@ -0,0 +1,3 @@ +#include "script_component.hpp" + +#include "XEH_PREP.hpp" diff --git a/addons/pylons/config.cpp b/addons/pylons/config.cpp new file mode 100644 index 0000000000..fc7159e08b --- /dev/null +++ b/addons/pylons/config.cpp @@ -0,0 +1,19 @@ +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + name = COMPONENT_NAME; + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = {"ace_interact_menu"}; + author = ECSTRING(common,ACETeam); + authors[] = {"654wak654"}; + url = ECSTRING(main,URL); + VERSION_CONFIG; + }; +}; + +#include "ACE_Settings.hpp" +#include "CfgEventHandlers.hpp" +#include "menu.hpp" diff --git a/addons/pylons/functions/fnc_canConfigurePylons.sqf b/addons/pylons/functions/fnc_canConfigurePylons.sqf new file mode 100644 index 0000000000..9582c69bd3 --- /dev/null +++ b/addons/pylons/functions/fnc_canConfigurePylons.sqf @@ -0,0 +1,25 @@ +/* + * Author: 654wak654 + * Checks if given unit can access the pylon configuration dialog for the given aircraft. + * + * Arguments: + * 0: Unit + * 1: Aircraft + * + * Return Value: + * Unit can configure the aircraft's pylons + * + * Example: + * [ace_player, cursorObject] call ace_pylons_fnc_canConfigurePylons + * + * Public: No + */ +#include "script_component.hpp" + +params ["_unit", "_aircraft"]; + +if (GVAR(requireEngineer) && {!(_unit getUnitTrait "engineer")}) exitWith {false}; + +if (GVAR(requireToolkit) && {!([_unit, "ToolKit"] call EFUNC(common,hasItem))}) exitWith {false}; + +(!isEngineOn _aircraft && {[_unit, _aircraft] call EFUNC(common,canInteractWith)}) diff --git a/addons/pylons/functions/fnc_configurePylons.sqf b/addons/pylons/functions/fnc_configurePylons.sqf new file mode 100644 index 0000000000..665f7ccdbc --- /dev/null +++ b/addons/pylons/functions/fnc_configurePylons.sqf @@ -0,0 +1,74 @@ +/* + * Author: 654wak654 + * Recursively shows the progress bar for each configured pylon. + * + * Arguments: + * 0: Indexes of pylons to configure + * 1: Current index + * + * Return Value: + * None + * + * Example: + * [_pylonsToConfigure, 0] call ace_pylons_fnc_configurePylons + * + * Public: No + */ +#include "script_component.hpp" + +params ["_pylonsToConfigure", "_currentPylon"]; + +if (_currentPylon == count _pylonsToConfigure) exitWith {}; + +// TODO: Animation and sound +[ + [GVAR(timePerPylon), 0] select GVAR(isCurator), + _this, + { + (_this select 0) params ["_pylonsToConfigure", "_currentPylon"]; + private _pylonIndex = _pylonsToConfigure select _currentPylon; + + // Remove the weapon of current pylon from aircraft IF weapon is only on this pylon + private _currentPylonMagazine = (getPylonMagazines GVAR(currentAircraft)) select _pylonIndex; + if (_currentPylonMagazine != "") then { + private _allPylonWeapons = (getPylonMagazines GVAR(currentAircraft)) apply { + getText (configFile >> "CfgMagazines" >> _x >> "pylonWeapon") + }; + private _pylonWeapon = _allPylonWeapons select _pylonIndex; + if (({_x == _pylonWeapon} count _allPylonWeapons) == 1) then { + GVAR(currentAircraft) removeWeaponGlobal _pylonWeapon; + }; + }; + + private _combo = GVAR(comboBoxes) select _pylonIndex select 0; + private _pylonMagazine = _combo lbData (lbCurSel _combo); + private _turret = (GVAR(comboBoxes) select _pylonIndex select 2) getVariable [QGVAR(turret), []]; + if (_turret isEqualTo [-1]) then {_turret = [];}; + + [ + QGVAR(setPylonLoadOutEvent), + [GVAR(currentAircraft), _pylonIndex + 1, _pylonMagazine, _turret] + ] call CBA_fnc_globalEvent; + + private _count = if (GVAR(rearmNewPylons) || {GVAR(isCurator)}) then { + getNumber (configFile >> "CfgMagazines" >> _pylonMagazine >> "count") + } else { + 0 + }; + + [ + QGVAR(setAmmoOnPylonEvent), + [GVAR(currentAircraft), _pylonIndex + 1, _count], + GVAR(currentAircraft) + ] call CBA_fnc_targetEvent; + + [_pylonsToConfigure, _currentPylon + 1] call FUNC(configurePylons); + }, + { + (_this select 0) params ["", "_currentPylon"]; + [format [localize LSTRING(Stopped), _currentPylon + 1], false, 5] call EFUNC(common,displayText); + }, + format [localize LSTRING(ReplacingPylon), _currentPylon + 1, count _pylonsToConfigure], + {true}, + ["isNotInZeus"] +] call EFUNC(common,progressBar); diff --git a/addons/pylons/functions/fnc_handleDisconnect.sqf b/addons/pylons/functions/fnc_handleDisconnect.sqf new file mode 100644 index 0000000000..c53d0ada17 --- /dev/null +++ b/addons/pylons/functions/fnc_handleDisconnect.sqf @@ -0,0 +1,26 @@ +/* + * Author: 654wak654 + * Cleans up pylons on client disconnect. + * + * Arguments: + * 0: Player + * + * Return Value: + * None + * + * Example: + * [] call ace_pylons_fnc_handleDisconnect + * + * Public: No + */ +#include "script_component.hpp" + +params ["", "", "_uid"]; + +private _aircraft = GVAR(currentAircraftNamespace) getVariable ["_uid", objNull]; +if (!isNull _aircraft) then { + _aircraft setVariable [QGVAR(currentUser), objNull, true]; + [_aircraft, "blockEngine", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); + + GVAR(currentAircraftNamespace) setVariable [_uid, nil, true]; // Remove var from namespace, no need to keep objNull +}; diff --git a/addons/pylons/functions/fnc_onButtonApply.sqf b/addons/pylons/functions/fnc_onButtonApply.sqf new file mode 100644 index 0000000000..ae27e98d4c --- /dev/null +++ b/addons/pylons/functions/fnc_onButtonApply.sqf @@ -0,0 +1,46 @@ +/* + * Author: 654wak654 + * Starts the pylon configuration. + * + * Arguments: + * None + * + * Return Value: + * None + * + * Example: + * [] call ace_pylons_fnc_onButtonApply + * + * Public: No + */ +#include "script_component.hpp" + +// Check for FRIES change +private _checkbox = CONTROL(ID_DIALOG) ID_CHECKBOX_FRIES; +if (ctrlShown _checkbox && {!((cbChecked _checkbox) isEqualTo (_checkbox getVariable QGVAR(originalState)))}) then { + if (cbChecked _checkbox) then { + [GVAR(currentAircraft)] call EFUNC(fastroping,equipFRIES); + } else { + [GVAR(currentAircraft)] call EFUNC(fastroping,cutRopes); + private _fries = GVAR(currentAircraft) getVariable [QEGVAR(fastroping,FRIES), objNull]; + deleteVehicle _fries; + }; + _checkbox setVariable [QGVAR(originalState), cbChecked _checkbox]; +}; + +private _pylonsToConfigure = []; +{ + // Pick combo boxes where current selection doesn't match original selection + if ((lbCurSel (_x select 0)) != (_x select 3)) then { + _pylonsToConfigure pushBack _forEachIndex; + }; +} forEach GVAR(comboBoxes); + +if (_pylonsToConfigure isEqualTo []) exitWith {}; + +[_pylonsToConfigure, 0] call FUNC(configurePylons); + +// As a zeus you expect module dialogs to close once you click apply +if (GVAR(isCurator)) then { + call FUNC(onButtonClose); +}; diff --git a/addons/pylons/functions/fnc_onButtonClose.sqf b/addons/pylons/functions/fnc_onButtonClose.sqf new file mode 100644 index 0000000000..ef93f3f1bf --- /dev/null +++ b/addons/pylons/functions/fnc_onButtonClose.sqf @@ -0,0 +1,21 @@ +/* + * Author: 654wak654 + * Handles the closing of the dialog. + * + * Arguments: + * None + * + * Return Value: + * None + * + * Example: + * [] call ace_pylons_fnc_onButtonClose + * + * Public: No + */ +#include "script_component.hpp" + +GVAR(currentAircraft) setVariable [QGVAR(currentUser), objNull, true]; +GVAR(currentAircraftNamespace) setVariable [getPlayerUID ace_player, nil, true]; // Remove var from namespace, no need to keep objNull +[GVAR(currentAircraft), "blockEngine", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); +closeDialog 2; diff --git a/addons/pylons/functions/fnc_onButtonDelete.sqf b/addons/pylons/functions/fnc_onButtonDelete.sqf new file mode 100644 index 0000000000..8d1fdee6de --- /dev/null +++ b/addons/pylons/functions/fnc_onButtonDelete.sqf @@ -0,0 +1,29 @@ +/* + * Author: 654wak654 + * Deletes the selected pylon configuration from profileNamespace. + * + * Arguments: + * None + * + * Return Value: + * None + * + * Example: + * [] call ace_pylons_fnc_onButtonDelete + * + * Public: No + */ +#include "script_component.hpp" + +private _loadoutName = lbText [ID_LIST_LOADOUTS, lbCurSel ID_LIST_LOADOUTS]; + +lbDelete [ID_LIST_LOADOUTS, lbCurSel ID_LIST_LOADOUTS]; + +private _aircraftLoadouts = profileNamespace getVariable [QGVAR(aircraftLoadouts), []]; +private _index = { + if ((_x select 0) isEqualTo _loadoutName && {(_x select 3) isEqualTo typeOf GVAR(currentAircraft)}) exitWith { + _forEachIndex + }; +} forEach _aircraftLoadouts; +_aircraftLoadouts deleteAt _index; +profileNamespace setVariable [QGVAR(aircraftLoadouts), _aircraftLoadouts]; diff --git a/addons/pylons/functions/fnc_onButtonLoad.sqf b/addons/pylons/functions/fnc_onButtonLoad.sqf new file mode 100644 index 0000000000..9092d0a910 --- /dev/null +++ b/addons/pylons/functions/fnc_onButtonLoad.sqf @@ -0,0 +1,58 @@ +/* + * Author: 654wak654 + * Loads selected pylon configuration from either config or profileNamespace. + * + * Arguments: + * None + * + * Return Value: + * None + * + * Example: + * [] call ace_pylons_fnc_onButtonLoad + * + * Public: No + */ +#include "script_component.hpp" + +[false] call FUNC(onPylonMirror); +(CONTROL(ID_DIALOG) ID_CHECKBOX_MIRROR) cbSetChecked false; + +private _loadoutName = ctrlText ID_EDIT_LOADOUTNAME; +private _fnc_setSelections = { + params ["_mags", "_turrets"]; + + { + _x params ["_combo", "_mirroredIndex", "_button"]; + + private _index = 0; + for "_i" from 1 to ((lbSize _combo) - 1) do { + if ((_combo lbData _i) == (_mags param [_forEachIndex, ""])) exitWith { + _index = _i; + }; + }; + _combo lbSetCurSel _index; + + [_button, false, _turrets select _forEachIndex] call FUNC(onButtonTurret); + } forEach GVAR(comboBoxes); +}; + +private _pylonComponent = configFile >> "CfgVehicles" >> typeOf GVAR(currentAircraft) >> "Components" >> "TransportPylonsComponent"; +private _loadoutFound = { + if (getText (_x >> "displayName") isEqualTo _loadoutName) exitWith { + // Get default turrets from config + private _turrets = ("true" configClasses (_pylonComponent >> "Pylons")) apply {getArray (_x >> "turret")}; + [getArray (_x >> "attachment"), _turrets] call _fnc_setSelections; + true + }; + false +} forEach ("true" configClasses (_pylonComponent >> "Presets")); + +if (_loadoutFound) exitWith {}; + +private _aircraftLoadouts = profileNamespace getVariable [QGVAR(aircraftLoadouts), []]; +{ + if ((_x select 0) isEqualTo _loadoutName && {(_x select 3) isEqualTo typeOf GVAR(currentAircraft)}) exitWith { + [_x select 1, _x select 2] call _fnc_setSelections; + }; +} forEach _aircraftLoadouts; diff --git a/addons/pylons/functions/fnc_onButtonSave.sqf b/addons/pylons/functions/fnc_onButtonSave.sqf new file mode 100644 index 0000000000..c20c8928ec --- /dev/null +++ b/addons/pylons/functions/fnc_onButtonSave.sqf @@ -0,0 +1,37 @@ +/* + * Author: 654wak654 + * Saves the selected pylon configuration to profileNamespace. + * + * Arguments: + * None + * + * Return Value: + * None + * + * Example: + * [] call ace_pylons_fnc_onButtonSave + * + * Public: No + */ +#include "script_component.hpp" + +private _loadoutName = ctrlText ID_EDIT_LOADOUTNAME; +private _aircraftLoadouts = profileNamespace getVariable [QGVAR(aircraftLoadouts), []]; +private _loadoutPylons = GVAR(comboBoxes) apply {(_x select 0) lbData (lbCurSel (_x select 0))}; +private _turretOwners = GVAR(comboBoxes) apply {(_x select 2) getVariable [QGVAR(turret), [-1]]}; + +private _found = false; +{ + if ((_x select 0) isEqualTo _loadoutName && {(_x select 2) isEqualTo typeOf GVAR(currentAircraft)}) exitWith { + _aircraftLoadouts set [_forEachIndex, [_loadoutName, _loadoutPylons, _turretOwners, typeOf GVAR(currentAircraft)]]; + _found = true; + }; +} forEach _aircraftLoadouts; + +if (!_found) then { + private _index = lbAdd [ID_LIST_LOADOUTS, _loadoutName]; + lbSetCurSel [ID_LIST_LOADOUTS, _index]; + _aircraftLoadouts pushBack [_loadoutName, _loadoutPylons, _turretOwners, typeOf GVAR(currentAircraft)]; +}; + +profileNamespace setVariable [QGVAR(aircraftLoadouts), _aircraftLoadouts]; diff --git a/addons/pylons/functions/fnc_onButtonTurret.sqf b/addons/pylons/functions/fnc_onButtonTurret.sqf new file mode 100644 index 0000000000..4554075c37 --- /dev/null +++ b/addons/pylons/functions/fnc_onButtonTurret.sqf @@ -0,0 +1,48 @@ +/* + * Author: 654wak654 + * Handles init and click events of turret switch buttons. + * + * Arguments: + * 0: Button + * 1: Should switch icons + * 2: Turret path + * + * Return Value: + * None + * + * Example: + * [_button, true, []] call ace_pylons_fnc_onButtonTurret + * + * Public: No + */ +#include "script_component.hpp" + +params ["_ctrl", "_switch", "_turret"]; + +if (_switch) then { + _turret = [[0], [-1]] select ((_ctrl getVariable QGVAR(turret)) isEqualTo [0]); + + { + _x params ["", "_mirroredIndex", "_button"]; + if (_ctrl == _button) exitWith { + if (_mirroredIndex == -1) then { + private _indexOf = _forEachIndex; + { + _x params ["", "_mirroredIndex", "_button"]; + if (_mirroredIndex == _indexOf && {!ctrlEnabled _button}) exitWith { + [_button, false, _turret] call FUNC(onButtonTurret); + }; + } forEach GVAR(comboBoxes); + }; + }; + } forEach GVAR(comboBoxes); +}; +_ctrl setVariable [QGVAR(turret), _turret]; + +if (_turret isEqualTo [-1]) then { + _ctrl ctrlSetText "a3\ui_f\data\IGUI\RscIngameUI\RscUnitInfo\role_driver_ca.paa"; + _ctrl ctrlSetTooltip localize "str_driver"; +} else { + _ctrl ctrlSetText "a3\ui_f\data\IGUI\RscIngameUI\RscUnitInfo\role_gunner_ca.paa"; + _ctrl ctrlSetTooltip localize "str_gunner"; +}; diff --git a/addons/pylons/functions/fnc_onComboSelChange.sqf b/addons/pylons/functions/fnc_onComboSelChange.sqf new file mode 100644 index 0000000000..97130ea54d --- /dev/null +++ b/addons/pylons/functions/fnc_onComboSelChange.sqf @@ -0,0 +1,38 @@ +/* + * Author: 654wak654 + * Handles various UI changes when a combobox' selection changes. + * + * Arguments: + * 0: Combobox + * 1: Selected index + * + * Return Value: + * None + * + * Example: + * [_combo, 5] call ace_pylons_fnc_onComboSelChange + * + * Public: No + */ +#include "script_component.hpp" + +params ["_ctrl", "_index"]; + +{ + _x params ["_combo", "_mirroredIndex", "", "_originalIndex"]; + if (_ctrl == _combo) exitWith { + if (_mirroredIndex == -1) then { + private _indexOf = _forEachIndex; + { + _x params ["_combo", "_mirroredIndex"]; + if (_mirroredIndex == _indexOf && {!ctrlEnabled _combo}) exitWith { + _combo lbSetCurSel _index; + }; + } forEach GVAR(comboBoxes); + }; + if !(GVAR(rearmNewPylons) || {GVAR(isCurator)}) then { + private _color = [[0.5, 0.05, 0.05, 1], [0.05, 0.05, 0.05, 1]] select (_index == _originalIndex); + _combo ctrlSetBackgroundColor _color; + }; + }; +} forEach GVAR(comboBoxes); diff --git a/addons/pylons/functions/fnc_onNameChange.sqf b/addons/pylons/functions/fnc_onNameChange.sqf new file mode 100644 index 0000000000..9915aeee70 --- /dev/null +++ b/addons/pylons/functions/fnc_onNameChange.sqf @@ -0,0 +1,25 @@ +/* + * Author: 654wak654 + * Called when current loadout name is changed. + * Prevents default presets from gettings deleted / overwritten. + * + * Arguments: + * None + * + * Return Value: + * None + * + * Example: + * [] call ace_pylons_fnc_onNameChange + * + * Public: No + */ +#include "script_component.hpp" + +if ((ctrlText ID_EDIT_LOADOUTNAME) in GVAR(defaultLoadoutNames)) then { + ctrlEnable [ID_BUTTON_SAVE, false]; + ctrlEnable [ID_BUTTON_DELETE, false]; +} else { + ctrlEnable [ID_BUTTON_SAVE, true]; + ctrlEnable [ID_BUTTON_DELETE, true]; +}; diff --git a/addons/pylons/functions/fnc_onPylonMirror.sqf b/addons/pylons/functions/fnc_onPylonMirror.sqf new file mode 100644 index 0000000000..55987b2b94 --- /dev/null +++ b/addons/pylons/functions/fnc_onPylonMirror.sqf @@ -0,0 +1,41 @@ +/* + * Author: 654wak654 + * Called when the "mirror" checkbox on the loadout dialog is checked. + * Changes the comboboxes and buttons to be mirrored / normal. + * + * Arguments: + * 0: Checked status + * + * Return Value: + * None + * + * Example: + * [false] call ace_pylons_fnc_onPylonMirror + * + * Public: No + */ +#include "script_component.hpp" + +params ["_checked"]; + +if (_checked) then { + { + _x params ["_combo", "_mirroredIndex", "_button"]; + + if (_mirroredIndex != -1) then { + private _selection = lbCurSel ((GVAR(comboBoxes) select _mirroredIndex) select 0); + _combo lbSetCurSel _selection; + _combo ctrlEnable false; + + private _mirroredButton = (GVAR(comboBoxes) select _mirroredIndex) select 2; + private _turret = _mirroredButton getVariable [QGVAR(turret), [-1]]; + [_button, false, _turret] call FUNC(onButtonTurret); + _button ctrlEnable false; + }; + } forEach GVAR(comboBoxes); +} else { + { + (_x select 0) ctrlEnable true; + (_x select 2) ctrlEnable true; + } forEach GVAR(comboBoxes); +}; diff --git a/addons/pylons/functions/fnc_showDialog.sqf b/addons/pylons/functions/fnc_showDialog.sqf new file mode 100644 index 0000000000..5379b1b2f9 --- /dev/null +++ b/addons/pylons/functions/fnc_showDialog.sqf @@ -0,0 +1,139 @@ +/* +* Author: 654wak654 +* Shows the aircraft loadout dialog for given aircraft. +* +* Arguments: +* 0: Aircraft +* 1: Is curator. Disables time and resource requirements. (default: false) +* +* Return Value: +* None +* +* Example: +* [vehicle ace_player] call ace_pylons_fnc_showDialog +* +* Public: Yes +*/ +#include "script_component.hpp" + +params ["_aircraft", ["_isCurator", false]]; + +if (!GVAR(enabled) || {!(typeOf _aircraft in GVAR(aircraftWithPylons))}) exitWith {}; + +private _currentUser = _aircraft getVariable [QGVAR(currentUser), objNull]; +if (!isNull _currentUser) exitWith { + [format [localize LSTRING(InUse), name _currentUser], false, 5] call EFUNC(common,displayText); +}; +_aircraft setVariable [QGVAR(currentUser), ace_player, true]; +GVAR(currentAircraftNamespace) setVariable [getPlayerUID ace_player, _aircraft, true]; +[_aircraft, "blockEngine", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); + +GVAR(isCurator) = _isCurator; +GVAR(currentAircraft) = _aircraft; + +createDialog QGVAR(DialogLoadout); +private _display = DISPLAY(ID_DIALOG); +_display displayAddEventHandler ["Unload", LINKFUNC(onButtonClose)]; + +if (GVAR(rearmNewPylons) || {_isCurator}) then { + ctrlShow [ID_TEXT_BANNER, false]; +}; + +private _config = configFile >> "CfgVehicles" >> typeOf _aircraft; +private _pylonComponent = _config >> "Components" >> "TransportPylonsComponent"; + +ctrlSetText [ID_PICTURE_AIRCRAFT, getText (_pylonComponent >> "uiPicture")]; + +private _hasFRIES = getNumber (_config >> QEGVAR(fastroping,enabled)); +if (["ace_fastroping"] call EFUNC(common,isModLoaded) && {_hasFRIES > 1}) then { + private _checkbox = _display displayCtrl ID_CHECKBOX_FRIES; + private _fries = _aircraft getVariable [QEGVAR(fastroping,FRIES), objNull]; + _checkbox cbSetChecked (!isNull _fries); + _checkbox setVariable [QGVAR(originalState), !isNull _fries]; +} else { + ctrlShow [ID_CHECKBOX_FRIES, false]; + ctrlShow [ID_TEXT_FRIES, false]; +}; + +GVAR(comboBoxes) = []; +{ + private _combo = _display ctrlCreate ["ctrlCombo", -1]; + private _picturePos = ctrlPosition (_display displayCtrl ID_PICTURE_AIRCRAFT); + private _uiPos = getArray (_x >> "UIposition"); + _combo ctrlSetPosition [ + (_picturePos select 0) + (_uiPos select 0), + (_picturePos select 1) + (_uiPos select 1), + 0.1 * safezoneW, + 0.028 * safezoneH + ]; + _combo ctrlCommit 0; + + _combo lbAdd localize LSTRING(Empty); + _combo lbSetData [0, ""]; + + private _mag = (getPylonMagazines _aircraft) select _forEachIndex; + private _mags = _aircraft getCompatiblePylonMagazines (_forEachIndex + 1); + private _index = 0; + { + _combo lbAdd getText (configFile >> "CfgMagazines" >> _x >> "displayName"); + _combo lbSetData [_forEachIndex + 1, _x]; + + if (_x == _mag) then { + _index = _forEachIndex + 1; + }; + } forEach _mags; + _combo lbSetCurSel _index; + _combo ctrlAddEventHandler ["LBSelChanged", LINKFUNC(onComboSelChange)]; + // TODO: Allow pylon priority selection? + + private _mirroredIndex = getNumber (_x >> "mirroredMissilePos"); + + private _button = controlNull; + if (count allTurrets [_aircraft, false] > 0) then { + _button = _display ctrlCreate ["ctrlButtonPictureKeepAspect", -1]; + private _turret = [_aircraft, _forEachIndex] call EFUNC(common,getPylonTurret); + [_button, false, _turret] call FUNC(onButtonTurret); + _button ctrlAddEventHandler ["ButtonClick", {[_this select 0, true, []] call FUNC(onButtonTurret)}]; + _button ctrlSetPosition [ + (_picturePos select 0) + (_uiPos select 0) - (0.0165 * safezoneW), + (_picturePos select 1) + (_uiPos select 1), + 0.0165 * safezoneW, + 0.028 * safezoneH + ]; + _button ctrlCommit 0; + }; + + GVAR(comboBoxes) pushBack [_combo, _mirroredIndex - 1, _button, _index]; +} forEach ("true" configClasses (_pylonComponent >> "Pylons")); + +GVAR(defaultLoadoutNames) = []; +{ + lbAdd [ID_LIST_LOADOUTS, getText (_x >> "displayName")]; + lbSetPicture [ID_LIST_LOADOUTS, _forEachIndex, "a3\data_f_jets\logos\jets_logo_small_ca.paa"]; + + GVAR(defaultLoadoutNames) pushBack getText (_x >> "displayName"); +} forEach ("true" configClasses (_pylonComponent >> "Presets")); + +{ + if ((_x select 3) == typeOf _aircraft) then { + lbAdd [ID_LIST_LOADOUTS, _x select 0]; + }; +} forEach (profileNamespace getVariable [QGVAR(aircraftLoadouts), []]); + +private _displayName = getText (_config >> "displayName"); +ctrlSetText [ID_TEXT_LISTTITLE, format [localize LSTRING(LoadoutsFor), _displayName]]; + +private _list = _display displayCtrl ID_LIST_LOADOUTS; +_list ctrlAddEventHandler ["LBSelChanged", { + params ["_ctrl"]; + + ctrlSetText [ID_EDIT_LOADOUTNAME, _ctrl lbText (lbCurSel _ctrl)]; + call FUNC(onNameChange); +}]; + +private _edit = _display displayCtrl ID_EDIT_LOADOUTNAME; +_edit ctrlAddEventHandler ["KeyUp", LINKFUNC(onNameChange)]; +_edit ctrlAddEventHandler ["KeyDown", LINKFUNC(onNameChange)]; + +private _checkbox = _display displayCtrl ID_CHECKBOX_MIRROR; +_checkbox ctrlAddEventHandler ["CheckedChanged", {[(_this select 1) == 1] call FUNC(onPylonMirror)}]; diff --git a/addons/pylons/functions/script_component.hpp b/addons/pylons/functions/script_component.hpp new file mode 100644 index 0000000000..62e8ea51a0 --- /dev/null +++ b/addons/pylons/functions/script_component.hpp @@ -0,0 +1 @@ +#include "\z\ace\addons\pylons\script_component.hpp" diff --git a/addons/pylons/menu.hpp b/addons/pylons/menu.hpp new file mode 100644 index 0000000000..8161f4d8a5 --- /dev/null +++ b/addons/pylons/menu.hpp @@ -0,0 +1,158 @@ +class IGUIBack; +class RscCheckBox; +class RscListBox; +class RscEdit; +class RscButtonMenu; +class RscText; +class RscPictureKeepAspect; + +class GVAR(DialogLoadout) { + idd = ID_DIALOG; + name = QGVAR(DialogLoadout); + enableSimulation = 1; + + class Controls { + class TextTitlebar: RscText { + idc = ID_TEXT_TITLEBAR; + text = CSTRING(AircraftLoadoutTitle); + x = 0.15835 * safezoneW + safezoneX; + y = 0.262 * safezoneH + safezoneY; + w = 0.68304 * safezoneW; + h = 0.028 * safezoneH; + colorBackground[] = {"(profileNamespace getVariable ['GUI_BCG_RGB_R', 0.13])","(profileNamespace getVariable ['GUI_BCG_RGB_G', 0.54])","(profileNamespace getVariable ['GUI_BCG_RGB_B', 0.21])",1}; + }; + class BackgroundDialog: IGUIBack { + idc = ID_BACKGROUND_DIALOG; + x = 0.15835 * safezoneW + safezoneX; + y = 0.29 * safezoneH + safezoneY; + w = 0.68304 * safezoneW; + h = 0.448 * safezoneH; + colorBackground[] = {0,0,0,0.3}; + }; + class BackgroundPicture: IGUIBack { + idc = ID_BACKGROUND_PICTURE; + x = 0.171616 * safezoneW + safezoneX; + y = 0.318 * safezoneH + safezoneY; + w = 0.440035 * safezoneW; + h = 0.392 * safezoneH; + colorBackground[] = {0.3,0.3,0.3,1}; + }; + class PictureAircraft: RscPictureKeepAspect { + idc = ID_PICTURE_AIRCRAFT; + x = 0.171616 * safezoneW + safezoneX; + y = 0.318 * safezoneH + safezoneY; + w = 0.440035 * safezoneW; + h = 0.392 * safezoneH; + }; + class CheckboxMirror: RscCheckBox { + idc = ID_CHECKBOX_MIRROR; + x = 0.171616 * safezoneW + safezoneX; + y = 0.318 * safezoneH + safezoneY; + w = 0.0165 * safezoneW; + h = 0.028 * safezoneH; + }; + class TextMirror: RscText { + idc = ID_TEXT_MIRROR; + text = "$STR_3DEN_Object_Attribute_PylonsMirror_displayName"; + tooltip="$STR_3DEN_Object_Attribute_PylonsMirror_tooltip"; + x = 0.188116 * safezoneW + safezoneX; + y = 0.318 * safezoneH + safezoneY; + w = 0.0656768 * safezoneW; + h = 0.028 * safezoneH; + colorBackground[] = {0,0,0,0.5}; + }; + class CheckboxFRIES: RscCheckBox { + idc = ID_CHECKBOX_FRIES; + x = 0.171616 * safezoneW + safezoneX; + y = 0.346 * safezoneH + safezoneY; + w = 0.0165 * safezoneW; + h = 0.028 * safezoneH; + }; + class TextFRIES: RscText { + idc = ID_TEXT_FRIES; + text = "FRIES"; + x = 0.188116 * safezoneW + safezoneX; + y = 0.346 * safezoneH + safezoneY; + w = 0.0656768 * safezoneW; + h = 0.028 * safezoneH; + colorBackground[] = {0,0,0,0.5}; + }; + class TextListTitle: RscText { + idc = ID_TEXT_LISTTITLE; + x = 0.624786 * safezoneW + safezoneX; + y = 0.318 * safezoneH + safezoneY; + w = 0.203437 * safezoneW; + h = 0.028 * safezoneH; + colorBackground[] = {0,0,0,0.5}; + }; + class ListLoadouts: RscListBox { + idc = ID_LIST_LOADOUTS; + x = 0.624786 * safezoneW + safezoneX; + y = 0.346 * safezoneH + safezoneY; + w = 0.203437 * safezoneW; + h = 0.294 * safezoneH; + }; + class EditLoadoutName: RscEdit { + idc = ID_EDIT_LOADOUTNAME; + x = 0.624786 * safezoneW + safezoneX; + y = 0.64 * safezoneH + safezoneY; + w = 0.203437 * safezoneW; + h = 0.028 * safezoneH; + colorBackground[] = {0,0,0,0.7}; + }; + class ButtonSave: RscButtonMenu { + idc = ID_BUTTON_SAVE; + action = QUOTE(call FUNC(onButtonSave)); + text = "$STR_disp_int_save"; + x = 0.624786 * safezoneW + safezoneX; + y = 0.682 * safezoneH + safezoneY; + w = 0.0590625 * safezoneW; + h = 0.028 * safezoneH; + }; + class ButtonLoad: RscButtonMenu { + idc = ID_BUTTON_LOAD; + action = QUOTE(call FUNC(onButtonLoad)); + text = "$STR_disp_int_load"; + x = 0.69703 * safezoneW + safezoneX; + y = 0.682 * safezoneH + safezoneY; + w = 0.0590625 * safezoneW; + h = 0.028 * safezoneH; + }; + class ButtonDelete: RscButtonMenu { + idc = ID_BUTTON_DELETE; + action = QUOTE(call FUNC(onButtonDelete)); + text = "$STR_disp_delete"; + x = 0.769275 * safezoneW + safezoneX; + y = 0.682 * safezoneH + safezoneY; + w = 0.0590625 * safezoneW; + h = 0.028 * safezoneH; + }; + class ButtonApply: RscButtonMenu { + idc = ID_BUTTON_APPLY; + action = QUOTE(call FUNC(onButtonApply)); + text = "$STR_ui_debug_but_apply"; + x = 0.683895 * safezoneW + safezoneX; + y = 0.738 * safezoneH + safezoneY; + w = 0.0721875 * safezoneW; + h = 0.028 * safezoneH; + }; + class ButtonClose: RscButtonMenu { + idc = ID_BUTTON_CLOSE; + text = "$STR_disp_cancel"; + action = QUOTE(call FUNC(onButtonClose)); + x = 0.769275 * safezoneW + safezoneX; + y = 0.738 * safezoneH + safezoneY; + w = 0.0721875 * safezoneW; + h = 0.028 * safezoneH; + }; + class TextBanner: RscText { + idc = ID_TEXT_BANNER; + text = CSTRING(BannerText); + x = 0.171616 * safezoneW + safezoneX; + y = 0.738 * safezoneH + safezoneY; + w = 0.440035 * safezoneW; + h = 0.028 * safezoneH; + colorBackground[] = {0.5,0,0,0.5}; + }; + }; +}; diff --git a/addons/pylons/script_component.hpp b/addons/pylons/script_component.hpp new file mode 100644 index 0000000000..fd511edc06 --- /dev/null +++ b/addons/pylons/script_component.hpp @@ -0,0 +1,37 @@ +#define COMPONENT pylons +#define COMPONENT_BEAUTIFIED Pylons +#include "\z\ace\addons\main\script_mod.hpp" + +// #define DEBUG_MODE_FULL +// #define DISABLE_COMPILE_CACHE +// #define ENABLE_PERFORMANCE_COUNTERS + +#ifdef DEBUG_ENABLED_PYLONS + #define DEBUG_MODE_FULL +#endif + +#ifdef DEBUG_SETTINGS_PYLONS + #define DEBUG_SETTINGS DEBUG_SETTINGS_PYLONS +#endif + +#include "\z\ace\addons\main\script_macros.hpp" + + +#define ID_DIALOG 654654 +#define ID_TEXT_TITLEBAR 100 +#define ID_BACKGROUND_DIALOG 110 +#define ID_BACKGROUND_PICTURE 111 +#define ID_PICTURE_AIRCRAFT 120 +#define ID_CHECKBOX_MIRROR 130 +#define ID_TEXT_MIRROR 140 +#define ID_CHECKBOX_FRIES 141 +#define ID_TEXT_FRIES 142 +#define ID_TEXT_LISTTITLE 150 +#define ID_LIST_LOADOUTS 160 +#define ID_EDIT_LOADOUTNAME 170 +#define ID_BUTTON_SAVE 180 +#define ID_BUTTON_LOAD 190 +#define ID_BUTTON_DELETE 200 +#define ID_BUTTON_APPLY 210 +#define ID_BUTTON_CLOSE 211 +#define ID_TEXT_BANNER 220 diff --git a/addons/pylons/stringtable.xml b/addons/pylons/stringtable.xml new file mode 100644 index 0000000000..d581b9e410 --- /dev/null +++ b/addons/pylons/stringtable.xml @@ -0,0 +1,68 @@ + + + + + AIRCRAFT LOADOUT + + + Loadouts for %1 + + + Configure Pylons + + + Pylons + + + <empty> + + + Pylons that are colored red will have to be manually rearmed. + + + %1 is already configuring this aircraft! + + + Replacing pylon %1 out of %2... + + + Stopped at pylon %1! + + + Enable Pylons Menu + + + Enable pylon configuration menu for aircraft. + + + Rearm New Pylons + + + Automatically rearm new pylons from the nearest rearm vehicle. + + + Time Per Pylon + + + The time it takes to replace each pylon (in seconds). + + + Search Distance + + + The distance an aircraft needs to be from a rearm vehicle. + + + Require Engineer + + + Require an engineer. + + + Require Toolkit + + + Require a toolkit in inventory. + + + diff --git a/addons/zeus/CfgVehicles.hpp b/addons/zeus/CfgVehicles.hpp index 9c61c2f5dd..453e69616b 100644 --- a/addons/zeus/CfgVehicles.hpp +++ b/addons/zeus/CfgVehicles.hpp @@ -120,6 +120,13 @@ class CfgVehicles { function = QFUNC(moduleCaptive); icon = QPATHTOF(UI\Icon_Module_Zeus_Captive_ca.paa); }; + class GVAR(moduleConfigurePylons): GVAR(moduleBase) { + curatorCanAttach = 1; + category = QGVAR(Utility); + displayName = ECSTRING(pylons,ConfigurePylons); + function = QFUNC(moduleConfigurePylons); + icon = "a3\data_f_jets\logos\jets_logo_small_ca.paa"; + }; class GVAR(moduleDefendArea): GVAR(moduleBase) { curatorCanAttach = 1; category = QGVAR(AI); diff --git a/addons/zeus/XEH_PREP.hpp b/addons/zeus/XEH_PREP.hpp index 8c86dc1590..bb842edaf3 100644 --- a/addons/zeus/XEH_PREP.hpp +++ b/addons/zeus/XEH_PREP.hpp @@ -11,6 +11,7 @@ PREP(moduleAddSpareTrack); PREP(moduleAddSpareWheel); PREP(moduleAddOrRemoveFRIES); PREP(moduleCaptive); +PREP(moduleConfigurePylons); PREP(moduleGarrison); PREP(moduleGlobalSetSkill); PREP(moduleGroupSide); diff --git a/addons/zeus/config.cpp b/addons/zeus/config.cpp index 392c012251..5b764b6007 100644 --- a/addons/zeus/config.cpp +++ b/addons/zeus/config.cpp @@ -4,6 +4,7 @@ class CfgPatches { class ADDON { name = COMPONENT_NAME; units[] = { + QGVAR(moduleConfigurePylons), QGVAR(moduleDefendArea), QGVAR(moduleEditableObjects), QGVAR(moduleGlobalSetSkill), @@ -63,6 +64,11 @@ class CfgPatches { QGVAR(moduleAddOrRemoveFRIES) }; }; + class GVAR(pylons): ADDON { + units[] = { + QGVAR(moduleConfigurePylons) + }; + }; }; class ACE_Curator { @@ -71,6 +77,7 @@ class ACE_Curator { GVAR(cargo) = "ace_cargo"; GVAR(cargoAndRepair)[] = {"ace_cargo", "ace_repair"}; GVAR(fastroping) = "ace_fastroping"; + GVAR(pylons) = "ace_pylons"; }; #include "CfgFactionClasses.hpp" diff --git a/addons/zeus/functions/fnc_moduleConfigurePylons.sqf b/addons/zeus/functions/fnc_moduleConfigurePylons.sqf new file mode 100644 index 0000000000..4998ae8bac --- /dev/null +++ b/addons/zeus/functions/fnc_moduleConfigurePylons.sqf @@ -0,0 +1,37 @@ +/* + * Author: 654wak654 + * Opens the pylon configuration menu for the aircraft module is placed on. + * + * Arguments: + * 0: Module logic + * 1: Synchronized units + * 2: Activated + * + * Return Value: + * None + * + * Example: + * [LOGIC, [bob, kevin], true] call ace_zeus_fnc_moduleConfigurePylons + * + * Public: No + */ +#include "script_component.hpp" + +if (canSuspend) exitWith {[FUNC(moduleConfigurePylons), _this] call CBA_fnc_directCall;}; + +params ["_logic", "_units", "_activated"]; + +if !(_activated && {local _logic}) exitWith {}; + +private _aircraft = attachedTo _logic; + +deleteVehicle _logic; + +if (isNull _aircraft) exitWith { + [LSTRING(NothingSelected)] call FUNC(showMessage); +}; +if (!alive _aircraft) exitWith { + [LSTRING(OnlyAlive)] call FUNC(showMessage); +}; + +[_aircraft, true] call EFUNC(pylons,showDialog);