diff --git a/addons/hellfire/functions/fnc_attackProfile.sqf b/addons/hellfire/functions/fnc_attackProfile.sqf index b2a08f24a3..47decd64c0 100644 --- a/addons/hellfire/functions/fnc_attackProfile.sqf +++ b/addons/hellfire/functions/fnc_attackProfile.sqf @@ -18,7 +18,7 @@ */ params ["_seekerTargetPos", "_args", "_attackProfileStateParams"]; -_args params ["_firedEH", "_launchParams", "", "", "_stateParams"]; +_args params ["_firedEH", "_launchParams", "_flightParams", "", "_stateParams"]; _stateParams params ["", "_seekerStateParams"]; _launchParams params ["","_targetLaunchParams","_seekerType"]; @@ -29,69 +29,72 @@ _firedEH params ["","","","","","","_projectile"]; if (_attackProfileStateParams isEqualTo []) then { _this call FUNC(getAttackProfileSettings); }; -_attackProfileStateParams params ["_attackStage", "_configLaunchHeightClear"]; - +_attackProfileStateParams params ["_attackStage", "_configLaunchHeightClear", "_missileStateData"]; private _projectilePos = getPosASL _projectile; private _distanceFromLaunch2d = _launchPos distance2d _projectilePos; private _heightAboveLaunch = (_projectilePos select 2) - (_launchPos select 2); // Add height depending on distance for compensate -private _returnTargetPos = nil; +private _returnTargetPos = _seekerTargetPos; + +private _closingRate = vectorMagnitude velocity _projectile; +private _timeToGo = (_projectilePos distance2d _seekerTargetPos) / _closingRate; + +private _los = vectorNormalized (_seekerTargetPos vectorDiff _projectilePos); + +_flightParams params ["_pitchRate", "_yawRate"]; + +private _angleToTarget = acos ((vectorDir _projectile) vectorCos _los); +private _atMinRotationAngle = _angleToTarget >= (0.5 * _pitchRate * _timeToGo); switch (_attackStage) do { case STAGE_LAUNCH: { // Gain height quickly to pass terrain mask - _returnTargetPos = _projectilePos getPos [100, getDir _projectile]; - _returnTargetPos set [2, (_projectilePos select 2) + 36.4]; // 100 and 36.4 gives a 20 deg angle + _missileStateData params ["_heightBeforeStateSwitch", "_initialDistanceToTarget"]; + _returnTargetPos set [2, _heightBeforeStateSwitch + (_initialDistanceToTarget * sin 20)]; // 100 and 36.4 gives a 20 deg angle if (_heightAboveLaunch > _configLaunchHeightClear) then { _attackProfileStateParams set [0, STAGE_SEEK_CRUISE]; TRACE_2("New Stage: STAGE_SEEK_CRUISE",_distanceFromLaunch2d,_heightAboveLaunch); }; + + if (_atMinRotationAngle) then { + _attackProfileStateParams set [0, STAGE_ATTACK_TERMINAL]; + TRACE_2("New Stage: STAGE_ATTACK_TERMINAL",_distanceToTarget2d,_currentHeightOverTarget); + }; }; case STAGE_SEEK_CRUISE: { // Slowly gain altitude while searching for target + _missileStateData params ["_heightBeforeStateSwitch", "_initialDistanceToTarget"]; // Before 4000 cruise at 5.7 degrees up, then level out - private _cruiseHeight = linearConversion [3000, 5000, _distanceFromLaunch2d, 10, 0, true]; - - _returnTargetPos = _projectilePos getPos [100, getDir _projectile]; - _returnTargetPos set [2, (_projectilePos select 2) + _cruiseHeight]; - + _returnTargetPos set [2, _heightBeforeStateSwitch + (_initialDistanceToTarget * sin 5.7)]; + if (_seekerTargetPos isNotEqualTo [0,0,0]) then { _attackProfileStateParams set [0, STAGE_ATTACK_CRUISE]; + + _attackProfileStateParams set [2, [_projectilePos select 2, _seekerTargetPos distance2d _projectilePos]]; TRACE_1("New Stage: STAGE_ATTACK_CRUISE",_distanceFromLaunch2d); }; }; case STAGE_ATTACK_CRUISE: { + _missileStateData params ["_heightBeforeStateSwitch", "_initialDistanceToTarget"]; + private _currentHeightOverTarget = (_projectilePos select 2) - (_seekerTargetPos select 2); private _distanceToTarget2d = _seekerTargetPos distance2d _projectilePos; - private _distToGoRatio = _distanceToTarget2d / (_launchPos distance2d _seekerTargetPos); - // arcing up at 7 degrees to start until 50% left, then smooth curve to a downward attack - private _gainSlope = linearConversion [0.5, 0.1, _distToGoRatio, 7, -7, true]; - _returnTargetPos = +_seekerTargetPos; - _returnTargetPos set [2, ((_projectilePos select 2) + (_distanceToTarget2d * sin _gainSlope)) max (_seekerTargetPos select 2)]; + _returnTargetPos set [2, _heightBeforeStateSwitch + (_initialDistanceToTarget * sin 7)]; - if ((_distanceToTarget2d < 500) || {(_currentHeightOverTarget atan2 _distanceToTarget2d) > 15}) then { // Wait until we can come down at a sharp angle + // if we are at the rotation limit, rotate to target + if (_atMinRotationAngle || {(_currentHeightOverTarget atan2 _distanceToTarget2d) > 15}) then { // Wait until we can come down at a sharp angle _attackProfileStateParams set [0, STAGE_ATTACK_TERMINAL]; TRACE_2("New Stage: STAGE_ATTACK_TERMINAL",_distanceToTarget2d,_currentHeightOverTarget); }; }; case STAGE_ATTACK_TERMINAL: { - private _distanceToTarget2d = _seekerTargetPos distance2d _projectilePos; - _returnTargetPos = _seekerTargetPos vectorAdd [0, 0, _distanceToTarget2d * 0.02]; }; }; -// Special radar case. Adjust target position such that we are leading it -if (_attackStage >= 3 && { _seekerType isEqualTo "ARH" }) then { - _seekerStateParams params ["", "", "", "", "", "", "", "_lastKnownVelocity"]; - private _projectileVelocity = velocity _projectile; - if (_projectileVelocity#2 < 0) then { - private _projectileSpeed = vectorMagnitude _projectileVelocity; // this gives a precise impact time versus using speed _projectile. Dont change - private _timeUntilImpact = (_seekerTargetPos distance _projectilePos) / _projectileSpeed; - _returnTargetPos = _returnTargetPos vectorAdd (_lastKnownVelocity vectorMultiply _timeUntilImpact); - }; -}; +// missile guidance defines this variable in doAttackProfile +_attackProfileName = ["na", "hellfire - LAUNCH", "hellfire - SEEK CRUISE", "hellfire - ATTACK CRUISE", "hellfire - TERMINAL"] select _attackStage; -// TRACE_1("Adjusted target position", _returnTargetPos); +TRACE_1("Adjusted target position", _returnTargetPos); _returnTargetPos; diff --git a/addons/hellfire/functions/fnc_getAttackProfileSettings.sqf b/addons/hellfire/functions/fnc_getAttackProfileSettings.sqf index 066d280d65..e264a3fe4e 100644 --- a/addons/hellfire/functions/fnc_getAttackProfileSettings.sqf +++ b/addons/hellfire/functions/fnc_getAttackProfileSettings.sqf @@ -27,6 +27,8 @@ private _attackConfig = configFile >> QEGVAR(missileguidance,AttackProfiles) >> // Launch (clearing terrain mask for LO/HI): private _configLaunchHeightClear = getNumber (_attackConfig >> QGVAR(launchHeightClear)); +private _projectilePos = getPosASL _projectile; + // Get starting stage private _startingStage = if (_configLaunchHeightClear > 0) then { STAGE_LAUNCH; // LOAL-HI / LO @@ -41,5 +43,9 @@ private _startingStage = if (_configLaunchHeightClear > 0) then { // Set data in param array _attackProfileStateParams set [0, _startingStage]; _attackProfileStateParams set [1, _configLaunchHeightClear]; +_attackProfileStateParams set [2, [ + _projectilePos select 2, + _seekerTargetPos distance2d _projectilePos +]]; TRACE_1("new shot settings",_attackProfileStateParams); diff --git a/addons/hellfire/script_component.hpp b/addons/hellfire/script_component.hpp index 6d16736a9c..4ab934511b 100644 --- a/addons/hellfire/script_component.hpp +++ b/addons/hellfire/script_component.hpp @@ -3,7 +3,7 @@ #include "\z\ace\addons\main\script_mod.hpp" // #define DEBUG_MODE_FULL -// #define DISABLE_COMPILE_CACHE + #define DISABLE_COMPILE_CACHE // #define ENABLE_PERFORMANCE_COUNTERS #ifdef DEBUG_ENABLED_HELLFIRE diff --git a/addons/missileguidance/functions/fnc_doAttackProfile.sqf b/addons/missileguidance/functions/fnc_doAttackProfile.sqf index 53d43883d3..d239e08e0c 100644 --- a/addons/missileguidance/functions/fnc_doAttackProfile.sqf +++ b/addons/missileguidance/functions/fnc_doAttackProfile.sqf @@ -22,7 +22,6 @@ _args params ["", "_launchParams"]; _launchParams params ["", "", "", "_attackProfileName"]; private _attackProfileFunction = getText (configFile >> QGVAR(AttackProfiles) >> _attackProfileName >> "functionName"); - private _attackProfilePos = _this call (missionNamespace getVariable _attackProfileFunction); if ((isNil "_attackProfilePos") || {_attackProfilePos isEqualTo [0,0,0]}) exitWith { diff --git a/addons/missileguidance/functions/fnc_guidancePFH.sqf b/addons/missileguidance/functions/fnc_guidancePFH.sqf index c93362ed85..e970566f36 100644 --- a/addons/missileguidance/functions/fnc_guidancePFH.sqf +++ b/addons/missileguidance/functions/fnc_guidancePFH.sqf @@ -18,7 +18,7 @@ BEGIN_COUNTER(guidancePFH); -#define TIMESTEP_FACTOR 0.01 +#define TIMESTEP_FACTOR diag_deltaTime params ["_args", "_pfID"]; _args params ["_firedEH", "_launchParams", "_flightParams", "_seekerParams", "_stateParams"]; @@ -31,24 +31,12 @@ if (!alive _projectile || isNull _projectile || isNull _shooter) exitWith { END_COUNTER(guidancePFH); }; -private _runtimeDelta = diag_tickTime - _lastRunTime; -private _adjustTime = 1; - -if (accTime > 0) then { - _adjustTime = 1/accTime; - _adjustTime = _adjustTime * (_runtimeDelta / TIMESTEP_FACTOR); - TRACE_4("Adjust timing", 1/accTime, _adjustTime, _runtimeDelta, (_runtimeDelta / TIMESTEP_FACTOR) ); -} else { - _adjustTime = 0; -}; - -private _pitchRate = _flightParams select 0; -private _yawRate = _flightParams select 1; +_flightParams params ["_pitchRate", "_yawRate"]; // Run seeker function: private _seekerTargetPos = [[0,0,0], _args, _seekerStateParams, _lastKnownPosState] call FUNC(doSeekerSearch); - // Run attack profile function: +_seekerTargetPos = AGLtoASL ASLToAGL _seekerTargetPos; private _profileAdjustedTargetPos = [_seekerTargetPos, _args, _attackProfileStateParams] call FUNC(doAttackProfile); private _projectilePos = getPosASLVisual _projectile; diff --git a/addons/missileguidance/functions/fnc_onFired.sqf b/addons/missileguidance/functions/fnc_onFired.sqf index 3155460355..d324c573a9 100644 --- a/addons/missileguidance/functions/fnc_onFired.sqf +++ b/addons/missileguidance/functions/fnc_onFired.sqf @@ -70,7 +70,7 @@ if (isNil "_navigationType" || {!(_navigationType in (getArray (_config >> "navi _navigationType = getText (_config >> "defaultNavigationType"); }; -if (isNil "_navigationType") then { +if (isNil "_navigationType" || _navigationType isEqualTo "") then { // most missiles use ProNav by default _navigationType = "ProportionalNavigation"; }; @@ -108,6 +108,14 @@ private _navigationParameters = [ // set up in navigation type onFired function ]; +// default config values to make sure there is backwards compat +private _pitchRate = 30; +private _yawRate = 30; +if (isNumber (_config >> "pitchRate")) then { + _pitchRate = getNumber ( _config >> "pitchRate" ); + _yawRate = getNumber ( _config >> "yawRate" ); +}; + TRACE_5("Beginning ACE guidance system",_target,_ammo,_seekerType,_attackProfile,_navigationType); private _args = [_this, [ _shooter, @@ -119,8 +127,8 @@ private _args = [_this, _navigationType ], [ - getNumber ( _config >> "pitchRate" ), - getNumber ( _config >> "yawRate" ) + _pitchRate, + _yawRate ], [ getNumber ( _config >> "seekerAngle" ), diff --git a/addons/missileguidance/functions/fnc_proNav_onFired.sqf b/addons/missileguidance/functions/fnc_proNav_onFired.sqf index 1f4e72ec1d..844a9d9284 100644 --- a/addons/missileguidance/functions/fnc_proNav_onFired.sqf +++ b/addons/missileguidance/functions/fnc_proNav_onFired.sqf @@ -23,12 +23,14 @@ _seekerParams params ["_seekerAngle", "_seekerAccuracy", "_seekerMaxRange", "_se private _ammoConfig = configOf _projectile; private _navigationGain = getNumber (_ammoConfig >> QUOTE(ADDON) >> "navigationGain"); +if (_navigationGain == 0) then { + _navigationGain = 3; +}; private _pitchYaw = (vectorDir _projectile) call CBA_fnc_vect2Polar; - _navigationParams = [ [ // Last Missile Frame - [0, 0, 0], // Last target position + [0, 0, 0], // Last target position array [0, 0, 0], // Last target velocity [0, 0, 0] // Last line of sight ], diff --git a/addons/missileguidance/functions/fnc_seekerType_ARH.sqf b/addons/missileguidance/functions/fnc_seekerType_ARH.sqf index a3bda11258..05eb5091de 100644 --- a/addons/missileguidance/functions/fnc_seekerType_ARH.sqf +++ b/addons/missileguidance/functions/fnc_seekerType_ARH.sqf @@ -61,7 +61,6 @@ if (_isActive || { CBA_missionTime >= _timeWhenActive }) then { }; // Look in front of seeker for any targets private _nearestObjects = nearestObjects [ASLtoAGL _searchPos, ["Air", "LandVehicle", "Ship"], _seekerBaseRadiusAdjusted, false]; - _nearestObjects = _nearestObjects apply { // I check both Line of Sight versions to make sure that a single bush doesnt make the target lock dissapear but at the same time ensure that this can see through smoke. Should work 80% of the time if ([_projectile, getPosASL _x, _seekerAngle] call FUNC(checkSeekerAngle) && { ([_projectile, _x, true] call FUNC(checkLOS)) || { ([_projectile, _x, false] call FUNC(checkLOS)) } }) then { @@ -74,6 +73,7 @@ if (_isActive || { CBA_missionTime >= _timeWhenActive }) then { // Select closest object to the expected position to be the current radar target if ((count _nearestObjects) <= 0) exitWith { _projectile setMissileTarget objNull; + _seekerStateParams set [3, _searchPos]; _searchPos }; private _closestDistance = _seekerBaseRadiusAtGround; @@ -104,17 +104,21 @@ if (_isActive || { CBA_missionTime >= _timeWhenActive }) then { }; }; +#ifdef DRAW_GUIDANCE_INFO +drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [1,0,0,1], ASLtoAGL _expectedTargetPos, 0.75, 0.75, 0, "expected target pos", 1, 0.025, "TahomaB"]; +#endif + if !(isNull _target) then { private _centerOfObject = getCenterOfMass _target; - private _targetAdjustedPos = _target modelToWorldWorld _centerOfObject; + private _targetAdjustedPos = _target modelToWorldVisualWorld _centerOfObject; _expectedTargetPos = _targetAdjustedPos; - _seekerStateParams set [3, _expectedTargetPos]; _seekerStateParams set [7, velocity _target]; _seekerStateParams set [8, CBA_missionTime]; _seekerStateParams set [9, false]; }; +_seekerStateParams set [3, _expectedTargetPos]; _launchParams set [0, _target]; _expectedTargetPos