Skip to content
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
2 changes: 1 addition & 1 deletion .vscode/settings.json
Comment thread
DartRuffian marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"editor.insertSpaces": true,
"editor.detectIndentation": false,

"files.autoSave": "onFocusChange",
"files.autoSave": "off",
"files.trimFinalNewlines": true,
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
Expand Down
5 changes: 3 additions & 2 deletions addons/common/functions/fnc_isRampOpen.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@ private _rampAnims = _vehicle call FUNC(getRampAnimations);
if (_checkAll) then {
{
_x params ["_anim", "_closed", "_opened"];
if (_vehicle animationSourcePhase _anim != _opened) exitWith {
// In MP, animationSourcePhase can be incorrect on remote machines. E.g. if animated to 0.6 it will return 0.6 where vehicle is local but may return 0.59... on a remote machine
if (((_vehicle animationSourcePhase _anim) toFixed 1) != (_opened toFixed 1)) exitWith {
Comment thread
mrschick marked this conversation as resolved.
_return = false;
};
} forEach _rampAnims;
} else {
private _rampAnim = (_rampAnims select 0) params ["_anim", "_closed", "_opened"];
if (_vehicle animationSourcePhase _anim != _opened) then {
if (((_vehicle animationSourcePhase _anim) toFixed 1) != (_opened toFixed 1)) then {
_return = false;
};
};
Expand Down
2 changes: 1 addition & 1 deletion addons/helocast/functions/fnc_unloadBoatPFH.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ TRACE_8("unloadPFH params",_vehicle,_boat,_fromPosASL,_toPosASL,_fromVelocity,_t

if (_interval > 1) then {
_handle call CBA_fnc_removePerFrameHandler;
[QGVAR(boatUnloaded), [_vehicle, _boat, _index]] call CBA_fnc_globalEvent;
[QGVAR(boatUnloaded), [_vehicle, _boat]] call CBA_fnc_globalEvent;
_vehicle setVariable [QGVAR(isUnloading), nil, true];
[QEGVAR(common,blockDamage), [_vehicle, QGVAR(isUnloadingBoat), false]] call CBA_fnc_globalEvent;
};
Expand Down
21 changes: 21 additions & 0 deletions addons/staticline/Cfg3DEN.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class Cfg3DEN {
class Object {
class AttributeCategories {
class PREFIX {
displayName = QUOTE(MOD_NAME);
collapsed = 0;
class Attributes {
class GVAR(isJumpMaster) {
displayName = CSTRING(jumpMaster_displayName);
tooltip = CSTRING(jumpMaster_tooltip);
property = QGVAR(isJumpMasterID);
control = "Checkbox";
defaultValue = "false";
condition = "objectBrain";
expression = QUOTE(_this setVariable [ARR_3(QQGVAR(isJumpMaster),_value,true)]);
};
};
};
};
};
};
5 changes: 5 additions & 0 deletions addons/staticline/XEH_PREP.hpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
PREP(addWaypoint);
PREP(canDeployGroups);
PREP(canHook);
PREP(canJump);
PREP(canUnhook);
PREP(checkJumpCondition);
PREP(createParachute);
PREP(deployGroupsChildrenActions);
PREP(getOutMan);
PREP(getUnitsToDeploy);
PREP(hook);
PREP(isAircraftCrew);
PREP(isEnabled);
PREP(jump);
PREP(jumpAI);
Expand Down
10 changes: 10 additions & 0 deletions addons/staticline/XEH_preInit.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,13 @@ PREP_RECOMPILE_END;
private _category = [QUOTE(MOD_NAME), LLSTRING(displayName)];

#include "initSettings.inc.sqf"

[QGVAR(jump), LINKFUNC(jump)] call CBA_fnc_addEventHandler;

// Keep the player's assignedTeam updated as a public object variable. Otherwise, clients in a different group cannot fetch our assignedTeam, causing locality issues for group deployments.
[{
private _assignedTeam = assignedTeam ace_player;
if (_assignedTeam != (ace_player getVariable [QGVAR(assignedTeam), "MAIN"])) then {
ace_player setVariable [QGVAR(assignedTeam), _assignedTeam, true];
};
}, 1] call CBA_fnc_addPerFrameHandler;
Comment thread
mrschick marked this conversation as resolved.
1 change: 1 addition & 0 deletions addons/staticline/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class CfgPatches {
};
};

#include "Cfg3DEN.hpp"
#include "CfgVehicles.hpp"
#include "CfgSounds.hpp"
#include "CfgEventHandlers.hpp"
Expand Down
26 changes: 26 additions & 0 deletions addons/staticline/functions/fnc_canDeployGroups.sqf
Comment thread
mrschick marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include "..\script_component.hpp"
/*
* Author: mrschick
* Checks if a unit can command the static line jump of an embarked+hooked player or AI group.
*
* Arguments:
* 0: Vehicle <OBJECT>
* 1: Unit <OBJECT>
*
* Return Value:
* True if unit can command jumps, otherwise false <BOOL>
*
* Example:
* [objectParent ace_player, ace_player] call aftb_staticLine_fnc_canDeployGroups;
*
* Public: No
*/

params ["_vehicle", "_unit"];
TRACE_2("fnc_canDeployGroups",_vehicle,_unit);

GVAR(commandGroupJumps) > 0 && {
(_unit == leader _unit) || {_unit getVariable [QGVAR(isJumpMaster), false]} || {[_vehicle, _unit] call FUNC(isAircraftCrew)}
} && {
_vehicle call EFUNC(common,isRampOpen) && { [_vehicle, _unit] call FUNC(checkJumpCondition) }
};
9 changes: 1 addition & 8 deletions addons/staticline/functions/fnc_canJump.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,6 @@
params ["_vehicle", "_unit"];
TRACE_2("fnc_canJump",_vehicle,_unit);

private _rampAnims = _vehicle call EFUNC(common,getRampAnimations);

private _jumpCondition = compile getText (configOf _vehicle >> QGVAR(condition));
if (_jumpCondition isEqualTo {}) then {
_jumpCondition = { true };
};

_unit getVariable [QGVAR(isHooked), false] and
{ _vehicle call EFUNC(common,isRampOpen) } and
{ [_vehicle, _unit, _rampAnims] call _jumpCondition };
{ [_vehicle, _unit] call FUNC(checkJumpCondition) };
27 changes: 27 additions & 0 deletions addons/staticline/functions/fnc_checkJumpCondition.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "..\script_component.hpp"
/*
* Author: DartRuffian
* Checks if a unit satisfies the vehicle's jump condition.
*
* Arguments:
* 0: Vehicle <OBJECT>
* 1: Unit <OBJECT>
*
* Return Value:
* True if the unit satisfies the vehicle's jump condition, otherwise false <BOOL>
*
* Example:
* [objectParent ace_player, ace_player] call aftb_staticLine_fnc_checkJumpCondition;
*
* Public: No
*/

params ["_vehicle", "_unit"];
TRACE_2("fnc_checkJumpCondition",_vehicle,_unit);

private _rampAnims = _vehicle call EFUNC(common,getRampAnimations);
private _jumpCondition = compile getText (configOf _vehicle >> QGVAR(condition));

if (_jumpCondition isEqualTo {}) then { _jumpCondition = { true }; };

[_vehicle, _unit, _rampAnims] call _jumpCondition
93 changes: 93 additions & 0 deletions addons/staticline/functions/fnc_deployGroupsChildrenActions.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#include "..\script_component.hpp"
/*
* Author: mrschick
* Dynamically fills the deployGroups action with subactions, allowing high-ranking crew/passengers to command the staggered line jump of embarked groups (hooked players or AI), or group leaders to command the jump of their own group.
*
* Arguments:
* 0: Vehicle <OBJECT>
* 1: Unit <OBJECT>
*
* Return Value:
* Array of ACE Child Actions <ARRAY>
*
* Example:
* [objectParent ace_player, ace_player] call aftb_staticLine_fnc_deployGroupsChildrenActions;
*
* Public: No
*/

params ["_vehicle", "_unit"];

// Generate array of embarked groups
private _embarkedUnits = _vehicle call EFUNC(common,getPassengers);
private _embarkedGroups = [];
{
_embarkedGroups pushBackUnique (group _x);
} forEach _embarkedUnits;

// Abort early if there are no groups to deploy
if (_embarkedGroups isEqualTo []) exitWith {[]};

// Evaluate specific permissions player should have, to determine which interactions are available to them
private _unitIsJumpMaster = (_unit getVariable [QGVAR(isJumpMaster), false]) || {GVAR(commandGroupJumps) > 1 && {[_vehicle, _unit] call FUNC(isAircraftCrew)}};

private _actions = [];
private _action = [];

if ((_vehicle getVariable [QGVAR(unitsToDeploy), []]) isNotEqualTo []) then {
// If a deployment is in progress, only give jumpmasters the action to abort any in-progress deployment
if (_unitIsJumpMaster) then {
private _unitsRemaining = count (_vehicle getVariable [QGVAR(unitsToDeploy), []]);
_action = ([
QGVAR(abortGroupDeployment),
format [LLSTRING(action_abortGroupDeployment), _unitsRemaining],
"",
{(_this select 0) setVariable [QGVAR(unitsToDeploy), [], true]},
{true}
] call ace_interact_menu_fnc_createAction);
_actions pushBack [_action, [], _vehicle];
};
} else {
// Pilot/Jumpmaster can deploy all groups in sequence
if (_unitIsJumpMaster && {count _embarkedGroups > 1}) then {
_action = [
QGVAR(deployAllGroups),
LLSTRING(action_deployAllGroups),
"",
{
params ["_vehicle", "_unit", "_args"];
[_vehicle, false, _args call FUNC(getUnitsToDeploy)] call FUNC(jumpAI);
},
{true},
{},
[_embarkedGroups, _embarkedUnits]
] call ace_interact_menu_fnc_createAction;
_actions pushBack [_action, [], _vehicle];
};

// Generate one action per-group, to deploy each automatically
{
private _group = _x;
// Jumpmasters can deploy any group, group leaders can only deploy their own
if (_unitIsJumpMaster || {GVAR(commandGroupJumps) == 3 && {_unit == leader _group}}) then {
private _groupUnits = (units _group) arrayIntersect _embarkedUnits;
private _hookedUnits = _groupUnits select {_x getVariable [QGVAR(isHooked), false] || {!isPlayer _x}};
private _groupName = groupId _group;
_action = [
QGVAR(deploy_) + _groupName,
format ["%1 (%2)", _groupName, format [LLSTRING(action_hooked), count _hookedUnits, count _groupUnits]],
"",
{
params ["_vehicle", "_unit", "_args"];
[_vehicle, false, _args call FUNC(getUnitsToDeploy)] call FUNC(jumpAI);
},
{true},
{},
[[_group], _embarkedUnits]
Comment thread
mrschick marked this conversation as resolved.
] call ace_interact_menu_fnc_createAction;
_actions pushBack [_action, [], _vehicle];
};
} forEach _embarkedGroups;
};

_actions;
105 changes: 105 additions & 0 deletions addons/staticline/functions/fnc_getUnitsToDeploy.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#include "..\script_component.hpp"
/*
* Author: mrschick
* Generate an array of ALL units to be deployed during the commanded Group Deployment.
* - The units are sorted by their group.
* - Within each group, units are always sorted side-by-side with others of their assigned color, so that "teams" aren't separated.
* - The position of the leader's "team", as well as his position within it, is determined by the CBA Setting GVAR(leaderJumpOrder).
*
* Arguments:
* 0: Groups to deploy <ARRAY>
* 1: Units embarked <ARRAY>
*
* Return Value:
* Array of units to deploy <ARRAY>
*
* Example:
* [group ace_player, units (vehicle ace_player)] call aftb_staticLine_fnc_getUnitsToDeploy;
*
* Public: No
*/

params ["_groupsToDeploy", "_embarkedUnits"];

if (_groupsToDeploy isEqualTo [] || {_embarkedUnits isEqualTo []}) exitWith {[]};

private _unitsToDeploy = [];

// Iterate through all groups to deploy, to ensure units are sorted by their group
{
private _group = _x;
private _leader = leader _group;
private _groupUnits = (units _group) arrayIntersect _embarkedUnits;
private _unitCount = count _groupUnits;

/*
* The following logic uses HashMaps and Array operations to ensure that:
* - Units of the same color (assignedTeam) are ALWAYS grouped together;
* - The Group Leader's position within the group's deployment sequence is AS CLOSE AS POSSIBLE to where determined by the CBA Setting (first, last, in the middle);
*/
private _groupUnitsSorted = [];

// 1. Group Units with the same "Team" (color) together, into HashMap Buckets
private _allTeams = createHashMap;
{ (_allTeams getOrDefault [(_x getVariable [QGVAR(assignedTeam), assignedTeam _x]), [], true]) pushBack _x } forEach _groupUnits;

// 2. Separate the Leader's Team Bucket from the others
private _leaderColor = _leader getVariable [QGVAR(assignedTeam), assignedTeam _leader];
private _leaderTeam = _allTeams get _leaderColor;
_allTeams deleteAt _leaderColor;

private _otherTeams = [];
{ _otherTeams pushBack _y } forEach _allTeams;

// 3. Reposition the leader's team in the sequence, as well him within his own team, to reflect the preference defined by the CBA Setting
switch (GVAR(leaderJumpOrder)) do {
case 0: { // Leader jumps first
_groupUnitsSorted append ([_leader] + (_leaderTeam - [_leader]));
_groupUnitsSorted append (flatten _otherTeams);
};
case 1: { // Leader jumps in the middle of his group
// Separate the other teams into 2 buckets, _before and _after, to place them around the leader's team
private _mid = floor ((count _otherTeams) / 2);
private _before = flatten (_otherTeams select [0, _mid]);
private _after = flatten (_otherTeams select [_mid]);

// Append teams before the leader's
_groupUnitsSorted append _before;

// Center the leader as close as possible in his group's sequence, while keeping him with his own team
private _firstLeaderTeamIdx = count _before;
private _lastLeaderTeamIdx = _unitCount - count _after - 1;
private _leaderIdx = ((floor (_unitCount / 2)) max _firstLeaderTeamIdx) min _lastLeaderTeamIdx;

// Append the leader's team to the group's sequence, with the leader in the desired position/index
_leaderTeam = _leaderTeam - [_leader];
for [{_i = _firstLeaderTeamIdx}, {_i <= _lastLeaderTeamIdx}, {_i = _i + 1}] do {
if (_i == _leaderIdx) then {
_groupUnitsSorted set [_i, _leader];
} else {
_groupUnitsSorted set [_i, _leaderTeam deleteAt 0];
};
};

// Append teams after the leader's
_groupUnitsSorted append _after;
};
case 2: { // Leader jumps last
_groupUnitsSorted append (flatten _otherTeams);
_groupUnitsSorted append ((_leaderTeam - [_leader]) + [_leader]);
};
};

#ifdef DEBUG_MODE_FULL
// Debug output of the current group's jump order, i.e: ["R", "R", "R-L", "B", "B", "B"]
systemChat str (_groupUnitsSorted apply {
private _color = (assignedTeam _x) select [0, 1];
if (_x == leader _x) then {_color + "-L"} else {_color};
});
#endif

// 4. Append the now sorted group to the collective sequence of groups to deploy, filtering out players that aren't hooked in
_unitsToDeploy append (_groupUnitsSorted select {_x getVariable [QGVAR(isHooked), false] || {!isPlayer _x}});
} forEach _groupsToDeploy;

_unitsToDeploy;
Loading
Loading