Add cargo eden attributes (#4780)

- Add a ace_cargo_space attribute to vehicles to alter how much cargo they can carry.
- Add an ace_cargo_size attribute to objects to alter how much cargo space they consume.
- Add two public functions `fnc_setSize.sqf` and `fnc_setSpace.sqf` to update the cargo size/space respectively of any given object.
- Deprecate cargo makeLoadable module and public function.
- Added some macros to get the space/size of a config, making code more readable in places.
This commit is contained in:
SilentSpike 2017-05-31 23:54:57 +01:00 committed by GitHub
parent cbe06e5bc7
commit fea2326488
18 changed files with 295 additions and 99 deletions

37
addons/cargo/CfgEden.hpp Normal file
View File

@ -0,0 +1,37 @@
class Cfg3DEN {
class Object {
class AttributeCategories {
class ace_attributes {
class Attributes {
class GVAR(space) {
displayName = CSTRING(space_edenName);
tooltip = CSTRING(space_edenDesc);
property = QGVAR(space);
control = "Edit";
expression = QUOTE([ARR_2(_this,_value)] call DFUNC(setSpace););
defaultValue = QUOTE(GET_NUMBER(configFile >> 'CfgVehicles' >> typeOf _this >> QQGVAR(space),0));
validate = "number";
condition = "objectHasInventoryCargo";
typeName = "NUMBER";
};
class GVAR(size) {
displayName = CSTRING(size_edenName);
tooltip = CSTRING(size_edenDesc);
property = QGVAR(size);
control = "Edit";
// Expression only runs on the server, must handle actions for all machines and future JIPs (Why BI?!)
expression = QUOTE([ARR_2(_this,_value)] call DFUNC(setSize););
defaultValue = QUOTE(GET_NUMBER(configFile >> 'CfgVehicles' >> typeOf _this >> QQGVAR(size),-1));
validate = "number";
condition = "1-objectBrain";
typeName = "NUMBER";
};
};
};
};
};
};

View File

@ -24,52 +24,3 @@ class Extended_Killed_EventHandlers {
};
};
};
//Need initPost or we have problems with setVariable with 'ACE_Cargo'
class Extended_InitPost_EventHandlers {
class ThingX {
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 PlasticCase_01_base_F {
class ADDON {
init = QUOTE(_this call DFUNC(initObject); _this call DFUNC(initVehicle));
};
};
class LandVehicle {
class ADDON {
init = QUOTE(_this call DFUNC(initVehicle));
};
};
class Air {
class ADDON {
init = QUOTE(_this call DFUNC(initVehicle));
};
};
class Ship_F {
class ADDON {
init = QUOTE(_this call DFUNC(initVehicle));
};
};
class ACE_ConcertinaWireCoil {
class ADDON {
init = QUOTE(_this call DFUNC(initObject));
};
};
class Land_PortableLight_single_F {
class ADDON {
init = QUOTE(_this call DFUNC(initObject));
};
};
class StaticWeapon {
class ADDON {
init = QUOTE(_this call DFUNC(initObject));
};
};
};

View File

@ -285,7 +285,7 @@ class CfgVehicles {
GVAR(space) = 4;
GVAR(hasCargo) = 1;
};
// autonomus
class UAV_01_base_F: Helicopter_Base_F {
GVAR(space) = 0;
@ -346,7 +346,7 @@ class CfgVehicles {
GVAR(space) = 8;
GVAR(hasCargo) = 1;
};
class StaticMortar;
class Mortar_01_base_F: StaticMortar {
GVAR(size) = 2; // 1 = small, 2 = large

View File

@ -14,6 +14,8 @@ PREP(moduleMakeLoadable);
PREP(moduleSettings);
PREP(onMenuOpen);
PREP(paradropItem);
PREP(setSize);
PREP(setSpace);
PREP(startLoadIn);
PREP(startUnload);
PREP(unloadItem);

View File

@ -51,3 +51,28 @@
_item hideObjectGlobal false;
_item setPosASL (AGLtoASL _emptyPosAGL);
}] call CBA_fnc_addEventHandler;
// Private events to handle adding actions globally via public functions
[QGVAR(initObject), DFUNC(initObject)] call CBA_fnc_addEventHandler;
[QGVAR(initVehicle), DFUNC(initVehicle)] call CBA_fnc_addEventHandler;
// Add all the vehicle init EHs (require initPost for set/get variables)
["LandVehicle", "initPost", DFUNC(initVehicle), nil, nil, true] call CBA_fnc_addClassEventHandler;
["Air", "initPost", DFUNC(initVehicle), nil, nil, true] call CBA_fnc_addClassEventHandler;
["Ship_F", "initPost", DFUNC(initVehicle), nil, nil, true] call CBA_fnc_addClassEventHandler;
// Add all the object init EHs
["StaticWeapon", "initPost", DFUNC(initObject), nil, nil, true] call CBA_fnc_addClassEventHandler;
["Land_PortableLight_single_F", "initPost", DFUNC(initObject), nil, nil, true] call CBA_fnc_addClassEventHandler;
["ACE_ConcertinaWireCoil", "initPost", DFUNC(initObject), nil, nil, true] call CBA_fnc_addClassEventHandler;
// Add all the vehicle/object init EHs
["ThingX", "initPost", {
_this call DFUNC(initObject); _this call DFUNC(initVehicle);
}, nil, nil, true] call CBA_fnc_addClassEventHandler;
["Land_PaperBox_closed_F", "initPost", {
_this call DFUNC(initObject); _this call DFUNC(initVehicle);
}, nil, nil, true] call CBA_fnc_addClassEventHandler;
["PlasticCase_01_base_F", "initPost", {
_this call DFUNC(initObject); _this call DFUNC(initVehicle);
}, nil, nil, true] call CBA_fnc_addClassEventHandler;

View File

@ -15,6 +15,7 @@ class CfgPatches {
};
#include "ACE_Settings.hpp"
#include "CfgEden.hpp"
#include "CfgEventHandlers.hpp"
#include "CfgVehicles.hpp"
#include "menu.hpp"

View File

@ -16,6 +16,8 @@
*/
#include "script_component.hpp"
params ["_target", "_player"];
private _statement = {
params ["_target", "_player", "_params"];
_params params ["_vehicle"];
@ -26,10 +28,9 @@ private _actions = [];
{
private _config = configFile >> "CfgVehicles" >> typeOf _x;
if (
1 == getNumber (_config >> QGVAR(hasCargo)) &&
{_x != _target}
) then {
private _hasCargoPublic = _x getVariable [QGVAR(hasCargo), false];
private _hasCargoConfig = getNumber (_config >> QGVAR(hasCargo)) == 1;
if ((_hasCargoPublic || _hasCargoConfig) && {_x != _target}) then {
private _name = getText (_config >> "displayName");
private _ownerName = [_x, true] call EFUNC(common,getName);
if ("" != _ownerName) then {

View File

@ -18,4 +18,4 @@
params ["_object"];
// TRACE_1("params",_object);
_object getVariable [QGVAR(space), getNumber (configFile >> "CfgVehicles" >> typeOf _object >> QGVAR(space))]
(_object getVariable [QGVAR(space), getNumber (configFile >> "CfgVehicles" >> typeOf _object >> QGVAR(space))]) max 0

View File

@ -1,5 +1,5 @@
/*
* Author: Glowbal
* Author: Glowbal, SilentSpike
* Get the cargo size of an object.
*
* Arguments:
@ -17,23 +17,13 @@
params ["_item"];
scopeName "return";
private _isVirtual = (_item isEqualType "");
private _itemClass = if (_isVirtual) then {_item} else {typeOf _item};
private _config = (configFile >> "CfgVehicles" >> _itemClass >> QGVAR(size));
if (_isVirtual) then {
if (isNumber _config) then {
(getNumber _config) breakOut "return";
};
// Virtual items are much easier to deal with
if (_item isEqualType "") then {
CARGO_SIZE(_item)
} else {
if (!isNil {_item getVariable QGVAR(size)}) then {
(_item getVariable QGVAR(size)) breakOut "return";
};
if (isNumber _config) then {
(getNumber _config) breakOut "return";
if (isNil {_item getVariable QGVAR(size)}) then {
CARGO_SIZE(typeOf _item)
} else {
_item getVariable QGVAR(size)
};
};
-1

View File

@ -1,5 +1,5 @@
/*
* Author: Glowbal
* Author: Glowbal, SilentSpike
* Initializes variables for loadable objects. Called from init EH.
*
* Arguments:
@ -19,32 +19,56 @@ params ["_object"];
private _type = typeOf _object;
TRACE_2("params",_object,_type);
if ((_object getVariable [QGVAR(canLoad), getNumber (configFile >> "CfgVehicles" >> _type >> QGVAR(canLoad))]) != 1) exitWith {};
// If object had size given to it via eden/public then override config canLoad setting
private _canLoadPublic = _object getVariable [QGVAR(canLoad), false];
private _canLoadConfig = getNumber (configFile >> "CfgVehicles" >> _type >> QGVAR(canLoad)) == 1;
// do nothing if the class is already initialized
// Nothing to do here if object can't be loaded
if !(_canLoadConfig || _canLoadPublic) exitWith {};
// Servers and HCs do not require action menus (beyond this point)
if !(hasInterface) exitWith {};
// Unnecessary to add actions to an object class that's already got them
if (_type in GVAR(initializedItemClasses)) exitWith {};
GVAR(initializedItemClasses) pushBack _type;
if (_object getVariable [QGVAR(initObject),false]) exitWith {};
TRACE_1("Adding load cargo action to class", _type);
// Objects given size via eden have their actions added to the object
// So this function may run for multiple of the same class in that case
if (_canLoadConfig) then {
GVAR(initializedItemClasses) pushBack _type;
TRACE_1("Adding load cargo action to class", _type);
} else {
_object setVariable [QGVAR(initObject),true];
TRACE_1("Adding load cargo action to object", _object);
};
// Vehicles with passengers inside are prevented from being loaded in `fnc_canLoadItemIn`
private _condition = {
//IGNORE_PRIVATE_WARNING ["_target", "_player"];
GVAR(enable) &&
{(_target getVariable [QGVAR(canLoad), getNumber (configFile >> "CfgVehicles" >> (typeOf _target) >> QGVAR(canLoad))]) == 1} &&
{(_target getVariable [QGVAR(canLoad), getNumber (configFile >> "CfgVehicles" >> (typeOf _target) >> QGVAR(canLoad)) == 1])} &&
{locked _target < 2} &&
{alive _target} &&
{[_player, _target, []] call EFUNC(common,canInteractWith)} &&
{0 < {
1 == getNumber (configFile >> "CfgVehicles" >> typeOf _x >> QGVAR(hasCargo)) &&
{_x != _target}
private _type = typeOf _x;
private _hasCargoPublic = _x getVariable [QGVAR(hasCargo), false];
private _hasCargoConfig = getNumber (configFile >> "CfgVehicles" >> _type >> QGVAR(hasCargo)) == 1;
(_hasCargoPublic || _hasCargoConfig) && {_x != _target}
} count (nearestObjects [_player, CARGO_VEHICLE_CLASSES, MAX_LOAD_DISTANCE])}
};
private _statement = {
params ["_target", "_player"];
[_player, _target] call FUNC(startLoadIn);
};
private _text = localize LSTRING(loadObject);
private _icon = QPATHTOF(UI\Icon_load.paa);
private _action = [QGVAR(load), _text, _icon, _statement, _condition, {call FUNC(addCargoVehiclesActions)}] call EFUNC(interact_menu,createAction);
[_type, 0, ["ACE_MainActions"], _action] call EFUNC(interact_menu,addActionToClass);
if (_canLoadConfig) then {
[_type, 0, ["ACE_MainActions"], _action] call EFUNC(interact_menu,addActionToClass);
} else {
[_object, 0, ["ACE_MainActions"], _action] call EFUNC(interact_menu,addActionToObject);
};

View File

@ -20,8 +20,14 @@ TRACE_1("params", _vehicle);
private _type = typeOf _vehicle;
if (getNumber (configFile >> "CfgVehicles" >> _type >> QGVAR(hasCargo)) != 1) exitWith {};
// If vehicle had space given to it via eden/public then override config hasCargo setting
private _hasCargoPublic = _vehicle getVariable [QGVAR(hasCargo), false];
private _hasCargoConfig = getNumber (configFile >> "CfgVehicles" >> _type >> QGVAR(hasCargo)) == 1;
// Nothing to do here if vehicle has no cargo space
if !(_hasCargoConfig || _hasCargoPublic) exitWith {};
// Vehicle can have default ace cargo in its config
if (isServer) then {
{
if (isClass _x) then {
@ -33,18 +39,30 @@ if (isServer) then {
} count ("true" configClasses (configFile >> "CfgVehicles" >> _type >> "ACE_Cargo" >> "Cargo"));
};
// do nothing if the class is already initialized
// Servers and HCs do not require action menus (beyond this point)
if !(hasInterface) exitWith {};
// Unnecessary to add actions to a vehicle class that's already got them
if (_type in GVAR(initializedVehicleClasses)) exitWith {};
// set class as initialized
GVAR(initializedVehicleClasses) pushBack _type;
if (_vehicle getVariable [QGVAR(initVehicle),false]) exitWith {};
if (!hasInterface) exitWith {};
TRACE_1("Adding unload cargo action to class", _type);
// Vehicles given cargo via eden have their actions added to the object
// So this function may run for multiple of the same class in that case
if (_hasCargoConfig) then {
GVAR(initializedVehicleClasses) pushBack _type;
TRACE_1("Adding unload cargo action to class", _type);
} else {
_vehicle setVariable [QGVAR(initVehicle),true];
TRACE_1("Adding unload cargo action to object", _vehicle);
};
private _condition = {
//IGNORE_PRIVATE_WARNING ["_target", "_player"];
GVAR(enable) && {locked _target < 2} && {alive _target} && {[_player, _target, ["isNotSwimming"]] call EFUNC(common,canInteractWith)}
GVAR(enable) &&
{(_target getVariable [QGVAR(hasCargo), getNumber (configFile >> "CfgVehicles" >> (typeOf _target) >> QGVAR(hasCargo)) == 1])} &&
{locked _target < 2} &&
{alive _target} &&
{[_player, _target, ["isNotSwimming"]] call EFUNC(common,canInteractWith)}
};
private _statement = {
//IGNORE_PRIVATE_WARNING ["_target", "_player"];
@ -56,7 +74,11 @@ private _text = localize LSTRING(openMenu);
private _icon = "";
private _action = [QGVAR(openMenu), _text, _icon, _statement, _condition] call EFUNC(interact_menu,createAction);
[_type, 0, ["ACE_MainActions"], _action] call EFUNC(interact_menu,addActionToClass);
if (_hasCargoConfig) then {
[_type, 0, ["ACE_MainActions"], _action] call EFUNC(interact_menu,addActionToClass);
} else {
[_vehicle, 0, ["ACE_MainActions"], _action] call EFUNC(interact_menu,addActionToObject);
};
// Add the paradrop self interaction for planes and helicopters
if (_vehicle isKindOf "Air") then {
@ -78,5 +100,9 @@ if (_vehicle isKindOf "Air") then {
private _icon = "";
private _action = [QGVAR(openMenu), _text, _icon, _statement, _condition] call EFUNC(interact_menu,createAction);
[_type, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToClass); // self action on the vehicle
if (_hasCargoConfig) then {
[_type, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToClass); // self action on the vehicle
} else {
[_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject);
};
};

View File

@ -17,6 +17,13 @@
*/
#include "script_component.hpp"
// Only run this after the settings are initialized
if !(EGVAR(common,settingsInitFinished)) exitWith {
EGVAR(common,runAtSettingsInitialized) pushBack [FUNC(makeLoadable), _this];
};
ACE_DEPRECATED(QFUNC(makeLoadable),"3.12.0",QFUNC(setSize));
params [["_object", objNull, [objNull]], ["_canLoad", true, [false, 0]], ["_setSize", 1, [0]]];
TRACE_3("params",_object,_canLoad,_setSize);
@ -25,7 +32,7 @@ private _type = typeOf _object;
private _cfgCanLoad = getNumber (configFile >> "CfgVehicles" >> _type >> QGVAR(canLoad));
private _curSize = [_object] call FUNC(getSizeItem);
_canLoad = [0, 1] select _canLoad; //convert true/false to scalar
_canLoad = [0, 1] select _canLoad; // Convert true/false to scalar
if ((_canLoad == 1) && {_setSize <= 0}) exitWith {
ERROR("ace_cargo_fnc_makeLoadable (size <= 0) when making loadable");
@ -33,7 +40,7 @@ if ((_canLoad == 1) && {_setSize <= 0}) exitWith {
TRACE_2("setVar if different from config",_canLoad,_cfgCanLoad);
if (_canLoad != _cfgCanLoad) then {
_object setVariable [QGVAR(canLoad), _canLoad];
_object setVariable [QGVAR(canLoad), _canLoad == 1];
};
TRACE_2("setVar if different from config",_setSize,_curSize);

View File

@ -20,6 +20,8 @@
params ["_logic", "_objects", "_activated"];
TRACE_3("params",_logic,_objects,_activated);
ACE_DEPRECATED(QFUNC(moduleMakeLoadable),"3.12.0","Eden editor object attributes");
if ((isNull _logic) || {!_activated}) exitWith {};
if (_objects isEqualTo []) exitWith {
WARNING_1("ace_cargo_fnc_moduleMakeLoadable has no synced objects [%1]", _logic);

View File

@ -32,9 +32,9 @@ private _itemSize = [_item] call FUNC(getSizeItem);
_vehicle setVariable [QGVAR(space), (_cargoSpace + _itemSize), true];
(boundingBoxReal _vehicle) params ["_bb1", "_bb2"];
private _distBehind = ((_bb1 select 1) min (_bb2 select 1)) - 3; // 3 meters behind max bounding box
private _distBehind = ((_bb1 select 1) min (_bb2 select 1)) - 4; // 4 meters behind max bounding box
TRACE_1("",_distBehind);
private _posBehindVehicleAGL = _vehicle modelToWorld [0, _distBehind, -1];
private _posBehindVehicleAGL = _vehicle modelToWorld [0, _distBehind, -2];
private _itemObject = if (_item isEqualType objNull) then {
@ -49,7 +49,7 @@ private _itemObject = if (_item isEqualType objNull) then {
_newItem
};
_itemObject setVelocity ((velocity _vehicle) vectorAdd ((vectorNormalized (vectorDir _vehicle)) vectorMultiply 10));
_itemObject setVelocity ((velocity _vehicle) vectorAdd ((vectorNormalized (vectorDir _vehicle)) vectorMultiply -5));
// open parachute and ir light effect
[{

View File

@ -0,0 +1,56 @@
/*
* Author: SilentSpike
* Set the cargo size of any object. Has global effect.
* Adds the load action menu if necessary.
* Negative size makes unloadable.
*
* Arguments:
* 0: Object <OBJECT>
* 1: Cargo size <NUMBER>
*
* Return Value:
* None
*
* Example:
* [cursorTarget, 3] call ace_cargo_fnc_setSize
*
* Public: Yes
*/
#include "script_component.hpp"
// Only run this after the settings are initialized
if !(EGVAR(common,settingsInitFinished)) exitWith {
EGVAR(common,runAtSettingsInitialized) pushBack [FUNC(setSize), _this];
};
params [
["_object",objNull,[objNull]],
["_size",nil,[0]] // Default can't be a number since all are valid
];
TRACE_2("setSize",_object,_size);
// Nothing to do here
if (
(isNil "_size") ||
{isNull _object} ||
{_size == _object getVariable [QGVAR(size), CARGO_SIZE(typeOf _object)]}
) exitWith {};
// Apply new size globally
// Necessary to update value, even if unloadable, as API could be used again
_object setVariable [QGVAR(canLoad), _size >= 0, true];
_object setVariable [QGVAR(size), _size, true];
// If no size no need for load action
if (_size < 0) exitWith {};
// If an existing ID is present, load action has already been added globally
private _jipID = _object getVariable QGVAR(setSize_jipID);
// Actions should be added to all future JIP players too
if (isNil "_jipID") then {
_jipID = [QGVAR(initObject), [_object]] call CBA_fnc_globalEventJIP;
// Store the ID for any future calls to this function
_object setVariable [QGVAR(setSize_jipID), _jipID, true];
};

View File

@ -0,0 +1,55 @@
/*
* Author: SilentSpike
* Set the cargo space of any object. Has global effect.
* Adds the cargo action menu if necessary.
*
* Arguments:
* 0: Object <OBJECT>
* 1: Cargo space <NUMBER>
*
* Return Value:
* None
*
* Example:
* [vehicle player, 20] call ace_cargo_fnc_setSpace
*
* Public: Yes
*/
#include "script_component.hpp"
// Only run this after the settings are initialized
if !(EGVAR(common,settingsInitFinished)) exitWith {
EGVAR(common,runAtSettingsInitialized) pushBack [FUNC(setSpace), _this];
};
params [
["_vehicle",objNull,[objNull]],
["_space",nil,[0]] // Default can't be a number since all are valid
];
TRACE_2("setSpace",_vehicle,_size);
// Nothing to do here
if (
(isNil "_space") ||
{isNull _vehicle} ||
{_space == _vehicle getVariable [QGVAR(space), CARGO_SPACE(typeOf _vehicle)]}
) exitWith {};
// Apply new space globally
// Necessary to update value, even if no space, as API could be used again
_vehicle setVariable [QGVAR(hasCargo), _space > 0, true];
_vehicle setVariable [QGVAR(space), _space, true];
// If no cargo space no need for cargo menu
if (_space <= 0) exitWith {};
// If an existing ID is present, cargo menu has already been added globally
private _jipID = _vehicle getVariable QGVAR(setSpace_jipID);
// Cargo menu should be added to all future JIP players too
if (isNil "_jipID") then {
_jipID = [QGVAR(initVehicle), [_vehicle]] call CBA_fnc_globalEventJIP;
// Store the ID for any future calls to this function
_vehicle setVariable [QGVAR(setSpace_jipID), _jipID, true];
};

View File

@ -17,4 +17,11 @@
#include "\z\ace\addons\main\script_macros.hpp"
#define MAX_LOAD_DISTANCE 10
#define CARGO_VEHICLE_CLASSES ["Car", "Air", "Tank", "Ship", "Cargo_base_F", "Land_PaperBox_closed_F"]
#define GET_NUMBER(config,default) (if (isNumber (config)) then {getNumber (config)} else {default})
// Default cargo size is -1 as 0 is a valid size
#define CARGO_SIZE(classname) GET_NUMBER(configFile >> "CfgVehicles" >> (classname) >> QGVAR(size),-1)
#define CARGO_SPACE(classname) GET_NUMBER(configFile >> "CfgVehicles" >> (classname) >> QGVAR(space),0)

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project name="ACE">
<Package name="Cargo">
<Key ID="STR_ACE_Cargo_loadObject">
@ -237,6 +237,18 @@
<Japanese>オブジェクトの大きさ</Japanese>
<Korean>물체 크기</Korean>
</Key>
<Key ID="STR_ACE_Cargo_space_edenName">
<English>Cargo Space</English>
</Key>
<Key ID="STR_ACE_Cargo_space_edenDesc">
<English>The cargo space available in this vehicle/container</English>
</Key>
<Key ID="STR_ACE_Cargo_size_edenName">
<English>Cargo Size</English>
</Key>
<Key ID="STR_ACE_Cargo_size_edenDesc">
<English>The cargo space required to hold this object (-1 for unloadable)</English>
</Key>
<Key ID="STR_ACE_Cargo_paradropButton">
<English>Airdrop</English>
<German>Türlast</German>