mrcurry 496 Posted October 20, 2012 (edited) Indoor building positions... It's one of those things that have been pretty elusive as far as arma scripting goes. I've been playing around with different ways of finding the positions but none of them have been satisfactory for a perfectionist like myself... Hence I create this topic, as a sort of brainstorm for possible solutions, from the simple to the outright insane. The essentials of the problem are: Imagine a function such as... fnc_findIndoorPositions = { //Stuff }; The parameter of the function would be a building of any kind. The return value must be an array of positions inside the building or an empty array. One could pre-define the positions through some "down and dirty" relative-position collecting. The plus side of this approach would be that you could define custom positions not defined in the buildings config. The drawback is the obvious that its massively time-consuming, especially for larger buildings which can have up to 50+ positions. It is also very inflexible. I've tried using commands like boundingBox to approximate the height of the building and have a rough "everything below rooftop level" selection, but buildings with several levels of roof kinda breaks it. Post your ideas or workarounds that you have, even a straight-up solutions are welcome. Oh, and leave the "it's impossible" attitude at the door. ;) Cheers /Curry Edited October 20, 2012 by mrCurry Typos and formatting Share this post Link to post Share on other sites
blackmamb 2 Posted October 20, 2012 (edited) There's at least one dude out there that did that massive amount of work and collected all (or almost all?) building positions for vanilla buildings. I just can't remember who that is right now, but I guess you'd find it pretty quickly if you search for the various house patrol/Garrison scripts on armaholic. Edit: That's Jakerod's. Edit again: Btw, you might wanna check its thread here, as Twirly's code (8th post) is what I'd use to find positions in buildings. Use Building pos in a loop that just stops when the returned position is [0,0,0]. Edited October 20, 2012 by BlackMamb Share this post Link to post Share on other sites
mrcurry 496 Posted October 24, 2012 (edited) Yes, I've seen his script and I feel that, while the work is solid and extensive, it is lacking in 1 important aspect. It has very little scale-ability. It is using the sort of "down and dirty" approach I was referring to in the OP. There is a lot work in making something like that (kudos to Jakerod) and adding more buildings to the script is... demanding to say the least even with his great comments, and it is exactly the kind of solution I am trying to avoid. Instead of cutting down the tree with an axe, I want to design a chainsaw. Hence I am looking for workarounds to the rather limited building configs and I'm trying to think outside the box (or the config if you will). Things like checking building height against an average floor height, dropping balls on top of the positions and checking if they get close enough for it to be a rooftop, etc. If you got any ideas, even somewhat crazy ones, do share! P.S. The ball option is currently not very good for run-time application. :rolleyes: Edited October 24, 2012 by mrCurry Typos... again... Share this post Link to post Share on other sites
giallustio 770 Posted October 24, 2012 The only way i know to get the house position is a while check: _house = _this select 0; _n_pos = 0; while {format ["%1", _house buildingPos _n_pos] != "[0,0,0]" } do {_n_pos = _n_pos + 1}; Share this post Link to post Share on other sites
cuel 25 Posted October 24, 2012 This was originally written for insurgency. #define ILLEGALHOUSES ["Land_molo_beton","Land_vez","Land_A_Crane_02b","land_nav_pier_c2_end","Land_nav_pier_m_2","land_nav_pier_c_big","Land_A_Crane_02a","land_nav_pier_c2","Land_Nasypka","Land_Mil_hangar_EP1", "Land_Mil_ControlTower_EP1", "Land_Mil_Guardhouse_EP1", "Land_Mil_Repair_center_EP1","Land_Mil_Barracks_i_EP1","Land_A_Minaret_EP1","Land_Ind_Coltan_Main_EP1","land_most_blok"] _findHouses = { private ["_buildings","_minPositions","_enterables","_alive"]; _buildings = nearestObjects [_this select 0, ["House"], _this select 1]; _minPositions = (_this select 2) - 1; _alive = _this select 3; _enterables = []; { if ( format["%1", _x buildingPos _minPositions] != "[0,0,0]" && (!(typeOf _x in ILLEGALHOUSES) && (alive _x || !_alive)) ) then { _enterables set [count _enterables, _x]; }; } forEach _buildings; _enterables }; // called with : _buildingsArray = [position _something,400,2,true] call _findHouses; _countPositions = { private ["_i","_house","_hPos"]; _house = _this select 0; _i = _this select 1; _hPos = format["%1", _house buildingPos _i]; if (_hPos == "[0,0,0]") exitWith { _i; }; [_house, _i+1] call _countPositions; }; // called with _nr = [_house,0] call _countPositions; And then I wrote this to position an ammobox inside the house correctly so it's not floating. It's not perfect (sometimes goes through the floor), playing around with the distances should help. _box = createVehicle ["GuerillaCacheBox", (_house buildingPos (floor (random _nr))), [], 0, "CAN_COLLIDE"]; if (count (lineIntersectsWith [[getPosASL _box select 0,getPosASL _box select 1,(getPosASL _box select 2) + 0.1], [getPosASL _box select 0,getPosASL _box select 1,(getPosASL _box select 2)-0.5],_box, objNull]) == 0) then { // it's in the air for "_i" from 0 to 100 do { if ((count (lineIntersectsWith [[getPosASL _box select 0,getPosASL _box select 1,(getPosASL _box select 2)], [getPosASL _box select 0,getPosASL _box select 1,(getPosASL _box select 2)-0.1],_box, objNull]) == 0)) then { // lower it a little if (getPosATL _box select 2 > 0.1) then { _box setPosASL [getPosASL _box select 0,getPosASL _box select 1,(getPosASL _box select 2)-0.2]; }else{_i = 100;} }else{_i = 100}; sleep 0.01; }; }; Share this post Link to post Share on other sites
panther42 52 Posted October 24, 2012 I don't know if you've ever looked through the ALICE module, but here's part of the scripting which puts civilians in houses: //--- Set values if (_movein) then { scopename "moveIn"; _marker = if (_debug) then {_house call BIS_fnc_boundingBoxMarker;} else {""}; //--- In da house _posList = []; for "_i" from 0 to 10 do { _point = _house selectionposition format ["AIspawnpos_%1",_i]; if (_point distance [0,0,0] > 0.1) then { _posList = _posList + [_point]; if (_debug) then { _pointPos = _house modeltoworld _point; _pointMarker = createmarker [format ["X%1",floor random 99999],_pointpos]; _pointMarker setmarkertype "mil_dot"; _pointMarker setmarkercolor "colorpink"; }; } else {breakto "moveIn"}; }; if (_debug) then { _color = if (count _posList > 0) then {"colorgreen"} else {"colorred"}; _marker setmarkercolor _color; }; if (count _posList == 0) then {_posList = [[0,0,0]]}; _spawnpos = _house modeltoworld (_posList call bis_fnc_selectrandom); _unit setposatl _spawnpos; _unit setskill (random 1); _unit setvelocity [0,0,0]; }; This may give you another option. Share this post Link to post Share on other sites
mrcurry 496 Posted November 3, 2012 (edited) Thanks for the feedback, I managed to get a function up an running with does the job decently. @cuel: Thanks for bringing my attention to the lineIntersectsWith command. It's an amazing addition to the SQF-library, so useful! Description: Using lineIntersectsWith you can trace the intersection between the model and lines going from positions outside the building you want to retrieve from. With that technique you filter the building positions into arch-types. With that in mind I put together the following function, it is a rewrite of my existing function for retrieving positions and allows for a more general use as well as sorting positions according to type. Input a building and it will get all positions in the building. Input a building in an array and it will retrieve all the building positions sorted into 3 nested arrays. In the first array you'll find all positions that are indoors. In the second are all positions that are on balconies and porches and the like. In the last array all outside positions are found, such as rooftops and ground-level positions. The function: /* ------------------------------------------------------------------------------------ Function: c_fnc_getBuildingPositions Can be used in 2 ways, simple and advanced Simple use: building call c_fnc_getBuildingPositions Parameter(s): building - Object Returns: All positions in a building Advanced use: [building (, offset)] call c_fnc_getBuildingPositions Parameter(s): [ building - Object , offset -(optional) Number - offset height which balcony-positions are measured against - default: 1.5 ] Returns: Array of 3 Arrays with positions sorted according to [ inside positions, balconies and porches, rooftops ] Beware, each nested array may or may not be empty, depending on the building. ------------------------------------------------------------------------------------ */ c_fnc_getBuildingPositions = { private ["_fnc_checkLOS", "_b", "_offset", "_aslPos", "_bBox", "_bBoxWidth", "_bBoxDepth", "_bBoxHeight", "_searchW", "_searchH", "_notVisable", "_visFromSide", "_visFromAbove", "_i", "_bP", "_xPos", "_visIndex", "_p"]; _fnc_checkLOS = { private ["_b", "_pos", "_width", "_height", "_facing", "_return", "_aPos", "_blockingObjects", "_nrVis", "_numChecks", "_dirDif", "_i", "_c", "_xDir", "_sidePos"]; _b = _this select 0; _pos = ATLtoASL (_this select 1); _width = _this select 2; _height = _this select 3; _facing = getDir _b; _return = 0; _aPos = [_pos select 0, _pos select 1, (_pos select 2) + _height]; _blockingObjects = lineIntersectsWith [_pos, _aPos]; if( !(_b in _blockingObjects) ) then { _return = 2; } else { _nrVis = 4; _numChecks = 12; _dirDif = 360/_numChecks; _i = 0; _c = 0; while {_i < _numChecks && _c < _nrVis} do { _xDir = _facing + _dirDif*_i; _sidePos = [(_pos select 0)+(_width*sin _xDir), (_pos select 1)+(_width*cos _xDir), _pos select 2]; _blockingObjects = lineIntersectsWith [_pos, _sidePos]; if (!(_b in _blockingObjects)) then { _c = _c + 1; } else { _c = 0; }; _i = _i + 1; }; if(_c == _nrVis) then { _return = 1; }; }; _return }; if(typeName _this == typeName []) then { _b = _this select 0; _offset = if(count _this > 1) then { _this select 1 } else { 1.5 }; _aslPos = getPosASL _b; _bBox = boundingBox _b; _bBoxWidth = ((_bBox select 1) select 0) - ((_bBox select 0) select 0); _bBoxDepth = ((_bBox select 1) select 1) - ((_bBox select 0) select 1); _bBoxHeight = ((_bBox select 1) select 2) - ((_bBox select 0) select 2); _searchW = if(_bBoxWidth > _bBoxDepth) then {_bBoxWidth} else {_bBoxDepth}; _searchH = _bBoxHeight; _notVisable = []; _visFromSide = []; _visFromAbove = []; _i = 0; _bP = _b buildingPos _i; while {{_x != 0} count _bP > 0} do { _xPos = [_bP select 0, _bP select 1, (_bP select 2) + _offset]; _visIndex = [_b, _xPos, _searchW, 50] call _fnc_checkLOS; switch (_visIndex) do { case 0: { _notVisable set [count _notVisable, _bP]; }; case 1: { _visFromSide set [count _visFromSide, _bP]; }; case 2: { _visFromAbove set [count _visFromAbove, _bP]; }; default { diag_log text format ["c_fnc_getBuildingPositions - Invalid _visIndex: %1", _visIndex]; }; }; _i = _i + 1; _bP = _b buildingPos _i; }; //Return [_notVisable, _visFromSide, _visFromAbove] } else { _b = _this; _p = []; _i = 0; _bP = _b buildingPos _i; while {{_x != 0} count _bP > 0} do { _p set [count _p, _bP]; _i = _i + 1; _bP = _b buildingPos _i; }; _p } }; The nested function _fnc_checkLOS can be, with some modification, used separately to check if any position is in a certain building. Known issues: Due to lineIntersectsWith not detecting some thin surfaces, window glass and some rooftops are not detected when checking Line Of Sight. In some cases this may cause odd sorting. Examples: Here is the test script I wrote for this function. It shows the usage of c_fnc_getBuildingPositions and will allow you to preview buildings in game. Usage: Place player in editor, add above code to init.sqf and add a repeatable radio-trigger Ingame you can trigger the test while looking at a building to show its positions and trigger it again to clean up. Red: Indoors Green: Balconies and porches Blue: Rooftops and outdoor positions Edited November 3, 2012 by mrCurry bad format Share this post Link to post Share on other sites