Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions addons/common/CfgVehicles.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ class CfgVehicles {
};
};*/

class Animal_Base_F;
// createVehicleLocal CAManBase units spams to RPT:
// "Tried to create local-only container with backpacks, that does not work in multiplayer"
// animals have clean RPT
class GVAR(seatHolder): Animal_Base_F {
scope = 1;
model = "\A3\Animals_F\mosquito.p3d";
};

// += needs a non inherited entry in that class, otherwise it simply overwrites
//#include <DefaultItems.hpp>
class Logic;
Expand Down
1 change: 1 addition & 0 deletions addons/common/XEH_PREP.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ PREP(isModLoaded);
PREP(isPlayer);
PREP(isSwimming);
PREP(lightIntensityFromObject);
PREP(loadDeadPerson);
PREP(loadPerson);
PREP(loadPersonLocal);
PREP(moduleCheckPBOs);
Expand Down
17 changes: 17 additions & 0 deletions addons/common/XEH_postInit.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,23 @@ if (isServer) then {
["ace_loadPersonEvent", LINKFUNC(loadPersonLocal)] call CBA_fnc_addEventHandler;
["ace_unloadPersonEvent", LINKFUNC(unloadPersonLocal)] call CBA_fnc_addEventHandler;

[QGVAR(loadDeadPerson), LINKFUNC(loadDeadPerson)] call CBA_fnc_addEventHandler;
[QGVAR(deadPersonLoaded), {
params ["_unit"];
TRACE_5("deadPersonLoaded event",_unit,isAwake _unit,local _unit,typeOf objectParent _unit,local objectParent _unit);
if (local _unit) exitWith {}; // no awake problems with local unit
if (isAwake _unit) then {_unit awake false};
// Unit may be set to awake multiple times after moveIn; keep it in non-awake state
private _pfeh = [{
params ["_unit"];
if (isAwake _unit) then {
TRACE_5("deadPersonLoaded pfh",_unit,isAwake _unit,local _unit,typeOf objectParent _unit,local objectParent _unit);
_unit awake false;
};
}, 0, _unit] call CBA_fnc_addPerFrameHandler;
[{_this call CBA_fnc_removePerFrameHandler}, _pfeh, 2] call CBA_fnc_waitAndExecute;
}] call CBA_fnc_addEventHandler;

[QGVAR(lockVehicle), {
_this setVariable [QGVAR(lockStatus), locked _this];
_this lock 2;
Expand Down
131 changes: 131 additions & 0 deletions addons/common/functions/fnc_loadDeadPerson.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#include "..\script_component.hpp"
/*
* Author: Dystopian
* Loads dead person into most suitable seat in vehicle.
*
* Arguments:
* 0: Unit <OBJECT>
* 1: Vehicle <OBJECT>
*
* Return Value:
* None
*
* Example:
* [cursorObject, vehicle player] call ace_common_fnc_loadDeadPerson
*
* Public: No
*/

params ["_unit", "_vehicle"];
TRACE_5("loadDeadPerson",_unit,_vehicle,typeOf _vehicle,local _unit,local _vehicle);

if (!local _vehicle) exitWith {ERROR_4("loadDeadPerson vehicle not local _unit=%1[%2] _vehicle=%3[%4]",_unit,typeOf _unit,_vehicle,typeOf _vehicle)};

#define PRIORITY_NONE -1
#define PRIORITY_DRIVER 0
#define PRIORITY_GUNNER 1
#define PRIORITY_COMMANDER 2
#define PRIORITY_TURRET_NO_FFV 3
#define PRIORITY_TURRET_FFV 4
#define PRIORITY_TURRET_EMPTY 5
#define PRIORITY_CARGO 6

// Determine highest-priority available seats
private _emptySeats = fullCrew [_vehicle, "", true] select {isNull (_x select 0)};
private _vehicleConfig = configOf _vehicle;
private _bestSeatsPriority = PRIORITY_NONE;
private _bestSeatsRole = "";
private _bestSeatsParams = [];
{
_x params ["", "_role", "_cargoIndex", "_turretPath", "_isPersonTurret"];
private _priority = PRIORITY_NONE;
switch (_role) do {
case "driver": {
if (
lockedDriver _vehicle
|| {unitIsUAV _vehicle}
|| {getNumber (_vehicleConfig >> "hasDriver") < 1}
|| {getNumber (_vehicleConfig >> "ejectDeadDriver") > 0}
) then {continue};
_priority = PRIORITY_DRIVER;
};
case "cargo": {
if (
_vehicle lockedCargo _cargoIndex
|| {getNumber (_vehicleConfig >> "ejectDeadCargo") > 0}
) then {continue};
_priority = PRIORITY_CARGO;
};
default {
private _turretConfig = [_vehicleConfig, _turretPath] call CBA_fnc_getTurret;
if (
_vehicle lockedTurret _turretPath
|| {getNumber (_turretConfig >> "ejectDeadGunner") > 0}
|| {_role == "gunner" && {unitIsUAV _vehicle}}
) then {continue};
_priority = switch (_role) do {
case "gunner": {PRIORITY_GUNNER};
case "commander": {PRIORITY_COMMANDER};
case "turret": {
if (_isPersonTurret) then {PRIORITY_TURRET_FFV}
else {[PRIORITY_TURRET_NO_FFV, PRIORITY_TURRET_EMPTY] select (getText (_turretConfig >> "gun") == "")}
};
};
};
};
TRACE_2("emptySeat",_x,_priority);
if (_priority > _bestSeatsPriority) then {
_bestSeatsPriority = _priority;
_bestSeatsRole = _role;
_bestSeatsParams = [[_cargoIndex, _turretPath]];
continue;
};
if (_priority == _bestSeatsPriority) then {
_bestSeatsParams pushBack [_cargoIndex, _turretPath];
};
} forEach _emptySeats;

if (_bestSeatsPriority == PRIORITY_NONE) exitWith {
TRACE_2("No seats found",_emptySeats apply {_x select [ARR_2(1,4)]},fullCrew _vehicle apply {_x select [ARR_2(0,5)]});
};

TRACE_3("emptySeats",_bestSeatsPriority,_bestSeatsRole,_bestSeatsParams);

// Probe seat positions using temporary units to identify exact seat
private _seatHolders = [];
private _moveInAnyPositions = [toUpper _bestSeatsRole];
private _remainingEmptyPositions = _vehicle emptyPositions _moveInAnyPositions; // Guard against infinite loop
while {_remainingEmptyPositions > 0} do {
private _seatHolder = createVehicleLocal [QGVAR(seatHolder), [0,0,0], [], 0, "CAN_COLLIDE"];
private _seatHolderMoveSuccess = _seatHolder moveInAny [_vehicle, _moveInAnyPositions];
private _seatHolderSeat = fullCrew _vehicle select {_x select 0 == _seatHolder};
if (!_seatHolderMoveSuccess || {_seatHolderSeat isEqualTo []}) then {
ERROR_8("moveInAny holder failed _unit=%1[%2] _vehicle=%3[%4] _seatHolder=%5 _seatHolderMoveSuccess=%6 fullCrew=%7 %8",_unit,typeOf _unit,_vehicle,typeOf _vehicle,_seatHolder,_seatHolderMoveSuccess,fullCrew _vehicle apply {_x select [ARR_2(0,5)]},__FILE__);
_vehicle deleteVehicleCrew _seatHolder;
if (!isNull _seatHolder) then { // failsafe
moveOut _seatHolder;
deleteVehicle _seatHolder;
};
break;
};
_seatHolderSeat select 0 params ["", "_role", "_cargoIndex", "_turretPath"];
if (_role == _bestSeatsRole && {[_cargoIndex, _turretPath] in _bestSeatsParams}) then {
_vehicle deleteVehicleCrew _seatHolder;
private _unitMoveSuccess = _unit moveInAny [_vehicle, _moveInAnyPositions];
if (_unitMoveSuccess) then {
[QGVAR(deadPersonLoaded), _unit] call CBA_fnc_globalEvent; // Ensure dead unit stays unconscious on all clients
} else {
ERROR_8("moveInAny unit failed _unit=%1[%2] _vehicle=%3[%4] _seatHolder=%5 _seatHolderSeat=%6 fullCrew=%7 %8",_unit,typeOf _unit,_vehicle,typeOf _vehicle,_seatHolder,_seatHolderSeat,fullCrew _vehicle apply {_x select [ARR_2(0,5)]},__FILE__);
};
TRACE_4("seat",_remainingEmptyPositions,_role,_cargoIndex,_turretPath);
break;
};
TRACE_4("seatHolder",_remainingEmptyPositions,_role,_cargoIndex,_turretPath);
_seatHolders pushBack _seatHolder;
DEC(_remainingEmptyPositions);
};

// Cleanup all temporary seat holders
{
_vehicle deleteVehicleCrew _x;
} forEach _seatHolders;
8 changes: 7 additions & 1 deletion addons/common/functions/fnc_loadPerson.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ if (isNull _vehicle) then {
_vehicle = ([_unit] call FUNC(nearestVehiclesFreeSeat)) param [0, objNull];
};

if (!isNull _vehicle) then {
if (isNull _vehicle) exitWith {objNull};

if (alive _unit) then {
switch (true) do {
case ((crew _vehicle isEqualTo []) && {side group _caller != side group _unit}): {
[_unit, true, GROUP_SWITCH_ID, side group _caller] call FUNC(switchToGroupSide);
Expand All @@ -43,6 +45,10 @@ if (!isNull _vehicle) then {

TRACE_5("sending ace_loadPersonEvent",_unit,_vehicle,_caller,_preferredSeats,_reverseFill);
["ace_loadPersonEvent", [_unit, _vehicle, _caller, _preferredSeats, _reverseFill], _unit] call CBA_fnc_targetEvent;
} else {
// vehicle must be local
TRACE_2("sending loadDeadPerson event",_unit,_vehicle);
[QGVAR(loadDeadPerson), [_unit, _vehicle], _vehicle] call CBA_fnc_targetEvent;
};

_vehicle
41 changes: 29 additions & 12 deletions addons/common/functions/fnc_nearestVehiclesFreeSeat.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,44 @@
* 0: Unit <OBJECT>
* 1: Distance <NUMBER> (default: 10)
* 2: Restricted to cargo only <BOOL> (default: false)
* 3: Override vehicle to check instead of distance search <OBJECT> (default: objNull)
*
* Return Value:
* Nearest vehicles with a free seat <ARRAY>
*
* Example:
* [cursorObject] call ace_common_fnc_nearestVehiclesFreeSeat
*
* Public: Yes
* Public: No
*/

params ["_unit", ["_distance", 10], ["_cargoOnly", false]];
params ["_unit", ["_distance", 10], ["_cargoOnly", false], ["_overrideVehicle", objNull]];

private _nearVehicles = if (isNull _overrideVehicle) then {
nearestObjects [_unit, ["Car", "Air", "Tank", "Ship_F", "Pod_Heli_Transport_04_crewed_base_F"], _distance]
} else {
[_overrideVehicle]
};

private _nearVehicles = nearestObjects [_unit, ["Car", "Air", "Tank", "Ship_F", "Pod_Heli_Transport_04_crewed_base_F"], _distance];
_nearVehicles select {
// Filter cargo seats that will eject unconscious units (e.g. quad bike)
private _canSitInCargo = (_unit call EFUNC(common,isAwake)) || {(getNumber (configOf _x >> "ejectDeadCargo")) == 0};
((fullCrew [_x, "", true]) findIf {
_x params ["_body", "_role", "_cargoIndex"];
(isNull _body) // seat empty
&& {_role != "DRIVER"} // not driver seat
&& {_canSitInCargo || {_cargoIndex == -1}} // won't be ejected (uncon)
&& {(!_cargoOnly) || {_cargoIndex != -1}} // not restricted (captive)
}) > -1
private _vehicle = _x;
alive _vehicle
&& {locked _vehicle < 2}
&& {simulationEnabled _vehicle}
&& {vectorUp _vehicle select 2 > 0.3} // flipped vehicles
&& {
// Filter cargo seats that will eject unconscious units (e.g. quad bike)
private _canSitInCargo = (_unit call EFUNC(common,isAwake)) || {(getNumber (configOf _vehicle >> "ejectDeadCargo")) == 0};
((fullCrew [_vehicle, "", true]) findIf {
_x params ["_body", "_role", "_cargoIndex"];
(isNull _body) // seat empty
&& {
_role != "DRIVER" // not driver seat
|| {!alive _unit} // dead unit in medical
|| {_unit isKindOf QEGVAR(dragging,clone)} // dead unit in dragging
}
&& {_canSitInCargo || {_cargoIndex == -1}} // won't be ejected (uncon)
&& {(!_cargoOnly) || {_cargoIndex != -1}} // not restricted (captive)
}) > -1
}
}
3 changes: 2 additions & 1 deletion addons/dragging/functions/fnc_carryObjectPFH.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ if (
!isNull _cursorObject && {[_unit, _cursorObject, ["isNotCarrying"]] call EFUNC(common,canInteractWith)} &&
{
if (_target isKindOf "CAManBase") then {
(_unit distance _cursorObject <= MAX_LOAD_DISTANCE_MAN) && {[_cursorObject, 0, true] call EFUNC(common,nearestVehiclesFreeSeat) isNotEqualTo []}
[_unit, _cursorObject] call EFUNC(interaction,getInteractionDistance) < MAX_LOAD_DISTANCE_MAN
&& {[_target, nil, nil, _cursorObject] call EFUNC(common,nearestVehiclesFreeSeat) isEqualTo [_cursorObject]}
} else {
["ace_cargo"] call EFUNC(common,isModLoaded) &&
{EGVAR(cargo,enable)} &&
Expand Down
13 changes: 9 additions & 4 deletions addons/dragging/functions/fnc_dropObject_carry.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,15 @@ _target setVariable [QGVAR(carryDirection_temp), nil];
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 {
if (
_tryLoad
&& {_target isKindOf "CAManBase"}
&& {[_unit, _cursorObject] call EFUNC(interaction,getInteractionDistance) < MAX_LOAD_DISTANCE_MAN}
) then {
// can't search nearest vehicles because target position can be desynced ATM
private _vehicles = [_target, nil, nil, _cursorObject] call EFUNC(common,nearestVehiclesFreeSeat);

if (_vehicles isEqualTo [_cursorObject]) then {
if (GETEGVAR(medical,enabled,false)) then {
[_unit, _target, _cursorObject] call EFUNC(medical_treatment,loadUnit);
} else {
Expand Down
2 changes: 1 addition & 1 deletion addons/dragging/script_component.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

#include "\z\ace\addons\main\script_macros.hpp"

#define MAX_LOAD_DISTANCE_MAN 5
#define MAX_LOAD_DISTANCE_MAN 2

#define DRAG_ANIMATIONS ["amovpercmstpslowwrfldnon_acinpknlmwlkslowwrfldb_2", "amovpercmstpsraswpstdnon_acinpknlmwlksnonwpstdb_2", "amovpercmstpsnonwnondnon_acinpknlmwlksnonwnondb_2", "acinpknlmstpsraswrfldnon", "acinpknlmstpsnonwpstdnon", "acinpknlmstpsnonwnondnon", "acinpknlmwlksraswrfldb", "acinpknlmwlksnonwnondb", "ace_dragging_rifle_limpb", "ace_dragging", "ace_dragging_limpb", "ace_dragging_static", "ace_dragging_drop"]
#define CARRY_ANIMATIONS ["acinpercmstpsnonwnondnon", "acinpknlmstpsnonwnondnon_acinpercmrunsnonwnondnon"]
Expand Down
6 changes: 1 addition & 5 deletions addons/medical_treatment/functions/fnc_loadUnit.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ if (_patient call EFUNC(common,isBeingDragged)) then {
[_medic, _patient] call EFUNC(dragging,dropObject);
};

if (!alive _patient) exitWith {
[[LSTRING(CanNotLoadDead), _patient call EFUNC(common,getName)]] call EFUNC(common,displayTextStructured);
};

private _vehicle = [
_medic,
_patient,
Expand All @@ -48,7 +44,7 @@ if (isNull _vehicle) exitWith { TRACE_1("no vehicle found",_vehicle); };

[{
params ["_unit", "_vehicle"];
(alive _unit) && {alive _vehicle} && {(vehicle _unit) == _vehicle}
alive _vehicle && {(objectParent _unit) == _vehicle} // objectParent instead of vehicle is for dead units
}, {
params ["_unit", "_vehicle"];
TRACE_2("success",_unit,_vehicle);
Expand Down
17 changes: 0 additions & 17 deletions addons/medical_treatment/stringtable.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1950,23 +1950,6 @@
<Turkish>Bu kişi (% 1) uyanık ve yüklenemiyor</Turkish>
<Ukrainian>Боєць (%1) у свідомості і не може бути завантажений</Ukrainian>
</Key>
<Key ID="STR_ACE_Medical_Treatment_CanNotLoadDead">
<English>This person (%1) is dead and cannot be loaded</English>
<Czech>Tato osoba (%1) je mrtvá a nemůže být naložena</Czech>
<French>%1 est mort et ne peut être embarqué.</French>
<Spanish>Esta persona (%1) está muerta y no puede ser cargado</Spanish>
<Italian>Questa persona (%1) è morta e non può essere caricata.</Italian>
<Polish>Ta osoba (%1) jest martwa i nie może zostać załadowana</Polish>
<Portuguese>Esta pessoa (%1) está morta e não pode ser carregada</Portuguese>
<Russian>Боец (%1) мертв и не может быть погружен</Russian>
<German>Diese Person (%1) ist tot und kann nicht verladen werden</German>
<Korean>이 사람 (%1) 은(는) 사망하여 태우지 못합니다</Korean>
<Japanese>患者 (%1) は死亡しており、積み込めない</Japanese>
<Chinese>此人(%1)已死亡,无法被装载</Chinese>
<Chinesesimp>此人(%1)已死亡,无法被装载</Chinesesimp>
<Turkish>Bu kişi (%1) ölü ve yüklenemiyor</Turkish>
<Ukrainian>Боєць (%1) мертвий і не може бути завантажений</Ukrainian>
</Key>
<Key ID="STR_ACE_Medical_Treatment_Carry">
<English>Carry</English>
<Czech>Nést</Czech>
Expand Down
Loading