Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quickmount - Fix quickmount for vehicle interactions #10126

Merged
merged 2 commits into from
Jul 20, 2024
Merged
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
5 changes: 2 additions & 3 deletions addons/quickmount/XEH_postInitClient.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@

if (!hasInterface) exitWith {};

["ACE3 Movement", QGVAR(mount), [localize LSTRING(KeybindName), localize LSTRING(KeybindDescription)], "", {
["ACE3 Movement", QGVAR(mount), [LLSTRING(KeybindName), LLSTRING(KeybindDescription)], "", {
if (!dialog) then {
[] call FUNC(getInNearest);
call FUNC(getInNearest);
};
false
}] call CBA_fnc_addKeybind;
180 changes: 87 additions & 93 deletions addons/quickmount/functions/fnc_getInNearest.sqf
Original file line number Diff line number Diff line change
@@ -1,131 +1,125 @@
#include "..\script_component.hpp"
/*
* Author: Kingsley
* Mount the player in the vehicle they are directly looking at based on their distance.
* Mounts the player in the vehicle they are directly looking at based on their distance.
*
* Arguments:
* 0: Target <OBJECT>(Optional)
* 0: Target <OBJECT> (default: objNull)
*
* Return Value:
* None
*
* Example:
* [] call ace_quickmount_fnc_getInNearest;
* call ace_quickmount_fnc_getInNearest
*
* Public: No
*/

if (!GVAR(enabled) ||
if (
!GVAR(enabled) ||
{isNull ACE_player} ||
{vehicle ACE_player != ACE_player} ||
{!alive ACE_player} ||
{ACE_player getVariable ["ace_unconscious", false]}
{!isNull objectParent ACE_player} ||
{!(ACE_player call EFUNC(common,isAwake))}
) exitWith {};

params [["_interactionTarget", objNull, [objNull]]];
TRACE_1("getInNearest",_interactionTarget);
params [["_target", objNull, [objNull]]];
TRACE_1("getInNearest",_target);

private _start = ACE_player modelToWorldVisualWorld (ACE_player selectionPosition "pilot");
private _end = (_start vectorAdd (getCameraViewDirection ACE_player vectorMultiply GVAR(distance)));
private _objects = lineIntersectsSurfaces [_start, _end, ACE_player];
private _target = (_objects param [0, []]) param [2, objNull];

if ((isNull _target) && {alive _interactionTarget}) then {
_end = _start vectorAdd ((_start vectorFromTo (aimPos _interactionTarget)) vectorMultiply GVAR(distance));
_objects = lineIntersectsSurfaces [_start, _end, ACE_player];
TRACE_1("2nd ray attempt at interaction target aim pos",_objects);
// If target is not defined (e.g. keybind was used), search for valid target
if (isNull _target) then {
private _start = ACE_player modelToWorldVisualWorld (ACE_player selectionPosition "pilot");
private _end = (_start vectorAdd (getCameraViewDirection ACE_player vectorMultiply GVAR(distance)));
private _objects = lineIntersectsSurfaces [_start, _end, ACE_player];
_target = (_objects param [0, []]) param [2, objNull];
};

if (locked _target in [2,3] || {!simulationEnabled _target}) exitWith {
[localize LSTRING(VehicleLocked)] call EFUNC(common,displayTextStructured);
true
if (!alive _target) exitWith {};

if (locked _target >= 2 || {!simulationEnabled _target}) exitWith {
[LLSTRING(VehicleLocked)] call EFUNC(common,displayTextStructured);
};

TRACE_2("",_target,typeOf _target);

if (!isNull _target &&
{alive _target} &&
{{_target isKindOf _x} count ["Air","LandVehicle","Ship","StaticMortar"] > 0} &&
{([ACE_player, _target, ["isNotSwimming"]] call EFUNC(common,canInteractWith))} &&
{speed _target <= GVAR(speed)}
) then {
if (
(speed _target > GVAR(speed)) ||
{["Air", "LandVehicle", "Ship", "StaticMortar"] findIf {_target isKindOf _x} == -1} ||
{!([ACE_player, _target, ["isNotSwimming"]] call EFUNC(common,canInteractWith))}
) exitWith {};

private _seats = ["driver", "gunner", "commander", "cargo"];
private _sortedSeats = [_seats select GVAR(priority)];
_seats deleteAt GVAR(priority);
_sortedSeats append _seats;

if (GVAR(priority) > 3 || GVAR(priority) < 0) then {
GVAR(priority) = 0;
};
private _fullCrew = fullCrew [_target, "", true];

private _seats = ["Driver", "Gunner", "Commander", "Cargo"];
private _sortedSeats = [_seats select GVAR(priority)];
_seats deleteAt GVAR(priority);
_sortedSeats append _seats;
private _hasAction = false;
scopeName "SearchForSeat";

{
private _desiredRole = _x;

private _hasAction = false;
scopeName "SearchForSeat";
{
private _desiredRole = _x;
{
_x params ["_unit", "_role", "_cargoIndex", "_turretPath"];
if ((isNull _unit) || {!alive _unit}) then {
private _effectiveRole = toLowerANSI _role;

if ((_effectiveRole in ["driver", "gunner"]) && {unitIsUAV _target}) exitWith {}; // Ignoring UAV Driver/Gunner
if ((_effectiveRole == "driver") && {(getNumber (configOf _target >> "hasDriver")) == 0}) exitWith {}; // Ignoring Non Driver (static weapons)

// Seats can be locked independently of the main vehicle
if ((_role == "driver") && {lockedDriver _target}) exitWith {TRACE_1("lockedDriver",_x);};
if ((_cargoIndex >= 0) && {_target lockedCargo _cargoIndex}) exitWith {TRACE_1("lockedCargo",_x);};
if ((_turretPath isNotEqualTo []) && {_target lockedTurret _turretPath}) exitWith {TRACE_1("lockedTurret",_x);};

if (_effectiveRole == "turret") then {
private _turretConfig = [_target, _turretPath] call CBA_fnc_getTurret;
if (getNumber (_turretConfig >> "isCopilot") == 1) exitWith {
_effectiveRole = "driver";
};
if (
_cargoIndex >= 0 // FFV
|| {"" isEqualTo getText (_turretConfig >> "gun")} // turret without weapon
) exitWith {
_effectiveRole = "cargo";
};
_effectiveRole = "gunner"; // door gunners / 2nd turret
_x params ["_unit", "_role", "_cargoIndex", "_turretPath"];

if (!alive _unit) then {
private _effectiveRole = _role;

if ((_effectiveRole in ["driver", "gunner"]) && {unitIsUAV _target}) exitWith {}; // Ignoring UAV Driver/Gunner
if ((_effectiveRole == "driver") && {(getNumber (configOf _target >> "hasDriver")) == 0}) exitWith {}; // Ignoring Non Driver (static weapons)

// Seats can be locked independently of the main vehicle
if ((_effectiveRole == "driver") && {lockedDriver _target}) exitWith {TRACE_1("lockedDriver",_x);};
if ((_cargoIndex >= 0) && {_target lockedCargo _cargoIndex}) exitWith {TRACE_1("lockedCargo",_x);};
if ((_turretPath isNotEqualTo []) && {_target lockedTurret _turretPath}) exitWith {TRACE_1("lockedTurret",_x);};

if (_effectiveRole == "turret") then {
private _turretConfig = [_target, _turretPath] call CBA_fnc_getTurret;

if (getNumber (_turretConfig >> "isCopilot") == 1) exitWith {
_effectiveRole = "driver";
};
TRACE_2("",_effectiveRole,_x);
if (_effectiveRole != _desiredRole) exitWith {};

if (_turretPath isNotEqualTo []) then {
// Using GetInTurret seems to solve problems with incorrect GetInEH params when gunner/commander
ACE_player action ["GetInTurret", _target, _turretPath];
TRACE_3("Geting In Turret",_x,_role,_turretPath);
} else {
if (_cargoIndex > -1) then {
// GetInCargo expects the index of the seat in the "cargo" array from fullCrew
// See description: https://community.bistudio.com/wiki/fullCrew
private _cargoActionIndex = -1;
{
if ((_x select 2) == _cargoIndex) exitWith {_cargoActionIndex = _forEachIndex};
} forEach (fullCrew [_target, "cargo", true]);

ACE_player action ["GetInCargo", _target, _cargoActionIndex];
TRACE_4("Geting In Cargo",_x,_role,_cargoActionIndex,_cargoIndex);
} else {
ACE_player action ["GetIn" + _role, _target];
TRACE_2("Geting In",_x,_role);
};
if (
_cargoIndex >= 0 || // FFV
{getText (_turretConfig >> "gun") == ""} // Turret without weapon
) exitWith {
_effectiveRole = "cargo";
};

_hasAction = true;
breakTo "SearchForSeat";
_effectiveRole = "gunner"; // Door gunners / 2nd turret
};
} forEach (fullCrew [_target, "", true]);
} forEach _sortedSeats;

if (!_hasAction) then {
TRACE_1("no empty seats",_hasAction);
[localize LSTRING(VehicleFull)] call EFUNC(common,displayTextStructured);
};
};
TRACE_2("",_effectiveRole,_x);

if (_effectiveRole != _desiredRole) exitWith {};

if (_turretPath isNotEqualTo []) then {
// Using GetInTurret seems to solve problems with incorrect GetInEH params when gunner/commander
ACE_player action ["GetInTurret", _target, _turretPath];
TRACE_3("Getting In Turret",_x,_role,_turretPath);
} else {
if (_cargoIndex > -1) then {
// GetInCargo expects the index of the seat in the "cargo" array from fullCrew
// See description: https://community.bistudio.com/wiki/fullCrew
private _cargoActionIndex = (fullCrew [_target, "cargo", true]) findIf {(_x select 2) == _cargoIndex};

true
ACE_player action ["GetInCargo", _target, _cargoActionIndex];
TRACE_4("Getting In Cargo",_x,_role,_cargoActionIndex,_cargoIndex);
} else {
ACE_player action ["GetIn" + _role, _target];
TRACE_2("Getting In",_x,_role);
};
};

_hasAction = true;
breakTo "SearchForSeat";
};
} forEach _fullCrew;
} forEach _sortedSeats;

if (!_hasAction) then {
TRACE_1("no empty seats",_hasAction);
[LLSTRING(VehicleFull)] call EFUNC(common,displayTextStructured);
};