mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
NLAW - Predicted Line Of Sight Guidance and Overfly Attack Mode (#4791)
* NLAW Prototype * Make AI Compatible * Add Overfly Top Attack Mode * Limit Max Deflection * Base prediction on AI skill * Generic cycle attack profile key for missile guidance * Add hint for weapons without huds * Configure for attack cycle key * Finish OTA ammo effects * Cleanup * Arm at 20m * Disable Debug * No models for short lived sub-ammos * Fix Korean strings * Change AI randomization to use skillFinal * Add wiki doc for nlaw * Cleanup * Cleanup * Cleanup
This commit is contained in:
parent
4872e186cd
commit
49374feb2a
@ -5,6 +5,7 @@ class CfgWeapons {
|
|||||||
magazines[] = {"ACE_PreloadedMissileDummy"}; // The dummy magazine
|
magazines[] = {"ACE_PreloadedMissileDummy"}; // The dummy magazine
|
||||||
};
|
};
|
||||||
class ACE_launch_NLAW_Used_F: launch_NLAW_F { // the used tube should be a sub class of the disposable launcher
|
class ACE_launch_NLAW_Used_F: launch_NLAW_F { // the used tube should be a sub class of the disposable launcher
|
||||||
|
EGVAR(nlaw,enabled) = 0; // disable guidance for the disposabled tube
|
||||||
scope = 1;
|
scope = 1;
|
||||||
ACE_isUsedLauncher = 1;
|
ACE_isUsedLauncher = 1;
|
||||||
author = ECSTRING(common,ACETeam);
|
author = ECSTRING(common,ACETeam);
|
||||||
|
@ -115,6 +115,15 @@ private _args = [_this,
|
|||||||
[ diag_tickTime, [], [], _lastKnownPosState]
|
[ diag_tickTime, [], [], _lastKnownPosState]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
// Run the "onFired" function passing the full guidance args array
|
||||||
|
private _onFiredFunc = getText (_config >> "onFired");
|
||||||
|
TRACE_1("",_onFiredFunc);
|
||||||
|
if (_onFiredFunc != "") then {
|
||||||
|
_args call (missionNamespace getVariable _onFiredFunc);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Reverse:
|
// Reverse:
|
||||||
// _args params ["_firedEH", "_launchParams", "_flightParams", "_seekerParams", "_stateParams"];
|
// _args params ["_firedEH", "_launchParams", "_flightParams", "_seekerParams", "_stateParams"];
|
||||||
// _firedEH params ["_shooter","","","","_ammo","","_projectile"];
|
// _firedEH params ["_shooter","","","","_ammo","","_projectile"];
|
||||||
|
1
addons/nlaw/$PBOPREFIX$
Normal file
1
addons/nlaw/$PBOPREFIX$
Normal file
@ -0,0 +1 @@
|
|||||||
|
z\ace\addons\nlaw
|
14
addons/nlaw/ACE_GuidanceConfig.hpp
Normal file
14
addons/nlaw/ACE_GuidanceConfig.hpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
class EGVAR(missileguidance,AttackProfiles) {
|
||||||
|
class GVAR(directAttack) {
|
||||||
|
name = CSTRING(directAttack);
|
||||||
|
functionName = QFUNC(attackProfile);
|
||||||
|
};
|
||||||
|
class GVAR(overflyTopAttack): GVAR(directAttack) {
|
||||||
|
name = CSTRING(overflyTopAttack);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
class EGVAR(missileguidance,SeekerTypes) {
|
||||||
|
class GVAR(seeker) {
|
||||||
|
functionName = QFUNC(seeker);
|
||||||
|
};
|
||||||
|
};
|
55
addons/nlaw/CfgAmmo.hpp
Normal file
55
addons/nlaw/CfgAmmo.hpp
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
class CfgAmmo {
|
||||||
|
class M_NLAW_AT_F;
|
||||||
|
class ACE_NLAW: M_NLAW_AT_F {
|
||||||
|
hit = 400; // Default was 500
|
||||||
|
indirectHit = 20; // Default was 15
|
||||||
|
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.
|
||||||
|
|
||||||
|
canVanillaLock = 0; // Can this default vanilla lock? Only applicable to non-cadet mode
|
||||||
|
|
||||||
|
// Guidance type for munitions
|
||||||
|
defaultSeekerType = QGVAR(seeker);
|
||||||
|
seekerTypes[] = {QGVAR(seeker)};
|
||||||
|
|
||||||
|
defaultSeekerLockMode = "LOBL";
|
||||||
|
seekerLockModes[] = {"LOBL"};
|
||||||
|
|
||||||
|
seekLastTargetPos = 0; // seek last target position [if seeker loses LOS of target, continue to last known pos]
|
||||||
|
seekerAngle = 45; // Angle in front of the missile which can be searched
|
||||||
|
seekerAccuracy = 1; // seeker accuracy multiplier
|
||||||
|
|
||||||
|
seekerMinRange = 0;
|
||||||
|
seekerMaxRange = 10; // Range from the missile which the seeker can visually search
|
||||||
|
|
||||||
|
// Attack profile type selection
|
||||||
|
defaultAttackProfile = QGVAR(directAttack);
|
||||||
|
attackProfiles[] = {QGVAR(directAttack), QGVAR(overflyTopAttack)};
|
||||||
|
showHintOnCycle = 1;
|
||||||
|
|
||||||
|
// Run once at fired event
|
||||||
|
onFired = QFUNC(onFired);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Sub ammos used in OTA mode (see fnc_seeker.sqf)
|
||||||
|
class ACE_NLAW_Explosion: ACE_NLAW { // Based on FCS-Airburst, will explode right away
|
||||||
|
timeToLive = 0;
|
||||||
|
model = "";
|
||||||
|
};
|
||||||
|
class ACE_NLAW_ShapedCharge: ACE_NLAW { // Shaped charge from rocket explosion, no effects
|
||||||
|
timeToLive = 1;
|
||||||
|
model = "";
|
||||||
|
hit = 750;
|
||||||
|
indirectHit = 0;
|
||||||
|
indirectHitRange = 0;
|
||||||
|
explosionSoundEffect = "";
|
||||||
|
explosionEffects = "";
|
||||||
|
CraterEffects = "";
|
||||||
|
muzzleEffect = "";
|
||||||
|
};
|
||||||
|
};
|
17
addons/nlaw/CfgEventhandlers.hpp
Normal file
17
addons/nlaw/CfgEventhandlers.hpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
class Extended_PreStart_EventHandlers {
|
||||||
|
class ADDON {
|
||||||
|
init = QUOTE(call COMPILE_FILE(XEH_preStart));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class Extended_PreInit_EventHandlers {
|
||||||
|
class ADDON {
|
||||||
|
init = QUOTE(call COMPILE_FILE(XEH_preInit));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class Extended_PostInit_EventHandlers {
|
||||||
|
class ADDON {
|
||||||
|
init = QUOTE(call COMPILE_FILE(XEH_postInit));
|
||||||
|
};
|
||||||
|
};
|
6
addons/nlaw/CfgMagazines.hpp
Normal file
6
addons/nlaw/CfgMagazines.hpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
class CfgMagazines {
|
||||||
|
class CA_LauncherMagazine;
|
||||||
|
class NLAW_F: CA_LauncherMagazine {
|
||||||
|
ammo = "ACE_NLAW";
|
||||||
|
};
|
||||||
|
};
|
13
addons/nlaw/CfgWeapons.hpp
Normal file
13
addons/nlaw/CfgWeapons.hpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
class CfgWeapons {
|
||||||
|
class Launcher_Base_F;
|
||||||
|
class launch_NLAW_F: Launcher_Base_F {
|
||||||
|
GVAR(enabled) = 1;
|
||||||
|
canLock = 1;
|
||||||
|
class OpticsModes {
|
||||||
|
class optic {
|
||||||
|
distanceZoomMin = 0;
|
||||||
|
distanceZoomMax = 0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
10
addons/nlaw/README.md
Normal file
10
addons/nlaw/README.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
ace_nlaw
|
||||||
|
===============
|
||||||
|
|
||||||
|
Adds Predicted Line Of Sight guidance to the NLAW.
|
||||||
|
|
||||||
|
## Maintainers
|
||||||
|
|
||||||
|
The people responsible for merging changes to this component or answering potential questions.
|
||||||
|
|
||||||
|
- [PabstMirror](https://github.com/PabstMirror)
|
6
addons/nlaw/XEH_PREP.hpp
Normal file
6
addons/nlaw/XEH_PREP.hpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
LOG("prep");
|
||||||
|
|
||||||
|
PREP(attackProfile);
|
||||||
|
PREP(keyDown);
|
||||||
|
PREP(onFired);
|
||||||
|
PREP(seeker);
|
46
addons/nlaw/XEH_postInit.sqf
Normal file
46
addons/nlaw/XEH_postInit.sqf
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
if (!hasInterface) exitWith {};
|
||||||
|
|
||||||
|
GVAR(isLockKeyDown) = false;
|
||||||
|
|
||||||
|
// Degrees per second
|
||||||
|
GVAR(yawChange) = 0;
|
||||||
|
GVAR(pitchChange) = 0;
|
||||||
|
|
||||||
|
// Add keybind
|
||||||
|
["ACE3 Weapons", QGVAR(trackTarget), localize LSTRING(trackTarget), {
|
||||||
|
call FUNC(keyDown);
|
||||||
|
false // Return false so it doesn't block the rest weapon action
|
||||||
|
}, {
|
||||||
|
TRACE_1("lock key up",GVAR(isLockKeyDown));
|
||||||
|
GVAR(isLockKeyDown) = false;
|
||||||
|
false
|
||||||
|
}, [15, [false, false, false]], false] call CBA_fnc_addKeybind; //Tab Key
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Visual debuging, idealy used with a moving vehicle called "testTarget"
|
||||||
|
#ifdef DRAW_NLAW_INFO
|
||||||
|
addMissionEventHandler ["Draw3d", {
|
||||||
|
// GREEN - Draw an object called "testTarget"'s aim pos and 1 sec aimpos predicted by velocity
|
||||||
|
if ((!isNil "testTarget") && {!isNull testTarget}) then {
|
||||||
|
{
|
||||||
|
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [0,1,0,1], ASLtoAGL ((aimPos testTarget) vectorAdd ((velocity testTarget) vectorMultiply _x)), 0.75, 0.75, 0, format ["%1", _x], 1, 0.025, "TahomaB"];
|
||||||
|
} forEach [0, 1, 2, 3];
|
||||||
|
};
|
||||||
|
|
||||||
|
// RED - If lock key is down, draw weapon dir and predicted path at various times
|
||||||
|
if (GVAR(yawChange) != 0) then {
|
||||||
|
{
|
||||||
|
private _viewASL = AGLtoASL positionCameraToWorld [0,0,0];
|
||||||
|
private _viewDir = ACE_player weaponDirection (currentWeapon ACE_player);
|
||||||
|
(_viewDir call CBA_fnc_vect2Polar) params ["", "_yaw", "_pitch"];
|
||||||
|
private _realYaw = _yaw + GVAR(yawChange) * _x;
|
||||||
|
private _realPitch = _pitch + GVAR(pitchChange) * _x;
|
||||||
|
private _returnTargetPos = _viewASL vectorAdd ([1000, _realYaw, _realPitch] call CBA_fnc_polar2vect);
|
||||||
|
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [1,0,0,1], ASLtoAGL _returnTargetPos, 0.75, 0.75, 0, format ["%1", _x], 1, 0.025, "TahomaB"];
|
||||||
|
} forEach [0, 1, 2, 3];
|
||||||
|
};
|
||||||
|
}];
|
||||||
|
#endif
|
9
addons/nlaw/XEH_preInit.sqf
Normal file
9
addons/nlaw/XEH_preInit.sqf
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
ADDON = false;
|
||||||
|
|
||||||
|
PREP_RECOMPILE_START;
|
||||||
|
#include "XEH_PREP.hpp"
|
||||||
|
PREP_RECOMPILE_END;
|
||||||
|
|
||||||
|
ADDON = true;
|
3
addons/nlaw/XEH_preStart.sqf
Normal file
3
addons/nlaw/XEH_preStart.sqf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
#include "XEH_PREP.hpp"
|
22
addons/nlaw/config.cpp
Normal file
22
addons/nlaw/config.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
class CfgPatches {
|
||||||
|
class ADDON {
|
||||||
|
name = COMPONENT_NAME;
|
||||||
|
units[] = {};
|
||||||
|
weapons[] = {};
|
||||||
|
requiredVersion = REQUIRED_VERSION;
|
||||||
|
requiredAddons[] = {"ace_missileguidance"};
|
||||||
|
author = ECSTRING(common,ACETeam);
|
||||||
|
url = ECSTRING(main,URL);
|
||||||
|
VERSION_CONFIG;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "CfgEventhandlers.hpp"
|
||||||
|
|
||||||
|
#include "CfgAmmo.hpp"
|
||||||
|
#include "CfgMagazines.hpp"
|
||||||
|
#include "CfgWeapons.hpp"
|
||||||
|
|
||||||
|
#include "ACE_GuidanceConfig.hpp"
|
60
addons/nlaw/functions/fnc_attackProfile.sqf
Normal file
60
addons/nlaw/functions/fnc_attackProfile.sqf
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Author: PabstMirror
|
||||||
|
* NLAW missile guidance attack profile.
|
||||||
|
*
|
||||||
|
* 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_nlaw_fnc_attackProfile
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
params ["_seekerTargetPos", "_args", "_attackProfileStateParams"];
|
||||||
|
_args params ["_firedEH", "_launchParams"];
|
||||||
|
_launchParams params ["","_targetLaunchParams", "", "_attackProfile"];
|
||||||
|
_targetLaunchParams params ["", "", "_launchPos"];
|
||||||
|
_firedEH params ["","","","","","","_projectile"];
|
||||||
|
|
||||||
|
// Use seeker (if terminal)
|
||||||
|
if (!(_seekerTargetPos isEqualTo [0,0,0])) exitWith {_seekerTargetPos};
|
||||||
|
|
||||||
|
_attackProfileStateParams params ["_startTime", "_startLOS", "_yawChange", "_pitchChange"];
|
||||||
|
(_startLOS call CBA_fnc_vect2Polar) params ["", "_yaw", "_pitch"];
|
||||||
|
|
||||||
|
private _projectilePos = getPosASL _projectile;
|
||||||
|
private _distanceFromLaunch = (_launchPos distance _projectilePos) + 10;
|
||||||
|
private _flightTime = CBA_missionTime - _startTime;
|
||||||
|
|
||||||
|
private _realYaw = _yaw + _yawChange * _flightTime;
|
||||||
|
private _realPitch = _pitch + _pitchChange * _flightTime;
|
||||||
|
|
||||||
|
private _returnTargetPos = _launchPos vectorAdd ([_distanceFromLaunch, _realYaw, _realPitch] call CBA_fnc_polar2vect);
|
||||||
|
|
||||||
|
if (_attackProfile == QGVAR(overflyTopAttack)) then { // Add 2m height in OTA attack mode
|
||||||
|
_returnTargetPos = _returnTargetPos vectorAdd [0,0,2];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef DRAW_NLAW_INFO
|
||||||
|
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [1,0,1,1], ASLtoAGL _launchPos, 0.75, 0.75, 0, "LAUNCH", 1, 0.025, "TahomaB"];
|
||||||
|
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [0,1,1,1], ASLtoAGL (_launchPos vectorAdd (_startLOS vectorMultiply (_distanceFromLaunch + 50))), 0.75, 0.75, 0, "Original LOS", 1, 0.025, "TahomaB"];
|
||||||
|
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [1,1,0,1], ASLtoAGL (_launchPos vectorAdd ([_distanceFromLaunch + 50, _realYaw, _realPitch] call CBA_fnc_polar2vect)), 0.75, 0.75, 0, format ["Predicted @%1sec",(floor(_flightTime * 10)/10)], 1, 0.025, "TahomaB"];
|
||||||
|
drawLine3D [ASLtoAGL _launchPos, ASLtoAGL (_launchPos vectorAdd (_startLOS vectorMultiply (_distanceFromLaunch + 50))), [1,0,0,1]];
|
||||||
|
drawLine3D [ASLtoAGL _launchPos, ASLtoAGL (_launchPos vectorAdd ([_distanceFromLaunch + 50, _realYaw, _realPitch] call CBA_fnc_polar2vect)), [1,1,0,1]];
|
||||||
|
private _test = lineIntersectsSurfaces [_launchPos, _launchPos vectorAdd (_startLOS vectorMultiply 3000), player, _projectile];
|
||||||
|
if ((count _test) > 0) then {
|
||||||
|
private _posAGL = ASLtoAGL ((_test select 0) select 0);
|
||||||
|
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [1,0,0,1], _posAGL, 0.75, 0.75, 0, "Original Impact", 1, 0.025, "TahomaB"];
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// TRACE_1("Adjusted target position", _returnTargetPos);
|
||||||
|
_returnTargetPos;
|
81
addons/nlaw/functions/fnc_keyDown.sqf
Normal file
81
addons/nlaw/functions/fnc_keyDown.sqf
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* Author: PabstMirror
|
||||||
|
* Handles the track key being held down.
|
||||||
|
* Tracks change in direction of weapon and computes angle change per second.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [] call ace_nlaw_fnc_keyDown
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
// #define DEBUG_MODE_FULL
|
||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
TRACE_1("lock key down",GVAR(isLockKeyDown));
|
||||||
|
|
||||||
|
if (!alive ACE_player) exitWith {};
|
||||||
|
if (!([ACE_player, objNull, ["isNotInside"]] call EFUNC(common,canInteractWith))) exitWith {};
|
||||||
|
if (!(ACE_player call CBA_fnc_canUseWeapon)) exitWith {};
|
||||||
|
if ((getNumber (configFile >> "CfgWeapons" >> (currentWeapon ACE_player) >> QGVAR(enabled))) == 0) exitWith {};
|
||||||
|
if (GVAR(isLockKeyDown)) exitWith {ERROR("already running?");};
|
||||||
|
|
||||||
|
GVAR(isLockKeyDown) = true;
|
||||||
|
playSound "ACE_Sound_Click";
|
||||||
|
|
||||||
|
// Get starting weapon dir
|
||||||
|
((ACE_player weaponDirection (currentWeapon ACE_player)) call CBA_fnc_vect2Polar) params ["", "_yaw", "_pitch"];
|
||||||
|
|
||||||
|
[{
|
||||||
|
params ["_args", "_pfID"];
|
||||||
|
_args params ["_lastTime", "_lastYaw", "_lastPitch", "_initPhase"];
|
||||||
|
|
||||||
|
if ((!alive ACE_player) ||
|
||||||
|
{!([ACE_player, objNull, ["isNotInside"]] call EFUNC(common,canInteractWith))} ||
|
||||||
|
{!GVAR(isLockKeyDown)} ||
|
||||||
|
{!(ACE_player call CBA_fnc_canUseWeapon)} ||
|
||||||
|
{(getNumber (configFile >> "CfgWeapons" >> (currentWeapon ACE_player) >> QGVAR(enabled))) == 0})
|
||||||
|
exitWith {
|
||||||
|
TRACE_1("ending track",_pfID);
|
||||||
|
[_pfID] call CBA_fnc_removePerFrameHandler;
|
||||||
|
playSound "ACE_Sound_Click";
|
||||||
|
|
||||||
|
[{ // reset gvars after a short delay
|
||||||
|
TRACE_1("reset vars",_this);
|
||||||
|
GVAR(yawChange) = 0;
|
||||||
|
GVAR(pitchChange) = 0;
|
||||||
|
}, [], 0.5] call CBA_fnc_waitAndExecute;
|
||||||
|
};
|
||||||
|
|
||||||
|
private _deltaT = CBA_missionTime - _lastTime;
|
||||||
|
if (_deltaT == 0) exitWith {};
|
||||||
|
if (_initPhase && {_deltaT < 0.75}) exitWith {};
|
||||||
|
|
||||||
|
((ACE_player weaponDirection (currentWeapon ACE_player)) call CBA_fnc_vect2Polar) params ["", "_yaw", "_pitch"];
|
||||||
|
private _yawChange = ([_yaw - _lastYaw] call CBA_fnc_simplifyAngle180) / _deltaT;
|
||||||
|
private _pitchChange = ([_pitch - _lastPitch] call CBA_fnc_simplifyAngle180) / _deltaT;
|
||||||
|
|
||||||
|
if (_initPhase) then { // initial value will use first 0.75 seconds of input
|
||||||
|
GVAR(yawChange) = _yawChange;
|
||||||
|
GVAR(pitchChange) = _pitchChange;
|
||||||
|
_args set [3, false];
|
||||||
|
} else {
|
||||||
|
// smoothing factor alpha - higher values will be more responsive to change, but also spike higher on jerky mouse movmeent
|
||||||
|
private _alpha = _deltaT / 3;
|
||||||
|
GVAR(yawChange) = (_yawChange * _alpha) + GVAR(yawChange) * (1 - _alpha);
|
||||||
|
GVAR(pitchChange) = (_pitchChange * _alpha) + GVAR(pitchChange) * (1 - _alpha);
|
||||||
|
};
|
||||||
|
|
||||||
|
_args set [0, CBA_missionTime];
|
||||||
|
_args set [1, _yaw];
|
||||||
|
_args set [2, _pitch];
|
||||||
|
|
||||||
|
#ifdef DEBUG_MODE_FULL
|
||||||
|
hintSilent format ["Instantaneous\nYaw: %1\n Pitch: %2\nGVAR\nYaw: %3\nPitch: %4", _yawChange, _pitchChange, GVAR(yawChange), GVAR(pitchChange)];
|
||||||
|
#endif
|
||||||
|
}, .25, [CBA_missionTime, _yaw, _pitch, true]] call CBA_fnc_addPerFrameHandler;
|
62
addons/nlaw/functions/fnc_onFired.sqf
Normal file
62
addons/nlaw/functions/fnc_onFired.sqf
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Author: PabstMirror
|
||||||
|
* Sets up missile guidance state arrays (called from missileGuidance's onFired).
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* Guidance Arg Array <ARRAY>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [] call ace_nlaw_fnc_onFired
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
params ["_firedEH", "_launchParams", "_flightParams", "_seekerParams", "_stateParams"];
|
||||||
|
_firedEH params ["_shooter","","","","","","_projectile"];
|
||||||
|
_launchParams params ["","_targetLaunchParams","","_attackProfile"];
|
||||||
|
_targetLaunchParams params ["_target"];
|
||||||
|
_stateParams params ["", "", "_attackProfileStateParams"];
|
||||||
|
|
||||||
|
// Reset _launchPos origin as projectile's height instead of player's foot
|
||||||
|
_targetLaunchParams set [2, getPosASL _projectile];
|
||||||
|
|
||||||
|
// Get state params:
|
||||||
|
TRACE_3("start of attack profile",_attackProfile,_shooter,vectorDir _projectile);
|
||||||
|
|
||||||
|
private _firedLOS = _shooter weaponDirection (currentWeapon _shooter);
|
||||||
|
private _yawChange = 0;
|
||||||
|
private _pitchChange = 0;
|
||||||
|
|
||||||
|
if (_shooter == ACE_player) then {
|
||||||
|
TRACE_2("isPlayer",GVAR(yawChange),GVAR(pitchChange));
|
||||||
|
_yawChange = GVAR(yawChange);
|
||||||
|
_pitchChange = GVAR(pitchChange);
|
||||||
|
TRACE_1("los check",_firedLOS call CBA_fnc_vect2Polar);
|
||||||
|
} else {
|
||||||
|
if ((!isNil "_target") && {!isNull _target}) then {
|
||||||
|
_firedLOS = (getPosASL _projectile) vectorFromTo (aimPos _target);
|
||||||
|
(((eyePos _shooter) vectorFromTo (aimPos _target)) call CBA_fnc_vect2Polar) params ["", "_startYaw", "_startPitch"];
|
||||||
|
// Add some random error to AI's velocity prediction:
|
||||||
|
private _random = random [(_shooter skillFinal "aimingAccuracy") min 0.9, 1, 2-((_shooter skillFinal "aimingAccuracy") min 0.9)];
|
||||||
|
(((eyePos _shooter) vectorFromTo ((aimPos _target) vectorAdd ((velocity _target) vectorMultiply (_random)))) call CBA_fnc_vect2Polar) params ["", "_predictedYaw", "_predictedPitch"];
|
||||||
|
_yawChange = ([_predictedYaw - _startYaw] call CBA_fnc_simplifyAngle180);
|
||||||
|
_pitchChange = ([_predictedPitch - _startPitch] call CBA_fnc_simplifyAngle180);
|
||||||
|
TRACE_1("AI",_target);
|
||||||
|
} else {
|
||||||
|
TRACE_1("AI - no target",_target);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Limit Max Deflection
|
||||||
|
_yawChange = -10 max _yawChange min 10;
|
||||||
|
_pitchChange = -10 max _pitchChange min 10;
|
||||||
|
|
||||||
|
TRACE_3("attackProfileStateParams",_firedLOS,_yawChange,_pitchChange);
|
||||||
|
_attackProfileStateParams set [0, CBA_missionTime];
|
||||||
|
_attackProfileStateParams set [1, _firedLOS];
|
||||||
|
_attackProfileStateParams set [2, _yawChange];
|
||||||
|
_attackProfileStateParams set [3, _pitchChange];
|
94
addons/nlaw/functions/fnc_seeker.sqf
Normal file
94
addons/nlaw/functions/fnc_seeker.sqf
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Author: PabstMirror
|
||||||
|
* Handles the top down attack seeker for missile guidance.
|
||||||
|
* Has a very short range (IR/Magnetic?) seeker that will trigger the shaped charge midair above the target.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* 1: Guidance Arg Array <ARRAY>
|
||||||
|
* 2: Seeker State <ARRAY>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* Seeker Pos <ARRAY>
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [] call ace_nlaw_fnc_seeker
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
// #define DEBUG_MODE_FULL
|
||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
params ["", "_args", "_seekerStateParams"];
|
||||||
|
_args params ["_firedEH", "_launchParams", "", "_seekerParams", "_stateParams"];
|
||||||
|
_firedEH params ["","","","","","","_projectile"];
|
||||||
|
_launchParams params ["", "_targetLaunchParams", "", "_attackProfile"];
|
||||||
|
_targetLaunchParams params ["", "", "_launchPos"];
|
||||||
|
|
||||||
|
if (_attackProfile == QGVAR(directAttack)) exitWith {[0,0,0]};
|
||||||
|
|
||||||
|
private _projPos = getPosASL _projectile;
|
||||||
|
|
||||||
|
// Arm seeker after 20 meters
|
||||||
|
if ((_projPos distance _launchPos) >= 20) then {
|
||||||
|
scopeName "targetScan";
|
||||||
|
BEGIN_COUNTER(targetScan);
|
||||||
|
|
||||||
|
if (_seekerStateParams isEqualTo []) then {
|
||||||
|
TRACE_2("Seeker Armed",_projPos distance _launchPos,diag_fps);
|
||||||
|
_seekerStateParams set [0, _projPos]; // Set _lastPos to current position
|
||||||
|
};
|
||||||
|
|
||||||
|
_seekerStateParams params ["_lastPos", "_terminal"];
|
||||||
|
if (_terminal) exitWith {};
|
||||||
|
|
||||||
|
private _vectorDir = _lastPos vectorFromTo _projPos;
|
||||||
|
private _frameDistance = _lastPos vectorDistance _projPos;
|
||||||
|
|
||||||
|
// Distance traveled depends on velocity and FPS - at 60fps it will be ~4m
|
||||||
|
// Step size will effect accuracy and performance costs
|
||||||
|
for "_stepSize" from 0 to _frameDistance step 0.5 do {
|
||||||
|
// This represents a position that the missile was at between the last frame and now
|
||||||
|
private _virtualPos = _lastPos vectorAdd (_vectorDir vectorMultiply _stepSize);
|
||||||
|
#ifdef DRAW_NLAW_INFO
|
||||||
|
drawLine3D [ASLtoAGL _virtualPos, ASLtoAGL (_virtualPos vectorAdd [0,0,-5]), [1,0,_stepSize/(_frameDistance max 0.1),1]];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Limit scan to 5 meters directly down (shaped charge jet has a very limited range)
|
||||||
|
private _res = lineIntersectsSurfaces [_virtualPos, (_virtualPos vectorAdd [0,0,-5]), _projectile];
|
||||||
|
if (!(_res isEqualTo [])) then {
|
||||||
|
(_res select 0) params ["_targetPos", "", "_target"];
|
||||||
|
if ((_target isKindOf "Tank") || {_target isKindOf "Car"} || {_target isKindOf "Air"}) exitWith {
|
||||||
|
TRACE_3("Firing shaped charge down",_target,_targetPos distance _virtualPos,_frameDistance);
|
||||||
|
TRACE_2("",_target worldToModel (ASLtoAGL _virtualPos),boundingBoxReal _target);
|
||||||
|
_virtualPos = _virtualPos vectorAdd (_vectorDir vectorMultiply 1.25);
|
||||||
|
|
||||||
|
deleteVehicle _projectile;
|
||||||
|
|
||||||
|
// Damage and effects of missile exploding (timeToLive is 0 so should happen next frame)
|
||||||
|
private _explosion = "ACE_NLAW_Explosion" createVehicle _virtualPos;
|
||||||
|
_explosion setPosASL _virtualPos;
|
||||||
|
|
||||||
|
// Just damage from shaped charge
|
||||||
|
private _shapedCharage = "ACE_NLAW_ShapedCharge" createVehicle _virtualPos;
|
||||||
|
_shapedCharage setPosASL _virtualPos;
|
||||||
|
_shapedCharage setVectorDirAndUp [[0,0,-1], [1,0,0]];
|
||||||
|
_shapedCharage setVelocity [0,0,-300];
|
||||||
|
|
||||||
|
_seekerStateParams set [1, true];
|
||||||
|
|
||||||
|
END_COUNTER(targetScan);
|
||||||
|
breakOut "targetScan";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
_seekerStateParams set [0, _projPos];
|
||||||
|
END_COUNTER(targetScan);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Exploded, return dummy value
|
||||||
|
if (_seekerStateParams param [1, false]) exitWith {
|
||||||
|
[0,0,1]
|
||||||
|
};
|
||||||
|
|
||||||
|
// return:
|
||||||
|
[0,0,0]
|
1
addons/nlaw/functions/script_component.hpp
Normal file
1
addons/nlaw/functions/script_component.hpp
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "\z\ace\addons\nlaw\script_component.hpp"
|
18
addons/nlaw/script_component.hpp
Normal file
18
addons/nlaw/script_component.hpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#define COMPONENT nlaw
|
||||||
|
#define COMPONENT_BEAUTIFIED NLAW
|
||||||
|
#include "\z\ace\addons\main\script_mod.hpp"
|
||||||
|
|
||||||
|
// #define DRAW_NLAW_INFO
|
||||||
|
// #define DEBUG_MODE_FULL
|
||||||
|
// #define DISABLE_COMPILE_CACHE
|
||||||
|
// #define ENABLE_PERFORMANCE_COUNTERS
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED_NLAW
|
||||||
|
#define DEBUG_MODE_FULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG_SETTINGS_NLAW
|
||||||
|
#define DEBUG_SETTINGS DEBUG_SETTINGS_NLAW
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "\z\ace\addons\main\script_macros.hpp"
|
14
addons/nlaw/stringtable.xml
Normal file
14
addons/nlaw/stringtable.xml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project name="ACE">
|
||||||
|
<Package name="NLAW">
|
||||||
|
<Key ID="STR_ACE_NLAW_trackTarget">
|
||||||
|
<English>NLAW Track Target (Hold)</English>
|
||||||
|
</Key>
|
||||||
|
<Key ID="STR_ACE_NLAW_directAttack">
|
||||||
|
<English>Direct Attack</English>
|
||||||
|
</Key>
|
||||||
|
<Key ID="STR_ACE_NLAW_overflyTopAttack">
|
||||||
|
<English>Overfly Top Attack</English>
|
||||||
|
</Key>
|
||||||
|
</Package>
|
||||||
|
</Project>
|
35
docs/wiki/feature/nlaw.md
Normal file
35
docs/wiki/feature/nlaw.md
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
layout: wiki
|
||||||
|
title: NLAW
|
||||||
|
description: NLAW
|
||||||
|
group: feature
|
||||||
|
category: equipment
|
||||||
|
parent: wiki
|
||||||
|
mod: ace
|
||||||
|
version:
|
||||||
|
major: 3
|
||||||
|
minor: 10
|
||||||
|
patch: 0
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Overview
|
||||||
|
|
||||||
|
### 1.1 Guidance
|
||||||
|
NLAW uses Predicted Line Of Sight guidance.
|
||||||
|
Before firing the shooter tracks the targets for several seconds.
|
||||||
|
This programs the missile with the angular rotation and allows it to fly a curved path that will hit the target.
|
||||||
|
It will also correct for gravity drop.
|
||||||
|
|
||||||
|
### 1.2 Attack profiles
|
||||||
|
- Direct - Normal impact fuze for non-armored targets. Note that the missile's shaped charge is aimed downards, so this mode is not recomended against armor.
|
||||||
|
- Overfly Top Attack - Flies high and when sensors detects a target below it triggers the shaped charge to fire downards into the weak top armor.
|
||||||
|
|
||||||
|
## 2. Usage
|
||||||
|
- Cycle attack profiles with the missile guidance "Cycle Fire Mode" keybind (default: <kbd>Ctrl</kbd> + <kbd>Tab</kbd>)
|
||||||
|
- Start tracking by pressing and holding the "NLAW Track Target" keybind (default: <kbd>Tab</kbd>)
|
||||||
|
- While holding the key down track the target for 2-3 seconds and fire.
|
||||||
|
- Can also be fired against static targets without tracking.
|
||||||
|
|
||||||
|
## 3. Dependencies
|
||||||
|
|
||||||
|
{% include dependencies_list.md component="nlaw" %}
|
Loading…
Reference in New Issue
Block a user