Skip to content

Commit

Permalink
Rebase before review
Browse files Browse the repository at this point in the history
  • Loading branch information
alganthe committed Sep 27, 2017
1 parent 315e50b commit adb2d65
Show file tree
Hide file tree
Showing 10 changed files with 376 additions and 61 deletions.
1 change: 1 addition & 0 deletions addons/ai/XEH_PREP.hpp
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
PREP(garrison);
PREP(unGarrison);
PREP(garrisonMove);
34 changes: 32 additions & 2 deletions addons/ai/XEH_postInit.sqf
Original file line number Diff line number Diff line change
@@ -1,8 +1,38 @@
#include "script_component.hpp"

[QGVAR(disableAI), {
params [["_units", [], [[]]], "_section"];
{_x disableAI _section} foreach (_units select {local _x});
params [["_units", [], [[]]], ["_sections", [], [[]]]];
{
private _section = _x;
{
_x disableAI _section;
LOG(format [ARR_4("XEH_postInit: %1 disableAI %2 | ID %3", _x, _section, clientOwner)]);
} foreach (_units select {local _x});
} foreach _sections
}] call CBA_fnc_addEventHandler;

[QGVAR(unGarrison), FUNC(unGarrison)] call CBA_fnc_addEventHandler;
[QGVAR(doMove), {
params ["_unitsArray"];
{
_x params ["_unit", "_pos"];
_unit doMove _pos;
LOG(format [ARR_4("XEH_postInit: %1 doMove %2 | ID %3", _unit, _pos, clientOwner)]);
} foreach _unitsArray
}] call CBA_fnc_addEventHandler;
[QGVAR(setBehaviour), {
params ["_groupsArray", "_behaviour"];
{
_x params ["_group"];
_group setBehaviour _behaviour;
LOG(format [ARR_4("XEH_postInit: %1 setBehaviour %2 | ID %3", _group, _behaviour, clientOwner)]);
} foreach _groupsArray
}] call CBA_fnc_addEventHandler;
[QGVAR(enableAttack), {
params ["_unitsArray", "_mode"];
{
_x params ["_unit"];
_unit enableAttack _mode;
LOG(format [ARR_4("XEH_postInit: %1 enableAttack %2 | ID %3", _unit, _mode, clientOwner)]);
} foreach _unitsArray
}] call CBA_fnc_addEventHandler;
191 changes: 147 additions & 44 deletions addons/ai/functions/fnc_garrison.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,32 @@
* 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)
* 5: True to fill building(s) from top to bottom <BOOL> (default: false) (note: only works with filling mode 0 and 1)
* 6: Teleport units <BOOL> (default: false)
* Return Value:
* Units not garrisoned <ARRAY>
*
* Example:
* [position, nil, [unit1, unit2, unit3, unitN], 200, 1, false] call ace_ai_fnc_garrison
* [position, nil, [unit1, unit2, unit3, unitN], 200, 1, false, false] call ace_ai_fnc_garrison
*
* Public: Yes
*/
#include "script_component.hpp"

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

TRACE_6("fnc_garrison start",_startingPos,_buldingTypes,_unitsArray,_fillingRadius,_fillingTYpe,_topDownFilling);
TRACE_6("fnc_garrison: Start",_startingPos,_buldingTypes,count _unitsArray,_fillingRadius,_fillingTYpe,_topDownFilling);

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

if (_startingPos isEqualTo [0,0,0]) exitWith {
TRACE_1("fnc_garrison startingPos error",_startingPos);
TRACE_1("fnc_garrison: StartingPos error",_startingPos);
[LSTRING(GarrisonInvalidPosition)] call EFUNC(common,displayTextStructured);
};

if (count _unitsArray == 0 || {isNull (_unitsArray select 0)}) exitWith {
TRACE_1("fnc_garrison units error",_unitsArray);
TRACE_1("fnc_garrison: Units error",_unitsArray);
[LSTRING(GarrisonNoUnits)] call EFUNC(common,displayTextStructured);
};

Expand All @@ -42,11 +43,11 @@ if (_fillingRadius >= 50) then {
};

if (count _buildings == 0) exitWith {
TRACE_1("fnc_garrison building error",_buildings);
TRACE_1("fnc_garrison: Building error",_buildings);
[LSTRING(GarrisonNoBuilding)] call EFUNC(common,displayTextStructured);
};

private _buildingsIndexes = [];
private _buildingsIndex = [];

if (_topDownFilling) then {
{
Expand All @@ -63,111 +64,213 @@ if (_topDownFilling) then {
reverse _x;
} foreach _buildingPos;

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

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

//Remove positions units are already pathing to
_buildingsIndex = _buildingsIndex apply {
private _testedBuilding = _x;

_testedBuilding select {
private _testedPos = _x;
(({(_x select 1) isEqualTo _testedPos} count (missionNameSpace getVariable [QGVAR(garrison_unitMoveList), []])) == 0)
}
};

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

private _placedUnits = [];
private _unitMoveList = [];

// Force all units to un-garrison
[QGVAR(unGarrison), [_unitsArray], _unitsArray] call CBA_fnc_targetEvent;

private _fnc_comparePos = {
params ["_nearestUnits", "_pos"];
({
if (surfaceIsWater getPos _x) then {
floor ((getPosASL _x) select 2) == floor ((AGLtoASL _pos) select 2)
} else {
floor ((getPosATL _x) select 2) == floor (_pos select 2)
};
} count _nearestUnits) > 0
};

// Do the placement
switch (_fillingType) do {

// Even filling
case 0: {

while {count _unitsArray > 0} do {
if (count _buildingsIndexes == 0) exitWith {};
private _building = _buildingsIndexes select 0;
if (count _buildingsIndex == 0) exitWith {};
private _building = _buildingsIndex select 0;

if (_building isEqualTo []) then {
_buildingsIndexes deleteAt 0;
LOG(format [ARR_2("fnc_garrison: Empty building array | removing building from buildingsIndex | %1 buildings remaining",count _buildingsIndex)]);
_buildingsIndex deleteAt 0;

} else {
private _pos = _building select 0;
private _nearestUnits = (_pos nearEntities ["CAManBase", 1]);
private _nearestUnits = (_pos nearEntities ["CAManBase", 2]);
LOG(format [ARR_3("fnc_garrison: Unit detection | %1 units nearby | %2 units within height",count _nearestUnits, {floor ((getPos _x) select 2) == floor (_pos select 2)} count _nearestUnits)]);

if (count _nearestUnits > 0 && {[_nearestUnits, _pos] call _fnc_comparePos}) then {
LOG(format [ARR_2("fnc_garrison: Unit present | removing position | %1 positions remaining for this building",count (_buildingsIndex select (_buildingsIndex find _building)) - 1)]);
_buildingsIndex set [0, _building - [_pos]];

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;
private _posSurface = surfaceIsWater _pos;

if (_teleport) then {
doStop _unit;
if (_posSurface) then {
_unit setPosASL (AGLtoASL _pos);
} else {
_unit setPosATL _pos;
};

} else {
_unitMoveList pushBack [_unit,[_pos, AGLToASL _pos] select (_posSurface)];
};

_placedUnits pushBack _unit;
_unitsArray deleteAt (_unitsArray find _unit);
_building deleteAt 0;
_buildingsIndexes deleteAt 0;
_buildingsIndexes pushBackUnique _building;
_buildingsIndex deleteAt 0;
_buildingsIndex pushBackUnique _building;
_unit setVariable [QGVAR(garrisonned), true, true];
};
};
};
};

// Building by building
case 1: {

while {count _unitsArray > 0} do {
if (count _buildingsIndexes == 0) exitWith {};
private _building = _buildingsIndexes select 0;
if (count _buildingsIndex == 0) exitWith {};
private _building = _buildingsIndex select 0;

if (_building isEqualTo []) then {
_buildingsIndexes deleteAt 0;
LOG(format [ARR_2("fnc_garrison: empty building array | removing building from buildingsIndex | %1 buildings remaining",count _buildingsIndex)]);
_buildingsIndex deleteAt 0;

} else {
private _pos = _building select 0;
private _nearestUnits = (_pos nearEntities ["CAManBase", 1]);
private _nearestUnits = (_pos nearEntities ["CAManBase", 2]);
LOG(format [ARR_3("fnc_garrison: Unit detection | %1 units nearby | %2 units within height",count _nearestUnits, {floor ((getPos _x) select 2) == floor (_pos select 2)} count _nearestUnits)]);

if (count _nearestUnits > 0 && {[_nearestUnits, _pos] call _fnc_comparePos}) then {
LOG(format [ARR_2("fnc_garrison: Unit present | removing position | %1 positions remaining for this building",count (_buildingsIndex select (_buildingsIndex find _building)) - 1)]);
_buildingsIndex set [0, _building - [_pos]];

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;
private _posSurface = surfaceIsWater _pos;

if (_teleport) then {
doStop _unit;
if (_posSurface) then {
_unit setPosASL (AGLtoASL _pos);
} else {
_unit setPosATL _pos;
};

} else {
_unitMoveList pushBack [_unit,[_pos, AGLToASL _pos] select (_posSurface)];
};

_placedUnits pushBack _unit;
_unitsArray deleteAt (_unitsArray find _unit);
_buildingsIndexes set [0, _building - [_pos]];
_buildingsIndex set [0, _building - [_pos]];
_unit setVariable [QGVAR(garrisonned), true, true];
};
};
};
};

// Random
case 2: {

while {count _unitsArray > 0} do {
if (count _buildingsIndexes == 0) exitWith {};
private _building = selectRandom _buildingsIndexes;
if (count _buildingsIndex == 0) exitWith {};
private _building = selectRandom _buildingsIndex;

if (_building isEqualTo []) then {
_buildingsIndexes deleteAt (_buildingsIndexes find _building);
LOG(format [ARR_2("fnc_garrison: empty building array | removing building from buildingsIndex | %1 buildings remaining",count _buildingsIndex)]);
_buildingsIndex deleteAt (_buildingsIndex find _building);

} else {
private _pos = selectRandom _building;
private _nearestUnits = (_pos nearEntities ["CAManBase", 1]);
private _nearestUnits = (_pos nearEntities ["CAManBase", 2]);
LOG(format [ARR_3("fnc_garrison: Unit detection | %1 units nearby | %2 units within height",count _nearestUnits, {floor ((getPos _x) select 2) == floor (_pos select 2)} count _nearestUnits)]);

if (count _nearestUnits > 0 && {[_nearestUnits, _pos] call _fnc_comparePos}) then {
LOG(format [ARR_2("fnc_garrison: Unit present | removing position | %1 positions remaining for this building",count (_buildingsIndex select (_buildingsIndex find _building)) - 1)]);
_buildingsIndex set [(_buildingsIndex find _building), _building - [_pos]];

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);
private _posSurface = surfaceIsWater _pos;

if (_teleport) then {
doStop _unit;
if (_posSurface) then {
_unit setPosASL (AGLtoASL _pos);
} else {
_unit setPosATL _pos;
};

} else {
_unitMoveList pushBack [_unit,[_pos, AGLToASL _pos] select (_posSurface)];
};

_placedUnits pushBack _unit;
_buildingsIndexes set [(_buildingsIndexes find _building), _building - [_pos]];
_unitsArray deleteAt (_unitsArray find _unit);
_buildingsIndex set [(_buildingsIndex find _building), _building - [_pos]];
_unit setVariable [QGVAR(garrisonned), true, true];
};
};
};
};
};

[QGVAR(disableAI), [_placedUnits, "AUTOCOMBAT"], _placedUnits] call CBA_fnc_targetEvent;
[QGVAR(disableAI), [_placedUnits, "PATH"], _placedUnits] call CBA_fnc_targetEvent;
TRACE_2("fnc_garrison ended, leftover units",_unitsArray,count _unitsArray);
TRACE_1(format [ARR_2("fnc_garrison: while loop ended | %1 units ready to be treated by PFH",count _unitMoveList)], _teleport);

// Update the unit list and remove duplicate positions and units
private _garrison_unitMoveList = missionNameSpace getVariable [QGVAR(garrison_unitMoveList), []];
_garrison_unitMoveList append (_unitMoveList select {
_x params ["_testedUnit", "_testedPos"];
(({(_x select 0) isEqualTo _testedUnit} count _garrison_unitMoveList) == 0) &&
(({(_x select 1) isEqualTo _testedPos} count _garrison_unitMoveList) == 0)
});

missionNameSpace setVariable [QGVAR(garrison_unitMoveList), _garrison_unitMoveList, true];

if (_teleport) then {
[QGVAR(disableAI), [_placedUnits, ["PATH"]], _placedUnits] call CBA_fnc_targetEvent;

} else {
[_unitMoveList] call FUNC(garrisonMove);
};

TRACE_1(format [ARR_3("fnc_garrison: End | %1 units left | %2 buildings left", count _unitsArray, count _buildingsIndex)], _unitsArray);
_unitsArray
Loading

0 comments on commit adb2d65

Please sign in to comment.