ACE3/addons/common/functions/fnc_findUnloadPosition.sqf
Dedmen Miller e2ac18a05d [WIP] Fix script errors reporting wrong line numbers (#6407)
* advanced_ballistics

* advanced_fatigue

* advanced_throwing

* ai

* aircraft

* arsenal

* atragmx

* attach

* backpacks

* ballistics

* captives

* cargo

* chemlights

* common

* concertina_wire

* cookoff

* dagr

* disarming

* disposable

* dogtags

* dragging

* explosives

* fastroping

* fcs

* finger

* frag

* gestures

* gforces

* goggles

* grenades

* gunbag

* hearing

* hitreactions

* huntir

* interact_menu

* interaction

* inventory

* kestrel4500

* laser

* laserpointer

* logistics_uavbattery

* logistics_wirecutter

* magazinerepack

* map

* map_gestures

* maptools

* markers

* medical

* medical_ai

* medical_blood

* medical_menu

* microdagr

* minedetector

* missileguidance

* missionmodules

* mk6mortar

* modules

* movement

* nametags

* nightvision

* nlaw

* optics

* optionsmenu

* overheating

* overpressure

* parachute

* pylons

* quickmount

* rangecard

* rearm

* recoil

* refuel

* reload

* reloadlaunchers

* repair

* respawn

* safemode

* sandbag

* scopes

* slideshow

* spectator

* spottingscope

* switchunits

* tacticalladder

* tagging

* trenches

* tripod

* ui

* vector

* vehiclelock

* vehicles

* viewdistance

* weaponselect

* weather

* winddeflection

* yardage450

* zeus

* arsenal defines.hpp

* optionals

* DEBUG_MODE_FULL 1

* DEBUG_MODE_FULL 2

* Manual fixes

* Add SQF Validator check for #include after block comment

* explosives fnc_openTimerUI

* fix uniqueItems
2018-09-17 14:19:29 -05:00

136 lines
6.5 KiB
Plaintext

#include "script_component.hpp"
/*
* Author: PabstMirror, ViperMaul
* Find a safe place near a vehicle to unload something.
* Handles Normal Terrain, In Water or On Buildings (Pier, StaticShip).
*
* Arguments:
* 0: Source Vehicle <OBJECT>
* 1: Cargo <OBJECT> or <STRING>
* 2: Unloader (player) <OBJECT> (default: objNull)
* 3: Max Distance (meters) <NUMBER> (default: 10)
* 4: Check Vehicle is Stable <BOOL> (default: true)
*
* Return Value:
* Unload PositionAGL (can Be [] if no valid pos found) <ARRAY>
*
* Example:
* [theCar, "CAManBase", player, 10, true] call ace_common_fnc_findUnloadPosition
*
* Public: No
*/
//Number of tests run (effects performance in worst case scenarior where nothing is found VERSUES reliably finding a pos):
#define MAX_TESTS 75
//Manual collision tests (count and radius):
#define COL_TEST_COUNT 12
params ["_vehicle", "_cargo", ["_theUnloader", objNull], ["_maxDistance", 10], ["_checkVehicleIsStable", true]];
TRACE_5("params",_vehicle,_cargo,_theUnloader,_maxDistance,_checkVehicleIsStable);
scopeName "main";
if (_checkVehicleIsStable) then {
if (((vectorMagnitude (velocity _vehicle)) > 1.5) || {(!(_vehicle isKindOf "Ship")) && {(!isTouchingGround _vehicle) && {((getPos _vehicle) select 2) > 1.5}}}) then {
TRACE_4("bad vehicle state",_vehicle,velocity _vehicle,isTouchingGround _vehicle,getPos _vehicle);
[] breakOut "main";
};
};
private _radiusOfItem = 1;
if (_cargo isKindOf "CAManBase") then {
_radiusOfItem = 1.1;
} else {
//`sizeOf` is unreliable, and does not work with object types that don't exist on map, so estimate size based on cargo size
private _typeOfCargo = if (_cargo isEqualType "") then {_cargo} else {typeOf _cargo};
private _itemSize = if (isNumber (configFile >> "CfgVehicles" >> _typeOfCargo >> QEGVAR(cargo,size)) && {getNumber (configFile >> "CfgVehicles" >> _typeOfCargo >> QEGVAR(cargo,size)) != -1}) then {
getNumber (configFile >> "CfgVehicles" >> _typeOfCargo >> QEGVAR(cargo,size));
} else {
if (["ace_cargo"] call FUNC(isModLoaded)) then {
[_cargo] call EFUNC(cargo,getSizeItem);
} else {
_radiusOfItem;
};
};
if (_itemSize != -1) then {
_radiusOfItem = (_itemSize ^ 0.35) max 0.75;
};
};
if (isNull _theUnloader) then {_theUnloader = _vehicle;};
//Ideal unload pos is halfway between unloader and vehicle (at the unloader's height)
private _originASL = ((getPosASL _theUnloader) vectorAdd (getPosASL _vehicle)) vectorMultiply 0.5;
_originASL set [2, (getPosASL _theUnloader) select 2];
private _originAGL = ASLtoAGL _originASL;
//Do a manual search for empty pos (handles underwater, buildings or piers)
TRACE_2("Checking for unload",_originAGL,_radiusOfItem);
private _rangeToCheck = 0;
while {_rangeToCheck < _maxDistance} do {
private _roundDistance = random _rangeToCheck;
private _roundAngle = random 360;
private _roundAGL = _originAGL vectorAdd [(cos _roundAngle) * _roundDistance, (sin _roundAngle) * _roundDistance, 0];
private _roundPointIsValid = false;
if (((AGLtoASL _roundAGL) select 2) > 0) then {
//Shoot a ray down, and make sure we hit something solid like a building or the ground:
private _belowRoundArray = lineIntersectsSurfaces [(AGLtoASL _roundAGL) vectorAdd [0,0,0.5], (AGLtoASL _roundAGL) vectorAdd [0,0,-1]];
TRACE_4("Testing for solid",_roundDistance,_roundAngle,_roundAGL,_belowRoundArray);
if (!(_belowRoundArray isEqualTo [])) then {
private _aboveBuilding = (_belowRoundArray select 0) select 2;
//Point is above something: Terrain(null) or Building
if ((isNull _aboveBuilding) || {_aboveBuilding isKindOf "Building"}) then {
//Get the real intersection point:
_roundAGL = ASLtoAGL ((_belowRoundArray select 0) select 0);
_roundPointIsValid = true;
};
};
} else {
//Underwater, just unload anywhere
TRACE_3("Under the sea",_roundDistance,_roundAngle,_roundAGL);
_roundPointIsValid = true;
};
//Make sure point is valid and do a fast check for people in the way (which sometimes aren't caught by line scaning)
if (_roundPointIsValid && {(_roundAGL nearEntities ["Man", _radiusOfItem]) isEqualTo []}) then {
for "_index" from 0 to (COL_TEST_COUNT -1) do {
//Scan for colisions with objects with lineIntersectsSurfaces
private _angle = _index * (360 / COL_TEST_COUNT);
private _point1ASL = (AGLtoASL _roundAGL) vectorAdd [_radiusOfItem * cos _angle, _radiusOfItem * sin _angle, 0.1];
private _point2ASL = (AGLtoASL _roundAGL) vectorAdd [-_radiusOfItem * cos _angle, -_radiusOfItem * sin _angle, (_radiusOfItem + 0.5)];
private _testIntersections = lineIntersectsSurfaces [_point1ASL, _point2ASL];
if (((count _testIntersections) == 1) && {isNull ((_testIntersections select 0) select 2)}) then {
private _hitGroundASL = (_testIntersections select 0) select 0;
private _hitHeightOffset = ((AGLtoASL _roundAGL) select 2) - (_hitGroundASL select 2);
private _hit2dOffset = _roundAGL distance2D _hitGroundASL;
private _slope = _hitHeightOffset atan2 _hit2dOffset;
if (_slope < 25) then { //Ignore ground hit if slope is reasonable
_testIntersections = [];
};
};
if (!(_testIntersections isEqualTo [])) exitWith {
TRACE_2("collision low/high",_roundAGL,_testIntersections);
_roundPointIsValid = false;
};
_point1ASL = (AGLtoASL _roundAGL) vectorAdd [_radiusOfItem * cos _angle, _radiusOfItem * sin _angle, 0.5];
_point2ASL = (AGLtoASL _roundAGL) vectorAdd [-_radiusOfItem * cos _angle, -_radiusOfItem * sin _angle, 1];
_testIntersections = lineIntersectsSurfaces [_point1ASL, _point2ASL];
if (!(_testIntersections isEqualTo [])) exitWith {
TRACE_2("collision mid",_roundAGL,_testIntersections);
_roundPointIsValid = false;
};
};
if (_roundPointIsValid) then {
TRACE_3("Valid point found", _rangeToCheck,_roundAGL, (_originAGL distance _roundAGL));
//Raise it slightly so we don't sink through the floor:
(_roundAGL vectorAdd [0,0,0.05]) breakOut "main";
};
};
_rangeToCheck = _rangeToCheck + (_maxDistance / MAX_TESTS);
};
TRACE_1("no valid spots found",_rangeToCheck);
[] //return empty array