Cargo - Improve various aspects (#9617)

* Update CfgVehicles.hpp

* Cargo cleanup

* Update menu.hpp

* Updated status effect key

* Update fnc_onMenuOpen.sqf

* Update fnc_onMenuOpen.sqf

* fix comment from merge

* nil interaction GVARs on menu close

* fix carry bug

* Fix floating objects in MP

* Updated ace_cargoAdded doc

* Fix progress bar prematurely stopping

* Finer cursor object selection

---------

Co-authored-by: LinkIsGrim <salluci.lovi@gmail.com>
This commit is contained in:
johnb432 2023-11-18 00:07:28 +01:00 committed by GitHub
parent 8f3129a02e
commit d1f0dc5e83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 821 additions and 639 deletions

View File

@ -9,7 +9,7 @@ class Cfg3DEN {
property = QGVAR(customName);
control = "Edit";
expression = QUOTE(_this setVariable [ARR_3(QQGVAR(customName),_value,true)];);
expression = QUOTE(_this setVariable [ARR_3(QQGVAR(customName),_value,true)]);
defaultValue = "''";
condition = "objectHasInventoryCargo - objectVehicle";

View File

@ -1,4 +1,3 @@
class Extended_PreStart_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_SCRIPT(XEH_preStart));

View File

@ -173,7 +173,7 @@ class CfgVehicles {
};
// misc. vehicles
// Misc. vehicles
class Quadbike_01_base_F: Car_F {
GVAR(space) = 0;
GVAR(hasCargo) = 0;
@ -184,7 +184,7 @@ class CfgVehicles {
GVAR(hasCargo) = 0;
};
// helicopters
// Helicopters
class Air;
class Helicopter: Air {
GVAR(space) = 8;
@ -224,7 +224,7 @@ class CfgVehicles {
};
class Heli_Transport_04_base_F: Helicopter_Base_H {
// note the double brackets are because loadmasterTurrets is an array of arrays / turret paths
// Note the double brackets are because loadmasterTurrets is an array of arrays / turret paths
GVAR(loadmasterTurrets)[] = {{1}};
GVAR(space) = 0;
GVAR(hasCargo) = 0;
@ -363,8 +363,9 @@ class CfgVehicles {
GVAR(size) = 6;
};
// Slingload pallets
class Slingload_base_F: ReammoBox_F {};
class CargoNet_01_base_F: Slingload_base_F { //Slingload pallets
class CargoNet_01_base_F: Slingload_base_F {
GVAR(size) = 6;
};

View File

@ -5,7 +5,6 @@ PREP(canUnloadItem);
PREP(getCargoSpaceLeft);
PREP(getNameItem);
PREP(getSizeItem);
PREP(handleDeleted);
PREP(handleDestroyed);
PREP(initObject);
PREP(initVehicle);
@ -21,4 +20,3 @@ PREP(startLoadIn);
PREP(startUnload);
PREP(unloadCarryItem);
PREP(unloadItem);
PREP(validateCargoSpace);

View File

@ -1,49 +1,33 @@
#include "script_component.hpp"
["ace_addCargo", {_this call FUNC(addCargoItem)}] call CBA_fnc_addEventHandler;
[QGVAR(paradropItem), {
params ["_item", "_vehicle", ["_showHint", true]];
private _unloaded = [_item, _vehicle, _showHint] call FUNC(paradropItem);
if (_unloaded && {GVAR(openAfterUnload) in [2, 3]}) then {
GVAR(interactionVehicle) = _vehicle;
GVAR(interactionParadrop) = true;
createDialog QGVAR(menu);
};
}] call CBA_fnc_addEventHandler;
["ace_addCargo", LINKFUNC(addCargoItem)] call CBA_fnc_addEventHandler;
["ace_loadCargo", {
params ["_item", "_vehicle"];
TRACE_2("LoadCargo EH",_item,_vehicle);
private _loaded = [_item, _vehicle] call FUNC(loadItem);
private _loaded = [_item, _vehicle] call FUNC(loadItem); // returns true if successful
// Show hint as feedback
private _hint = [LSTRING(LoadingFailed), LSTRING(LoadedItem)] select _loaded;
private _hint = [LSTRING(loadingFailed), LSTRING(loadedItem)] select _loaded;
private _itemName = [_item, true] call FUNC(getNameItem);
private _vehicleName = getText (configOf _vehicle >> "displayName");
[[_hint, _itemName, _vehicleName], 3.0] call EFUNC(common,displayTextStructured);
if (_loaded) then {
// Invoke listenable event
["ace_cargoLoaded", [_item, _vehicle]] call CBA_fnc_globalEvent;
};
[[_hint, _itemName, _vehicleName], 3] call EFUNC(common,displayTextStructured);
}] call CBA_fnc_addEventHandler;
["ace_unloadCargo", {
params ["_item", "_vehicle", ["_unloader", objNull]];
TRACE_3("UnloadCargo EH",_item,_vehicle,_unloader);
private _unloaded = [_item, _vehicle, _unloader] call FUNC(unloadItem); //returns true if sucessful
private _unloaded = [_item, _vehicle, _unloader] call FUNC(unloadItem); // returns true if successful
// Show hint as feedback
private _hint = [LSTRING(UnloadingFailed), LSTRING(UnloadedItem)] select _unloaded;
private _hint = [LSTRING(unloadingFailed), LSTRING(unloadedItem)] select _unloaded;
private _itemName = [_item, true] call FUNC(getNameItem);
private _vehicleName = getText (configOf _vehicle >> "displayName");
[[_hint, _itemName, _vehicleName], 3.0] call EFUNC(common,displayTextStructured);
[[_hint, _itemName, _vehicleName], 3] call EFUNC(common,displayTextStructured);
if (_unloaded && {GVAR(openAfterUnload) in [1, 3]}) then {
GVAR(interactionVehicle) = _vehicle;
@ -58,16 +42,27 @@
_item hideObjectGlobal false;
_item setPosASL (AGLtoASL _emptyPosAGL);
[_item, "blockDamage", "ACE_cargo", false] call EFUNC(common,statusEffect_set);
[_item, "blockDamage", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
}] call CBA_fnc_addEventHandler;
[QGVAR(paradropItem), {
params ["_item", "_vehicle", ["_showHint", true]];
private _unloaded = [_item, _vehicle, _showHint] call FUNC(paradropItem);
if (_unloaded && {GVAR(openAfterUnload) in [2, 3]}) then {
GVAR(interactionVehicle) = _vehicle;
GVAR(interactionParadrop) = true;
createDialog QGVAR(menu);
};
}] 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;
[QGVAR(initObject), LINKFUNC(initObject)] call CBA_fnc_addEventHandler;
[QGVAR(initVehicle), LINKFUNC(initVehicle)] call CBA_fnc_addEventHandler;
GVAR(vehicleAction) = [
QGVAR(openMenu), localize LSTRING(openMenu), "",
QGVAR(openMenu), LLSTRING(openMenu), "",
{
//IGNORE_PRIVATE_WARNING ["_target", "_player"];
GVAR(interactionVehicle) = _target;
@ -77,17 +72,17 @@ GVAR(vehicleAction) = [
{
//IGNORE_PRIVATE_WARNING ["_target", "_player"];
GVAR(enable) &&
{(_target getVariable [QGVAR(hasCargo), getNumber (configOf _target >> QGVAR(hasCargo)) == 1])} &&
{locked _target < 2} &&
{([_player, _target] call EFUNC(interaction,getInteractionDistance)) < MAX_LOAD_DISTANCE} &&
{alive _target} &&
{locked _target < 2} &&
{(_target getVariable [QGVAR(hasCargo), getNumber (configOf _target >> QGVAR(hasCargo)) == 1])} &&
{[_player, _target, ["isNotSwimming"]] call EFUNC(common,canInteractWith)} &&
{[_player, _target] call EFUNC(interaction,canInteractWithVehicleCrew)}
{[_player, _target] call EFUNC(interaction,canInteractWithVehicleCrew)} &&
{([_player, _target] call EFUNC(interaction,getInteractionDistance)) < MAX_LOAD_DISTANCE}
}
] call EFUNC(interact_menu,createAction);
GVAR(objectActions) = [
[QGVAR(renameObject), LELSTRING(common,rename), "", //TODO: add icon, maybe a pencil couldn't find it before.
[QGVAR(renameObject), LELSTRING(common,rename), "\a3\Modules_F_Curator\Data\iconMissionName_ca.paa",
{
//IGNORE_PRIVATE_WARNING ["_target", "_player"];
GVAR(interactionVehicle) = _target;
@ -97,59 +92,67 @@ GVAR(objectActions) = [
//IGNORE_PRIVATE_WARNING ["_target", "_player"];
GVAR(enable) &&
{GVAR(enableRename)} &&
{(_target getVariable [QGVAR(canLoad), getNumber (configOf _target >> QGVAR(canLoad))]) in [true, 1]} &&
{alive _target} &&
{_target getVariable [QGVAR(canLoad), getNumber (configOf _target >> QGVAR(canLoad)) == 1]} &&
{!(_target getVariable [QGVAR(noRename), getNumber (configOf _target >> QGVAR(noRename)) == 1])} &&
{[_player, _target, ["isNotSwimming"]] call EFUNC(common,canInteractWith)} &&
{[_player, _target] call EFUNC(interaction,canInteractWithVehicleCrew)} &&
{(_target getVariable [QGVAR(noRename), getNumber (configOf _target >> QGVAR(noRename))]) in [false, 0]}
{[_player, _target] call EFUNC(interaction,canInteractWithVehicleCrew)}
}
] call EFUNC(interact_menu,createAction),
[QGVAR(load), localize LSTRING(loadObject), "a3\ui_f\data\IGUI\Cfg\Actions\loadVehicle_ca.paa",
[QGVAR(load), LLSTRING(loadObject), "a3\ui_f\data\IGUI\Cfg\Actions\loadVehicle_ca.paa",
{
params ["_target", "_player"];
//IGNORE_PRIVATE_WARNING ["_target", "_player"];
[_player, _target] call FUNC(startLoadIn);
},
{
//IGNORE_PRIVATE_WARNING ["_target", "_player"];
GVAR(enable) &&
{(_target getVariable [QGVAR(canLoad), getNumber (configOf _target >> QGVAR(canLoad))]) in [true, 1]} &&
{locked _target < 2} &&
{alive _target} &&
{locked _target < 2} &&
{_target getVariable [QGVAR(canLoad), getNumber (configOf _target >> QGVAR(canLoad)) == 1]} &&
{[_player, _target, ["isNotSwimming"]] call EFUNC(common,canInteractWith)} &&
{[_player, _target] call EFUNC(interaction,canInteractWithVehicleCrew)} &&
{((nearestObjects [_target, GVAR(cargoHolderTypes), (MAX_LOAD_DISTANCE + 10)]) findIf {
private _hasCargoConfig = 1 == getNumber (configOf _x >> QGVAR(hasCargo));
private _hasCargoPublic = _x getVariable [QGVAR(hasCargo), false];
(_hasCargoConfig || {_hasCargoPublic}) && {_x != _target} && {alive _x} && {locked _x < 2} &&
{((nearestObjects [_target, GVAR(cargoHolderTypes), MAX_LOAD_DISTANCE + 10]) findIf {
_x != _target &&
{alive _x} &&
{locked _x < 2} &&
{_x getVariable [QGVAR(hasCargo), getNumber (configOf _x >> QGVAR(hasCargo)) == 1]} &&
{([_target, _x] call EFUNC(interaction,getInteractionDistance)) < MAX_LOAD_DISTANCE}
}) > -1}
}) != -1}
},
LINKFUNC(addCargoVehiclesActions)
] call EFUNC(interact_menu,createAction)
];
// find all remaining configured classes and init them, see XEH_preStart.sqf
// Find all remaining configured classes and init them, see XEH_preStart.sqf
private _vehicleClassesAddAction = call (uiNamespace getVariable [QGVAR(initializedVehicleClasses), {[]}]);
{
[_x, 0, ["ACE_MainActions"], GVAR(vehicleAction)] call EFUNC(interact_menu,addActionToClass);
} forEach _vehicleClassesAddAction;
GVAR(initializedVehicleClasses) append _vehicleClassesAddAction;
private _objectClassesAddAction = call (uiNamespace getVariable [QGVAR(initializedItemClasses), {[]}]);
{
private _objectClass = _x;
{
[_objectClass, 0, ["ACE_MainActions"], _x] call EFUNC(interact_menu,addActionToClass);
} forEach GVAR(objectActions);
} forEach _objectClassesAddAction;
GVAR(initializedItemClasses) append _objectClassesAddAction;
private _vehicleClassesAddClassEH = call (uiNamespace getVariable [QGVAR(vehicleClasses_classEH), {[]}]);
{
[_x, "initPost", DFUNC(initVehicle), nil, nil, true] call CBA_fnc_addClassEventHandler;
} forEach _vehicleClassesAddClassEH;
private _objectClassesAddClassEH = call (uiNamespace getVariable [QGVAR(objectClasses_classEH), {[]}]);
{
[_x, "initPost", DFUNC(initObject), nil, nil, true] call CBA_fnc_addClassEventHandler;
} forEach _objectClassesAddClassEH;
@ -157,7 +160,9 @@ private _objectClassesAddClassEH = call (uiNamespace getVariable [QGVAR(objectCl
if (isServer) then {
["ace_placedInBodyBag", {
params ["_target", "_bodyBag", "_isGrave"];
if (_isGrave) exitWith {}; // assume graves aren't cargo
_bodyBag setVariable [QGVAR(customName), [_target, false, true] call EFUNC(common,getName), true];
}] call CBA_fnc_addEventHandler;
};

View File

@ -10,11 +10,11 @@ PREP_RECOMPILE_END;
GVAR(initializedItemClasses) = [];
GVAR(initializedVehicleClasses) = [];
GVAR(cargoHolderTypes) = ["Car", "Air", "Tank", "Ship", "Cargo_base_F", "Land_PaperBox_closed_F"];
GVAR(disableParadropEffectsClasstypes) = ["Car_F"];
GVAR(cargoHolderTypes) = ["Car", "Air", "Tank", "Ship", "Cargo_base_F", "Land_PaperBox_closed_F"] apply {_x call EFUNC(common,getConfigName)}; // make sure they are config case
GVAR(disableParadropEffectsClasstypes) = ["Car_F"] apply {_x call EFUNC(common,getConfigName)};
if (isServer) then {
["All", "Deleted", LINKFUNC(handleDeleted)] call CBA_fnc_addClassEventHandler;
["All", "Deleted", LINKFUNC(handleDestroyed)] call CBA_fnc_addClassEventHandler;
};
["All", "Killed", LINKFUNC(handleDestroyed)] call CBA_fnc_addClassEventHandler;

View File

@ -2,36 +2,38 @@
#include "XEH_PREP.hpp"
//See XEH_postInit.sqf
// See XEH_postInit.sqf
private _vehicleClasses_addClassEH = ["ThingX", "LandVehicle", "Air", "Ship_F"];
private _objectClasses_addClassEH = ["ThingX", "StaticWeapon"];
private _vehicleClasses_addAction = [];
private _itemClasses_addAction = [];
private _class = "";
// find all remaining configured classes and init them
// Find all remaining configured classes and init them
{
private _class = configName _x;
// init vehicle
_class = configName _x;
// Init vehicle
if (
1 == getNumber (_x >> QGVAR(hasCargo))
&& {-1 == _vehicleClasses_addClassEH findIf {_class isKindOf _x}}
getNumber (_x >> QGVAR(hasCargo)) == 1 &&
{_vehicleClasses_addClassEH findIf {_class isKindOf _x} == -1}
) then {
if (_class isKindOf "Static") then {
if (2 == getNumber (_x >> "scope")) then {
if (getNumber (_x >> "scope") == 2) then {
_vehicleClasses_addAction pushBackUnique _class;
};
} else {
_vehicleClasses_addClassEH pushBackUnique _class;
};
};
// init object
// Init object
if (
1 == getNumber (_x >> QGVAR(canLoad))
&& {-1 == _objectClasses_addClassEH findIf {_class isKindOf _x}}
getNumber (_x >> QGVAR(canLoad)) == 1 &&
{_objectClasses_addClassEH findIf {_class isKindOf _x} == -1}
) then {
if (_class isKindOf "Static") then {
if (2 == getNumber (_x >> "scope")) then {
if (getNumber (_x >> "scope") == 2) then {
_itemClasses_addAction pushBackUnique _class;
};
} else {
@ -40,7 +42,6 @@ private _itemClasses_addAction = [];
};
} forEach ("true" configClasses (configFile >> "CfgVehicles"));
uiNamespace setVariable [QGVAR(vehicleClasses_classEH), compileFinal str _vehicleClasses_addClassEH];
uiNamespace setVariable [QGVAR(objectClasses_classEH), compileFinal str _objectClasses_addClassEH];
uiNamespace setVariable [QGVAR(initializedVehicleClasses), compileFinal str _vehicleClasses_addAction];

View File

@ -4,26 +4,34 @@
* Adds a cargo item to the vehicle.
*
* Arguments:
* 0: Item Classname <STRING>
* 1: Vehicle <OBJECT>
* 0: Item to be loaded <STRING> or <OBJECT>
* 1: Holder object (vehicle) <OBJECT>
* 2: Amount <NUMBER> (default: 1)
* 3: Show Hint <BOOL> (default: false)
*
* Return Value:
* None
*
* Example:
* ["item", vehicle] call ace_cargo_fnc_addCargoItem
* ["ACE_Wheel", cursorObject] call ace_cargo_fnc_addCargoItem
*
* Public: No
*/
params ["_itemClass", "_vehicle", ["_amount", 1], ["_showHint", false, [false]]];
TRACE_3("params",_itemClass,_vehicle,_amount);
params ["_item", "_vehicle", ["_amount", 1]];
TRACE_3("params",_item,_vehicle,_amount);
for "_i" from 1 to _amount do {
[_itemClass, _vehicle] call FUNC(loadItem);
// Get config sensitive case name
if (_item isEqualType "") then {
_item = _item call EFUNC(common,getConfigName);
for "_i" from 1 to _amount do {
[_item, _vehicle] call FUNC(loadItem);
};
} else {
[_item, _vehicle] call FUNC(loadItem);
_item = typeOf _item;
};
// Invoke listenable event
["ace_cargoAdded", [_itemClass, _vehicle, _amount]] call CBA_fnc_globalEvent;
["ace_cargoAdded", [_item, _vehicle, _amount]] call CBA_fnc_globalEvent;

View File

@ -1,32 +1,34 @@
#include "..\script_component.hpp"
/*
* Author: Dystopian
* Create actions for nearest vehicles with cargo.
* Creates actions for nearest vehicles with cargo.
*
* Arguments:
* 0: Target <OBJECT>
* 0: Holder object (vehicle) <OBJECT>
*
* Return Value:
* Child actions <ARRAY>
*
* Example:
* [cursorObject] call ace_cargo_fnc_addCargoVehiclesActions
* cursorObject call ace_cargo_fnc_addCargoVehiclesActions
*
* Public: No
*/
params ["_target"];
params ["_vehicle"];
private _statement = {
params ["_target", "_player", "_vehicle"];
[_player, _target, _vehicle] call FUNC(startLoadIn);
params ["_item", "_loader", "_vehicle"];
[_loader, _item, _vehicle] call FUNC(startLoadIn);
};
private _vehicles = (nearestObjects [_target, GVAR(cargoHolderTypes), (MAX_LOAD_DISTANCE + 10)]) select {
private _hasCargoConfig = 1 == getNumber (configOf _x >> QGVAR(hasCargo));
private _hasCargoPublic = _x getVariable [QGVAR(hasCargo), false];
(_hasCargoConfig || {_hasCargoPublic}) && {_x != _target} && {alive _x} && {locked _x < 2} &&
{([_target, _x] call EFUNC(interaction,getInteractionDistance)) < MAX_LOAD_DISTANCE}
private _vehicles = (nearestObjects [_vehicle, GVAR(cargoHolderTypes), MAX_LOAD_DISTANCE + 10]) select {
_x != _vehicle &&
{alive _x} &&
{locked _x < 2} &&
{_x getVariable [QGVAR(hasCargo), getNumber (configOf _x >> QGVAR(hasCargo)) == 1]} &&
{([_vehicle, _x] call EFUNC(interaction,getInteractionDistance)) < MAX_LOAD_DISTANCE}
};
[_vehicles, _statement, _target] call EFUNC(interact_menu,createVehiclesActions)
[_vehicles, _statement, _vehicle] call EFUNC(interact_menu,createVehiclesActions)

View File

@ -1,48 +1,57 @@
#include "..\script_component.hpp"
/*
* Author: Glowbal
* Check if item can be loaded into other Object.
* Checks if the item can be loaded into another object.
*
* Arguments:
* 0: Item <OBJECT or STRING>
* 1: Holder Object (Vehicle) <OBJECT>
* 2: Ignore interaction distance and stability checks <BOOL>
* 0: Item to be loaded <STRING> or <OBJECT>
* 1: Holder object (vehicle) <OBJECT>
* 2: Ignore interaction distance and stability checks <BOOL> (default: false)
*
* Return Value:
* Can load in <BOOL>
* Can be loaded <BOOL>
*
* Example:
* [item, holder] call ace_cargo_fnc_canLoadItemIn
* ["ACE_Wheel", cursorObject] call ace_cargo_fnc_canLoadItemIn
*
* Public: No
*/
params [["_item", "", [objNull,""]], "_vehicle", ["_ignoreInteraction", false]];
params ["_item", "_vehicle", ["_ignoreInteraction", false]];
if ((!_ignoreInteraction) && {speed _vehicle > 1 || {((getPos _vehicle) select 2) > 3}}) exitWith {TRACE_1("vehicle not stable",_vehicle); false};
// Check if vehicle is stable
if (!_ignoreInteraction && {speed _vehicle > 1 || {((getPos _vehicle) select 2) > 3}}) exitWith {
TRACE_1("vehicle not stable",_vehicle);
if (_item isEqualType objNull && {{alive _x && {getText (configOf _x >> "simulation") != "UAVPilot"}} count crew _item > 0}) exitWith {
TRACE_1("item is occupied",_item);
false
false // return
};
private _itemSize = [_item] call FUNC(getSizeItem);
private _validItem = false;
if (_item isEqualType "") then {
_validItem =
isClass (configFile >> "CfgVehicles" >> _item) &&
{getNumber (configFile >> "CfgVehicles" >> _item >> QGVAR(canLoad)) == 1};
// If there is crew that isn't UAV crew, exit
if (_item isEqualType objNull && {(crew _item) findIf {alive _x && {!unitIsUAV _x}} != -1}) exitWith {
TRACE_1("item is occupied",_item);
false // return
};
private _itemSize = _item call FUNC(getSizeItem);
private _validItem = if (_item isEqualType "") then {
private _config = configFile >> "CfgVehicles" >> _item;
isClass _config &&
{getNumber (_config >> QGVAR(canLoad)) == 1}
} else {
_validItem =
(alive _item) &&
{_ignoreInteraction || {([_item, _vehicle] call EFUNC(interaction,getInteractionDistance)) < MAX_LOAD_DISTANCE}} &&
{!(_item getVariable [QEGVAR(cookoff,isCookingOff), false])} &&
{isNull(_item getVariable [QEGVAR(refuel,nozzle), objNull])} && // Objects which have a refueling nozzle connected to them cannot be loaded
{isNull(_item getVariable [QEGVAR(refuel,ownedNozzle), objNull])}; // Fuel sources which have their nozzle out cannot be loaded
alive _item &&
{_item getVariable [QGVAR(canLoad), getNumber (configOf _item >> QGVAR(canLoad)) == 1]} &&
{_ignoreInteraction || {([_item, _vehicle] call EFUNC(interaction,getInteractionDistance)) < MAX_LOAD_DISTANCE}} &&
{!(_item getVariable [QEGVAR(cookoff,isCookingOff), false])} && // do not load items that are cooking off
{isNull (_item getVariable [QEGVAR(refuel,nozzle), objNull])} && // objects which have a refueling nozzle connected to them cannot be loaded
{isNull (_item getVariable [QEGVAR(refuel,ownedNozzle), objNull])} // fuel sources which have their nozzle out cannot be loaded
};
_validItem &&
{_itemSize > 0} &&
{alive _vehicle} &&
{_itemSize <= ([_vehicle] call FUNC(getCargoSpaceLeft))} &&
{locked _vehicle < 2}
{locked _vehicle < 2} &&
{_vehicle getVariable [QGVAR(hasCargo), getNumber (configOf _vehicle >> QGVAR(hasCargo)) == 1]} &&
{_itemSize >= 0} &&
{_itemSize <= (_vehicle call FUNC(getCargoSpaceLeft)) max 0}

View File

@ -1,30 +1,44 @@
#include "..\script_component.hpp"
/*
* Author: Glowbal, ViperMaul
* Check if item can be unloaded.
* Checks if the item can be unloaded from another object.
*
* Arguments:
* 0: loaded Object <OBJECT>
* 1: Object <OBJECT>
* 2: Unloader (player) <OBJECT> (default: objNull)
* 0: Item to be unloaded <STRING> or <OBJECT>
* 1: Holder object (vehicle) <OBJECT>
* 2: Unit doing the unloading <OBJECT> (default: objNull)
* 3: Ignore interaction distance and stability checks <BOOL> (default: false)
* 4: Ignore finding a suitable position <BOOL> (default: false)
*
* Return Value:
* Can be unloaded <BOOL>
*
* Example:
* [item, holder] call ace_cargo_fnc_canUnloadItem
* ["ACE_Wheel", cursorObject] call ace_cargo_fnc_canUnloadItem
*
* Public: No
*/
params ["_item", "_vehicle", ["_unloader", objNull]];
params ["_item", "_vehicle", ["_unloader", objNull], ["_ignoreInteraction", false], ["_ignoreFindPosition", false]];
TRACE_2("params",_item,_vehicle);
private _loaded = _vehicle getVariable [QGVAR(loaded), []];
if !(_item in _loaded) exitWith {false};
// Get config sensitive case name
if (_item isEqualType "") then {
_item = _item call EFUNC(common,getConfigName);
};
private _itemClass = if (_item isEqualType "") then {_item} else {typeOf _item};
if !(_item in (_vehicle getVariable [QGVAR(loaded), []])) exitWith {false};
private _emptyPos = [_vehicle, _itemClass, _unloader] call EFUNC(common,findUnloadPosition);
private _validItem = if (_item isEqualType objNull) then {
alive _item
} else {
true
};
(count _emptyPos) == 3
_validItem &&
{alive _vehicle} &&
{locked _vehicle < 2} &&
{_vehicle getVariable [QGVAR(hasCargo), getNumber (configOf _vehicle >> QGVAR(hasCargo)) == 1]} &&
{_item call FUNC(getSizeItem) >= 0} &&
{_ignoreInteraction || {([_unloader, _vehicle] call EFUNC(interaction,getInteractionDistance)) < MAX_LOAD_DISTANCE}} &&
{_ignoreFindPosition || {([_vehicle, _item, _unloader, MAX_LOAD_DISTANCE, !_ignoreInteraction] call EFUNC(common,findUnloadPosition)) isNotEqualTo []}}

View File

@ -1,21 +1,20 @@
#include "..\script_component.hpp"
/*
* Author: Glowbal
* Get the cargo space left on object.
* Gets the object's remaining cargo space.
*
* Arguments:
* 0: Object <OBJECT>
* 0: Holder object (vehicle) <OBJECT>
*
* Return Value:
* Cargo space left <NUMBER>
*
* Example:
* [object] call ace_cargo_fnc_getCargoSpaceLeft
* cursorObject call ace_cargo_fnc_getCargoSpaceLeft
*
* Public: No
*/
params ["_object"];
// TRACE_1("params",_object);
params ["_vehicle"];
(_object getVariable [QGVAR(space), getNumber (configOf _object >> QGVAR(space))]) max 0
_vehicle getVariable [QGVAR(space), getNumber (configOf _vehicle >> QGVAR(space))]

View File

@ -4,31 +4,31 @@
* Gets the name of the item, and alternatively the custom name if requested and available.
*
* Arguments:
* 0: Target <OBJECT>
* 1: Add custom name part <BOOL> (default: false)
* 0: Item <STRING> or <OBJECT> (default: "")
* 1: Add custom name <BOOL> (default: false)
*
* Return Value:
* Item Name <STRING>
* Item name <STRING>
*
* Example:
* [crate_7] call ace_cargo_fnc_getNameItem
* cursorObject call ace_cargo_fnc_getNameItem
*
* Public: Yes
*/
params ["_object", ["_addCustomPart", false]];
params [["_item", "", [objNull, ""]], ["_addCustomName", false, [false]]];
private _displayName = if (_object isEqualType "") then {
getText (configFile >> "CfgVehicles" >> _object >> "displayName")
private _displayName = if (_item isEqualType "") then {
getText (configFile >> "CfgVehicles" >> _item >> "displayName")
} else {
getText ((configOf _object) >> "displayName")
getText (configOf _item >> "displayName")
};
if (_addCustomPart && {!(_object isEqualType "")}) then {
private _customPart = _object getVariable [QGVAR(customName), ""];
if (_addCustomName && {_item isEqualType objNull}) then {
private _customName = _item getVariable [QGVAR(customName), ""];
if (_customPart isNotEqualTo "") then {
_displayName = _displayName + " [" + _customPart + "]";
if (_customName isNotEqualTo "") then {
_displayName = _displayName + " [" + _customName + "]";
};
};

View File

@ -1,29 +1,25 @@
#include "..\script_component.hpp"
/*
* Author: Glowbal, kymckay
* Get the cargo size of an object.
* Gets the cargo size of an object.
*
* Arguments:
* 0: Item <OBJECT or STRING>
* 0: Item <STRING> or <OBJECT>
*
* Return Value:
* Cargo size <NUMBER> (default: -1)
*
* Example:
* [object] call ace_cargo_fnc_getSizeItem
* cursorObject call ace_cargo_fnc_getSizeItem
*
* Public: No
*/
params ["_item"];
// Virtual items are much easier to deal with
// Default cargo size is -1 as 0 is a valid size
if (_item isEqualType "") then {
CARGO_SIZE(_item)
GET_NUMBER(configFile >> "CfgVehicles" >> _item >> QGVAR(size),-1)
} else {
if (isNil {_item getVariable QGVAR(size)}) then {
CARGO_SIZE(typeOf _item)
} else {
_item getVariable QGVAR(size)
};
_item getVariable [QGVAR(size), GET_NUMBER(configOf _item >> QGVAR(size),-1)]
};

View File

@ -1,25 +0,0 @@
#include "..\script_component.hpp"
/*
* Author: mharis001
* Handles an object being deleted by deleting all loaded cargo.
*
* Arguments:
* 0: Object <OBJECT>
*
* Return Value:
* None
*
* Example:
* [_object] call ace_cargo_fnc_handleDeleted
*
* Public: No
*/
params ["_object"];
{
if (_x isEqualType objNull) then {
detach _x;
deleteVehicle _x;
};
} forEach (_object getVariable [QGVAR(loaded), []]);

View File

@ -1,7 +1,9 @@
#include "..\script_component.hpp"
/*
* Author: Glowbal
* Handle object being destroyed.
* Author: mharis001, Glowbal
* Handles an object being destroyed/deleted.
* If object contained loaded cargo, the cargo is deleted.
* If object was loaded cargo, it's removed from loaded cargo list.
*
* Arguments:
* 0: Object <OBJECT>
@ -10,23 +12,34 @@
* None
*
* Example:
* [_object] call ace_cargo_fnc_handleDestroyed
* cursorObject call ace_cargo_fnc_handleDestroyed
*
* Public: No
*/
params ["_vehicle"];
TRACE_1("params",_vehicle);
params ["_object"];
private _loaded = _vehicle getVariable [QGVAR(loaded), []];
if (_loaded isEqualTo []) exitWith {};
private _loaded = _object getVariable [QGVAR(loaded), []];
{
// TODO Do we want to be able to recover destroyed equipment?
if (_x isEqualType objNull) then {
detach _x;
deleteVehicle _x;
};
} forEach _loaded;
if (_loaded isNotEqualTo []) then {
// Delete all cargo
{
if (_x isEqualType objNull) then {
detach _x;
deleteVehicle _x;
};
} forEach _loaded;
[_vehicle] call FUNC(validateCargoSpace);
// In case vehicle is killed, but not deleted, reset loaded list
_object setVariable [QGVAR(loaded), [], true];
};
// Update remaining cargo space, if loaded as cargo in a vehicle
private _vehicle = attachedTo _object;
if (!isNull _vehicle && {_object in (_vehicle getVariable [QGVAR(loaded), []])}) then {
private _cargoSpace = _vehicle call FUNC(getCargoSpaceLeft);
private _itemSize = (_object call FUNC(getSizeItem)) max 0; // don't let negative size items increase space
_vehicle setVariable [QGVAR(space), _cargoSpace + _itemSize, true];
};

View File

@ -4,51 +4,57 @@
* Initializes variables for loadable objects. Called from init EH.
*
* Arguments:
* 0: Object <OBJECT>
* 0: Item <OBJECT>
*
* Return Value:
* None
*
* Example:
* [object] call ace_cargo_fnc_initObject
* cursorObject call ace_cargo_fnc_initObject
*
* Public: No
*/
params ["_object"];
private _type = typeOf _object;
private _config = configOf _object;
TRACE_2("params",_object,_type);
// Dedicated servers and HCs do not require action menus
if (!hasInterface) exitWith {};
// If object had size given to it via eden/public then override config canLoad setting
private _canLoadPublic = _object getVariable [QGVAR(canLoad), false];
if (!(_canLoadPublic isEqualType false)) then {
WARNING_4("%1[%2] - Variable %3 is %4 - Should be bool",_object,_type,QGVAR(canLoad),_canLoadPublic);
params ["_item"];
private _type = typeOf _item;
TRACE_2("params",_item,_type);
// If object had size given to it via eden/public, then override config canLoad setting
private _canLoadPublic = _item getVariable QGVAR(canLoad);
private _canLoadPublicDefined = !isNil "_canLoadPublic";
if (_canLoadPublicDefined && {!(_canLoadPublic isEqualType false)}) then {
WARNING_4("%1[%2] - Variable %3 is %4 - Should be bool",_item,_type,QGVAR(canLoad),_canLoadPublic);
};
private _canLoadConfig = getNumber (_config >> QGVAR(canLoad)) == 1;
private _canLoadConfig = getNumber (configOf _item >> QGVAR(canLoad)) == 1;
// Nothing to do here if object can't be loaded
if !(_canLoadConfig || {_canLoadPublic in [true, 1]}) exitWith {};
// Servers and HCs do not require action menus (beyond this point)
if !(hasInterface) exitWith {};
if !((_canLoadPublicDefined && {_canLoadPublic in [true, 1]}) || {!_canLoadPublicDefined && {_canLoadConfig}}) exitWith {};
// Unnecessary to add actions to an object class that's already got them
if (_type in GVAR(initializedItemClasses)) exitWith {};
if (_object getVariable [QGVAR(initObject),false]) exitWith {};
if (_item getVariable [QGVAR(initObject),false]) exitWith {};
// 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);
{
[_type, 0, ["ACE_MainActions"], _x] call EFUNC(interact_menu,addActionToClass);
} forEach GVAR(objectActions);
} else {
_object setVariable [QGVAR(initObject),true];
TRACE_1("Adding load cargo action to object", _object);
_item setVariable [QGVAR(initObject), true];
TRACE_1("Adding load cargo action to object", _item);
{
[_object, 0, ["ACE_MainActions"], _x] call EFUNC(interact_menu,addActionToObject);
[_item, 0, ["ACE_MainActions"], _x] call EFUNC(interact_menu,addActionToObject);
} forEach GVAR(objectActions);
};

View File

@ -10,7 +10,7 @@
* None
*
* Example:
* [vehicle] call ace_cargo_fnc_initVehicle
* cursorObject call ace_cargo_fnc_initVehicle
*
* Public: No
*/
@ -21,7 +21,7 @@ TRACE_1("params", _vehicle);
private _type = typeOf _vehicle;
private _config = configOf _vehicle;
// If vehicle had space given to it via eden/public then override config hasCargo setting
// 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 (_config >> QGVAR(hasCargo)) == 1;
@ -29,41 +29,53 @@ private _hasCargoConfig = getNumber (_config >> QGVAR(hasCargo)) == 1;
if !(_hasCargoConfig || _hasCargoPublic) exitWith {};
// Check if cargo is in cargo holder types (checked when trying to search for loadable objects)
private _addCargoType = true;
{
if (_type isKindOf _x) exitWith {_addCargoType = false};
} forEach GVAR(cargoHolderTypes);
private _addCargoType = GVAR(cargoHolderTypes) findIf {_type isKindOf _x} == -1;
TRACE_2("",_addCargoType,_type);
if (_addCargoType) then {
GVAR(cargoHolderTypes) pushBack _type;
};
// Vehicle can have default ace cargo in its config
// If already initialised (both actions and cargo), then skip
if (_vehicle getVariable [QGVAR(initVehicle), false]) exitWith {};
// Vehicles can have default ace cargo in their config
if (isServer) then {
_vehicle setVariable [QGVAR(initVehicle), true];
private _cargoClassname = "";
private _cargoCount = 0;
{
private _cargoClassname = getText (_x >> "type");
private _cargoCount = getNumber (_x >> "amount");
TRACE_3("adding ACE_Cargo", (configName _x), _cargoClassname, _cargoCount);
_cargoClassname = getText (_x >> "type");
_cargoCount = getNumber (_x >> "amount");
TRACE_3("adding ACE_Cargo",configName _x,_cargoClassname,_cargoCount);
["ace_addCargo", [_cargoClassname, _vehicle, _cargoCount]] call CBA_fnc_localEvent;
} forEach ("true" configClasses (_config >> QUOTE(ADDON) >> "Cargo"));
} forEach ("true" configClasses (_config >> QUOTE(ADDON) >> "cargo"));
};
// Servers and HCs do not require action menus (beyond this point)
if !(hasInterface) exitWith {};
if (!hasInterface) exitWith {};
// Unnecessary to add actions to a vehicle class that's already got them
if (_type in GVAR(initializedVehicleClasses)) exitWith {};
if (_vehicle getVariable [QGVAR(initVehicle),false]) exitWith {};
// 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);
[_type, 0, ["ACE_MainActions"], GVAR(vehicleAction)] call EFUNC(interact_menu,addActionToClass);
} else {
_vehicle setVariable [QGVAR(initVehicle),true];
_vehicle setVariable [QGVAR(initVehicle), true];
TRACE_1("Adding unload cargo action to object", _vehicle);
[_vehicle, 0, ["ACE_MainActions"], GVAR(vehicleAction)] call EFUNC(interact_menu,addActionToObject);
};
@ -71,24 +83,31 @@ if (_hasCargoConfig) then {
if (_vehicle isKindOf "Air") then {
private _condition = {
//IGNORE_PRIVATE_WARNING ["_target", "_player"];
GVAR(enable) && {[_player, _target, []] call EFUNC(common,canInteractWith)} && {
private _turretPath = _player call CBA_fnc_turretPath;
(_player == (driver _target)) || // pilot
{(getNumber (([_target, _turretPath] call CBA_fnc_getTurret) >> "isCopilot")) == 1} || // coPilot
{_turretPath in (getArray (configOf _target >> QGVAR(loadmasterTurrets)))}} // loadMaster turret from config
GVAR(enable) &&
{[_player, _target, []] call EFUNC(common,canInteractWith)} && {
private _turretPath = _target unitTurret _player;
(_player == currentPilot _target) || // Pilot/Co-pilot
{(getNumber ([_target, _turretPath] call CBA_fnc_getTurret >> "isCopilot")) == 1} || // Co-pilot
{_turretPath in (getArray (configOf _target >> QGVAR(loadmasterTurrets)))}
}
};
private _statement = {
//IGNORE_PRIVATE_WARNING ["_target", "_player"];
GVAR(interactionVehicle) = _target;
GVAR(interactionParadrop) = true;
createDialog QGVAR(menu);
};
private _text = localize LSTRING(openMenu);
private _text = LLSTRING(openMenu);
private _icon = "";
private _action = [QGVAR(openMenu), _text, _icon, _statement, _condition] call EFUNC(interact_menu,createAction);
// Self action on the vehicle
if (_hasCargoConfig) then {
[_type, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToClass); // self action on the vehicle
[_type, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToClass);
} else {
[_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject);
};

View File

@ -1,27 +1,36 @@
#include "..\script_component.hpp"
/*
* Author: Glowbal
* Load object into vehicle.
* Loads an object into a vehicle.
* Objects loaded via classname remain virtual until unloaded.
*
* Arguments:
* 0: Item <OBJECT or STRING>
* 1: Vehicle <OBJECT>
* 2: Ignore interaction distance and stability checks <BOOL>
* 0: Item to be loaded <STRING> or <OBJECT> (default: "")
* 1: Holder object (vehicle) <OBJECT> (default: objNull)
* 2: Ignore interaction distance and stability checks <BOOL> (default: false)
*
* Return Value:
* Object loaded <BOOL>
*
* Example:
* [object, vehicle] call ace_cargo_fnc_loadItem
* ["ACE_Wheel", cursorObject] call ace_cargo_fnc_loadItem
*
* Public: Yes
*/
params [["_item","",[objNull,""]], ["_vehicle",objNull,[objNull]], ["_ignoreInteraction", false]];
TRACE_2("params",_item,_vehicle);
params [["_item", "", [objNull, ""]], ["_vehicle", objNull, [objNull]], ["_ignoreInteraction", false, [false]]];
TRACE_3("params",_item,_vehicle,_ignoreInteraction);
if !([_item, _vehicle, _ignoreInteraction] call FUNC(canLoadItemIn)) exitWith {TRACE_2("cannot load",_item,_vehicle); false};
// Get config sensitive case name
if (_item isEqualType "") then {
_item = _item call EFUNC(common,getConfigName);
};
if !([_item, _vehicle, _ignoreInteraction] call FUNC(canLoadItemIn)) exitWith {
TRACE_3("cannot load",_item,_vehicle,_ignoreInteraction);
false // return
};
private _loaded = _vehicle getVariable [QGVAR(loaded), []];
_loaded pushBack _item;
@ -29,13 +38,15 @@ _vehicle setVariable [QGVAR(loaded), _loaded, true];
TRACE_1("added to loaded array",_loaded);
private _space = [_vehicle] call FUNC(getCargoSpaceLeft);
private _itemSize = [_item] call FUNC(getSizeItem);
_vehicle setVariable [QGVAR(space), _space - _itemSize, true];
// Update cargo space remaining
private _cargoSpace = _vehicle call FUNC(getCargoSpaceLeft);
private _itemSize = (_item call FUNC(getSizeItem)) max 0; // don't let negative size items increase space
_vehicle setVariable [QGVAR(space), _cargoSpace - _itemSize, true];
// Attach object 100m below vehicle
if (_item isEqualType objNull) then {
detach _item;
_item attachTo [_vehicle,[0,0,-100]];
_item attachTo [_vehicle, [0, 0, -100]];
[QEGVAR(common,hideObjectGlobal), [_item, true]] call CBA_fnc_serverEvent;
if (["ace_zeus"] call EFUNC(common,isModLoaded)) then {
@ -49,8 +60,11 @@ if (_item isEqualType objNull) then {
[QEGVAR(zeus,removeObjects), [[_item], _objectCurators]] call CBA_fnc_serverEvent;
};
// Some objects below water will take damage over time and eventualy become "water logged" and unfixable (because of negative z attach)
[_item, "blockDamage", "ACE_cargo", true] call EFUNC(common,statusEffect_set);
// Some objects below water will take damage over time, eventually becoming "water logged" and unfixable (because of negative z attach)
[_item, "blockDamage", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
};
true
// Invoke listenable event
["ace_cargoLoaded", [_item, _vehicle]] call CBA_fnc_globalEvent;
true // return

View File

@ -1,7 +1,7 @@
#include "..\script_component.hpp"
/*
* Author: Glowbal
* Handle the UI data display.
* Handles the UI data display.
*
* Arguments:
* 0: Display <DISPLAY>
@ -10,7 +10,7 @@
* None
*
* Example:
* [display] call ace_cargo_fnc_onMenuOpen
* display call ace_cargo_fnc_onMenuOpen
*
* Public: No
*/
@ -22,37 +22,70 @@ params ["_display"];
uiNamespace setVariable [QGVAR(menuDisplay), _display];
if (GVAR(interactionParadrop)) then {
(_display displayCtrl 12) ctrlSetText (localize LSTRING(paradropButton));
(_display displayCtrl 12) ctrlSetText LLSTRING(paradropButton);
};
[{
params ["_vehicle", "_pfhID"];
disableSerialization;
private _display = uiNamespace getVariable QGVAR(menuDisplay);
if (isnil "_display") exitWith {
[_this select 1] call CBA_fnc_removePerFrameHandler;
if (isNil "_display") exitWith {
GVAR(interactionVehicle) = nil;
GVAR(interactionParadrop) = nil;
_pfhID call CBA_fnc_removePerFrameHandler;
};
if (isNull GVAR(interactionVehicle) || {(([ACE_player, GVAR(interactionVehicle)] call EFUNC(interaction,getInteractionDistance)) >= MAX_LOAD_DISTANCE) && {(vehicle ACE_player) != GVAR(interactionVehicle)}}) exitWith {
// Close menu if in invalid state
if (
!alive _vehicle ||
{locked _vehicle >= 2} ||
{!(_vehicle getVariable [QGVAR(hasCargo), true])} || // if the cargo menu could be opened, the vehicle has QGVAR(hasCargo) in its config or the variable is set using FUNC(setSpace)
{(([ACE_player, _vehicle] call EFUNC(interaction,getInteractionDistance)) >= MAX_LOAD_DISTANCE) && {(vehicle ACE_player) != _vehicle}}
) exitWith {
closeDialog 0;
[_this select 1] call CBA_fnc_removePerFrameHandler;
GVAR(interactionVehicle) = nil;
GVAR(interactionParadrop) = nil;
_pfhID call CBA_fnc_removePerFrameHandler;
};
private _loaded = GVAR(interactionVehicle) getVariable [QGVAR(loaded), []];
private _ctrl = _display displayCtrl 100;
private _label = _display displayCtrl 2;
// Remove previous entries
lbClear _ctrl;
// Display item names
private _displayName = "";
private _itemSize = 0;
private _index = -1;
{
private _class = if (_x isEqualType "") then {_x} else {typeOf _x};
private _displayName = [_x, true] call FUNC(getNameItem);
if (GVAR(interactionParadrop)) then {
_ctrl lbAdd format ["%1 (%2s)", _displayName, GVAR(paradropTimeCoefficent) * ([_class] call FUNC(getSizeItem))];
_displayName = [_x, true] call FUNC(getNameItem);
_itemSize = _x call FUNC(getSizeItem);
if (_itemSize >= 0) then {
_index = if (GVAR(interactionParadrop)) then {
_ctrl lbAdd format ["%1 (%2s)", _displayName, GVAR(paradropTimeCoefficent) * _itemSize]
} else {
_ctrl lbAdd _displayName
};
_ctrl lbSetTooltip [_index, format [LLSTRING(sizeMenu), _itemSize]];
} else {
_ctrl lbAdd _displayName;
// If item has a size < 0, it means it's not loadable
_index = _ctrl lbAdd _displayName;
_ctrl lbSetTooltip [_index, LLSTRING(unloadingImpossible)];
_ctrl lbSetColor [_index, [1, 0, 0, 1]]; // set text to red
_ctrl lbSetSelectColor [_index, [1, 0, 0, 1]];
};
} forEach (_vehicle getVariable [QGVAR(loaded), []]);
true
} count _loaded;
_label ctrlSetText format[localize LSTRING(labelSpace), [GVAR(interactionVehicle)] call DFUNC(getCargoSpaceLeft)];
}, 0, []] call CBA_fnc_addPerFrameHandler;
_label ctrlSetText format [LLSTRING(labelSpace), (_vehicle call FUNC(getCargoSpaceLeft)) max 0];
}, 0, GVAR(interactionVehicle)] call CBA_fnc_addPerFrameHandler;

View File

@ -1,18 +1,18 @@
#include "..\script_component.hpp"
/*
* Author: marc_book, commy2, CAA-Picard
* Unload and paradrop object from plane or helicopter.
* Unloads and paradrops an object from a plane or helicopter.
*
* Arguments:
* 0: Object <OBJECT>
* 1: Vehicle <OBJECT>
* 0: Item <STRING> or <OBJECT>
* 1: Holder object (vehicle) <OBJECT>
* 2: Show Hint <BOOL> (default: true)
*
* Return Value:
* Object unloaded <BOOL>
*
* Example:
* [object, vehicle] call ace_cargo_fnc_paradropItem
* ["ACE_Wheel", vehicle player] call ace_cargo_fnc_paradropItem
*
* Public: No
*/
@ -20,51 +20,68 @@
params ["_item", "_vehicle", ["_showHint", true]];
TRACE_2("params",_item,_vehicle);
// Get config sensitive case name
if (_item isEqualType "") then {
_item = _item call EFUNC(common,getConfigName);
};
// Check if item is actually part of cargo
private _loaded = _vehicle getVariable [QGVAR(loaded), []];
if !(_item in _loaded) exitWith {false};
if !(_item in _loaded) exitWith {
false // return
};
// unload item from cargo
// Check if item can be unloaded
private _itemSize = _item call FUNC(getSizeItem);
if (_itemSize < 0) exitWith {
false // return
};
// Unload item from cargo
_loaded deleteAt (_loaded find _item);
_vehicle setVariable [QGVAR(loaded), _loaded, true];
private _cargoSpace = [_vehicle] call FUNC(getCargoSpaceLeft);
private _itemSize = [_item] call FUNC(getSizeItem);
_vehicle setVariable [QGVAR(space), (_cargoSpace + _itemSize), true];
// Update cargo space remaining
private _cargoSpace = _vehicle call FUNC(getCargoSpaceLeft);
_vehicle setVariable [QGVAR(space), _cargoSpace + _itemSize, true];
(boundingBoxReal _vehicle) params ["_bb1", "_bb2"];
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, -2];
TRACE_1("",_distBehind);
private _object = _item;
if (_item isEqualType objNull) then {
detach _object;
// hideObjectGlobal must be executed before setPos to ensure light objects are rendered correctly
// do both on server to ensure they are executed in the correct order
// Do both on server to ensure they are executed in the correct order
[QGVAR(serverUnload), [_object, _posBehindVehicleAGL]] call CBA_fnc_serverEvent;
} else {
_object = createVehicle [_item, _posBehindVehicleAGL, [], 0, "NONE"];
_object setPosASL (AGLtoASL _posBehindVehicleAGL);
};
[QEGVAR(common,setVelocity), [_object, ((velocity _vehicle) vectorAdd ((vectorNormalized (vectorDir _vehicle)) vectorMultiply -5))], _object] call CBA_fnc_targetEvent;
[QEGVAR(common,setVelocity), [_object, (velocity _vehicle) vectorAdd ((vectorNormalized (vectorDir _vehicle)) vectorMultiply -5)], _object] call CBA_fnc_targetEvent;
// open parachute and ir light effect
// Open parachute and IR light effect
[{
params ["_object"];
if (isNull _object || {getPos _object select 2 < 1}) exitWith {};
private _parachute = createVehicle ["B_Parachute_02_F", [0,0,0], [], 0, "CAN_COLLIDE"];
private _parachute = createVehicle ["B_Parachute_02_F", [0, 0, 0], [], 0, "CAN_COLLIDE"];
// Prevent collision damage
[QEGVAR(common,fixCollision), _parachute] call CBA_fnc_localEvent;
[QEGVAR(common,fixCollision), _object, _object] call CBA_fnc_targetEvent;
// cannot use setPos on parachutes without them closing down
_parachute attachTo [_object, [0,0,0]];
// Cannot use setPos on parachutes without them closing down
_parachute attachTo [_object, [0, 0, 0]];
detach _parachute;
private _velocity = velocity _object;
@ -76,13 +93,12 @@ if (_item isEqualType objNull) then {
_parachute setVelocity _velocity;
if ((GVAR(disableParadropEffectsClasstypes) findIf {_object isKindOf _x}) == -1) then {
private _light = "Chemlight_yellow" createVehicle [0,0,0];
_light attachTo [_object, [0,0,0]];
private _light = "Chemlight_yellow" createVehicle [0, 0, 0];
_light attachTo [_object, [0, 0, 0]];
};
}, _object, 0.7] call CBA_fnc_waitAndExecute;
}, [_object], 0.7] call CBA_fnc_waitAndExecute;
// smoke effect when crate landed
// Create smoke effect when crate landed
[{
(_this select 0) params ["_object"];
@ -90,21 +106,20 @@ if (_item isEqualType objNull) then {
[_this select 1] call CBA_fnc_removePerFrameHandler;
};
if (getPos _object select 2 < 1) then {
if ((GVAR(disableParadropEffectsClasstypes) findIf {_object isKindOf _x}) == -1) then {
private _smoke = "SmokeshellYellow" createVehicle [0,0,0];
_smoke attachTo [_object, [0,0,0]];
};
if (getPos _object select 2 < 1) exitWith {
[_this select 1] call CBA_fnc_removePerFrameHandler;
};
}, 1, [_object]] call CBA_fnc_addPerFrameHandler;
if ((GVAR(disableParadropEffectsClasstypes) findIf {_object isKindOf _x}) == -1) then {
private _smoke = "SmokeshellYellow" createVehicle [0, 0, 0];
_smoke attachTo [_object, [0, 0, 0]];
};
};
}, 1, _object] call CBA_fnc_addPerFrameHandler;
if (_showHint) then {
[
[
LSTRING(UnloadedItem),
LSTRING(unloadedItem),
[_object, true] call FUNC(getNameItem),
getText (configOf _vehicle >> "displayName")
],
@ -115,4 +130,4 @@ if (_showHint) then {
// Invoke listenable event
["ace_cargoUnloaded", [_object, _vehicle, "paradrop"]] call CBA_fnc_globalEvent;
true
true // return

View File

@ -4,23 +4,28 @@
* Removes a cargo item from the vehicle.
*
* Arguments:
* 0: Item <STRING> or <OBJECT>
* 1: Vehicle <OBJECT>
* 0: Item to be removed <STRING> or <OBJECT> (default: "")
* 1: Holder object (vehicle) <OBJECT> (default: objNull)
* 2: Amount <NUMBER> (default: 1)
*
* Return Value:
* Number of items removed <NUMBER>
*
* Example:
* ["ACE_Wheel", vehicle, 2] call ace_cargo_fnc_removeCargoItem
* ["ACE_Wheel", cursorObject, 2] call ace_cargo_fnc_removeCargoItem
* [crate_7, truck] call ace_cargo_fnc_removeCargoItem
*
* Public: Yes
*/
params ["_item", "_vehicle", ["_amount", 1]];
params [["_item", "", [objNull, ""]], ["_vehicle", objNull, [objNull]], ["_amount", 1, [0]]];
TRACE_3("params",_item,_vehicle,_amount);
// Get config sensitive case name
if (_item isEqualType "") then {
_item = _item call EFUNC(common,getConfigName);
};
private _loaded = _vehicle getVariable [QGVAR(loaded), []];
private _addedSpace = 0;
@ -29,31 +34,40 @@ private _itemsRemoved = 0;
private _continue = if (_item isEqualType objNull) then {
if !(_item in _loaded) exitWith {false};
_addedSpace = [_item] call FUNC(getSizeItem);
_addedSpace = (_item call FUNC(getSizeItem)) max 0; // don't let negative size items increase space
_loaded deleteAt (_loaded find _item);
_itemClass = typeOf _item;
// Delete item
deleteVehicle _item;
_itemsRemoved = 1;
true
} else {
{
if (_itemsRemoved == _amount) exitWith {};
if (
(_x isEqualType "" && {_x == _item}) || // Check for classname, case-insensitive
{_x isEqualType objNull && {typeOf _x isEqualTo _item}}
(_x isEqualType "" && {_x == _item}) ||
{_x isEqualType objNull && {typeOf _x == _item}}
) then {
INC(_itemsRemoved);
ADD(_addedSpace,[_x] call FUNC(getSizeItem));
_addedSpace = _addedSpace + ((_x call FUNC(getSizeItem)) max 0); // don't let negative size items increase space
// Delete item
if (_x isEqualType objNull) then {
deleteVehicle _x;
};
_loaded set [_forEachIndex, nil];
};
} forEach _loaded;
FILTER(_loaded,!isNil "_x");
true
};
@ -61,8 +75,9 @@ if (!_continue) exitWith {0};
_vehicle setVariable [QGVAR(loaded), _loaded, true];
private _space = [_vehicle] call FUNC(getCargoSpaceLeft);
_vehicle setVariable [QGVAR(space), _space + _addedSpace, true];
// Update remaining cargo space
private _cargoSpace = _vehicle call FUNC(getCargoSpaceLeft);
_vehicle setVariable [QGVAR(space), _cargoSpace + _addedSpace, true];
// Invoke listenable event
["ace_cargoRemoved", [_itemClass, _vehicle, _amount, _itemsRemoved]] call CBA_fnc_globalEvent;

View File

@ -1,7 +1,7 @@
#include "..\script_component.hpp"
/*
* Author: JasperRab
* Renames object.
* Renames an object.
*
* Arguments:
* None
@ -10,19 +10,23 @@
* None
*
* Example:
* [] call ace_cargo_fnc_renameObject
* call ace_cargo_fnc_renameObject
*
* Public: Yes
* Public: No
*/
private _display = uiNamespace getVariable QGVAR(menuDisplay);
if (isNil "_display") exitWith {};
private _ctrlEditText = ctrlText 100;
_ctrlEditText = _ctrlEditText select [0,32];
if (_ctrlEditText isEqualTo "") then { // custom name has been removed
_ctrlEditText = _ctrlEditText select [0, 32];
// Check if custom name has been removed
if (_ctrlEditText isEqualTo "") then {
[LSTRING(clearedCustomName), 3] call EFUNC(common,displayTextStructured);
} else {
[[LSTRING(renamedObject), _ctrlEditText], 3] call EFUNC(common,displayTextStructured);
};
GVAR(interactionVehicle) setVariable [QGVAR(customName), _ctrlEditText, true];

View File

@ -1,57 +1,55 @@
#include "..\script_component.hpp"
/*
* Author: kymckay
* Set the cargo size of any object. Has global effect.
* Sets the cargo size of any object. Has global effect.
* Adds the load action menu if necessary.
* Negative size makes unloadable.
* A negative size disables the object's cargo interactions.
*
* Arguments:
* 0: Object <OBJECT>
* 1: Cargo size <NUMBER>
* 0: Object <OBJECT> (default: objNull)
* 1: Cargo size <NUMBER> (default: nil)
*
* Return Value:
* None
*
* Example:
* [cursorTarget, 3] call ace_cargo_fnc_setSize
* [cursorObject, 3] call ace_cargo_fnc_setSize
*
* Public: Yes
*/
// 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
["_object", objNull, [objNull]],
["_size", nil, [0]] // default can't be a number since all are valid
];
TRACE_2("setSize",_object,_size);
private _oldSize = _object call FUNC(getSizeItem);
// Nothing to do here
if (
(isNil "_size") ||
{isNull _object} ||
{_size == _object getVariable [QGVAR(size), CARGO_SIZE(typeOf _object)]}
) exitWith {};
if (isNil "_size" || {isNull _object} || {_size == _oldSize}) exitWith {};
// Apply new size globally
// Necessary to update value, even if unloadable, as API could be used again
// Necessary to update value, even if disabled, 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 {};
// Update remaining cargo space, if loaded as cargo in a vehicle
private _vehicle = attachedTo _object;
// If an existing ID is present, load action has already been added globally
private _jipID = _object getVariable QGVAR(setSize_jipID);
if (!isNull _vehicle && {_object in (_vehicle getVariable [QGVAR(loaded), []])}) then {
private _cargoSpace = _vehicle call FUNC(getCargoSpaceLeft);
// Actions should be added to all future JIP players too
if (isNil "_jipID") then {
_jipID = [QGVAR(initObject), [_object]] call CBA_fnc_globalEventJIP;
_vehicle setVariable [QGVAR(space), _cargoSpace + (_oldSize max 0) - (_size max 0), true]; // don't let negative size items increase space
};
// Actions should be added for all future JIP players too, regardless of size
private _jipID = format [QGVAR(sizeJipID_%1), hashValue _object];
[QGVAR(initObject), _object, _jipID] call CBA_fnc_globalEventJIP;
// Remove from JIP queue if object is deleted
if !(_object getVariable [QGVAR(setSizeRemoveJip), false]) then {
[_jipID, _object] call CBA_fnc_removeGlobalEventJIP;
// Store the ID for any future calls to this function
_object setVariable [QGVAR(setSize_jipID), _jipID, true];
_object setVariable [QGVAR(setSizeRemoveJip), true, true];
};

View File

@ -1,12 +1,12 @@
#include "..\script_component.hpp"
/*
* Author: kymckay
* Set the cargo space of any object. Has global effect.
* Sets the cargo space of any object. Has global effect.
* Adds the cargo action menu if necessary.
*
* Arguments:
* 0: Object <OBJECT>
* 1: Cargo space <NUMBER>
* 0: Vehicle <OBJECT> (default: objNull)
* 1: Cargo space <NUMBER> (default: nil)
*
* Return Value:
* None
@ -17,49 +17,38 @@
* Public: Yes
*/
// 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
["_vehicle", objNull, [objNull]],
["_space", nil, [0]] // default can't be a number since all are valid
];
TRACE_2("setSpace",_vehicle,_size);
TRACE_2("setSpace",_vehicle,_space);
// Nothing to do here
if (
(isNil "_space") ||
{isNull _vehicle}
) exitWith {};
if (isNil "_space" || {isNull _vehicle}) exitWith {};
// Account for cargo already in the vehicle
private _loaded = _vehicle getVariable [QGVAR(loaded), []];
private _newSpace = _space;
private _cargoSpace = _space;
{
_newSpace = _newSpace - ([_x] call FUNC(getSizeItem));
_cargoSpace = _cargoSpace - ((_x call FUNC(getSizeItem)) max 0);
} forEach _loaded;
// If the new value is the same as the old, do nothing
if (_newSpace == (_vehicle getVariable [QGVAR(space), CARGO_SPACE(typeOf _vehicle)])) exitwith {};
if (_cargoSpace == (_vehicle call FUNC(getCargoSpaceLeft))) exitwith {};
// Apply new space globally
_vehicle setVariable [QGVAR(space), _newSpace, true];
// 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), _cargoSpace, true];
// If no cargo space no need for cargo menu
if (_space <= 0) exitWith {};
// Space should be added for all future JIP players too, regardless of space
private _jipID = format [QGVAR(spaceJipID_%1), hashValue _vehicle];
[QGVAR(initVehicle), _vehicle, _jipID] call CBA_fnc_globalEventJIP;
// 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;
// Remove from JIP queue if vehicle is deleted
if !(_vehicle getVariable [QGVAR(setSpaceRemoveJip), false]) then {
[_jipID, _vehicle] call CBA_fnc_removeGlobalEventJIP;
// Store the ID for any future calls to this function
_vehicle setVariable [QGVAR(setSpace_jipID), _jipID, true];
_vehicle setVariable [QGVAR(setSpaceRemoveJip), true, true];
};

View File

@ -1,67 +1,103 @@
#include "..\script_component.hpp"
/*
* Author: Glowbal
* Start load item.
* Starts loading item.
*
* Arguments:
* 0: Player <OBJECT>
* 1: Object <OBJECT>
* 2: Vehicle <OBJECT> (Optional)
* 0: Unit doing the loading <OBJECT>
* 1: Item to be loaded <OBJECT>
* 2: Holder object (vehicle) <OBJECT> (default: objNull)
*
* Return Value:
* Load ProgressBar Started <BOOL>
*
* Example:
* [player, cursorTarget] call ace_cargo_fnc_startLoadIn
* [player, cursorObject] call ace_cargo_fnc_startLoadIn
*
* Public: No
*/
params ["_player", "_object", ["_cargoVehicle", objNull]];
TRACE_3("params",_player,_object,_cargoVehicle);
params ["_loader", "_item", ["_vehicle", objNull]];
TRACE_3("params",_loader,_item,_vehicle);
private _vehicle = _cargoVehicle;
if (isNull _vehicle) then {
{
if ([_object, _x] call FUNC(canLoadItemIn)) exitWith {_vehicle = _x};
} forEach (nearestObjects [_player, GVAR(cargoHolderTypes), (MAX_LOAD_DISTANCE + 10)]);
if ([_item, _x] call FUNC(canLoadItemIn)) exitWith {
_vehicle = _x;
};
} forEach (nearestObjects [_loader, GVAR(cargoHolderTypes), MAX_LOAD_DISTANCE + 10]);
};
if (isNull _vehicle) exitWith {
TRACE_3("Could not find vehicle",_player,_object,_vehicle);
false
TRACE_3("Could not find vehicle",_loader,_item,_vehicle);
false // return
};
private _return = false;
// Start progress bar
if ([_object, _vehicle] call FUNC(canLoadItemIn)) then {
[_player, _object, true] call EFUNC(common,claim);
private _size = [_object] call FUNC(getSizeItem);
if ([_item, _vehicle] call FUNC(canLoadItemIn)) then {
private _duration = GVAR(loadTimeCoefficient) * (_item call FUNC(getSizeItem));
// If load time is 0, don't show a progress bar
if (_duration <= 0) exitWith {
["ace_loadCargo", [_item, _vehicle]] call CBA_fnc_localEvent;
true // return
};
// Claim so nobody else can interact with it
[_loader, _item, true] call EFUNC(common,claim);
[
GVAR(loadTimeCoefficient) * _size,
[_object, _vehicle],
_duration,
[_item, _vehicle],
{
TRACE_1("load finish",_this);
[objNull, _this select 0 select 0, true] call EFUNC(common,claim);
["ace_loadCargo", _this select 0] call CBA_fnc_localEvent;
},
{
TRACE_1("load fail",_this);
[objNull, _this select 0 select 0, true] call EFUNC(common,claim);
(_this select 0) params ["_item", "_vehicle"];
[objNull, _item, true] call EFUNC(common,claim);
// Fix cancelling loading a carried item
if (!isNull attachedTo _item) then {
detach _item;
// Prevent coliisions between item and vehicle
[QEGVAR(common,fixCollision), _vehicle, _vehicle] call CBA_fnc_targetEvent;
[QEGVAR(common,fixCollision), _item, _item] call CBA_fnc_targetEvent;
[QEGVAR(common,fixPosition), _item, _item] call CBA_fnc_targetEvent;
[QEGVAR(common,fixFloating), _item, _item] call CBA_fnc_targetEvent;
};
},
localize LSTRING(LoadingItem),
LLSTRING(loadingItem),
{
(_this select 0) params ["_item", "_target"];
(alive _target) && {locked _target < 2} && {alive _item}
&& {([_item, _target] call EFUNC(interaction,getInteractionDistance)) < MAX_LOAD_DISTANCE}
(_this select 0) call FUNC(canLoadItemIn)
},
["isNotSwimming"]
] call EFUNC(common,progressBar);
_return = true;
} else {
private _displayName = [_object, true] call FUNC(getNameItem);
[[LSTRING(LoadingFailed), _displayName], 3] call EFUNC(common,displayTextStructured);
};
_return
true // return
} else {
[[LSTRING(loadingFailed), [_item, true] call FUNC(getNameItem)], 3] call EFUNC(common,displayTextStructured);
// Fix cancelling loading a carried item
if (!isNull attachedTo _item) then {
detach _item;
// Prevent coliisions between item and vehicle
[QEGVAR(common,fixCollision), _vehicle, _vehicle] call CBA_fnc_targetEvent;
[QEGVAR(common,fixCollision), _item, _item] call CBA_fnc_targetEvent;
[QEGVAR(common,fixPosition), _item, _item] call CBA_fnc_targetEvent;
[QEGVAR(common,fixFloating), _item, _item] call CBA_fnc_targetEvent;
};
false // return
};

View File

@ -1,16 +1,16 @@
#include "..\script_component.hpp"
/*
* Author: Glowbal
* Start unload action.
* Starts unloading item selected in the cargo menu.
*
* Arguments:
* None
* 0: Unit doing the unloading <OBJECT>
*
* Return Value:
* None
*
* Example:
* [] call ace_cargo_fnc_startUnload
* player call ace_cargo_fnc_startUnload
*
* Public: No
*/
@ -18,76 +18,92 @@
disableSerialization;
private _display = uiNamespace getVariable QGVAR(menuDisplay);
if (isNil "_display") exitWith {};
private _loaded = GVAR(interactionVehicle) getVariable [QGVAR(loaded), []];
if (_loaded isEqualTo []) exitWith {};
private _ctrl = _display displayCtrl 100;
// This can be an object or a classname string
private _item = _loaded param [lbCurSel (_display displayCtrl 100), nil];
private _selected = (lbCurSel _ctrl) max 0;
if (isNil "_item") exitWith {};
if (count _loaded <= _selected) exitWith {};
private _item = _loaded select _selected; // This can be an object or a classname string
params ["_unit"];
if (GVAR(interactionParadrop)) exitWith {
// If drop time is 0 don't show a progress bar
if (GVAR(paradropTimeCoefficent) == 0) exitWith {
// Close the cargo menu
closeDialog 0;
private _duration = GVAR(paradropTimeCoefficent) * (_item call FUNC(getSizeItem));
// If drop time is 0, don't show a progress bar
if (_duration <= 0) exitWith {
[QGVAR(paradropItem), [_item, GVAR(interactionVehicle)]] call CBA_fnc_localEvent;
};
// Start progress bar - paradrop
private _size = [_item] call FUNC(getSizeItem);
[
GVAR(paradropTimeCoefficent) * _size,
[_item, GVAR(interactionVehicle), ACE_player],
// Delay execution by a frame, to avoid progress bar stopping prematurely because of the cargo menu still being open
[EFUNC(common,progressBar), [
_duration,
[_item, GVAR(interactionVehicle)],
{
(_this select 0) params ["_item", "_target", "_player"];
[QGVAR(paradropItem), [_item, _target]] call CBA_fnc_localEvent;
[QGVAR(paradropItem), _this select 0] call CBA_fnc_localEvent;
},
{
params ["_args", "", "", "_errorCode"]; // show warning if we failed because of flight conditions
if (_errorCode == 3) then {
_args params ["_item", "_target", "_player"];
[localize LSTRING(unlevelFlightWarning)] call EFUNC(common,displayTextStructured);
params ["", "", "", "_errorCode"];
if (_errorCode == 3) then { // show warning if we failed because of flight conditions
[LSTRING(unlevelFlightWarning)] call EFUNC(common,displayTextStructured);
};
},
localize LSTRING(UnloadingItem),
LLSTRING(unloadingItem),
{
(_this select 0) params ["_item", "_target", "_player"];
(_this select 0) params ["", "_target"];
if ((acos ((vectorUp _target) select 2)) > 30) exitWith {false}; // check flight level
if (((getPos _target) select 2) < 25) exitWith {false}; // check height
if ((speed _target) < -5) exitWith {false}; // check reverse
true
},
["isNotSwimming", "isNotInside"],
false
] call EFUNC(common,progressBar);
]] call CBA_fnc_execNextFrame;
};
// Start progress bar - normal ground unload
if ([_item, GVAR(interactionVehicle), ACE_player] call FUNC(canUnloadItem)) then {
private _size = [_item] call FUNC(getSizeItem);
if ([_item, GVAR(interactionVehicle), _unit] call FUNC(canUnloadItem)) then {
// Close the cargo menu
closeDialog 0;
private _duration = GVAR(loadTimeCoefficient) * (_item call FUNC(getSizeItem));
// If unload time is 0, don't show a progress bar
if (_duration <= 0) exitWith {
["ace_unloadCargo", [_item, GVAR(interactionVehicle), _unit]] call CBA_fnc_localEvent;
};
[
GVAR(loadTimeCoefficient) * _size,
[_item, GVAR(interactionVehicle), ACE_player],
{TRACE_1("unload finish",_this); ["ace_unloadCargo", _this select 0] call CBA_fnc_localEvent},
{TRACE_1("unload fail",_this);},
localize LSTRING(UnloadingItem),
_duration,
[_item, GVAR(interactionVehicle), _unit],
{
(_this select 0) params ["_item", "_target", "_player"];
TRACE_1("unload finish",_this);
(alive _target)
&& {locked _target < 2}
&& {([_player, _target] call EFUNC(interaction,getInteractionDistance)) < MAX_LOAD_DISTANCE}
&& {_item in (_target getVariable [QGVAR(loaded), []])}
["ace_unloadCargo", _this select 0] call CBA_fnc_localEvent;
},
{
TRACE_1("unload fail",_this);
},
LLSTRING(unloadingItem),
{
(_this select 0) params ["_item", "_vehicle", "_unit"];
[_item, _vehicle, _unit, false, true] call FUNC(canUnloadItem) // don't check for a suitable unloading position every frame
},
["isNotSwimming"]
] call EFUNC(common,progressBar);
} else {
private _displayName = [_item, true] call FUNC(getNameItem);
[[LSTRING(UnloadingFailed), _displayName], 3] call EFUNC(common,displayTextStructured);
[[LSTRING(unloadingFailed), [_item, true] call FUNC(getNameItem)], 3] call EFUNC(common,displayTextStructured);
};

View File

@ -4,17 +4,18 @@
* Dragging integration. Unloader starts carrying unloaded object.
*
* Arguments:
* 0: Unloader <OBJECT>
* 1: Item <OBJECT>
* 0: Unit doing the unloading <OBJECT>
* 1: Unloaded item <OBJECT>
*
* Return Value:
* None
*
* Example:
* [player, object] call ace_cargo_fnc_unloadCarryItem
* [player, cursorObject] call ace_cargo_fnc_unloadCarryItem
*
* Public: No
*/
params ["_unloader", "_object"];
TRACE_2("unloadCarryItem-start",_unloader,_object);
@ -24,17 +25,21 @@ if (!GVAR(carryAfterUnload) || {getNumber (configOf _object >> QGVAR(blockUnload
// When unloading attached objects, this code will run before server has finished moving object to the safe position
[{
params ["_unloader", "_object"];
(_unloader distance _object) < 10
}, {
params ["_unloader", "_object"];
TRACE_2("unloadCarryItem-unloaded",_unloader,_object);
if ([_unloader, _object] call EFUNC(dragging,canCarry)) exitWith {
[_unloader, _object] call EFUNC(dragging,startCarry);
};
if ([_unloader, _object] call EFUNC(dragging,canDrag)) exitWith {
[_unloader, _object] call EFUNC(dragging,startDrag);
};
}, _this, 1.0, { // delay is based on how long it will take server event to trigger and take effect
// not a hard error if this fails, could have just unloaded to other side of vehicle because of findSafePos
}, _this, 1, { // Delay is based on how long it will take server event to trigger and take effect
// Not a hard error if this fails, could have just unloaded to other side of vehicle because of findSafePos
TRACE_1("unloadCarryItem-failed to unload nearby player",_this);
}] call CBA_fnc_waitUntilAndExecute;

View File

@ -1,57 +1,74 @@
#include "..\script_component.hpp"
/*
* Author: Glowbal, ViperMaul
* Unload object from vehicle.
* Unloads an object from a vehicle.
*
* Arguments:
* 0: Item <OBJECT or STRING>
* 1: Vehicle <OBJECT>
* 0: Item to be unloaded <STRING> or <OBJECT> (default: "")
* 1: Holder object (vehicle) <OBJECT> (default: objNull)
* 2: Unloader <OBJECT> (default: objNull)
*
* Return Value:
* Object was unloaded <BOOL>
* Object unloaded <BOOL>
*
* Example:
* [object, vehicle] call ace_cargo_fnc_unloadItem
* ["ACE_Wheel", cursorObject] call ace_cargo_fnc_unloadItem
*
* Public: Yes
*/
params ["_item", "_vehicle", ["_unloader", objNull]];
params [["_item", "", [objNull, ""]], ["_vehicle", objNull, [objNull]], ["_unloader", objNull, [objNull]]];
TRACE_3("params",_item,_vehicle,_unloader);
//This covers testing vehicle stability and finding a safe position
private _emptyPosAGL = [_vehicle, _item, _unloader] call EFUNC(common,findUnloadPosition);
TRACE_1("findUnloadPosition",_emptyPosAGL);
if ((count _emptyPosAGL) != 3) exitWith {
TRACE_4("Could not find unload pos",_vehicle,getPosASL _vehicle,isTouchingGround _vehicle,speed _vehicle);
if ((!isNull _unloader) && {_unloader == ACE_player}) then {
//display text saying there are no safe places to exit the vehicle
[localize ELSTRING(common,NoRoomToUnload)] call EFUNC(common,displayTextStructured);
};
false
// Get config sensitive case name
if (_item isEqualType "") then {
_item = _item call EFUNC(common,getConfigName);
};
// Check if item is actually part of cargo
private _loaded = _vehicle getVariable [QGVAR(loaded), []];
if !(_item in _loaded) exitWith {
ERROR_3("Tried to unload item [%1] not in vehicle[%2] cargo[%3]", _item, _vehicle, _loaded);
false
ERROR_3("Tried to unload item [%1] not in vehicle[%2] cargo[%3]",_item,_vehicle,_loaded);
false // return
};
// Check if item can be unloaded
private _itemSize = _item call FUNC(getSizeItem);
if (_itemSize < 0) exitWith {
false // return
};
// This covers testing vehicle stability and finding a safe position
private _emptyPosAGL = [_vehicle, _item, _unloader] call EFUNC(common,findUnloadPosition);
TRACE_1("findUnloadPosition",_emptyPosAGL);
if (_emptyPosAGL isEqualTo []) exitWith {
// Display text saying there are no safe places to exit the vehicle
if (!isNull _unloader && {_unloader == ACE_player}) then {
[ELSTRING(common,NoRoomToUnload)] call EFUNC(common,displayTextStructured);
};
false // return
};
// Unload item from cargo
_loaded deleteAt (_loaded find _item);
_vehicle setVariable [QGVAR(loaded), _loaded, true];
private _space = [_vehicle] call FUNC(getCargoSpaceLeft);
private _itemSize = [_item] call FUNC(getSizeItem);
_vehicle setVariable [QGVAR(space), (_space + _itemSize), true];
// Update cargo space remaining
private _cargoSpace = _vehicle call FUNC(getCargoSpaceLeft);
_vehicle setVariable [QGVAR(space), _cargoSpace + _itemSize, true];
private _object = _item;
if (_object isEqualType objNull) then {
detach _object;
// hideObjectGlobal must be executed before setPos to ensure light objects are rendered correctly
// do both on server to ensure they are executed in the correct order
// Do both on server to ensure they are executed in the correct order
[QGVAR(serverUnload), [_object, _emptyPosAGL]] call CBA_fnc_serverEvent;
if (["ace_zeus"] call EFUNC(common,isModLoaded)) then {
@ -75,4 +92,5 @@ if (_object isEqualType objNull) then {
// Invoke listenable event
["ace_cargoUnloaded", [_object, _vehicle, "unload"]] call CBA_fnc_globalEvent;
true
true // return

View File

@ -1,37 +0,0 @@
#include "..\script_component.hpp"
/*
* Author: Glowbal
* Validate the vehicle cargo space.
*
* Arguments:
* 0: Object <OBJECT>
*
* Return Value:
* None
*
* Example:
* [object] call ace_cargo_fnc_validateCargoSpace
*
* Public: No
*/
params ["_vehicle"];
TRACE_1("params",_vehicle);
private _loaded = _vehicle getVariable [QGVAR(loaded), []];
private _newLoaded = [];
private _totalSpaceOccupied = 0;
{
if ((_x isEqualType "") || {!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 (configOf _vehicle >> QGVAR(space)) - _totalSpaceOccupied, true];

View File

@ -1,52 +1,58 @@
[
QGVAR(enable), "CHECKBOX",
QGVAR(enable),
"CHECKBOX",
[LSTRING(ModuleSettings_enable), LSTRING(ModuleSettings_enable_Description)],
[LELSTRING(OptionsMenu,CategoryLogistics), LLSTRING(openMenu)],
[ELSTRING(OptionsMenu,CategoryLogistics), LSTRING(openMenu)],
true,
true,
{[QGVAR(enable), _this] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting;
[
QGVAR(loadTimeCoefficient), "SLIDER",
QGVAR(loadTimeCoefficient),
"SLIDER",
[LSTRING(loadTimeCoefficient), LSTRING(loadTimeCoefficient_description)],
[LELSTRING(OptionsMenu,CategoryLogistics), LLSTRING(openMenu)],
[ELSTRING(OptionsMenu,CategoryLogistics), LSTRING(openMenu)],
[0, 10, 5, 1],
true,
{[QGVAR(loadTimeCoefficient), _this, true] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting;
[
QGVAR(paradropTimeCoefficent), "SLIDER",
QGVAR(paradropTimeCoefficent),
"SLIDER",
[LSTRING(paradropTimeCoefficent), LSTRING(paradropTimeCoefficent_description)],
[LELSTRING(OptionsMenu,CategoryLogistics), LLSTRING(openMenu)],
[ELSTRING(OptionsMenu,CategoryLogistics), LSTRING(openMenu)],
[0, 10, 2.5, 1],
true,
{[QGVAR(paradropTimeCoefficent), _this, true] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting;
[
QGVAR(openAfterUnload), "LIST",
QGVAR(openAfterUnload),
"LIST",
[LSTRING(openAfterUnload), LSTRING(openAfterUnload_description)],
[LELSTRING(OptionsMenu,CategoryLogistics), LLSTRING(openMenu)],
[ELSTRING(OptionsMenu,CategoryLogistics), LSTRING(openMenu)],
[[0, 1, 2, 3], [ELSTRING(common,never), LSTRING(unloadObject), LSTRING(paradropButton), ELSTRING(common,both)], 0],
false,
{[QGVAR(openAfterUnload), _this, true] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting;
[
QGVAR(enableRename), "CHECKBOX",
QGVAR(enableRename),
"CHECKBOX",
[LSTRING(ModuleSettings_enableRename), LSTRING(ModuleSettings_enableRename_Description)],
[LELSTRING(OptionsMenu,CategoryLogistics), LLSTRING(openMenu)],
[ELSTRING(OptionsMenu,CategoryLogistics), LSTRING(openMenu)],
true,
false,
{[QGVAR(enableRename), _this, true] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting;
[
QGVAR(carryAfterUnload), "CHECKBOX",
QGVAR(carryAfterUnload),
"CHECKBOX",
[LSTRING(carryAfterUnload), LSTRING(carryAfterUnload_description)],
[LELSTRING(OptionsMenu,CategoryLogistics), LLSTRING(openMenu)],
[ELSTRING(OptionsMenu,CategoryLogistics), LSTRING(openMenu)],
true,
false,
{[QGVAR(carryAfterUnload), _this] call EFUNC(common,cbaSettings_settingChanged)}

View File

@ -4,7 +4,7 @@ class GVAR(menu) {
idd = 314614;
movingEnable = 1;
onLoad = QUOTE([_this select 0] call FUNC(onMenuOpen));
onUnload = QUOTE(uiNamespace setVariable [ARR_2(QUOTE(QGVAR(menuDisplay)),nil)];);
onUnload = QUOTE(uiNamespace setVariable [ARR_2(QQGVAR(menuDisplay),nil)]);
class controlsBackground {
class HeaderBackground: ACE_gui_backgroundBase {
idc = -1;
@ -20,7 +20,7 @@ class GVAR(menu) {
h = "13.1 * ((((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])"};
colorBackground[] = {0, 0, 0, "(profilenamespace getVariable ['GUI_BCG_RGB_A',0.9])"};
};
};
@ -46,8 +46,8 @@ class GVAR(menu) {
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};
colorText[] = {1, 1, 1, 0.9};
colorBackground[] = {0, 0, 0, 0};
SizeEx = "(((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 1.2)";
text = "";
};
@ -83,12 +83,12 @@ class GVAR(menu) {
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};
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);
@ -97,7 +97,7 @@ class GVAR(menu) {
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));
action = QUOTE(ACE_player call FUNC(startUnload));
};
};
};

View File

@ -3,8 +3,8 @@
class GVAR(renameMenu) {
idd = 314615;
movingEnable = 0;
onLoad = QUOTE(uiNamespace setVariable [ARR_2(QUOTE(QGVAR(menuDisplay)),_this select 0)];);
onUnload = QUOTE(uiNamespace setVariable [ARR_2(QUOTE(QGVAR(menuDisplay)),nil)];);
onLoad = QUOTE(uiNamespace setVariable [ARR_2(QQGVAR(menuDisplay),_this select 0)]);
onUnload = QUOTE(uiNamespace setVariable [ARR_2(QQGVAR(menuDisplay),nil)]);
class controlsBackground {
class HeaderBackground: ACE_gui_backgroundBase {
idc = -1;
@ -20,7 +20,7 @@ class GVAR(renameMenu) {
h = "2.9 * ((((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])"};
colorBackground[] = {0, 0, 0, "(profilenamespace getVariable ['GUI_BCG_RGB_A',0.9])"};
};
};
@ -36,11 +36,11 @@ class GVAR(renameMenu) {
font = "RobotoCondensed";
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])"};
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(renameObjectUI);
};
class edit: ACE_gui_editBase {
onLoad = QUOTE((_this select 0) ctrlSetText (GVAR(interactionVehicle) getVariable [ARR_2(QUOTE(QGVAR(customName)),'')]));
onLoad = QUOTE((_this select 0) ctrlSetText (GVAR(interactionVehicle) getVariable [ARR_2(QQGVAR(customName),'')]));
idc = 100;
canModify = 1;
x = "13.1 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX + (safezoneW - ((safezoneW / safezoneH) min 1.2))/2)";
@ -65,12 +65,12 @@ class GVAR(renameMenu) {
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};
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);

View File

@ -19,7 +19,3 @@
#define MAX_LOAD_DISTANCE 5
#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

@ -38,7 +38,7 @@
<Japanese>名前を次に変更:&lt;br/&gt;%1</Japanese>
<French>Renommé en :&lt;br/&gt;%1</French>
<Russian>Переименовано в:&lt;br/&gt;%1</Russian>
<German>Neu Bewaffnet: &lt;br/&gt;%1</German>
<German>Neu umbenannt zu: &lt;br/&gt;%1</German>
<Polish>Nazwa zmieniona na:&lt;br/&gt;%1</Polish>
<Chinesesimp>重命名为:&lt;br/&gt;%1</Chinesesimp>
<Korean>%1(으)로 명칭을 바꿈</Korean>
@ -294,6 +294,16 @@
<Chinesesimp>%1&lt;br/&gt;无法被卸载</Chinesesimp>
<Turkish>%1&lt;br/&gt; kargo boşaltılamadı</Turkish>
</Key>
<Key ID="STR_ACE_Cargo_UnloadingImpossible">
<English>Can't be unloaded</English>
<German>Kann nicht entladen werden</German>
<French>Ne peut pas être déchargé</French>
</Key>
<Key ID="STR_ACE_Cargo_SizeMenu">
<English>Cargo Size: %1</English>
<German>Frachtgröße: %1</German>
<French>Encombrement fret: %1</French>
</Key>
<Key ID="STR_ACE_Cargo_customName_edenName">
<English>Custom Name</English>
<Japanese>カスタム名</Japanese>
@ -364,7 +374,7 @@
<Turkish>Kargo Boyutu</Turkish>
</Key>
<Key ID="STR_ACE_Cargo_size_edenDesc">
<English>The cargo space required to hold this object (-1 for unloadable)</English>
<English>The cargo space required to hold this object (-1 for not loadable)</English>
<German>Frachtraumgröße, welche zum Einladen dieses Objektes benötigt wird (-1 nicht einladbar)</German>
<Italian>Lo spazio del cargo necessita di mantenere questo oggetto (-1 per scaricabile)</Italian>
<Japanese>オブジェクトを積載するのに必要なカーゴ スペース (-1 で積載不可)</Japanese>

View File

@ -2,138 +2,150 @@
/*
* Author: PabstMirror, ViperMaul
* Find a safe place near a vehicle to unload something.
* Handles Normal Terrain, In Water or On Buildings (Pier, StaticShip).
* Handles normal terrain, water or on buildings (Pier, StaticShip).
*
* Arguments:
* 0: Source Vehicle <OBJECT>
* 1: Cargo <OBJECT> or <STRING>
* 2: Unloader (player) <OBJECT> (default: objNull)
* 3: Max Distance (meters) <NUMBER> (default: 10)
* 4: Check Vehicle is Stable <BOOL> (default: true)
* 0: Holder object (vehicle) <OBJECT>
* 1: Item to be unloaded <STRING> or <OBJECT>
* 2: Unit doing the unloading <OBJECT> (default: objNull)
* 3: Max distance (meters) <NUMBER> (default: 10)
* 4: Check if holder object is stable <BOOL> (default: true)
*
* Return Value:
* Unload PositionAGL (can Be [] if no valid pos found) <ARRAY>
* Unload PositionAGL ([] if no valid pos found) <ARRAY>
*
* Example:
* [theCar, "CAManBase", player, 10, true] call ace_common_fnc_findUnloadPosition
* [cursorObject, "CAManBase", player, 10, true] call ace_common_fnc_findUnloadPosition
*
* Public: No
*/
//Number of tests run (effects performance in worst case scenarior where nothing is found VERSUES reliably finding a pos):
// Number of tests run (effects performance in worst case scenario where nothing is found VERSUS reliably finding a pos)
#define MAX_TESTS 75
//Manual collision tests (count and radius):
// Manual collision tests (count and radius)
#define COL_TEST_COUNT 12
params ["_vehicle", "_cargo", ["_theUnloader", objNull], ["_maxDistance", 10], ["_checkVehicleIsStable", true]];
TRACE_5("params",_vehicle,_cargo,_theUnloader,_maxDistance,_checkVehicleIsStable);
params ["_vehicle", "_item", ["_unloader", objNull], ["_maxDistance", 10], ["_checkVehicleIsStable", true]];
TRACE_5("params",_vehicle,_item,_unloader,_maxDistance,_checkVehicleIsStable);
scopeName "main";
if (_checkVehicleIsStable) then {
if (((vectorMagnitude (velocity _vehicle)) > 1.5) || {(!(_vehicle isKindOf "Ship")) && {(!isTouchingGround _vehicle) && {((getPos _vehicle) select 2) > 1.5}}}) then {
TRACE_4("bad vehicle state",_vehicle,velocity _vehicle,isTouchingGround _vehicle,getPos _vehicle);
[] breakOut "main";
[] breakOut "main"
};
};
private _radiusOfItem = 1;
if (_cargo isKindOf "CAManBase") then {
if (_item isKindOf "CAManBase") then {
_radiusOfItem = 1.1;
} else {
//`sizeOf` is unreliable, and does not work with object types that don't exist on map, so estimate size based on cargo size
private _configOfCargo = if (_cargo isEqualType objNull) then {
configOf _cargo
} else {
configFile >> "CfgVehicles" >> _cargo
};
private _itemSize = if (isNumber (_configOfCargo >> QEGVAR(cargo,size)) && {getNumber (_configOfCargo >> QEGVAR(cargo,size)) != -1}) then {
getNumber (_configOfCargo >> QEGVAR(cargo,size));
} else {
if (["ace_cargo"] call FUNC(isModLoaded)) then {
[_cargo] call EFUNC(cargo,getSizeItem);
} else {
_radiusOfItem;
// `sizeOf` is unreliable, and does not work with object types that don't exist on map, so estimate size based on cargo size
if (["ace_cargo"] call FUNC(isModLoaded)) then {
private _itemSize = _item call EFUNC(cargo,getSizeItem);
if (_itemSize > 0) then {
_radiusOfItem = (_itemSize ^ 0.35) max 0.75;
};
};
if (_itemSize != -1) then {
_radiusOfItem = (_itemSize ^ 0.35) max 0.75;
};
};
if (isNull _theUnloader) then {_theUnloader = _vehicle;};
if (isNull _unloader) then {
_unloader = _vehicle;
};
//Ideal unload pos is halfway between unloader and vehicle (at the unloader's height)
private _originASL = ((getPosASL _theUnloader) vectorAdd (getPosASL _vehicle)) vectorMultiply 0.5;
_originASL set [2, (getPosASL _theUnloader) select 2];
// Ideal unload pos is halfway between unloader and vehicle (at the unloader's height)
private _originASL = ((getPosASL _unloader) vectorAdd (getPosASL _vehicle)) vectorMultiply 0.5;
_originASL set [2, (getPosASL _unloader) select 2];
private _originAGL = ASLtoAGL _originASL;
//Do a manual search for empty pos (handles underwater, buildings or piers)
// Do a manual search for empty pos (handles underwater, buildings or piers)
TRACE_2("Checking for unload",_originAGL,_radiusOfItem);
private _rangeToCheck = 0;
while {_rangeToCheck < _maxDistance} do {
private _roundDistance = random _rangeToCheck;
private _roundAngle = random 360;
private _roundAGL = _originAGL vectorAdd [(cos _roundAngle) * _roundDistance, (sin _roundAngle) * _roundDistance, 0];
private _roundPointIsValid = false;
if (((AGLtoASL _roundAGL) select 2) > 0) then {
//Shoot a ray down, and make sure we hit something solid like a building or the ground:
private _belowRoundArray = lineIntersectsSurfaces [(AGLtoASL _roundAGL) vectorAdd [0,0,0.5], (AGLtoASL _roundAGL) vectorAdd [0,0,-1]];
// Shoot a ray down, and make sure we hit something solid like a building or the ground
private _belowRoundArray = lineIntersectsSurfaces [(AGLtoASL _roundAGL) vectorAdd [0, 0, 0.5], (AGLtoASL _roundAGL) vectorAdd [0, 0, -1]];
TRACE_4("Testing for solid",_roundDistance,_roundAngle,_roundAGL,_belowRoundArray);
if (_belowRoundArray isNotEqualTo []) then {
private _aboveBuilding = (_belowRoundArray select 0) select 2;
//Point is above something: Terrain(null) or Building
// Point is above something: Terrain (null) or Building
if ((isNull _aboveBuilding) || {_aboveBuilding isKindOf "Building"}) then {
//Get the real intersection point:
// Get the real intersection point
_roundAGL = ASLtoAGL ((_belowRoundArray select 0) select 0);
_roundPointIsValid = true;
};
};
} else {
//Underwater, just unload anywhere
// Underwater, just unload anywhere
TRACE_3("Under the sea",_roundDistance,_roundAngle,_roundAGL);
_roundPointIsValid = true;
};
//Make sure point is valid and do a fast check for people in the way (which sometimes aren't caught by line scaning)
// Make sure point is valid and do a fast check for people in the way (which sometimes aren't caught by line scanning)
if (_roundPointIsValid && {(_roundAGL nearEntities ["Man", _radiusOfItem]) isEqualTo []}) then {
for "_index" from 0 to (COL_TEST_COUNT -1) do {
//Scan for colisions with objects with lineIntersectsSurfaces
// Scan for collisions with objects with lineIntersectsSurfaces
private _angle = _index * (360 / COL_TEST_COUNT);
private _point1ASL = (AGLtoASL _roundAGL) vectorAdd [_radiusOfItem * cos _angle, _radiusOfItem * sin _angle, 0.1];
private _point2ASL = (AGLtoASL _roundAGL) vectorAdd [-_radiusOfItem * cos _angle, -_radiusOfItem * sin _angle, (_radiusOfItem + 0.5)];
private _point2ASL = (AGLtoASL _roundAGL) vectorAdd [-_radiusOfItem * cos _angle, -_radiusOfItem * sin _angle, _radiusOfItem + 0.5];
private _testIntersections = lineIntersectsSurfaces [_point1ASL, _point2ASL];
if (((count _testIntersections) == 1) && {isNull ((_testIntersections select 0) select 2)}) then {
private _hitGroundASL = (_testIntersections select 0) select 0;
private _hitHeightOffset = ((AGLtoASL _roundAGL) select 2) - (_hitGroundASL select 2);
private _hit2dOffset = _roundAGL distance2D _hitGroundASL;
private _slope = _hitHeightOffset atan2 _hit2dOffset;
if (_slope < 25) then { //Ignore ground hit if slope is reasonable
// Ignore ground hit if slope is reasonable
if (_slope < 25) then {
_testIntersections = [];
};
};
if (_testIntersections isNotEqualTo []) exitWith {
TRACE_2("collision low/high",_roundAGL,_testIntersections);
_roundPointIsValid = false;
};
_point1ASL = (AGLtoASL _roundAGL) vectorAdd [_radiusOfItem * cos _angle, _radiusOfItem * sin _angle, 0.5];
_point2ASL = (AGLtoASL _roundAGL) vectorAdd [-_radiusOfItem * cos _angle, -_radiusOfItem * sin _angle, 1];
_testIntersections = lineIntersectsSurfaces [_point1ASL, _point2ASL];
if (_testIntersections isNotEqualTo []) exitWith {
TRACE_2("collision mid",_roundAGL,_testIntersections);
_roundPointIsValid = false;
};
};
if (_roundPointIsValid) then {
TRACE_3("Valid point found", _rangeToCheck,_roundAGL, (_originAGL distance _roundAGL));
//Raise it slightly so we don't sink through the floor:
(_roundAGL vectorAdd [0,0,0.05]) breakOut "main";
TRACE_3("Valid point found",_rangeToCheck,_roundAGL,_originAGL distance _roundAGL);
// Raise it slightly so we don't sink through the floor
(_roundAGL vectorAdd [0, 0, 0.05]) breakOut "main"; // return
};
};
_rangeToCheck = _rangeToCheck + (_maxDistance / MAX_TESTS);
};
TRACE_1("no valid spots found",_rangeToCheck);
[] //return empty array
[] // return

View File

@ -72,13 +72,13 @@ if (_previousHint isEqualType "") exitWith {};
// Mouse hint
private _hintLMB = LLSTRING(Drop);
getCursorObjectParams params ["_cursorObject", "", "_distance"];
private _cursorObject = cursorObject;
if (
!isNull _cursorObject && {[_unit, _cursorObject, ["isNotCarrying"]] call EFUNC(common,canInteractWith)} &&
{
if (_target isKindOf "CAManBase") then {
(_distance <= MAX_LOAD_DISTANCE_MAN) && {[_cursorObject, 0, true] call EFUNC(common,nearestVehiclesFreeSeat) isNotEqualTo []}
(_unit distance _cursorObject <= MAX_LOAD_DISTANCE_MAN) && {[_cursorObject, 0, true] call EFUNC(common,nearestVehiclesFreeSeat) isNotEqualTo []}
} else {
["ace_cargo"] call EFUNC(common,isModLoaded) &&
{EGVAR(cargo,enable)} &&

View File

@ -30,8 +30,17 @@ private _inBuilding = _unit call FUNC(isObjectOnObject);
[QEGVAR(common,fixCollision), _unit] call CBA_fnc_localEvent;
[QEGVAR(common,fixCollision), _target, _target] call CBA_fnc_targetEvent;
// Release object
detach _target;
private _cursorObject = cursorObject;
_tryLoad = _tryLoad && {!isNull _cursorObject} && {[_unit, _cursorObject, ["isNotCarrying"]] call EFUNC(common,canInteractWith)};
private _loadCargo = false;
// Don't release object if loading into vehicle (object might be released into vehicle)
if (_tryLoad && {!(_target isKindOf "CAManBase")} && {["ace_cargo"] call EFUNC(common,isModLoaded)} && {[_target, _cursorObject] call EFUNC(cargo,canLoadItemIn)}) then {
_loadCargo = true;
} else {
// Release object
detach _target;
};
// Fix anim when aborting carrying persons
if (_target isKindOf "CAManBase" || {animationState _unit in CARRY_ANIMATIONS}) then {
@ -97,13 +106,11 @@ if (_mass != 0) then {
// Reset temp direction
_target setVariable [QGVAR(carryDirection_temp), nil];
getCursorObjectParams params ["_cursorObject", "", "_distance"];
// Try loading into vehicle
if (_tryLoad && {!isNull _cursorObject} && {[_unit, _cursorObject, ["isNotCarrying"]] call EFUNC(common,canInteractWith)}) then {
if (_target isKindOf "CAManBase") then {
if (_distance > MAX_LOAD_DISTANCE_MAN) exitWith {};
// (Try) loading into vehicle
if (_loadCargo) then {
[_unit, _target, _cursorObject] call EFUNC(cargo,startLoadIn);
} else {
if (_tryLoad && {_unit distance _cursorObject <= MAX_LOAD_DISTANCE_MAN} && {_target isKindOf "CAManBase"}) then {
private _vehicles = [_cursorObject, 0, true] call EFUNC(common,nearestVehiclesFreeSeat);
if ([_cursorObject] isEqualTo _vehicles) then {
@ -113,13 +120,5 @@ if (_tryLoad && {!isNull _cursorObject} && {[_unit, _cursorObject, ["isNotCarryi
[_unit, _target, _cursorObject] call EFUNC(common,loadPerson);
};
};
} else {
if (
["ace_cargo"] call EFUNC(common,isModLoaded) &&
{EGVAR(cargo,enable)} &&
{[_target, _cursorObject] call EFUNC(cargo,canLoadItemIn)}
) then {
[_unit, _target, _cursorObject] call EFUNC(cargo,startLoadIn);
};
};
};

View File

@ -1,4 +1,4 @@
private _category = [LELSTRING(OptionsMenu,CategoryLogistics), LLSTRING(DisplayName)];
private _category = [ELSTRING(OptionsMenu,CategoryLogistics), LLSTRING(DisplayName)];
[
QGVAR(enabled), "CHECKBOX",

View File

@ -1,7 +1,9 @@
private _category = [ELSTRING(OptionsMenu,CategoryLogistics), "str_state_refuel"];
[
QGVAR(rate), "SLIDER",
[LSTRING(RefuelSettings_speed_DisplayName), LSTRING(RefuelSettings_speed_Description)],
[localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_refuel"],
_category,
[0,25,1,1], // [min, max, default value, trailing decimals (-1 for whole numbers only)]
true, // isGlobal
{[QGVAR(rate), _this] call EFUNC(common,cbaSettings_settingChanged)}
@ -10,7 +12,7 @@
[
QGVAR(cargoRate), "SLIDER",
[LSTRING(RefuelSettings_speedCargo_DisplayName), LSTRING(RefuelSettings_speedCargo_Description)],
[localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_refuel"],
_category,
[0,250,10,1], // [min, max, default value, trailing decimals (-1 for whole numbers only)]
true, // isGlobal
{[QGVAR(cargoRate), _this] call EFUNC(common,cbaSettings_settingChanged)}
@ -19,7 +21,7 @@
[
QGVAR(hoseLength), "SLIDER",
[LSTRING(RefuelSettings_hoseLength_DisplayName)],
[localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_refuel"],
_category,
[0,50,12,1], // [min, max, default value, trailing decimals (-1 for whole numbers only)]
true, // isGlobal
{[QGVAR(hoseLength), _this] call EFUNC(common,cbaSettings_settingChanged)}
@ -28,7 +30,7 @@
[
QGVAR(progressDuration), "TIME",
[LSTRING(RefuelSettings_progressDuration_DisplayName), LSTRING(RefuelSettings_progressDuration_Description)],
[localize ELSTRING(OptionsMenu,CategoryLogistics), localize "str_state_refuel"],
_category,
[0, 10, 2], // [min, max, default value]
true, // isGlobal
{[QGVAR(progressDuration), _this] call EFUNC(common,cbaSettings_settingChanged)}

View File

@ -1,7 +1,7 @@
[
QGVAR(addRopeToVehicleInventory), "CHECKBOX",
LSTRING(Setting_addRopeToVehicleInventory_DisplayName),
LELSTRING(OptionsMenu,CategoryLogistics),
ELSTRING(OptionsMenu,CategoryLogistics),
true,
true,
{

View File

@ -32,10 +32,10 @@ if !(["ace_cargo"] call EFUNC(common,isModLoaded) && ["ace_repair"] call EFUNC(c
if !(alive _mouseOverUnit) then {
[LSTRING(OnlyAlive)] call FUNC(showMessage);
} else {
if (getNumber (configFile >> "CfgVehicles" >> "ACE_Track" >> QEGVAR(cargo,size)) > [_mouseOverUnit] call EFUNC(cargo,getCargoSpaceLeft)) then {
if ("ACE_Track" call EFUNC(cargo,getSizeItem) > _mouseOverUnit call EFUNC(cargo,getCargoSpaceLeft)) then {
[LSTRING(OnlyEnoughCargoSpace)] call FUNC(showMessage);
} else {
["ace_addCargo", ["ACE_Track", _mouseOverUnit, 1, true]] call CBA_fnc_localEvent;
["ace_addCargo", ["ACE_Track", _mouseOverUnit, 1]] call CBA_fnc_localEvent;
};
};
};

View File

@ -32,10 +32,10 @@ if !(["ace_cargo"] call EFUNC(common,isModLoaded) && ["ace_repair"] call EFUNC(c
if !(alive _mouseOverUnit) then {
[LSTRING(OnlyAlive)] call FUNC(showMessage);
} else {
if (getNumber (configFile >> "CfgVehicles" >> "ACE_Wheel" >> QEGVAR(cargo,size)) > [_mouseOverUnit] call EFUNC(cargo,getCargoSpaceLeft)) then {
if ("ACE_Wheel" call EFUNC(cargo,getSizeItem) > _mouseOverUnit call EFUNC(cargo,getCargoSpaceLeft)) then {
[LSTRING(OnlyEnoughCargoSpace)] call FUNC(showMessage);
} else {
["ace_addCargo", ["ACE_Wheel", _mouseOverUnit, 1, true]] call CBA_fnc_localEvent;
["ace_addCargo", ["ACE_Wheel", _mouseOverUnit, 1]] call CBA_fnc_localEvent;
};
};
};

View File

@ -21,6 +21,8 @@ class CfgVehicles {
class yourVehicleBaseClass {
ace_cargo_space = 4; // Cargo space your vehicle has
ace_cargo_hasCargo = 1; // Enables cargo to be loaded inside the vehicle (1-yes, 0-no)
ace_cargo_loadmasterTurrets = {{1}}; // If vehicle inherits from "Air", you can set this attribute.
// When sitting in the turret paths you define here, you can paradrop cargo items. By default, pilots and co-pilots can paradrop cargo items.
};
};
```
@ -50,8 +52,9 @@ class CfgVehicles {
Event Name | Passed Parameter(s) | Locality | Description
---------- | ----------- | ------------------- | --------
`ace_cargoLoaded` | [_item, _vehicle] | Global | Cargo has been Loaded into vehicle
`ace_cargoUnloaded` | [_item, _vehicle, _unloadType] | Global | Cargo has been Unloaded from vehicle
`ace_cargoAdded` | [_itemClass, _vehicle, _amount] | Global | Cargo has been added to vehicle
`ace_cargoLoaded` | [_item, _vehicle] | Global | Cargo has been loaded into vehicle
`ace_cargoUnloaded` | [_item, _vehicle, _unloadType] | Global | Cargo has been unloaded from vehicle
`ace_cargoRemoved` | [_itemClass, _vehicle, _amountRequested, _amountRemoved] | Global | Cargo has been removed (deleted) from vehicle
## 3. Editor Attributes
@ -73,12 +76,12 @@ To disable cargo for a mission object use:
### 4.2 Adjusting cargo size of an object
`ace_cargo_fnc_setSize`
Note that this function can be used to make objects loadable/unloadable (set to `-1` for unloadable).
Note that this function can be used to make objects loadable/unloadable (set to `-1` to disable cargo interactions).
```sqf
* Set the cargo size of any object. Has global effect.
* Sets the cargo size of any object. Has global effect.
* Adds the load action menu if necessary.
* Negative size makes unloadable.
* A negative size disables the object's cargo interactions.
*
* Arguments:
* 0: Object <OBJECT>
@ -97,7 +100,7 @@ Note that this function can be used to make objects loadable/unloadable (set to
Note that this function can be used to enable/disable a vehicle's cargo space (set to `0` to disable).
```sqf
* Set the cargo space of any object. Has global effect.
* Sets the cargo space of any object. Has global effect.
* Adds the cargo action menu if necessary.
*
* Arguments:
@ -113,14 +116,17 @@ Note that this function can be used to enable/disable a vehicle's cargo space (s
### 4.4 Load cargo into vehicle
`ace_cargo_fnc_loadItem` (Also callable from cba event `ace_loadCargo`)
Note first arg can be a in-game object or a classname of an object type.
`ace_cargo_fnc_loadItem` (Also callable from CBA event `ace_loadCargo`)
Note first argument can be a in-game object or a classname of an object type.
```sqf
* Load an object into a vehicle.
* Objects loaded via classname remain virtual until unloaded.
*
* Arguments:
* 0: Item <OBJECT or STRING>
* 1: Vehicle <OBJECT>
* 2: Ignore interaction distance and stability checks <BOOL>
* 0: Item to be loaded <STRING> or <OBJECT>
* 1: Holder object (vehicle) <OBJECT>
* 2: Ignore interaction distance and stability checks <BOOL> (default: false)
*
* Return Value:
* Object loaded <BOOL>
@ -131,16 +137,16 @@ Note first arg can be a in-game object or a classname of an object type.
### 4.5 Unload cargo from vehicle
`ace_cargo_fnc_unloadItem` (Also callable from cba event `ace_unloadCargo`)
`ace_cargo_fnc_unloadItem` (Also callable from CBA event `ace_unloadCargo`)
```sqf
* Arguments:
* 0: Item <OBJECT or STRING>
* 1: Vehicle <OBJECT>
* 0: Item to be unloaded <STRING> or <OBJECT>
* 1: Holder object (vehicle) <OBJECT>
* 2: Unloader <OBJECT> (default: objNull)
*
* Return Value:
* Object was unloaded <BOOL>
* Object unloaded <BOOL>
*
* Example:
* [object, vehicle] call ace_cargo_fnc_unloadItem
@ -152,8 +158,8 @@ Note first arg can be a in-game object or a classname of an object type.
```sqf
* Arguments:
* 0: Item <STRING> or <OBJECT>
* 1: Vehicle <OBJECT>
* 0: Item to be removed <STRING> or <OBJECT>
* 1: Holder object (vehicle) <OBJECT>
* 2: Amount <NUMBER> (default: 1)
*
* Return Value:
@ -167,5 +173,5 @@ Note first arg can be a in-game object or a classname of an object type.
### 4.7 Disable cargo renaming via script
```sqf
cargoBox setVariable ["ace_cargo_noRename", true]
cargoBox setVariable ["ace_cargo_noRename", true, _disableGlobally]
```