Files
DayZ-Epoch/SQF/dayz_code/old/fn_niceSpot.sqf
2020-06-10 17:03:31 +02:00

215 lines
6.9 KiB
Plaintext

/*
Created exclusively for ArmA2:OA - DayZMod.
Please request permission to use/alter/distribute from project leader (R4Z0R49) AND the author (facoptere@gmail.com)
*/
// Check/find a spot before pitching "Land_Fire_DZ", "TentStorage", "Wire_cat1", "Sandbag1_DZ" or "Hedgehog_DZ"
// _this 0: object class
// _this 1: object (player) or array (ATL format)
// _this 2: optional, empty array that will be filled by computed boolean: _testonLadder, _testSea, _testPond, _testBuilding, _testSlope, _testDistance
// return a worldspace consisting of array [ direction, ATL position ] or empty array if no position is found
// if 2nd argument is a player, the position returned is just in front of the player, direction is so that the object is "looking to" the player
private ["_booleans","_class","_isPlayer","_size","_testPond","_testBuilding","_testonLadder","_testSlope","_testSea","_testDistance","_noCollision","_dir","_obj","_objectsPond","_ok","_maxdistance","_x","_new","_pos"];
_class = _this select 0;
_pos = _this select 1;
_realSize = {
[[0,0], (boundingBox _this) select 1] call BIS_fnc_distance2D
};
// check that tent position is outside the pool footprint.
// we can't check altitude since pool has no height
_checkPerimeter = {
private ["_inside","_relPos","_point","_boundingBox","_min","_max","_myX","_myY","_building"];
_building = _this select 0;
_point = _this select 1;
_inside = false;
_relPos = _building worldToModel _point;
_boundingBox = boundingBox _building;
//diag_log format ["%1 %2", _relPos, _boundingBox];
_min = _boundingBox select 0;
_max = _boundingBox select 1;
_myX = _relPos select 0;
_myY = _relPos select 1;
if ((_myX > (_min select 0)) and {(_myX < (_max select 0))}) then {
if ((_myY > (_min select 1)) and {(_myY < (_max select 1))}) then {
_inside = true;
};
};
_inside
};
// check if _pos a player object or some ATL coordinates array
_isPlayer = (typeName _pos != "ARRAY");
_testBuilding = true;
_testDistance = _isPlayer;
_maxdistance = 5;
_testonLadder = _isPlayer;
_testPond = false;
_testSea = false;
_testSlope = false;
_noCollision = false;
switch _class do {
case "TentStorage" : { // tent pitching must follow all restrictions
_testPond = true;
_testSea = true;
};
case "DomeTentStorage" : { // tent pitching must follow all restrictions
_testPond = true;
_testSea = true;
};
case "StashSmall" : {
_testPond = true;
_testSea = true;
};
case "StashMedium" : {
_testPond = true;
_testSea = true;
};
case "Land_Fire_DZ" : { // no fire in the water :)
_testPond = true;
_testSea = true;
};
case "CamoNet_DZ" : { // no fire in the water :)
_testPond = true;
_testSea = true;
_testSlope = false;
_noCollision = false;
_testBuilding = false;
};
case "Wire_cat1" : {};
case "Sandbag1_DZ" : {};
case "Hedgehog_DZ" : {};
default { // = vehicles (used for hive maintenance on startup)
_testBuilding = false;
_testSlope = false;
_noCollision = false;
};
};
//diag_log(format["niceSpot: will test: pond:%1 building:%2 slope:%3 sea:%4 distance:%5 collide:%6", _testPond, _testBuilding, _testSlope, _testSea, _testDistance, _noCollision]);
_dir = if (_isPlayer) then {getDir(_pos)} else {0};
_obj = _class createVehicleLocal (getMarkerpos "respawn_west");
uiSleep 0.01;
_size = _obj call _realSize;
if (_isPlayer) then { _size = _size + (_pos call _realSize); };
// compute initial position. If _pos is the player, then the object will be in front of him/her
_new = nil;
_new = if (_isPlayer) then { _pos modeltoworld [0,_size/2,0] } else { _pos };
_new set [2, 0];
// place a temporary object (not colliding or can colliding)
if (_noCollision) then {
deleteVehicle _obj;
uiSleep 0.01;
_obj = _class createVehicleLocal _new;
// get non colliding position
_new = getPosATL _obj;
// get relative angle of object position according to player PoV
if (_isPlayer) then {
_x = _pos worldToModel _new;
_dir = _dir + (if ((_x select 1)==0) then { 0 } else { (_x select 0) atan2 (_x select 1) });
};
} else {
_obj setDir _dir;
_obj setPosATL(_new);
};
if (_testBuilding) then { // let's proceed to the "something or its operator in a building" test
_testBuilding = (([_obj, true] call fnc_isInsideBuilding) // obj in/close to a building (enterable or not)
// or _pos is a player who is in a *enterable* building
OR {(_isPLayer AND {([_pos, false] call fnc_isInsideBuilding)})});
};
deleteVehicle _obj;
uiSleep 0.01;
if (_testPond) then { // let's proceed to the "object in the pond" test (not dirty)
_testPond = false;
_objectsPond = nearestObjects [_new, [], 100];
{
if (((typeOf(_x) == "") // unnamed class?
AND {((((_x worldToModel _new) select 2) < 0)) // below water level?
AND {([_x, _new] call _checkPerimeter)}}) // inside pond square footprint?
AND {(["pond", str(_x), false] call fnc_inString)} // and is actually a pond?
) exitWith {
_testPond = true;
};
} forEach _objectsPond;
};
if (_testSlope) then { // "flat spot" test
_testSlope = false;
_x = _new isflatempty [
0, // don't check collisions
0, // don't look around
(0.1*_size), // slope gradient
_size, // object size
1, // do not check in the sea
false, // don't check far from shore
if (_isPlayer) then {_pos} else {objNull} // not used -- seems buggy.
];
if (count _x < 2) then { // safepos found (gradient ok AND not in sea water)
_testSlope = true;
};
};
if (_testSea) then { // "not in the sea, not on the beach" test
_testSea = false;
_x = _new isflatempty [
0, // don't check collisions
0, // don't look around
999, // do not check slope gradient
_size, // object size
0, // check not in the sea
false, // don't check far from shore
if (_isPlayer) then {_pos} else {objNull} // not used -- seems buggy.
];
if (count _x < 2) then { // safepos found (gradient ok AND not in sea water)
_testSea = true;
}
else {
_x set [2,0];
_x = ATLtoASL _x;
if (_x select 2 < 3) then { // in the wave foam
_testSea = true;
};
};
};
if (_testDistance) then { // check effective distance from the player
_testDistance = ((_pos distance _new) > _maxdistance);
};
if (_testonLadder) then { // forbid item install process if player is on a ladder (or in a vehicle)
_testonLadder = (
((getNumber (configFile >> "CfgMovesMaleSdr" >> "States" >> (animationState _pos) >> "onLadder")) == 1)
OR {((isPlayer _pos) AND {((vehicle _pos) != _pos)})}
);
};
//diag_log(format["niceSpot: result pond:%1 building:%2 slope:%3 sea:%4 distance:%5 collide:%6", _testPond, _testBuilding, _testSlope, _testSea, _testDistance, _noCollision]);
_ok = !_testPond AND !_testBuilding AND !_testSlope AND !_testSea AND !_testDistance AND !_testonLadder;
if (count _this > 2) then {
_booleans = _this select 2;
_booleans set [0, _testonLadder];
_booleans set [1, _testSea];
_booleans set [2, _testPond];
_booleans set [3, _testBuilding];
_booleans set [4, _testSlope];
_booleans set [5, _testDistance];
//diag_log(format["niceSpot: booleans: %1", _booleans]);
};
if (_ok) then { [round(_dir), _new] } else { [] }