Missile Guidance Overhaul

This commit is contained in:
PabstMirror 2016-10-12 17:35:24 -05:00
parent 846b7f26f7
commit 63f3673a65
27 changed files with 600 additions and 455 deletions

View File

@ -14,7 +14,7 @@ private _testSeekerPosASL = AGLtoASL (_seekerVehicle modelToWorldVisual [0,0,1])
private _testSeekerDir = vectorDirVisual _seekerVehicle;
{
private _code = _x;
private _results = [_testSeekerPosASL, _testSeekerDir, 45, [1550,1550], _code, _seekerVehicle] call FUNC(seekerFindLaserSpot);
private _results = [_testSeekerPosASL, _testSeekerDir, 45, 10000, [1550,1550], _code, _seekerVehicle] call FUNC(seekerFindLaserSpot);
private _resultPos = _results select 0;
if (!isNil "_resultPos") then {
// Draw lock results

View File

@ -7,9 +7,10 @@
* 0: Position of seeker (ASL) <ARRAY>
* 1: Direction vector (will be normalized) <ARRAY>
* 2: Seeker FOV in degrees <NUMBER>
* 3: Seeker wavelength sensitivity range, [1550,1550] is common eye safe. <ARRAY>
* 4: Seeker laser code. <NUMBER>
* 5: Ignore 1 (e.g. Player's vehicle) <OPTIONAL><OBJECT>
* 3: Seeker max distance in meters <NUMBER>
* 4: Seeker wavelength sensitivity range, [1550,1550] is common eye safe. <ARRAY>
* 5: Seeker laser code. <NUMBER>
* 6: Ignore 1 (e.g. Player's vehicle) <OPTIONAL><OBJECT>
*
* Return Value:
* Array, [Strongest compatible laser spot ASL pos, owner object] Nil array values if nothing found.
@ -24,13 +25,15 @@
BEGIN_COUNTER(seekerFindLaserSpot);
params ["_posASL", "_dir", "_seekerFov", "_seekerWavelengths", "_seekerCode", ["_ignoreObj1", objNull]];
params ["_posASL", "_dir", "_seekerFov", "_seekerMaxDistnace", "_seekerWavelengths", "_seekerCode", ["_ignoreObj1", objNull]];
_dir = vectorNormalized _dir;
_seekerWavelengths params ["_seekerWavelengthMin", "_seekerWavelengthMax"];
private _seekerCos = cos _seekerFov;
TRACE_5("",_posASL,_dir,_seekerFov,_seekerWavelengths,_seekerCode);
private _seekerCos = cos _seekerFov;
private _seekerMaxDistSq = _seekerMaxDistnace ^ 2;
TRACE_6("",_posASL,_dir,_seekerFov,_seekerMaxDistnace,_seekerWavelengths,_seekerCode);
private _spots = [];
private _finalPos = nil;
@ -76,7 +79,7 @@ private _finalOwner = objNull;
_testPoint = _x select 0;
private _testPointVector = _posASL vectorFromTo _testPoint;
private _testDotProduct = _dir vectorDotProduct _testPointVector;
if (_testDotProduct > _seekerCos) then {
if ((_testDotProduct > _seekerCos) && {(_testPoint vectorDistanceSqr _posASL) < _seekerMaxDistSq}) then {
_spots pushBack [_testPoint, _owner];
};
} forEach _resultPositions;
@ -87,7 +90,7 @@ private _finalOwner = objNull;
if (_distance > 0) then {
private _testPointVector = _posASL vectorFromTo _resultPos;
private _testDotProduct = _dir vectorDotProduct _testPointVector;
if (_testDotProduct > _seekerCos) then {
if ((_testDotProduct > _seekerCos) && {(_testPoint vectorDistanceSqr _posASL) < _seekerMaxDistSq}) then {
_spots pushBack [_resultPos, _owner];
};
};

View File

@ -2,9 +2,8 @@ class ACE_Settings {
class GVAR(enabled) {
value = 2;
typeName = "SCALAR";
isClientSettable = 1;
displayName = CSTRING(Title);
description = CSTRING(Desc);
values[] = {CSTRING(Off), CSTRING(PlayerOnly), CSTRING(PlayerAndAi)};
};
};
};

View File

@ -108,6 +108,8 @@ class CfgAmmo {
seekerMinRange = 0;
seekerMaxRange = 2500; // Range from the missile which the seeker can visually search
seekLastTargetPos = 1; // seek last target position [if seeker loses LOS of target, continue to last known pos]
// Attack profile type selection
defaultAttackProfile = "JAV_TOP";
attackProfiles[] = { "JAV_TOP", "JAV_DIR" };

View File

@ -1,6 +1,4 @@
PREP(rotateVectLineGetMap);
PREP(rotateVectLine);
PREP(changeMissileDirection);
PREP(checkSeekerAngle);
@ -17,11 +15,11 @@ PREP(doHandoff);
PREP(handleHandoff);
// Attack Profiles
PREP(attackProfile_LIN);
PREP(attackProfile_DIR);
PREP(attackProfile_MID);
PREP(attackProfile_HI);
PREP(attackProfile_AIR);
PREP(attackProfile_DIR);
PREP(attackProfile_HI);
PREP(attackProfile_LIN);
PREP(attackProfile_MID);
// Javelin profiles
PREP(attackProfile_JAV_DIR);

View File

@ -1,4 +1,22 @@
//#define DEBUG_MODE_FULL
/*
* Author: jaynus / nou
* Attack profile: AIR
* TODO: falls back to Linear
*
* Arguments:
* 0: Seeker Target PosASL <ARRAY>
* 1: Guidance Arg Array <ARRAY>
* 2: Seeker State <ARRAY>
*
* Return Value:
* Missile Aim PosASL <ARRAY>
*
* Example:
* [[1,2,3], [], []] call ace_missileguidance_fnc_attackProfile_AIR;
*
* Public: No
*/
// #define DEBUG_MODE_FULL
#include "script_component.hpp"
_this call FUNC(attackProfile_LIN);
_this call FUNC(attackProfile_LIN);

View File

@ -1,4 +1,22 @@
//#define DEBUG_MODE_FULL
/*
* Author: jaynus / nou
* Attack profile: DIR
* TODO: falls back to Linear
*
* Arguments:
* 0: Seeker Target PosASL <ARRAY>
* 1: Guidance Arg Array <ARRAY>
* 2: Seeker State <ARRAY>
*
* Return Value:
* Missile Aim PosASL <ARRAY>
*
* Example:
* [[1,2,3], [], []] call ace_missileguidance_fnc_attackProfile_DIR;
*
* Public: No
*/
// #define DEBUG_MODE_FULL
#include "script_component.hpp"
_this call FUNC(attackProfile_LIN);
_this call FUNC(attackProfile_LIN);

View File

@ -1,4 +1,22 @@
//#define DEBUG_MODE_FULL
/*
* Author: jaynus / nou
* Attack profile: HI
* TODO: falls back to Linear
*
* Arguments:
* 0: Seeker Target PosASL <ARRAY>
* 1: Guidance Arg Array <ARRAY>
* 2: Attack Profile State <ARRAY>
*
* Return Value:
* Missile Aim PosASL <ARRAY>
*
* Example:
* [[1,2,3], [], []] call ace_missileguidance_fnc_attackProfile_HI;
*
* Public: No
*/
// #define DEBUG_MODE_FULL
#include "script_component.hpp"
_this call FUNC(attackProfile_LIN);
_this call FUNC(attackProfile_LIN);

View File

@ -1,4 +1,21 @@
//#define DEBUG_MODE_FULL
/*
* Author: jaynus / nou
* Attack profile: Javelin Dir
*
* Arguments:
* 0: Seeker Target PosASL <ARRAY>
* 1: Guidance Arg Array <ARRAY>
* 2: Attack Profile State <ARRAY>
*
* Return Value:
* Missile Aim PosASL <ARRAY>
*
* Example:
* [[1,2,3], [], []] call ace_missileguidance_fnc_attackProfile_JAV_DIR;
*
* Public: No
*/
// #define DEBUG_MODE_FULL
#include "script_component.hpp"
#define STAGE_LAUNCH 1
@ -6,48 +23,41 @@
#define STAGE_COAST 3
#define STAGE_TERMINAL 4
EXPLODE_7_PVT(((_this select 1) select 0),_shooter,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile);
private["_targetPos", "_projectilePos", "_target", "_seekerTargetPos", "_launchParams", "_targetLaunchParams"];
private["_distanceToTarget", "_distanceToShooter", "_addHeight", "_returnTargetPos", "_state"];
private["_cruisAlt", "_distanceShooterToTarget", "_shooterPos"];
_seekerTargetPos = _this select 0;
_launchParams = _this select 1;
params ["_seekerTargetPos", "_args", "_attackProfileStateParams"];
_args params ["_firedEH"];
_firedEH params ["_shooter","","","","","","_projectile"];
_target = _launchParams select 0;
_targetLaunchParams = _launchParams select 1;
_state = _this select 2;
if( (count _state) < 1) then {
_state set[0, STAGE_LAUNCH];
if (_attackProfileStateParams isEqualTo []) then {
_attackProfileStateParams set [0, STAGE_LAUNCH];
};
_shooterPos = getPosASL _shooter;
_projectilePos = getPosASL _projectile;
private _shooterPos = getPosASL _shooter;
private _projectilePos = getPosASL _projectile;
_distanceToTarget = _projectilePos vectorDistance _seekerTargetPos;
_distanceToShooter = _projectilePos vectorDistance _shooterPos;
_distanceShooterToTarget = _shooterPos vectorDistance _seekerTargetPos;
private _distanceToTarget = _projectilePos vectorDistance _seekerTargetPos;
private _distanceToShooter = _projectilePos vectorDistance _shooterPos;
private _distanceShooterToTarget = _shooterPos vectorDistance _seekerTargetPos;
TRACE_2("", _distanceToTarget, _distanceToShooter);
// Add height depending on distance for compensate
_returnTargetPos = _seekerTargetPos;
private _returnTargetPos = _seekerTargetPos;
switch( (_state select 0) ) do {
switch (_attackProfileStateParams select 0) do {
case STAGE_LAUNCH: {
TRACE_1("STAGE_LAUNCH","");
if(_distanceToShooter < 10) then {
if (_distanceToShooter < 10) then {
_returnTargetPos = _seekerTargetPos vectorAdd [0,0,_distanceToTarget*2];
} else {
_state set[0, STAGE_CLIMB];
_attackProfileStateParams set [0, STAGE_CLIMB];
};
};
case STAGE_CLIMB: {
TRACE_1("STAGE_CLIMB","");
_cruisAlt = 60 * (_distanceShooterToTarget/2000);
private _cruisAlt = 60 * (_distanceShooterToTarget/2000);
if( ((ASLToAGL _projectilePos) select 2) - ((ASLToAGL _seekerTargetPos) select 2) >= _cruisAlt) then {
_state set[0, STAGE_TERMINAL];
if ( ((ASLToAGL _projectilePos) select 2) - ((ASLToAGL _seekerTargetPos) select 2) >= _cruisAlt) then {
_attackProfileStateParams set [0, STAGE_TERMINAL];
} else {
_returnTargetPos = _seekerTargetPos vectorAdd [0,0,_distanceToTarget*1.5];
};
@ -58,9 +68,5 @@ switch( (_state select 0) ) do {
};
};
#ifdef DEBUG_MODE_FULL
drawLine3D [(ASLtoAGL _returnTargetPos), (ASLtoAGL _seekerTargetPos), [0,1,0,1]];
#endif
TRACE_1("Adjusted target position", _returnTargetPos);
_returnTargetPos;

View File

@ -1,4 +1,21 @@
//#define DEBUG_MODE_FULL
/*
* Author: jaynus / nou
* Attack profile: Javelin Top
*
* Arguments:
* 0: Seeker Target PosASL <ARRAY>
* 1: Guidance Arg Array <ARRAY>
* 2: Attack Profile State <ARRAY>
*
* Return Value:
* Missile Aim PosASL <ARRAY>
*
* Example:
* [[1,2,3], [], []] call ace_missileguidance_fnc_attackProfile_JAV_TOP;
*
* Public: No
*/
// #define DEBUG_MODE_FULL
#include "script_component.hpp"
#define STAGE_LAUNCH 1
@ -6,55 +23,47 @@
#define STAGE_COAST 3
#define STAGE_TERMINAL 4
EXPLODE_7_PVT(((_this select 1) select 0),_shooter,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile);
private["_targetPos", "_projectilePos", "_target", "_seekerTargetPos", "_launchParams", "_targetLaunchParams"];
private["_distanceToTarget", "_distanceToShooter", "_addHeight", "_returnTargetPos", "_state"];
private["_cruisAlt", "_distanceShooterToTarget", "_shooterPos"];
params ["_seekerTargetPos", "_args", "_attackProfileStateParams"];
_args params ["_firedEH"];
_firedEH params ["_shooter","","","","","","_projectile"];
_seekerTargetPos = _this select 0;
_launchParams = _this select 1;
_target = _launchParams select 0;
_targetLaunchParams = _launchParams select 1;
_state = _this select 2;
if( (count _state) < 1) then {
_state set[0, STAGE_LAUNCH];
if (_attackProfileStateParams isEqualTo []) then {
_attackProfileStateParams set [0, STAGE_LAUNCH];
};
_shooterPos = getPosASL _shooter;
_projectilePos = getPosASL _projectile;
private _shooterPos = getPosASL _shooter;
private _projectilePos = getPosASL _projectile;
_distanceToTarget = _projectilePos vectorDistance _seekerTargetPos;
_distanceToShooter = _projectilePos vectorDistance _shooterPos;
_distanceShooterToTarget = _shooterPos vectorDistance _seekerTargetPos;
private _distanceToTarget = _projectilePos vectorDistance _seekerTargetPos;
private _distanceToShooter = _projectilePos vectorDistance _shooterPos;
private _distanceShooterToTarget = _shooterPos vectorDistance _seekerTargetPos;
TRACE_2("", _distanceToTarget, _distanceToShooter);
// Add height depending on distance for compensate
_returnTargetPos = _seekerTargetPos;
private _returnTargetPos = _seekerTargetPos;
switch( (_state select 0) ) do {
switch( (_attackProfileStateParams select 0) ) do {
case STAGE_LAUNCH: {
TRACE_1("STAGE_LAUNCH","");
if(_distanceToShooter < 10) then {
if (_distanceToShooter < 10) then {
_returnTargetPos = _seekerTargetPos vectorAdd [0,0,_distanceToTarget*2];
} else {
_state set[0, STAGE_CLIMB];
_attackProfileStateParams set [0, STAGE_CLIMB];
};
};
case STAGE_CLIMB: {
TRACE_1("STAGE_CLIMB","");
_cruisAlt = 140;
if(_distanceShooterToTarget < 1250) then {
_cruisAlt = 140 * (_distanceShooterToTarget/1250);
if (_distanceShooterToTarget < 1250) then {
private _cruisAlt = 140 * (_distanceShooterToTarget/1250);
TRACE_1("_cruisAlt", _cruisAlt);
};
if( ((ASLToAGL _projectilePos) select 2) - ((ASLToAGL _seekerTargetPos) select 2) >= _cruisAlt) then {
if(_cruisAlt < 140) then {
_state set[0, STAGE_TERMINAL];
if ( ((ASLToAGL _projectilePos) select 2) - ((ASLToAGL _seekerTargetPos) select 2) >= _cruisAlt) then {
if (_cruisAlt < 140) then {
_attackProfileStateParams set [0, STAGE_TERMINAL];
} else {
_state set[0, STAGE_COAST];
_attackProfileStateParams set [0, STAGE_COAST];
};
} else {
_returnTargetPos = _seekerTargetPos vectorAdd [0,0,_distanceToTarget*1.5];
@ -63,8 +72,8 @@ switch( (_state select 0) ) do {
case STAGE_COAST: {
TRACE_1("STAGE_COAST","");
TRACE_1("", ((ASLToAGL _projectilePos) select 2) - (( ASLToAGL _seekerTargetPos) select 2) );
if(_distanceToTarget < ( ((ASLToAGL _projectilePos) select 2) - (( ASLToAGL _seekerTargetPos) select 2) ) * 1.5) then {
_state set[0, STAGE_TERMINAL];
if (_distanceToTarget < ( ((ASLToAGL _projectilePos) select 2) - (( ASLToAGL _seekerTargetPos) select 2) ) * 2) then {
_attackProfileStateParams set [0, STAGE_TERMINAL];
} else {
_returnTargetPos = _seekerTargetPos vectorAdd [0,0,(_projectilePos select 2)];
};
@ -76,9 +85,5 @@ switch( (_state select 0) ) do {
};
};
#ifdef DEBUG_MODE_FULL
drawLine3D [(ASLtoAGL _returnTargetPos), (ASLtoAGL _seekerTargetPos), [0,1,0,1]];
#endif
TRACE_1("Adjusted target position", _returnTargetPos);
_returnTargetPos;

View File

@ -1,50 +1,63 @@
//#define DEBUG_MODE_FULL
/*
* Author: jaynus / nou
* Attack profile: Linear (used by DAGR)
*
* Arguments:
* 0: Seeker Target PosASL <ARRAY>
* 1: Guidance Arg Array <ARRAY>
* 2: Attack Profile State <ARRAY>
*
* Return Value:
* Missile Aim PosASL <ARRAY>
*
* Example:
* [[1,2,3], [], []] call ace_missileguidance_fnc_attackProfile_LIN;
*
* Public: No
*/
// #define DEBUG_MODE_FULL
#include "script_component.hpp"
EXPLODE_7_PVT(((_this select 1) select 0),_shooter,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile);
private["_targetPos", "_projectilePos", "_target", "_seekerTargetPos", "_launchParams", "_targetLaunchParams"];
private["_distanceToTarget", "_distanceToShooter", "_addHeight", "_returnTargetPos", "_shooterPos"];
_seekerTargetPos = _this select 0;
_launchParams = _this select 1;
params ["_seekerTargetPos", "_args"];
_args params ["_firedEH"];
_firedEH params ["_shooter","","","","","","_projectile"];
_target = _launchParams select 0;
_targetLaunchParams = _launchParams select 1;
private _shooterPos = getPosASL _shooter;
private _projectilePos = getPosASL _projectile;
_shooterPos = getPosASL _shooter;
_projectilePos = getPosASL _projectile;
private _distanceToTarget = _projectilePos vectorDistance _seekerTargetPos;
private _distanceToShooter = _projectilePos vectorDistance _shooterPos;
private _distanceShooterToTarget = _shooterPos vectorDistance _seekerTargetPos;
_distanceToTarget = _projectilePos vectorDistance _seekerTargetPos;
_distanceToShooter = _projectilePos vectorDistance _shooterPos;
TRACE_3("", _distanceToTarget, _distanceToShooter, _seekerTargetPos);
TRACE_2("", _distanceToTarget, _distanceToShooter);
// Add height depending on distance for compensate
_addHeight = [0,0,0];
private _addHeight = [0,0,0];
// Always climb an arc on initial launch if we are close to the round
if( ((ASLtoAGL _projectilePos) select 2) < 5 && _distanceToShooter < 15) then {
_addHeight = _addHeight vectorAdd [0,0,_distanceToTarget];
if ((((ASLtoAGL _projectilePos) select 2) < 5) && {_distanceToShooter < 15}) then {
_addHeight = _addHeight vectorAdd [0,0,_distanceToTarget];
TRACE_1("climb - near shooter",_addHeight);
} else {
// If we are below the target, increase the climbing arc
if((_projectilePos select 2) < (_seekerTargetPos select 2) && _distanceToTarget > 100) then {
if (((_projectilePos select 2) < (_seekerTargetPos select 2)) && {_distanceToTarget > 100}) then {
_addHeight = _addHeight vectorAdd [0,0, ((_seekerTargetPos select 2) - (_projectilePos select 2))];
TRACE_1("climb - below target and far",_addHeight);
};
};
// Handle arcing terminal low for high decent
if( (_projectilePos select 2) > (_seekerTargetPos select 2) && _distanceToTarget < 100) then {
_addHeight = _addHeight vectorDiff [0,0, ((_projectilePos select 2) - (_seekerTargetPos select 2)) * 0.5];
} else {
if((_projectilePos select 2) > (_seekerTargetPos select 2) && _distanceToTarget > 100) then {
// Handle arcing terminal low for high decent (when projectile above target)
if ((_projectilePos select 2) > (_seekerTargetPos select 2)) then {
if (_distanceToTarget < 100) then {
_addHeight = _addHeight vectorDiff [0,0, ((_projectilePos select 2) - (_seekerTargetPos select 2)) * 0.5];
TRACE_1("above - close",_addHeight);
} else {
TRACE_1("above - far",_addHeight);
_addHeight = _addHeight vectorAdd [0,0, _distanceToTarget*0.02];
};
};
_returnTargetPos = _seekerTargetPos vectorAdd _addHeight;
private _returnTargetPos = _seekerTargetPos vectorAdd _addHeight;
#ifdef DEBUG_MODE_FULL
drawLine3D [(ASLtoAGL _returnTargetPos) vectorAdd _addHeight, ASLtoAGL _returnTargetPos, [0,1,0,1]];
#endif
TRACE_1("Adjusted target position", _returnTargetPos);
TRACE_2("Adjusted target position",_returnTargetPos,_addHeight);
_returnTargetPos;

View File

@ -1,4 +1,22 @@
//#define DEBUG_MODE_FULL
/*
* Author: jaynus / nou
* Attack profile: MID
* TODO: falls back to Linear
*
* Arguments:
* 0: Seeker Target PosASL <ARRAY>
* 1: Guidance Arg Array <ARRAY>
* 2: Attack Profile State <ARRAY>
*
* Return Value:
* Missile Aim PosASL <ARRAY>
*
* Example:
* [[1,2,3], [], []] call ace_missileguidance_fnc_attackProfile_MID;
*
* Public: No
*/
// #define DEBUG_MODE_FULL
#include "script_component.hpp"
_this call FUNC(attackProfile_LIN);
_this call FUNC(attackProfile_LIN);

View File

@ -1,11 +1,26 @@
/*
* Author: jaynus / nou
* Change a projectile's direction, maintaing speed
*
* Arguments:
* 0: Projectile <OBJECT>
* 1: Direction (unit vector) <ARRAY>
*
* Return Value:
* None
*
* Example:
* [missile, [0,1,0]] call ace_missileguidance_fnc_changeMissileDirection;
*
* Public: No
*/
// #define DEBUG_MODE_FULL
#include "script_component.hpp"
private ["_projectile", "_v", "_l", "_r"];
_projectile = _this select 0;
_v = _this select 1;
params ["_projectile", "_v"];
_l = sqrt ((_v select 0) ^ 2 + (_v select 1) ^ 2);
_r = -(_v select 2) / _l;
private _l = sqrt ((_v select 0) ^ 2 + (_v select 1) ^ 2);
private _r = -(_v select 2) / _l;
_projectile setVectorDirAndUp [ _v, [(_v select 0) * _r,(_v select 1) * _r, _l] ];
_projectile setVelocity (_v vectorMultiply (vectorMagnitude (velocity _projectile)));
_projectile setVelocity (_v vectorMultiply (vectorMagnitude (velocity _projectile)));

View File

@ -3,17 +3,25 @@
* Returns whether the seeker object can see the target position with lineIntersect
*
* Arguments:
* 0: Seeker [Object]
* 1: Target [Object]
* 0: Seeker <OBJECT>
* 1: Target <OBJECT>
*
* Return Value:
* Boolean
* Has LOS <BOOL>
*
* Example:
* [player, cursorTarget] call ace_missileguidance_fnc_checkLOS;
*
* Public: No
*/
#include "script_component.hpp"
params ["_seeker", "_target"];
if ((isNil "_seeker") || {isNil "_target"}) exitWith {false};
if ((isNil "_seeker") || {isNil "_target"}) exitWith {
ERROR_2("nil",_seeker,_target);
false
};
private _targetPos = getPosASL _target;
private _targetAimPos = aimPos _target;
@ -21,11 +29,11 @@ private _seekerPos = getPosASL _seeker;
private _return = true;
if (!((terrainIntersectASL [_seekerPos, _targetPos]) && {terrainIntersectASL [_seekerPos, _targetAimPos]})) then {
if(lineIntersects [_seekerPos, _targetPos, _seeker, _target]) then {
if (lineIntersects [_seekerPos, _targetPos, _seeker, _target]) then {
_return = false;
};
} else {
_return = false;
};
_return;
_return;

View File

@ -1,31 +1,35 @@
/*
* Author: jaynus
* Returns whether the target position is within the maximum angle FOV of the provided seeker
* Returns whether the target position is within the maximum angle FOV of the provided seeker
* objects current direction.
*
* Arguments:
* 0: Seeker [Object]
* 1: Target [Position]
* 2: Max Angle [Degrees]
*
* 0: Seeker <OBJECT>
* 1: Target PosASL <ARRAY>
* 2: Max Angle (degrees) <NUMBER>
*
* Return Value:
* Boolean
* Can See <BOOL>
*
* Example:
* [player, cursorTarget, 45] call ace_missileguidance_fnc_checkSeekerAngle;
*
* Public: No
*/
// #define DEBUG_MODE_FULL
#include "script_component.hpp"
private ["_seeker", "_targetPos", "_seekerMaxAngle", "_sensorPos", "_testPointVector", "_testDotProduct"];
_seeker = _this select 0;
_targetPos = _this select 1;
_seekerMaxAngle = _this select 2;
params ["_seeker", "_targetPos", "_seekerMaxAngle"];
_sensorPos = getPosASL _seeker;
private _sensorPos = getPosASL _seeker;
_testPointVector = vectorNormalized (_targetPos vectorDiff _sensorPos);
_testDotProduct = (vectorNormalized (velocity _seeker)) vectorDotProduct _testPointVector;
private _testPointVector = vectorNormalized (_targetPos vectorDiff _sensorPos);
private _testDotProduct = (vectorNormalized (velocity _seeker)) vectorDotProduct _testPointVector;
if(_testDotProduct < (cos _seekerMaxAngle)) exitWith {
false
TRACE_2("fov",acos _testDotProduct,_seekerMaxAngle);
if (_testDotProduct < (cos _seekerMaxAngle)) exitWith {
false
};
true
true

View File

@ -1,29 +1,40 @@
//#define DEBUG_MODE_FULL
/*
* Author: jaynus / nou, PabstMirror
* Do attack profile with a valid seeker target location
*
* Arguments:
* 0: Seeker Target PosASL <ARRAY>
* 1: Guidance Arg Array <ARRAY>
* 2: Seeker State <ARRAY>
*
* Return Value:
* Missile Aim PosASL <ARRAY>
*
* Example:
* [[1,2,3], [], []] call ace_missileguidance_fnc_doAttackProfile;
*
* Public: No
*/
// #define DEBUG_MODE_FULL
#include "script_component.hpp"
EXPLODE_7_PVT(((_this select 1) select 0),_shooter,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile);
private ["_testName", "_attackProfilePos", "_attackProfile", "_attackProfileName", "_attackProfilesCfg", "_i", "_launchParams", "_testame", "_testProfile"];
_launchParams = ((_this select 1) select 1);
_attackProfileName = _launchParams select 3;
params ["_seekerTargetPos", "_args"];
_args params ["", "_launchParams"];
_launchParams params ["", "", "", "_attackProfileName"];
TRACE_1("Attacking profile", _attackProfileName);
private _attackProfileFunction = getText (configFile >> QGVAR(AttackProfiles) >> _attackProfileName >> "functionName");
_attackProfilesCfg = ( configFile >> QGVAR(AttackProfiles) );
private _attackProfilePos = _this call (missionNamespace getVariable _attackProfileFunction);
_attackProfile = nil;
for [{_i=0}, {_i< (count _attackProfilesCfg) }, {_i=_i+1}] do {
_testProfile = _attackProfilesCfg select _i;
_testName = configName _testProfile;
TRACE_3("", _testName, _testProfile, _attackProfilesCfg);
if( _testName == _attackProfileName) exitWith {
_attackProfile = _attackProfilesCfg select _i;
};
if ((isNil "_attackProfilePos") || {(vectorMagnitude _attackProfilePos) == 0}) exitWith {
ERROR_1("attack profile returned bad pos",_attackProfilePos);
[0,0,0]
};
_attackProfilePos = [0,0,0];
if(!isNil "_attackProfile") then {
_attackProfilePos = _this call (missionNamespace getVariable (getText (_attackProfile >> "functionName")));
};
#ifdef DRAW_GUIDANCE_INFO
drawLine3D [(ASLtoAGL _attackProfilePos), (ASLtoAGL _seekerTargetPos), [0,1,1,1]];
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [0,0,1,1], ASLtoAGL _attackProfilePos, 0.5, 0.5, 0, _attackProfileName, 1, 0.025, "TahomaB"];
#endif
TRACE_2("return",_attackProfilePos,_attackProfileName);
_attackProfilePos;

View File

@ -1,4 +1,5 @@
// Not currently used
#include "script_component.hpp"
PARAMS_2(_target,_args);
[QGVAR(handoff), [_target, _args]] call CBA_fnc_globalEvent;
[QGVAR(handoff), [_target, _args]] call CBA_fnc_globalEvent;

View File

@ -1,30 +1,51 @@
//#define DEBUG_MODE_FULL
/*
* Author: jaynus / nou, PabstMirror
* Do seeker search
* Handles a nil/bad return and will attempt to use last known position if enabled on ammo
*
* Arguments:
* 1: Guidance Arg Array <ARRAY>
* 3: Last known pos state array <ARRAY>
*
* Return Value:
* Missile Aim PosASL <ARRAY>
*
* Example:
* [[], [], []] call ace_missileguidance_fnc_seekerType_Optic;
*
* Public: No
*/
// #define DEBUG_MODE_FULL
#include "script_component.hpp"
EXPLODE_7_PVT(((_this select 1) select 0),_shooter,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile);
private ["_seekerProfilePos", "_i", "_launchParams", "_seekerType", "_seekerTypeName", "_seekerTypesCfg", "_testName", "_testProfile"];
params ["", "_args", "", "_lastKnownPosState"];
_args params ["", "_launchParams"];
_launchParams params ["", "", "_seekerTypeName"];
_lastKnownPosState params ["_seekLastTargetPos", "_lastKnownPos"];
_launchParams = ((_this select 1) select 1);
_seekerTypeName = _launchParams select 2;
private _seekerFunction = getText (configFile >> QGVAR(SeekerTypes) >> _seekerTypeName >> "functionName");
TRACE_1("Seeker type", _seekerTypeName);
private _seekerTargetPos = _this call (missionNamespace getVariable _seekerFunction);
_seekerTypesCfg = ( configFile >> QGVAR(SeekerTypes) );
_seekerType = nil;
for [{_i = 0}, {_i< (count _seekerTypesCfg) }, {_i=_i + 1}] do {
_testProfile = _seekerTypesCfg select _i;
_testName = configName _testProfile;
TRACE_3("", _testName, _testProfile, _seekerTypesCfg);
if( _testName == _seekerTypeName) exitWith {
_seekerType = _seekerTypesCfg select _i;
if ((isNil "_seekerTargetPos") || {(vectorMagnitude _seekerTargetPos) == 0}) then {
// Seeker returned nil / bad pos
if (_seekLastTargetPos && {(vectorMagnitude _lastKnownPos) != 0}) then {
TRACE_2("seeker returned bad pos - using last known",_seekLastTargetPos,_lastKnownPos);
_seekerTargetPos = _lastKnownPos;
} else {
TRACE_1("seeker returned no pos",_seekerTargetPos);
_seekerTargetPos = [0,0,0];
};
} else {
if (_seekLastTargetPos) then {
TRACE_1("saving current pos",_seekLastTargetPos);
_lastKnownPosState set [1, _seekerTargetPos];
};
};
_seekerProfilePos = [0, 0, 0];
if(!isNil "_seekerType") then {
_seekerProfilePos = _this call (missionNamespace getVariable (getText (_seekerType >> "functionName")));
};
#ifdef DRAW_GUIDANCE_INFO
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [0,1,0,1], ASLtoAGL _seekerTargetPos, 0.5, 0.5, 0, _seekerTypeName, 1, 0.025, "TahomaB"];
#endif
_seekerProfilePos;
TRACE_2("return",_seekerTargetPos,_seekerTypeName);
_seekerTargetPos;

View File

@ -1,33 +1,41 @@
//#define DEBUG_MODE_FULL
/*
* Author: jaynus / nou
* Guidance Per Frame Handler
*
* Arguments:
* 0: Guidance Arg Array <ARRAY>
* 1: PFID <NUMBER>
*
* Return Value:
* Nothing
*
* Example:
* [[], 0] call ace_missileguidance_fnc_guidancePFH;
*
* Public: No
*/
// #define DEBUG_MODE_FULL
#include "script_component.hpp"
BEGIN_COUNTER(guidancePFH);
#define TIMESTEP_FACTOR 0.01
private ["_launchParams", "_targetLaunchParams", "_flightParams", "_seekerParams", "_stateParams"];
private ["_lastRunTime", "_runtimeDelta", "_adjustTime", "_args", "_seekerTargetPos", "_projectilePos"];
private ["_profileAdjustedTargetPos", "_incDeflection", "_minDeflection", "_maxDeflection"];
private ["_targetVector", "_adjustVector", "_finalAdjustVector", "_changeVector", "_pitch", "_yaw", "_roll"];
private ["_PS", "_distanceToTarget", "_targetRelativeVector", "_vectorTo"];
params ["_args", "_pfID"];
_args params ["_firedEH", "_launchParams", "_flightParams", "_seekerParams", "_stateParams"];
_firedEH params ["_shooter","","","","_ammo","","_projectile"];
_launchParams params ["","_targetLaunchParams"];
_stateParams params ["_lastRunTime", "_seekerStateParams", "_attackProfileStateParams", "_lastKnownPosState"];
_args = _this select 0;
EXPLODE_7_PVT((_args select 0),_shooter,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile);
if(!alive _projectile || isNull _projectile || isNull _shooter) exitWith {
[(_this select 1)] call CBA_fnc_removePerFrameHandler;
if (!alive _projectile || isNull _projectile || isNull _shooter) exitWith {
[_pfID] call CBA_fnc_removePerFrameHandler;
END_COUNTER(guidancePFH);
};
_launchParams = _args select 1;
_targetLaunchParams = _launchParams select 1;
_flightParams = _args select 2;
_seekerParams = _args select 3;
private _runtimeDelta = diag_tickTime - _lastRunTime;
private _adjustTime = 1;
_stateParams = _args select 4;
_lastRunTime = _stateParams select 0;
_runtimeDelta = diag_tickTime - _lastRunTime;
_adjustTime = 1;
if(accTime > 0) then {
if (accTime > 0) then {
_adjustTime = 1/accTime;
_adjustTime = _adjustTime * (_runtimeDelta / TIMESTEP_FACTOR);
TRACE_4("Adjust timing", 1/accTime, _adjustTime, _runtimeDelta, (_runtimeDelta / TIMESTEP_FACTOR) );
@ -35,72 +43,71 @@ if(accTime > 0) then {
_adjustTime = 0;
};
_minDeflection = ((_flightParams select 0) - ((_flightParams select 0) * _adjustTime)) max 0;
_maxDeflection = (_flightParams select 1) * _adjustTime;
_incDeflection = _flightParams select 2;
private _minDeflection = ((_flightParams select 0) - ((_flightParams select 0) * _adjustTime)) max 0;
private _maxDeflection = (_flightParams select 1) * _adjustTime;
// private _incDeflection = _flightParams select 2; // todo
_projectilePos = getPosASL _projectile;
private _projectilePos = getPosASL _projectile;
// @TODO: placeholder for "last seek target position"
// Last target pos should be optional based on the seeker unit
_seekerTargetPos = [ [0,0,0], _args, (_stateParams select 1)] call FUNC(doSeekerSearch);
if(isNil "_seekerTargetPos") then {
_seekerTargetPos = _seekerTargetPos vectorAdd ((velocity _projectile) vectorMultiply 5);
} else {
if( (vectorMagnitude _seekerTargetPos) == 0) then {
_seekerTargetPos = _seekerTargetPos vectorAdd ((velocity _projectile) vectorMultiply 5);
// Run seeker function:
private _seekerTargetPos = [[0,0,0], _args, _seekerStateParams, _lastKnownPosState] call FUNC(doSeekerSearch);
// If we have no seeker target, then do not change anything
if (!(_seekerTargetPos isEqualTo [0,0,0])) then {
// Run attack profile function:
private _profileAdjustedTargetPos = [_seekerTargetPos, _args, _attackProfileStateParams] call FUNC(doAttackProfile);
private _targetVector = _projectilePos vectorFromTo _profileAdjustedTargetPos;
private _adjustVector = _targetVector vectorDiff (vectorDir _projectile);
_adjustVector params ["_adjustVectorX", "_adjustVectorY", "_adjustVectorZ"];
private _yaw = 0;
private _pitch = 0;
private _roll = 0;
if (_adjustVectorX < 0) then {
_yaw = - ( (_minDeflection max ((abs _adjustVectorX) min _maxDeflection) ) );
} else {
if (_adjustVectorX > 0) then {
_yaw = ( (_minDeflection max (_adjustVectorX min _maxDeflection) ) );
};
};
if (_adjustVectorY < 0) then {
_roll = - ( (_minDeflection max ((abs _adjustVectorY) min _maxDeflection) ) );
} else {
if (_adjustVectorY > 0) then {
_roll = ( (_minDeflection max (_adjustVectorY min _maxDeflection) ) );
};
};
if (_adjustVectorZ < 0) then {
_pitch = - ( (_minDeflection max ((abs _adjustVectorZ) min _maxDeflection) ) );
} else {
if (_adjustVectorZ > 0) then {
_pitch = ( (_minDeflection max (_adjustVectorZ min _maxDeflection) ) );
};
};
private _finalAdjustVector = [_yaw, _roll, _pitch];
TRACE_3("", _pitch, _yaw, _roll);
TRACE_3("", _targetVector, _adjustVector, _finalAdjustVector);
if (accTime > 0) then {
private _changeVector = (vectorDir _projectile) vectorAdd _finalAdjustVector;
TRACE_2("",_projectile,_changeVector);
[_projectile, _changeVector] call FUNC(changeMissileDirection);
};
};
_profileAdjustedTargetPos = [_seekerTargetPos,_args, (_stateParams select 2)] call FUNC(doAttackProfile);
_targetVector = _projectilePos vectorFromTo _profileAdjustedTargetPos;
_adjustVector = _targetVector vectorDiff (vectorDir _projectile);
#ifdef DRAW_GUIDANCE_INFO
TRACE_3("",_projectilePos,_seekerTargetPos,_profileAdjustedTargetPos);
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [1,0,0,1], ASLtoAGL _projectilePos, 0.75, 0.75, 0, _ammo, 1, 0.025, "TahomaB"];
_yaw = 0;
_pitch = 0;
_roll = 0;
if((_adjustVector select 0) < 0) then {
_yaw = - ( (_minDeflection max (abs(_adjustVector select 0) min _maxDeflection) ) );
} else {
if((_adjustVector select 0) > 0) then {
_yaw = ( (_minDeflection max ((_adjustVector select 0) min _maxDeflection) ) );
};
};
if((_adjustVector select 1) < 0) then {
_roll = - ( (_minDeflection max (abs(_adjustVector select 1) min _maxDeflection) ) );
} else {
if((_adjustVector select 1) > 0) then {
_roll = ( (_minDeflection max ((_adjustVector select 1) min _maxDeflection) ) );
};
};
if((_adjustVector select 2) < 0) then {
_pitch = - ( (_minDeflection max (abs(_adjustVector select 2) min _maxDeflection) ) );
} else {
if((_adjustVector select 2) > 0) then {
_pitch = ( (_minDeflection max ((_adjustVector select 2) min _maxDeflection) ) );
};
};
_finalAdjustVector = [_yaw, _roll, _pitch];
TRACE_2("", _pitch, _yaw);
TRACE_4("", _targetVector, _targetRelativeVector, _adjustVector, _finalAdjustVector);
if(accTime > 0) then {
_changeVector = (vectorDir _projectile) vectorAdd _finalAdjustVector;
[_projectile, _changeVector] call FUNC(changeMissileDirection);
};
#ifdef DEBUG_MODE_FULL
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [1,1,1,1], ASLtoAGL _projectilePos, 0.75, 0.75, 0, str _vectorTo, 1, 0.025, "TahomaB"];
drawLine3D [ASLtoAGL _projectilePos, ASLtoAGL _profileAdjustedTargetPos, [1,0,0,1]];
_ps = "#particlesource" createVehicleLocal (ASLtoAGL _projectilePos);
private _ps = "#particlesource" createVehicleLocal (ASLtoAGL _projectilePos);
_PS setParticleParams [["\A3\Data_f\cl_basic", 8, 3, 1], "", "Billboard", 1, 3.0141, [0, 0, 2], [0, 0, 0], 1, 1.275, 1, 0, [1, 1], [[1, 0, 0, 1], [1, 0, 0, 1], [1, 0, 0, 1]], [1], 1, 0, "", "", nil];
_PS setDropInterval 3.0;
//hintSilent format["d: %1", _distanceToTarget];
#endif
_stateParams set[0, diag_tickTime];
_stateParams set [0, diag_tickTime];
_args set[4, _stateParams];
_this set[0, _args];
END_COUNTER(guidancePFH);

View File

@ -1,6 +1,7 @@
// Not currently used
#include "script_component.hpp"
PARAMS_2(_target,_args);
if(isNil "_target" || {isNull _target} || {!local _target} ) exitWith { false };
if (isNil "_target" || {isNull _target} || {!local _target} ) exitWith { false };
[FUNC(guidancePFH), 0, _args] call CBA_fnc_addPerFrameHandler;
[FUNC(guidancePFH), 0, _args] call CBA_fnc_addPerFrameHandler;

View File

@ -1,44 +1,58 @@
//#define DEBUG_MODE_FULL
/*
* Author: jaynus / nou
* Fired event handler, starts guidance if enabled for ammo
*
* Arguments:
* 0: Shooter (Man/Vehicle) <OBJECT>
* 4: Ammo <STRING>
* 6: Projectile <OBJECT>
*
* Return Value:
* Nothing
*
* Example:
* [player, "", "", "", "ACE_Javelin_FGM148", "", theMissile] call ace_missileguidance_fnc_onFired;
*
* Public: No
*/
// #define DEBUG_MODE_FULL
#include "script_component.hpp"
PARAMS_7(_shooter,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile);
// Bail if guidance is disabled
// Bail on locality of the projectile, it should be local to us
if(GVAR(enabled) < 1 || {!local _projectile} ) exitWith { false };
//Bail if shooter isn't player AND system not enabled for AI:
if( !isPlayer _shooter && { GVAR(enabled) < 2 } ) exitWith { false };
params ["_shooter","","","","_ammo","","_projectile"];
// Bail on not missile
if(! (_ammo isKindOf "MissileBase") ) exitWith { false };
if (!(_ammo isKindOf "MissileBase")) exitWith {};
private ["_config", "_configs", "_enabled", "_target", "_seekerType", "_attackProfile"];
private ["_args", "_canUseLock", "_guidingUnit", "_launchPos", "_lockMode", "_targetPos", "_vanillaTarget"];
// Bail if guidance is disabled for this ammo
if ((getNumber (configFile >> "CfgAmmo" >> _ammo >> QUOTE(ADDON) >> "enabled")) != 1) exitWith {};
//Verify ammo has explicity added guidance config (ignore inheritances)
_configs = configProperties [(configFile >> "CfgAmmo" >> _ammo), QUOTE(configName _x == QUOTE(QUOTE(ADDON))), false];
if( (count _configs) < 1) exitWith {};
// Bail on locality of the projectile, it should be local to us
if (GVAR(enabled) < 1 || {!local _projectile} ) exitWith {};
_config = (configFile >> "CfgAmmo" >> _ammo >> QUOTE(ADDON));
_enabled = getNumber ( _config >> "enabled");
// Bail if shooter isn't player AND system not enabled for AI:
if ( !isPlayer _shooter && { GVAR(enabled) < 2 } ) exitWith {};
// Bail if guidance is not enabled
if(isNil "_enabled" || {_enabled != 1}) exitWith { false };
// Verify ammo has explicity added guidance config (ignore inheritances)
private _configs = configProperties [(configFile >> "CfgAmmo" >> _ammo), QUOTE(configName _x == QUOTE(QUOTE(ADDON))), false];
if ((count _configs) < 1) exitWith {};
_target = (vehicle _shooter) getVariable [QGVAR(target), nil];
_targetPos = (vehicle _shooter) getVariable [QGVAR(targetPosition), nil];
_seekerType = (vehicle _shooter) getVariable [QGVAR(seekerType), nil];
_attackProfile = (vehicle _shooter) getVariable [QGVAR(attackProfile), nil];
_lockMode = (vehicle _shooter) getVariable [QGVAR(lockMode), nil];
// MissileGuidance is enabled for this shot
TRACE_4("enabled",_shooter,_ammo,_projectile,typeOf _shooter);
// @TODO: make this vehicle shooter, but we need to differentiate where its set in ace_laser
_laserCode = _shooter getVariable [QEGVAR(laser,code), ACE_DEFAULT_LASER_CODE];
_laserInfo = [_laserCode, ACE_DEFAULT_LASER_WAVELENGTH, ACE_DEFAULT_LASER_WAVELENGTH];
private _config = configFile >> "CfgAmmo" >> _ammo >> QUOTE(ADDON);
_launchPos = getPosASL (vehicle _shooter);
private _target = _shooter getVariable [QGVAR(target), nil];
private _targetPos = _shooter getVariable [QGVAR(targetPosition), nil];
private _seekerType = _shooter getVariable [QGVAR(seekerType), nil];
private _attackProfile = _shooter getVariable [QGVAR(attackProfile), nil];
private _lockMode = _shooter getVariable [QGVAR(lockMode), nil];
TRACE_3("Begin guidance", _target, _seekerType, _attackProfile);
private _laserCode = _shooter getVariable [QEGVAR(laser,code), ACE_DEFAULT_LASER_CODE];
private _laserInfo = [_laserCode, ACE_DEFAULT_LASER_WAVELENGTH, ACE_DEFAULT_LASER_WAVELENGTH];
TRACE_6("getVars",_target,_targetPos,_seekerType,_attackProfile,_lockMode,_laserCode);
private _launchPos = getPosASL (vehicle _shooter);
if (isNil "_seekerType" || {!(_seekerType in (getArray (_config >> "seekerTypes")))}) then {
_seekerType = getText (_config >> "defaultSeekerType");
@ -51,28 +65,37 @@ if (isNil "_lockMode" || {!(_lockMode in (getArray (_config >> "seekerLockModes"
};
// If we didn't get a target, try to fall back on tab locking
if(isNil "_target") then {
if(!isPlayer _shooter) then {
if (isNil "_target") then {
if (!isPlayer _shooter) then {
// This was an AI shot, lets still guide it on the AI target
_target = _shooter getVariable[QGVAR(vanilla_target), nil];
_target = _shooter getVariable [QGVAR(vanilla_target), nil];
TRACE_1("Detected AI Shooter!", _target);
} else {
_canUseLock = getNumber (_config >> "canVanillaLock");
private _canUseLock = getNumber (_config >> "canVanillaLock");
// @TODO: Get vanilla target
if(_canUseLock > 0 || difficulty < 1) then {
_vanillaTarget = cursorTarget;
if (_canUseLock > 0 || difficulty < 1) then {
private _vanillaTarget = cursorTarget;
TRACE_1("Using Vanilla Locking", _vanillaTarget);
if(!isNil "_vanillaTarget") then {
if (!isNil "_vanillaTarget") then {
_target = _vanillaTarget;
};
};
};
};
// Array for seek last target position
private _seekLastTargetPos = (getNumber ( _config >> "seekLastTargetPos")) == 1;
private _lastKnownPosState = [_seekLastTargetPos];
if (_seekLastTargetPos && {!isNil "_target"}) then {
_lastKnownPosState set [1, (getPosASL _target)];
} else {
_lastKnownPosState set [1, [0,0,0]];
};
TRACE_4("Beginning ACE guidance system",_target,_ammo,_seekerType,_attackProfile);
_args = [_this,
[_shooter,
private _args = [_this,
[ _shooter,
[_target, _targetPos, _launchPos],
_seekerType,
_attackProfile,
@ -89,30 +112,41 @@ _args = [_this,
getNumber ( _config >> "seekerAccuracy" ),
getNumber ( _config >> "seekerMaxRange" )
],
[ diag_tickTime, [], [] ]
[ diag_tickTime, [], [], _lastKnownPosState]
];
// Reverse:
// _args params ["_firedEH", "_launchParams", "_flightParams", "_seekerParams", "_stateParams"];
// _firedEH params ["_shooter","","","","_ammo","","_projectile"];
// _launchParams params ["_shooter","_targetLaunchParams","_seekerType","_attackProfile","_lockMode","_laserInfo"];
// _targetLaunchParams params ["_target", "_targetPos", "_launchPos"];
// _stateParams params ["_lastRunTime", "_seekerStateParams", "_attackProfileStateParams", "_lastKnownPosState"];
// _seekerParams params ["_seekerAngle", "_seekerAccuracy", "_seekerMaxRange"];
// Hand off to the guiding unit. We just use local player so local PFH fires for now
// Laser code needs to give us a shooter for LOBL, or the seeker unit needs to be able to shift locality
// Based on its homing laser
// Lasers need to be handled in a special LOAL/LOBL case
//if(isPlayer _shooter) then {
// _guidingUnit = ACE_player;
//if (isPlayer _shooter) then {
// private _guidingUnit = ACE_player;
//
// if(local _guidingUnit) then {
// if (local _guidingUnit) then {
// [FUNC(guidancePFH), 0, _args ] call CBA_fnc_addPerFrameHandler;
// } else {
// [QGVAR(handoff), [_guidingUnit, _args] ] call FUNC(doHandoff);
// };
//} else {
[FUNC(guidancePFH), 0, _args ] call CBA_fnc_addPerFrameHandler;
// [FUNC(guidancePFH), 0, _args ] call CBA_fnc_addPerFrameHandler;
//};
[FUNC(guidancePFH), 0, _args ] call CBA_fnc_addPerFrameHandler;
/* Clears locking settings
(vehicle _shooter) setVariable [QGVAR(target), nil];
(vehicle _shooter) setVariable [QGVAR(seekerType), nil];
(vehicle _shooter) setVariable [QGVAR(attackProfile), nil];
(vehicle _shooter) setVariable [QGVAR(lockMode), nil];
*/
*/

View File

@ -1,8 +1,27 @@
//#define DEBUG_MODE_FULL
/*
* Author: jaynus / nou
* Handles AI shooting a locking missile
*
* Arguments:
* 0: Target <OBJECT>
* 1: Ammo <STRING>
* 2: Shooter <OBJECT>
*
* Return Value:
* None
*
* Example:
* [cursorTarget, "x", player] call ace_missileguidance_fnc_changeMissileDirection;
*
* Public: No
*/
// #define DEBUG_MODE_FULL
#include "script_component.hpp"
PARAMS_3(_target,_ammo,_shooter);
if(GVAR(enabled) < 1) exitWith {}; // bail if enabled
params ["_target", "_ammo", "_shooter"];
if (GVAR(enabled) < 1) exitWith {}; // bail if enabled
if !(local (gunner _shooter) || {local _shooter}) exitWith {}; // bail if not shooter
_shooter setVariable [QGVAR(vanilla_target),_target, false];
_shooter setVariable [QGVAR(vanilla_target),_target, false];
TRACE_2("setting vanilla target",_shooter,_target);

View File

@ -1,39 +0,0 @@
#include "script_component.hpp"
private ["_d", "_map", "_p", "_theta", "_u"];
_map = _this select 0;
_theta = _this select 1;
_p = _map select 0;
_p1 = _map select 1;
_p2 = _map select 2;
_q1 = +(_map select 3);
_q2 = +(_map select 4);
_u = _map select 5;
_d = _map select 6;
/* Step 4 */
_q2 set[0, (_q1 select 0) * cos(_theta) - (_q1 select 1) * sin(_theta)];
_q2 set[1, (_q1 select 0) * sin(_theta) + (_q1 select 1) * cos(_theta)];
_q2 set[2, (_q1 select 2)];
/* Inverse of step 3 */
_q1 set[0, (_q2 select 0) * _d + (_q2 select 2) * (_u select 0)];
_q1 set[1, (_q2 select 1)];
_q1 set[2, - (_q2 select 0) * (_u select 0) + (_q2 select 2) * _d];
/* Inverse of step 2 */
if (_d != 0) then {
_q2 set[0, (_q1 select 0)];
_q2 set[1, (_q1 select 1) * (_u select 2) / _d + (_q1 select 2) * (_u select 1) / _d];
_q2 set[2, - (_q1 select 1) * (_u select 1) / _d + (_q1 select 2) * (_u select 2) / _d];
} else {
_q2 = _q1;
};
/* Inverse of step 1 */
_q1 set[0, (_q2 select 0) + (_p1 select 0)];
_q1 set[1, (_q2 select 1) + (_p1 select 1)];
_q1 set[2, (_q2 select 2) + (_p1 select 2)];
_q1;

View File

@ -1,37 +0,0 @@
#include "script_component.hpp"
private ["_p", "_theta", "_p1", "_p2", "_q1", "_q2", "_u", "_d"];
_p = _this select 0;
_p1 = _this select 1;
_p2 = _this select 2;
_q1 = [];
_q2 = [];
_u = [];
/* Step 1 */
_q1 set[0, (_p select 0) - (_p1 select 0)];
_q1 set[1, (_p select 1) - (_p1 select 1)];
_q1 set[2, (_p select 2) - (_p1 select 2)];
_u set[0, (_p2 select 0) - (_p1 select 0)];
_u set[1, (_p2 select 1) - (_p1 select 1)];
_u set[2, (_p2 select 2) - (_p1 select 2)];
_u = _u call BIS_fnc_unitVector;
_d = sqrt((_u select 1)*(_u select 1) + (_u select 2)*(_u select 2));
/* Step 2 */
if (_d != 0) then {
_q2 set[0, (_q1 select 0)];
_q2 set[1, (_q1 select 1) * (_u select 2) / _d - (_q1 select 2) * (_u select 1) / _d];
_q2 set[2, (_q1 select 1) * (_u select 1) / _d + (_q1 select 2) * (_u select 2) / _d];
} else {
_q2 = _q1;
};
/* Step 3 */
_q1 set[0, (_q2 select 0) * _d - (_q2 select 2) * (_u select 0)];
_q1 set[1, (_q2 select 1)];
_q1 set[2, (_q2 select 0) * (_u select 0) + (_q2 select 2) * _d];
[_p, _p1, _p2, _q1, _q2, _u, _d]

View File

@ -1,52 +1,54 @@
//#define DEBUG_MODE_FULL
/*
* Author: jaynus / nou
* Seeker Type: Optic
*
* Arguments:
* 1: Guidance Arg Array <ARRAY>
* 2: Seeker State <ARRAY>
*
* Return Value:
* Missile Aim PosASL <ARRAY>
*
* Example:
* [[], [], []] call ace_missileguidance_fnc_seekerType_Optic;
*
* Public: No
*/
// #define DEBUG_MODE_FULL
#include "script_component.hpp"
EXPLODE_7_PVT(((_this select 1) select 0),_shooter,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile);
private ["_targets", "_foundTargetPos", "_launchParams", "_seekerParams", "_targetLaunchParams"];
private ["_angleFov", "_angleOkay", "_losOkay", "_seekerTargetPos", "_sensorPos", "_target"];
params ["", "_args"];
_args params ["_firedEH", "_launchParams", "", "_seekerParams", "_stateParams"];
_firedEH params ["","","","","","","_projectile"];
_launchParams params ["", "_targetParams"];
_targetParams params ["_target"];
_seekerParams params ["_seekerAngle", "", "_seekerMaxRange"];
_seekerTargetPos = _this select 0;
if (isNil "_target") exitWith {[0,0,0]};
_launchParams = _this select 1;
_target = (((_launchParams select 1) select 1) select 0);
_seekerParams = _launchParams select 3;
TRACE_1("", _this);
TRACE_1("", _launchParams);
// TODO:: Make sure the missile maintains LOS
_foundTargetPos = [0,0,0];
if(!isNil "_target") then {
_foundTargetPos = aimPos _target ;
//_foundTargetPos = (_target modelToWorldVisual (getCenterOfMass _target));
};
private _foundTargetPos = aimPos _target;
// @TODO: This is seeker LOS and angle checks for LOAL only; LOBL does not need visual
_angleFov = _seekerParams select 0;
_angleOkay = [_projectile, _foundTargetPos, _angleFov] call FUNC(checkSeekerAngle);
private _angleOkay = [_projectile, _foundTargetPos, _seekerAngle] call FUNC(checkSeekerAngle);
_losOkay = false;
if(_angleOkay) then {
private _losOkay = false;
if (_angleOkay) then {
_losOkay = [_projectile, _target] call FUNC(checkLos);
};
TRACE_2("", _angleOkay, _losOkay);
// If we got here, it was an invalid target, just return a spot 5m in front of the missile
if(!_angleOkay || !_losOkay) then {
_foundTargetPos = _sensorPos vectorAdd ((velocity _projectile) vectorMultiply 5);
} else {
TRACE_2("", _target, _foundTargetPos);
private ["_projectileSpeed", "_distanceToTarget", "_eta", "_adjustDistance"];
// @TODO: Configurable lead for seekers
_projectileSpeed = (vectorMagnitude velocity _projectile);
_distanceToTarget = (getPosASL _projectile) vectorDistance _foundTargetPos;
// Can't see target, return [0,0,0] and let doSeekerSearch handle it
if (!_angleOkay || !_losOkay) exitWith {[0,0,0]};
_eta = _distanceToTarget / _projectileSpeed;
TRACE_2("", _target, _foundTargetPos);
// @TODO: Configurable lead for seekers
private _projectileSpeed = (vectorMagnitude velocity _projectile);
private _distanceToTarget = (getPosASL _projectile) vectorDistance _foundTargetPos;
private _eta = _distanceToTarget / _projectileSpeed;
_adjustDistance = (velocity _target) vectorMultiply _eta;
TRACE_3("leading target",_distanceToTarget,_eta,_adjustDistance);
_foundTargetPos = _foundTargetPos vectorAdd _adjustDistance;
};
private _adjustDistance = (velocity _target) vectorMultiply _eta;
TRACE_3("leading target",_distanceToTarget,_eta,_adjustDistance);
_foundTargetPos = _foundTargetPos vectorAdd _adjustDistance;
TRACE_2("return",_foundTargetPos,(aimPos _target) distance _foundTargetPos);
_foundTargetPos;

View File

@ -1,32 +1,33 @@
/*
* Author: jaynus / nou
* Seeker Type: SALH (Laser)
* Wrapper for ace_laser_fnc_seekerFindLaserSpot
*
* Arguments:
* 1: Guidance Arg Array <ARRAY>
* 2: Seeker State <ARRAY>
*
* Return Value:
* Missile Aim PosASL <ARRAY>
*
* Example:
* [[], [], []] call ace_missileguidance_fnc_seekerType_SALH;
*
* Public: No
*/
// #define DEBUG_MODE_FULL
#include "script_component.hpp"
params ["_lastSeekTargetPos", "_args"];
_args params ["_firedEH", "_launchParams", "_flightParams", "_seekerParams", "_stateParams"];
_firedEH params ["_shooter","_weapon","_muzzle","_mode","_ammo","_magazine","_projectile"];
params ["", "_args"];
_args params ["_firedEH", "_launchParams", "", "_seekerParams"];
_firedEH params ["","","","","","","_projectile"];
_launchParams params ["","","","","","_laserParams"];
_seekerParams params ["_seekerAngle", "", "_seekerMaxRange"];
_laserParams params ["_code", "_wavelengthMin", "_wavelengthMax"];
private "_foundTargetPos";
if (!isNil "_target") then {
// Handle AI or moving vanilla lasers
_foundTargetPos = getPosASL _target;
} else {
private _laserResult = [(getPosASL _projectile), (velocity _projectile), _seekerAngle, [_wavelengthMin, _wavelengthMax], _code, _projectile] call EFUNC(laser,seekerFindLaserSpot);
_foundTargetPos = _laserResult select 0;
TRACE_1("Search", _laserResult);
};
if(!isNil "_foundTargetPos") then {
// Fov is already checked by laser func, check if distance
private _canSeeTarget = _seekerMaxRange >= (_foundTargetPos vectorDistance (getPosASL _projectile));
// If we got here, it was an invalid target, just return a spot 5m in front of the missile
if(!_canSeeTarget) then {
_foundTargetPos = _sensorPos vectorAdd ((velocity _projectile) vectorMultiply 5);
};
};
private _laserResult = [(getPosASL _projectile), (velocity _projectile), _seekerAngle, _seekerMaxRange, [_wavelengthMin, _wavelengthMax], _code, _projectile] call EFUNC(laser,seekerFindLaserSpot);
private _foundTargetPos = _laserResult select 0;
TRACE_1("Search", _laserResult);
_foundTargetPos;

View File

@ -2,6 +2,7 @@
#define COMPONENT_BEAUTIFIED Missile Guidance
#include "\z\ace\addons\main\script_mod.hpp"
// #define DRAW_GUIDANCE_INFO
// #define DEBUG_MODE_FULL
// #define DISABLE_COMPILE_CACHE
// #define ENABLE_PERFORMANCE_COUNTERS
@ -15,5 +16,3 @@
#endif
#include "\z\ace\addons\main\script_macros.hpp"
#define FIREMODE_DIRECT_LOAL 1