Cargo - Add alternative unloading item from vehicle cargo (#8827)

Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com>
Co-authored-by: LinkIsGrim <salluci.lovi@gmail.com>
Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com>
This commit is contained in:
Smith 2024-02-07 14:16:18 +02:00 committed by GitHub
parent 6637a15af9
commit 8731bcc8b5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 509 additions and 53 deletions

View File

@ -15,3 +15,17 @@ class Extended_PostInit_EventHandlers {
init = QUOTE(call COMPILE_SCRIPT(XEH_postInit)); init = QUOTE(call COMPILE_SCRIPT(XEH_postInit));
}; };
}; };
class Extended_Killed_EventHandlers {
class CAManBase {
class ADDON {
killed = QUOTE((_this select 0) call FUNC(handleDeployInterrupt));
};
};
};
class Extended_DisplayLoad_EventHandlers {
class RscDisplayMission {
ADDON = QUOTE(_this call COMPILE_SCRIPT(XEH_missionDisplayLoad));
};
};

View File

@ -2,10 +2,15 @@ PREP(addCargoItem);
PREP(addCargoVehiclesActions); PREP(addCargoVehiclesActions);
PREP(canLoadItemIn); PREP(canLoadItemIn);
PREP(canUnloadItem); PREP(canUnloadItem);
PREP(deployCancel);
PREP(deployConfirm);
PREP(getCargoSpaceLeft); PREP(getCargoSpaceLeft);
PREP(getNameItem); PREP(getNameItem);
PREP(getSelectedItem);
PREP(getSizeItem); PREP(getSizeItem);
PREP(handleDestroyed); PREP(handleDestroyed);
PREP(handleDeployInterrupt);
PREP(handleScrollWheel);
PREP(initObject); PREP(initObject);
PREP(initVehicle); PREP(initVehicle);
PREP(loadItem); PREP(loadItem);
@ -16,6 +21,7 @@ PREP(removeCargoItem);
PREP(renameObject); PREP(renameObject);
PREP(setSize); PREP(setSize);
PREP(setSpace); PREP(setSpace);
PREP(startDeploy);
PREP(startLoadIn); PREP(startLoadIn);
PREP(startUnload); PREP(startUnload);
PREP(unloadCarryItem); PREP(unloadCarryItem);

View File

@ -0,0 +1,11 @@
#include "script_component.hpp"
params ["_display"];
_display displayAddEventHandler ["MouseZChanged", {(_this select 1) call FUNC(handleScrollWheel)}];
_display displayAddEventHandler ["MouseButtonDown", {
// Right clicking cancels deployment
if (_this select 1 == 1) then {
ACE_player call FUNC(handleDeployInterrupt);
};
}];

View File

@ -17,10 +17,10 @@
}] call CBA_fnc_addEventHandler; }] call CBA_fnc_addEventHandler;
["ace_unloadCargo", { ["ace_unloadCargo", {
params ["_item", "_vehicle", ["_unloader", objNull]]; params ["_item", "_vehicle", ["_unloader", objNull], ["_place", []]];
TRACE_3("UnloadCargo EH",_item,_vehicle,_unloader); TRACE_4("UnloadCargo EH",_item,_vehicle,_unloader,_place);
private _unloaded = [_item, _vehicle, _unloader] call FUNC(unloadItem); // returns true if successful private _unloaded = [_item, _vehicle, _unloader, _place] call FUNC(unloadItem); // returns true if successful
// Show hint as feedback // Show hint as feedback
private _hint = [LSTRING(unloadingFailed), LSTRING(unloadedItem)] select _unloaded; private _hint = [LSTRING(unloadingFailed), LSTRING(unloadedItem)] select _unloaded;
@ -36,13 +36,25 @@
}; };
}] call CBA_fnc_addEventHandler; }] call CBA_fnc_addEventHandler;
// Direction must be set before setting position according to wiki
[QGVAR(setDirAndUnload), {
params ["_item", "_emptyPosAGL", "_direction"];
_item setDir _direction;
[QGVAR(serverUnload), [_item, _emptyPosAGL]] call CBA_fnc_serverEvent;
}] call CBA_fnc_addEventHandler;
// 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
[QGVAR(serverUnload), { [QGVAR(serverUnload), {
params ["_item", "_emptyPosAGL"]; params ["_item", "_emptyPosAGL"];
_item hideObjectGlobal false; _item hideObjectGlobal false;
_item setPosASL (AGLtoASL _emptyPosAGL); _item setPosASL (AGLtoASL _emptyPosAGL);
[_item, "blockDamage", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); // Let objects remain invulernable for a short while after placement
[EFUNC(common,statusEffect_set), [_item, "blockDamage", QUOTE(ADDON), false], 2] call CBA_fnc_waitAndExecute;
}] call CBA_fnc_addEventHandler; }] call CBA_fnc_addEventHandler;
[QGVAR(paradropItem), { [QGVAR(paradropItem), {
@ -166,3 +178,38 @@ if (isServer) then {
_bodyBag setVariable [QGVAR(customName), [_target, false, true] call EFUNC(common,getName), true]; _bodyBag setVariable [QGVAR(customName), [_target, false, true] call EFUNC(common,getName), true];
}] call CBA_fnc_addEventHandler; }] call CBA_fnc_addEventHandler;
}; };
// Set variables, even on machines without interfaces, just to be safe
GVAR(selectedItem) = objNull;
GVAR(itemPreviewObject) = objNull;
GVAR(deployPFH) = -1;
GVAR(deployDistance) = -1;
GVAR(deployDirection) = 0;
GVAR(deployHeight) = 0;
GVAR(canDeploy) = false;
if (!hasInterface) exitWith {};
// Cancel object deployment if interact menu opened
["ace_interactMenuOpened", {ACE_player call FUNC(handleDeployInterrupt)}] call CBA_fnc_addEventHandler;
// Cancel deploy on player change. This does work when returning to lobby, but not when hard disconnecting
["unit", LINKFUNC(handleDeployInterrupt)] call CBA_fnc_addPlayerEventHandler;
["vehicle", {(_this select 0) call FUNC(handleDeployInterrupt)}] call CBA_fnc_addPlayerEventHandler;
["weapon", {(_this select 0) call FUNC(handleDeployInterrupt)}] call CBA_fnc_addPlayerEventHandler;
// When changing feature cameras, stop deployment
["featureCamera", {(_this select 0) call FUNC(handleDeployInterrupt)}] call CBA_fnc_addPlayerEventHandler;
// Handle falling unconscious while trying to deploy
["ace_unconscious", {(_this select 0) call FUNC(handleDeployInterrupt)}] call CBA_fnc_addEventHandler;
// Handle surrendering and handcuffing
["ace_captiveStatusChanged", {
params ["_unit", "_state"];
// If surrendered or handcuffed, stop deployment
if (_state) then {
_unit call FUNC(handleDeployInterrupt);
};
}] call CBA_fnc_addEventHandler;

View File

@ -0,0 +1,39 @@
#include "..\script_component.hpp"
/*
* Author: Garth 'L-H' de Wet, Ruthberg, commy2, Smith
* Cancels unloading when deploying.
*
* Arguments:
* 0: Unit <OBJECT>
*
* Return Value:
* None
*
* Example:
* player call ace_cargo_fnc_deployCancel
*
* Public: No
*/
if (GVAR(deployPFH) == -1) exitWith {};
// Remove deployment pfh
GVAR(deployPFH) call CBA_fnc_removePerFrameHandler;
GVAR(deployPFH) = -1;
params ["_unit"];
// Enable running again
[_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
[_unit, "blockThrow", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
// Delete placement dummy
deleteVehicle GVAR(itemPreviewObject);
// Remove mouse button actions
call EFUNC(interaction,hideMouseHint);
[_unit, "DefaultAction", _unit getVariable [QGVAR(deploy), -1]] call EFUNC(common,removeActionEventHandler);
_unit setVariable [QGVAR(deploy), -1];
_unit setVariable [QGVAR(isDeploying), false, true];

View File

@ -0,0 +1,56 @@
#include "..\script_component.hpp"
/*
* Author: Garth 'L-H' de Wet, Ruthberg, commy2, Smith
* Confirms unloading when deploying.
*
* Arguments:
* 0: Unit <OBJECT>
*
* Return Value:
* None
*
* Example:
* player call ace_cargo_fnc_deployConfirm
*
* Public: No
*/
if (GVAR(deployPFH) == -1) exitWith {};
params ["_unit"];
// Delete placement dummy and unload real item from cargo at dummy position
if (!isNull GVAR(itemPreviewObject) && {[GVAR(selectedItem), GVAR(interactionVehicle), _unit, false, true] call FUNC(canUnloadItem)}) then {
// Position is AGL for unloading event
private _position = ASLToAGL getPosASL GVAR(itemPreviewObject);
private _direction = getDir GVAR(itemPreviewObject);
private _duration = GVAR(loadTimeCoefficient) * (GVAR(selectedItem) call FUNC(getSizeItem));
// If unload time is 0, don't show a progress bar
if (_duration <= 0) exitWith {
["ace_unloadCargo", [GVAR(selectedItem), GVAR(interactionVehicle), _unit, [_position, _direction]]] call CBA_fnc_localEvent;
};
[
_duration,
[GVAR(selectedItem), GVAR(interactionVehicle), _unit, [_position, _direction]],
{
TRACE_1("deploy finish",_this);
["ace_unloadCargo", _this select 0] call CBA_fnc_localEvent;
},
{
TRACE_1("deploy fail",_this);
},
format [LLSTRING(unloadingItem), [GVAR(selectedItem), true] call FUNC(getNameItem), getText (configOf GVAR(interactionVehicle) >> "displayName")],
{
(_this select 0) params ["_item", "_vehicle", "_unit"];
[_item, _vehicle, _unit, false, true] call FUNC(canUnloadItem) // don't check for a suitable unloading position when deploying
},
["isNotSwimming"]
] call EFUNC(common,progressBar);
};
// Cleanup EHs and preview object
_unit call FUNC(deployCancel);

View File

@ -0,0 +1,29 @@
#include "..\script_component.hpp"
/*
* Author: Glowbal, Smith
* Get selected item from cargo menu.
*
* Arguments:
* None
*
* Return Value:
* Classname of selected item or selected object <STRING> or <OBJECT> (default: nil)
*
* Example:
* call ace_cargo_fnc_getSelectedItem
*
* Public: No
*/
disableSerialization;
private _display = uiNamespace getVariable QGVAR(menuDisplay);
if (isNil "_display") exitWith {};
private _loaded = GVAR(interactionVehicle) getVariable [QGVAR(loaded), []];
if (_loaded isEqualTo []) exitWith {};
// This can be an object or a classname string
_loaded param [lbCurSel (_display displayCtrl 100), nil]

View File

@ -0,0 +1,30 @@
#include "..\script_component.hpp"
/*
* Author: commy2, Smith
* Handle various interruption types.
*
* Arguments:
* 0: (New) unit <OBJECT>
* 1: Old unit (for player change) <OBJECT> (default: objNull)
*
* Return Value:
* None
*
* Example:
* player call ace_cargo_fnc_handleDeployInterrupt
*
* Public: No
*/
params ["_newPlayer", ["_oldPlayer", objNull]];
TRACE_2("params",_newPlayer,_oldPlayer);
if (!local _newPlayer) exitWith {};
if (_newPlayer getVariable [QGVAR(isDeploying), false]) then {
_newPlayer call FUNC(deployCancel);
};
if (_oldPlayer getVariable [QGVAR(isDeploying), false]) then {
_oldPlayer call FUNC(deployCancel);
};

View File

@ -0,0 +1,58 @@
#include "..\script_component.hpp"
/*
* Author: L-H, commy2, Smith
* Handles rotation of object to unload.
*
* Arguments:
* 0: Scroll amount <NUMBER>
*
* Return Value:
* If the scroll was handled <BOOL>
*
* Example:
* 1.2 call ace_cargo_fnc_handleScrollWheel
*
* Public: No
*/
if (GVAR(deployPFH) == -1) exitWith {false};
params ["_scrollAmount"];
private _deployedItem = GVAR(itemPreviewObject);
if (!CBA_events_control) then {
private _unit = ACE_player;
// Raise/lower
// Move deployed item 15 cm per scroll interval
_scrollAmount = _scrollAmount * 0.15;
private _position = getPosASL _deployedItem;
private _maxHeight = (_unit modelToWorldVisualWorld [0, 0, 0]) select 2;
_position set [2, ((_position select 2) + _scrollAmount min (_maxHeight + 1.5)) max _maxHeight];
// Move up/down object and reattach at current position
detach _deployedItem;
// Uses this method of selecting position because setPosATL did not have immediate effect
private _positionChange = _position vectorDiff (getPosASL _deployedItem);
private _selectionPosition = _unit worldToModel (ASLtoAGL getPosWorld _deployedItem);
_selectionPosition = _selectionPosition vectorAdd _positionChange;
_deployedItem attachTo [_unit, _selectionPosition];
// Reset the deploy direction
private _direction = _deployedItem getVariable [QGVAR(deployDirection_temp), 0];
_deployedItem setDir _direction;
} else {
// Rotate
private _direction = _deployedItem getVariable [QGVAR(deployDirection_temp), 0];
_scrollAmount = _scrollAmount * 10;
_direction = _direction + _scrollAmount;
_deployedItem setDir _direction;
_deployedItem setVariable [QGVAR(deployDirection_temp), _direction];
};
true

View File

@ -22,11 +22,17 @@ private _type = typeOf _vehicle;
private _config = configOf _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 _hasCargoPublic = _item getVariable QGVAR(hasCargo);
private _hasCargoPublicDefined = !isNil "_canLoadPublic";
if (_hasCargoPublicDefined && {!(_hasCargoPublic isEqualType false)}) then {
WARNING_4("%1[%2] - Variable %3 is %4 - Should be bool",_item,_type,QGVAR(hasCargo),_hasCargoPublic);
};
private _hasCargoConfig = getNumber (_config >> QGVAR(hasCargo)) == 1; private _hasCargoConfig = getNumber (_config >> QGVAR(hasCargo)) == 1;
// Nothing to do here if vehicle has no cargo space // Nothing to do here if vehicle has no cargo space
if !(_hasCargoConfig || _hasCargoPublic) exitWith {}; if !((_hasCargoPublicDefined && {_hasCargoPublic in [true, 1]}) || {!_hasCargoPublicDefined && {_hasCargoConfig}}) exitWith {};
// Check if cargo is in cargo holder types (checked when trying to search for loadable objects) // Check if cargo is in cargo holder types (checked when trying to search for loadable objects)
private _addCargoType = GVAR(cargoHolderTypes) findIf {_type isKindOf _x} == -1; private _addCargoType = GVAR(cargoHolderTypes) findIf {_type isKindOf _x} == -1;

View File

@ -25,6 +25,9 @@ if (GVAR(interactionParadrop)) then {
(_display displayCtrl 12) ctrlSetText LLSTRING(paradropButton); (_display displayCtrl 12) ctrlSetText LLSTRING(paradropButton);
}; };
// Disable deploy option if paradropping or in Zeus
(_display displayCtrl 13) ctrlEnable (GVAR(enableDeploy) && !GVAR(interactionParadrop) && {isNull curatorCamera});
[{ [{
params ["_vehicle", "_pfhID"]; params ["_vehicle", "_pfhID"];
@ -33,7 +36,6 @@ if (GVAR(interactionParadrop)) then {
private _display = uiNamespace getVariable QGVAR(menuDisplay); private _display = uiNamespace getVariable QGVAR(menuDisplay);
if (isNil "_display") exitWith { if (isNil "_display") exitWith {
GVAR(interactionVehicle) = nil;
GVAR(interactionParadrop) = nil; GVAR(interactionParadrop) = nil;
_pfhID call CBA_fnc_removePerFrameHandler; _pfhID call CBA_fnc_removePerFrameHandler;
@ -41,18 +43,18 @@ if (GVAR(interactionParadrop)) then {
// Close menu if in invalid state // Close menu if in invalid state
if ( if (
!alive _vehicle || !alive ACE_player ||
{!alive _vehicle} ||
{locked _vehicle >= 2} || {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) {!(_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)
{ {
isNull findDisplay 312 && // if in Zeus, ignore the following checks isNull curatorCamera && // if in Zeus, ignore the checks that follow
{([ACE_player, _vehicle] call EFUNC(interaction,getInteractionDistance)) >= MAX_LOAD_DISTANCE} && {([ACE_player, _vehicle] call EFUNC(interaction,getInteractionDistance)) >= MAX_LOAD_DISTANCE} &&
{(vehicle ACE_player) != _vehicle} {(vehicle ACE_player) != _vehicle}
} }
) exitWith { ) exitWith {
closeDialog 0; closeDialog 0;
GVAR(interactionVehicle) = nil;
GVAR(interactionParadrop) = nil; GVAR(interactionParadrop) = nil;
_pfhID call CBA_fnc_removePerFrameHandler; _pfhID call CBA_fnc_removePerFrameHandler;

View File

@ -0,0 +1,86 @@
#include "..\script_component.hpp"
/*
* Author: Garth 'L-H' de Wet, Ruthberg, commy2, Smith
* Starts the deploy process for unloading an object.
*
* Arguments:
* 0: Unit deploying <OBJECT>
*
* Return Value:
* None
*
* Example:
* player call ace_cargo_fnc_startDeploy
*
* Public: No
*/
// Deny creating preview item as it will destroy player vehicle instantly by collision
if (GVAR(interactionParadrop)) exitWith {};
params ["_unit"];
// Don't allow deploying if already deploying
if (_unit getVariable [QGVAR(isDeploying), false]) exitWith {};
// This can be an object or a classname string
private _item = call FUNC(getSelectedItem);
if (isNil "_item") exitWith {};
// Close opened cargo menu
closeDialog 0;
GVAR(selectedItem) = _item;
private _classname = _item;
if (_classname isEqualType objNull) then {
_classname = typeOf _classname;
};
// Prevent the placing unit from running
[_unit, "forceWalk", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
[_unit, "blockThrow", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
// Create a local preview object
private _itemPreviewObject = createVehicleLocal [_classname, [0, 0, 0], [], 0, "CAN_COLLIDE"];
GVAR(itemPreviewObject) = _itemPreviewObject;
// Prevent collisions with object
_itemPreviewObject disableCollisionWith _unit;
_itemPreviewObject enableSimulation false;
_itemPreviewObject setMass 1e-12;
// Detect radius of zone where collision can damage the player
private _itemPreviewObjectRadius = 1 max ((boundingBoxReal [_itemPreviewObject, "FireGeometry"]) select 2);
// Add height offset of model
private _offset = ((_itemPreviewObject modelToWorldVisual [0, 0, 0]) select 2) - ((_unit modelToWorldVisual [0, 0, 0]) select 2) + 1;
// Attach object
_itemPreviewObject attachTo [_unit, [0, 1.5 * _itemPreviewObjectRadius, _offset]];
// PFH that runs while the deployment is in progress
GVAR(deployPFH) = [{
(_this select 0) params ["_unit", "_vehicle", "_item", "_itemPreviewObject"];
if !(
!isNull _itemPreviewObject &&
{[_item, _vehicle, _unit, false, true] call FUNC(canUnloadItem)} // don't check for a suitable unloading position when deploying
) exitWith {
_unit call FUNC(deployCancel);
};
}, 0.5, [_unit, GVAR(interactionVehicle), _item, _itemPreviewObject]] call CBA_fnc_addPerFrameHandler;
// Add mouse button action and hint
[LLSTRING(unloadObject), localize "STR_DISP_CANCEL", LLSTRING(scrollAction)] call EFUNC(interaction,showMouseHint);
_unit setVariable [QGVAR(deploy), [
_unit, "DefaultAction",
{GVAR(deployPFH) != -1},
{[_this select 0] call FUNC(deployConfirm)}
] call EFUNC(common,addActionEventHandler)];
_unit setVariable [QGVAR(isDeploying), true, true];

View File

@ -15,18 +15,8 @@
* Public: No * Public: No
*/ */
disableSerialization;
private _display = uiNamespace getVariable QGVAR(menuDisplay);
if (isNil "_display") exitWith {};
private _loaded = GVAR(interactionVehicle) getVariable [QGVAR(loaded), []];
if (_loaded isEqualTo []) exitWith {};
// This can be an object or a classname string // This can be an object or a classname string
private _item = _loaded param [lbCurSel (_display displayCtrl 100), nil]; private _item = call FUNC(getSelectedItem);
if (isNil "_item") exitWith {}; if (isNil "_item") exitWith {};
@ -60,11 +50,11 @@ if (GVAR(interactionParadrop)) exitWith {
}, },
format [LLSTRING(unloadingItem), [_item, true] call FUNC(getNameItem), getText (configOf GVAR(interactionVehicle) >> "displayName")], format [LLSTRING(unloadingItem), [_item, true] call FUNC(getNameItem), getText (configOf GVAR(interactionVehicle) >> "displayName")],
{ {
(_this select 0) params ["", "_target"]; (_this select 0) params ["", "_vehicle"];
if ((acos ((vectorUp _target) select 2)) > 30) exitWith {false}; // check flight level if ((acos ((vectorUp _vehicle) select 2)) > 30) exitWith {false}; // check flight level
if (((getPos _target) select 2) < 25) exitWith {false}; // check height if (((getPos _vehicle) select 2) < 25) exitWith {false}; // check height
if ((speed _target) < -5) exitWith {false}; // check reverse if ((speed _vehicle) < -5) exitWith {false}; // check reverse
true true
}, },
@ -74,7 +64,7 @@ if (GVAR(interactionParadrop)) exitWith {
}; };
// If in zeus // If in zeus
if (!isNull findDisplay 312) exitWith { if (!isNull curatorCamera) exitWith {
// Do not check distance to unit, but do check for valid position // Do not check distance to unit, but do check for valid position
if !([_item, GVAR(interactionVehicle), objNull, true] call FUNC(canUnloadItem)) exitWith { if !([_item, GVAR(interactionVehicle), objNull, true] call FUNC(canUnloadItem)) exitWith {
[[LSTRING(unloadingFailed), [_item, true] call FUNC(getNameItem)], 3] call EFUNC(common,displayTextStructured); [[LSTRING(unloadingFailed), [_item, true] call FUNC(getNameItem)], 3] call EFUNC(common,displayTextStructured);

View File

@ -7,6 +7,9 @@
* 0: Item to be unloaded <STRING> or <OBJECT> (default: "") * 0: Item to be unloaded <STRING> or <OBJECT> (default: "")
* 1: Holder object (vehicle) <OBJECT> (default: objNull) * 1: Holder object (vehicle) <OBJECT> (default: objNull)
* 2: Unloader <OBJECT> (default: objNull) * 2: Unloader <OBJECT> (default: objNull)
* 3: Deploy parameters <ARRAY> (default: [])
* - 0: Position AGL <ARRAY>
* - 1: Direction <NUMBER>
* *
* Return Value: * Return Value:
* Object unloaded <BOOL> * Object unloaded <BOOL>
@ -17,8 +20,10 @@
* Public: Yes * Public: Yes
*/ */
params [["_item", "", [objNull, ""]], ["_vehicle", objNull, [objNull]], ["_unloader", objNull, [objNull]]]; params [["_item", "", [objNull, ""]], ["_vehicle", objNull, [objNull]], ["_unloader", objNull, [objNull]], ["_deploy", []]];
TRACE_3("params",_item,_vehicle,_unloader); _deploy params ["_emptyPosAGL", "_direction"];
TRACE_4("params",_item,_vehicle,_unloader,_deploy);
// Get config sensitive case name // Get config sensitive case name
if (_item isEqualType "") then { if (_item isEqualType "") then {
@ -41,9 +46,18 @@ if (_itemSize < 0) exitWith {
false // return false // return
}; };
// This covers testing vehicle stability and finding a safe position private _deployed = _deploy isNotEqualTo [];
private _emptyPosAGL = [_vehicle, _item, _unloader] call EFUNC(common,findUnloadPosition);
TRACE_1("findUnloadPosition",_emptyPosAGL); if (!_deployed) then {
// This covers testing vehicle stability and finding a safe position
for "_i" from 1 to 3 do {
_emptyPosAGL = [_vehicle, _item, _unloader] call EFUNC(common,findUnloadPosition);
if (_emptyPosAGL isNotEqualTo []) exitWith {};
};
TRACE_1("findUnloadPosition",_emptyPosAGL);
};
if (_emptyPosAGL isEqualTo []) exitWith { if (_emptyPosAGL isEqualTo []) exitWith {
// Display text saying there are no safe places to exit the vehicle // Display text saying there are no safe places to exit the vehicle
@ -67,9 +81,12 @@ private _object = _item;
if (_object isEqualType objNull) then { if (_object isEqualType objNull) then {
detach _object; detach _object;
// hideObjectGlobal must be executed before setPos to ensure light objects are rendered correctly // If player unloads via deployment, set direction first, then unload
// Do both on server to ensure they are executed in the correct order if (_deployed) then {
[QGVAR(serverUnload), [_object, _emptyPosAGL]] call CBA_fnc_serverEvent; [QGVAR(setDirAndUnload), [_object, _emptyPosAGL, _direction], _object] call CBA_fnc_targetEvent;
} else {
[QGVAR(serverUnload), [_object, _emptyPosAGL]] call CBA_fnc_serverEvent;
};
if (["ace_zeus"] call EFUNC(common,isModLoaded)) then { if (["ace_zeus"] call EFUNC(common,isModLoaded)) then {
// Get which curators had this object as editable // Get which curators had this object as editable
@ -81,6 +98,12 @@ if (_object isEqualType objNull) then {
}; };
} else { } else {
_object = createVehicle [_item, _emptyPosAGL, [], 0, "NONE"]; _object = createVehicle [_item, _emptyPosAGL, [], 0, "NONE"];
// If player unloads via deployment, set direction. Must happen before setPosASL command according to wiki
if (_deployed) then {
_object setDir _direction;
};
_object setPosASL (AGLtoASL _emptyPosAGL); _object setPosASL (AGLtoASL _emptyPosAGL);
[QEGVAR(common,fixCollision), _object] call CBA_fnc_localEvent; [QEGVAR(common,fixCollision), _object] call CBA_fnc_localEvent;
@ -88,7 +111,9 @@ if (_object isEqualType objNull) then {
}; };
// Dragging integration // Dragging integration
[_unloader, _object] call FUNC(unloadCarryItem); if (!_deployed) then {
[_unloader, _object] call FUNC(unloadCarryItem);
};
// Invoke listenable event // Invoke listenable event
["ace_cargoUnloaded", [_object, _vehicle, "unload"]] call CBA_fnc_globalEvent; ["ace_cargoUnloaded", [_object, _vehicle, "unload"]] call CBA_fnc_globalEvent;

View File

@ -6,7 +6,7 @@ private _category = [ELSTRING(main,Category_Logistics), LSTRING(openMenu)];
[LSTRING(ModuleSettings_enable), LSTRING(ModuleSettings_enable_Description)], [LSTRING(ModuleSettings_enable), LSTRING(ModuleSettings_enable_Description)],
_category, _category,
true, true,
true, 1,
{[QGVAR(enable), _this] call EFUNC(common,cbaSettings_settingChanged)} {[QGVAR(enable), _this] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting; ] call CBA_fnc_addSetting;
@ -16,7 +16,7 @@ private _category = [ELSTRING(main,Category_Logistics), LSTRING(openMenu)];
[LSTRING(loadTimeCoefficient), LSTRING(loadTimeCoefficient_description)], [LSTRING(loadTimeCoefficient), LSTRING(loadTimeCoefficient_description)],
_category, _category,
[0, 10, 5, 1], [0, 10, 5, 1],
true, 1,
{[QGVAR(loadTimeCoefficient), _this, true] call EFUNC(common,cbaSettings_settingChanged)} {[QGVAR(loadTimeCoefficient), _this, true] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting; ] call CBA_fnc_addSetting;
@ -26,7 +26,7 @@ private _category = [ELSTRING(main,Category_Logistics), LSTRING(openMenu)];
[LSTRING(paradropTimeCoefficent), LSTRING(paradropTimeCoefficent_description)], [LSTRING(paradropTimeCoefficent), LSTRING(paradropTimeCoefficent_description)],
_category, _category,
[0, 10, 2.5, 1], [0, 10, 2.5, 1],
true, 1,
{[QGVAR(paradropTimeCoefficent), _this, true] call EFUNC(common,cbaSettings_settingChanged)} {[QGVAR(paradropTimeCoefficent), _this, true] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting; ] call CBA_fnc_addSetting;
@ -36,26 +36,36 @@ private _category = [ELSTRING(main,Category_Logistics), LSTRING(openMenu)];
[LSTRING(openAfterUnload), LSTRING(openAfterUnload_description)], [LSTRING(openAfterUnload), LSTRING(openAfterUnload_description)],
_category, _category,
[[0, 1, 2, 3], [ELSTRING(common,never), LSTRING(unloadObject), LSTRING(paradropButton), ELSTRING(common,both)], 0], [[0, 1, 2, 3], [ELSTRING(common,never), LSTRING(unloadObject), LSTRING(paradropButton), ELSTRING(common,both)], 0],
false, 0,
{[QGVAR(openAfterUnload), _this, true] call EFUNC(common,cbaSettings_settingChanged)} {[QGVAR(openAfterUnload), _this, true] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting; ] call CBA_fnc_addSetting;
[
QGVAR(enableRename),
"CHECKBOX",
[LSTRING(ModuleSettings_enableRename), LSTRING(ModuleSettings_enableRename_Description)],
_category,
true,
false,
{[QGVAR(enableRename), _this, true] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting;
[ [
QGVAR(carryAfterUnload), QGVAR(carryAfterUnload),
"CHECKBOX", "CHECKBOX",
[LSTRING(carryAfterUnload), LSTRING(carryAfterUnload_description)], [LSTRING(carryAfterUnload), LSTRING(carryAfterUnload_description)],
_category, _category,
true, true,
false, 0,
{[QGVAR(carryAfterUnload), _this] call EFUNC(common,cbaSettings_settingChanged)} {[QGVAR(carryAfterUnload), _this] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting; ] call CBA_fnc_addSetting;
[
QGVAR(enableDeploy),
"CHECKBOX",
[LSTRING(enableDeploy), LSTRING(enableDeploy_description)],
_category,
true,
1,
{[QGVAR(enableDeploy), _this] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting;
[
QGVAR(enableRename),
"CHECKBOX",
[LSTRING(ModuleSettings_enableRename), LSTRING(ModuleSettings_enableRename_Description)],
_category,
true,
0,
{[QGVAR(enableRename), _this, true] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting;

View File

@ -17,7 +17,7 @@ class GVAR(menu) {
}; };
class CenterBackground: HeaderBackground { class CenterBackground: HeaderBackground {
y = "2.1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + (safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))/2)"; y = "2.1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + (safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))/2)";
h = "13.1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; h = "14.2 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)";
text = "#(argb,8,8,3)color(0,0,0,0.8)"; text = "#(argb,8,8,3)color(0,0,0,0.8)";
colorText[] = {0, 0, 0, "(profilenamespace getVariable ['GUI_BCG_RGB_A',0.9])"}; 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])"};
@ -72,7 +72,7 @@ class GVAR(menu) {
idc = 11; idc = 11;
x = "13.1 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX + (safezoneW - ((safezoneW / safezoneH) min 1.2))/2)"; x = "13.1 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX + (safezoneW - ((safezoneW / safezoneH) min 1.2))/2)";
y = "14.1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + (safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))/2)"; y = "14.1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + (safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))/2)";
w = "5 * (((safezoneW / safezoneH) min 1.2) / 40)"; w = "6 * (((safezoneW / safezoneH) min 1.2) / 40)";
h = "1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; h = "1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)";
size = "(((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 1)"; size = "(((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 1)";
SizeEx = "(((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 0.7)"; SizeEx = "(((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 0.7)";
@ -96,8 +96,15 @@ class GVAR(menu) {
class btnUnload: btnCancel { class btnUnload: btnCancel {
text = CSTRING(unloadObject); text = CSTRING(unloadObject);
idc = 12; idc = 12;
x = "20.9 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX + (safezoneW - ((safezoneW / safezoneH) min 1.2))/2)"; x = "19.9 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX + (safezoneW - ((safezoneW / safezoneH) min 1.2))/2)";
action = QUOTE(ACE_player call FUNC(startUnload)); action = QUOTE(ACE_player call FUNC(startUnload));
}; };
class btnPlace: btnUnload {
text = CSTRING(deployObject);
idc = 13;
y = "15.2 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + (safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))/2)";
action = QUOTE(ACE_player call FUNC(startDeploy));
colorDisabled[] = {0.25, 0.25, 0.25, 1};
};
}; };
}; };

View File

@ -33,6 +33,40 @@
<Chinesesimp>卸载</Chinesesimp> <Chinesesimp>卸载</Chinesesimp>
<Turkish>Boşalt</Turkish> <Turkish>Boşalt</Turkish>
</Key> </Key>
<Key ID="STR_ACE_Cargo_deployObject">
<English>Deploy</English>
</Key>
<Key ID="STR_ACE_Cargo_ScrollAction">
<English>Raise/Lower | (Ctrl + Scroll) Rotate</English>
<German>Heben/Senken | (Strg + Scrollen) Drehen</German>
<Italian>Alza/Abbassa | (Ctrl + Rotellina) Ruota</Italian>
<French>Lever/Baisser | (Ctrl + Scroll) Rotation</French>
<Japanese>上げる/下げる | (Ctrl + スクロール) 回転</Japanese>
<Czech>Zvednout/Snížit | (Ctrl + Kolečko myši) Otáčet</Czech>
<Russian>Поднять/опустить | (Ctrl + Скролл) Крутить</Russian>
<Polish>Wyżej/niżej | (Ctrl + Kółko myszy) obracanie</Polish>
<Turkish>Yükselt/Alçalt | (Ctrl + Tekerlek) Döndür</Turkish>
<Spanish>Subir/Bajar | (Ctrl + Scroll) Rotar</Spanish>
<Chinesesimp>抬起/放低 |Ctrl + 鼠标滚轮)旋转</Chinesesimp>
<Korean>높이기/내리기 | (컨트롤 + 스크롤) 회전</Korean>
<Portuguese>Subir/Abaixar | (Ctrl + Scroll) Rotacionar</Portuguese>
</Key>
<Key ID="STR_ACE_Cargo_BlockedAction">
<English>Blocked</English>
<Spanish>Obstruido</Spanish>
<Portuguese>Bloqueado</Portuguese>
<Russian>Заблокировано</Russian>
<Czech>Blokováno</Czech>
<Polish>Zablokowany</Polish>
<Italian>Bloccato</Italian>
<German>Blockiert</German>
<French>Bloqué</French>
<Japanese>取り付け不可</Japanese>
<Korean>막힘</Korean>
<Chinesesimp>断开</Chinesesimp>
<Chinese>斷開</Chinese>
<Turkish>Bloke Edilmiş</Turkish>
</Key>
<Key ID="STR_ACE_Cargo_renamedObject"> <Key ID="STR_ACE_Cargo_renamedObject">
<English>Renamed to:&lt;br/&gt;%1</English> <English>Renamed to:&lt;br/&gt;%1</English>
<Japanese>名前を次に変更:&lt;br/&gt;%1</Japanese> <Japanese>名前を次に変更:&lt;br/&gt;%1</Japanese>
@ -528,5 +562,11 @@
<French>Active si les éléments de cargaison sont portés ou traînés après le déchargement.</French> <French>Active si les éléments de cargaison sont portés ou traînés après le déchargement.</French>
<Portuguese>Controla se os itens de carga são carregados ou arrastados após a descarga.</Portuguese> <Portuguese>Controla se os itens de carga são carregados ou arrastados após a descarga.</Portuguese>
</Key> </Key>
<Key ID="STR_ACE_Cargo_enableDeploy">
<English>Enable deploy</English>
</Key>
<Key ID="STR_ACE_Cargo_enableDeploy_description">
<English>Controls whether cargo items can be unloaded via the deploy method.</English>
</Key>
</Package> </Package>
</Project> </Project>