diff --git a/addons/cargo/$PBOPREFIX$ b/addons/cargo/$PBOPREFIX$ new file mode 100644 index 0000000000..74e5e4186e --- /dev/null +++ b/addons/cargo/$PBOPREFIX$ @@ -0,0 +1 @@ +z\ace\addons\cargo \ No newline at end of file diff --git a/addons/cargo/ACE_Settings.hpp b/addons/cargo/ACE_Settings.hpp new file mode 100644 index 0000000000..300add74d2 --- /dev/null +++ b/addons/cargo/ACE_Settings.hpp @@ -0,0 +1,9 @@ +class ACE_Settings { + class GVAR(enable) { + displayName = CSTRING(ModuleSettings_enable); + description = CSTRING(ModuleSettings_enable_desc); + typeName = "BOOL"; + value = 1; + category = CSTRING(settingsCategory); + }; +}; diff --git a/addons/cargo/CfgEventHandlers.hpp b/addons/cargo/CfgEventHandlers.hpp new file mode 100644 index 0000000000..f5dd29da0e --- /dev/null +++ b/addons/cargo/CfgEventHandlers.hpp @@ -0,0 +1,80 @@ + +class Extended_PreInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_FILE(XEH_preInit)); + }; +}; + +class Extended_Killed_EventHandlers { + class All { + init = QUOTE(call FUNC(handleDestroyed)); + }; +}; + +class Extended_Init_EventHandlers { + class StaticWeapon { + class ADDON { + init = QUOTE(_this call DFUNC(initObject)); + }; + }; + + class ReammoBox_F { + class ADDON { + init = QUOTE(_this call DFUNC(initObject)); + }; + }; + + class Cargo_base_F { + class ADDON { + init = QUOTE(_this call DFUNC(initObject); _this call DFUNC(initVehicle)); + }; + }; + + class CargoNet_01_box_F { + class ADDON { + init = QUOTE(_this call DFUNC(initObject); _this call DFUNC(initVehicle)); + }; + }; + + class Land_CargoBox_V1_F { + class ADDON { + init = QUOTE(_this call DFUNC(initObject); _this call DFUNC(initVehicle)); + }; + }; + + class Land_PaperBox_closed_F { + class ADDON { + init = QUOTE(_this call DFUNC(initObject); _this call DFUNC(initVehicle)); + }; + }; + + class Car { + class ADDON { + init = QUOTE(_this call DFUNC(initVehicle)); + }; + }; + + class Tank { + class ADDON { + init = QUOTE(_this call DFUNC(initVehicle)); + }; + }; + + class Helicopter { + class ADDON { + init = QUOTE(_this call DFUNC(initVehicle)); + }; + }; + + class Plane { + class ADDON { + init = QUOTE(_this call DFUNC(initVehicle)); + }; + }; + + class Ship_F { + class ADDON { + init = QUOTE(_this call DFUNC(initVehicle)); + }; + }; +}; diff --git a/addons/cargo/CfgVehicles.hpp b/addons/cargo/CfgVehicles.hpp new file mode 100644 index 0000000000..d8df9e7da9 --- /dev/null +++ b/addons/cargo/CfgVehicles.hpp @@ -0,0 +1,301 @@ + +class CfgVehicles { + + class ACE_Module; + class ACE_moduleCargoSettings: ACE_Module { + scope = 2; + displayName = CSTRING(SettingsModule_DisplayName); + icon = QUOTE(PATHTOF(UI\Icon_Module_Cargo_ca.paa)); + category = "ACE"; + function = QUOTE(DFUNC(moduleSettings)); + functionPriority = 1; + isGlobal = 1; + isTriggerActivated = 0; + author = ECSTRING(common,ACETeam); + class Arguments { + class enable { + displayName = CSTRING(ModuleSettings_enable); + description = CSTRING(ModuleSettings_enable_desc); + typeName = "BOOL"; + defaultValue = 1; + }; + }; + class ModuleDescription { + description = CSTRING(SettingsModule_Desc); + sync[] = {}; + }; + }; + + + class LandVehicle; + class Car: LandVehicle { + GVAR(space) = 4; + GVAR(hasCargo) = 1; + class ACE_Cargo { + /* + class Cargo { + class ACE_medicalSupplyCrate { + type = "ACE_medicalSupplyCrate"; + amount = 1; + }; + };*/ + }; + }; + + class Tank: LandVehicle { + GVAR(space) = 4; + GVAR(hasCargo) = 1; + }; + class Car_F; + class Truck_F: Car_F { + GVAR(space) = 8; + GVAR(hasCargo) = 1; + }; + + class Air; + // Repair helicopters + class Helicopter: Air { + GVAR(space) = 8; + GVAR(hasCargo) = 1; + }; + + class Heli_Transport_02_base_F; + class I_Heli_Transport_02_F : Heli_Transport_02_base_F { + GVAR(space) = 20; + GVAR(hasCargo) = 1; + }; + + // Repair fixed wing aircraft + class Plane: Air { + GVAR(space) = 4; + GVAR(hasCargo) = 1; + }; + + // boats + class Ship; + class Ship_F: Ship { + GVAR(space) = 4; + GVAR(hasCargo) = 1; + }; + + // Static weapons + class StaticWeapon: LandVehicle { + GVAR(size) = 2; // 1 = small, 2 = large + GVAR(canLoad) = 1; + }; + + class StaticMortar; + class Mortar_01_base_F: StaticMortar { + GVAR(size) = 2; // 1 = small, 2 = large + GVAR(canLoad) = 1; + }; + + // Ammo boxes + class ThingX; + class ReammoBox_F: ThingX { + GVAR(size) = 2; // 1 = small, 2 = large + GVAR(canLoad) = 1; + }; + + class Scrapyard_base_F; + class Land_PaperBox_closed_F: Scrapyard_base_F { + GVAR(space) = 10; + GVAR(hasCargo) = 1; + GVAR(size) = 11; + GVAR(canLoad) = 1; + XEH_ENABLED; + class ACE_Actions { + class ACE_MainActions { + displayName = ECSTRING(interaction,MainAction); + distance = 5; + condition = QUOTE(true); + statement = ""; + icon = "\a3\ui_f\data\IGUI\Cfg\Actions\eject_ca.paa"; + selection = ""; + }; + }; + }; + + class Cargo_base_F: ThingX { + GVAR(space) = 4; + GVAR(hasCargo) = 1; + GVAR(size) = 4; + GVAR(canLoad) = 1; + class ACE_Actions { + class ACE_MainActions { + displayName = ECSTRING(interaction,MainAction); + distance = 5; + condition = QUOTE(true); + statement = ""; + icon = "\a3\ui_f\data\IGUI\Cfg\Actions\eject_ca.paa"; + selection = ""; + }; + }; + }; + class Cargo10_base_F: Cargo_base_F { + GVAR(space) = 14; + GVAR(size) = 15; + XEH_ENABLED; + }; + class Land_Cargo20_blue_F: Cargo_base_F { + GVAR(space) = 49; + GVAR(size) = 50; + XEH_ENABLED; + }; + class Land_Cargo20_brick_red_F: Cargo_base_F { + GVAR(space) = 49; + GVAR(size) = 50; + XEH_ENABLED; + }; + class Land_Cargo20_cyan_F: Cargo_base_F { + GVAR(space) = 49; + GVAR(size) = 50; + XEH_ENABLED; + }; + class Land_Cargo20_grey_F: Cargo_base_F { + GVAR(space) = 49; + GVAR(size) = 50; + XEH_ENABLED; + }; + class Land_Cargo20_light_blue_F: Cargo_base_F { + GVAR(space) = 49; + GVAR(size) = 50; + XEH_ENABLED; + }; + class Land_Cargo20_light_green_F: Cargo_base_F { + GVAR(space) = 49; + GVAR(size) = 50; + XEH_ENABLED; + }; + class Land_Cargo20_military_green_F: Cargo_base_F { + GVAR(space) = 49; + GVAR(size) = 50; + XEH_ENABLED; + }; + class Ruins_F; + class Land_Cargo20_military_ruins_F: Ruins_F { + GVAR(space) = 49; + GVAR(size) = 50; + XEH_ENABLED; + }; + class Land_Cargo20_orange_F: Cargo_base_F { + GVAR(space) = 49; + GVAR(size) = 50; + XEH_ENABLED; + }; + class Land_Cargo20_red_F: Cargo_base_F { + GVAR(space) = 49; + GVAR(size) = 50; + XEH_ENABLED; + }; + class Land_Cargo20_sand_F: Cargo_base_F { + GVAR(space) = 49; + GVAR(size) = 50; + XEH_ENABLED; + }; + class Land_Cargo20_vr_F: Cargo_base_F { + GVAR(space) = 49; + GVAR(size) = 50; + XEH_ENABLED; + }; + class Land_Cargo20_white_F: Cargo_base_F { + GVAR(space) = 49; + GVAR(size) = 50; + XEH_ENABLED; + }; + class Land_Cargo20_yellow_F: Cargo_base_F { + GVAR(space) = 49; + GVAR(size) = 50; + XEH_ENABLED; + }; + + + class Land_Cargo40_blue_F: Cargo_base_F { + GVAR(space) = 99; + GVAR(size) = 100; + XEH_ENABLED; + }; + class Land_Cargo40_brick_red_F: Cargo_base_F { + GVAR(space) = 99; + GVAR(size) = 100; + XEH_ENABLED; + }; + class Land_Cargo40_cyan_F: Cargo_base_F { + GVAR(space) = 99; + GVAR(size) = 100; + XEH_ENABLED; + }; + class Land_Cargo40_grey_F: Cargo_base_F { + GVAR(space) = 99; + GVAR(size) = 100; + XEH_ENABLED; + }; + class Land_Cargo40_light_blue_F: Cargo_base_F { + GVAR(space) = 99; + GVAR(size) = 100; + XEH_ENABLED; + }; + class Land_Cargo40_light_green_F: Cargo_base_F { + GVAR(space) = 99; + GVAR(size) = 100; + XEH_ENABLED; + }; + class Land_Cargo40_military_green_F: Cargo_base_F { + GVAR(space) = 99; + GVAR(size) = 100; + XEH_ENABLED; + }; + class Land_Cargo40_military_ruins_F: Ruins_F { + GVAR(space) = 99; + GVAR(size) = 100; + XEH_ENABLED; + }; + class Land_Cargo40_orange_F: Cargo_base_F { + GVAR(space) = 99; + GVAR(size) = 100; + XEH_ENABLED; + }; + class Land_Cargo40_red_F: Cargo_base_F { + GVAR(space) = 99; + GVAR(size) = 100; + XEH_ENABLED; + }; + class Land_Cargo40_sand_F: Cargo_base_F { + GVAR(space) = 99; + GVAR(size) = 100; + XEH_ENABLED; + }; + class Land_Cargo40_vr_F: Cargo_base_F { + GVAR(space) = 99; + GVAR(size) = 100; + XEH_ENABLED; + }; + class Land_Cargo40_white_F: Cargo_base_F { + GVAR(space) = 99; + GVAR(size) = 100; + XEH_ENABLED; + }; + class Land_Cargo40_yellow_F: Cargo_base_F { + GVAR(space) = 99; + GVAR(size) = 100; + XEH_ENABLED; + }; + // small + class Land_CargoBox_V1_F: ThingX { + GVAR(space) = 7; + GVAR(hasCargo) = 1; + GVAR(size) = 7; + XEH_ENABLED; + class ACE_Actions { + class ACE_MainActions { + displayName = ECSTRING(interaction,MainAction); + distance = 5; + condition = QUOTE(true); + statement = ""; + icon = "\a3\ui_f\data\IGUI\Cfg\Actions\eject_ca.paa"; + selection = ""; + }; + }; + }; + +}; diff --git a/addons/cargo/UI/Icon_Module_Cargo_ca.paa b/addons/cargo/UI/Icon_Module_Cargo_ca.paa new file mode 100644 index 0000000000..a292fb4227 Binary files /dev/null and b/addons/cargo/UI/Icon_Module_Cargo_ca.paa differ diff --git a/addons/cargo/UI/Icon_load.paa b/addons/cargo/UI/Icon_load.paa new file mode 100644 index 0000000000..ccd77761e4 Binary files /dev/null and b/addons/cargo/UI/Icon_load.paa differ diff --git a/addons/cargo/XEH_preInit.sqf b/addons/cargo/XEH_preInit.sqf new file mode 100644 index 0000000000..f0cf3357cd --- /dev/null +++ b/addons/cargo/XEH_preInit.sqf @@ -0,0 +1,27 @@ +#include "script_component.hpp" + +ADDON = false; + +PREP(canLoadItemIn); +PREP(canUnloadItem); +PREP(canLoad); +PREP(findNearestVehicle); +PREP(getCargoSpaceLeft); +PREP(GetSizeItem); +PREP(initObject); +PREP(initVehicle); +PREP(handleDestroyed); +PREP(moduleSettings); +PREP(loadItem); +PREP(onMenuOpen); +PREP(unloadItem); +PREP(validateCargoSpace); +PREP(startLoadIn); +PREP(startUnload); +GVAR(initializedItemClasses) = []; + +if (isServer) then { + ["cargo_hideItem", {params ["_object", "_status"]; _object hideObjectGlobal _status;}] call EFUNC(common,addEventHandler); +}; + +ADDON = true; diff --git a/addons/cargo/config.cpp b/addons/cargo/config.cpp new file mode 100644 index 0000000000..2972e8ef1b --- /dev/null +++ b/addons/cargo/config.cpp @@ -0,0 +1,18 @@ +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = {"ace_interaction"}; + author[] = {"commy2", "Glowbal"}; + authorUrl = "https://ace3mod.com/"; + VERSION_CONFIG; + }; +}; + +#include "CfgEventHandlers.hpp" +#include "CfgVehicles.hpp" +#include "menu.hpp" +#include "ACE_Settings.hpp" diff --git a/addons/cargo/functions/fnc_canLoad.sqf b/addons/cargo/functions/fnc_canLoad.sqf new file mode 100644 index 0000000000..88391e80da --- /dev/null +++ b/addons/cargo/functions/fnc_canLoad.sqf @@ -0,0 +1,31 @@ +/* + * Author: Glowbal + * Check if player can load item into the nearest vehicle + * + * Arguments: + * 0: Player + * 1: Object to load + * + * Return value: + * Can load + * + * Public: No + */ + +#include "script_component.hpp" + +params ["_player", "_object"]; + +private ["_nearestVehicle"]; +_nearestVehicle = [_player] call FUNC(findNearestVehicle); + +if (_nearestVehicle isKindOf "Cargo_Base_F" || isNull _nearestVehicle) then { + + { + if ([_object, _x] call FUNC(canLoadItemIn)) exitwith {_nearestVehicle = _x}; + }foreach (nearestObjects [_player, ["Cargo_base_F", "Land_PaperBox_closed_F"], MAX_LOAD_DISTANCE]); +}; + +if (isNull _nearestVehicle) exitwith {false}; + +[_object, _nearestVehicle] call FUNC(canLoadItemIn); diff --git a/addons/cargo/functions/fnc_canLoadItemIn.sqf b/addons/cargo/functions/fnc_canLoadItemIn.sqf new file mode 100644 index 0000000000..5d844cc91c --- /dev/null +++ b/addons/cargo/functions/fnc_canLoadItemIn.sqf @@ -0,0 +1,23 @@ +/* + * Author: Glowbal + * Check if item can be loaded into other Object + * + * Arguments: + * 0: Item Object + * 1: Holder Object (vehicle) + * + * Return value: + * Can load in + * + * Public: No + */ + +#include "script_component.hpp" + +params ["_item", "_vehicle"]; + +if (speed _vehicle > 1 || (((getPos _vehicle) select 2) > 3)) exitwith {false}; + +private "_itemSize"; +_itemSize = ([_item] call FUNC(getSizeItem)); +_itemSize > 0 && {alive _item && alive _vehicle} && {(_item distance _vehicle <= MAX_LOAD_DISTANCE)} && {_itemSize <= ([_vehicle] call FUNC(getCargoSpaceLeft))}; diff --git a/addons/cargo/functions/fnc_canUnloadItem.sqf b/addons/cargo/functions/fnc_canUnloadItem.sqf new file mode 100644 index 0000000000..74b4c1bb9e --- /dev/null +++ b/addons/cargo/functions/fnc_canUnloadItem.sqf @@ -0,0 +1,39 @@ +/* + * Author: Glowbal, ViperMaul + * Check if item can be unloaded + * + * Arguments: + * 0: loaded object + * 1: Object + * + * Return value: + * Can be unloaded + * + * Public: No + */ + +#include "script_component.hpp" + +private ["_loaded", "_validVehiclestate", "_emptyPos"]; +params ["_item", "_vehicle"]; +_loaded = _vehicle getvariable [QGVAR(loaded), []]; +if !(_item in _loaded) exitwith {false}; + +_validVehiclestate = true; +_emptyPos = []; +if (_vehicle isKindOf "Ship" ) then { + if !(speed _vehicle <1 && {(((getPosATL _vehicle) select 2) < 2)}) then {_validVehiclestate = false}; + _emptyPos = ((getPosASL _vehicle) call EFUNC(common,ASLtoPosition) findEmptyPosition [0, 15, typeOf _item]); // TODO: if spot is underwater pick another spot. +} else { + if (_vehicle isKindOf "Air" ) then { + if !(speed _vehicle <1 && {isTouchingGround _vehicle}) then {_validVehiclestate = false}; + _emptyPos = (getPosASL _vehicle) call EFUNC(common,ASLtoPosition); + _emptyPos = [(_emptyPos select 0) + random(5), (_emptyPos select 1) + random(5), _emptyPos select 2 ]; + } else { + if !(speed _vehicle <1 && {(((getPosATL _vehicle) select 2) < 2)}) then {_validVehiclestate = false}; + _emptyPos = ((getPosASL _vehicle) call EFUNC(common,ASLtoPosition) findEmptyPosition [0, 15, typeOf _item]); + }; +}; + +if (!_validVehiclestate) exitwith { false }; +(count _emptyPos != 0); diff --git a/addons/cargo/functions/fnc_findNearestVehicle.sqf b/addons/cargo/functions/fnc_findNearestVehicle.sqf new file mode 100644 index 0000000000..40f554adc1 --- /dev/null +++ b/addons/cargo/functions/fnc_findNearestVehicle.sqf @@ -0,0 +1,34 @@ +/* + * Author: Glowbal + * Get nearest vehicle, priority car, air, tank, ship + * + * Arguments: + * 0: Object + * + * Return value: + * Vehicle that is in Distance + * + * Public: No + */ + +#include "script_component.hpp" + +private ["_loadCar", "_loadHelicopter", "_loadTank", "_loadShip", "_loadContainer"]; +params ["_unit"]; + +_loadCar = nearestObject [_unit, "car"]; +if (_unit distance _loadCar <= MAX_LOAD_DISTANCE) exitwith {_loadCar}; + +_loadHelicopter = nearestObject [_unit, "air"]; +if (_unit distance _loadHelicopter <= MAX_LOAD_DISTANCE) exitwith {_loadHelicopter}; + +_loadTank = nearestObject [_unit, "tank"]; +if (_unit distance _loadTank <= MAX_LOAD_DISTANCE) exitwith {_loadTank}; + +_loadShip = nearestObject [_unit, "ship"]; +if (_unit distance _loadShip <= MAX_LOAD_DISTANCE) exitwith {_loadShip}; + +_loadContainer = nearestObject [_unit,"Cargo_base_F"]; +if (_unit distance _loadContainer <= MAX_LOAD_DISTANCE) exitwith {_loadContainer}; + +objNull; diff --git a/addons/cargo/functions/fnc_getCargoSpaceLeft.sqf b/addons/cargo/functions/fnc_getCargoSpaceLeft.sqf new file mode 100644 index 0000000000..3c50e24ad3 --- /dev/null +++ b/addons/cargo/functions/fnc_getCargoSpaceLeft.sqf @@ -0,0 +1,17 @@ +/* + * Author: Glowbal + * Get the cargo space left on object + * + * Arguments: + * 0: Object + * + * Return value: + * Cargo space left + * + * Public: No + */ + +#include "script_component.hpp" + +params ["_vehicle"]; +_vehicle getvariable [QGVAR(space), getNumber (configFile >> "CfgVehicles" >> typeof _vehicle >> QGVAR(space))]; diff --git a/addons/cargo/functions/fnc_getSizeItem.sqf b/addons/cargo/functions/fnc_getSizeItem.sqf new file mode 100644 index 0000000000..02e5313217 --- /dev/null +++ b/addons/cargo/functions/fnc_getSizeItem.sqf @@ -0,0 +1,22 @@ +/* + * Author: Glowbal + * Get the cargo size of an object + * + * Arguments: + * 0: Object + * + * Return value: + * Cargo size. (default: -1) + * + * Public: No + */ + +#include "script_component.hpp" + +private "_config"; +params ["_item"]; +_config = (configFile >> "CfgVehicles" >> typeof _item >> QGVAR(size)); +if (isNumber (_config)) exitwith { + _item getvariable [QGVAR(size), getNumber (_config)]; +}; +-1 diff --git a/addons/cargo/functions/fnc_handleDestroyed.sqf b/addons/cargo/functions/fnc_handleDestroyed.sqf new file mode 100644 index 0000000000..25e7a6a4e0 --- /dev/null +++ b/addons/cargo/functions/fnc_handleDestroyed.sqf @@ -0,0 +1,29 @@ +/* + * Author: Glowbal + * Handle object being destroyed + * + * Arguments: + * 0: Object + * + * Return value: + * None + * + * Public: No + */ + +#include "script_component.hpp" + +params ["_vehicle"]; + +private["_loaded"]; + +_loaded = _vehicle getvariable [QGVAR(loaded), []]; +if (count _loaded == 0) exitwith {}; + +{ + // TODO deleteVehicle or just delete vehicle? Do we want to be able to recover destroyed equipment? + deleteVehicle _x; + //_x setDamage 1; +} count _loaded; + +[_vehicle] call FUNC(validateCargoSpace); diff --git a/addons/cargo/functions/fnc_initObject.sqf b/addons/cargo/functions/fnc_initObject.sqf new file mode 100644 index 0000000000..c834bcf7b0 --- /dev/null +++ b/addons/cargo/functions/fnc_initObject.sqf @@ -0,0 +1,28 @@ +/* + * Author: Glowbal + * Initialize variables for loadable objects. Called from init EH. + * + * Arguments: + * 0: Any object + * + * Return value: + * None + * + * Public: No + */ + +#include "script_component.hpp" + +params ["_object"]; + +if (getNumber (configFile >> "CfgVehicles" >> typeOf _object >> QGVAR(canLoad)) != 1) exitwith {}; + +private ["_type", "_action"]; +_type = typeOf _object; + +// do nothing if the class is already initialized +if (_type in GVAR(initializedItemClasses)) exitWith {}; +GVAR(initializedItemClasses) pushBack _type; + +_action = [QGVAR(load), localize LSTRING(loadObject), QUOTE(PATHTOF(UI\Icon_load.paa)), {[_player, _target] call FUNC(startLoadIn)}, {GVAR(enable) && {[_player, _target] call FUNC(canLoad)}}] call EFUNC(interact_menu,createAction); +[_type, 0, ["ACE_MainActions"], _action] call EFUNC(interact_menu,addActionToClass); diff --git a/addons/cargo/functions/fnc_initVehicle.sqf b/addons/cargo/functions/fnc_initVehicle.sqf new file mode 100644 index 0000000000..48e83c3858 --- /dev/null +++ b/addons/cargo/functions/fnc_initVehicle.sqf @@ -0,0 +1,58 @@ +/* + * Author: Glowbal + * initalize vehicle. Adds open caro menu action if available + * + * Arguments: + * 0: vehicle + * + * Return Value: + * None + * + * Public: No + */ + +#include "script_component.hpp" + +params ["_vehicle"]; +TRACE_1("params", _vehicle); + +private ["_type", "_initializedClasses"]; +_type = typeOf _vehicle; +_initializedClasses = GETMVAR(GVAR(initializedClasses),[]); + +if (isServer) then { + { + if (isClass _x) then { + private ["_className", "_amount","_position","_object"]; + _className = getText (_x >> "type"); + _amount = getNumber (_x >> "amount"); + _position = getPos _vehicle; + _position set [1, (_position select 1) + 1]; + _position set [2, (_position select 2) + 7.5]; + for "_i" from 1 to _amount do { + _object = createVehicle [_className, _position, [], 0, "CAN_COLLIDE"]; + if !([_object, _vehicle] call FUNC(loadItem)) exitwith { + deleteVehicle _object; + }; + }; + }; + nil + } count ("true" configClasses (configFile >> "CfgVehicles" >> _type >> "ACE_Cargo" >> "Cargo")); +}; + +// do nothing if the class is already initialized +if (_type in _initializedClasses) exitWith {}; +// set class as initialized +_initializedClasses pushBack _type; +SETMVAR(GVAR(initializedClasses),_initializedClasses); + +if (getNumber (configFile >> "CfgVehicles" >> _type >> QGVAR(hasCargo)) != 1) exitwith {}; + +private ["_text", "_condition", "_statement", "_icon", "_action"]; +_condition = {GVAR(enable)}; +_text = localize LSTRING(openMenu); +_statement = {GVAR(interactionVehicle) = _target; createDialog QGVAR(menu);}; +_icon = ""; + +_action = [QGVAR(openMenu), _text, _icon, _statement, _condition] call EFUNC(interact_menu,createAction); +[_type, 0, ["ACE_MainActions"], _action] call EFUNC(interact_menu,addActionToClass); diff --git a/addons/cargo/functions/fnc_loadItem.sqf b/addons/cargo/functions/fnc_loadItem.sqf new file mode 100644 index 0000000000..0abebdd43c --- /dev/null +++ b/addons/cargo/functions/fnc_loadItem.sqf @@ -0,0 +1,34 @@ +/* + * Author: Glowbal + * Load object into vehicle + * + * Arguments: + * 0: Object + * 1: Vehicle + * + * Return value: + * None + * + * Public: No + */ + +#include "script_component.hpp" + +private ["_loaded", "_space", "_itemSize"]; +params ["_item", "_vehicle"]; + +if !([_item, _vehicle] call FUNC(canLoadItemIn)) exitwith {false}; + +_loaded = _vehicle getvariable [QGVAR(loaded), []]; +_loaded pushback _item; +_vehicle setvariable [QGVAR(loaded), _loaded, true]; + +_space = [_vehicle] call FUNC(getCargoSpaceLeft); +_itemSize = [_item] call FUNC(getSizeItem); +_vehicle setvariable [QGVAR(space), _space - _itemSize, true]; + +detach _item; +_item attachTo [_vehicle,[0,0,100]]; +["cargo_hideItem", [_item, true]] call EFUNC(common,serverEvent); + +true; diff --git a/addons/cargo/functions/fnc_moduleSettings.sqf b/addons/cargo/functions/fnc_moduleSettings.sqf new file mode 100644 index 0000000000..bb876c2840 --- /dev/null +++ b/addons/cargo/functions/fnc_moduleSettings.sqf @@ -0,0 +1,21 @@ +/* + * Author: Glowbal + * Module for adjusting the cargo settings + * + * Arguments: + * 0: The module logic + * 1: units + * 2: activated + * + * Return Value: + * None + * + * Public: No + */ + +#include "script_component.hpp" + +params ["_logic", "_units", "_activated"]; +if !(_activated) exitWith {}; + +[_logic, QGVAR(enable), "enable"] call EFUNC(common,readSettingFromModule); diff --git a/addons/cargo/functions/fnc_onMenuOpen.sqf b/addons/cargo/functions/fnc_onMenuOpen.sqf new file mode 100644 index 0000000000..8c3bbfecf2 --- /dev/null +++ b/addons/cargo/functions/fnc_onMenuOpen.sqf @@ -0,0 +1,45 @@ +/* + * Author: Glowbal + * Handle the UI data display + * + * Arguments: + * 0: display + * + * Return value: + * None + * + * Public: No + */ + +#include "script_component.hpp" + +disableSerialization; +params["_display"]; + +uiNamespace setvariable [QGVAR(menuDisplay), _display]; + +[{ + private ["_display","_loaded", "_ctrl", "_label"]; + disableSerialization; + _display = uiNamespace getvariable QGVAR(menuDisplay); + if (isnil "_display") exitwith { + [_this select 1] call CBA_fnc_removePerFrameHandler; + }; + + if (isNull GVAR(interactionVehicle) || ACE_player distance GVAR(interactionVehicle) >= 10) exitwith { + closeDialog 0; + [_this select 1] call CBA_fnc_removePerFrameHandler; + }; + + _loaded = GVAR(interactionVehicle) getvariable [QGVAR(loaded), []]; + _ctrl = _display displayCtrl 100; + _label = _display displayCtrl 2; + + lbClear _ctrl; + { + _ctrl lbAdd (getText(configfile >> "CfgVehicles" >> typeOf _x >> "displayName")); + true + } count _loaded; + + _label ctrlSetText format[localize LSTRING(labelSpace), [GVAR(interactionVehicle)] call DFUNC(getCargoSpaceLeft)]; +}, 0, []] call CBA_fnc_addPerFrameHandler; diff --git a/addons/cargo/functions/fnc_startLoadIn.sqf b/addons/cargo/functions/fnc_startLoadIn.sqf new file mode 100644 index 0000000000..0da44ba04c --- /dev/null +++ b/addons/cargo/functions/fnc_startLoadIn.sqf @@ -0,0 +1,29 @@ +/* + * Author: Glowbal + * Start load item + * + * Arguments: + * 0: Any object + * + * Return value: + * None + * + * Public: No + */ + +#include "script_component.hpp" + +params ["_player", "_object"]; + +private ["_nearestVehicle"]; +_nearestVehicle = [_player] call FUNC(findNearestVehicle); + +if (isNull _nearestVehicle || _nearestVehicle isKindOf "Cargo_Base_F") then { + + { + if ([_object, _x] call FUNC(canLoadItemIn)) exitwith {_nearestVehicle = _x}; + }foreach (nearestObjects [_player, ["Cargo_base_F", "Land_PaperBox_closed_F"], MAX_LOAD_DISTANCE]); +}; + +if (isNull _nearestVehicle) exitwith {false}; +[_object, _nearestVehicle] call FUNC(loadItem); diff --git a/addons/cargo/functions/fnc_startUnload.sqf b/addons/cargo/functions/fnc_startUnload.sqf new file mode 100644 index 0000000000..615c1cafbd --- /dev/null +++ b/addons/cargo/functions/fnc_startUnload.sqf @@ -0,0 +1,31 @@ +/* + * Author: Glowbal + * Start unload action + * + * Arguments: + * None + * + * Return value: + * None + * + * Public: No + */ + +#include "script_component.hpp" + +private ["_display", "_loaded", "_ctrl", "_selected", "_item"]; +disableSerialization; +_display = uiNamespace getvariable QGVAR(menuDisplay); +if (isnil "_display") exitwith {}; + +_loaded = GVAR(interactionVehicle) getvariable [QGVAR(loaded), []]; +if (count _loaded == 0) exitwith {}; + +_ctrl = _display displayCtrl 100; + +_selected = (lbCurSel _ctrl) max 0; + +if (count _loaded <= _selected) exitwith {}; +_item = _loaded select _selected; + +[_item, GVAR(interactionVehicle)] call FUNC(unloadItem); diff --git a/addons/cargo/functions/fnc_unloadItem.sqf b/addons/cargo/functions/fnc_unloadItem.sqf new file mode 100644 index 0000000000..0209c5256e --- /dev/null +++ b/addons/cargo/functions/fnc_unloadItem.sqf @@ -0,0 +1,62 @@ +/* + * Author: Glowbal, ViperMaul + * Unload object from vehicle + * + * Arguments: + * 0: Object + * 1: Vehicle + * + * Return value: + * None + * + * Public: No + */ + +#include "script_component.hpp" + +private ["_loaded", "_space", "_itemSize", "_emptyPos", "_validVehiclestate"]; +params ["_item", "_vehicle"]; + +if !([_item, _vehicle] call FUNC(canUnloadItem)) exitwith { + false +}; + +_validVehiclestate = true; +_emptyPos = []; +if (_vehicle isKindOf "Ship" ) then { + if !(speed _vehicle <1 && {(((getPosATL _vehicle) select 2) < 2)}) then {_validVehiclestate = false}; + TRACE_1("SHIP Ground Check", getPosATL _vehicle ); + _emptyPos = ((getPosASL _vehicle) call EFUNC(common,ASLtoPosition) findEmptyPosition [0, 15, typeOf _item]); // TODO: if spot is underwater pick another spot. +} else { + if (_vehicle isKindOf "Air" ) then { + if !(speed _vehicle <1 && {isTouchingGround _vehicle}) then {_validVehiclestate = false}; + TRACE_1("Vehicle Ground Check", isTouchingGround _vehicle); + _emptyPos = (getPosASL _vehicle) call EFUNC(common,ASLtoPosition); + _emptyPos = [(_emptyPos select 0) + random(5), (_emptyPos select 1) + random(5), _emptyPos select 2 ]; + } else { + if !(speed _vehicle <1 && {(((getPosATL _vehicle) select 2) < 2)}) then {_validVehiclestate = false}; + TRACE_1("Vehicle Ground Check", isTouchingGround _vehicle); + _emptyPos = ((getPosASL _vehicle) call EFUNC(common,ASLtoPosition) findEmptyPosition [0, 13, typeOf _item]); + }; +}; + +TRACE_1("getPosASL Vehicle Check", getPosASL _vehicle); +if (!_validVehiclestate) exitwith { false }; + +if (count _emptyPos == 0) exitwith { false }; //consider displaying text saying there are no safe places to exit the vehicle + +_loaded = _vehicle getvariable [QGVAR(loaded), []]; +_loaded = _loaded - [_item]; +_vehicle setvariable [QGVAR(loaded), _loaded, true]; + +_space = [_vehicle] call FUNC(getCargoSpaceLeft); +_itemSize = [_item] call FUNC(getSizeItem); +_vehicle setvariable [QGVAR(space), (_space + _itemSize), true]; + +detach _item; +_item setPosASL (_emptyPos call EFUNC(common,PositiontoASL)); +["cargo_hideItem", [_item, false]] call EFUNC(common,serverEvent); + +// TOOO maybe drag/carry the unloaded item? + +true; diff --git a/addons/cargo/functions/fnc_validateCargoSpace.sqf b/addons/cargo/functions/fnc_validateCargoSpace.sqf new file mode 100644 index 0000000000..6452e850bc --- /dev/null +++ b/addons/cargo/functions/fnc_validateCargoSpace.sqf @@ -0,0 +1,32 @@ +/* + * Author: Glowbal + * Validate the vehicle cargo space + * + * Arguments: + * 0: Object + * + * Return value: + * None + * + * Public: No + */ + +#include "script_component.hpp" + +private ["_loaded", "_newLoaded", "_totalSpaceOccupied"]; +params ["_vehicle"]; +_loaded = _vehicle getvariable [QGVAR(loaded), []]; +_newLoaded = []; +_totalSpaceOccupied = 0; +{ + if !(isNull _x) then { + _newLoaded pushback _x; + _totalSpaceOccupied = _totalSpaceOccupied + ([_x] call FUNC(getSizeItem)); + }; + true +} count _loaded; + +if (count _loaded != count _newLoaded) then { + _vehicle setvariable [QGVAR(loaded), _newLoaded, true]; +}; +_vehicle setvariable [QGVAR(space), getNumber (configFile >> "CfgVehicles" >> typeof _vehicle >> QGVAR(space)) - _totalSpaceOccupied, true]; diff --git a/addons/cargo/functions/script_component.hpp b/addons/cargo/functions/script_component.hpp new file mode 100644 index 0000000000..bd91738fd3 --- /dev/null +++ b/addons/cargo/functions/script_component.hpp @@ -0,0 +1 @@ +#include "\z\ace\addons\cargo\script_component.hpp" \ No newline at end of file diff --git a/addons/cargo/menu.hpp b/addons/cargo/menu.hpp new file mode 100644 index 0000000000..35976d19ad --- /dev/null +++ b/addons/cargo/menu.hpp @@ -0,0 +1,104 @@ + +#include "\z\ace\addons\common\define.hpp" + +class GVAR(menu) { + idd = 314614; + movingEnable = true; + onLoad = QUOTE([_this select 0] call FUNC(onMenuOpen)); + onUnload = QUOTE(uiNamespace setvariable [ARR_2(QUOTE(QGVAR(menuDisplay)),nil)];); + class controlsBackground { + class HeaderBackground: ACE_gui_backgroundBase{ + idc = -1; + SizeEx = "(((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 1)"; + x = "13 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX + (safezoneW - ((safezoneW / safezoneH) min 1.2))/2)"; + y = "1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + (safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))/2)"; + w = "13 * (((safezoneW / safezoneH) min 1.2) / 40)"; + h = "1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; + text = "#(argb,8,8,3)color(0,0,0,0)"; + }; + class CenterBackground: HeaderBackground { + y = "2.1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + (safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))/2)"; + h = "14 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; + text = "#(argb,8,8,3)color(0,0,0,0.8)"; + colorText[] = {0, 0, 0, "(profilenamespace getvariable ['GUI_BCG_RGB_A',0.9])"}; + colorBackground[] = {0,0,0,"(profilenamespace getvariable ['GUI_BCG_RGB_A',0.9])"}; + }; + }; + + class controls { + class HeaderName { + idc = 1; + type = CT_STATIC; + x = "13 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX + (safezoneW - ((safezoneW / safezoneH) min 1.2))/2)"; + y = "1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + (safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))/2)"; + w = "13 * (((safezoneW / safezoneH) min 1.2) / 40)"; + h = "1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; + style = ST_LEFT + ST_SHADOW; + font = "PuristaMedium"; + SizeEx = "(((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 1)"; + colorText[] = {0.95, 0.95, 0.95, 0.75}; + colorBackground[] = {"(profilenamespace getvariable ['GUI_BCG_RGB_R',0.69])","(profilenamespace getvariable ['GUI_BCG_RGB_G',0.75])","(profilenamespace getvariable ['GUI_BCG_RGB_B',0.5])", "(profilenamespace getvariable ['GUI_BCG_RGB_A',0.9])"}; + text = CSTRING(cargoMenu); + }; + class SubHeader: HeaderName { + idc = 2; + x = "13 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX + (safezoneW - ((safezoneW / safezoneH) min 1.2))/2)"; + y = "2.5 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + (safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))/2)"; + w = "13 * (((safezoneW / safezoneH) min 1.2) / 40)"; + h = "1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; + style = ST_CENTER; + colorText[] = {1, 1, 1.0, 0.9}; + colorBackground[] = {0,0,0,0}; + SizeEx = "(((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 1.2)"; + text = ""; + }; + class cargoList: ACE_gui_listBoxBase { + idc = 100; + x = "13.1 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX + (safezoneW - ((safezoneW / safezoneH) min 1.2))/2)"; + y = "4 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + (safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))/2)"; + w = "12.8 * (((safezoneW / safezoneH) min 1.2) / 40)"; + h = "10 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; + SizeEx = "(((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 0.7)"; + rowHeight = 0.03; + colorBackground[] = {0, 0, 0, 0.2}; + colorText[] = {1, 1, 1, 1.0}; + colorScrollbar[] = {0.95, 0.95, 0.95, 1}; + colorSelect[] = {1, 1, 1, 1.0}; + colorSelect2[] = {1, 1, 1, 1.0}; + colorSelectBackground[] = {0.3, 0.3, 0.3, 1.0}; + colorSelectBackground2[] = {0.3, 0.3, 0.3, 1.0}; + }; + class btnUnload: ACE_gui_buttonBase { + text = "Cancel"; + idc = 11; + x = "13.1 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX + (safezoneW - ((safezoneW / safezoneH) min 1.2))/2)"; + y = "14.1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + (safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))/2)"; + w = "5 * (((safezoneW / safezoneH) min 1.2) / 40)"; + h = "1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; + size = "(((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 1)"; + SizeEx = "(((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 0.7)"; + animTextureNormal = "#(argb,8,8,3)color(0,0,0,0.9)"; + animTextureDisabled = "#(argb,8,8,3)color(0,0,0,0.8)"; + animTextureOver = "#(argb,8,8,3)color(1,1,1,1)"; + animTextureFocused = "#(argb,8,8,3)color(1,1,1,1)"; + animTexturePressed = "#(argb,8,8,3)color(1,1,1,1)"; + animTextureDefault = "#(argb,8,8,3)color(1,1,1,1)"; + color[] = {1, 1, 1, 1}; + color2[] = {0,0,0, 1}; + colorBackgroundFocused[] = {1,1,1,1}; + colorBackground[] = {1,1,1,1}; + colorbackground2[] = {1,1,1,1}; + colorDisabled[] = {1,1,1,1}; + colorFocused[] = {0,0,0,1}; + periodFocus = 1; + periodOver = 1; + action = QUOTE(closeDialog 0); + }; + class btnCancel: btnUnload { + text = CSTRING(unloadObject); + idc = 12; + x = "20.9 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX + (safezoneW - ((safezoneW / safezoneH) min 1.2))/2)"; + action = QUOTE([] call FUNC(startUnload);); + }; + }; +}; \ No newline at end of file diff --git a/addons/cargo/script_component.hpp b/addons/cargo/script_component.hpp new file mode 100644 index 0000000000..9716d7a536 --- /dev/null +++ b/addons/cargo/script_component.hpp @@ -0,0 +1,14 @@ +#define COMPONENT cargo +#include "\z\ace\addons\main\script_mod.hpp" + +#ifdef DEBUG_ENABLED_CARGO + #define DEBUG_MODE_FULL +#endif + +#ifdef DEBUG_ENABLED_CARGO + #define DEBUG_SETTINGS DEBUG_ENABLED_CARGO +#endif + +#include "\z\ace\addons\main\script_macros.hpp" + +#define MAX_LOAD_DISTANCE 10 diff --git a/addons/cargo/stringtable.xml b/addons/cargo/stringtable.xml new file mode 100644 index 0000000000..eab51350a3 --- /dev/null +++ b/addons/cargo/stringtable.xml @@ -0,0 +1,35 @@ + + + + + Load + + + Unload + + + Cargo + + + Cargo Menu + + + Cargo space left: %1 + + + Cargo + + + Enable Cargo + + + Enable the load in cargo module + + + Cargo Settings + + + Configure the cargo module settings + + + diff --git a/extras/assets/icons/Icon_Module_png/Icon_Module_Cargo_ca.png b/extras/assets/icons/Icon_Module_png/Icon_Module_Cargo_ca.png new file mode 100644 index 0000000000..0209ed8676 Binary files /dev/null and b/extras/assets/icons/Icon_Module_png/Icon_Module_Cargo_ca.png differ