mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
Improve radar simulation
This commit is contained in:
parent
d0775283e3
commit
8318b60982
@ -15,8 +15,8 @@ class CfgAmmo {
|
|||||||
canVanillaLock = 1; // Can this default vanilla lock? Only applicable to non-cadet mode
|
canVanillaLock = 1; // Can this default vanilla lock? Only applicable to non-cadet mode
|
||||||
|
|
||||||
// Guidance type for munitions
|
// Guidance type for munitions
|
||||||
defaultSeekerType = "ARH";
|
defaultSeekerType = "DopplerRadar";
|
||||||
seekerTypes[] = { "ARH" };
|
seekerTypes[] = { "DopplerRadar" };
|
||||||
lockableTypes[] = {"Air"};
|
lockableTypes[] = {"Air"};
|
||||||
|
|
||||||
defaultSeekerLockMode = "LOAL";
|
defaultSeekerLockMode = "LOAL";
|
||||||
@ -55,8 +55,8 @@ class CfgAmmo {
|
|||||||
canVanillaLock = 1; // Can this default vanilla lock? Only applicable to non-cadet mode
|
canVanillaLock = 1; // Can this default vanilla lock? Only applicable to non-cadet mode
|
||||||
|
|
||||||
// Guidance type for munitions
|
// Guidance type for munitions
|
||||||
defaultSeekerType = "ARH";
|
defaultSeekerType = "DopplerRadar";
|
||||||
seekerTypes[] = { "ARH" };
|
seekerTypes[] = { "DopplerRadar" };
|
||||||
lockableTypes[] = {"Air"};
|
lockableTypes[] = {"Air"};
|
||||||
|
|
||||||
defaultSeekerLockMode = "LOAL";
|
defaultSeekerLockMode = "LOAL";
|
||||||
|
@ -76,8 +76,8 @@ class CfgAmmo {
|
|||||||
canVanillaLock = 1;
|
canVanillaLock = 1;
|
||||||
enabled = 1; // Missile Guidance must be explicitly enabled
|
enabled = 1; // Missile Guidance must be explicitly enabled
|
||||||
seekLastTargetPos = 0;
|
seekLastTargetPos = 0;
|
||||||
defaultSeekerType = "ARH";
|
defaultSeekerType = "MillimeterWaveRadar";
|
||||||
seekerTypes[] = { "ARH" };
|
seekerTypes[] = { "MillimeterWaveRadar" };
|
||||||
defaultSeekerLockMode = "LOBL";
|
defaultSeekerLockMode = "LOBL";
|
||||||
seekerLockModes[] = { "LOBL" };
|
seekerLockModes[] = { "LOBL" };
|
||||||
|
|
||||||
|
@ -80,13 +80,21 @@ class GVAR(SeekerTypes) {
|
|||||||
functionName = QFUNC(seekerType_SACLOS);
|
functionName = QFUNC(seekerType_SACLOS);
|
||||||
onFired = QFUNC(SACLOS_onFired);
|
onFired = QFUNC(SACLOS_onFired);
|
||||||
};
|
};
|
||||||
class ARH {
|
class MillimeterWaveRadar {
|
||||||
name = "";
|
name = "";
|
||||||
visualName = "";
|
visualName = "";
|
||||||
description = "";
|
description = "";
|
||||||
|
|
||||||
functionName = QFUNC(seekerType_ARH);
|
functionName = QFUNC(seekerType_MWR);
|
||||||
onFired = QFUNC(ahr_onFired);
|
onFired = QFUNC(mwr_onFired);
|
||||||
|
};
|
||||||
|
class DopplerRadar {
|
||||||
|
name = "";
|
||||||
|
visualName = "";
|
||||||
|
description = "";
|
||||||
|
|
||||||
|
functionName = QFUNC(seekerType_Doppler);
|
||||||
|
onFired = QFUNC(doppler_onFired);
|
||||||
};
|
};
|
||||||
class IR {
|
class IR {
|
||||||
name = "";
|
name = "";
|
||||||
|
@ -16,6 +16,8 @@ PREP(doSeekerSearch);
|
|||||||
PREP(doHandoff);
|
PREP(doHandoff);
|
||||||
PREP(handleHandoff);
|
PREP(handleHandoff);
|
||||||
|
|
||||||
|
PREP(shouldFilterRadarHit);
|
||||||
|
|
||||||
// Attack Profiles
|
// Attack Profiles
|
||||||
PREP(attackProfile_AIR);
|
PREP(attackProfile_AIR);
|
||||||
PREP(attackProfile_DIR);
|
PREP(attackProfile_DIR);
|
||||||
@ -38,7 +40,8 @@ PREP(navigationType_lineOfSight);
|
|||||||
PREP(seekerType_SALH);
|
PREP(seekerType_SALH);
|
||||||
PREP(seekerType_Optic);
|
PREP(seekerType_Optic);
|
||||||
PREP(seekerType_SACLOS);
|
PREP(seekerType_SACLOS);
|
||||||
PREP(seekerType_ARH);
|
PREP(seekerType_Doppler);
|
||||||
|
PREP(seekerType_MWR);
|
||||||
PREP(seekerType_IR);
|
PREP(seekerType_IR);
|
||||||
|
|
||||||
// Attack Profiles OnFired
|
// Attack Profiles OnFired
|
||||||
@ -46,7 +49,8 @@ PREP(wire_onFired);
|
|||||||
|
|
||||||
// Seeker OnFired
|
// Seeker OnFired
|
||||||
PREP(SACLOS_onFired);
|
PREP(SACLOS_onFired);
|
||||||
PREP(ahr_onFired);
|
PREP(doppler_onFired);
|
||||||
|
PREP(mwr_onFired);
|
||||||
PREP(IR_onFired);
|
PREP(IR_onFired);
|
||||||
|
|
||||||
// Navigation OnFired
|
// Navigation OnFired
|
||||||
|
76
addons/missileguidance/functions/fnc_doppler_onFired.sqf
Normal file
76
addons/missileguidance/functions/fnc_doppler_onFired.sqf
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: Brandon (TCVM)
|
||||||
|
* Sets up doppler radar state arrays (called from missileGuidance's onFired).
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* Guidance Arg Array <ARRAY>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [] call ace_missileguidance_fnc_mwr_onFired
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
params ["_firedEH", "_launchParams", "", "", "_stateParams"];
|
||||||
|
_firedEH params ["_shooter","","","","","","_projectile"];
|
||||||
|
_stateParams params ["", "_seekerStateParams"];
|
||||||
|
_launchParams params ["","_targetLaunchParams"];
|
||||||
|
_targetLaunchParams params ["_target"];
|
||||||
|
|
||||||
|
_target = missileTarget _projectile;
|
||||||
|
if (isNull _target && isVehicleRadarOn vehicle _shooter) then {
|
||||||
|
_target = cursorTarget;
|
||||||
|
};
|
||||||
|
if !(_target isKindOf "AllVehicles") then {
|
||||||
|
_target = nil;
|
||||||
|
};
|
||||||
|
_launchParams set [0, _target];
|
||||||
|
_projectile setMissileTarget objNull; // to emulate a no launch warning
|
||||||
|
|
||||||
|
private _projectileConfig = configOf _projectile;
|
||||||
|
private _config = _projectileConfig >> "ace_missileguidance";
|
||||||
|
|
||||||
|
private _isActive = false;
|
||||||
|
private _activeRadarDistance = [_config >> "activeRadarEngageDistance", "NUMBER", 500] call CBA_fnc_getConfigEntry;
|
||||||
|
private _projectileThrust = [_projectileConfig >> "thrust", "NUMBER", 0] call CBA_fnc_getConfigEntry;
|
||||||
|
private _projectileThrustTime = [_projectileConfig >> "thrustTime", "NUMBER", 0] call CBA_fnc_getConfigEntry;
|
||||||
|
|
||||||
|
private _lockTypes = [_config >> "lockableTypes", "ARRAY", ["Air", "LandVehicle", "Ship"]] call CBA_fnc_getConfigEntry;
|
||||||
|
|
||||||
|
private _velocityAtImpact = _projectileThrust * _projectileThrustTime;
|
||||||
|
private _timeToActive = 0;
|
||||||
|
if (!isNil "_target" && _velocityAtImpact > 0) then {
|
||||||
|
private _distanceUntilActive = (((getPosASL _shooter) vectorDistance (getPosASL _target)) - _activeRadarDistance);
|
||||||
|
_timeToActive = 0 max (_distanceUntilActive / _velocityAtImpact);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isNil "_target") then {
|
||||||
|
_timeToActive = 0;
|
||||||
|
_isActive = true;
|
||||||
|
_target = objNull;
|
||||||
|
};
|
||||||
|
|
||||||
|
private _shooterHasActiveRadar = {
|
||||||
|
if ("ActiveRadarSensorComponent" in _x) exitWith { true };
|
||||||
|
false
|
||||||
|
} forEach listVehicleSensors vehicle _shooter;
|
||||||
|
|
||||||
|
if !(isVehicleRadarOn vehicle _shooter) then {
|
||||||
|
_isActive = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
_seekerStateParams set [0, _isActive];
|
||||||
|
_seekerStateParams set [1, _activeRadarDistance];
|
||||||
|
_seekerStateParams set [2, CBA_missionTime + _timeToActive];
|
||||||
|
_seekerStateParams set [3, getPosASL _target];
|
||||||
|
_seekerStateParams set [4, CBA_missionTime];
|
||||||
|
_seekerStateParams set [5, _shooterHasActiveRadar];
|
||||||
|
_seekerStateParams set [6, false];
|
||||||
|
_seekerStateParams set [7, [0, 0, 0]];
|
||||||
|
_seekerStateParams set [8, CBA_missionTime];
|
||||||
|
_seekerStateParams set [9, isNull _target];
|
||||||
|
_seekerStateParams set [10, _lockTypes];
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
#include "script_component.hpp"
|
#include "script_component.hpp"
|
||||||
/*
|
/*
|
||||||
* Author: Brandon (TCVM)
|
* Author: Brandon (TCVM)
|
||||||
* Sets up Active Radar state arrays (called from missileGuidance's onFired).
|
* Sets up MWR state arrays (called from missileGuidance's onFired).
|
||||||
*
|
*
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* Guidance Arg Array <ARRAY>
|
* Guidance Arg Array <ARRAY>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
* None
|
* None
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* [] call ace_missileguidance_fnc_ahr_onFired
|
* [] call ace_missileguidance_fnc_mwr_onFired
|
||||||
*
|
*
|
||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
160
addons/missileguidance/functions/fnc_seekerType_Doppler.sqf
Normal file
160
addons/missileguidance/functions/fnc_seekerType_Doppler.sqf
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: Brandon (TCVM)
|
||||||
|
* doppler radar seeker
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* 1: Guidance Arg Array <ARRAY>
|
||||||
|
* 2: Seeker State <ARRAY>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* Seeker Pos <ARRAY>
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [] call call ace_missileguidance_fnc_seekerType_MWR;
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
params ["", "_args", "_seekerStateParams", "", "_timestep"];
|
||||||
|
_args params ["_firedEH", "_launchParams", "", "_seekerParams", "_stateParams", "_targetData"];
|
||||||
|
_firedEH params ["_shooter","","","","","","_projectile"];
|
||||||
|
_launchParams params ["_target","","","",""];
|
||||||
|
_seekerParams params ["_seekerAngle", "", "_seekerMaxRange"];
|
||||||
|
_seekerStateParams params ["_isActive", "_activeRadarEngageDistance", "_timeWhenActive", "_expectedTargetPos", "_lastTargetPollTime", "_shooterHasRadar", "_wasActive", "_lastKnownVelocity", "_lastTimeSeen", "_doesntHaveTarget", "_lockTypes"];
|
||||||
|
|
||||||
|
private _minimumFilterSpeed = 25;
|
||||||
|
private _minimumFilterTime = 1e-4;
|
||||||
|
private _maxTerrainCheck = 16000;
|
||||||
|
|
||||||
|
if (_isActive || { CBA_missionTime >= _timeWhenActive }) then {
|
||||||
|
if !(_isActive) then {
|
||||||
|
_seekerStateParams set [0, true];
|
||||||
|
};
|
||||||
|
if !(_wasActive) then {
|
||||||
|
_seekerStateParams set [6, true];
|
||||||
|
TRACE_1("Missile Pitbull",_seekerStateParams);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal radar homing
|
||||||
|
// For performance reasons only poll for target every so often instead of each frame
|
||||||
|
if ((_lastTargetPollTime + ACTIVE_RADAR_POLL_FREQUENCY) - CBA_missionTime < 0) then {
|
||||||
|
private _searchPos = _expectedTargetPos;
|
||||||
|
if (_searchPos isEqualTo [0, 0, 0] || { _doesntHaveTarget }) then {
|
||||||
|
_seekerStateParams set [9, true];
|
||||||
|
// no target pos - shot without lock. Have the missile's radar search infront of it on the ground
|
||||||
|
_searchPos = (getPosASL _projectile) vectorAdd (_projectile vectorModelToWorld [0, _seekerMaxRange, -((getPos _projectile)#2)]);
|
||||||
|
};
|
||||||
|
|
||||||
|
_target = objNull;
|
||||||
|
_lastTargetPollTime = CBA_missionTime;
|
||||||
|
_seekerStateParams set [4, _lastTargetPollTime];
|
||||||
|
private _distanceToExpectedTarget = _seekerMaxRange min ((getPosASL _projectile) vectorDistance _searchPos);
|
||||||
|
|
||||||
|
// Simulate how much the seeker can see at the ground
|
||||||
|
private _projDir = vectorDir _projectile;
|
||||||
|
private _projYaw = getDir _projectile;
|
||||||
|
private _rotatedYaw = (+(_projDir select 0) * sin _projYaw) + (+(_projDir select 1) * cos _projYaw);
|
||||||
|
if (_rotatedYaw isEqualTo 0) then { _rotatedYaw = 0.001 };
|
||||||
|
private _projPitch = atan ((_projDir select 2) / _rotatedYaw);
|
||||||
|
private _a1 = abs _projPitch;
|
||||||
|
private _a2 = 180 - ((_seekerAngle / 2) + _a1);
|
||||||
|
private _seekerBaseRadiusAtGround = ACTIVE_RADAR_MINIMUM_SCAN_AREA max (_distanceToExpectedTarget / sin(_a2) * sin(_seekerAngle / 2));
|
||||||
|
|
||||||
|
private _lastKnownSpeed = if (_lastKnownVelocity isEqualTo [0, 0, 0]) then {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
vectorMagnitude _lastKnownVelocity;
|
||||||
|
};
|
||||||
|
private _seekerBaseRadiusAdjusted = linearConversion [0, _seekerBaseRadiusAtGround, (CBA_missionTime - _lastTimeSeen) * vectorMagnitude _lastKnownVelocity, ACTIVE_RADAR_MINIMUM_SCAN_AREA, _seekerBaseRadiusAtGround, false];
|
||||||
|
if (_doesntHaveTarget) then {
|
||||||
|
_seekerBaseRadiusAdjusted = _seekerBaseRadiusAtGround;
|
||||||
|
};
|
||||||
|
// Look in front of seeker for any targets
|
||||||
|
private _nearestObjects = nearestObjects [ASLtoAGL _searchPos, _lockTypes, _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 {
|
||||||
|
|
||||||
|
if !([_x, _projectile, _minimumFilterSpeed, _minimumFilterTime, _maxTerrainCheck, _seekerAngle] call FUNC(shouldFilterRadarHit)) exitWith {
|
||||||
|
_x
|
||||||
|
};
|
||||||
|
objNull;
|
||||||
|
} else {
|
||||||
|
objNull
|
||||||
|
};
|
||||||
|
};
|
||||||
|
_nearestObjects = _nearestObjects select { !isNull _x };
|
||||||
|
// 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;
|
||||||
|
{
|
||||||
|
if ((_x distance2d _searchPos) < _closestDistance) then {
|
||||||
|
_closestDistance = _x distance2d _searchPos;
|
||||||
|
_target = _x;
|
||||||
|
};
|
||||||
|
} forEach _nearestObjects;
|
||||||
|
|
||||||
|
_expectedTargetPos = _searchPos;
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
#ifdef DRAW_GUIDANCE_INFO
|
||||||
|
_seekerTypeName = "DOPPLER - EXT";
|
||||||
|
#endif
|
||||||
|
// External radar homing
|
||||||
|
// if the target is in the remote targets for the side, whoever the donor is will "datalink" the target for the hellfire.
|
||||||
|
private _remoteTargets = listRemoteTargets side _shooter;
|
||||||
|
if ((_remoteTargets findIf { (_target in _x) && (_x#1 > 0) }) < 0) then {
|
||||||
|
// 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 (!_shooterHasRadar || { !isVehicleRadarOn vehicle _shooter } || { !alive vehicle _shooter } || { !([vehicle _shooter, _target, true] call FUNC(checkLOS)) && { !([vehicle _shooter, _target, false] call FUNC(checkLOS)) } }) then {
|
||||||
|
_seekerStateParams set [0, true];
|
||||||
|
_target = objNull; // set up state for active guidance
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#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 {
|
||||||
|
// we check if the target is moving away from us or perpendicular to see if we maintain lock
|
||||||
|
private _centerOfObject = getCenterOfMass _target;
|
||||||
|
private _targetAdjustedPos = _target modelToWorldVisualWorld _centerOfObject;
|
||||||
|
_expectedTargetPos = _targetAdjustedPos;
|
||||||
|
|
||||||
|
private _filterTarget = [_target, _projectile, _minimumFilterSpeed, _minimumFilterTime, _maxTerrainCheck, _seekerAngle] call FUNC(shouldFilterRadarHit);
|
||||||
|
if (_filterTarget) then {
|
||||||
|
// filter out target
|
||||||
|
_target = objNull;
|
||||||
|
_seekerStateParams set [9, true];
|
||||||
|
} else {
|
||||||
|
private _lineOfSight = vectorDirVisual _projectile;
|
||||||
|
private _realTargetVelocity = velocity _target;
|
||||||
|
private _projectedTargetVelocity = _lineOfSight vectorMultiply (_realTargetVelocity vectorDotProduct _lineOfSight);
|
||||||
|
private _relativeTargetVelocity = _realTargetVelocity vectorDiff _projectedTargetVelocity;
|
||||||
|
|
||||||
|
_seekerStateParams set [7, _relativeTargetVelocity];
|
||||||
|
_seekerStateParams set [8, CBA_missionTime];
|
||||||
|
_seekerStateParams set [9, false];
|
||||||
|
|
||||||
|
_targetData set [2, _projectile distance _target];
|
||||||
|
_targetData set [3, _relativeTargetVelocity];
|
||||||
|
|
||||||
|
if (_timestep != 0) then {
|
||||||
|
private _acceleration = (_relativeTargetVelocity vectorDiff _lastKnownVelocity) vectorMultiply (1 / _timestep);
|
||||||
|
_targetData set [4, _acceleration];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
_projectile setMissileTarget _target;
|
||||||
|
};
|
||||||
|
|
||||||
|
_targetData set [0, (getPosASLVisual _projectile) vectorFromTo _expectedTargetPos];
|
||||||
|
|
||||||
|
_seekerStateParams set [3, _expectedTargetPos];
|
||||||
|
_launchParams set [0, _target];
|
||||||
|
_expectedTargetPos
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
#include "script_component.hpp"
|
#include "script_component.hpp"
|
||||||
/*
|
/*
|
||||||
* Author: Brandon (TCVM)
|
* Author: Brandon (TCVM)
|
||||||
* Active Radar Homing seeker
|
* millimeter wave radar seeker
|
||||||
*
|
*
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* 1: Guidance Arg Array <ARRAY>
|
* 1: Guidance Arg Array <ARRAY>
|
||||||
@ -11,11 +11,11 @@
|
|||||||
* Seeker Pos <ARRAY>
|
* Seeker Pos <ARRAY>
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* [] call call ace_missileguidance_fnc_seekerType_ARH;
|
* [] call call ace_missileguidance_fnc_seekerType_MWR;
|
||||||
*
|
*
|
||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
params ["", "_args", "_seekerStateParams"];
|
params ["", "_args", "_seekerStateParams", "", "_timestep"];
|
||||||
_args params ["_firedEH", "_launchParams", "", "_seekerParams", "_stateParams", "_targetData"];
|
_args params ["_firedEH", "_launchParams", "", "_seekerParams", "_stateParams", "_targetData"];
|
||||||
_firedEH params ["_shooter","","","","","","_projectile"];
|
_firedEH params ["_shooter","","","","","","_projectile"];
|
||||||
_launchParams params ["_target","","","",""];
|
_launchParams params ["_target","","","",""];
|
||||||
@ -119,7 +119,11 @@ if !(isNull _target) then {
|
|||||||
|
|
||||||
_targetData set [2, _projectile distance _target];
|
_targetData set [2, _projectile distance _target];
|
||||||
_targetData set [3, velocity _target];
|
_targetData set [3, velocity _target];
|
||||||
_targetData set [4, [0, 0, 0]]; // todo: acceleration
|
|
||||||
|
if (_timestep != 0) then {
|
||||||
|
private _acceleration = ((velocity _target) vectorDiff _lastKnownVelocity) vectorMultiply (1 / _timestep);
|
||||||
|
_targetData set [4, _acceleration];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
_targetData set [0, (getPosASLVisual _projectile) vectorFromTo _expectedTargetPos];
|
_targetData set [0, (getPosASLVisual _projectile) vectorFromTo _expectedTargetPos];
|
141
addons/missileguidance/functions/fnc_shouldFilterRadarHit.sqf
Normal file
141
addons/missileguidance/functions/fnc_shouldFilterRadarHit.sqf
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: Brandon (TCVM)
|
||||||
|
* Whether or not we should filter out this target due to masking. Useful for only doppler radar types
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* 0: Target <OBJECT>
|
||||||
|
* 1: Projectile <OBJECT>
|
||||||
|
* 2: Minimum speed for doppler return to filter out <NUMBER>
|
||||||
|
* 3: Minimum time for doppler return to filter out <NUMBER>
|
||||||
|
* 4: Maximum distance to check for terrain <NUMBER>
|
||||||
|
* 5: Radar seeker angle <NUMBER>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* Whether or not to filter out this target
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [] call call ace_missileguidance_fnc_shouldFilterRadarHit;
|
||||||
|
*
|
||||||
|
* Public: Yes
|
||||||
|
*/
|
||||||
|
// as defined by lineIntersectsSurfaces
|
||||||
|
#define MAX_LINE_DISTANCE 5000
|
||||||
|
|
||||||
|
params ["_target", "_projectile", "_minimumSpeed", "_minimumTime", "_maximumTerrainCheck", "_seekerAngle"];
|
||||||
|
TRACE_5("should filter target",_projectile,_target,_minimumSpeed,_minimumTime,_maximumTerrainCheck);
|
||||||
|
// Theory developed from doppler radar visuals at https://www.mudspike.com/dcs-f-15c-combat-guide-for-beginners/
|
||||||
|
|
||||||
|
// helicopter blades will always produce a doppler shift due to their nature. Don't filter
|
||||||
|
if (_target isKindOf "Helicopter" && isEngineOn _target) exitWith {
|
||||||
|
TRACE_2("dont filter helicopters",_target isKindOf "Helicopter",isEngineOn _target);
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
private _lineOfSight = (getPosASLVisual _projectile) vectorFromTo (getPosASLVisual _target);
|
||||||
|
private _realTargetVelocity = velocity _target;
|
||||||
|
private _closingVelocity = _lineOfSight vectorMultiply (_realTargetVelocity vectorDotProduct _lineOfSight);
|
||||||
|
private _closingSpeed = vectorMagnitude _closingVelocity;
|
||||||
|
|
||||||
|
// if relative target velocity is greather than threshold, we can easily see it. Don't filter
|
||||||
|
if (_closingSpeed > _minimumSpeed) exitWith {
|
||||||
|
TRACE_2("dont filter fast objects approaching",_closingSpeed,_minimumSpeed);
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
private _projectilePos = getPosASLVisual _projectile;
|
||||||
|
|
||||||
|
private _stepDistance = _lineOfSight vectorMultiply (MAX_LINE_DISTANCE min _maximumTerrainCheck);
|
||||||
|
|
||||||
|
private _checkPos = _projectilePos;
|
||||||
|
private _maskedByGround = false;
|
||||||
|
|
||||||
|
// Check for all surfaces until we reach our max range
|
||||||
|
for "_i" from 0 to _maximumTerrainCheck step MAX_LINE_DISTANCE do {
|
||||||
|
// determine if target is masked by ground
|
||||||
|
private _endPos = _checkPos vectorAdd _stepDistance;
|
||||||
|
private _groundHit = lineIntersectsSurfaces [_checkPos, _endPos, _projectile, _target];
|
||||||
|
|
||||||
|
_maskedByGround = _groundHit isNotEqualTo [];
|
||||||
|
|
||||||
|
_checkPos = _endPos;
|
||||||
|
|
||||||
|
if (_maskedByGround || (_checkPos select 2) <= 0) then {
|
||||||
|
// for ease assume that we can't check underwater
|
||||||
|
if ((_checkPos select 2) < 0) then {
|
||||||
|
_checkPos set [2, 0];
|
||||||
|
};
|
||||||
|
break
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// looking at sky, target is clear as day. Check for chaff before filtering
|
||||||
|
if !(_maskedByGround) exitWith {
|
||||||
|
TRACE_1("dont filter stuff in the sky",_maskedByGround);
|
||||||
|
|
||||||
|
// If there is chaff nearby, check if they will confuse missile
|
||||||
|
private _nearby = _target nearObjects 50;
|
||||||
|
_nearby = _nearby select {
|
||||||
|
// 8 = radar blocking
|
||||||
|
private _blocking = configOf _x >> "weaponLockSystem";
|
||||||
|
private _isChaff = false;
|
||||||
|
if (isNumber _blocking) then {
|
||||||
|
_isChaff = (8 == getNumber _blocking);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isText _blocking) then {
|
||||||
|
_isChaff = ("8" in getText _blocking);
|
||||||
|
};
|
||||||
|
|
||||||
|
private _withinView = [_projectile, getPosASLVisual _x, _seekerAngle] call FUNC(checkSeekerAngle);
|
||||||
|
private _canSee = [_projectile, _x, false] call FUNC(checkLos);
|
||||||
|
|
||||||
|
{ (_withinView && _canSee && _isChaff) }
|
||||||
|
};
|
||||||
|
|
||||||
|
private _foundDecoy = false;
|
||||||
|
private _projectileVelocity = velocity _projectile;
|
||||||
|
{
|
||||||
|
private _considering = false;
|
||||||
|
|
||||||
|
private _distanceToFlare = _target distanceSqr _x;
|
||||||
|
if !(_foundDecoy) then {
|
||||||
|
private _chaffRelativeVelocity = (velocity _x) vectorDiff _projectileVelocity;
|
||||||
|
private _angleBetweenVelocities = acos (_closingVelocity vectorCos _chaffRelativeVelocity);
|
||||||
|
|
||||||
|
if (_angleBetweenVelocities <= 2) then {
|
||||||
|
_considering = true;
|
||||||
|
if (0.95 <= random 1) then {
|
||||||
|
_foundDecoy = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef DRAW_GUIDANCE_INFO
|
||||||
|
private _chaffPos = ASLToAGL getPosASLVisual _x;
|
||||||
|
private _colour = [1, 0, 0, 1];
|
||||||
|
if (_considering) then {
|
||||||
|
_colour = [0, 1, 0, 1];
|
||||||
|
};
|
||||||
|
if (_foundDecoy) then {
|
||||||
|
_colour = [0, 0, 1, 1];
|
||||||
|
};
|
||||||
|
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", _colour, _chaffPos, 0.75, 0.75, 0, "F", 1, 0.025, "TahomaB"];
|
||||||
|
#endif
|
||||||
|
} forEach _nearby;
|
||||||
|
|
||||||
|
_foundDecoy
|
||||||
|
};
|
||||||
|
|
||||||
|
private _distanceToTerrain = _checkPos vectorDistance _projectilePos;
|
||||||
|
private _checkTime = _distanceToTerrain / 3e8;
|
||||||
|
|
||||||
|
// Time to ground is large enough to know if we are looking at a target, don't filter
|
||||||
|
if (_checkTime > _minimumTime) exitWith {
|
||||||
|
TRACE_2("dont filter targets that we can see in ground clutter",_checkTime,_minimumTime);
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
// filter out the target since we can't reasonably see it
|
||||||
|
true
|
||||||
|
|
Loading…
Reference in New Issue
Block a user