mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
e8c3be8016
* Add quickmount GetIn menu * Add compartment support * Check engine, check pilot, check static turret driver * Add doc, condition, translation * Add hybrid config entries, fix MP issue * Optimize condition * Ignore Enabled setting in vehicle * Work around SQF validator macro issue * Fix config macro entries * Add workaround for getting damage when seat changing while moving * Add setting for Get In menu disabling * Fix race when 2 players try to get the same seat * Convert if-else to switch * Decrease move-back timeout to 0.5s * Check if vehicle is flipped * Add getin statement for parent menu * Improve canShowFreeSeats * Apply latest trends * Improve fnc_addFreeSeatsActions * Change copilot and gunless turret icons * Fix macro name * Fix FFV icon * Optimize turret icon code * Extend setting to 4 values * Fix menu is shown when vehicle is full * Optimize UAV checking code * Fix bug with disabled FFV turrets * Remove bugged FFV, Add turret locality check, Add Failed message * Replace some macros with function * Fix validator * Remove global variables, Add debug
248 lines
11 KiB
Plaintext
248 lines
11 KiB
Plaintext
#include "script_component.hpp"
|
|
/*
|
|
* Author: Dystopian
|
|
* Creates actions for vehicle free seats.
|
|
*
|
|
* Arguments:
|
|
* 0: Vehicle <OBJECT>
|
|
* 1: Unit <OBJECT>
|
|
*
|
|
* Return Value:
|
|
* Child actions <ARRAY>
|
|
*
|
|
* Example:
|
|
* [cursorObject, player] call ace_quickmount_fnc_addFreeSeatsActions
|
|
*
|
|
* Public: No
|
|
*/
|
|
|
|
#define TAKEN_SEAT_TIMEOUT 0.5
|
|
|
|
#define ICON_DRIVER "A3\ui_f\data\IGUI\RscIngameUI\RscUnitInfo\role_driver_ca.paa"
|
|
#define ICON_PILOT "A3\ui_f\data\IGUI\Cfg\Actions\getinpilot_ca.paa"
|
|
#define ICON_CARGO "A3\ui_f\data\IGUI\RscIngameUI\RscUnitInfo\role_cargo_ca.paa"
|
|
#define ICON_GUNNER "A3\ui_f\data\IGUI\Cfg\Actions\getingunner_ca.paa"
|
|
#define ICON_COMMANDER "A3\ui_f\data\IGUI\RscIngameUI\RscUnitInfo\role_commander_ca.paa"
|
|
#define ICON_TURRET "A3\ui_f\data\IGUI\RscIngameUI\RscUnitInfo\role_gunner_ca.paa"
|
|
#define ICON_FFV "A3\ui_f\data\IGUI\Cfg\CrewAimIndicator\gunnerAuto_ca.paa"
|
|
|
|
#define TO_COMPARTMENT_STRING(var) if !(var isEqualType "") then {var = format [ARR_2("Compartment%1",var)]}
|
|
|
|
// if unit isn't moved to new seat in TAKEN_SEAT_TIMEOUT, we move him back to his seat
|
|
#define WAIT_IN_OR_MOVE_BACK \
|
|
[ARR_5( \
|
|
{!isNull objectParent (_this select 0)}, \
|
|
{ \
|
|
params [ARR_2("_player","_damageBlocked")]; \
|
|
if (_damageBlocked) then {_player allowDamage true}; \
|
|
LOG_1("moved in in %1 frames",diag_frameno-GVAR(frame)); \
|
|
}, \
|
|
[ARR_4(_player,_damageBlocked,_moveBackCode,_moveBackParams)], \
|
|
TAKEN_SEAT_TIMEOUT, \
|
|
{ \
|
|
params [ARR_4("_player","_damageBlocked","_moveBackCode","_moveBackParams")]; \
|
|
[ARR_2(_player,_moveBackParams)] call _moveBackCode; \
|
|
if (_damageBlocked) then {_player allowDamage true}; \
|
|
localize "str_mis_state_failed" call EFUNC(common,displayTextStructured); \
|
|
} \
|
|
)] call CBA_fnc_waitUntilAndExecute;
|
|
|
|
#define IS_MOVED_OUT \
|
|
( \
|
|
isNull objectParent _player \
|
|
&& { \
|
|
[] isEqualTo _currentTurret \
|
|
|| {local _target isEqualTo (_target turretLocal _currentTurret)} \
|
|
} \
|
|
)
|
|
|
|
#define MOVE_IN_CODE(command) (_this select 0) command (_this select 1)
|
|
|
|
private _fnc_move = {
|
|
(_this select 2) params ["_moveInCode", "_moveInParams", "_currentTurret", "_moveBackCode", "_moveBackParams", ["_enabledByAnimationSource", ""]];
|
|
TRACE_7("fnc_move params",_moveInCode,_moveInParams,_currentTurret,_moveBackCode,_moveBackParams,_enabledByAnimationSource,call {GVAR(frame)=diag_frameno});
|
|
|
|
// check bugged FFV
|
|
if (
|
|
!("" isEqualTo _enabledByAnimationSource)
|
|
&& {1 > _target doorPhase _enabledByAnimationSource}
|
|
) exitWith {};
|
|
|
|
// workaround getting damage when moveOut while vehicle is moving
|
|
private _damageBlocked = false;
|
|
if (isDamageAllowed _player) then {
|
|
_player allowDamage false;
|
|
_damageBlocked = true;
|
|
};
|
|
private _preserveEngineOn = _player == driver _target && {isEngineOn _target};
|
|
moveOut _player;
|
|
if (_preserveEngineOn) then {_target engineOn true};
|
|
|
|
// moveIn right after moveOut doesn't work in MP for non-local vehicles, player just stays out
|
|
// so we have to wait some time (e.g. until player is out and turret locality become vehicle locality)
|
|
// usually it's done in the same frame for local vehicles/turrets and takes 3-7 frames for non-local, so in MP can look a little lagging
|
|
if (IS_MOVED_OUT) exitWith {
|
|
LOG("moved out in current frame");
|
|
[_player, _moveInParams] call _moveInCode;
|
|
WAIT_IN_OR_MOVE_BACK;
|
|
};
|
|
[
|
|
{params ["_target", "_player", "_currentTurret"]; IS_MOVED_OUT},
|
|
{
|
|
params ["", "_player", "", "_moveInCode", "_moveInParams", "_moveBackCode", "_moveBackParams", "_damageBlocked"];
|
|
LOG_2("moved out in %1 frames",diag_frameno-GVAR(frame),call {GVAR(frame)=diag_frameno; 0});
|
|
[_player, _moveInParams] call _moveInCode;
|
|
WAIT_IN_OR_MOVE_BACK;
|
|
},
|
|
[_target, _player, _currentTurret, _moveInCode, _moveInParams, _moveBackCode, _moveBackParams, _damageBlocked]
|
|
] call CBA_fnc_waitUntilAndExecute;
|
|
};
|
|
|
|
scopeName "main";
|
|
|
|
params ["_vehicle", "_player"];
|
|
|
|
private _vehicleConfig = configFile >> "CfgVehicles" >> typeOf _vehicle;
|
|
private _isInVehicle = _player in _vehicle;
|
|
private _fullCrew = fullCrew [_vehicle, "", true];
|
|
|
|
private ["_driverCompartments", "_isDriverIsolated", "_cargoCompartments", "_cargoCompartmentsLast", "_compartment", "_currentTurret", "_moveBackCode", "_moveBackParams"];
|
|
|
|
if (_isInVehicle) then {
|
|
_driverCompartments = (_vehicleConfig >> "driverCompartments") call BIS_fnc_getCfgData;
|
|
// Air class by default has driverCompartments=0 and cargoCompartments[]={0}, so we have to disable them
|
|
_isDriverIsolated = _driverCompartments isEqualTo 0 && {_vehicle isKindOf "Air"};
|
|
TO_COMPARTMENT_STRING(_driverCompartments);
|
|
|
|
_cargoCompartments = getArray (_vehicleConfig >> "cargoCompartments");
|
|
{
|
|
if !(_x isEqualType "") then {
|
|
_cargoCompartments set [_forEachIndex, format ["Compartment%1", _x]];
|
|
};
|
|
} forEach _cargoCompartments;
|
|
_cargoCompartmentsLast = count _cargoCompartments - 1;
|
|
|
|
// find current compartment
|
|
(
|
|
_fullCrew select (_fullCrew findIf {_player == _x select 0})
|
|
) params ["", "_role", "_cargoIndex", "_turretPath"];
|
|
|
|
_currentTurret = _turretPath;
|
|
|
|
switch (_role) do {
|
|
case "driver": {
|
|
if (_isDriverIsolated) then {
|
|
[] breakOut "main";
|
|
};
|
|
_compartment = _driverCompartments;
|
|
_moveBackCode = {MOVE_IN_CODE(moveInDriver)};
|
|
_moveBackParams = _vehicle;
|
|
};
|
|
case "cargo": {
|
|
private _cargoNumber = fullCrew [_vehicle, "cargo", true] findIf {_player == _x select 0};
|
|
_compartment = _cargoCompartments select (_cargoNumber min _cargoCompartmentsLast);
|
|
_moveBackCode = {MOVE_IN_CODE(moveInCargo)};
|
|
_moveBackParams = [_vehicle, _cargoIndex];
|
|
};
|
|
default {
|
|
private _turretConfig = [_vehicleConfig, _turretPath] call CBA_fnc_getTurret;
|
|
_compartment = (_turretConfig >> "gunnerCompartments") call BIS_fnc_getCfgData;
|
|
TO_COMPARTMENT_STRING(_compartment);
|
|
_moveBackCode = {MOVE_IN_CODE(moveInTurret)};
|
|
_moveBackParams = [_vehicle, _turretPath];
|
|
};
|
|
};
|
|
TRACE_6("current",_role,_cargoIndex,_turretPath,_compartment,_driverCompartments,_cargoCompartments);
|
|
};
|
|
|
|
private _actions = [];
|
|
private _cargoNumber = -1;
|
|
{
|
|
scopeName "crewLoop";
|
|
_x params ["_unit", "_role", "_cargoIndex", "_turretPath", "_isPersonTurret"];
|
|
if (!isNull _unit && {alive _unit}) then {
|
|
if (_role == "cargo") then {
|
|
INC(_cargoNumber);
|
|
};
|
|
} else {
|
|
private ["_name", "_icon", "_statement", "_params"];
|
|
switch (toLower _role) do {
|
|
case "driver": {
|
|
if (
|
|
lockedDriver _vehicle
|
|
|| {unitIsUAV _vehicle}
|
|
|| {0 == getNumber (_vehicleConfig >> "hasDriver")}
|
|
) then {
|
|
breakTo "crewLoop";
|
|
};
|
|
if (_isInVehicle) then {
|
|
if (_compartment != _driverCompartments || {_isDriverIsolated}) then {breakTo "crewLoop"};
|
|
_params = [{MOVE_IN_CODE(moveInDriver)}, _vehicle, _currentTurret, _moveBackCode, _moveBackParams];
|
|
_statement = _fnc_move;
|
|
} else {
|
|
_params = ["GetInDriver", _vehicle];
|
|
_statement = {_player action (_this select 2)};
|
|
};
|
|
if (_vehicle isKindOf "Air") then {
|
|
_name = localize "str_getin_pos_pilot";
|
|
_icon = ICON_PILOT;
|
|
} else {
|
|
_name = localize "str_driver";
|
|
_icon = ICON_DRIVER;
|
|
};
|
|
};
|
|
case "cargo": {
|
|
INC(_cargoNumber);
|
|
if (_vehicle lockedCargo _cargoIndex) then {breakTo "crewLoop"};
|
|
if (_isInVehicle) then {
|
|
if (_compartment != (_cargoCompartments select (_cargoNumber min _cargoCompartmentsLast))) then {breakTo "crewLoop"};
|
|
_params = [{MOVE_IN_CODE(moveInCargo)}, [_vehicle, _cargoIndex], _currentTurret, _moveBackCode, _moveBackParams];
|
|
_statement = _fnc_move;
|
|
} else {
|
|
_params = ["GetInCargo", _vehicle, _cargoNumber];
|
|
_statement = {_player action (_this select 2)};
|
|
};
|
|
_name = format ["%1 %2", localize "str_getin_pos_passenger", _cargoNumber + 1];
|
|
_icon = ICON_CARGO;
|
|
};
|
|
default { // all turrets including FFV
|
|
if (_vehicle lockedTurret _turretPath) then {breakTo "crewLoop"};
|
|
if (_role == "gunner" && {unitIsUAV _vehicle}) then {breakTo "crewLoop"};
|
|
private _turretConfig = [_vehicleConfig, _turretPath] call CBA_fnc_getTurret;
|
|
if (!_isInVehicle) then {
|
|
_params = ["GetInTurret", _vehicle, _turretPath];
|
|
_statement = {_player action (_this select 2)};
|
|
} else {
|
|
private _gunnerCompartments = (_turretConfig >> "gunnerCompartments") call BIS_fnc_getCfgData;
|
|
TO_COMPARTMENT_STRING(_gunnerCompartments);
|
|
if (_compartment != _gunnerCompartments) then {breakTo "crewLoop"};
|
|
// due to arma bug the unit is stuck in wrong anim when move in turret with configured enabledByAnimationSource
|
|
private _enabledByAnimationSource = getText (_turretConfig >> "enabledByAnimationSource");
|
|
if (
|
|
!("" isEqualTo _enabledByAnimationSource)
|
|
&& {1 > _vehicle doorPhase _enabledByAnimationSource}
|
|
) then {breakTo "crewLoop"};
|
|
_params = [{MOVE_IN_CODE(moveInTurret)}, [_vehicle, _turretPath], _currentTurret, _moveBackCode, _moveBackParams, _enabledByAnimationSource];
|
|
_statement = _fnc_move;
|
|
};
|
|
_name = getText (_turretConfig >> "gunnerName");
|
|
_icon = switch true do {
|
|
case (0 < getNumber (_turretConfig >> "isCopilot")): {ICON_PILOT};
|
|
case (_role == "gunner"): {ICON_GUNNER};
|
|
case (_role == "commander"): {ICON_COMMANDER};
|
|
case (_isPersonTurret): {ICON_FFV};
|
|
case ("" isEqualTo getText (_turretConfig >> "gun")): {ICON_CARGO};
|
|
default {ICON_TURRET};
|
|
};
|
|
};
|
|
};
|
|
private _action = [
|
|
format ["%1%2%3", _role, _cargoIndex, _turretPath],
|
|
_name, _icon, _statement, {true}, {}, _params
|
|
] call EFUNC(interact_menu,createAction);
|
|
_actions pushBack [_action, [], _vehicle];
|
|
};
|
|
} forEach _fullCrew;
|
|
|
|
_actions
|