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

Quick Mount - Add Get In and Change seat action menu #5745

Merged
merged 38 commits into from
Nov 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
c1b9ec8
Add quickmount GetIn menu
Dystopian Nov 6, 2017
39c9c8b
Add compartment support
Dystopian Nov 6, 2017
9e73ca8
Check engine, check pilot, check static turret driver
Dystopian Nov 7, 2017
0222463
Add doc, condition, translation
Dystopian Nov 8, 2017
9e17c18
Add hybrid config entries, fix MP issue
Dystopian Nov 11, 2017
414d00e
Optimize condition
Dystopian Nov 11, 2017
5316536
Ignore Enabled setting in vehicle
Dystopian Nov 12, 2017
8af3296
Work around SQF validator macro issue
Dystopian Nov 12, 2017
3e3993a
Fix config macro entries
Dystopian Nov 12, 2017
02d5a69
Add workaround for getting damage when seat changing while moving
Dystopian Nov 26, 2017
3b0d540
Merge remote-tracking branch 'upstream/master' into getin_menu
Dystopian Nov 26, 2017
17ca955
Add setting for Get In menu disabling
Dystopian Nov 26, 2017
7eccae8
Merge branch 'master' into getin_menu
Dystopian Dec 22, 2017
a66d97e
Fix race when 2 players try to get the same seat
Dystopian Dec 23, 2017
81f711d
Convert if-else to switch
Dystopian Dec 24, 2017
6cc77b8
Decrease move-back timeout to 0.5s
Dystopian Dec 26, 2017
5dedfd4
Check if vehicle is flipped
Dystopian Jan 3, 2018
b03fde9
Merge remote-tracking branch 'upstream/master' into getin_menu
Dystopian Jan 16, 2018
a04b4c8
Merge branch 'master' into getin_menu
Dystopian Apr 27, 2018
6a204d4
Add getin statement for parent menu
Dystopian Apr 27, 2018
fdc67c7
Improve canShowFreeSeats
Dystopian Apr 27, 2018
7ac8515
Merge remote-tracking branch 'upstream/master' into getin_menu
Dystopian Oct 12, 2018
b70c904
Apply latest trends
Dystopian Oct 12, 2018
e472b02
Improve fnc_addFreeSeatsActions
Dystopian Oct 13, 2018
de71707
Merge remote-tracking branch 'upstream/master' into getin_menu
Dystopian Oct 13, 2018
0e439af
Change copilot and gunless turret icons
Dystopian Oct 13, 2018
8d59c9e
Fix macro name
Dystopian Oct 14, 2018
5a02381
Fix FFV icon
Dystopian Oct 23, 2018
283fae0
Optimize turret icon code
Dystopian Oct 23, 2018
fb01018
Extend setting to 4 values
Dystopian Oct 30, 2018
5856d7b
Fix menu is shown when vehicle is full
Dystopian Oct 31, 2018
09356d6
Optimize UAV checking code
Dystopian Oct 31, 2018
493e5b3
Fix bug with disabled FFV turrets
Dystopian Nov 5, 2018
59a97df
Merge remote-tracking branch 'upstream/master' into getin_menu
Dystopian Nov 11, 2018
32e8e5d
Remove bugged FFV, Add turret locality check, Add Failed message
Dystopian Nov 15, 2018
274ef00
Replace some macros with function
Dystopian Nov 15, 2018
66b661d
Fix validator
Dystopian Nov 15, 2018
ef3cc84
Remove global variables, Add debug
Dystopian Nov 18, 2018
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
47 changes: 47 additions & 0 deletions addons/quickmount/CfgVehicles.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,51 @@ class CfgVehicles {
description = CSTRING(KeybindDescription);
};
};

#define GETIN_ACTIONS \
class ACE_Actions { \
class ACE_MainActions { \
class GVAR(GetIn) { \
displayName = "$STR_rscMenu.hppRscGroupRootMenu_Items_GetIn1"; \
condition = QUOTE(call DFUNC(canShowFreeSeats)); \
statement = QUOTE(call DFUNC(getInNearest)); \
exceptions[] = {"isNotSwimming"}; \
insertChildren = QUOTE(call DFUNC(addFreeSeatsActions)); \
}; \
}; \
}; \
class ACE_SelfActions { \
class GVAR(ChangeSeat) { \
displayName = CSTRING(ChangeSeat); \
condition = QUOTE(call DFUNC(canShowFreeSeats)); \
statement = ""; \
insertChildren = QUOTE(call DFUNC(addFreeSeatsActions)); \
}; \
}

class LandVehicle;
class Car: LandVehicle {
GETIN_ACTIONS;
};
class Motorcycle: LandVehicle {
GETIN_ACTIONS;
};
class StaticWeapon: LandVehicle {
GETIN_ACTIONS;
};
class Tank: LandVehicle {
GETIN_ACTIONS;
};
class Air;
class Helicopter: Air {
GETIN_ACTIONS;
};
class Plane: Air {
GETIN_ACTIONS;
};
class Ship;
class Ship_F: Ship {
GETIN_ACTIONS;
};

};
2 changes: 2 additions & 0 deletions addons/quickmount/XEH_PREP.hpp
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
PREP(addFreeSeatsActions);
PREP(canShowFreeSeats);
PREP(getInNearest);
PREP(moduleInit);
247 changes: 247 additions & 0 deletions addons/quickmount/functions/fnc_addFreeSeatsActions.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
#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]];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use apply
Also you made a macro for this. Why don't you use it now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look how it was with apply: 9e17c18#diff-ded96a376761ae515c888f369fb06b23R55
I changed it to forEach only last days because IMHO it looks better and clearer.

Macro sets variable not array member so I can't use it here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_cargoCompartments = _cargoCompartments apply {[format ["Compartment%1", _x], -x] select (_x isEqualType "")}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will test in a week

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apply is slower (even without intermediate cargoCompartments assignment) and less clear ✋

Copy link
Contributor

@dedmen dedmen Oct 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't understand how it can be. If you are doing the same thing, but with less commands and less variables (forEachIndex) it shouldn't possibly be slower.

Edit: Ah understood now.

If you are doing the same thing

yeah they aren't. My variant copies _x if it's already a string. Yours just does nothing.

Do you have an example vehicle where cargoCompartments isn't actually an array of strings?
Oh okey. Compartment1 is actually a enum that evaluates to 1.
Compartment2 = 2
Compartment3 = 4
Compartment4 = 8 and so on.. Meh.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0.0083 ms

private _cargoCompartments = getArray (configFile >> "CfgVehicles" >> typeOf cursorobject >> "cargoCompartments"); 
{ 
    if !(_x isEqualType "") then { 
        _cargoCompartments set [_forEachIndex, format ["Compartment%1", _x]]; 
    }; 
} forEach _cargoCompartments; 
_cargoCompartments 

vs
0.0108 ms

private _cargoCompartments = getArray (configFile >> "CfgVehicles" >> typeOf cursorobject >> "cargoCompartments") apply {[format ["Compartment%1", _x], _x] select (_x isEqualType "")}; 
_cargoCompartments 

when cursorObject is I_Truck_02_covered_F

Copy link
Contributor Author

@Dystopian Dystopian Oct 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dedmen when you edit your message nobody gets notification unlike when you create message (maybe in github desktop?). I really accidentally found your question.

Do you have an example vehicle where cargoCompartments isn't actually an array of strings?

CUP_Ural_ZU23_Base, rhs_truck, rhsusf_fmtv_base and some more RHS vehicles. No in vanilla.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well I expected you read the message on github. Instead of in a notification E-Mail or wherever.

};
} forEach _cargoCompartments;
_cargoCompartmentsLast = count _cargoCompartments - 1;

// find current compartment
(
_fullCrew select (_fullCrew findIf {_player == _x select 0})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will error if player is not in crew. Are you sure he is?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, if (_isInVehicle) then { ^^ L88

) 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
39 changes: 39 additions & 0 deletions addons/quickmount/functions/fnc_canShowFreeSeats.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include "script_component.hpp"
/*
* Author: Dystopian
* Checks if Free Seats menu can be shown.
*
* Arguments:
* 0: Vehicle <OBJECT>
* 1: Unit <OBJECT>
*
* Return Value:
* Can show menu <BOOL>
*
* Example:
* [cursorObject, player] call ace_quickmount_fnc_canShowFreeSeats
*
* Public: No
*/

params ["_vehicle", "_unit"];

private _isInVehicle = _unit in _vehicle;

GVAR(enabled)
&& {
GVAR(enableMenu) == 3
|| {_isInVehicle && {GVAR(enableMenu) == 2}}
|| {!_isInVehicle && {GVAR(enableMenu) == 1}}
}
&& {alive _vehicle}
&& {2 > locked _vehicle}
&& {
-1 == crew _vehicle findIf {alive _x}
|| {0.6 <= side group _unit getFriend side group _vehicle}
}
&& {
0.3 < vectorUp _vehicle select 2 // moveIn* and GetIn* don't work for flipped vehicles
|| {_vehicle isKindOf "Air"} // except Air
}
&& {!([] isEqualTo (_this call FUNC(addFreeSeatsActions)))} // this should be replaced with faster function
Loading