diff --git a/addons/danger/functions/fnc_brainForced.sqf b/addons/danger/functions/fnc_brainForced.sqf index 8ac20a44d..eabe9cea1 100644 --- a/addons/danger/functions/fnc_brainForced.sqf +++ b/addons/danger/functions/fnc_brainForced.sqf @@ -39,11 +39,6 @@ if (fleeing _unit) exitWith { _timeout }; -// units in vehicles -if (!isNull objectParent _unit) exitWith { - _timeout + 1.5 -}; - // attack speed and stance if ((currentCommand _unit) isEqualTo "ATTACK") then { private _attackTarget = getAttackTarget _unit; diff --git a/addons/danger/functions/fnc_brainVehicle.sqf b/addons/danger/functions/fnc_brainVehicle.sqf index 64ca2d832..b25fc864c 100644 --- a/addons/danger/functions/fnc_brainVehicle.sqf +++ b/addons/danger/functions/fnc_brainVehicle.sqf @@ -4,7 +4,7 @@ * handles vehicle brain * * Arguments: - * 0: unit doing the avaluation + * 0: unit doing the evaluation * 2: current action queue * * Return Value: @@ -51,11 +51,11 @@ _causeArray params ["_cause", "_dangerPos", "", "_dangerCausedBy"]; // "_dangerU _unit setVariable [QEGVAR(main,FSMDangerCauseData), _causeArray, EGVAR(main,debug_functions)]; // is it an attack? -private _attack = _cause in [DANGER_ENEMYDETECTED, DANGER_ENEMYNEAR, DANGER_HIT, DANGER_CANFIRE, DANGER_BULLETCLOSE] && {(side _dangerCausedBy) isNotEqualTo (side _unit)} && {!isNull _dangerCausedBy}; +private _attack = _cause in [DANGER_ENEMYDETECTED, DANGER_ENEMYNEAR, DANGER_HIT, DANGER_CANFIRE, DANGER_BULLETCLOSE] && {(side _dangerCausedBy) isNotEqualTo (side _unit)} && {!isNull _dangerCausedBy} && {(behaviour _unit) isEqualTo "COMBAT"}; // update dangerPos if attacking. Check that the position is not too far above, or below ground. if (_attack) then { - private _dangerPos = _unit getHideFrom _dangerCausedBy; + _dangerPos = _unit getHideFrom _dangerCausedBy; if (_dangerPos isEqualTo [0, 0, 0]) exitWith {_attack = false;}; _dangerPos = ASLToAGL (ATLToASL _dangerPos); if ((_dangerPos select 2) > 6 || {(_dangerPos select 2) < 2}) then {_dangerPos set [2, 1]}; @@ -78,6 +78,63 @@ if (_artillery) exitWith { { _x setSuppression 0.94; // to prevent instant laser aim on exiting vehicle } forEach _vehicleCrew; // There may be more than one unit in vehicle + [_unit, "Combat", "Eject", 125] call EFUNC(main,doCallout); + }; + + // mortars fire rounds + private _mortarTime = _vehicle getVariable [QEGVAR(main,mortarTime), 0]; + if (_attack && {_vehicle isKindOf "StaticMortar"} && {unitReady _vehicle} && {_mortarTime < time} && {isTouchingGround _dangerCausedBy}) then { + + // delay + _timeout = _timeout + 2; + _vehicle doWatch _dangerPos; + + // check ammo & range + private _ammo = getArtilleryAmmo [_vehicle]; + private _shell = _ammo param [0, ""]; + if (_shell isEqualTo "") exitWith {}; + private _flareIndex = _ammo findIf {"flare" in (toLowerANSI _x)}; + private _smokeIndex = _ammo findIf {"smoke" in (toLowerANSI _x)}; + + // check friendlies + private _dangerRound = false; + private _repeatRounds = true; + if ( RND(0.8) || { ([_unit, _dangerPos, 150] call EFUNC(main,findNearbyFriendlies)) isNotEqualTo [] } ) then { + if (_smokeIndex isEqualTo -1) then { + _dangerRound = true; + } else { + _shell = _ammo select _smokeIndex; + _repeatRounds = RND(0.5); + }; + }; + + // check night + if ( RND(0.2) && { _unit call EFUNC(main,isNight) } && { _flareIndex isNotEqualTo -1 } ) then { + _dangerPos = _dangerPos getPos [-50 + random 100, (_vehicle getDir _dangerPos) - 45 + random 90]; + _shell = _ammo select _flareIndex; + _dangerRound = false; + _repeatRounds = false; + }; + + // check for issues + if ( _dangerRound || { !(_dangerPos inRangeOfArtillery [[_vehicle], _shell]) } ) exitWith {}; + + // execute fire command + _vehicle commandArtilleryFire [_dangerPos getPos [30 + random 80, (_dangerPos getDir _vehicle) - 10 + random 20], _shell, 1 + random 2]; + _vehicle setVariable [QEGVAR(main,mortarTime), time + 24 + random 66]; + _unit setVariable [QEGVAR(main,currentTask), "Mortar Fire", EGVAR(main,debug_functions)]; + if (_repeatRounds) then { + [ + { + params [["_vehicle", objNull], ["_dangerPos", [0, 0, 0]], ["_shell", ""]]; + if ( canFire _vehicle && { unitReady _vehicle } ) then { + _vehicle commandArtilleryFire [_dangerPos, _shell, ( 2 + random 1 ) min ((gunner _vehicle) ammo (currentMuzzle (gunner _vehicle)))]; + }; + }, + [_vehicle, _dangerPos, _shell], + 18 + random 6 + ] call CBA_fnc_waitAndExecute; + }; }; [_timeout] + _causeArray }; @@ -95,8 +152,9 @@ if (_vehicle isKindOf "StaticWeapon") exitWith { // get out if enemy near OR out of ammunition if ((count (magazines _vehicle)) isEqualTo 0 || {(_unit findNearestEnemy _dangerPos) distance _vehicle < (6 + random 15)}) then { - private _vehicleCrew = (crew _vehicle); + private _vehicleCrew = crew _vehicle; _vehicleCrew orderGetIn false; + [_unit, "Combat", "Eject"] call EFUNC(main,doCallout); { _x setSuppression 0.94; // to prevent instant laser aim on exiting vehicle } forEach _vehicleCrew; // There may be more than one unit in vehicle @@ -112,8 +170,14 @@ if (_vehicle isKindOf "StaticWeapon") exitWith { [_timeout + random 4] + _causeArray }; +// Make leadership assessment as infantry +private _leader = leader _unit; +if (((vehicle _leader) isEqualTo _vehicle) && {_leader call FUNC(isLeader)}) then { + [_leader, _dangerCausedBy] call FUNC(tactics); +}; + // update information -if (_cause isEqualTo DANGER_ENEMYNEAR) then {[_unit, _dangerCausedBy] call EFUNC(main,doShareInformation);}; +if (_cause in [DANGER_ENEMYNEAR, DANGER_SCREAM]) then {[_unit, _dangerCausedBy] call EFUNC(main,doShareInformation);}; // select turret ammunition if (_attack && {!EGVAR(main,disableAutonomousMunitionSwitching) && {!(isNull _dangerCausedBy) && { @@ -143,14 +207,6 @@ if (_armored && {!isNull _dangerCausedBy}) exitWith { // keep cargo aboard! _vehicle setUnloadInCombat [false, false]; - // vehicle jink - private _oldDamage = _vehicle getVariable [QGVAR(vehicleDamage), 0]; - if (_validTarget && {_distance < (12 + random 15) || {damage _vehicle > _oldDamage}}) exitWith { - _vehicle setVariable [QGVAR(vehicleDamage), damage _vehicle]; - [_unit] call EFUNC(main,doVehicleJink); - [_timeout + _delay] + _causeArray - }; - // foot infantry support ~ unload private _group = group _vehicle; private _cargo = ((fullCrew [_vehicle, "cargo"]) apply {_x select 0}); @@ -173,15 +229,17 @@ if (_armored && {!isNull _dangerCausedBy}) exitWith { // define enemy direction _group setFormDir (_vehicle getDir _dangerCausedBy); - _cargo doMove _dangerPos; // delayed unload + _unit setVariable [QEGVAR(main,currentTask), "Dismounting troops", EGVAR(main,debug_functions)]; [ { params [["_cargo", []], ["_side", east], ["_vehicle", objNull]]; - _cargo orderGetIn false; + {_x action ["Eject", _vehicle];} forEach _cargo; + [selectRandom _cargo, "Combat", "Dismount"] call EFUNC(main,doCallout); _cargo allowGetIn false; if (EGVAR(main,debug_functions)) then {["%1 %2 unloading %3 carried troops", _side, getText (configOf _vehicle >> "displayName"), count _cargo] call EFUNC(main,debugLog);}; + _vehicle doMove (getPosASL _vehicle); }, [_cargo, side _group, _vehicle], 0.1 @@ -191,21 +249,55 @@ if (_armored && {!isNull _dangerCausedBy}) exitWith { [_timeout + _delay + 1] + _causeArray }; + // move into gunners seat ~ Enemy Detected, commander alive but gunner dead + private _slow = speed _vehicle < 20; + if ( + RND(0.4) + && _slow + && {someAmmo _vehicle} + && {_cause isEqualTo DANGER_ENEMYDETECTED} + && {!alive (gunner _vehicle)} + && {(commander _vehicle) call EFUNC(main,isAlive)} + ) exitWith { + (commander _vehicle) assignAsGunner _vehicle; + [_timeout + 3] + _causeArray + }; + + // vehicle jink + private _oldDamage = _vehicle getVariable [QGVAR(vehicleDamage), 0]; + if (_slow && _validTarget && {_distance < (12 + random 15) || {damage _vehicle > _oldDamage}} && {(driver _vehicle) call EFUNC(main,isAlive)}) exitWith { + _vehicle setVariable [QGVAR(vehicleDamage), damage _vehicle]; + [_unit] call EFUNC(main,doVehicleJink); + [_timeout + _delay] + _causeArray + }; + // tank assault - if (_attack && {speed _vehicle < 20}) then { + if (_attack && _slow && {(getUnitState _unit) in ["OK", "DELAY"]}) then { // rotate - if ((getUnitState _unit) isEqualTo "OK") then { - [_vehicle, _dangerPos] call EFUNC(main,doVehicleRotate); - }; - - // assault - if (_distance < 750 && {_dangerCausedBy isKindOf "Man"} && {_cause isEqualTo DANGER_ENEMYDETECTED}) then { - [ - {_this call EFUNC(main,doVehicleAssault)}, - [_unit, _dangerPos, _dangerCausedBy], - _delay - 1 - ] call CBA_fnc_waitAndExecute; + private _rotate = [_unit, _dangerPos] call EFUNC(main,doVehicleRotate); + + // assault + vehicle assault + if (!_rotate && {_distance < 750} && {(gunner _vehicle) call EFUNC(main,isAlive)}) then { + + // infantry + if ( _dangerCausedBy isKindOf "CAManBase" && { !( terrainIntersectASL [ eyePos _vehicle, eyePos _dangerCausedBy ] ) } ) exitWith { + [ + {_this call EFUNC(main,doVehicleAssault)}, + [_unit, _dangerPos, _dangerCausedBy], + _delay - 1.5 + ] call CBA_fnc_waitAndExecute; + }; + + // everything else -- assault! + if ( + isTouchingGround _dangerCausedBy + && { unitReady _vehicle } + && { (driver _vehicle) call EFUNC(main,isAlive) } + && { [_vehicle, "VIEW", vehicle _dangerCausedBy] checkVisibility [eyePos _vehicle, eyePos _dangerCausedBy] < 0.5 } + ) then { + [_unit, _dangerPos, _dangerCausedBy, _distance] call EFUNC(main,doVehicleAssaultMove); + }; }; }; @@ -221,14 +313,47 @@ if (_car) exitWith { private _delay = 0; private _slow = speed _vehicle < 30; + // move into gunners seat ~ 30-90 meters and Enemy Detected + if ( + _slow + && {canUnloadInCombat _vehicle} + && {someAmmo _vehicle} + && {_cause isEqualTo DANGER_ENEMYDETECTED} + && {_vehicle distanceSqr _dangerPos < (900 + random 3600)} + && {!alive (gunner _vehicle)} + ) exitWith { + _unit action ["Eject", _vehicle]; + _unit assignAsGunner _vehicle; + [ + { + params ["_unit", "_vehicle"]; + if (_unit call EFUNC(main,isAlive)) then { + [_unit, "Stealth", "Eject"] call EFUNC(main,doCallout); + _unit setDir (_unit getDir _vehicle); + _unit action ["getInGunner", _vehicle]; + }; + }, [_unit, _vehicle], 0.9 + ] call CBA_fnc_waitAndExecute; + [_timeout + 3] + _causeArray + }; + // escape ~ if enemy within 15-50 meters or explosions are nearby! - if (_slow && {(side _dangerCausedBy) isNotEqualTo (side _unit)} && {_cause isEqualTo DANGER_EXPLOSION || {_vehicle distanceSqr _dangerCausedBy < (225 + random 1225)}}) exitWith { + if ( + _slow + && {(side _dangerCausedBy) isNotEqualTo (side _unit)} + && {_cause isEqualTo DANGER_EXPLOSION || {_vehicle distanceSqr _dangerCausedBy < (225 + random 1225)}} + && {(driver _vehicle) call EFUNC(main,isAlive)} + ) exitWith { [_unit] call EFUNC(main,doVehicleJink); [_timeout + 3] + _causeArray }; - // look to danger - if (_attack && {_vehicle knowsAbout _dangerCausedBy > 3}) then {_vehicle doWatch (AGLToASL _dangerPos);}; + // look toward danger + if ( + _attack + && {_vehicle knowsAbout _dangerCausedBy > 3} + && {(gunner _vehicle) call EFUNC(main,isAlive)} + ) then {_vehicle doWatch (AGLToASL _dangerPos);}; // suppression if (_attack && {_slow}) then { @@ -241,9 +366,36 @@ if (_car) exitWith { [_timeout + _delay] + _causeArray }; -// Make leadership assessment as infantry -if (_unit call FUNC(isLeader)) then { - [_unit, _dangerCausedBy] call FUNC(tactics); +// vehicle type ~ Unarmed car +if (_vehicle isKindOf "Car_F" && {!someAmmo _vehicle}) then { + + // speed + private _stopped = speed _vehicle < 2; + + // leaders should dismount unarmed vehicles + if ( + _stopped + && {_unit isEqualTo _leader} + && {_leader isEqualTo (driver _vehicle)} + && {canUnloadInCombat _vehicle} + && {_cause in [DANGER_HIT, DANGER_BULLETCLOSE]} + ) exitWith { + [{moveOut _this; unassignVehicle _this;}, _unit, 1] call CBA_fnc_waitAndExecute; + }; + + // is static and a driver and enemy near and a threat - enemy within 10-35 meters + if ( + _stopped + && {!isNull (driver _vehicle)} + && {canUnloadInCombat _vehicle} + && {_cause isEqualTo DANGER_ENEMYDETECTED} + && {_vehicle distanceSqr _dangerCausedBy < (100 + random 225)} + ) then { + private _driver = driver _vehicle; + _driver action ["Eject", _vehicle]; + _driver setSuppression 0.94; // to prevent instant laser aim on exiting vehicle + [_driver, "Combat", "Eject"] call EFUNC(main,doCallout); + }; }; // end diff --git a/addons/main/XEH_PREP.hpp b/addons/main/XEH_PREP.hpp index 74a4b9844..8acf23974 100644 --- a/addons/main/XEH_PREP.hpp +++ b/addons/main/XEH_PREP.hpp @@ -55,6 +55,7 @@ SUBPREP(UnitAction,doSuppress); SUBPREP(UnitAction,doUGL); SUBPREP(VehicleAction,doVehicleAssault); +SUBPREP(VehicleAction,doVehicleAssaultMove); SUBPREP(VehicleAction,doVehicleJink); SUBPREP(VehicleAction,doVehicleRotate); SUBPREP(VehicleAction,doVehicleSuppress); diff --git a/addons/main/functions/UnitAction/fnc_doFleeing.sqf b/addons/main/functions/UnitAction/fnc_doFleeing.sqf index 2465b9e92..0e85c2fe3 100644 --- a/addons/main/functions/UnitAction/fnc_doFleeing.sqf +++ b/addons/main/functions/UnitAction/fnc_doFleeing.sqf @@ -14,7 +14,7 @@ * * Public: No */ -#define SEARCH_FOR_HIDE 6 +#define SEARCH_FOR_HIDE 12 #define SEARCH_FOR_BUILDING 8 params ["_unit"]; @@ -25,7 +25,7 @@ if ( || {!(_unit checkAIFeature "PATH")} || {!(_unit checkAIFeature "MOVE")} || {GVAR(disableAIFleeing)} - || {currentCommand _unit in ["GET IN", "ACTION", "REARM", "HEAL"]} + || {(currentCommand _unit) in ["GET IN", "ACTION", "REARM", "HEAL"]} ) exitWith {false}; // check for vehicle @@ -38,30 +38,70 @@ _unit setVariable [QGVAR(currentTarget), objNull, GVAR(debug_functions)]; // eventhandler [QGVAR(OnFleeing), [_unit, group _unit]] call FUNC(eventCallback); -// Abandon vehicles in need! -private _vehicle = vehicle _unit; -if ( - RND(0.5) - && {!_onFoot} - && {morale _unit < 0} - && {canUnloadInCombat _vehicle || {_vehicle isKindOf "StaticWeapon"}} - && {(speed _vehicle) < 3} - && {isTouchingGround _vehicle} -) exitWith { - [_unit] orderGetIn false; - _unit setSuppression 1; // prevents instant laser aim - nkenny + +// Vehicle sub-actions +if (!_onFoot) exitWith { + + // get vehicle + private _vehicle = vehicle _unit; + private _changeSeats = (speed _vehicle) < 3 && { isTouchingGround _vehicle }; + + // move into gunners seat ~ Enemy Detected, commander alive but gunner dead + private _candidate = call { + if ((commander _vehicle) call EFUNC(main,isAlive)) exitWith {commander _vehicle}; + if ((driver _vehicle) call EFUNC(main,isAlive)) exitWith {driver _vehicle}; + objNull + }; + + if ( + _changeSeats + && {!isNull _candidate} + && {someAmmo _vehicle} + && {!((gunner _vehicle) call EFUNC(main,isAlive))} + ) exitWith { + if (_vehicle isKindOf "Tank") then { + _candidate assignAsGunner _vehicle; + } else { + _candidate action ["Eject", _vehicle]; + _candidate assignAsGunner _vehicle; + [ + { + params ["_unit", "_vehicle"]; + if (_unit call EFUNC(main,isAlive)) then { + _unit setDir (_unit getDir _vehicle); + _unit action ["getInGunner", _vehicle]; + }; + }, [_candidate, _vehicle], 0.8 + ] call CBA_fnc_waitAndExecute; + }; + false + }; + + // Abandon vehicles in need! + private _abandonChance = ( (1 - damage _vehicle) + (_unit skillFinal "courage") ) * 0.5; + if (!canMove _vehicle || {fuel _vehicle < 0.1} || {_vehicle isKindOf "StaticWeapon"}) then { _abandonChance = _abandonChance * 0.25 }; + if (someAmmo _vehicle) then { _abandonChance = _abandonChance * 1.3 }; + if ( + RND(_abandonChance) + && {canUnloadInCombat _vehicle || (damage _vehicle) > 0.9} + && {_changeSeats} + ) exitWith { + if (_abandonChance < 0.5) then {_unit leaveVehicle _vehicle;}; + [_unit] orderGetIn false; + _unit setSuppression 1; // prevents instant laser aim - nkenny + false + }; + + // exit false }; -// no further action in vehicle -if (!_onFoot) exitWith {false}; // enemy private _enemy = _unit findNearestEnemy _unit; private _distance2D = _unit distance2D _enemy; // get destination -private _pos = (expectedDestination _unit) select 0; private _eyePos = eyePos _unit; private _suppression = getSuppression _unit; @@ -94,11 +134,18 @@ if (_onFootAndSeen) then { _unit forceSpeed -1; _unit setUnitPos (["MIDDLE", "DOWN"] select (_suppression > 0 || {_cover isNotEqualTo []})); // test nkenny + // update cover + _cover = _cover apply {_x getPos [1.5, _enemy getDir _x]}; + // find buildings to hide - private _buildings = [_unit, SEARCH_FOR_BUILDING, true, true] call FUNC(findBuildings); - _buildings append (_cover apply {getPos _x}); - if ((_buildings isNotEqualTo []) && {_distance2D > 5}) then { - _unit doMove selectRandom _buildings; + if (_distance2D > 30) then { + private _buildings = [_unit, SEARCH_FOR_BUILDING, true, true] call FUNC(findBuildings); + _cover append _buildings; + }; + + // execute move + if (_cover isNotEqualTo [] && {_distance2D > 5}) then { + _unit doMove selectRandom _cover; }; } else { @@ -107,6 +154,7 @@ if (_onFootAndSeen) then { // reset _unit setUnitPos "AUTO"; + _unit setUnitPosWeak "MIDDLE"; }; // debug @@ -115,7 +163,7 @@ if (GVAR(debug_functions)) then { "%1 Fleeing! %2 (%3m %4%5%6)", side _unit, name _unit, - [format ["Enemy @ %1", round _distance2D], format ["Destination @ %1", round (_unit distance2D _pos)]] select (isNull _enemy), + [format ["Enemy @ %1", round _distance2D], format ["Destination @ %1", round (_unit distance2D ((expectedDestination _unit) select 0))]] select (isNull _enemy), ["", "- suppressed "] select (_suppression > 0), ["", "- inside "] select (lineIntersects [_eyePos, _eyePos vectorAdd [0, 0, 10], _unit]), ["", "- spotted "] select (([objNull, "VIEW", objNull] checkVisibility [_eyePos, eyePos _enemy]) > 0.01) diff --git a/addons/main/functions/VehicleAction/fnc_doVehicleAssault.sqf b/addons/main/functions/VehicleAction/fnc_doVehicleAssault.sqf index 46c20f25b..0ecc329dd 100644 --- a/addons/main/functions/VehicleAction/fnc_doVehicleAssault.sqf +++ b/addons/main/functions/VehicleAction/fnc_doVehicleAssault.sqf @@ -62,11 +62,11 @@ _vehicle doWatch (AGLToASL _pos); private _suppression = [_unit, _pos] call FUNC(doVehicleSuppress); // set task -_unit setVariable [QEGVAR(main,currentTarget), _target, EGVAR(main,debug_functions)]; -_unit setVariable [QEGVAR(main,currentTask), "Vehicle Assault", EGVAR(main,debug_functions)]; +_unit setVariable [QGVAR(currentTarget), _target, GVAR(debug_functions)]; +_unit setVariable [QGVAR(currentTask), "Vehicle Assault", GVAR(debug_functions)]; // minor jink if no suppression possible -if (!_suppression) then {[_unit, 25] call FUNC(doVehicleJink)}; +if (!_suppression) exitWith {[_unit, 35] call FUNC(doVehicleJink)}; // cannon direction ~ threshold 30 degrees private _fnc_turretDir = { diff --git a/addons/main/functions/VehicleAction/fnc_doVehicleAssaultMove.sqf b/addons/main/functions/VehicleAction/fnc_doVehicleAssaultMove.sqf new file mode 100644 index 000000000..5249fb01f --- /dev/null +++ b/addons/main/functions/VehicleAction/fnc_doVehicleAssaultMove.sqf @@ -0,0 +1,97 @@ +#include "script_component.hpp" +/* + * Author: nkenny + * Vehicle moves aggressively to superior position + * + * Arguments: + * 0: _unit moving + * 1: dangerous position + * 2: dangerous object + * 3: distance to position and object + * + * Return Value: + * bool + * + * Example: + * [bob, getPos angryJoe, angryJoe] call lambs_main_fnc_doVehicleAssaultMove; + * + * Public: No +*/ +params ["_unit", "_pos", ["_target", objNull], ["_distance", -1]]; + +// settings +private _vehicle = vehicle _unit; + +// distance to position +if (_distance < 0) then {_distance = _vehicle distance _pos}; +if (isNull _target) then {_target = _vehicle;}; + +// cannot move or moving or enemy too close or too far away +if ( + !canMove _vehicle + || { (fuel _vehicle) < 0.1 } + || { (currentCommand _vehicle) in ["MOVE", "ATTACK"] } + || {_distance < (precision _vehicle)} + || {_distance > 200} + ) exitWith { + _vehicle doMove (getPosASL _vehicle); + false +}; + +private _destination = call { + + // 25 meters ahead + private _typeOf = typeOf _vehicle; + private _distance = _vehicle distance _pos; + private _movePos = _vehicle getPos [50 min _distance, _vehicle getDir _pos]; + _movePos = _movePos findEmptyPosition [0, 15, _typeOf]; + if (_movePos isNotEqualTo [] && {[vehicle _target, "VIEW", objNull] checkVisibility [(AGLToASL _movePos) vectorAdd [0, 0, 3], AGLToASL _pos] > 0}) exitWith { + _movePos + }; + + // random 200 + road adjustment + _movePos = (_vehicle getPos [200 min _distance, (_vehicle getDir _pos) - 45 + random 90]) findEmptyPosition [10, 30, _typeOf]; + if (_movePos isNotEqualTo [] && {[vehicle _target, "VIEW", objNull] checkVisibility [(AGLToASL _movePos) vectorAdd [0, 0, 3], AGLToASL _pos] > 0}) exitWith { + + // road adjust + private _roads = _movePos nearRoads 20; + if (_roads isNotEqualTo []) then {_movePos = (ASLToAGL (getPosASL (selectRandom _roads)));}; + + // return + _movePos + }; + + // On top of + _movePos = _pos findEmptyPosition [5, 35, _typeOf]; + if (_movePos isNotEqualTo []) exitWith { + _movePos + }; + + // none + [] +}; + +// check it! +if (_destination isEqualTo []) exitWith { + false +}; + +// set task +_unit setVariable [QGVAR(currentTarget), _destination, GVAR(debug_functions)]; +_unit setVariable [QGVAR(currentTask), "Vehicle Assault Move", GVAR(debug_functions)]; + +// execute +_vehicle doMove _destination; + +// debug +if (GVAR(debug_functions)) then { + [ + "%1 assault move (%2 moves %3m | visiblity %4)", + side _unit, getText (configOf _vehicle >> "displayName"), + round (_unit distance _destination), + [vehicle _target, "VIEW", objNull] checkVisibility [(AGLToASL _destination) vectorAdd [0, 0, 5], AGLToASL _pos] + ] call FUNC(debugLog); +}; + +// exit +true diff --git a/addons/main/functions/VehicleAction/fnc_doVehicleJink.sqf b/addons/main/functions/VehicleAction/fnc_doVehicleJink.sqf index b47840b25..316e01896 100644 --- a/addons/main/functions/VehicleAction/fnc_doVehicleJink.sqf +++ b/addons/main/functions/VehicleAction/fnc_doVehicleJink.sqf @@ -23,8 +23,8 @@ private _vehicle = vehicle _unit; // cannot move or moving if ( !canMove _vehicle - || {currentCommand _vehicle isEqualTo "MOVE" - || currentCommand _vehicle isEqualTo "ATTACK"} + || { (fuel _vehicle) < 0.1 } + || { (currentCommand _vehicle) in ["MOVE", "ATTACK"] } ) exitWith { getPosASL _unit }; diff --git a/addons/main/functions/VehicleAction/fnc_doVehicleRotate.sqf b/addons/main/functions/VehicleAction/fnc_doVehicleRotate.sqf index 82dad2830..3f7d695a6 100644 --- a/addons/main/functions/VehicleAction/fnc_doVehicleRotate.sqf +++ b/addons/main/functions/VehicleAction/fnc_doVehicleRotate.sqf @@ -10,13 +10,13 @@ * Arguments: * 0: Vehicle rotating * 1: Direction which to turn towards - * 2: Acceptible threshold in degrees + * 2: Acceptable threshold in degrees * * Return Value: * success * * Example: - * [bob, angryJoe] call lambs_main_fnc_doVehicleRotate; + * [bob, reallyAgryJoe] call lambs_main_fnc_doVehicleRotate; * * Public: No */ @@ -26,60 +26,81 @@ if (_target isEqualTo []) then { _target = _unit getHideFrom (_unit findNearestEnemy _unit); }; if (_target isEqualTo [0, 0, 0] || {_unit distanceSqr _target < 2}) exitWith {false}; +_target = _target call CBA_fnc_getPos; // cannot move or moving -if (!canMove _unit || {currentCommand _unit isEqualTo "MOVE"}) exitWith {false}; +private _vehicle = vehicle _unit; +if ( + !canMove _vehicle + || {(currentCommand _vehicle) isEqualTo "MOVE"} + || {!((driver _vehicle) call FUNC(isAlive))} + || {((vehicleMoveInfo _vehicle) select 1) in ["LEFT", "RIGHT"]} +) exitWith { + false +}; -// CQB tweak -- target within 75m - look instead -if (_unit distanceSqr _target < 5625) exitWith { - (vehicle _unit) doWatch (ATLToASL _target); +// CQB tweak -- target within 35m - look instead +if (_unit distanceSqr _target < 1225) exitWith { + _vehicle doWatch (ATLToASL _target); + false +}; + +// within acceptable limits +if (_vehicle getRelDir _target < _threshold || {_vehicle getRelDir _target > (360-_threshold)}) exitWith { false }; _unit setVariable [QGVAR(currentTarget), _target, GVAR(debug_functions)]; _unit setVariable [QGVAR(currentTask), "Vehicle Rotate", GVAR(debug_functions)]; -// within acceptble limits -if (_unit getRelDir _target < _threshold || {_unit getRelDir _target > (360-_threshold)}) exitWith { - false -}; +// move +_unit setFormDir (_unit getDir _target); +if (_vehicle isKindOf "Tank") then { + + // turn vehicle + _vehicle sendSimpleCommand (["LEFT", "RIGHT"] select (_unit getRelDir _target < 180)); + +} else { -// settings -private _pos = []; -private _min = 20; // Minimum range + // settings + private _pos = []; + private _min = 20; // Minimum range -for "_i" from 0 to 5 do { - _pos = (_unit getPos [_min, _unit getDir _target]) findEmptyPosition [0, 2.2, typeOf _unit]; + for "_i" from 0 to 5 do { + _pos = (_vehicle getPos [_min, _vehicle getDir _target]) findEmptyPosition [0, precision _vehicle, typeOf _vehicle]; - // water or exit - if !(_pos isEqualTo [] || {surfaceIsWater _pos}) exitWith {}; + // water or exit + if !(_pos isEqualTo [] || {surfaceIsWater _pos}) exitWith {}; - // update - _min = _min + 15; + // update + _min = _min + 15; + }; + if (_pos isEqualTo []) then {_pos = _vehicle modelToWorldVisual [0, -100, 0]}; + _vehicle doMove _pos; }; -if (_pos isEqualTo []) then {_pos = _unit modelToWorldVisual [0, -100, 0]}; -// move -_unit doMove _pos; -_unit setFormDir (_unit getDir _pos); // waitUntil [ { - params ["_unit", "_target", "_threshold"]; - ((_unit getRelDir _target) < _threshold || {(_unit getRelDir _target) > (360 - _threshold)}) + params ["_vehicle", "_target", "_threshold"]; + ((_vehicle getRelDir _target) < _threshold || {(_vehicle getRelDir _target) > (360 - _threshold)}) }, { - params ["_unit", "_target"]; - // check vehicle - if (canMove _unit && {(crew _unit) isNotEqualTo []}) then { - - // refresh ready - (effectiveCommander _unit) doMove (getPosASL _unit); + params ["_vehicle", "_target"]; + // refresh ready + _vehicle sendSimpleCommand "STOPTURNING"; + _vehicle sendSimpleCommand "STOP"; + _vehicle doMove (_vehicle getPos [precision _vehicle, _vehicle getDir _target]); - // refresh formation - (group _unit) setFormDir (_unit getDir _target); - }; - }, [_unit, _target, _threshold], (4 + random 6) + // refresh formation + (group _vehicle) setFormDir (_vehicle getDir _target); + }, [_vehicle, _target, _threshold * 3], 4 + random 3, + { + params ["_vehicle", "_target"]; + _vehicle doWatch (ATLToASL _target); + _vehicle sendSimpleCommand "STOPTURNING"; + _vehicle doMove (getPosASL _vehicle); + } ] call CBA_fnc_waitUntilAndExecute; // end diff --git a/addons/main/functions/VehicleAction/fnc_doVehicleSuppress.sqf b/addons/main/functions/VehicleAction/fnc_doVehicleSuppress.sqf index c08f49776..d5463297e 100644 --- a/addons/main/functions/VehicleAction/fnc_doVehicleSuppress.sqf +++ b/addons/main/functions/VehicleAction/fnc_doVehicleSuppress.sqf @@ -21,10 +21,10 @@ private _vehicle = vehicle _unit; _pos = _pos call CBA_fnc_getPos; // exit if vehicle is moving too fast or target is too high -if (speed _vehicle > 30 || {(_pos select 2) > 100}) exitWith {false}; +if (speed _vehicle > 30 || {(_pos select 2) > 100} || {!((gunner _vehicle) call FUNC(isAlive))}) exitWith {false}; // pos -private _eyePos = eyePos _unit; +private _eyePos = eyePos _vehicle; _pos = (AGLToASL _pos) vectorAdd [0.5 - random 1, 0.5 - random 1, 0.3 + random 1.3]; // target is close or terrain occludes target @@ -34,7 +34,7 @@ if ( ) exitWith {false}; // artillery (no tactical options) -if (_vehicle getVariable [QGVAR(isArtillery), getNumber (configOf (vehicle _unit) >> "artilleryScanner") > 0]) exitWith { +if (_vehicle getVariable [QGVAR(isArtillery), getNumber (configOf _vehicle >> "artilleryScanner") > 0]) exitWith { _vehicle setVariable [QGVAR(isArtillery), true]; false }; @@ -44,7 +44,7 @@ _unit setVariable [QGVAR(currentTarget), _pos, GVAR(debug_functions)]; _unit setVariable [QGVAR(currentTask), "Vehicle Suppress", GVAR(debug_functions)]; // trace -private _vis = lineIntersectsSurfaces [_eyePos, _pos, _unit, vehicle _unit, true, 1, "GEOM", "VIEW"]; +private _vis = lineIntersectsSurfaces [_eyePos, _pos, _unit, _vehicle, true, 1, "GEOM", "VIEW"]; if (_vis isNotEqualTo []) then {_pos = (_vis select 0) select 0;}; // recheck diff --git a/addons/main/functions/debug/fnc_debugDraw.sqf b/addons/main/functions/debug/fnc_debugDraw.sqf index 575243099..068eb08ab 100644 --- a/addons/main/functions/debug/fnc_debugDraw.sqf +++ b/addons/main/functions/debug/fnc_debugDraw.sqf @@ -127,7 +127,7 @@ private _posCam = positionCameraToWorld [0, 0, 0]; private _renderPos = getPosATLVisual _unit; private _isLeader = _unit isEqualTo (leader _unit); private _sideColor = [side (group _unit), false] call BIS_fnc_sideColor; - if ((_posCam distance _renderPos) <= _viewDistance && {((units _unit - [_unit]) findIf {_x distanceSqr _unit < 1}) isEqualTo -1}) then { + if ((_posCam distance _renderPos) <= _viewDistance) then { if (!GVAR(debug_drawAllUnitsInVehicles) && {_unit isNotEqualTo (effectiveCommander (vehicle _unit))}) exitWith {}; private _textData = [""]; diff --git a/addons/main/functions/fnc_doCallout.sqf b/addons/main/functions/fnc_doCallout.sqf index 0a8379fed..d640cbfb6 100644 --- a/addons/main/functions/fnc_doCallout.sqf +++ b/addons/main/functions/fnc_doCallout.sqf @@ -59,6 +59,9 @@ switch (toLowerANSI(_callout)) do { case ("flank"): { _callout = selectRandom ["OnYourFeet", "Advance", "FlankLeft", "FlankRight"]; }; + case ("eject"): { + _callout = selectRandom ["Eject", "EndangeredE"]; + }; }; private _cacheName = format ["%1_%2_%3_%4", QGVAR(callouts), _speaker, _behavior, _callout]; @@ -79,7 +82,7 @@ if (isNil "_cachedSounds") then { _cachedSounds set [_forEachIndex, objNull]; continue; }; - + private _hasFileEnding = _sound regexMatch ".+?\.(?:ogg|wss|wav|mp3)$/io"; if (_sound select [0, 1] != "\") then {