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

Add garrison zeus modules #4555

Merged
merged 25 commits into from
Oct 10, 2017
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
fa4d7f8
Add garrison and un-garrison modules
alganthe Oct 16, 2016
328c78e
Remove unnecessary text from garrison header
alganthe Oct 16, 2016
39a50ab
Add french translations to new strings
alganthe Oct 16, 2016
538ae61
Add changes requested by review
alganthe Oct 19, 2016
56a14cc
Change pushback to pushBack
alganthe Oct 19, 2016
9b26c8e
Merge branch 'master' into garrison_modules
jonpas Jun 22, 2017
ec0c684
Merge branch 'master' of https://github.com/acemod/ACE3 into garrison…
alganthe Sep 8, 2017
7e9ee8d
Move garrison funcs to ai, finish headers
alganthe Sep 8, 2017
27dc72d
Remove diag log debug
alganthe Sep 8, 2017
921944b
Fix typos and header issues
alganthe Sep 8, 2017
907fd90
Add missing newlines
alganthe Sep 8, 2017
32ec046
Fix strings, Fix typos and headers
alganthe Sep 24, 2017
19a9d16
Enable debug and disable compile cache, Add trace and comments
alganthe Sep 24, 2017
315e50b
Merge branch 'master' into garrison_modules
alganthe Sep 24, 2017
adb2d65
Rebase before review
alganthe Sep 24, 2017
89dc380
Fix default case running instead of case 3
alganthe Sep 28, 2017
15478f8
Fix edge case related to players being in garrison group
alganthe Sep 28, 2017
186bf7f
Fix some arrays in garrsionMove and garrison
alganthe Sep 28, 2017
6555a4b
Relax distance checks in garrisonMove, change AI behaviour while path…
alganthe Sep 28, 2017
d8dafa4
Add debug view
alganthe Sep 29, 2017
10d2321
Remove unused var, fix unit pos using the wrong format
alganthe Sep 29, 2017
343319c
Make debug more visually pleasing
alganthe Sep 29, 2017
f0795e1
Change garrison debug target to a waypoint icon
alganthe Sep 30, 2017
b5e1e3c
Change disableAI event to AISection, comment out doFollow in doMove EH
alganthe Oct 2, 2017
b23492a
Fix locality issue
alganthe Oct 10, 2017
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: 2 additions & 0 deletions addons/common/XEH_PREP.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ PREP(fixCollision);
PREP(fixFloating);
PREP(fixLoweredRifleAnimation);
PREP(fixPosition);
PREP(garrison);
Copy link
Member

Choose a reason for hiding this comment

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

Unsure if these functions belong in common or not 😝

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd say ace_ai, despite it not having any sqf atm.

Copy link
Member

Choose a reason for hiding this comment

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

Doesn't CBA now have garrison functions that could be used instead? If not, then yeah, those should go into ace_ai component.

PREP(getAllDefinedSetVariables);
PREP(getDeathAnim);
PREP(getDefaultAnim);
Expand Down Expand Up @@ -165,6 +166,7 @@ PREP(toBitmask);
PREP(toHex);
PREP(toNumber);
PREP(unhideUnit);
PREP(unGarrison);
PREP(uniqueElements);
PREP(unloadPerson);
PREP(unloadPersonLocal);
Expand Down
11 changes: 11 additions & 0 deletions addons/common/XEH_postInit.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,17 @@ if (isServer) then {
[QGVAR(switchMove), {(_this select 0) switchMove (_this select 1)}] call CBA_fnc_addEventHandler;
[QGVAR(setVectorDirAndUp), {(_this select 0) setVectorDirAndUp (_this select 1)}] call CBA_fnc_addEventHandler;
[QGVAR(setVanillaHitPointDamage), {(_this select 0) setHitPointDamage (_this select 1)}] call CBA_fnc_addEventHandler;
[QGVAR(doMove), {(_this select 0) doMove (_this select 1)}] call CBA_fnc_addEventHandler;
[QGVAR(doFollow), {(_this select 0) doMove (_this select 1)}] call CBA_fnc_addEventHandler;

[QGVAR(disableAI), {
params [["_units", [], [[]]], "_section"];
{_x disableAI _section} foreach (_units select {local _x});
}] call CBA_fnc_addEventHandler;
[QGVAR(enableAI), {
params [["_units", [], [[]]], "_section"];
{_x enableAI _section} foreach (_units select {local _x});
}] call CBA_fnc_addEventHandler;

// Request framework
[QGVAR(requestCallback), FUNC(requestCallback)] call CBA_fnc_addEventHandler;
Expand Down
173 changes: 173 additions & 0 deletions addons/common/functions/fnc_garrison.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/*
* Author: alganthe
* Garrison function used to garrison AI inside buildings.
*
* Arguments:
* 0: The building(s) nearest this position are used <POSITION>
* 1: Limit the building search to those type of building <ARRAY>
* 2: Units that will be garrisoned <ARRAY>
* 3: Radius to fill building(s) <SCALAR> default: 50
* 4: 0: even filling, 1: building by building, 2: random filling <SCALAR> default: 0
* 5: True to fill building(s) from top to bottom <BOOL> default: false

* Return Value:
* Array of units not garrisoned
*
* Public: Yes
*
* Example:
* [position, nil, [unit1, unit2, unit3, unitN], 200, 1, false] call ace_common_fnc_garrison
*/
#include "script_component.hpp"

params [["_startingPos",[0,0,0], [[]], 3], ["_buildingTypes", ["Building"], [[]]], ["_unitsArray", [], [[]]], ["_fillingRadius", 50, [0]], ["_fillingType", 0, [0]], ["_topDownFilling", false, [true]]];

_unitsArray = _unitsArray select {alive _x && {!isPlayer _x}};

if (_startingPos isEqualTo [0,0,0]) exitWith {
[LSTRING(GarrisonInvalidPosition)] call EFUNC(common,displayTextStructured);
};

if (count _unitsArray == 0 || {isNull (_unitsArray select 0)}) exitWith {
[LSTRING(GarrisonNoUnits)] call EFUNC(common,displayTextStructured);
};

private _buildings = [];

if (_fillingRadius < 50) then {
_buildings = nearestObjects [_startingPos, _buildingTypes, 50];
} else {
_buildings = nearestObjects [_startingPos, _buildingTypes, _fillingRadius];
_buildings = _buildings call BIS_fnc_arrayShuffle;
};

if (count _buildings == 0) exitWith {
[LSTRING(GarrisonNoBuilding)] call EFUNC(common,displayTextStructured);
};

private _buildingsIndexes = [];

if (_topDownFilling) then {
{
private _buildingPos = _x buildingPos -1;

// Those reverse are necessary, as dumb as it is there's no better way to sort those subarrays in sqf
{
reverse _x;
} foreach _buildingPos;

_buildingPos sort false;

{
reverse _x;
} foreach _buildingPos;

_buildingsIndexes pushback _buildingPos;
} foreach _buildings;
} else {
{
_buildingsIndexes pushback (_x buildingPos -1);
} foreach _buildings;
};

// Remove buildings without positions
{
_buildingsIndexes deleteAt (_buildingsIndexes find _x);
} foreach (_buildingsIndexes select {count _x == 0});

// Warn the user that there's not enough positions to place all units
private _count = 0;
{_count = _count + count _x} foreach _buildingsIndexes;
private _leftOverAICount = (count _unitsArray) - _count;
if (_leftOverAICount > 0) then {
[LSTRING(GarrisonNotEnoughPos)] call EFUNC(common,displayTextStructured);
};

private _placedUnits = [];

// Do the placement
switch (_fillingType) do {
case 0: {
while {count _unitsArray > 0} do {
if (count _buildingsIndexes == 0) exitWith {};

private _building = _buildingsIndexes select 0;

if (_building isEqualTo []) then {
_buildingsIndexes deleteAt 0;
} else {
private _pos = _building select 0;

private _nearestUnits = (_pos nearEntities ["CAManBase", 1]);
if (count _nearestUnits > 0 && {count (_nearestUnits select {getPos _x select 2 == _pos select 2}) > 0}) then {
_buildingsIndexes set [0, _building - [_pos]];

} else {
private _unit = _unitsArray select 0;
_unit setPos _pos;
_placedUnits pushBack _unit;
_unitsArray deleteAt (_unitsArray find _unit);
_building deleteAt 0;
_buildingsIndexes deleteAt 0;
_buildingsIndexes pushbackUnique _building;
};
};
};
};

case 1: {
while {count _unitsArray > 0} do {
if (count _buildingsIndexes == 0) exitWith {};

private _building = _buildingsIndexes select 0;

if (_building isEqualTo []) then {
_buildingsIndexes deleteAt 0;
} else {
private _pos = _building select 0;

private _nearestUnits = (_pos nearEntities ["CAManBase", 1]);
if (count _nearestUnits > 0 && {count (_nearestUnits select {getPos _x select 2 == _pos select 2}) > 0}) then {
_buildingsIndexes set [0, _building - [_pos]];

} else {
private _unit = _unitsArray select 0;
_unit setPos _pos;
_placedUnits pushBack _unit;
_unitsArray deleteAt (_unitsArray find _unit);
_buildingsIndexes set [0, _building - [_pos]];
};
};
};
};

case 2: {
while {count _unitsArray > 0} do {
if (count _buildingsIndexes == 0) exitWith {};

private _building = selectRandom _buildingsIndexes;

if (_building isEqualTo []) then {
_buildingsIndexes deleteAt (_buildingsIndexes find _building);
} else {
private _pos = selectRandom _building;

private _nearestUnits = (_pos nearEntities ["CAManBase", 1]);
if (count _nearestUnits > 0 && {count (_nearestUnits select {getPos _x select 2 == _pos select 2}) > 0}) then {
_buildingsIndexes set [(_buildingsIndexes find _building), _building - [_pos]];

} else {
private _unit = _unitsArray select 0;
_unit setPos _pos;
_unitsArray deleteAt (_unitsArray find _unit);
_placedUnits pushBack _unit;
_buildingsIndexes set [(_buildingsIndexes find _building), _building - [_pos]];
};
};
};
};
};

[QGVAR(disableAI), [_placedUnits, "AUTOCOMBAT"], _placedUnits] call CBA_fnc_targetEvent;
[QGVAR(disableAI), [_placedUnits, "PATH"], _placedUnits] call CBA_fnc_targetEvent;
_unitsArray
45 changes: 45 additions & 0 deletions addons/common/functions/fnc_unGarrison.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Author: alganthe
* Used to un-garrison units garrisoned with ace_common_fnc_garrison
*
* Arguments:
* 0: Array of units to un-garrison <ARRAY>
*
* Return Value:
* Nothing
*
* Public: Yes
*
*/
#include "script_component.hpp"

params [["_unitsArray", [], [[]]]];

{
if !(isPlayer _x) then {
if (local _x) then {
_x enableAI "AUTOCOMBAT";
_x enableAI "PATH";
} else {
[QGVAR(enableAI), [_placedUnits, "AUTOCOMBAT"], _placedUnits] call CBA_fnc_targetEvent;
[QGVAR(enableAI), [_placedUnits, "PATH"], _placedUnits] call CBA_fnc_targetEvent;
Copy link
Member

Choose a reason for hiding this comment

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

Not sure why this is being done inside this loop (also this variable doesn't exist).

};

private _leader = leader _x;
if (_leader != _x) then {
doStop _x;
if (local _leader) then {
_x doFollow _leader;
} else {
[QGVAR(doFollow), [_x, _leader], _leader] call CBA_fnc_targetEvent;
};

} else {
if (local _x) then {
_x doMove ((nearestBuilding (getPos _x)) buildingExit 0);
} else {
[QGVAR(doMove), [_x, ((nearestBuilding (getPos _x)) buildingExit 0)], _x] call CBA_fnc_targetEvent;
Copy link
Member

Choose a reason for hiding this comment

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

Rather than sending an event for every unit from within this function, you should be running this whole function via an event from the module function.

Copy link
Contributor

Choose a reason for hiding this comment

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

👍

Also to the note above:

CBA_fnc_targetEvent will send the event to every machine where at least one element of the array is local. If there are object with different localities in the array, it will execute the commands on each of those machines for every object, even if remote. But I guess that would still work for these.

};
};
};
} foreach _unitsArray;
16 changes: 16 additions & 0 deletions addons/common/stringtable.xml
Original file line number Diff line number Diff line change
Expand Up @@ -874,5 +874,21 @@
<Russian>Нет места для выгрузки</Russian>
<Japanese>降ろすための空間がありません</Japanese>
</Key>
<Key ID="STR_ACE_Common_GarrisonInvalidPosition">
<English>Invalid position provided.</English>
<French>Position invalide fourni</French>
</Key>
<Key ID="STR_ACE_Common_GarrisonNoUnits">
<English>No units provided.</English>
<French>Aucune unité fourni</French>
</Key>
<Key ID="STR_ACE_Common_GarrisonNotEnoughPos">
<English>There isn't enough positions to place all units.</English>
Copy link
Member

Choose a reason for hiding this comment

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

aren't

<French>Il n'y a pas assez de positions pour placer toutes les unités</French>
</Key>
<Key ID="STR_ACE_Common_GarrisonNoBuilding">
<English>No building found.</English>
<French>Aucun bâtiment trouvé</French>
</Key>
</Package>
</Project>
12 changes: 12 additions & 0 deletions addons/zeus/CfgVehicles.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,4 +174,16 @@ class CfgVehicles {
function = QFUNC(moduleUnconscious);
icon = QPATHTOF(UI\Icon_Module_Zeus_Unconscious_ca.paa);
};
class GVAR(moduleGarrison): GVAR(moduleBase) {
curatorCanAttach = 1;
displayName = CSTRING(ModuleGarrison_DisplayName);
curatorInfoType = QGVAR(RscGarrison);
icon = QPATHTOF(UI\Icon_Module_Zeus_Garrison_ca.paa);
};
class GVAR(moduleUnGarrison): GVAR(moduleBase) {
Copy link
Member

Choose a reason for hiding this comment

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

Not sure if I like having a separate module to undo the effects of another, could combine these into 1 by having a UI option to un-garrison - that way there's a single module that handles all things garrison.

Though that's just a thought, very much unsure what works better in terms of UX (if anyone else has thoughts on this please chime in).

Copy link
Member

Choose a reason for hiding this comment

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

We should decide with what and stick with it. Currently there is already add/remove Virtual Arsenal which is 2 modules. Can always streamline into 1 later if it would be better.

curatorCanAttach = 1;
displayName = CSTRING(ModuleUnGarrison_DisplayName);
function = QFUNC(moduleUnGarrison);
icon = QPATHTOF(UI\Icon_Module_Zeus_UnGarrison_ca.paa);
};
};
3 changes: 3 additions & 0 deletions addons/zeus/XEH_PREP.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ PREP(handleZeusUnitAssigned);
PREP(moduleAddSpareTrack);
PREP(moduleAddSpareWheel);
PREP(moduleCaptive);
PREP(moduleGarrison);
PREP(moduleGlobalSetSkill);
PREP(moduleGroupSide);
PREP(moduleSearchNearby);
Expand All @@ -17,11 +18,13 @@ PREP(moduleSetMedicalFacility);
PREP(moduleSurrender);
PREP(moduleTeleportPlayers);
PREP(moduleUnconscious);
PREP(moduleUnGarrison);
PREP(moduleZeusSettings);
PREP(ui_attributeCargo);
//PREP(ui_attributePosition);
PREP(ui_attributeRadius);
PREP(ui_defendArea);
PREP(ui_garrison);
PREP(ui_globalSetSkill);
PREP(ui_groupSide);
PREP(ui_patrolArea);
Expand Down
4 changes: 3 additions & 1 deletion addons/zeus/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ class CfgPatches {
QGVAR(modulePatrolArea),
QGVAR(moduleSearchArea),
QGVAR(moduleSearchNearby),
QGVAR(moduleTeleportPlayers)
QGVAR(moduleTeleportPlayers),
QGVAR(moduleGarrison),
QGVAR(moduleUnGarrison)
};
weapons[] = {};
requiredVersion = REQUIRED_VERSION;
Expand Down
57 changes: 57 additions & 0 deletions addons/zeus/functions/fnc_moduleGarrison.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Author: alganthe
* Module calling the garrison function
Copy link
Member

Choose a reason for hiding this comment

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

Missing final dot.

*
* Arguments:
* 0: The module logic <OBJECT>
Copy link
Member

Choose a reason for hiding this comment

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

The is superfluous.

* 1: Position of the module <POSITION>
* 2: Radius of the task <NUMBER>
* 3: Filling mode of the garrison function <NUMBER>
* 4: Enable or not top down filling <BOOLEAN>
Copy link
Member

Choose a reason for hiding this comment

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

<BOOL>

*
* Return Value:
* None
*/

#include "script_component.hpp"

params ["_logic", "_pos", "_radius" ,"_mode" , "_topDownMode"];

private _unit = (attachedTo _logic);
private _building = nearestBuilding (getPosASL _unit);

// Handles errors
Copy link
Member

Choose a reason for hiding this comment

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

Validation of the module target should only be taking place in the ui function (it doesn't make sense to show zeus a UI and then tell them they placed the module wrong only after they close it).

Copy link
Contributor

Choose a reason for hiding this comment

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

Only true if the zeus interface updates in real time. I think it's fine to have the check in both

Copy link
Member

Choose a reason for hiding this comment

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

Actually, good point. The unit could be deleted between the UI opening and closing. Can safely ignore my initial comment 👍

scopeName "Main";
private _fnc_errorAndClose = {
params ["_msg"];
deleteVehicle _logic;
[_msg] call EFUNC(common,displayTextStructured);
breakOut "Main";
};

switch (false) do {
case !(isNull _unit): {
[LSTRING(NothingSelected)] call _fnc_errorAndClose;
};
case (_unit isKindOf "CAManBase"): {
[LSTRING(OnlyInfantry)] call _fnc_errorAndClose;
};
case (alive _unit): {
[LSTRING(OnlyAlive)] call _fnc_errorAndClose;
};
case (_unit distance _building < 500): {
[LSTRING(BuildingTooFar)] call _fnc_errorAndClose;
};
};

private _units = units _unit;
// Make sure all units are disembarked.
Copy link
Member

Choose a reason for hiding this comment

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

No final dot.

{
if (vehicle _x != _x) then {
moveOut _x;
};
} forEach _units;

[_pos, ["Building"], _units, _radius, _mode, _topDownMode] call EFUNC(common,garrison);

deleteVehicle _logic;
Loading