diff --git a/addons/hellfire/CfgAmmo.hpp b/addons/hellfire/CfgAmmo.hpp index 5eef9ad47e..02346deac3 100644 --- a/addons/hellfire/CfgAmmo.hpp +++ b/addons/hellfire/CfgAmmo.hpp @@ -26,9 +26,8 @@ class CfgAmmo { class ace_missileguidance { enabled = 1; - minDeflection = 0.0005; // Minium flap deflection for guidance - maxDeflection = 0.01; // Maximum flap deflection for guidance - incDeflection = 0.0005; // The incrmeent in which deflection adjusts. + pitchRate = 30; // degrees per second + yawRate = 30; canVanillaLock = 0; // Can this default vanilla lock? Only applicable to non-cadet mode @@ -39,6 +38,9 @@ class CfgAmmo { defaultSeekerLockMode = "LOAL"; seekerLockModes[] = { "LOAL", "LOBL" }; + defaultNavigationType = "Direct"; + navigationTypes[] = { "Direct", "ZeroEffortMiss" }; + seekLastTargetPos = 1; // seek last target position [if seeker loses LOS of target, continue to last known pos] seekerAngle = 70; // Angle in front of the missile which can be searched seekerAccuracy = 1; // seeker accuracy multiplier @@ -49,6 +51,19 @@ class CfgAmmo { // Attack profile type selection defaultAttackProfile = "hellfire"; attackProfiles[] = {"hellfire", "hellfire_hi", "hellfire_lo"}; + + class navigationStates { + class initial { + transitionCondition = QFUNC(midCourseTransition); + navigationType = "Direct"; + }; + class terminal { + transitionCondition = ""; + navigationType = "ZeroEffortMiss"; + }; + // transitions from initial -> termimal + states[] = {"initial", "terminal"}; + }; }; }; class ACE_Hellfire_AGM114N: ACE_Hellfire_AGM114K { @@ -75,8 +90,8 @@ class CfgAmmo { canVanillaLock = 1; enabled = 1; // Missile Guidance must be explicitly enabled seekLastTargetPos = 0; - defaultSeekerType = "ARH"; - seekerTypes[] = { "ARH" }; + defaultSeekerType = "MillimeterWaveRadar"; + seekerTypes[] = { "MillimeterWaveRadar" }; defaultSeekerLockMode = "LOBL"; seekerLockModes[] = { "LOBL" }; diff --git a/addons/hellfire/XEH_PREP.hpp b/addons/hellfire/XEH_PREP.hpp index f30cf0bffd..011810aa04 100644 --- a/addons/hellfire/XEH_PREP.hpp +++ b/addons/hellfire/XEH_PREP.hpp @@ -2,3 +2,4 @@ LOG("prep"); PREP(attackProfile); PREP(getAttackProfileSettings); PREP(setupVehicle); +PREP(midCourseTransition); diff --git a/addons/hellfire/functions/fnc_attackProfile.sqf b/addons/hellfire/functions/fnc_attackProfile.sqf index 26bc3f1ff0..221d99e7ae 100644 --- a/addons/hellfire/functions/fnc_attackProfile.sqf +++ b/addons/hellfire/functions/fnc_attackProfile.sqf @@ -18,80 +18,99 @@ */ params ["_seekerTargetPos", "_args", "_attackProfileStateParams"]; -_args params ["_firedEH", "_launchParams", "", "", "_stateParams"]; +_args params ["_firedEH", "_launchParams", "_flightParams", "", "_stateParams"]; _stateParams params ["", "_seekerStateParams"]; _launchParams params ["","_targetLaunchParams","_seekerType"]; -_targetLaunchParams params ["", "", "_launchPos"]; +_targetLaunchParams params ["", "", "_launchPos", "_launchDir"]; _firedEH params ["","","","","","","_projectile"]; // Get state params: 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; +if (_returnTargetPos isEqualTo [0, 0, 0]) then { + private _initialDistanceToTarget = 8000; + _returnTargetPos = _launchPos vectorAdd (_launchDir vectorMultiply _initialDistanceToTarget); +}; + +private _closingRate = vectorMagnitude velocity _projectile; +// subtract 500 meters to account for the fact that we don't want to be at the perfect pitch exactly when we cross the target +// 500 seemed good in testing +private _timeToGo = ((_projectilePos distance2d _seekerTargetPos) - 500) / _closingRate; + +// we could do stuff like desired attack angle, but I'm not going that far today +private _los = _projectilePos vectorFromTo _seekerTargetPos; + +_flightParams params ["_pitchRate", "_yawRate"]; + +private _angleToTarget = acos ((vectorDir _projectile) vectorCos _los); +private _atMinRotationAngle = _angleToTarget >= (_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]; + + _attackProfileStateParams set [2, [_projectilePos select 2, _seekerTargetPos distance2d _projectilePos]]; TRACE_2("New Stage: STAGE_SEEK_CRUISE",_distanceFromLaunch2d,_heightAboveLaunch); }; + + if (_atMinRotationAngle) then { + _attackProfileStateParams set [0, STAGE_ATTACK_TERMINAL]; + + _attackProfileStateParams set [2, [_projectilePos select 2, _seekerTargetPos distance2d _projectilePos]]; + 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]; + + _attackProfileStateParams set [2, [_projectilePos select 2, _seekerTargetPos distance2d _projectilePos]]; 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 +//IGNORE_PRIVATE_WARNING ["_attackProfileName"]; +_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 14d89f82e3..b032c44d23 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 @@ -40,5 +42,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/functions/fnc_midCourseTransition.sqf b/addons/hellfire/functions/fnc_midCourseTransition.sqf new file mode 100644 index 0000000000..ee56773410 --- /dev/null +++ b/addons/hellfire/functions/fnc_midCourseTransition.sqf @@ -0,0 +1,29 @@ +#include "..\script_component.hpp" +/* + * Author: tcvm + * Condition to switch to next navigation profile + * + * Arguments: + * Guidance Arg Array + * + * Return Value: + * None + * + * Example: + * [] call ace_hellfire_fnc_midCourseTransition + * + * Public: No + */ + +_args params ["_firedEH", "_launchParams", "_flightParams", "_seekerParams", "_stateParams", "_targetData", "_navigationStateData"]; +_firedEH params ["_shooter","","","","_ammo","","_projectile"]; +_launchParams params ["_shooter","_targetLaunchParams","_seekerType","_attackProfile","_lockMode","_laserInfo","_navigationType"]; +_targetLaunchParams params ["_target", "_targetPos", "_launchPos", "_launchDir", "_launchTime"]; +_flightParams params ["_pitchRate", "_yawRate", "_isBangBangGuidance"]; +_stateParams params ["_lastRunTime", "_seekerStateParams", "_attackProfileStateParams", "_lastKnownPosState","_navigationParams", "_guidanceParameters"]; +_seekerParams params ["_seekerAngle", "_seekerAccuracy", "_seekerMaxRange", "_seekerMinRange"]; +_targetData params ["_targetDirection", "_attackProfileDirection", "_targetRange", "_targetVelocity", "_targetAcceleration"]; + +_attackProfileStateParams params ["_state"]; +_state isEqualTo STAGE_ATTACK_TERMINAL; +