2023-09-12 18:58:10 +00:00
|
|
|
#include "..\script_component.hpp"
|
2016-10-12 22:35:24 +00:00
|
|
|
/*
|
|
|
|
* 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:
|
2017-06-08 13:31:51 +00:00
|
|
|
* None
|
2016-10-12 22:35:24 +00:00
|
|
|
*
|
|
|
|
* Example:
|
|
|
|
* [player, "", "", "", "ACE_Javelin_FGM148", "", theMissile] call ace_missileguidance_fnc_onFired;
|
|
|
|
*
|
|
|
|
* Public: No
|
|
|
|
*/
|
2016-05-30 16:37:03 +00:00
|
|
|
|
2019-01-31 04:11:01 +00:00
|
|
|
params ["_shooter","_weapon","","_mode","_ammo","","_projectile"];
|
2016-05-30 16:37:03 +00:00
|
|
|
|
2016-10-12 22:35:24 +00:00
|
|
|
// Bail if guidance is disabled for this ammo
|
|
|
|
if ((getNumber (configFile >> "CfgAmmo" >> _ammo >> QUOTE(ADDON) >> "enabled")) != 1) exitWith {};
|
2016-05-30 16:37:03 +00:00
|
|
|
|
2016-10-12 22:35:24 +00:00
|
|
|
// Bail on locality of the projectile, it should be local to us
|
|
|
|
if (GVAR(enabled) < 1 || {!local _projectile} ) exitWith {};
|
2016-05-30 16:37:03 +00:00
|
|
|
|
2016-10-12 22:35:24 +00:00
|
|
|
// Bail if shooter isn't player AND system not enabled for AI:
|
|
|
|
if ( !isPlayer _shooter && { GVAR(enabled) < 2 } ) exitWith {};
|
2016-05-30 16:37:03 +00:00
|
|
|
|
2016-10-12 22:35:24 +00:00
|
|
|
// 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 {};
|
2016-05-30 16:37:03 +00:00
|
|
|
|
2016-10-12 22:35:24 +00:00
|
|
|
// MissileGuidance is enabled for this shot
|
|
|
|
TRACE_4("enabled",_shooter,_ammo,_projectile,typeOf _shooter);
|
2016-05-30 16:37:03 +00:00
|
|
|
|
2016-10-12 22:35:24 +00:00
|
|
|
private _config = configFile >> "CfgAmmo" >> _ammo >> QUOTE(ADDON);
|
2016-05-30 16:37:03 +00:00
|
|
|
|
2016-10-12 22:35:24 +00:00
|
|
|
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];
|
2024-08-23 14:21:31 +00:00
|
|
|
private _navigationType = _shooter getVariable [QGVAR(navigationType), nil];
|
2019-01-31 04:11:01 +00:00
|
|
|
if ((getNumber (configFile >> "CfgAmmo" >> _ammo >> QUOTE(ADDON) >> "useModeForAttackProfile")) == 1) then {
|
|
|
|
_attackProfile = getText (configFile >> "CfgWeapons" >> _weapon >> _mode >> QGVAR(attackProfile))
|
|
|
|
};
|
2016-10-12 22:35:24 +00:00
|
|
|
private _lockMode = _shooter getVariable [QGVAR(lockMode), nil];
|
2016-05-30 16:37:03 +00:00
|
|
|
|
2016-10-12 22:35:24 +00:00
|
|
|
private _laserCode = _shooter getVariable [QEGVAR(laser,code), ACE_DEFAULT_LASER_CODE];
|
|
|
|
private _laserInfo = [_laserCode, ACE_DEFAULT_LASER_WAVELENGTH, ACE_DEFAULT_LASER_WAVELENGTH];
|
2016-05-30 16:37:03 +00:00
|
|
|
|
2024-08-23 14:21:31 +00:00
|
|
|
TRACE_7("getVars",_target,_targetPos,_seekerType,_attackProfile,_lockMode,_laserCode,_navigationType);
|
2016-05-30 16:37:03 +00:00
|
|
|
|
2016-10-12 22:35:24 +00:00
|
|
|
private _launchPos = getPosASL (vehicle _shooter);
|
2016-05-30 16:37:03 +00:00
|
|
|
|
|
|
|
if (isNil "_seekerType" || {!(_seekerType in (getArray (_config >> "seekerTypes")))}) then {
|
|
|
|
_seekerType = getText (_config >> "defaultSeekerType");
|
|
|
|
};
|
|
|
|
if (isNil "_attackProfile" || {!(_attackProfile in (getArray (_config >> "attackProfiles")))}) then {
|
|
|
|
_attackProfile = getText (_config >> "defaultAttackProfile");
|
|
|
|
};
|
|
|
|
if (isNil "_lockMode" || {!(_lockMode in (getArray (_config >> "seekerLockModes")))}) then {
|
|
|
|
_lockMode = getText (_config >> "defaultSeekerLockMode");
|
|
|
|
};
|
2024-08-23 14:21:31 +00:00
|
|
|
if (isNil "_navigationType" || {!(_navigationType in (getArray (_config >> "navigationTypes")))}) then {
|
|
|
|
_navigationType = getText (_config >> "defaultNavigationType");
|
|
|
|
};
|
|
|
|
|
|
|
|
if (isNil "_navigationType" || _navigationType isEqualTo "") then {
|
|
|
|
// most missiles use ProNav by default
|
|
|
|
_navigationType = "ProportionalNavigation";
|
|
|
|
};
|
2016-05-30 16:37:03 +00:00
|
|
|
|
|
|
|
// If we didn't get a target, try to fall back on tab locking
|
2016-10-12 22:35:24 +00:00
|
|
|
if (isNil "_target") then {
|
|
|
|
if (!isPlayer _shooter) then {
|
2016-05-30 16:37:03 +00:00
|
|
|
// This was an AI shot, lets still guide it on the AI target
|
2016-10-12 22:35:24 +00:00
|
|
|
_target = _shooter getVariable [QGVAR(vanilla_target), nil];
|
2024-02-05 17:04:24 +00:00
|
|
|
TRACE_1("Detected AI Shooter!",_target);
|
2016-05-30 16:37:03 +00:00
|
|
|
} else {
|
2016-10-12 22:35:24 +00:00
|
|
|
private _canUseLock = getNumber (_config >> "canVanillaLock");
|
2016-05-30 16:37:03 +00:00
|
|
|
// @TODO: Get vanilla target
|
2016-10-12 22:35:24 +00:00
|
|
|
if (_canUseLock > 0 || difficulty < 1) then {
|
2024-08-23 14:21:31 +00:00
|
|
|
private _vanillaTarget = missileTarget _projectile;
|
2016-05-30 16:37:03 +00:00
|
|
|
|
2024-02-05 17:04:24 +00:00
|
|
|
TRACE_1("Using Vanilla Locking",_vanillaTarget);
|
2016-10-12 22:35:24 +00:00
|
|
|
if (!isNil "_vanillaTarget") then {
|
2016-05-30 16:37:03 +00:00
|
|
|
_target = _vanillaTarget;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
2024-08-23 14:21:31 +00:00
|
|
|
_targetPos = getPosASLVisual _target;
|
2016-05-30 16:37:03 +00:00
|
|
|
|
2016-10-12 22:35:24 +00:00
|
|
|
// 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]];
|
|
|
|
};
|
|
|
|
|
2024-08-23 14:21:31 +00:00
|
|
|
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;
|
|
|
|
private _bangBang = false;
|
|
|
|
if (isNumber (_config >> "pitchRate")) then {
|
|
|
|
_pitchRate = getNumber ( _config >> "pitchRate" );
|
|
|
|
_yawRate = getNumber ( _config >> "yawRate" );
|
|
|
|
_bangBang = (1 == getNumber (_config >> "bangBangGuidance"));
|
|
|
|
};
|
|
|
|
|
|
|
|
// How much this projectile likes to stay toward current velocity
|
|
|
|
private _stabilityCoefficient = getNumber (_config >> "stabilityCoefficient");
|
|
|
|
|
|
|
|
// show a light trail in flight
|
|
|
|
private _showTrail = (1 == getNumber (_config >> "showTrail"));
|
|
|
|
|
|
|
|
private _navigationStateSubclass = _config >> "navigationStates";
|
|
|
|
private _states = getArray (_navigationStateSubclass >> "states");
|
|
|
|
|
|
|
|
private _navigationStateData = [];
|
|
|
|
private _initialState = "";
|
|
|
|
|
|
|
|
if (_states isNotEqualTo []) then {
|
|
|
|
_initialState = _states select 0;
|
|
|
|
{
|
|
|
|
private _stateClass = _navigationStateSubclass >> _x;
|
|
|
|
_navigationStateData pushBack [
|
|
|
|
getText (_stateClass >> "transitionCondition"),
|
|
|
|
getText (_stateClass >> "navigationType"),
|
|
|
|
[]
|
|
|
|
];
|
|
|
|
} forEach _states;
|
|
|
|
};
|
|
|
|
|
|
|
|
private _initialRoll = getNumber (_config >> "initialRoll");
|
|
|
|
private _initialYaw = getNumber (_config >> "initialYaw");
|
|
|
|
private _initialPitch = getNumber (_config >> "initialPitch");
|
|
|
|
|
|
|
|
private _yawRollPitch = (vectorDir _projectile) call CBA_fnc_vect2Polar;
|
|
|
|
|
|
|
|
TRACE_5("Beginning ACE guidance system",_target,_ammo,_seekerType,_attackProfile,_navigationType);
|
2016-10-12 22:35:24 +00:00
|
|
|
private _args = [_this,
|
|
|
|
[ _shooter,
|
2024-08-23 14:21:31 +00:00
|
|
|
[_target, _targetPos, _launchPos, vectorDirVisual vehicle _shooter, CBA_missionTime],
|
2016-05-30 16:37:03 +00:00
|
|
|
_seekerType,
|
|
|
|
_attackProfile,
|
|
|
|
_lockMode,
|
2024-08-23 14:21:31 +00:00
|
|
|
_laserInfo,
|
|
|
|
_navigationType
|
2016-05-30 16:37:03 +00:00
|
|
|
],
|
|
|
|
[
|
2024-08-23 14:21:31 +00:00
|
|
|
_pitchRate,
|
|
|
|
_yawRate,
|
|
|
|
_bangBang,
|
|
|
|
_stabilityCoefficient,
|
|
|
|
_showTrail
|
2016-05-30 16:37:03 +00:00
|
|
|
],
|
|
|
|
[
|
|
|
|
getNumber ( _config >> "seekerAngle" ),
|
|
|
|
getNumber ( _config >> "seekerAccuracy" ),
|
2019-06-08 04:48:37 +00:00
|
|
|
getNumber ( _config >> "seekerMaxRange" ),
|
|
|
|
getNumber ( _config >> "seekerMinRange" )
|
2016-05-30 16:37:03 +00:00
|
|
|
],
|
2024-08-23 14:21:31 +00:00
|
|
|
[ diag_tickTime, [], [], _lastKnownPosState, _navigationParameters, [_initialYaw + (_yawRollPitch select 1), _initialRoll, _initialPitch + (_yawRollPitch select 2)]],
|
|
|
|
[
|
|
|
|
// target data from missile. Must be filled by seeker for navigation to work
|
|
|
|
[0, 0, 0], // direction to target
|
|
|
|
[0, 0, 0], // direction to attack profile
|
|
|
|
0, // range to target
|
|
|
|
[0, 0, 0], // target velocity
|
|
|
|
[0, 0, 0] // target acceleration
|
|
|
|
],
|
|
|
|
[0, _navigationStateData]
|
2016-05-30 16:37:03 +00:00
|
|
|
];
|
|
|
|
|
2019-06-08 04:48:37 +00:00
|
|
|
private _onFiredFunc = getText (configFile >> QGVAR(SeekerTypes) >> _seekerType >> "onFired");
|
2024-08-23 14:21:31 +00:00
|
|
|
TRACE_1("seeker on fired",_onFiredFunc);
|
2019-06-08 04:48:37 +00:00
|
|
|
if (_onFiredFunc != "") then {
|
|
|
|
_args call (missionNamespace getVariable _onFiredFunc);
|
|
|
|
};
|
2019-12-17 02:01:30 +00:00
|
|
|
|
2019-06-08 04:48:37 +00:00
|
|
|
_onFiredFunc = getText (configFile >> QGVAR(AttackProfiles) >> _attackProfile >> "onFired");
|
2024-08-23 14:21:31 +00:00
|
|
|
TRACE_1("attack on fired",_onFiredFunc);
|
2017-06-02 21:51:20 +00:00
|
|
|
if (_onFiredFunc != "") then {
|
|
|
|
_args call (missionNamespace getVariable _onFiredFunc);
|
|
|
|
};
|
2019-12-17 02:01:30 +00:00
|
|
|
|
2024-08-23 14:21:31 +00:00
|
|
|
if (_states isEqualTo []) then {
|
|
|
|
_onFiredFunc = getText (configFile >> QGVAR(NavigationTypes) >> _navigationType >> "onFired");
|
|
|
|
TRACE_1("navigation on fired",_onFiredFunc);
|
|
|
|
if (_onFiredFunc != "") then {
|
|
|
|
private _navState = (_args call (missionNamespace getVariable _onFiredFunc));
|
|
|
|
(_args select 4) set [4, _navState];
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
{
|
|
|
|
_onFiredFunc = getText (configFile >> QGVAR(NavigationTypes) >> _x >> "onFired");
|
|
|
|
TRACE_1("navigation on fired",_onFiredFunc);
|
|
|
|
if (_onFiredFunc != "") then {
|
|
|
|
private _navState = (_args call (missionNamespace getVariable _onFiredFunc));
|
|
|
|
(_navigationStateData select _forEachIndex) set [2, _navState];
|
|
|
|
};
|
|
|
|
} forEach getArray (_config >> "navigationTypes");
|
|
|
|
};
|
|
|
|
|
2019-06-08 04:48:37 +00:00
|
|
|
// Run the "onFired" function passing the full guidance args array
|
|
|
|
_onFiredFunc = getText (_config >> "onFired");
|
2024-08-23 14:21:31 +00:00
|
|
|
TRACE_1("general on fired",_onFiredFunc);
|
2019-06-08 04:48:37 +00:00
|
|
|
if (_onFiredFunc != "") then {
|
|
|
|
_args call (missionNamespace getVariable _onFiredFunc);
|
|
|
|
};
|
2019-12-17 02:01:30 +00:00
|
|
|
|
2016-10-12 22:35:24 +00:00
|
|
|
// Reverse:
|
2024-08-23 14:21:31 +00:00
|
|
|
// _args params ["_firedEH", "_launchParams", "_flightParams", "_seekerParams", "_stateParams", "_targetData", "_navigationStateData"];
|
2016-10-12 22:35:24 +00:00
|
|
|
// _firedEH params ["_shooter","","","","_ammo","","_projectile"];
|
2024-08-23 14:21:31 +00:00
|
|
|
// _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"];
|
2019-12-17 02:01:30 +00:00
|
|
|
// _seekerParams params ["_seekerAngle", "_seekerAccuracy", "_seekerMaxRange", "_seekerMinRange"];
|
2024-08-23 14:21:31 +00:00
|
|
|
// _targetData params ["_targetDirection", "_attackProfileDirection", "_targetRange", "_targetVelocity", "_targetAcceleration"];
|
|
|
|
|
|
|
|
[LINKFUNC(guidancePFH),0, _args ] call CBA_fnc_addPerFrameHandler;
|
2016-10-12 22:35:24 +00:00
|
|
|
|
2024-08-23 14:21:31 +00:00
|
|
|
if (GVAR(debug_enableMissileCamera)) then {
|
|
|
|
[_projectile] call FUNC(dev_ProjectileCamera);
|
|
|
|
};
|
2016-10-12 22:35:24 +00:00
|
|
|
|
2016-05-30 16:37:03 +00:00
|
|
|
|
|
|
|
/* 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];
|
2016-10-12 22:35:24 +00:00
|
|
|
*/
|