Add Pylons Component (#5517)

* Initial commit

* Change order

* ace-ify functions

* Add function headers, tweak onPylonMirror function

* Finish localization

* Fix trivial idc collision

* Styling

* Add self as author

* Add interaction for the dialog

* Add settings to enable menu and change behaviour

* Add strings

* Move changes into pylons component

* Progress

* Only one function left!

* Fix issues with overlapping players, Use LINKFUNC

* Add progress bar

* I need to switch branches

* Remove old pylon weapons from aircraft

* Explicitly set new pylon's ammo to 0

* Replace magic numbers with ID list

* Align controls properly

* Remove space before eol

* Add ability to add/remove FRIES

* 🐛 Whoops

* Fix logic errors

* Value of 1 means helicopter has built-in FRIES

* Add pilot/gunner switch button

Working on those buttons also helped me improve both the static and
on-the-fly (pun intended) parts of the dialog.

* Add quick zeus module

* Add a way to retrieve scripted pylon turrets

Not entirely reliable, but if used in both rearm and pylons, missions
that only use ace will work perfectly.

* Use getNumber default

* Use common's getPylonTurret

* Make dialog close on apply for zeus

* Handle UI Scaling better

* Prevent progressBar from failing in zeus

* Remove unnecessary stringtable key
This commit is contained in:
Ozan Eğitmen 2017-10-11 22:05:54 +03:00 committed by PabstMirror
parent b51adcec3e
commit 1b86063ade
31 changed files with 1091 additions and 7 deletions

View File

@ -1,23 +1,21 @@
/* /*
* Author: Glowbal * Author: Glowbal
* Check if unit has item * Check if unit has item. Note: case-sensitive.
* *
* Arguments: * Arguments:
* 0: Unit <OBJECT> * 0: Unit <OBJECT>
* 1: Item Classname <STRING> * 1: Item Classname <STRING>
* *
* Return Value: * Return Value:
* has Item <BOOL> * Unit has Item <BOOL>
* *
* Example: * Example:
* [[bob, "item"] call ace_common_fnc_hasItem * [bob, "item"] call ace_common_fnc_hasItem
* *
* Public: yes * Public: Yes
*
* Note: Case sensitive
*/ */
#include "script_component.hpp" #include "script_component.hpp"
params [["_unit", objNull, [objNull]], ["_item", "", [""]]]; params [["_unit", objNull, [objNull]], ["_item", "", [""]]];
_item in items _unit // return _item in items _unit

View File

@ -0,0 +1 @@
z\ace\addons\pylons

View File

@ -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";
};
};

View File

@ -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));
};
};

11
addons/pylons/README.md Normal file
View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -0,0 +1,9 @@
#include "script_component.hpp"
ADDON = false;
PREP_RECOMPILE_START;
#include "XEH_PREP.hpp"
PREP_RECOMPILE_END;
ADDON = true;

View File

@ -0,0 +1,3 @@
#include "script_component.hpp"
#include "XEH_PREP.hpp"

19
addons/pylons/config.cpp Normal file
View File

@ -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"

View File

@ -0,0 +1,25 @@
/*
* Author: 654wak654
* Checks if given unit can access the pylon configuration dialog for the given aircraft.
*
* Arguments:
* 0: Unit <OBJECT>
* 1: Aircraft <OBJECT>
*
* Return Value:
* Unit can configure the aircraft's pylons <BOOL>
*
* 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)})

View File

@ -0,0 +1,74 @@
/*
* Author: 654wak654
* Recursively shows the progress bar for each configured pylon.
*
* Arguments:
* 0: Indexes of pylons to configure <ARRAY>
* 1: Current index <NUMBER>
*
* 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);

View File

@ -0,0 +1,26 @@
/*
* Author: 654wak654
* Cleans up pylons on client disconnect.
*
* Arguments:
* 0: Player <OBJECT>
*
* 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
};

View File

@ -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);
};

View File

@ -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;

View File

@ -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];

View File

@ -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;

View File

@ -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];

View File

@ -0,0 +1,48 @@
/*
* Author: 654wak654
* Handles init and click events of turret switch buttons.
*
* Arguments:
* 0: Button <CONTROL>
* 1: Should switch icons <BOOL>
* 2: Turret path <ARRAY>
*
* 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";
};

View File

@ -0,0 +1,38 @@
/*
* Author: 654wak654
* Handles various UI changes when a combobox' selection changes.
*
* Arguments:
* 0: Combobox <CONTROL>
* 1: Selected index <NUMBER>
*
* 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);

View File

@ -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];
};

View File

@ -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 <BOOL>
*
* 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);
};

View File

@ -0,0 +1,139 @@
/*
* Author: 654wak654
* Shows the aircraft loadout dialog for given aircraft.
*
* Arguments:
* 0: Aircraft <OBJECT>
* 1: Is curator. Disables time and resource requirements. <BOOL> (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)}];

View File

@ -0,0 +1 @@
#include "\z\ace\addons\pylons\script_component.hpp"

158
addons/pylons/menu.hpp Normal file
View File

@ -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};
};
};
};

View File

@ -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

View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<Project name="ACE">
<Package name="Pylons">
<Key ID="STR_ACE_Pylons_AircraftLoadoutTitle">
<English>AIRCRAFT LOADOUT</English>
</Key>
<Key ID="STR_ACE_Pylons_LoadoutsFor">
<English>Loadouts for %1</English>
</Key>
<Key ID="STR_ACE_Pylons_ConfigurePylons">
<English>Configure Pylons</English>
</Key>
<Key ID="STR_ACE_Pylons_Category_Pylons">
<English>Pylons</English>
</Key>
<Key ID="STR_ACE_Pylons_Empty">
<English>&lt;empty&gt;</English> <!-- <empty> -->
</Key>
<Key ID="STR_ACE_Pylons_BannerText">
<English>Pylons that are colored red will have to be manually rearmed.</English>
</Key>
<Key ID="STR_ACE_Pylons_InUse">
<English>%1 is already configuring this aircraft!</English>
</Key>
<Key ID="STR_ACE_Pylons_ReplacingPylon">
<English>Replacing pylon %1 out of %2...</English>
</Key>
<Key ID="STR_ACE_Pylons_Stopped">
<English>Stopped at pylon %1!</English>
</Key>
<Key ID="STR_ACE_Pylons_Enabled">
<English>Enable Pylons Menu</English>
</Key>
<Key ID="STR_ACE_Pylons_Enabled_description">
<English>Enable pylon configuration menu for aircraft.</English>
</Key>
<Key ID="STR_ACE_Pylons_RearmNewPylons">
<English>Rearm New Pylons</English>
</Key>
<Key ID="STR_ACE_Pylons_RearmNewPylons_description">
<English>Automatically rearm new pylons from the nearest rearm vehicle.</English>
</Key>
<Key ID="STR_ACE_Pylons_TimePerPylon">
<English>Time Per Pylon</English>
</Key>
<Key ID="STR_ACE_Pylons_TimePerPylon_description">
<English>The time it takes to replace each pylon (in seconds).</English>
</Key>
<Key ID="STR_ACE_Pylons_SearchDistance">
<English>Search Distance</English>
</Key>
<Key ID="STR_ACE_Pylons_SearchDistance_description">
<English>The distance an aircraft needs to be from a rearm vehicle.</English>
</Key>
<Key ID="STR_ACE_Pylons_RequireEngineer">
<English>Require Engineer</English>
</Key>
<Key ID="STR_ACE_Pylons_RequireEngineer_description">
<English>Require an engineer.</English>
</Key>
<Key ID="STR_ACE_Pylons_RequireToolkit">
<English>Require Toolkit</English>
</Key>
<Key ID="STR_ACE_Pylons_RequireToolkit_description">
<English>Require a toolkit in inventory.</English>
</Key>
</Package>
</Project>

View File

@ -120,6 +120,13 @@ class CfgVehicles {
function = QFUNC(moduleCaptive); function = QFUNC(moduleCaptive);
icon = QPATHTOF(UI\Icon_Module_Zeus_Captive_ca.paa); 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) { class GVAR(moduleDefendArea): GVAR(moduleBase) {
curatorCanAttach = 1; curatorCanAttach = 1;
category = QGVAR(AI); category = QGVAR(AI);

View File

@ -11,6 +11,7 @@ PREP(moduleAddSpareTrack);
PREP(moduleAddSpareWheel); PREP(moduleAddSpareWheel);
PREP(moduleAddOrRemoveFRIES); PREP(moduleAddOrRemoveFRIES);
PREP(moduleCaptive); PREP(moduleCaptive);
PREP(moduleConfigurePylons);
PREP(moduleGarrison); PREP(moduleGarrison);
PREP(moduleGlobalSetSkill); PREP(moduleGlobalSetSkill);
PREP(moduleGroupSide); PREP(moduleGroupSide);

View File

@ -4,6 +4,7 @@ class CfgPatches {
class ADDON { class ADDON {
name = COMPONENT_NAME; name = COMPONENT_NAME;
units[] = { units[] = {
QGVAR(moduleConfigurePylons),
QGVAR(moduleDefendArea), QGVAR(moduleDefendArea),
QGVAR(moduleEditableObjects), QGVAR(moduleEditableObjects),
QGVAR(moduleGlobalSetSkill), QGVAR(moduleGlobalSetSkill),
@ -63,6 +64,11 @@ class CfgPatches {
QGVAR(moduleAddOrRemoveFRIES) QGVAR(moduleAddOrRemoveFRIES)
}; };
}; };
class GVAR(pylons): ADDON {
units[] = {
QGVAR(moduleConfigurePylons)
};
};
}; };
class ACE_Curator { class ACE_Curator {
@ -71,6 +77,7 @@ class ACE_Curator {
GVAR(cargo) = "ace_cargo"; GVAR(cargo) = "ace_cargo";
GVAR(cargoAndRepair)[] = {"ace_cargo", "ace_repair"}; GVAR(cargoAndRepair)[] = {"ace_cargo", "ace_repair"};
GVAR(fastroping) = "ace_fastroping"; GVAR(fastroping) = "ace_fastroping";
GVAR(pylons) = "ace_pylons";
}; };
#include "CfgFactionClasses.hpp" #include "CfgFactionClasses.hpp"

View File

@ -0,0 +1,37 @@
/*
* Author: 654wak654
* Opens the pylon configuration menu for the aircraft module is placed on.
*
* Arguments:
* 0: Module logic <OBJECT>
* 1: Synchronized units <ARRAY>
* 2: Activated <BOOL>
*
* 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);