Jump to content
Zenophon

Release - Infantry Occupy House Script

Recommended Posts

I don't really see many buildings in the editor, so I'm assuming it's equivalent to spawning them with createVehicle. Once the building is detected, it's preset positions will be accessible, so it's just a matter of getting the object.

Did you try the fill radius argument as e.g. 50 or so meters?  This will make the script use the nearestObjects command; using -1 will have it use nearestBuilding, which might be where the issue is. nearestObjects is working for me; try this in the debug console with a spawned building.

buildingsArray0 = nearestObjects [getPosATL player, ["house"], 50];
buildingsArray1 = nearestObjects [getPosATL player, ["building"], 50];
hint str (buildingsArray0 arrayIntersect buildingsArray1)

This is basically what the script uses; it just replaces the position and distance with its arguments. I can replace nearestBuilding when using '-1' with nearestObjects and just select the first one; but then I'd have to figure out a distance to search in that not inefficiently large or too small to find anything.

 

Changing the -1 to a radius did the trick.  Not sure why I didn't try that.  Thanks.

Share this post


Link to post
Share on other sites

Hey. i was wondering if there is a way to add buildings and military houses to this script from Arma 2 maps like taviana? thanks

Share this post


Link to post
Share on other sites

There is no information about specific buildings in the script. If a building is detectable by nearestObjects command and has preset buildingPos spots near windows, the script should be able to do something with it. It's mostly up to the building's config as to whether or not it will work. Test it out (use a radius that includes the building instead of -1) and see what happens.
 

Share this post


Link to post
Share on other sites

Nice script you have made wondering if i could get a little help I just cant get it to work

 

_x = 0;
for "_x" from 0 to PARAMS_GarrBuildings do {
_randomPos = [[[getMarkerPos currentAO, PARAMS_AOSize],_dt],["water","out"]] call BIS_fnc_randomPos;
_spawnGroup = [_randomPos, EAST, (configfile >> "CfgGroups" >> "East" >> "OPF_F" >> "Infantry" >> "OIA_InfSquad")] call BIS_fnc_spawnGroup;
if(random 1 > 0) then {"O_Soldier_AA_F" createUnit [_randomPos, _spawnGroup];};
[_spawnGroup, _pos] call BIS_fnc_taskDefend;
 
nul = [currentAO, _spawnGroup,(random(300)+25), true, true, true] execVM "scripts\Zen_OccupyHouse.sqf";
_enemiesArray = _enemiesArray + [_spawnGroup];
};

Share this post


Link to post
Share on other sites

You don't need _x = 0, and _x should be reserved for forEach loops. Next, I'm assuming the global variables PARAMS_GarrBuildings, currentAO, and PARAMS_AOSize as well as local variables _dt, _pos, and _enemiesArray are properly defined. Using pushBack on _enemiesArray is more efficient than + [].

I see currentAO being used as a marker; Zen_OccupyHouse requires that the first argument is a position. Then, the second argument is a group, when it should be an array of units. The other arguments look good. All those changes give:
 

for "_i" from 0 to PARAMS_GarrBuildings do {
    _randomPos = [[[getMarkerPos currentAO, PARAMS_AOSize],_dt],["water","out"]] call BIS_fnc_randomPos;
    _spawnGroup = [_randomPos, EAST, (configFile >> "CfgGroups" >> "East" >> "OPF_F" >> "Infantry" >> "OIA_InfSquad")] call BIS_fnc_spawnGroup;
    if (random 1 > 0) then {"O_Soldier_AA_F" createUnit [_randomPos, _spawnGroup];};
    [_spawnGroup, _pos] call BIS_fnc_taskDefend;

    nul = [getMarkerPos currentAO, units _spawnGroup,(random(300)+25), true, true, true] execVM "scripts\Zen_OccupyHouse.sqf";
    _enemiesArray pushBack _spawnGroup;
};

Share this post


Link to post
Share on other sites

Cant you just mention classnames of enemy ai for the script to choose from? I mean is it necessary to spawn everyunit via createunit/creategroup? O.o

Share this post


Link to post
Share on other sites

This is not a spawning script; the method of spawning the units has no impact on the effects of this script. It's intended to work in the editor and with SQF scripts that spawn units. Spawning units leads to things like AI skill, loadouts, etc. that are up to the mission maker and outside the scope of this script. There are many scripts and systems for spawning units out there; anything that returns the units it spawned can be used with this script.

Share this post


Link to post
Share on other sites
1 hour ago, davidoss said:

Very nice script

Yessir.  Love this script.  This is a must have script for any mission maker.  Simple to use, and it removes all the hassle of placing units in buildings.  Very flexible and easy to:

  • Place units in single building
  • Spread out units randomly over multiple buildings.
  • Have units move to positions in buildings rather than start in those positions.

 

Share this post


Link to post
Share on other sites

"Fuggedaboutit"

 

Edit. I got this working in the editor with placed units, but have been unable to get it working in the escape mission that spawns units.


Zen_OccupyHouse = compileFinal preprocessFileLineNumbers "Zen_OccupyHouse.sqf";
_blackList = [group player, group Y];

{
   if ((side _x != WEST) && {!(_x in _blackList)}) then {
       0 = [getPosATL leader _x, units _x, -1, true, true] call Zen_OccupyHouse;
   };
} forEach allGroups;

 

This is what  I used in the editor to call the script, in the mp mission I also tried adding if (!isServer && isNull player) then...and closed it }; after the zen code. Anybody any idea why it isn't working n the mp mission?

Also in the editor it seems it doesn't like quite a few buildings that have preset buildingPos spots that work with ALiVE. This might be because the window is too far, but I don't think it is and it still doesn't place them on roof positions either.

Finally how do you reduce the numbers it uses and is there a way to make it select from individual units instead of groups?

Share this post


Link to post
Share on other sites

If you place code anywhere in the editor that runs on mission start (i.e. not a trigger), it will run before an external spawning script; at the time it runs those spawned units don't exist.  Anything that acts on the spawned units must run after the spawning code; also be aware of the spawning script using 'spawn' or 'execVM', which will run it on another thread.  You would end up with something like

_units = [...] call <Spawning_Function>;

// if you want different positions you'll need a similar loop over the groups/units
0 = [..., _units, ...] call Zen_OccupyHouse;

or

0 = [...] spawn <Spawning_Function>;

waitUntil {
    // determine when <Spawning_Function> has finished
}

// you'll also need another way to get the objects
_units = ...
0 = [..., _units, ...] call Zen_OccupyHouse;

Any script using the 'buildingPos' command is entirely dependent upon the building being configured correctly.  It is possible to generate entirely dynamic positions within a building, but this is more computationally expensive and can result in odd/bad positions.

 

If you want Zen_OccupyHouse to only use part of a group, you'll need to select them somehow (i.e. any slicing/selecting function/command, maybe shuffle/sort before etc.) from the full list, e.g.

// pick the first two units
0 = [getPosATL leader _x, (units _x) select [0, 2], -1, true, true] call Zen_OccupyHouse;

 

  • Like 1

Share this post


Link to post
Share on other sites

I would love to use this in my mission but sadly i cannot get it to work. Here's what i did:

 

___________________________

-Opened a brand new map (no mods, no scripts, nothing)

-Saved the mission and put your script into the mission folder

-spawned an AI group right next to a house

-put the following code into the group leaders init:

 

0 = [getPosATL player, units group this, -1, false, false] execVM "Zen_OccupyHouse.sqf";

 

-hit "Play Scenario"

____________________________

 

The AI still stands where initially put them. What am i missing here?

 

37d3693fee11788a0fbc83282247d3c8.jpg

Share this post


Link to post
Share on other sites

Just tried with 2 man sentry team next to house in Stratis

0 = [getPosATL player, units group this, -1, false, false] execVM "Zen_OccupyHouse.sqf";

 

and works no problem they were both upstairs. Are you sure you have the Zen_OccupyHouse.sqf in the root Mission folder?

Share this post


Link to post
Share on other sites

Okay. It does work in Singleplayer, but when i host it locally it does not. Does anyone know a fix for that?

 

EDIT: Okay it works with if isServer

 

Quote

if (isServer) then {0 = [getPosATL this, units group this, -1, false, false] execVM "Zen_OccupyHouse.sqf";};

 

Share this post


Link to post
Share on other sites

made a small change to JBOY UpDown script.  added a logic statement that lockouts further while loops from exec if one is already running. then removes EH based on eventhandler index id for the unit 

Spoiler

// Infantry Occupy House
// by Zenophon
// Released under Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0)
// http://creativecommons.org/licenses/by-nc/4.0/

// Teleports the units to random windows of the building(s) within the distance
// Faces units in the right direction and orders them to stand up or crouch on a roof
// Units will only fill the building to as many positions as there are windows
// Multiple buildings can be filled either evenly or to the limit of each sequentially
// Usage : Call, execVM
// Params: 1. Array, the building(s) nearest this position is used
//         2. Array of objects, the units that will garrison the building(s)
//  (opt.) 3. Scalar, radius in which to fill building(s), -1 for only nearest building, (default: -1)
//  (opt.) 4. Boolean, true to put units on the roof, false for only inside, (default: false)
//  (opt.) 5. Boolean, true to fill all buildings in radius evenly, false for one by one, (default: false)
//  (opt.) 6. Boolean, true to fill from the top of the building down, (default: false)
//  (opt.) 7. Boolean, true to order AI units to move to the position instead of teleporting, (default: false)
// Return: Array of objects, the units that were not garrisoned

#define I(X) X = X + 1;
#define EVAL(X) (X call _comparator)
#define EYE_HEIGHT 1.53
#define CHECK_DISTANCE 5
#define FOV_ANGLE 10
#define ROOF_CHECK 4
#define ROOF_EDGE 2

private ["_center", "_units", "_buildingRadius", "_putOnRoof", "_fillEvenly", "_Zen_ExtendPosition", "_buildingsArray", "_buildingPosArray", "_buildingPositions", "_posArray", "_unitIndex", "_j", "_building", "_posArray", "_randomIndex", "_housePos", "_startAngle", "_i", "_checkPos", "_hitCount", "_isRoof", "_edge", "_k", "_unUsedUnits", "_array", "_sortHeight", "_Zen_InsertionSort", "_Zen_ArrayShuffle", "_doMove"];

_center = _this param [0, [0,0,0], [[]], 3];
_units = _this param [1, [objNull], [[]]];
_buildingRadius = _this param [2, -1, [0]];
_putOnRoof = _this param [3, false, [true]];
_fillEvenly = _this param [4, false, [true]];
_sortHeight = _this param [5, false, [true]];
_doMove = _this param [6, false, [true]];

if (_center isEqualTo [0,0,0]) exitWith {
    player sideChat str "Zen_Occupy House Error : Invalid position given.";
    diag_log "Zen_Occupy House Error : Invalid position given.";
    ([])
};

if ((count _units == 0) || {isNull (_units select 0)}) exitWith {
    player sideChat str "Zen_Occupy House Error : No units given.";
    diag_log "Zen_Occupy House Error : No units given.";
    ([])
};

_Zen_ExtendPosition = {
    private ["_center", "_dist", "_phi"];

    _center = _this select 0;
    _dist = _this select 1;
    _phi = _this select 2;

    ([(_center select 0) + (_dist * (cos _phi)),(_center select 1) + (_dist * (sin _phi)), (_this select 3)])
};

_Zen_InsertionSort = {
    private ["_i", "_j", "_count", "_array", "_element", "_value", "_comparator"];

    _array = _this select 0;
    _comparator = _this select 1;
    _count = count _array - 1;

    if (count _array == 0) exitWith {};
    for "_i" from 1 to _count step 1 do {
        scopeName "forI";
        _element = _array select _i;
        _value = EVAL(_element);

        for [{_j = _i}, {_j >= 1}, {_j = _j - 1}] do {
            if (_value > EVAL(_array select (_j - 1))) then {
                breakTo "forI";
            };
            _array set [_j, _array select (_j - 1)];
        };

        _array set [_j, _element];
    };
    if (true) exitWith {};
};

_Zen_ArrayShuffle = {
    private ["_array", "_j", "_i", "_temp"];
    _array = _this select 0;

    if (count _array > 1) then {
        for "_i" from 0 to (count _array - 1) do {
                _j = _i + floor random ((count _array) - _i);
                _temp = _array select _i;
                _array set [_i, (_array select _j)];
                _array set [_j, _temp];
        };
    };
    if (true) exitWith {};
};

if (_buildingRadius < 0) then {
    _buildingsArray = [nearestBuilding _center];
} else {
    _buildingsArray0 = nearestObjects [_center, ["house"], _buildingRadius];
    _buildingsArray1 = nearestObjects [_center, ["building"], _buildingRadius];
    _buildingsArray = _buildingsArray0 arrayIntersect _buildingsArray1;
};

if (count _buildingsArray == 0) exitWith {
    player sideChat str "Zen_Occupy House Error : No buildings found.";
    diag_log "Zen_Occupy House Error : No buildings found.";
    ([])
};

_buildingPosArray = [];
0 = [_buildingsArray] call _Zen_ArrayShuffle;
{
    _posArray = [];
    for "_i" from 0 to 1000 do {
        if ((_x buildingPos _i) isEqualTo [0,0,0]) exitWith {};
        _posArray pushBack (_x buildingPos _i);
    };

    _buildingPosArray pushBack _posArray;
} forEach _buildingsArray;

if (_sortHeight) then {
    {
        0 = [_x, {-1 * (_this select 2)}] call _Zen_InsertionSort;
    } forEach _buildingPosArray;
} else {
    {
        0 = [_x] call _Zen_ArrayShuffle;
    } forEach _buildingPosArray;
};

_unitIndex = 0;
for [{_j = 0}, {(_unitIndex < count _units) && {(count _buildingPosArray > 0)}}, {I(_j)}] do {
    scopeName "for";

    _building = _buildingsArray select (_j % (count _buildingsArray));
    _posArray = _buildingPosArray select (_j % (count _buildingPosArray));

    if (count _posArray == 0) then {
        _buildingsArray deleteAt (_j % (count _buildingsArray));
        _buildingPosArray deleteAt (_j % (count _buildingPosArray));
    };

    while {(count _posArray) > 0} do {
        scopeName "while";
        if (_unitIndex >= count _units) exitWith {};

        _housePos = _posArray select 0;
        _posArray deleteAt 0;
        _housePos = [(_housePos select 0), (_housePos select 1), (_housePos select 2) + (getTerrainHeightASL _housePos) + EYE_HEIGHT];

        _startAngle = (round random 10) * (round random 36);
        for "_i" from _startAngle to (_startAngle + 350) step 10 do {
            _checkPos = [_housePos, CHECK_DISTANCE, (90 - _i), (_housePos select 2)] call _Zen_ExtendPosition;
            if !(lineIntersects [_checkPos, [_checkPos select 0, _checkPos select 1, (_checkPos select 2) + 25], objNull, objNull]) then {
                if !(lineIntersects [_housePos, _checkPos, objNull, objNull]) then {
                    _checkPos = [_housePos, CHECK_DISTANCE, (90 - _i), (_housePos select 2) + (CHECK_DISTANCE * tan FOV_ANGLE)] call _Zen_ExtendPosition;
                    if !(lineIntersects [_housePos, _checkPos, objNull, objNull]) then {
                        _hitCount = 0;
                        for "_k" from 30 to 360 step 30 do {
                            _checkPos = [_housePos, 20, (90 - _k), (_housePos select 2)] call _Zen_ExtendPosition;
                            if (lineIntersects [_housePos, _checkPos, objNull, objNull]) then {
                                I(_hitCount)
                            };

                            if (_hitCount >= ROOF_CHECK) exitWith {};
                        };

                        _isRoof = (_hitCount < ROOF_CHECK) && {!(lineIntersects [_housePos, [_housePos select 0, _housePos select 1, (_housePos select 2) + 25], objNull, objNull])};
                        if (!(_isRoof) || {((_isRoof) && {(_putOnRoof)})}) then {
                            if (_isRoof) then {
                                _edge = false;
                                for "_k" from 30 to 360 step 30 do {
                                    _checkPos = [_housePos, ROOF_EDGE, (90 - _k), (_housePos select 2)] call _Zen_ExtendPosition;
                                    _edge = !(lineIntersects [_checkPos, [(_checkPos select 0), (_checkPos select 1), (_checkPos select 2) - EYE_HEIGHT - 1], objNull, objNull]);

                                    if (_edge) exitWith {
                                        _i = _k;
                                    };
                                };
                            };

                            if (!(_isRoof) || {_edge}) then {
                                (_units select _unitIndex) doWatch ([_housePos, CHECK_DISTANCE, (90 - _i), (_housePos select 2) - (getTerrainHeightASL _housePos)] call _Zen_ExtendPosition);

                                (_units select _unitIndex) disableAI "TARGET";
                                if (_doMove) then {
                                    (_units select _unitIndex) doMove ASLToATL ([(_housePos select 0), (_housePos select 1), (_housePos select 2) - EYE_HEIGHT]);
                                } else {
                                    (_units select _unitIndex) setPosASL [(_housePos select 0), (_housePos select 1), (_housePos select 2) - EYE_HEIGHT];
                                    (_units select _unitIndex) setDir _i;

                                    doStop (_units select _unitIndex);
                                    (_units select _unitIndex) forceSpeed 0;
                                };

                               //** JBOY_UpDown by JohnnyBoy //*/
                                #define JBOY_UpDown \
                                    if ((_this select 0) getVariable ["FIREDLOCKOUT", false]) exitWith {}; \
                                    (_this select 0) setVariable ["FIREDLOCKOUT", true]; \
                                    if (!isServer)  exitWith {}; \
                                    _dude = _this select 0; \
                                    _stances = _this select 1; \
                                    _ehid = (_dude getVariable "EHID"); \
                                    _dude removeEventHandler ["FiredNear",_ehid]; \
                                    while {alive _dude} do { \
                                        if ((unitPos _dude) == (_stances select 0)) then { \
                                            _dude setUnitPos (_stances select 1); \
                                        } else { \
                                            _dude setUnitPos (_stances select 0); \
                                        }; \
                                        sleep 5 + (random 2); \
                                    };  
                                    
                                    if (_isRoof) then {
                                    	(_units select _unitIndex) setUnitPos "MIDDLE";
                                       _eh = (_units select _unitIndex) addEventHandler ["FiredNear",{[(_this select 0),["DOWN","MIDDLE"]] spawn {JBOY_UpDown};}];
                                    	(_units select _unitIndex) setVariable ["EHID", _eh];
                                       
                                    } else {
                                    	(_units select _unitIndex) setUnitPos "UP";
                                       _eh = (_units select _unitIndex) addEventHandler ["FiredNear",{[(_this select 0),["UP","MIDDLE"]] spawn {JBOY_UpDown};}];
                                       (_units select _unitIndex) setVariable ["EHID", _eh];
                                      
                                    }; 
								

                                I(_unitIndex)
                                if (_fillEvenly) then {
                                    breakTo "for";
                                } else {
                                    breakTo "while";
                                };
                            };
                        };
                    };
                };
            };
        };
    };
};

if (_doMove) then {
    0 = [_units, _unitIndex] spawn {
        _units = _this select 0;
        _unitIndex = _this select 1;

        _usedUnits = [];
        for "_i" from 0 to (_unitIndex - 1) do {
            _usedUnits pushBack (_units select _i);
        };

        while {count _usedUnits > 0} do {
            sleep 1;
            _toRemove =  [];
            {
                if (unitReady _x) then {
                    doStop _x;
                    _x forceSpeed 0;
                    _toRemove pushBack _forEachIndex;
                };
            } forEach _usedUnits;

            {
                _usedUnits deleteAt (_x - _forEachIndex);
            } forEach _toRemove;
        };
        if (true) exitWith {};
    };
};

_unUsedUnits = [];
for "_i" from _unitIndex to (count _units - 1) step 1 do {
    _unUsedUnits pushBack (_units select _i);
};

(_unUsedUnits)

// Changelog
// 7/21/15
    // 1. Added: Error reporting for invalid position and unit array arguments
    // 1. Added: Check and error report if no buildings are found
    // 3. Improved: Parameters 3, 4, and 5 are now optional and check for the correct type
    // 4. Improved: Parameters 6 and 7 check for the correct type
    // 5. Improved: AI should now stay in place better (thanks to JohnnyBoy)

// 7/6/15
    // 1. Added: AI now take cover when fired upon (credit to JohnnyBoy)
    // 2. Added: Parameter to order the AI to move to their position
    // 3. Improved: The order of buildings filled is now random
    // 4. Improved: A few minor optimizations

// 6/30/15
    // 1. Added: Parameter to fill buildings from top to bottom
    // 2. Improved: Optimized

// 7/31/14
    // 1. Added: Parameter to cycle through each building in the radius, giving units to each one
    // 2. Improved: Units on roof are only placed at the edge, and face the edge
    // 3. Improved: Optimized roof check
    // 4. Improved: General script cleanup

// 7/28/14
    // 1. Fixed: Units facing the wrong window
    // 2. Added: Parameter for distance to select multiple buildings
    // 3. Added: Parameter for units being on a roof
    // 4. Improved: Now checks that unit has a good FOV from the windows
    // 5. Improved: Units can no longer face a windows greater than 5 meters away
    // 6. Improved: Units on a roof now crouch
    // 7. Tweaked: Height of human eye to the exact value in ArmA

// 7/24/14
    // Initial Release

// Known Issues
    // None

 

 

  • Like 1
  • Thanks 2

Share this post


Link to post
Share on other sites

Has anyone had any trouble getting this script to work with buildings on Livonia?

Share this post


Link to post
Share on other sites
On 8/11/2019 at 11:20 AM, sabot10.5mm said:

made a small change to JBOY UpDown script.  added a logic statement that lockouts further while loops from exec if one is already running. then removes EH based on eventhandler index id for the unit 

  Reveal hidden contents


// Infantry Occupy House
// by Zenophon
// Released under Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0)
// http://creativecommons.org/licenses/by-nc/4.0/

// Teleports the units to random windows of the building(s) within the distance
// Faces units in the right direction and orders them to stand up or crouch on a roof
// Units will only fill the building to as many positions as there are windows
// Multiple buildings can be filled either evenly or to the limit of each sequentially
// Usage : Call, execVM
// Params: 1. Array, the building(s) nearest this position is used
//         2. Array of objects, the units that will garrison the building(s)
//  (opt.) 3. Scalar, radius in which to fill building(s), -1 for only nearest building, (default: -1)
//  (opt.) 4. Boolean, true to put units on the roof, false for only inside, (default: false)
//  (opt.) 5. Boolean, true to fill all buildings in radius evenly, false for one by one, (default: false)
//  (opt.) 6. Boolean, true to fill from the top of the building down, (default: false)
//  (opt.) 7. Boolean, true to order AI units to move to the position instead of teleporting, (default: false)
// Return: Array of objects, the units that were not garrisoned

#define I(X) X = X + 1;
#define EVAL(X) (X call _comparator)
#define EYE_HEIGHT 1.53
#define CHECK_DISTANCE 5
#define FOV_ANGLE 10
#define ROOF_CHECK 4
#define ROOF_EDGE 2

private ["_center", "_units", "_buildingRadius", "_putOnRoof", "_fillEvenly", "_Zen_ExtendPosition", "_buildingsArray", "_buildingPosArray", "_buildingPositions", "_posArray", "_unitIndex", "_j", "_building", "_posArray", "_randomIndex", "_housePos", "_startAngle", "_i", "_checkPos", "_hitCount", "_isRoof", "_edge", "_k", "_unUsedUnits", "_array", "_sortHeight", "_Zen_InsertionSort", "_Zen_ArrayShuffle", "_doMove"];

_center = _this param [0, [0,0,0], [[]], 3];
_units = _this param [1, [objNull], [[]]];
_buildingRadius = _this param [2, -1, [0]];
_putOnRoof = _this param [3, false, [true]];
_fillEvenly = _this param [4, false, [true]];
_sortHeight = _this param [5, false, [true]];
_doMove = _this param [6, false, [true]];

if (_center isEqualTo [0,0,0]) exitWith {
    player sideChat str "Zen_Occupy House Error : Invalid position given.";
    diag_log "Zen_Occupy House Error : Invalid position given.";
    ([])
};

if ((count _units == 0) || {isNull (_units select 0)}) exitWith {
    player sideChat str "Zen_Occupy House Error : No units given.";
    diag_log "Zen_Occupy House Error : No units given.";
    ([])
};

_Zen_ExtendPosition = {
    private ["_center", "_dist", "_phi"];

    _center = _this select 0;
    _dist = _this select 1;
    _phi = _this select 2;

    ([(_center select 0) + (_dist * (cos _phi)),(_center select 1) + (_dist * (sin _phi)), (_this select 3)])
};

_Zen_InsertionSort = {
    private ["_i", "_j", "_count", "_array", "_element", "_value", "_comparator"];

    _array = _this select 0;
    _comparator = _this select 1;
    _count = count _array - 1;

    if (count _array == 0) exitWith {};
    for "_i" from 1 to _count step 1 do {
        scopeName "forI";
        _element = _array select _i;
        _value = EVAL(_element);

        for [{_j = _i}, {_j >= 1}, {_j = _j - 1}] do {
            if (_value > EVAL(_array select (_j - 1))) then {
                breakTo "forI";
            };
            _array set [_j, _array select (_j - 1)];
        };

        _array set [_j, _element];
    };
    if (true) exitWith {};
};

_Zen_ArrayShuffle = {
    private ["_array", "_j", "_i", "_temp"];
    _array = _this select 0;

    if (count _array > 1) then {
        for "_i" from 0 to (count _array - 1) do {
                _j = _i + floor random ((count _array) - _i);
                _temp = _array select _i;
                _array set [_i, (_array select _j)];
                _array set [_j, _temp];
        };
    };
    if (true) exitWith {};
};

if (_buildingRadius < 0) then {
    _buildingsArray = [nearestBuilding _center];
} else {
    _buildingsArray0 = nearestObjects [_center, ["house"], _buildingRadius];
    _buildingsArray1 = nearestObjects [_center, ["building"], _buildingRadius];
    _buildingsArray = _buildingsArray0 arrayIntersect _buildingsArray1;
};

if (count _buildingsArray == 0) exitWith {
    player sideChat str "Zen_Occupy House Error : No buildings found.";
    diag_log "Zen_Occupy House Error : No buildings found.";
    ([])
};

_buildingPosArray = [];
0 = [_buildingsArray] call _Zen_ArrayShuffle;
{
    _posArray = [];
    for "_i" from 0 to 1000 do {
        if ((_x buildingPos _i) isEqualTo [0,0,0]) exitWith {};
        _posArray pushBack (_x buildingPos _i);
    };

    _buildingPosArray pushBack _posArray;
} forEach _buildingsArray;

if (_sortHeight) then {
    {
        0 = [_x, {-1 * (_this select 2)}] call _Zen_InsertionSort;
    } forEach _buildingPosArray;
} else {
    {
        0 = [_x] call _Zen_ArrayShuffle;
    } forEach _buildingPosArray;
};

_unitIndex = 0;
for [{_j = 0}, {(_unitIndex < count _units) && {(count _buildingPosArray > 0)}}, {I(_j)}] do {
    scopeName "for";

    _building = _buildingsArray select (_j % (count _buildingsArray));
    _posArray = _buildingPosArray select (_j % (count _buildingPosArray));

    if (count _posArray == 0) then {
        _buildingsArray deleteAt (_j % (count _buildingsArray));
        _buildingPosArray deleteAt (_j % (count _buildingPosArray));
    };

    while {(count _posArray) > 0} do {
        scopeName "while";
        if (_unitIndex >= count _units) exitWith {};

        _housePos = _posArray select 0;
        _posArray deleteAt 0;
        _housePos = [(_housePos select 0), (_housePos select 1), (_housePos select 2) + (getTerrainHeightASL _housePos) + EYE_HEIGHT];

        _startAngle = (round random 10) * (round random 36);
        for "_i" from _startAngle to (_startAngle + 350) step 10 do {
            _checkPos = [_housePos, CHECK_DISTANCE, (90 - _i), (_housePos select 2)] call _Zen_ExtendPosition;
            if !(lineIntersects [_checkPos, [_checkPos select 0, _checkPos select 1, (_checkPos select 2) + 25], objNull, objNull]) then {
                if !(lineIntersects [_housePos, _checkPos, objNull, objNull]) then {
                    _checkPos = [_housePos, CHECK_DISTANCE, (90 - _i), (_housePos select 2) + (CHECK_DISTANCE * tan FOV_ANGLE)] call _Zen_ExtendPosition;
                    if !(lineIntersects [_housePos, _checkPos, objNull, objNull]) then {
                        _hitCount = 0;
                        for "_k" from 30 to 360 step 30 do {
                            _checkPos = [_housePos, 20, (90 - _k), (_housePos select 2)] call _Zen_ExtendPosition;
                            if (lineIntersects [_housePos, _checkPos, objNull, objNull]) then {
                                I(_hitCount)
                            };

                            if (_hitCount >= ROOF_CHECK) exitWith {};
                        };

                        _isRoof = (_hitCount < ROOF_CHECK) && {!(lineIntersects [_housePos, [_housePos select 0, _housePos select 1, (_housePos select 2) + 25], objNull, objNull])};
                        if (!(_isRoof) || {((_isRoof) && {(_putOnRoof)})}) then {
                            if (_isRoof) then {
                                _edge = false;
                                for "_k" from 30 to 360 step 30 do {
                                    _checkPos = [_housePos, ROOF_EDGE, (90 - _k), (_housePos select 2)] call _Zen_ExtendPosition;
                                    _edge = !(lineIntersects [_checkPos, [(_checkPos select 0), (_checkPos select 1), (_checkPos select 2) - EYE_HEIGHT - 1], objNull, objNull]);

                                    if (_edge) exitWith {
                                        _i = _k;
                                    };
                                };
                            };

                            if (!(_isRoof) || {_edge}) then {
                                (_units select _unitIndex) doWatch ([_housePos, CHECK_DISTANCE, (90 - _i), (_housePos select 2) - (getTerrainHeightASL _housePos)] call _Zen_ExtendPosition);

                                (_units select _unitIndex) disableAI "TARGET";
                                if (_doMove) then {
                                    (_units select _unitIndex) doMove ASLToATL ([(_housePos select 0), (_housePos select 1), (_housePos select 2) - EYE_HEIGHT]);
                                } else {
                                    (_units select _unitIndex) setPosASL [(_housePos select 0), (_housePos select 1), (_housePos select 2) - EYE_HEIGHT];
                                    (_units select _unitIndex) setDir _i;

                                    doStop (_units select _unitIndex);
                                    (_units select _unitIndex) forceSpeed 0;
                                };

                               //** JBOY_UpDown by JohnnyBoy //*/
                                #define JBOY_UpDown \
                                    if ((_this select 0) getVariable ["FIREDLOCKOUT", false]) exitWith {}; \
                                    (_this select 0) setVariable ["FIREDLOCKOUT", true]; \
                                    if (!isServer)  exitWith {}; \
                                    _dude = _this select 0; \
                                    _stances = _this select 1; \
                                    _ehid = (_dude getVariable "EHID"); \
                                    _dude removeEventHandler ["FiredNear",_ehid]; \
                                    while {alive _dude} do { \
                                        if ((unitPos _dude) == (_stances select 0)) then { \
                                            _dude setUnitPos (_stances select 1); \
                                        } else { \
                                            _dude setUnitPos (_stances select 0); \
                                        }; \
                                        sleep 5 + (random 2); \
                                    };  
                                    
                                    if (_isRoof) then {
                                    	(_units select _unitIndex) setUnitPos "MIDDLE";
                                       _eh = (_units select _unitIndex) addEventHandler ["FiredNear",{[(_this select 0),["DOWN","MIDDLE"]] spawn {JBOY_UpDown};}];
                                    	(_units select _unitIndex) setVariable ["EHID", _eh];
                                       
                                    } else {
                                    	(_units select _unitIndex) setUnitPos "UP";
                                       _eh = (_units select _unitIndex) addEventHandler ["FiredNear",{[(_this select 0),["UP","MIDDLE"]] spawn {JBOY_UpDown};}];
                                       (_units select _unitIndex) setVariable ["EHID", _eh];
                                      
                                    }; 
								

                                I(_unitIndex)
                                if (_fillEvenly) then {
                                    breakTo "for";
                                } else {
                                    breakTo "while";
                                };
                            };
                        };
                    };
                };
            };
        };
    };
};

if (_doMove) then {
    0 = [_units, _unitIndex] spawn {
        _units = _this select 0;
        _unitIndex = _this select 1;

        _usedUnits = [];
        for "_i" from 0 to (_unitIndex - 1) do {
            _usedUnits pushBack (_units select _i);
        };

        while {count _usedUnits > 0} do {
            sleep 1;
            _toRemove =  [];
            {
                if (unitReady _x) then {
                    doStop _x;
                    _x forceSpeed 0;
                    _toRemove pushBack _forEachIndex;
                };
            } forEach _usedUnits;

            {
                _usedUnits deleteAt (_x - _forEachIndex);
            } forEach _toRemove;
        };
        if (true) exitWith {};
    };
};

_unUsedUnits = [];
for "_i" from _unitIndex to (count _units - 1) step 1 do {
    _unUsedUnits pushBack (_units select _i);
};

(_unUsedUnits)

// Changelog
// 7/21/15
    // 1. Added: Error reporting for invalid position and unit array arguments
    // 1. Added: Check and error report if no buildings are found
    // 3. Improved: Parameters 3, 4, and 5 are now optional and check for the correct type
    // 4. Improved: Parameters 6 and 7 check for the correct type
    // 5. Improved: AI should now stay in place better (thanks to JohnnyBoy)

// 7/6/15
    // 1. Added: AI now take cover when fired upon (credit to JohnnyBoy)
    // 2. Added: Parameter to order the AI to move to their position
    // 3. Improved: The order of buildings filled is now random
    // 4. Improved: A few minor optimizations

// 6/30/15
    // 1. Added: Parameter to fill buildings from top to bottom
    // 2. Improved: Optimized

// 7/31/14
    // 1. Added: Parameter to cycle through each building in the radius, giving units to each one
    // 2. Improved: Units on roof are only placed at the edge, and face the edge
    // 3. Improved: Optimized roof check
    // 4. Improved: General script cleanup

// 7/28/14
    // 1. Fixed: Units facing the wrong window
    // 2. Added: Parameter for distance to select multiple buildings
    // 3. Added: Parameter for units being on a roof
    // 4. Improved: Now checks that unit has a good FOV from the windows
    // 5. Improved: Units can no longer face a windows greater than 5 meters away
    // 6. Improved: Units on a roof now crouch
    // 7. Tweaked: Height of human eye to the exact value in ArmA

// 7/24/14
    // Initial Release

// Known Issues
    // None

 

 

 

Can anyone help me put it on a warlords mission?

Share this post


Link to post
Share on other sites
On 4/15/2015 at 7:41 PM, Zenophon said:

It works in the script's old test mission, which I've kept all this time, with this code in the leader of an AI group's init field:

 


0 = [getPosATL this, units group this, -1, true, false] execVM "Zen_OccupyHouse.sqf"
 

 

My first guess for why it doesn't work is the buildings in Bornholm. This script relies upon predefined building positions to place units (where you see lines drawn when commanding AI in a building). If there are too few or none of these (or the building isn't enterable), the script has nowhere to move the units. The script assumes that all buildings have some positions because enterable buildings are standard on Altis.

If this is the issue, for partially enterable buildings the solution is to generate valid positions manually. The point of this script is that the units look out windows. My framework's Zen_FindBuildingPositions function will generate positions, but you'd need to check each one for having a decent view outside the building. The time to compute positions and the success rate of the script would be significantly worse, as many predetermined building positions tend to be near windows.

 

Cant make this work in a mission like Warlords. Seems to be that units to be spawned (not placed in editor) are not affected by the script. Any idea please?

Share this post


Link to post
Share on other sites

Hi Zenophon,

 

First of all, I'm absolutely loving this script. Top-notch work, mate 👌

 

If I used Zen_OccupyHouse on some units and then later wanted to give those units waypoints and move orders (e.g. to flee their town after taking heavy casualties), what would I need to do to kill instances of the script still running?

 

From reading through this thread I was able to gather that I need to use the forceSpeed command to allow the units to be able to move again, and that seems to be all I need to get them moving around. It looks as though, ideally, I'd also have to have a way of interrupting the JBOY_UpDown while-do loop (technically I could just leave this running, but yeah not ideal).

 

Would you have any suggestions as to how to exit that loop? Are there any other parts of the script that remain active after initially garrisoning the units?

Share this post


Link to post
Share on other sites
On 8/27/2019 at 4:09 PM, Blitzen88 said:

Has anyone had any trouble getting this script to work with buildings on Livonia?

 

Tested in Stratis, then copied to Livonia, and it worked. 

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

×