mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
Missileguidance -- rewrite to use real-world guidance principles, general refactor (#10019)
* update todo with list of weapons
* Add AIM-120 with ARH. Change AHR to not always seek all targets
* Implement some generic modes of flight
* implement augmented proportional navigation
* Add zero-effort miss. Seeker now feeds data to navigation
* Fix bug with ZEM
* remove placeholder
* Change out missile types to reflect navigation scheme they use IRL
* remove uneeded sets
* chane navigation profiles to go for attack direction instead of target
* multiple changes
* SALH: only update seeker pos if it within small error
* IR seeker and AIM-9M
* small tweaks
* more tweaks
* todo: fix nlaw
* update todo
* implement course state machine
* Improve radar simulation
* enable chaff decoy
* add config entries
* Implement optical mavericks
* Allow for debug info to be displayed via variable
* Change AIM-9 agility
* update dragon to not use new guidance
* Tweak flight parameters. Add R-77
* Add AIM-120A
* add ASRAAM
* add R-73/4
* Add all GBU-12s that exist for all planes
* update todo
* update todo for ground based weapons
* Add GPS selector dialog for GPS munitions
* add TOO TGP
* Add SDB and JDAM
* update todo
* fix gimbal lock via rotating with quaternions
* tweak JDAM guidance
* Better attack angle calculation. Does not get exactly right, but works for all cases.
Need to implement a PID controller navigation type to get a correct attack angle
* Fix SACLOS missiles
* Fix NLAW and PLOS
The missile pitches up due to initial angle stuff. I don't know if this is behaviour we want to fix or not?
* update todo
* update todo
* Add Vikhr ATGM
* Add long range SAMs
* fix SAM animations
* Add all ground based missiles. Tweak AIM-9 flare angle
* remove debugh print
* Fix Wiesel ATGM animation. Tweak SACLOS values
* Add action to get into jdam settings
* fix all script components
* Add paremter to allow weathervaning
Weapons usually tend toward the velocity vector due to aerodynamics - calculate side slip and use calculation to do this
* Add new navigation profile. Tweak javelin mid-course guidance
* Process all navigation onFired. Send the correct array to function
* fix missing semicolons
* Add hellfire mid course guidance
* Tweak hellfire attack profile
* change how IR seeker performs
The angle check is better now. Relative velocites guarenteed
* tabs -> spaces
* localise aim120
* localise aim9
* localise gbu
* fix IR tracker losing lock immediately due to being blocked by launcher
* localise manpad
* actually localise manpad
* localise maverick
* localise missile guidance
* localise sam
* localise sdb
* localise vikhr
* tabs -> spaces again
* init commit 9m14
* update stringtables so they are in titlecase
* crash on load
* perplexed
* fix game crashing on load
* Add joystick model
* Add realistic 9m14 behaviour
the 9m14 control joystick can attach 4 9m14 launchers at a time. Replicate that here
* add MCLOS guidance
* add the ability to see a light trail
* tweak HOT guidance params
* tweak metis guidance params
* tweak Vikhr guidance
* add trail to vikhr
* Add Iron Dome interceptor API
* Optimise iron dome
* Only launch if we are above a threshold angle
* add local event for mission makers
* change events to allow for any number of arguments
* avoid making un-needed calls to the server
* Update doppler seeker to allow the tracking and killing of projectiles
* Avoid overshooting target
* Add settings for various things
* Add missile hiding for malyutka
* init commit of cruise missile
* Various - Add missing units/weapons to cfgPatches (#8175)
* Various - Add missing units/weapons to cfgPatches
* Update config.cpp
* Documentation - Add Mikero binarization note (#8172)
* Bump is-svg from 4.2.1 to 4.3.1 in /docs/src (#8177)
Bumps [is-svg](https://github.com/sindresorhus/is-svg) from 4.2.1 to 4.3.1.
- [Release notes](https://github.com/sindresorhus/is-svg/releases)
- [Commits](https://github.com/sindresorhus/is-svg/compare/v4.2.1...v4.3.1)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Adjust "New issue" link to lead to template selection page (#8182)
We want people to choose a template when creating a new issue
* Update linguist settings (#8151)
* Typo in usage example (#8201)
* Mk6 Mortar - Fix README.md typo (#8205)
* Overhaul CSW docs (#8206)
* Medical - Add Alternative Survival Chance (#8192)
Co-authored-by: TyroneMF <TyroneMF@hotmail.com>
Co-authored-by: Filip Maciejewski <veteran29@users.noreply.github.com>
Co-authored-by: Kyle Mckay <5459452+kymckay@users.noreply.github.com>
* Fix make.py temp files cleanup (#8189)
* Fix Injured Sounds Not Playing At Altitudes Above 70 (#8212)
* Particles - Fix macro (#8214)
* initial push
* Update script_component.hpp
* Update script_component.hpp
* Update script_component.hpp
* Map - Fix stuck map compass size (add 0.1 zoom duration) (#8176)
Co-authored-by: jonpas <jonpas33@gmail.com>
* Medical - Allow unconscious unit in Taru pods (#8168)
Co-authored-by: Filip Maciejewski <veteran29@users.noreply.github.com>
* Name Tags - Add ability to set custom rank icon (#8174)
* Tools - Add script to update HEMTT include folder (#8134)
* Tools - Add script to check sqf/config with sqfvm (#8137)
* Medical - Add Vehicle Crashes setting (#8149)
Co-authored-by: jonpas <jonpas33@gmail.com>
* Dragging - Add new dragging animations (#7950)
* New custom animation added
* Adjusted CfgMoves and the script components
* New drop animation and key handler
* CBA settings and new ManActions added
* Adjustments to the drop animation
* Added translations and fixed some stuff
* Update CfgMovesBasic.hpp
* Fix translations
Co-authored-by: Elgin675 <elgin675@hotmail.com>
Co-authored-by: Blutze <37950828+Blutze@users.noreply.github.com>
* Use the same key to drop object
* Update addons/dragging/stringtable.xml
Co-authored-by: Jo David <github@jonathandavid.de>
* Fix French translation
Co-authored-by: Elgin675 <elgin675@hotmail.com>
* Lower the weapon accuracy of the drag animations
* Removed auto-switch to handgun
* Update fnc_startDrag.sqf
- Holding a launcher breaks the firing animation.
- Now the unit has to hold either a primary weapon or handgun.
* Handle the unit's current weapon
Co-authored-by: BaerMitUmlaut <BaerMitUmlaut@users.noreply.github.com>
* Update addons/dragging/functions/fnc_handlePlayerWeaponChanged.sqf
Co-authored-by: Filip Maciejewski <veteran29@users.noreply.github.com>
* Update addons/dragging/initSettings.sqf
Co-authored-by: Elgin675 <elgin675@hotmail.com>
Co-authored-by: Blutze <37950828+Blutze@users.noreply.github.com>
Co-authored-by: Jo David <github@jonathandavid.de>
Co-authored-by: BaerMitUmlaut <BaerMitUmlaut@users.noreply.github.com>
Co-authored-by: Filip Maciejewski <veteran29@users.noreply.github.com>
Co-authored-by: jonpas <jonpas33@gmail.com>
* Dragging - Fix build issue (#8219)
* Documentation - Remove DeTex requirement (#8220)
DeTex is subscriber-only now, not required for building ACE3.
* User Interface - Add setting for Development Build watermark (#8140)
Co-authored-by: jonpas <jonpas33@gmail.com>
* RHS USAF Compat - Nightforce NXS scopes updated (#8222)
* Interact Menu - Make List default (#8217)
* Markers - Add scale slider (#8059)
Co-authored-by: commy2 <commy-2@gmx.de>
Co-authored-by: PabstMirror <pabstmirror@gmail.com>
Co-authored-by: jonpas <jonpas33@gmail.com>
* Initial push (#8225)
* MicroDAGR - Add mode switching keybinds (#8216)
* Initial push
* Mode cycling
* Use defines
* RHS ARF Compat - Fix RPK74M wrong ammo bug (#8223)
* Fixed RPK74M wrong ammo bug
* Fix wrong deleted lines of code
* Edit rjs_weap_rpk74_base to rhs_weap_rpk_base
Co-authored-by: Dabako <github@dabakoworld.de>
Co-authored-by: PabstMirror <pabstmirror@gmail.com>
* Extensions - Various Improvments (#8227)
* Translations - Spanish (#8229)
Complete to date spanish translation.
* Attach - Added attached/detaching events (#8193)
* Added ace_attach attached/detach events
* Apply suggestions from code review
Co-authored-by: Jo David <github@jonathandavid.de>
* Apply suggestions from code review
Co-authored-by: jonpas <jonpas33@gmail.com>
Co-authored-by: Jo David <github@jonathandavid.de>
Co-authored-by: jonpas <jonpas33@gmail.com>
* Markers - Fix marker scale (#8233)
* Cargo - paradrop fixes (#8203)
* Small fixes in ace_cargo
Makes paradropItem and unloadItem invoke event "ace_cargoUnloaded" with parameters _itemObject, _vehicle and "paradrop" or "unload" respectivelty.
paradropItem invoked said event but if item was classname it would send classname to event which is not particularly useful.
* Update XEH_postInit.sqf
Moved event invocation to unloadItem, this provides ability to always pass object to eventhandlers.
* code refactor
refactored according to https://github.com/acemod/ACE3/pull/8203#discussion_r610394484
* Update fnc_paradropItem.sqf
apply new fix
* Revert "Update fnc_paradropItem.sqf"
This reverts commit 3db5cc1910
.
* Update fnc_paradropItem.sqf
fixed hint that was broken by previous fixes
* style check
Co-authored-by: commy2 <commy-2@gmx.de>
* style check
Co-authored-by: commy2 <commy-2@gmx.de>
* naming convention
replaced object references called _item with _object.
* Update fnc_paradropItem.sqf
Co-authored-by: commy2 <commy-2@gmx.de>
* Parachute - Add failure chance (#8226)
* Initial push
* disable forgotten define
* Improve exitWith check
* Requested/suggested changes
* Requested changes
* Requested changes
* Bump lodash from 4.17.20 to 4.17.21 in /docs/src (#8244)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.20 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.20...4.17.21)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Bump grunt from 1.0.4 to 1.3.0 in /docs/src (#8246)
Bumps [grunt](https://github.com/gruntjs/grunt) from 1.0.4 to 1.3.0.
- [Release notes](https://github.com/gruntjs/grunt/releases)
- [Changelog](https://github.com/gruntjs/grunt/blob/main/CHANGELOG)
- [Commits](https://github.com/gruntjs/grunt/compare/v1.0.4...v1.3.0)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Bump hosted-git-info from 2.5.0 to 2.8.9 in /docs/src (#8247)
Bumps [hosted-git-info](https://github.com/npm/hosted-git-info) from 2.5.0 to 2.8.9.
- [Release notes](https://github.com/npm/hosted-git-info/releases)
- [Changelog](https://github.com/npm/hosted-git-info/blob/v2.8.9/CHANGELOG.md)
- [Commits](https://github.com/npm/hosted-git-info/compare/v2.5.0...v2.8.9)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Markers - Fix JIP scale (#8248)
* Night Vision - Add color variants to all generations (#8209)
* Fix wrong shot size in birdshot strings (#8253)
* Patachute - Add sound effect when cutting (#8239)
* Changes poisson disc to centered random. (#8257)
It looks nicer and distributes more realistically. I don't know what I was thinking when I first put in poisson disc.
* Fix tabs and manpad UBC
* fix tabs in aim9
* progress update: tercom now flies to acquisition basket
* add TERCOM state defines
* work on parsing heightmap
* Change GBU navigation
* remove testing constants
* remove TERCOM guidance
* better JDAM simulation
Attack heading and impact angle now are followed better
* Better flare decoy calculation
* Update 9m14_joystick.p3d
removed p:\ part from proxy path:
was: `\p:\a3\data_f\proxies\gunner_static_low01\gunner.p3d`
* Destroy projectile on all clients
The projectile needs to be destroyed on all clients to stop it from being simulated. If not destroyed where projectile is local, it will still explode when hitting the ground. If not destroyed on remote clients, the projectile will still be visible but deal no damage
* fix NLAW navigation profile
* fix uninitialised values
* make over-fly trajectory over-fly
* remove malyutka
* SACLOS tweaks
* small changes
* fix bug in laser
* make pronav use the correct units
* change back
* add dev function to get ammo which has MG class data
* improve lin navigation
* Minor style
* add spike ATGM
* Allow multiple cameras to exist at once. Fix script error
* fix bug with angles close to 0
* remove debug
* misc updates
* Handle pre-tracking
* Tweak target acquisition. Reset target after shooting
* Tweak how targets are acquired. Fix velocity calculation
* tweak navigation to allow for <200m shots
* enhance target designation
* Stringtable addition
* Config changes
* more SACLOS tweaks
* Some minor fixes
* fix undefined array
* Only play sound when Spike is launcher. Change onFired to missileguidance
* Tweak IR seeker. Fix MCLOS fired from vehicles
* Remove debug sets
* Update all Line guidance missiles
* remove debug sets
* tweak javelin to make minimum ranges more realistic
* cut spike
* add better error messaging
* better debug info
* Rewrite documentation
* Add ability to disable iron dome (disabled by default)
* Change name
* fix typo
* Remove null projectiles from iron dome nonTrackingProjectiles
* HEMTT v10 Compatibility
* Update addons/field_rations/CfgUIGrids.hpp
Co-authored-by: PabstMirror <pabstmirror@gmail.com>
* fix PabstMirror review
* optionals
* Change configs to enclose strings for calculations
* Fix NLAW guidance that was causing massive overfly
* make tweaks for PLOS movement path
* fix NLAW overfly
* Fix hemmit merge
* fix header
* Update fnc_seekerType_SACLOS.sqf
* Update to new include paths
* Update fnc_midCourseTransition.sqf
* initSettings.inc.sqf
* Remove weapon additions
* revert old weapons, pt1
* revert pt2
* readd javelin
* split iron dome
* cleanup laser
* remove GPS files
* remove gps definitions
* remove IR
* remove MCLOS
* remove doppler
* final cleanup
* restore final final i promise
* cleanup arbitrary files
* small cleanup
* fix hemtt warnings
* cleanup unused var
* fix preping some missing files (jdam/doppler)
* move cam func
---------
Co-authored-by: PabstMirror <pabstmirror@gmail.com>
Co-authored-by: jonpas <jonpas33@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jo David <github@jonathandavid.de>
Co-authored-by: Filip Maciejewski <veteran29@users.noreply.github.com>
Co-authored-by: Pascal Dunaj <32539404+t-zilla@users.noreply.github.com>
Co-authored-by: BaerMitUmlaut <BaerMitUmlaut@users.noreply.github.com>
Co-authored-by: Brett <brett@bmandesigns.com>
Co-authored-by: TyroneMF <TyroneMF@hotmail.com>
Co-authored-by: Kyle Mckay <5459452+kymckay@users.noreply.github.com>
Co-authored-by: Dystopian <sddex@ya.ru>
Co-authored-by: commy2 <commy-2@gmx.de>
Co-authored-by: R3voA3 <robertseibel@outlook.de>
Co-authored-by: Steve Zhao <ampersand38@gmail.com>
Co-authored-by: Kyle J. McKeown <Drift91@users.noreply.github.com>
Co-authored-by: Salluci <69561145+Salluci@users.noreply.github.com>
Co-authored-by: Dániel Boros <43353942+Malbryn@users.noreply.github.com>
Co-authored-by: Elgin675 <elgin675@hotmail.com>
Co-authored-by: Blutze <37950828+Blutze@users.noreply.github.com>
Co-authored-by: Laid3acK <bal2.chris@orange.fr>
Co-authored-by: frankplow <post@frankplowman.com>
Co-authored-by: JoramD <j.davids@hotmail.nl>
Co-authored-by: Dabako <dabako@gmx.de>
Co-authored-by: Dabako <github@dabakoworld.de>
Co-authored-by: Abogado <regiregi22@hotmail.com>
Co-authored-by: Dedmen Miller <dedmen@users.noreply.github.com>
Co-authored-by: Lupus the Canine <tymoteusz.2000.0+GitHub@gmail.com>
Co-authored-by: Drofseh <Drofseh@users.noreply.github.com>
Co-authored-by: LorenLuke <LukeLLL@aol.com>
Co-authored-by: SzwedzikPL <szwedzikpl@gmail.com>
Co-authored-by: BrettMayson <brett@mayson.io>
This commit is contained in:
parent
1f67058dda
commit
8ac2d09c31
@ -6,6 +6,11 @@ class GVAR(AttackProfiles) {
|
|||||||
|
|
||||||
functionName = QFUNC(attackProfile_LIN);
|
functionName = QFUNC(attackProfile_LIN);
|
||||||
};
|
};
|
||||||
|
// empty classes for backwards compat
|
||||||
|
class MID: LIN {
|
||||||
|
};
|
||||||
|
class HI: LIN {
|
||||||
|
};
|
||||||
class DIR {
|
class DIR {
|
||||||
name = "";
|
name = "";
|
||||||
visualName = "";
|
visualName = "";
|
||||||
@ -13,19 +18,12 @@ class GVAR(AttackProfiles) {
|
|||||||
|
|
||||||
functionName = QFUNC(attackProfile_DIR);
|
functionName = QFUNC(attackProfile_DIR);
|
||||||
};
|
};
|
||||||
class MID {
|
class LOFT {
|
||||||
name = "";
|
name = "";
|
||||||
visualName = "";
|
visualName = "";
|
||||||
description = "";
|
description = "";
|
||||||
|
|
||||||
functionName = QFUNC(attackProfile_MID);
|
functionName = QFUNC(attackProfile_LOFT);
|
||||||
};
|
|
||||||
class HI {
|
|
||||||
name = "";
|
|
||||||
visualName = "";
|
|
||||||
description = "";
|
|
||||||
|
|
||||||
functionName = QFUNC(attackProfile_HI);
|
|
||||||
};
|
};
|
||||||
class JAV_DIR {
|
class JAV_DIR {
|
||||||
name = "";
|
name = "";
|
||||||
@ -82,12 +80,39 @@ class GVAR(SeekerTypes) {
|
|||||||
functionName = QFUNC(seekerType_SACLOS);
|
functionName = QFUNC(seekerType_SACLOS);
|
||||||
onFired = QFUNC(SACLOS_onFired);
|
onFired = QFUNC(SACLOS_onFired);
|
||||||
};
|
};
|
||||||
class ARH {
|
class MillimeterWaveRadar {
|
||||||
name = "";
|
name = "";
|
||||||
visualName = "";
|
visualName = "";
|
||||||
description = "";
|
description = "";
|
||||||
|
|
||||||
functionName = QFUNC(seekerType_ARH);
|
functionName = QFUNC(seekerType_MWR);
|
||||||
onFired = QFUNC(ahr_onFired);
|
onFired = QFUNC(mwr_onFired);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class GVAR(NavigationTypes) {
|
||||||
|
class Direct {
|
||||||
|
functionName = QFUNC(navigationType_direct);
|
||||||
|
onFired = "";
|
||||||
|
};
|
||||||
|
class Line {
|
||||||
|
functionName = QFUNC(navigationType_line);
|
||||||
|
onFired = QFUNC(line_onFired);
|
||||||
|
};
|
||||||
|
class LineOfSight {
|
||||||
|
functionName = QFUNC(navigationType_lineOfSight);
|
||||||
|
onFired = QFUNC(proNav_onFired);
|
||||||
|
};
|
||||||
|
class ProportionalNavigation {
|
||||||
|
functionName = QFUNC(navigationType_proNav);
|
||||||
|
onFired = QFUNC(proNav_onFired);
|
||||||
|
};
|
||||||
|
class AugmentedProportionalNavigation {
|
||||||
|
functionName = QFUNC(navigationType_augmentedProNav);
|
||||||
|
onFired = QFUNC(proNav_onFired);
|
||||||
|
};
|
||||||
|
class ZeroEffortMiss {
|
||||||
|
functionName = QFUNC(navigationType_zeroEffortMiss);
|
||||||
|
onFired = QFUNC(proNav_onFired);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -6,6 +6,8 @@ PREP(changeMissileDirection);
|
|||||||
PREP(checkSeekerAngle);
|
PREP(checkSeekerAngle);
|
||||||
PREP(checkLos);
|
PREP(checkLos);
|
||||||
|
|
||||||
|
PREP(dev_ProjectileCamera);
|
||||||
|
|
||||||
PREP(onFired);
|
PREP(onFired);
|
||||||
PREP(onIncomingMissile);
|
PREP(onIncomingMissile);
|
||||||
|
|
||||||
@ -16,28 +18,44 @@ PREP(doSeekerSearch);
|
|||||||
PREP(doHandoff);
|
PREP(doHandoff);
|
||||||
PREP(handleHandoff);
|
PREP(handleHandoff);
|
||||||
|
|
||||||
|
//re-enable after feature merge - PREP(shouldFilterRadarHit);
|
||||||
|
|
||||||
// Attack Profiles
|
// Attack Profiles
|
||||||
PREP(attackProfile_AIR);
|
PREP(attackProfile_AIR);
|
||||||
PREP(attackProfile_DIR);
|
PREP(attackProfile_DIR);
|
||||||
PREP(attackProfile_HI);
|
|
||||||
PREP(attackProfile_LIN);
|
PREP(attackProfile_LIN);
|
||||||
PREP(attackProfile_MID);
|
PREP(attackProfile_LOFT);
|
||||||
PREP(attackProfile_WIRE);
|
PREP(attackProfile_WIRE);
|
||||||
PREP(attackProfile_BEAM);
|
PREP(attackProfile_BEAM);
|
||||||
|
//re-enable after feature merge - PREP(attackProfile_JDAM);
|
||||||
|
|
||||||
// Javelin profiles
|
// Javelin profiles
|
||||||
PREP(attackProfile_JAV_DIR);
|
PREP(attackProfile_JAV_DIR);
|
||||||
PREP(attackProfile_JAV_TOP);
|
PREP(attackProfile_JAV_TOP);
|
||||||
|
|
||||||
|
// Navigation Profiles
|
||||||
|
PREP(navigationType_zeroEffortMiss);
|
||||||
|
PREP(navigationType_augmentedProNav);
|
||||||
|
PREP(navigationType_proNav);
|
||||||
|
PREP(navigationType_lineOfSight);
|
||||||
|
PREP(navigationType_line);
|
||||||
|
PREP(navigationType_direct);
|
||||||
|
|
||||||
// Seeker search functions
|
// Seeker search functions
|
||||||
PREP(seekerType_SALH);
|
PREP(seekerType_SALH);
|
||||||
PREP(seekerType_Optic);
|
PREP(seekerType_Optic);
|
||||||
PREP(seekerType_SACLOS);
|
PREP(seekerType_SACLOS);
|
||||||
PREP(seekerType_ARH);
|
//re-enable after feature merge - PREP(seekerType_Doppler);
|
||||||
|
PREP(seekerType_MWR);
|
||||||
|
|
||||||
// Attack Profiles OnFired
|
// Attack Profiles OnFired
|
||||||
PREP(wire_onFired);
|
PREP(wire_onFired);
|
||||||
|
|
||||||
// Seeker OnFired
|
// Seeker OnFired
|
||||||
PREP(SACLOS_onFired);
|
PREP(SACLOS_onFired);
|
||||||
PREP(ahr_onFired);
|
PREP(mwr_onFired);
|
||||||
|
|
||||||
|
// Navigation OnFired
|
||||||
|
PREP(proNav_onFired);
|
||||||
|
PREP(line_onFired);
|
||||||
|
|
||||||
|
@ -2,12 +2,10 @@
|
|||||||
|
|
||||||
[QGVAR(handoff), LINKFUNC(handleHandoff)] call CBA_fnc_addEventHandler;
|
[QGVAR(handoff), LINKFUNC(handleHandoff)] call CBA_fnc_addEventHandler;
|
||||||
|
|
||||||
["ACE3 Weapons", QGVAR(cycleFireMode), localize LSTRING(CycleFireMode),
|
["ACE3 Weapons", QGVAR(cycleFireMode), localize LSTRING(CycleFireMode), {
|
||||||
{
|
|
||||||
[] call FUNC(cycleAttackProfileKeyDown);
|
[] call FUNC(cycleAttackProfileKeyDown);
|
||||||
false
|
false
|
||||||
},
|
}, {
|
||||||
{
|
|
||||||
false
|
false
|
||||||
},
|
},
|
||||||
[15, [false, true, false]], false] call CBA_fnc_addKeybind; //Ctrl+Tab Key
|
[15, [false, true, false]], false] call CBA_fnc_addKeybind; //Ctrl+Tab Key
|
||||||
|
@ -11,4 +11,15 @@ PREP_RECOMPILE_END;
|
|||||||
// As weapons take config changes, there is little point in being able to disable guidance
|
// As weapons take config changes, there is little point in being able to disable guidance
|
||||||
if (isNil QGVAR(enabled)) then { GVAR(enabled) = 2; };
|
if (isNil QGVAR(enabled)) then { GVAR(enabled) = 2; };
|
||||||
|
|
||||||
|
GVAR(debug_enableMissileCamera) = false;
|
||||||
|
GVAR(debug_drawGuidanceInfo) = false;
|
||||||
|
|
||||||
|
#ifdef DRAW_GUIDANCE_INFO
|
||||||
|
GVAR(debug_drawGuidanceInfo) = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_PROJECTILE_CAMERA
|
||||||
|
GVAR(debug_enableMissileCamera) = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
ADDON = true;
|
ADDON = true;
|
||||||
|
26
addons/missileguidance/dev/getAmmoProperties.sqf
Normal file
26
addons/missileguidance/dev/getAmmoProperties.sqf
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include "..\script_component.hpp"
|
||||||
|
|
||||||
|
private _configs = configProperties [configFile >> "CfgAmmo", QUOTE((isClass _x) && { isClass (_x >> QUOTE(QUOTE(ADDON)))})];
|
||||||
|
|
||||||
|
private _seekerTypes = createHashMap;
|
||||||
|
private _navigationTypes = createHashMap;
|
||||||
|
private _attackProfiles = createHashMap;
|
||||||
|
{
|
||||||
|
private _seekerType = getText (_x >> QUOTE(ADDON) >> "defaultSeekerType");
|
||||||
|
private _navigationType = getText (_x >> QUOTE(ADDON) >> "defaultNavigationType");
|
||||||
|
private _attackProfile = getText (_x >> QUOTE(ADDON) >> "defaultAttackProfile");
|
||||||
|
|
||||||
|
private _seekers = _seekerTypes getOrDefault [_seekerType, []];
|
||||||
|
private _navigations = _navigationTypes getOrDefault [_navigationType, []];
|
||||||
|
private _attacks = _attackProfiles getOrDefault [_attackProfile, []];
|
||||||
|
|
||||||
|
_seekers pushBack configName _x;
|
||||||
|
_navigations pushBack configName _x;
|
||||||
|
_attacks pushBack configName _x;
|
||||||
|
|
||||||
|
_seekerTypes set [_seekerType, _seekers];
|
||||||
|
_navigationTypes set [_navigationType, _navigations];
|
||||||
|
_attackProfiles set [_attackProfile, _attacks];
|
||||||
|
} forEach _configs;
|
||||||
|
|
||||||
|
[_seekerTypes, _navigationTypes, _attackProfiles]
|
@ -32,4 +32,3 @@ _seekerStateParams set [2, _animationSourceGun];
|
|||||||
_seekerStateParams set [3, _usePilotCamera || { (_shooter isKindOf "Plane") && hasPilotCamera _shooter }];
|
_seekerStateParams set [3, _usePilotCamera || { (_shooter isKindOf "Plane") && hasPilotCamera _shooter }];
|
||||||
|
|
||||||
if ((_shooter isKindOf "Plane") && !hasPilotCamera _shooter) then { WARNING("SACLOS fired from planes without pilot camera unsupported!"); };
|
if ((_shooter isKindOf "Plane") && !hasPilotCamera _shooter) then { WARNING("SACLOS fired from planes without pilot camera unsupported!"); };
|
||||||
|
|
||||||
|
@ -17,31 +17,26 @@
|
|||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
params ["_seekerTargetPos", "_args", "_attackProfileStateParams"];
|
params ["_seekerTargetPos", "_args", "_attackProfileStateParams"];
|
||||||
_args params ["_firedEH"];
|
_args params ["_firedEH", "", "", "", "", "_targetData"];
|
||||||
_firedEH params ["_shooter","","","","","","_projectile"];
|
_firedEH params ["_shooter","","","","","","_projectile"];
|
||||||
_attackProfileStateParams params["_maxCorrectableDistance", "_wireCut", "_randomVector", "_crosshairOffset", "_seekerMaxRangeSqr", "_seekerMinRangeSqr", "_wireCutSource", "_distanceAheadOfMissile"];
|
_attackProfileStateParams params ["_maxCorrectableDistance", "_wireCut", "_lastInput", "_crosshairOffset", "_seekerMaxRangeSqr", "_seekerMinRangeSqr", "_wireCutSource", "_distanceAheadOfMissile"];
|
||||||
|
|
||||||
private _projectilePos = getPosASL _projectile;
|
private _projectilePos = getPosASL _projectile;
|
||||||
private _shooterPos = getPosASL _shooter;
|
private _shooterPos = getPosASL _shooter;
|
||||||
|
|
||||||
private _shooterDir = vectorNormalized(_seekerTargetPos vectorDiff _shooterPos);
|
|
||||||
private _distanceToProjectile = _shooterPos vectorDistanceSqr _projectilePos;
|
private _distanceToProjectile = _shooterPos vectorDistanceSqr _projectilePos;
|
||||||
|
|
||||||
if (_distanceToProjectile > _seekerMaxRangeSqr || { _seekerTargetPos isEqualTo [0, 0, 0] } || { _distanceToProjectile < _seekerMinRangeSqr }) exitWith {
|
if ((_distanceToProjectile > _seekerMaxRangeSqr) || { _wireCut }) exitWith {
|
||||||
// return position 50m infront of projectile
|
// wire snap, random direction
|
||||||
_projectilePos vectorAdd (_projectile vectorModelToWorld [0, 50, 0])
|
if !(_wireCut) then {
|
||||||
|
_attackProfileStateParams set [1, true];
|
||||||
|
};
|
||||||
|
_lastInput
|
||||||
};
|
};
|
||||||
|
|
||||||
private _relativeCorrection = _projectile vectorWorldToModel (_projectilePos vectorDiff _seekerTargetPos);
|
private _final = _seekerTargetPos vectorAdd _crosshairOffset;
|
||||||
_relativeCorrection = _relativeCorrection vectorDiff _crosshairOffset;
|
_attackProfileStateParams set [2, _final];
|
||||||
|
|
||||||
private _magnitude = vectorMagnitude [_relativeCorrection select 0, 0, _relativeCorrection select 2];
|
_targetData set [0, _projectilePos vectorFromTo _final];
|
||||||
private _fovImpulse = 1 min (_magnitude / _maxCorrectableDistance); // the simulated impulse for the missile being close to the center of the crosshair
|
|
||||||
|
|
||||||
// Adjust the impulse due to near-zero values creating wobbly missiles?
|
_final
|
||||||
private _correction = _fovImpulse;
|
|
||||||
|
|
||||||
|
|
||||||
_relativeCorrection = (vectorNormalized _relativeCorrection) vectorMultiply _correction;
|
|
||||||
private _returnPos = _projectilePos vectorDiff (_projectile vectorModelToWorld _relativeCorrection);
|
|
||||||
_returnPos vectorAdd (_shooterDir vectorMultiply _distanceAheadOfMissile)
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#include "..\script_component.hpp"
|
#include "..\script_component.hpp"
|
||||||
/*
|
/*
|
||||||
* Author: jaynus / nou
|
* Author: tcvm
|
||||||
* Attack profile: DIR
|
* Attack profile: DIR
|
||||||
* TODO: falls back to Linear
|
* Returns target position with no modifications
|
||||||
*
|
*
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* 0: Seeker Target PosASL <ARRAY>
|
* 0: Seeker Target PosASL <ARRAY>
|
||||||
@ -18,4 +18,5 @@
|
|||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
|
|
||||||
_this call FUNC(attackProfile_LIN);
|
params ["_seekerTargetPos"];
|
||||||
|
_seekerTargetPos
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
#include "..\script_component.hpp"
|
|
||||||
/*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
_this call FUNC(attackProfile_LIN);
|
|
@ -18,8 +18,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
params ["_seekerTargetPos", "_args"];
|
params ["_seekerTargetPos", "_args"];
|
||||||
_args params ["_firedEH"];
|
_args params ["_firedEH", "_launchParams"];
|
||||||
_firedEH params ["_shooter","","","","","","_projectile"];
|
_firedEH params ["_shooter","","","","","","_projectile"];
|
||||||
|
_launchParams params ["","_targetLaunchParams"];
|
||||||
|
_targetLaunchParams params ["", "", "_launchPos"];
|
||||||
|
|
||||||
if (_seekerTargetPos isEqualTo [0,0,0]) exitWith {_seekerTargetPos};
|
if (_seekerTargetPos isEqualTo [0,0,0]) exitWith {_seekerTargetPos};
|
||||||
|
|
||||||
@ -30,11 +32,18 @@ private _distanceToTarget = _projectilePos vectorDistance _seekerTargetPos;
|
|||||||
private _distanceToShooter = _projectilePos vectorDistance _shooterPos;
|
private _distanceToShooter = _projectilePos vectorDistance _shooterPos;
|
||||||
private _distanceShooterToTarget = _shooterPos vectorDistance _seekerTargetPos;
|
private _distanceShooterToTarget = _shooterPos vectorDistance _seekerTargetPos;
|
||||||
|
|
||||||
|
private _ttgo = _distanceToTarget / (vectorMagnitude velocity _projectile);
|
||||||
|
|
||||||
TRACE_2("",_distanceToTarget,_distanceToShooter);
|
TRACE_2("",_distanceToTarget,_distanceToShooter);
|
||||||
|
|
||||||
// Add height depending on distance for compensate
|
// Add height depending on distance for compensate
|
||||||
private _addHeight = [0,0,0];
|
private _addHeight = [0,0,0];
|
||||||
|
|
||||||
|
private _2dDistance = (800 + (_projectilePos distance2D _launchPos)) / (_projectilePos distance2D _seekerTargetPos);
|
||||||
|
|
||||||
|
if (_2dDistance <= 1) then {
|
||||||
|
_addHeight = [0, 0, (_projectilePos#2) + 8];
|
||||||
|
} else {
|
||||||
// Always climb an arc on initial launch if we are close to the round
|
// Always climb an arc on initial launch if we are close to the round
|
||||||
if ((((ASLtoAGL _projectilePos) select 2) < 5) && {_distanceToShooter < 15}) then {
|
if ((((ASLtoAGL _projectilePos) select 2) < 5) && {_distanceToShooter < 15}) then {
|
||||||
_addHeight = _addHeight vectorAdd [0,0,_distanceToTarget];
|
_addHeight = _addHeight vectorAdd [0,0,_distanceToTarget];
|
||||||
@ -46,11 +55,6 @@ if ((((ASLtoAGL _projectilePos) select 2) < 5) && {_distanceToShooter < 15}) the
|
|||||||
TRACE_1("climb - below target and far",_addHeight);
|
TRACE_1("climb - below target and far",_addHeight);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Projectile above target
|
|
||||||
if ((_projectilePos select 2) > (_seekerTargetPos select 2)) then {
|
|
||||||
TRACE_1("above - far",_addHeight);
|
|
||||||
_addHeight = _addHeight vectorAdd [0,0, _distanceToTarget / 50];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private _returnTargetPos = _seekerTargetPos vectorAdd _addHeight;
|
private _returnTargetPos = _seekerTargetPos vectorAdd _addHeight;
|
||||||
|
53
addons/missileguidance/functions/fnc_attackProfile_LOFT.sqf
Normal file
53
addons/missileguidance/functions/fnc_attackProfile_LOFT.sqf
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#include "..\script_component.hpp"
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
params ["_seekerTargetPos", "_args"];
|
||||||
|
_args params ["_firedEH", "_launchParams", "_flightParams", "_seekerParams", "_stateParams"];
|
||||||
|
_firedEH params ["_shooter","","","","_ammo","","_projectile"];
|
||||||
|
_launchParams params ["_shooter","_targetLaunchParams","_seekerType","_attackProfile","_lockMode","_laserInfo","_navigationType"];
|
||||||
|
_targetLaunchParams params ["_target", "_targetPos", "_launchPos", "_launchDir", "_launchTime"];
|
||||||
|
_flightParams params ["_pitchRate", "_yawRate", "_isBangBangGuidance"];
|
||||||
|
_stateParams params ["_lastRunTime", "_seekerStateParams", "_attackProfileStateParams", "_lastKnownPosState","_navigationParams"];
|
||||||
|
_seekerParams params ["_seekerAngle", "_seekerAccuracy", "_seekerMaxRange", "_seekerMinRange"];
|
||||||
|
|
||||||
|
if (_seekerTargetPos isEqualTo [0, 0, 0]) exitWith {
|
||||||
|
_seekerTargetPos
|
||||||
|
};
|
||||||
|
|
||||||
|
private _projectilePos = getPosASLVisual _projectile;
|
||||||
|
private _distanceToTarget2d = _projectilePos distance2d _seekerTargetPos;
|
||||||
|
|
||||||
|
private _closingRate = vectorMagnitude velocity _projectile;
|
||||||
|
private _timeToGo = (_projectilePos distance _seekerTargetPos) / _closingRate;
|
||||||
|
|
||||||
|
// we could do stuff like desired attack angle, but I'm not going that far today
|
||||||
|
private _los = vectorNormalized (_seekerTargetPos vectorDiff _projectilePos);
|
||||||
|
|
||||||
|
private _angleToTarget = acos ((vectorDir _projectile) vectorCos _los);
|
||||||
|
private _atMinRotationAngle = _angleToTarget >= (0.5 * _pitchRate * _timeToGo);
|
||||||
|
|
||||||
|
private _returnTargetPos = _seekerTargetPos;
|
||||||
|
|
||||||
|
if (!_atMinRotationAngle && _distanceToTarget2d >= 500 && _timeToGo >= 10) then {
|
||||||
|
// 10 degree pitch up
|
||||||
|
_returnTargetPos = _seekerTargetPos vectorAdd [0, 0, (_projectilePos distance _seekerTargetPos) * sin 10];
|
||||||
|
};
|
||||||
|
|
||||||
|
_returnTargetPos
|
@ -1,21 +0,0 @@
|
|||||||
#include "..\script_component.hpp"
|
|
||||||
/*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
_this call FUNC(attackProfile_LIN);
|
|
@ -17,47 +17,27 @@
|
|||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
params ["_seekerTargetPos", "_args", "_attackProfileStateParams"];
|
params ["_seekerTargetPos", "_args", "_attackProfileStateParams"];
|
||||||
_args params ["_firedEH"];
|
_args params ["_firedEH", "", "", "", "", "_targetData"];
|
||||||
_firedEH params ["_shooter","","","","","","_projectile"];
|
_firedEH params ["_shooter","","","","","","_projectile"];
|
||||||
_attackProfileStateParams params["_maxCorrectableDistance", "_wireCut", "_randomVector", "_crosshairOffset", "_seekerMaxRangeSqr", "_seekerMinRangeSqr", "_wireCutSource", "_distanceAheadOfMissile"];
|
_attackProfileStateParams params ["_maxCorrectableDistance", "_wireCut", "_lastInput", "_crosshairOffset", "_seekerMaxRangeSqr", "_seekerMinRangeSqr", "_wireCutSource", "_distanceAheadOfMissile"];
|
||||||
|
|
||||||
private _projectilePos = getPosASL _projectile;
|
private _projectilePos = getPosASL _projectile;
|
||||||
private _shooterPos = getPosASL _shooter;
|
private _shooterPos = getPosASL _shooter;
|
||||||
|
|
||||||
private _shooterDir = vectorNormalized(_seekerTargetPos vectorDiff _shooterPos);
|
|
||||||
private _distanceToProjectile = _shooterPos vectorDistanceSqr _projectilePos;
|
private _distanceToProjectile = _shooterPos vectorDistanceSqr _projectilePos;
|
||||||
|
|
||||||
if ((_distanceToProjectile > _seekerMaxRangeSqr) || { _wireCut }) exitWith {
|
if ((_distanceToProjectile > _seekerMaxRangeSqr) || { _wireCut }) exitWith {
|
||||||
// wire snap, random direction
|
// wire snap, random direction
|
||||||
if (_randomVector isEqualTo [0, 0, 0]) then {
|
if !(_wireCut) then {
|
||||||
_randomVector = RANDOM_VECTOR_3D vectorMultiply 300;
|
|
||||||
_attackProfileStateParams set [1, true];
|
_attackProfileStateParams set [1, true];
|
||||||
_attackProfileStateParams set [2, _randomVector];
|
|
||||||
|
|
||||||
playSound3D ["a3\sounds_f\air\sfx\SL_rope_break.wss", objNull, false, AGLtoASL (_shooter modelToWorld _wireCutSource), 5, 1, 150];
|
playSound3D ["a3\sounds_f\air\sfx\SL_rope_break.wss", objNull, false, AGLtoASL (_shooter modelToWorld _wireCutSource), 5, 1, 150];
|
||||||
};
|
};
|
||||||
_projectilePos vectorAdd _randomVector
|
_lastInput
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_seekerTargetPos isEqualTo [0, 0, 0] || { _distanceToProjectile < _seekerMinRangeSqr }) exitWith {
|
private _final = _seekerTargetPos vectorAdd _crosshairOffset;
|
||||||
// cut wire if its caught on terrain
|
_attackProfileStateParams set [2, _final];
|
||||||
/*if (lineIntersectsSurfaces [getPosASL _shooter, _projectilePos, _shooter] isNotEqualTo []) then {
|
|
||||||
_attackProfileStateParams set [1, true];
|
|
||||||
};*/
|
|
||||||
// return position 50m infront of projectile
|
|
||||||
_projectilePos vectorAdd (_projectile vectorModelToWorld [0, 50, 0])
|
|
||||||
};
|
|
||||||
|
|
||||||
private _relativeCorrection = _projectile vectorWorldToModel (_projectilePos vectorDiff _seekerTargetPos);
|
_targetData set [0, _projectilePos vectorFromTo _final];
|
||||||
_relativeCorrection = _relativeCorrection vectorDiff _crosshairOffset;
|
|
||||||
|
|
||||||
private _magnitude = vectorMagnitude [_relativeCorrection select 0, 0, _relativeCorrection select 2];
|
_final
|
||||||
private _fovImpulse = 1 min (_magnitude / _maxCorrectableDistance); // the simulated impulse for the missile being close to the center of the crosshair
|
|
||||||
|
|
||||||
// Adjust the impulse due to near-zero values creating wobbly missiles?
|
|
||||||
private _correction = _fovImpulse;
|
|
||||||
|
|
||||||
|
|
||||||
_relativeCorrection = (vectorNormalized _relativeCorrection) vectorMultiply _correction;
|
|
||||||
private _returnPos = _projectilePos vectorDiff (_projectile vectorModelToWorld _relativeCorrection);
|
|
||||||
_returnPos vectorAdd (_shooterDir vectorMultiply _distanceAheadOfMissile)
|
|
||||||
|
@ -16,10 +16,9 @@
|
|||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
|
|
||||||
params ["_projectile", "_v"];
|
params ["_projectile", "_pitch", "_yaw", "_roll"];
|
||||||
|
|
||||||
private _l = sqrt ((_v select 0) ^ 2 + (_v select 1) ^ 2);
|
private _dir = [sin _yaw * cos _pitch, cos _yaw * cos _pitch, sin _pitch];
|
||||||
private _r = -(_v select 2) / _l;
|
private _up = [[sin _roll, -sin _pitch, cos _roll * cos _pitch], -_yaw] call BIS_fnc_rotateVector2D;
|
||||||
|
|
||||||
_projectile setVectorDirAndUp [ _v, [(_v select 0) * _r,(_v select 1) * _r, _l] ];
|
_projectile setVectorDirAndUp [_dir, _up];
|
||||||
_projectile setVelocity (_v vectorMultiply (vectorMagnitude (velocity _projectile)));
|
|
||||||
|
@ -43,4 +43,3 @@ if (!((terrainIntersectASL [_seekerPos, _targetPos]) && {terrainIntersectASL [_s
|
|||||||
};
|
};
|
||||||
|
|
||||||
_return
|
_return
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ private _nextFireMode = _attackProfiles select _index;
|
|||||||
TRACE_4("",_currentFireMode,_nextFireMode,_index,_attackProfiles);
|
TRACE_4("",_currentFireMode,_nextFireMode,_index,_attackProfiles);
|
||||||
|
|
||||||
|
|
||||||
private _currentFireMode = if (_useModeForAttackProfile) then {
|
if (_useModeForAttackProfile) then {
|
||||||
TRACE_2("setting fire mode",_weaponStateToken,_nextFireMode);
|
TRACE_2("setting fire mode",_weaponStateToken,_nextFireMode);
|
||||||
{
|
{
|
||||||
_x params ["_xIndex", "", "_xWeapon", "", "_xMode"];
|
_x params ["_xIndex", "", "_xWeapon", "", "_xMode"];
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
#include "..\script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: tcvm
|
||||||
|
* tracks a projectile until it explodes
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
params ["_projectile"];
|
||||||
|
|
||||||
|
private _camera = "camera" camCreate getPosATL _projectile;
|
||||||
|
_camera camPrepareFOV 0.7;
|
||||||
|
_camera cameraEffect ["internal", "back"];
|
||||||
|
|
||||||
|
_camera camCommitPrepared 0;
|
||||||
|
|
||||||
|
GVAR(debug_camera_close) = false;
|
||||||
|
private _displayEH = (findDisplay 46) displayAddEventHandler ["KeyDown", {
|
||||||
|
params ["_displayorcontrol", "_key", "_shift", "_ctrl", "_alt"];
|
||||||
|
GVAR(debug_camera_close) = (_key == 1);
|
||||||
|
true
|
||||||
|
}];
|
||||||
|
|
||||||
|
[{
|
||||||
|
params ["_args", "_pfh"];
|
||||||
|
_args params ["_projectile", "_camera", "_projectilePos", "_displayEH"];
|
||||||
|
if (!alive _projectile || GVAR(debug_camera_close)) exitWith {
|
||||||
|
private _delay = 1.5;
|
||||||
|
if (GVAR(debug_camera_close)) then {
|
||||||
|
_delay = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
(findDisplay 46) displayRemoveEventHandler ["KeyDown", _displayEH];
|
||||||
|
|
||||||
|
[{
|
||||||
|
params ["_camera"];
|
||||||
|
|
||||||
|
_camera cameraEffect ["terminate", "back"];
|
||||||
|
_camera camCommitPrepared 0;
|
||||||
|
camDestroy _camera;
|
||||||
|
}, [_camera], _delay] call CBA_fnc_waitAndExecute;
|
||||||
|
|
||||||
|
_camera camPrepareTarget _projectilePos;
|
||||||
|
_camera camCommitPrepared 0;
|
||||||
|
|
||||||
|
[_pfh] call CBA_fnc_removePerFrameHandler;
|
||||||
|
};
|
||||||
|
|
||||||
|
private _currentProjectilePos = getPosATLVisual _projectile;
|
||||||
|
|
||||||
|
_camera camPrepareTarget _projectile;
|
||||||
|
_camera camPrepareRelPos [0, -5, 1];
|
||||||
|
_camera camCommitPrepared 0;
|
||||||
|
|
||||||
|
_args set [2, getPosATL _projectile];
|
||||||
|
}, 0, [_projectile, _camera, getPosATL _projectile, _displayEH]] call CBA_fnc_addPerFrameHandler;
|
@ -22,7 +22,6 @@ _args params ["", "_launchParams"];
|
|||||||
_launchParams params ["", "", "", "_attackProfileName"];
|
_launchParams params ["", "", "", "_attackProfileName"];
|
||||||
|
|
||||||
private _attackProfileFunction = getText (configFile >> QGVAR(AttackProfiles) >> _attackProfileName >> "functionName");
|
private _attackProfileFunction = getText (configFile >> QGVAR(AttackProfiles) >> _attackProfileName >> "functionName");
|
||||||
|
|
||||||
private _attackProfilePos = _this call (missionNamespace getVariable _attackProfileFunction);
|
private _attackProfilePos = _this call (missionNamespace getVariable _attackProfileFunction);
|
||||||
|
|
||||||
if ((isNil "_attackProfilePos") || {_attackProfilePos isEqualTo [0,0,0]}) exitWith {
|
if ((isNil "_attackProfilePos") || {_attackProfilePos isEqualTo [0,0,0]}) exitWith {
|
||||||
@ -30,10 +29,10 @@ if ((isNil "_attackProfilePos") || {_attackProfilePos isEqualTo [0,0,0]}) exitWi
|
|||||||
[0,0,0]
|
[0,0,0]
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef DRAW_GUIDANCE_INFO
|
if (GVAR(debug_drawGuidanceInfo)) then {
|
||||||
drawLine3D [(ASLtoAGL _attackProfilePos), (ASLtoAGL _seekerTargetPos), [0,1,1,1]];
|
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"];
|
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);
|
TRACE_2("return",_attackProfilePos,_attackProfileName);
|
||||||
_attackProfilePos;
|
_attackProfilePos;
|
||||||
|
@ -30,9 +30,9 @@ if ((isNil "_seekerTargetPos") || {_seekerTargetPos isEqualTo [0,0,0]}) then { /
|
|||||||
if (_seekLastTargetPos && {_lastKnownPos isNotEqualTo [0,0,0]}) then { // if enabled for the ammo, use last known position if we have one stored
|
if (_seekLastTargetPos && {_lastKnownPos isNotEqualTo [0,0,0]}) then { // if enabled for the ammo, use last known position if we have one stored
|
||||||
TRACE_2("seeker returned bad pos - using last known",_seekLastTargetPos,_lastKnownPos);
|
TRACE_2("seeker returned bad pos - using last known",_seekLastTargetPos,_lastKnownPos);
|
||||||
_seekerTargetPos = _lastKnownPos;
|
_seekerTargetPos = _lastKnownPos;
|
||||||
#ifdef DRAW_GUIDANCE_INFO
|
if (GVAR(debug_drawGuidanceInfo)) then {
|
||||||
drawIcon3D ["\A3\ui_f\data\map\markers\military\unknown_CA.paa", [1,1,0,1], ASLtoAGL _lastKnownPos, 0.25, 0.25, 0, "LastKnownPos", 1, 0.02, "TahomaB"];
|
drawIcon3D ["\A3\ui_f\data\map\markers\military\unknown_CA.paa", [1,1,0,1], ASLtoAGL _lastKnownPos, 0.25, 0.25, 0, "LastKnownPos", 1, 0.02, "TahomaB"];
|
||||||
#endif
|
};
|
||||||
} else {
|
} else {
|
||||||
TRACE_1("seeker returned no pos",_seekerTargetPos);
|
TRACE_1("seeker returned no pos",_seekerTargetPos);
|
||||||
_seekerTargetPos = [0,0,0];
|
_seekerTargetPos = [0,0,0];
|
||||||
@ -44,9 +44,9 @@ if ((isNil "_seekerTargetPos") || {_seekerTargetPos isEqualTo [0,0,0]}) then { /
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef DRAW_GUIDANCE_INFO
|
if (GVAR(debug_drawGuidanceInfo)) then {
|
||||||
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"];
|
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
|
};
|
||||||
|
|
||||||
TRACE_2("return",_seekerTargetPos,_seekerTypeName);
|
TRACE_2("return",_seekerTargetPos,_seekerTypeName);
|
||||||
_seekerTargetPos;
|
_seekerTargetPos;
|
||||||
|
@ -15,100 +15,215 @@
|
|||||||
*
|
*
|
||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
|
#define TRAIL_COLOUR(multiplier) [1 * multiplier, 1 * multiplier, 0.3 * multiplier, 0.7 * multiplier]
|
||||||
|
|
||||||
BEGIN_COUNTER(guidancePFH);
|
BEGIN_COUNTER(guidancePFH);
|
||||||
|
|
||||||
#define TIMESTEP_FACTOR 0.01
|
|
||||||
|
|
||||||
params ["_args", "_pfID"];
|
params ["_args", "_pfID"];
|
||||||
_args params ["_firedEH", "_launchParams", "_flightParams", "_seekerParams", "_stateParams"];
|
_args params ["_firedEH", "_launchParams", "_flightParams", "_seekerParams", "_stateParams", "_targetData", "_navigationStateParams"];
|
||||||
_firedEH params ["_shooter","","","","_ammo","","_projectile"];
|
_firedEH params ["_shooter","","","","_ammo","","_projectile"];
|
||||||
_launchParams params ["","_targetLaunchParams"];
|
_launchParams params ["","_targetLaunchParams","","","","","_navigationType"];
|
||||||
_stateParams params ["_lastRunTime", "_seekerStateParams", "_attackProfileStateParams", "_lastKnownPosState"];
|
_stateParams params ["_lastRunTime", "_seekerStateParams", "_attackProfileStateParams", "_lastKnownPosState", "_navigationParameters", "_guidanceParameters"];
|
||||||
|
_navigationStateParams params ["_currentState", "_navigationStateData"];
|
||||||
|
_flightParams params ["_pitchRate", "_yawRate", "_isBangBangGuidance", "_stabilityCoefficient", "_showTrail"];
|
||||||
|
|
||||||
if (!alive _projectile || isNull _projectile || isNull _shooter) exitWith {
|
if (!alive _projectile || isNull _projectile || isNull _shooter) exitWith {
|
||||||
[_pfID] call CBA_fnc_removePerFrameHandler;
|
[_pfID] call CBA_fnc_removePerFrameHandler;
|
||||||
END_COUNTER(guidancePFH);
|
END_COUNTER(guidancePFH);
|
||||||
};
|
};
|
||||||
|
|
||||||
private _runtimeDelta = diag_tickTime - _lastRunTime;
|
if (_showTrail) then {
|
||||||
private _adjustTime = 1;
|
drop [
|
||||||
|
"\a3\data_f\kouleSvetlo", "", "Billboard",
|
||||||
if (accTime > 0) then {
|
100,
|
||||||
_adjustTime = 1/accTime;
|
0.03,
|
||||||
_adjustTime = _adjustTime * (_runtimeDelta / TIMESTEP_FACTOR);
|
_projectile modelToWorld [0, 0, 0],
|
||||||
TRACE_4("Adjust timing",1/accTime,_adjustTime,_runtimeDelta,(_runtimeDelta / TIMESTEP_FACTOR));
|
[0, 0, 0],
|
||||||
} else {
|
0,
|
||||||
_adjustTime = 0;
|
1.25,
|
||||||
|
1,
|
||||||
|
0.05,
|
||||||
|
[0.5],
|
||||||
|
[TRAIL_COLOUR(1)],
|
||||||
|
[0],
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
-1,
|
||||||
|
[TRAIL_COLOUR(10000)]
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
private _minDeflection = ((_flightParams select 0) - ((_flightParams select 0) * _adjustTime)) max 0;
|
private _timestep = diag_deltaTime * accTime;
|
||||||
private _maxDeflection = (_flightParams select 1) * _adjustTime;
|
|
||||||
// private _incDeflection = _flightParams select 2; // todo
|
|
||||||
|
|
||||||
private _projectilePos = getPosASL _projectile;
|
|
||||||
|
|
||||||
// Run seeker function:
|
// Run seeker function:
|
||||||
private _seekerTargetPos = [[0,0,0], _args, _seekerStateParams, _lastKnownPosState] call FUNC(doSeekerSearch);
|
private _seekerTargetPos = [[0,0,0], _args, _seekerStateParams, _lastKnownPosState, _timestep] call FUNC(doSeekerSearch);
|
||||||
|
|
||||||
// Run attack profile function:
|
// Run attack profile function:
|
||||||
private _profileAdjustedTargetPos = [_seekerTargetPos, _args, _attackProfileStateParams] call FUNC(doAttackProfile);
|
_seekerTargetPos = AGLtoASL ASLToAGL _seekerTargetPos;
|
||||||
|
private _profileAdjustedTargetPos = [_seekerTargetPos, _args, _attackProfileStateParams, _timestep] call FUNC(doAttackProfile);
|
||||||
|
|
||||||
|
private _projectilePos = getPosASLVisual _projectile;
|
||||||
|
_targetData set [1, _projectilePos vectorFromTo _profileAdjustedTargetPos];
|
||||||
|
|
||||||
// If we have no seeker target, then do not change anything
|
// If we have no seeker target, then do not change anything
|
||||||
// If there is no deflection on the missile, this cannot change and therefore is redundant. Avoid calculations for missiles without any deflection
|
// If there is no deflection on the missile, this cannot change and therefore is redundant. Avoid calculations for missiles without any deflection
|
||||||
if ((_minDeflection != 0 || {_maxDeflection != 0}) && {_profileAdjustedTargetPos isNotEqualTo [0,0,0]}) then {
|
if ((_pitchRate != 0 || {_yawRate != 0})) then {
|
||||||
|
private _navigationFunction = getText (configFile >> QGVAR(NavigationTypes) >> _navigationType >> "functionName");
|
||||||
|
if (_navigationStateData isNotEqualTo []) then {
|
||||||
|
(_navigationStateData select _currentState) params ["_transitionCondition"];
|
||||||
|
private _transition = (_args call (missionNamespace getVariable [_transitionCondition, { false }]));
|
||||||
|
if (_transition) then {
|
||||||
|
_currentState = _currentState + 1;
|
||||||
|
_navigationStateParams set [0, _currentState];
|
||||||
|
};
|
||||||
|
|
||||||
private _targetVector = _projectilePos vectorFromTo _profileAdjustedTargetPos;
|
_navigationType = (_navigationStateData select _currentState) select 1;
|
||||||
private _adjustVector = _targetVector vectorDiff (vectorDir _projectile);
|
_navigationFunction = getText (configFile >> QGVAR(NavigationTypes) >> _navigationType >> "functionName");
|
||||||
_adjustVector params ["_adjustVectorX", "_adjustVectorY", "_adjustVectorZ"];
|
|
||||||
|
|
||||||
private _yaw = 0;
|
_navigationParameters = (_navigationStateData select _currentState) select 2;
|
||||||
private _pitch = 0;
|
_stateParams set [4, _navigationParameters];
|
||||||
private _roll = 0;
|
};
|
||||||
|
private _commandedAcceleration = [_args, _timestep, _seekerTargetPos, _profileAdjustedTargetPos, _targetData, _navigationParameters] call (missionNamespace getVariable _navigationFunction);
|
||||||
|
|
||||||
if (_adjustVectorX < 0) then {
|
if (isNil "_commandedAcceleration") exitWith {
|
||||||
_yaw = - ( (_minDeflection max ((abs _adjustVectorX) min _maxDeflection) ) );
|
systemChat format ["Error in %1 Missile Type %2 Seeker Pos %3", _navigationFunction, typeOf _projectile, _seekerTargetPos];
|
||||||
|
ERROR_MSG_3("_commandedAcceleration is nil! Guidance cancelled [%1 %2 %3]",_navigationFunction,typeOf _projectile,_seekerTargetPos);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (GVAR(debug_drawGuidanceInfo)) then {
|
||||||
|
private _projectilePosAGL = ASLToAGL _projectilePos;
|
||||||
|
private _cmdAccelLocal = _projectile vectorWorldToModelVisual _commandedAcceleration;
|
||||||
|
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [1,0,0,1], _projectilePosAGL vectorAdd [0, 0, 1], 0.75, 0.75, 0, format ["cmdPitch: %1 cmdYaw %2", _cmdAccelLocal#2, _cmdAccelLocal#0], 1, 0.025, "TahomaB"];
|
||||||
|
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [1,1,0,1], _projectilePosAGL vectorAdd [0, 0, 2], 0.75, 0.75, 0, _navigationType, 1, 0.025, "TahomaB"];
|
||||||
|
drawLine3D [_projectilePosAGL, _projectilePosAGL vectorAdd _commandedAcceleration, [1, 0, 1, 1]];
|
||||||
|
};
|
||||||
|
|
||||||
|
// activate missile servos and change direction
|
||||||
|
if (!isGamePaused && accTime > 0) then {
|
||||||
|
_guidanceParameters params ["_yaw", "_roll", "_pitch"];
|
||||||
|
|
||||||
|
_commandedAcceleration = _projectile vectorWorldToModelVisual _commandedAcceleration;
|
||||||
|
_commandedAcceleration params ["_yawChange", "", "_pitchChange"];
|
||||||
|
|
||||||
|
if (isNil "_yawChange") then {
|
||||||
|
_yawChange = 0;
|
||||||
|
};
|
||||||
|
if (isNil "_pitchChange") then {
|
||||||
|
_pitchChange = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
private _clampedPitch = (_pitchChange min _pitchRate) max -_pitchRate;
|
||||||
|
private _clampedYaw = (_yawChange min _yawRate) max -_yawRate;
|
||||||
|
|
||||||
|
// controls are either on or off, no proportional
|
||||||
|
if (_isBangBangGuidance) then {
|
||||||
|
private _pitchSign = if (_clampedPitch == 0) then {
|
||||||
|
0
|
||||||
} else {
|
} else {
|
||||||
if (_adjustVectorX > 0) then {
|
_clampedPitch / abs _clampedPitch
|
||||||
_yaw = ( (_minDeflection max (_adjustVectorX min _maxDeflection) ) );
|
|
||||||
};
|
};
|
||||||
};
|
private _yawSign = if (_clampedYaw == 0) then {
|
||||||
if (_adjustVectorY < 0) then {
|
0
|
||||||
_roll = - ( (_minDeflection max ((abs _adjustVectorY) min _maxDeflection) ) );
|
|
||||||
} else {
|
} else {
|
||||||
if (_adjustVectorY > 0) then {
|
_clampedYaw / abs _clampedYaw
|
||||||
_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);
|
|
||||||
};
|
};
|
||||||
|
_clampedPitch = _pitchSign * _pitchRate;
|
||||||
|
_clampedYaw = _yawSign * _yawRate;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef DRAW_GUIDANCE_INFO
|
TRACE_9("pitch/yaw/roll",_pitch,_yaw,_roll,_yawChange,_pitchChange,_pitchRate,_yawRate,_clampedPitch,_clampedYaw);
|
||||||
|
// directional stability
|
||||||
|
private _localVelocity = _projectile vectorWorldToModelVisual (velocity _projectile);
|
||||||
|
|
||||||
|
private _velocityAngleYaw = (_localVelocity#0) atan2 (_localVelocity#1);
|
||||||
|
private _velocityAnglePitch = (_localVelocity#2) atan2 (_localVelocity#1);
|
||||||
|
|
||||||
|
// bastardized version of direction stability https://en.wikipedia.org/wiki/Directional_stability#Steering_forces
|
||||||
|
private _forceYaw = _stabilityCoefficient * _velocityAngleYaw + _clampedYaw;
|
||||||
|
private _forcePitch = _stabilityCoefficient * _velocityAnglePitch + _clampedPitch;
|
||||||
|
|
||||||
|
_pitch = _pitch + _forcePitch * _timestep;
|
||||||
|
_yaw = _yaw + _forceYaw * _timestep;
|
||||||
|
|
||||||
|
TRACE_3("new pitch/yaw/roll",_pitch,_yaw,_roll);
|
||||||
|
|
||||||
|
private _multiplyQuat = {
|
||||||
|
params ["_qLHS", "_qRHS"];
|
||||||
|
_qLHS params ["_lhsX", "_lhsY", "_lhsZ", "_lhsW"];
|
||||||
|
_qRHS params ["_rhsX", "_rhsY", "_rhsZ", "_rhsW"];
|
||||||
|
|
||||||
|
private _lhsImaginary = [_lhsX, _lhsY, _lhsZ];
|
||||||
|
private _rhsImaginary = [_rhsX, _rhsY, _rhsZ];
|
||||||
|
|
||||||
|
private _scalar = _lhsW * _rhsW - (_lhsImaginary vectorDotProduct _rhsImaginary);
|
||||||
|
private _imginary = (_rhsImaginary vectorMultiply _lhsW) vectorAdd (_lhsImaginary vectorMultiply _rhsW) vectorAdd (_lhsImaginary vectorCrossProduct _rhsImaginary);
|
||||||
|
|
||||||
|
_imginary + [_scalar]
|
||||||
|
};
|
||||||
|
|
||||||
|
private _multiplyVector = {
|
||||||
|
params ["_quaternion", "_vector"];
|
||||||
|
|
||||||
|
private _real = _quaternion#3;
|
||||||
|
private _imaginary = [
|
||||||
|
_quaternion#0,
|
||||||
|
_quaternion#1,
|
||||||
|
_quaternion#2
|
||||||
|
];
|
||||||
|
|
||||||
|
private _vectorReturn = _vector vectorAdd ((
|
||||||
|
_imaginary vectorCrossProduct (
|
||||||
|
(_imaginary vectorCrossProduct _vector) vectorAdd (
|
||||||
|
_vector vectorMultiply _real
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) vectorMultiply 2);
|
||||||
|
|
||||||
|
_vectorReturn
|
||||||
|
};
|
||||||
|
|
||||||
|
private _quaternion = [0, 0, 0, 1];
|
||||||
|
|
||||||
|
private _temp = [0, 0, sin (-_yaw / 2), cos (-_yaw / 2)];
|
||||||
|
_quaternion = [_quaternion, _temp] call _multiplyQuat;
|
||||||
|
|
||||||
|
_temp = [sin (_pitch / 2), 0, 0, cos (_pitch / 2)];
|
||||||
|
_quaternion = [_quaternion, _temp] call _multiplyQuat;
|
||||||
|
|
||||||
|
private _dir = [_quaternion, [0, 1, 0]] call _multiplyVector;
|
||||||
|
private _up = [_quaternion, [0, 0, 1]] call _multiplyVector;
|
||||||
|
|
||||||
|
_projectile setVectorDirAndUp [_dir, _up];
|
||||||
|
|
||||||
|
//[_projectile, _pitch, _yaw, 0] call FUNC(changeMissileDirection);
|
||||||
|
|
||||||
|
_guidanceParameters set [0, _yaw];
|
||||||
|
_guidanceParameters set [2, _pitch];
|
||||||
|
|
||||||
|
_stateParams set [5, _guidanceParameters];
|
||||||
|
};
|
||||||
|
|
||||||
|
_stateParams set [4, _navigationParameters];
|
||||||
|
_args set [4, _stateParams];
|
||||||
|
};
|
||||||
|
|
||||||
|
if (GVAR(debug_drawGuidanceInfo)) then {
|
||||||
TRACE_3("",_projectilePos,_seekerTargetPos,_profileAdjustedTargetPos);
|
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"];
|
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"];
|
||||||
|
|
||||||
|
if (!isGamePaused && accTime > 0) then {
|
||||||
private _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 setParticleParams [["\A3\Data_f\cl_basic", 8, 3, 1], "", "Billboard", 1, 3.0141, [0, 0, 0], [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;
|
_PS setDropInterval 1.0;
|
||||||
#endif
|
};
|
||||||
|
|
||||||
|
drawLine3D [ASLtoAGL _projectilePos, (ASLtoAGL _projectilePos) vectorAdd velocity _projectile, [1, 1, 1, 1]];
|
||||||
|
};
|
||||||
|
|
||||||
_stateParams set [0, diag_tickTime];
|
_stateParams set [0, diag_tickTime];
|
||||||
|
|
||||||
END_COUNTER(guidancePFH);
|
END_COUNTER(guidancePFH);
|
||||||
|
|
||||||
|
35
addons/missileguidance/functions/fnc_line_onFired.sqf
Normal file
35
addons/missileguidance/functions/fnc_line_onFired.sqf
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#include "..\script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: tcvm
|
||||||
|
* Sets up line state arrays (called from missileGuidance's onFired).
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* Guidance Arg Array <ARRAY>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [] call ace_missileguidance_fnc_line_onFired
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
params ["_firedEH", "", "", "", "_stateParams"];
|
||||||
|
_firedEH params ["","","","","","","_projectile"];
|
||||||
|
|
||||||
|
private _ammoConfig = configOf _projectile;
|
||||||
|
private _p = getNumber (_ammoConfig >> QUOTE(ADDON) >> "lineGainP");
|
||||||
|
private _d = getNumber (_ammoConfig >> QUOTE(ADDON) >> "lineGainD");
|
||||||
|
private _correctionDistance = getNumber (_ammoConfig >> QUOTE(ADDON) >> "correctionDistance");
|
||||||
|
|
||||||
|
if (_correctionDistance == 0) then {
|
||||||
|
_correctionDistance = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
private _navigationParams = [
|
||||||
|
_p, 0, _d,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
_correctionDistance
|
||||||
|
];
|
||||||
|
_navigationParams
|
@ -10,7 +10,7 @@
|
|||||||
* None
|
* None
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* [] call ace_missileguidance_fnc_ahr_onFired
|
* [] call ace_missileguidance_fnc_mwr_onFired
|
||||||
*
|
*
|
||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
@ -38,6 +38,8 @@ private _activeRadarDistance = [_config >> "activeRadarEngageDistance", "NUMBER"
|
|||||||
private _projectileThrust = [_projectileConfig >> "thrust", "NUMBER", 0] call CBA_fnc_getConfigEntry;
|
private _projectileThrust = [_projectileConfig >> "thrust", "NUMBER", 0] call CBA_fnc_getConfigEntry;
|
||||||
private _projectileThrustTime = [_projectileConfig >> "thrustTime", "NUMBER", 0] call CBA_fnc_getConfigEntry;
|
private _projectileThrustTime = [_projectileConfig >> "thrustTime", "NUMBER", 0] call CBA_fnc_getConfigEntry;
|
||||||
|
|
||||||
|
private _lockTypes = [_config >> "lockableTypes", "ARRAY", ["Air", "LandVehicle", "Ship"]] call CBA_fnc_getConfigEntry;
|
||||||
|
|
||||||
private _velocityAtImpact = _projectileThrust * _projectileThrustTime;
|
private _velocityAtImpact = _projectileThrust * _projectileThrustTime;
|
||||||
private _timeToActive = 0;
|
private _timeToActive = 0;
|
||||||
if (!isNil "_target" && _velocityAtImpact > 0) then {
|
if (!isNil "_target" && _velocityAtImpact > 0) then {
|
||||||
@ -70,4 +72,4 @@ _seekerStateParams set [6, false];
|
|||||||
_seekerStateParams set [7, [0, 0, 0]];
|
_seekerStateParams set [7, [0, 0, 0]];
|
||||||
_seekerStateParams set [8, CBA_missionTime];
|
_seekerStateParams set [8, CBA_missionTime];
|
||||||
_seekerStateParams set [9, isNull _target];
|
_seekerStateParams set [9, isNull _target];
|
||||||
|
_seekerStateParams set [10, _lockTypes];
|
@ -0,0 +1,50 @@
|
|||||||
|
#include "..\script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: tcvm
|
||||||
|
* Determine path for projectile to take in accordance to proportional navigation, takes target acceleration into account
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* Guidance Arg Array <ARRAY>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* Commanded acceleration normal to LOS in world space <ARRAY>
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [] call ace_missileguidance_fnc_navigationType_augmentedProNav
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
params ["_args", "_timestep", "_seekerTargetPos", "_profileAdjustedTargetPos"];
|
||||||
|
_args params ["_firedEH", "", "", "", "_stateParams", "_targetData"];
|
||||||
|
_firedEH params ["","","","","","","_projectile"];
|
||||||
|
_stateParams params ["", "", "", "","_navigationParams"];
|
||||||
|
_navigationParams params ["_lastMissileFrame", "_navigationGain"];
|
||||||
|
_lastMissileFrame params ["_lastLineOfSight"];
|
||||||
|
_targetData params ["_targetDirection", "_attackProfileDirection", "", "_targetVelocity", "_targetAcceleration"];
|
||||||
|
|
||||||
|
// Proportional navigation implemented via "Fundamentals of proportional navigation" by Stephen Murtaugh and Harry Criel
|
||||||
|
private _closingVelocity = _targetVelocity vectorDiff velocity _projectile;
|
||||||
|
|
||||||
|
private _targetAccelerationProjected = _attackProfileDirection vectorMultiply (_targetAcceleration vectorDotProduct _attackProfileDirection);
|
||||||
|
_targetAcceleration = _targetAcceleration vectorDiff _targetAccelerationProjected;
|
||||||
|
|
||||||
|
private _losDelta = (vectorNormalized _attackProfileDirection) vectorDiff (vectorNormalized _lastLineOfSight);
|
||||||
|
private _losRate = if (_timestep == 0) then {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
1 * (vectorMagnitude _losDelta) / _timestep;
|
||||||
|
};
|
||||||
|
|
||||||
|
private _lateralAcceleration = _navigationGain * _losRate;
|
||||||
|
private _commandedAcceleration = _closingVelocity vectorMultiply _lateralAcceleration;
|
||||||
|
_commandedAcceleration = _commandedAcceleration vectorAdd (_losDelta vectorMultiply (0.5 * _navigationGain * vectorMagnitude _targetAcceleration));
|
||||||
|
|
||||||
|
// we need acceleration normal to our LOS
|
||||||
|
private _commandedAccelerationProjected = _attackProfileDirection vectorMultiply (_commandedAcceleration vectorDotProduct _attackProfileDirection);
|
||||||
|
_commandedAcceleration = _commandedAcceleration vectorDiff _commandedAccelerationProjected;
|
||||||
|
|
||||||
|
if (accTime > 0) then {
|
||||||
|
_navigationParams set [0, [_seekerTargetPos, _targetVelocity, _attackProfileDirection]];
|
||||||
|
};
|
||||||
|
|
||||||
|
_commandedAcceleration vectorMultiply _timestep
|
@ -0,0 +1,21 @@
|
|||||||
|
#include "..\script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: tcvm
|
||||||
|
* Points directly toward attack profile positon
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* Guidance Arg Array <ARRAY>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* Commanded acceleration normal to LOS in world space <ARRAY>
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [] call ace_missileguidance_fnc_navigationType_direct
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
params ["_args", "", "", "_profileAdjustedTargetPos"];
|
||||||
|
_args params ["_firedEH"];
|
||||||
|
_firedEH params ["","","","","","","_projectile"];
|
||||||
|
|
||||||
|
_profileAdjustedTargetPos vectorDiff getPosASLVisual _projectile
|
52
addons/missileguidance/functions/fnc_navigationType_line.sqf
Normal file
52
addons/missileguidance/functions/fnc_navigationType_line.sqf
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#include "..\script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: tcvm
|
||||||
|
* Assumes targetDir is pointing toward line we want to stay on
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* Guidance Arg Array <ARRAY>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* Commanded acceleration normal to LOS in world space <ARRAY>
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [] call ace_missileguidance_fnc_navigationType_line
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
params ["_args", "_timestep", "_seekerTargetPos", "_profileAdjustedTargetPos", "_targetData", "_navigationParams"];
|
||||||
|
_args params ["", "", "_flightParams"];
|
||||||
|
_targetData params ["", "_targetDir", "_distance"];
|
||||||
|
_flightParams params ["_pitchRate", "_yawRate"];
|
||||||
|
|
||||||
|
_navigationParams params ["_proportionalGain", "", "_derivativeGain", "_lastErrorX", "_lastErrorY", "_correctionDistance"];
|
||||||
|
private _relativeTargetDirection = [0, (velocityModelSpace _projectile) select 1, 0] vectorAdd (_projectile vectorWorldToModelVisual (_targetDir vectorMultiply _distance));
|
||||||
|
|
||||||
|
private _angleX = ((_relativeTargetDirection select 0) atan2 (_relativeTargetDirection select 1));
|
||||||
|
private _angleY = ((_relativeTargetDirection select 2) atan2 (_relativeTargetDirection select 1));
|
||||||
|
|
||||||
|
private _pX = _proportionalGain * _angleX;
|
||||||
|
private _dX = 0;
|
||||||
|
if (_timestep > 0) then {
|
||||||
|
_dX = _derivativeGain * (_angleX - _lastErrorX) / _timestep;
|
||||||
|
};
|
||||||
|
|
||||||
|
private _pY = _proportionalGain * _angleY;
|
||||||
|
private _dY = 0;
|
||||||
|
if (_timestep > 0) then {
|
||||||
|
_dY = _derivativeGain * (_angleY - _lastErrorY) / _timestep;
|
||||||
|
};
|
||||||
|
|
||||||
|
private _accelerationX = _pX + _dX;
|
||||||
|
private _accelerationY = _pY + _dY;
|
||||||
|
|
||||||
|
private _commandedAcceleration = [
|
||||||
|
_accelerationX,
|
||||||
|
0,
|
||||||
|
_accelerationY
|
||||||
|
];
|
||||||
|
|
||||||
|
_navigationParams set [3, _angleX];
|
||||||
|
_navigationParams set [4, _angleY];
|
||||||
|
|
||||||
|
_projectile vectorModelToWorldVisual _commandedAcceleration;
|
@ -0,0 +1,48 @@
|
|||||||
|
#include "..\script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: tcvm
|
||||||
|
* Accelerates toward LOS
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* Guidance Arg Array <ARRAY>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* Commanded acceleration normal to LOS in world space <ARRAY>
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [] call ace_missileguidance_fnc_navigationType_lineOfSight
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
params ["_args", "_timestep", "_seekerTargetPos", "_profileAdjustedTargetPos"];
|
||||||
|
_args params ["_firedEH", "", "", "", "_stateParams", "_targetData"];
|
||||||
|
_firedEH params ["","","","","","","_projectile"];
|
||||||
|
_stateParams params ["", "", "", "","_navigationParams"];
|
||||||
|
_navigationParams params ["_onLaunch"];
|
||||||
|
_onLaunch params ["_lastLineOfSight"];
|
||||||
|
_targetData params ["_targetDirection", "_attackProfileDirection", "", "_targetVelocity", ""];
|
||||||
|
|
||||||
|
// Semi-proportional navigation implemented via "Fundamentals of proportional navigation" by Stephen Murtaugh and Harry Criel
|
||||||
|
|
||||||
|
// the los rate is tiny, so we multiply by a constant of a power of ten to get more aggressive acceleration
|
||||||
|
// this is just due to how we measure our LOS delta, the vectors involved are _tiny_
|
||||||
|
private _losDelta = _attackProfileDirection vectorDiff _lastLineOfSight;
|
||||||
|
private _losRate = if (_timestep == 0) then {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
10 * (vectorMagnitude _losDelta) / _timestep;
|
||||||
|
};
|
||||||
|
|
||||||
|
private _closingVelocity = _targetVelocity vectorDiff (velocity _projectile);
|
||||||
|
|
||||||
|
private _commandedAcceleration = _closingVelocity vectorMultiply _losRate;
|
||||||
|
|
||||||
|
// we need acceleration normal to our LOS
|
||||||
|
private _commandedAccelerationProjected = _attackProfileDirection vectorMultiply (_commandedAcceleration vectorDotProduct _attackProfileDirection);
|
||||||
|
_commandedAcceleration = _commandedAcceleration vectorDiff _commandedAccelerationProjected;
|
||||||
|
|
||||||
|
if (accTime > 0) then {
|
||||||
|
_navigationParams set [0, [_attackProfileDirection]];
|
||||||
|
};
|
||||||
|
|
||||||
|
_targetDirection
|
@ -0,0 +1,46 @@
|
|||||||
|
#include "..\script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: tcvm
|
||||||
|
* Determine path for projectile to take in accordance to proportional navigation
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* Guidance Arg Array <ARRAY>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* Commanded acceleration normal to LOS in world space <ARRAY>
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [] call ace_missileguidance_fnc_navigationType_proNav
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
params ["_args", "_timestep", "_seekerTargetPos", "_profileAdjustedTargetPos"];
|
||||||
|
_args params ["_firedEH", "", "", "", "_stateParams", "_targetData"];
|
||||||
|
_firedEH params ["","","","","","","_projectile"];
|
||||||
|
_stateParams params ["", "", "", "","_navigationParams"];
|
||||||
|
_navigationParams params ["_lastMissileFrame", "_navigationGain"];
|
||||||
|
_lastMissileFrame params ["_lastLineOfSight"];
|
||||||
|
_targetData params ["_targetDirection", "_attackProfileDirection", "", "_targetVelocity", ""];
|
||||||
|
|
||||||
|
// Proportional navigation implemented via "Fundamentals of proportional navigation" by Stephen Murtaugh and Harry Criel
|
||||||
|
private _closingVelocity = _targetVelocity vectorDiff velocity _projectile;
|
||||||
|
|
||||||
|
private _losDelta = (vectorNormalized _attackProfileDirection) vectorDiff (vectorNormalized _lastLineOfSight);
|
||||||
|
private _losRate = if (_timestep == 0) then {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
1 * (vectorMagnitude _losDelta) / _timestep;
|
||||||
|
};
|
||||||
|
|
||||||
|
private _lateralAcceleration = _navigationGain * _losRate;
|
||||||
|
private _commandedAcceleration = _closingVelocity vectorMultiply _lateralAcceleration;
|
||||||
|
|
||||||
|
// we need acceleration normal to our LOS
|
||||||
|
private _commandedAccelerationProjected = _attackProfileDirection vectorMultiply (_commandedAcceleration vectorDotProduct _attackProfileDirection);
|
||||||
|
_commandedAcceleration = _commandedAcceleration vectorDiff _commandedAccelerationProjected;
|
||||||
|
|
||||||
|
if (accTime > 0) then {
|
||||||
|
_navigationParams set [0, [_seekerTargetPos, _targetVelocity, _attackProfileDirection]];
|
||||||
|
};
|
||||||
|
|
||||||
|
_commandedAcceleration vectorMultiply _timestep
|
@ -0,0 +1,38 @@
|
|||||||
|
#include "..\script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: tcvm
|
||||||
|
* Determine path for projectile to take in accordance to zero-effort miss pro-nav, takes target acceleration into account. Super deadly
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* Guidance Arg Array <ARRAY>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* Commanded acceleration normal to LOS in world space <ARRAY>
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [] call ace_missileguidance_fnc_navigationType_zeroEffortMiss
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
params ["_args", "_timestep", "_seekerTargetPos", "_profileAdjustedTargetPos"];
|
||||||
|
_args params ["_firedEH", "", "", "", "_stateParams", "_targetData"];
|
||||||
|
_firedEH params ["","","","","","","_projectile"];
|
||||||
|
_stateParams params ["", "", "", "","_navigationParams"];
|
||||||
|
_navigationParams params ["", "_navigationGain"];
|
||||||
|
_targetData params ["_targetDirection", "_attackProfileDirection", "_targetRange", "_targetVelocity", "_targetAcceleration"];
|
||||||
|
|
||||||
|
private _vectorToTarget = _attackProfileDirection vectorMultiply _targetRange;
|
||||||
|
private _closingVelocity = _targetVelocity vectorDiff velocity _projectile;
|
||||||
|
private _timeToGo = _targetRange / vectorMagnitude _closingVelocity;
|
||||||
|
|
||||||
|
if (_timeToGo == 0) then {
|
||||||
|
_timeToGo = 0.001;
|
||||||
|
};
|
||||||
|
|
||||||
|
private _zeroEffortMiss = _vectorToTarget vectorAdd (_closingVelocity vectorMultiply _timeToGo);
|
||||||
|
private _zeroEffortMissProjectiled = _attackProfileDirection vectorMultiply (_zeroEffortMiss vectorDotProduct _attackProfileDirection);
|
||||||
|
private _zeroEffortMissNormal = _zeroEffortMiss vectorDiff _zeroEffortMissProjectiled;
|
||||||
|
|
||||||
|
private _commandedAcceleration = _zeroEffortMissNormal vectorMultiply (_navigationGain / (_timeToGo * _timeToGo));
|
||||||
|
|
||||||
|
_commandedAcceleration
|
@ -19,9 +19,6 @@
|
|||||||
|
|
||||||
params ["_shooter","_weapon","","_mode","_ammo","","_projectile"];
|
params ["_shooter","_weapon","","_mode","_ammo","","_projectile"];
|
||||||
|
|
||||||
// Bail on not missile
|
|
||||||
if !(_ammo isKindOf "MissileBase") exitWith {};
|
|
||||||
|
|
||||||
// Bail if guidance is disabled for this ammo
|
// Bail if guidance is disabled for this ammo
|
||||||
if ((getNumber (configFile >> "CfgAmmo" >> _ammo >> QUOTE(ADDON) >> "enabled")) != 1) exitWith {};
|
if ((getNumber (configFile >> "CfgAmmo" >> _ammo >> QUOTE(ADDON) >> "enabled")) != 1) exitWith {};
|
||||||
|
|
||||||
@ -44,6 +41,7 @@ private _target = _shooter getVariable [QGVAR(target), nil];
|
|||||||
private _targetPos = _shooter getVariable [QGVAR(targetPosition), nil];
|
private _targetPos = _shooter getVariable [QGVAR(targetPosition), nil];
|
||||||
private _seekerType = _shooter getVariable [QGVAR(seekerType), nil];
|
private _seekerType = _shooter getVariable [QGVAR(seekerType), nil];
|
||||||
private _attackProfile = _shooter getVariable [QGVAR(attackProfile), nil];
|
private _attackProfile = _shooter getVariable [QGVAR(attackProfile), nil];
|
||||||
|
private _navigationType = _shooter getVariable [QGVAR(navigationType), nil];
|
||||||
if ((getNumber (configFile >> "CfgAmmo" >> _ammo >> QUOTE(ADDON) >> "useModeForAttackProfile")) == 1) then {
|
if ((getNumber (configFile >> "CfgAmmo" >> _ammo >> QUOTE(ADDON) >> "useModeForAttackProfile")) == 1) then {
|
||||||
_attackProfile = getText (configFile >> "CfgWeapons" >> _weapon >> _mode >> QGVAR(attackProfile))
|
_attackProfile = getText (configFile >> "CfgWeapons" >> _weapon >> _mode >> QGVAR(attackProfile))
|
||||||
};
|
};
|
||||||
@ -52,7 +50,7 @@ private _lockMode = _shooter getVariable [QGVAR(lockMode), nil];
|
|||||||
private _laserCode = _shooter getVariable [QEGVAR(laser,code), ACE_DEFAULT_LASER_CODE];
|
private _laserCode = _shooter getVariable [QEGVAR(laser,code), ACE_DEFAULT_LASER_CODE];
|
||||||
private _laserInfo = [_laserCode, ACE_DEFAULT_LASER_WAVELENGTH, ACE_DEFAULT_LASER_WAVELENGTH];
|
private _laserInfo = [_laserCode, ACE_DEFAULT_LASER_WAVELENGTH, ACE_DEFAULT_LASER_WAVELENGTH];
|
||||||
|
|
||||||
TRACE_6("getVars",_target,_targetPos,_seekerType,_attackProfile,_lockMode,_laserCode);
|
TRACE_7("getVars",_target,_targetPos,_seekerType,_attackProfile,_lockMode,_laserCode,_navigationType);
|
||||||
|
|
||||||
private _launchPos = getPosASL (vehicle _shooter);
|
private _launchPos = getPosASL (vehicle _shooter);
|
||||||
|
|
||||||
@ -65,6 +63,14 @@ if (isNil "_attackProfile" || {!(_attackProfile in (getArray (_config >> "attack
|
|||||||
if (isNil "_lockMode" || {!(_lockMode in (getArray (_config >> "seekerLockModes")))}) then {
|
if (isNil "_lockMode" || {!(_lockMode in (getArray (_config >> "seekerLockModes")))}) then {
|
||||||
_lockMode = getText (_config >> "defaultSeekerLockMode");
|
_lockMode = getText (_config >> "defaultSeekerLockMode");
|
||||||
};
|
};
|
||||||
|
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";
|
||||||
|
};
|
||||||
|
|
||||||
// If we didn't get a target, try to fall back on tab locking
|
// If we didn't get a target, try to fall back on tab locking
|
||||||
if (isNil "_target") then {
|
if (isNil "_target") then {
|
||||||
@ -76,7 +82,7 @@ if (isNil "_target") then {
|
|||||||
private _canUseLock = getNumber (_config >> "canVanillaLock");
|
private _canUseLock = getNumber (_config >> "canVanillaLock");
|
||||||
// @TODO: Get vanilla target
|
// @TODO: Get vanilla target
|
||||||
if (_canUseLock > 0 || difficulty < 1) then {
|
if (_canUseLock > 0 || difficulty < 1) then {
|
||||||
private _vanillaTarget = cursorTarget;
|
private _vanillaTarget = missileTarget _projectile;
|
||||||
|
|
||||||
TRACE_1("Using Vanilla Locking",_vanillaTarget);
|
TRACE_1("Using Vanilla Locking",_vanillaTarget);
|
||||||
if (!isNil "_vanillaTarget") then {
|
if (!isNil "_vanillaTarget") then {
|
||||||
@ -85,6 +91,7 @@ if (isNil "_target") then {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
_targetPos = getPosASLVisual _target;
|
||||||
|
|
||||||
// Array for seek last target position
|
// Array for seek last target position
|
||||||
private _seekLastTargetPos = (getNumber ( _config >> "seekLastTargetPos")) == 1;
|
private _seekLastTargetPos = (getNumber ( _config >> "seekLastTargetPos")) == 1;
|
||||||
@ -95,19 +102,66 @@ if (_seekLastTargetPos && {!isNil "_target"}) then {
|
|||||||
_lastKnownPosState set [1, [0,0,0]];
|
_lastKnownPosState set [1, [0,0,0]];
|
||||||
};
|
};
|
||||||
|
|
||||||
TRACE_4("Beginning ACE guidance system",_target,_ammo,_seekerType,_attackProfile);
|
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);
|
||||||
private _args = [_this,
|
private _args = [_this,
|
||||||
[ _shooter,
|
[ _shooter,
|
||||||
[_target, _targetPos, _launchPos],
|
[_target, _targetPos, _launchPos, vectorDirVisual vehicle _shooter, CBA_missionTime],
|
||||||
_seekerType,
|
_seekerType,
|
||||||
_attackProfile,
|
_attackProfile,
|
||||||
_lockMode,
|
_lockMode,
|
||||||
_laserInfo
|
_laserInfo,
|
||||||
|
_navigationType
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
getNumber ( _config >> "minDeflection" ),
|
_pitchRate,
|
||||||
getNumber ( _config >> "maxDeflection" ),
|
_yawRate,
|
||||||
getNumber ( _config >> "incDeflection" )
|
_bangBang,
|
||||||
|
_stabilityCoefficient,
|
||||||
|
_showTrail
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
getNumber ( _config >> "seekerAngle" ),
|
getNumber ( _config >> "seekerAngle" ),
|
||||||
@ -115,38 +169,71 @@ private _args = [_this,
|
|||||||
getNumber ( _config >> "seekerMaxRange" ),
|
getNumber ( _config >> "seekerMaxRange" ),
|
||||||
getNumber ( _config >> "seekerMinRange" )
|
getNumber ( _config >> "seekerMinRange" )
|
||||||
],
|
],
|
||||||
[ diag_tickTime, [], [], _lastKnownPosState]
|
[ 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]
|
||||||
];
|
];
|
||||||
|
|
||||||
private _onFiredFunc = getText (configFile >> QGVAR(SeekerTypes) >> _seekerType >> "onFired");
|
private _onFiredFunc = getText (configFile >> QGVAR(SeekerTypes) >> _seekerType >> "onFired");
|
||||||
TRACE_1("",_onFiredFunc);
|
TRACE_1("seeker on fired",_onFiredFunc);
|
||||||
if (_onFiredFunc != "") then {
|
if (_onFiredFunc != "") then {
|
||||||
_args call (missionNamespace getVariable _onFiredFunc);
|
_args call (missionNamespace getVariable _onFiredFunc);
|
||||||
};
|
};
|
||||||
|
|
||||||
_onFiredFunc = getText (configFile >> QGVAR(AttackProfiles) >> _attackProfile >> "onFired");
|
_onFiredFunc = getText (configFile >> QGVAR(AttackProfiles) >> _attackProfile >> "onFired");
|
||||||
TRACE_1("",_onFiredFunc);
|
TRACE_1("attack on fired",_onFiredFunc);
|
||||||
if (_onFiredFunc != "") then {
|
if (_onFiredFunc != "") then {
|
||||||
_args call (missionNamespace getVariable _onFiredFunc);
|
_args call (missionNamespace getVariable _onFiredFunc);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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");
|
||||||
|
};
|
||||||
|
|
||||||
// Run the "onFired" function passing the full guidance args array
|
// Run the "onFired" function passing the full guidance args array
|
||||||
_onFiredFunc = getText (_config >> "onFired");
|
_onFiredFunc = getText (_config >> "onFired");
|
||||||
TRACE_1("",_onFiredFunc);
|
TRACE_1("general on fired",_onFiredFunc);
|
||||||
if (_onFiredFunc != "") then {
|
if (_onFiredFunc != "") then {
|
||||||
_args call (missionNamespace getVariable _onFiredFunc);
|
_args call (missionNamespace getVariable _onFiredFunc);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Reverse:
|
// Reverse:
|
||||||
// _args params ["_firedEH", "_launchParams", "_flightParams", "_seekerParams", "_stateParams"];
|
// _args params ["_firedEH", "_launchParams", "_flightParams", "_seekerParams", "_stateParams", "_targetData", "_navigationStateData"];
|
||||||
// _firedEH params ["_shooter","","","","_ammo","","_projectile"];
|
// _firedEH params ["_shooter","","","","_ammo","","_projectile"];
|
||||||
// _launchParams params ["_shooter","_targetLaunchParams","_seekerType","_attackProfile","_lockMode","_laserInfo"];
|
// _launchParams params ["_shooter","_targetLaunchParams","_seekerType","_attackProfile","_lockMode","_laserInfo","_navigationType"];
|
||||||
// _targetLaunchParams params ["_target", "_targetPos", "_launchPos"];
|
// _targetLaunchParams params ["_target", "_targetPos", "_launchPos", "_launchDir", "_launchTime"];
|
||||||
// _stateParams params ["_lastRunTime", "_seekerStateParams", "_attackProfileStateParams", "_lastKnownPosState"];
|
// _flightParams params ["_pitchRate", "_yawRate", "_isBangBangGuidance"];
|
||||||
|
// _stateParams params ["_lastRunTime", "_seekerStateParams", "_attackProfileStateParams", "_lastKnownPosState", "_navigationParams", "_guidanceParameters"];
|
||||||
// _seekerParams params ["_seekerAngle", "_seekerAccuracy", "_seekerMaxRange", "_seekerMinRange"];
|
// _seekerParams params ["_seekerAngle", "_seekerAccuracy", "_seekerMaxRange", "_seekerMinRange"];
|
||||||
|
// _targetData params ["_targetDirection", "_attackProfileDirection", "_targetRange", "_targetVelocity", "_targetAcceleration"];
|
||||||
|
|
||||||
[LINKFUNC(guidancePFH),0, _args ] call CBA_fnc_addPerFrameHandler;
|
[LINKFUNC(guidancePFH),0, _args ] call CBA_fnc_addPerFrameHandler;
|
||||||
|
|
||||||
|
if (GVAR(debug_enableMissileCamera)) then {
|
||||||
|
[_projectile] call FUNC(dev_ProjectileCamera);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Clears locking settings
|
/* Clears locking settings
|
||||||
(vehicle _shooter) setVariable [QGVAR(target), nil];
|
(vehicle _shooter) setVariable [QGVAR(target), nil];
|
||||||
|
36
addons/missileguidance/functions/fnc_proNav_onFired.sqf
Normal file
36
addons/missileguidance/functions/fnc_proNav_onFired.sqf
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#include "..\script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: tcvm
|
||||||
|
* Sets up proportional navigation state arrays (called from missileGuidance's onFired).
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* Guidance Arg Array <ARRAY>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [] call ace_missileguidance_fnc_proNav_onFired
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
params ["_firedEH", "", "", "", "_stateParams"];
|
||||||
|
_firedEH params ["_shooter","","","","_ammo","","_projectile"];
|
||||||
|
_launchParams params ["_shooter","_targetLaunchParams","_seekerType","_attackProfile","_lockMode","_laserInfo","_navigationType"];
|
||||||
|
_targetLaunchParams params ["_target", "_targetPos", "_launchPos"];
|
||||||
|
_stateParams params ["_lastRunTime", "_seekerStateParams", "_attackProfileStateParams", "_lastKnownPosState"];
|
||||||
|
_seekerParams params ["_seekerAngle", "_seekerAccuracy", "_seekerMaxRange", "_seekerMinRange"];
|
||||||
|
|
||||||
|
private _ammoConfig = configOf _projectile;
|
||||||
|
private _navigationGain = getNumber (_ammoConfig >> QUOTE(ADDON) >> "navigationGain");
|
||||||
|
if (_navigationGain == 0) then {
|
||||||
|
_navigationGain = 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
private _navigationParams = [
|
||||||
|
[ // Last Missile Frame
|
||||||
|
[0, 0, 0] // Last line of sight
|
||||||
|
],
|
||||||
|
_navigationGain // navigation gain of missile. Set in the navigation onFired function
|
||||||
|
];
|
||||||
|
_navigationParams
|
@ -11,16 +11,16 @@
|
|||||||
* Seeker Pos <ARRAY>
|
* Seeker Pos <ARRAY>
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* [] call call ace_missileguidance_fnc_seekerType_ARH;
|
* [] call call ace_missileguidance_fnc_seekerType_MWR;
|
||||||
*
|
*
|
||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
params ["", "_args", "_seekerStateParams"];
|
params ["", "_args", "_seekerStateParams", "", "_timestep"];
|
||||||
_args params ["_firedEH", "_launchParams", "", "_seekerParams", "_stateParams"];
|
_args params ["_firedEH", "_launchParams", "", "_seekerParams", "_stateParams", "_targetData"];
|
||||||
_firedEH params ["_shooter","","","","","","_projectile"];
|
_firedEH params ["_shooter","","","","","","_projectile"];
|
||||||
_launchParams params ["_target","","","",""];
|
_launchParams params ["_target","","","",""];
|
||||||
_seekerParams params ["_seekerAngle", "", "_seekerMaxRange"];
|
_seekerParams params ["_seekerAngle", "", "_seekerMaxRange"];
|
||||||
_seekerStateParams params ["_isActive", "_activeRadarEngageDistance", "_timeWhenActive", "_expectedTargetPos", "_lastTargetPollTime", "_shooterHasRadar", "_wasActive", "_lastKnownVelocity", "_lastTimeSeen", "_doesntHaveTarget"];
|
_seekerStateParams params ["_isActive", "_activeRadarEngageDistance", "_timeWhenActive", "_expectedTargetPos", "_lastTargetPollTime", "_shooterHasRadar", "_wasActive", "_lastKnownVelocity", "_lastTimeSeen", "_doesntHaveTarget", "_lockTypes"];
|
||||||
|
|
||||||
if (_isActive || { CBA_missionTime >= _timeWhenActive }) then {
|
if (_isActive || { CBA_missionTime >= _timeWhenActive }) then {
|
||||||
if !(_isActive) then {
|
if !(_isActive) then {
|
||||||
@ -60,8 +60,7 @@ if (_isActive || { CBA_missionTime >= _timeWhenActive }) then {
|
|||||||
_seekerBaseRadiusAdjusted = _seekerBaseRadiusAtGround;
|
_seekerBaseRadiusAdjusted = _seekerBaseRadiusAtGround;
|
||||||
};
|
};
|
||||||
// Look in front of seeker for any targets
|
// Look in front of seeker for any targets
|
||||||
private _nearestObjects = nearestObjects [ASLtoAGL _searchPos, ["Air", "LandVehicle", "Ship"], _seekerBaseRadiusAdjusted, false];
|
private _nearestObjects = nearestObjects [ASLtoAGL _searchPos, _lockTypes, _seekerBaseRadiusAdjusted, false];
|
||||||
|
|
||||||
_nearestObjects = _nearestObjects apply {
|
_nearestObjects = _nearestObjects apply {
|
||||||
// I check both Line of Sight versions to make sure that a single bush doesnt make the target lock dissapear but at the same time ensure that this can see through smoke. Should work 80% of the time
|
// I check both Line of Sight versions to make sure that a single bush doesnt make the target lock dissapear but at the same time ensure that this can see through smoke. Should work 80% of the time
|
||||||
if ([_projectile, getPosASL _x, _seekerAngle] call FUNC(checkSeekerAngle) && { ([_projectile, _x, true] call FUNC(checkLOS)) || { ([_projectile, _x, false] call FUNC(checkLOS)) } }) then {
|
if ([_projectile, getPosASL _x, _seekerAngle] call FUNC(checkSeekerAngle) && { ([_projectile, _x, true] call FUNC(checkLOS)) || { ([_projectile, _x, false] call FUNC(checkLOS)) } }) then {
|
||||||
@ -74,6 +73,7 @@ if (_isActive || { CBA_missionTime >= _timeWhenActive }) then {
|
|||||||
// Select closest object to the expected position to be the current radar target
|
// Select closest object to the expected position to be the current radar target
|
||||||
if (_nearestObjects isEqualTo []) exitWith {
|
if (_nearestObjects isEqualTo []) exitWith {
|
||||||
_projectile setMissileTarget objNull;
|
_projectile setMissileTarget objNull;
|
||||||
|
_seekerStateParams set [3, _searchPos];
|
||||||
_searchPos
|
_searchPos
|
||||||
};
|
};
|
||||||
private _closestDistance = _seekerBaseRadiusAtGround;
|
private _closestDistance = _seekerBaseRadiusAtGround;
|
||||||
@ -89,9 +89,9 @@ if (_isActive || { CBA_missionTime >= _timeWhenActive }) then {
|
|||||||
|
|
||||||
_projectile setMissileTarget _target;
|
_projectile setMissileTarget _target;
|
||||||
} else {
|
} else {
|
||||||
#ifdef DRAW_GUIDANCE_INFO
|
if (GVAR(debug_drawGuidanceInfo)) then {
|
||||||
_seekerTypeName = "AHR - EXT";
|
_seekerTypeName = "MWR - EXT";
|
||||||
#endif
|
};
|
||||||
// External radar homing
|
// External radar homing
|
||||||
// if the target is in the remote targets for the side, whoever the donor is will "datalink" the target for the hellfire.
|
// if the target is in the remote targets for the side, whoever the donor is will "datalink" the target for the hellfire.
|
||||||
private _remoteTargets = listRemoteTargets side _shooter;
|
private _remoteTargets = listRemoteTargets side _shooter;
|
||||||
@ -104,16 +104,30 @@ if (_isActive || { CBA_missionTime >= _timeWhenActive }) then {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (GVAR(debug_drawGuidanceInfo)) then {
|
||||||
|
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [1,0,0,1], ASLtoAGL _expectedTargetPos, 0.75, 0.75, 0, "expected target pos", 1, 0.025, "TahomaB"];
|
||||||
|
};
|
||||||
|
|
||||||
if !(isNull _target) then {
|
if !(isNull _target) then {
|
||||||
private _centerOfObject = getCenterOfMass _target;
|
private _centerOfObject = getCenterOfMass _target;
|
||||||
private _targetAdjustedPos = _target modelToWorldWorld _centerOfObject;
|
private _targetAdjustedPos = _target modelToWorldVisualWorld _centerOfObject;
|
||||||
_expectedTargetPos = _targetAdjustedPos;
|
_expectedTargetPos = _targetAdjustedPos;
|
||||||
|
|
||||||
_seekerStateParams set [3, _expectedTargetPos];
|
|
||||||
_seekerStateParams set [7, velocity _target];
|
_seekerStateParams set [7, velocity _target];
|
||||||
_seekerStateParams set [8, CBA_missionTime];
|
_seekerStateParams set [8, CBA_missionTime];
|
||||||
_seekerStateParams set [9, false];
|
_seekerStateParams set [9, false];
|
||||||
|
|
||||||
|
_targetData set [2, _projectile distance _target];
|
||||||
|
_targetData set [3, velocity _target];
|
||||||
|
|
||||||
|
if (_timestep != 0) then {
|
||||||
|
private _acceleration = ((velocity _target) vectorDiff _lastKnownVelocity) vectorMultiply (1 / _timestep);
|
||||||
|
_targetData set [4, _acceleration];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_targetData set [0, (getPosASLVisual _projectile) vectorFromTo _expectedTargetPos];
|
||||||
|
|
||||||
|
_seekerStateParams set [3, _expectedTargetPos];
|
||||||
_launchParams set [0, _target];
|
_launchParams set [0, _target];
|
||||||
_expectedTargetPos
|
_expectedTargetPos
|
@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
params ["", "_args"];
|
params ["", "_args"];
|
||||||
_args params ["_firedEH", "_launchParams", "", "_seekerParams", "_stateParams"];
|
_args params ["_firedEH", "_launchParams", "", "_seekerParams", "_stateParams", "_targetData"];
|
||||||
_firedEH params ["","","","","","","_projectile"];
|
_firedEH params ["","","","","","","_projectile"];
|
||||||
_launchParams params ["", "_targetParams"];
|
_launchParams params ["", "_targetParams"];
|
||||||
_targetParams params ["_target"];
|
_targetParams params ["_target"];
|
||||||
@ -25,7 +25,7 @@ _seekerParams params ["_seekerAngle", "", "_seekerMaxRange"];
|
|||||||
|
|
||||||
if (isNil "_target") exitWith {[0,0,0]};
|
if (isNil "_target") exitWith {[0,0,0]};
|
||||||
|
|
||||||
private _foundTargetPos = aimPos _target;
|
private _foundTargetPos = _target modelToWorldVisualWorld getCenterOfMass _target;
|
||||||
|
|
||||||
// @TODO: This is seeker LOS and angle checks for LOAL only; LOBL does not need visual
|
// @TODO: This is seeker LOS and angle checks for LOAL only; LOBL does not need visual
|
||||||
private _angleOkay = [_projectile, _foundTargetPos, _seekerAngle] call FUNC(checkSeekerAngle);
|
private _angleOkay = [_projectile, _foundTargetPos, _seekerAngle] call FUNC(checkSeekerAngle);
|
||||||
@ -40,14 +40,11 @@ TRACE_2("",_angleOkay,_losOkay);
|
|||||||
if (!_angleOkay || !_losOkay) exitWith {[0,0,0]};
|
if (!_angleOkay || !_losOkay) exitWith {[0,0,0]};
|
||||||
|
|
||||||
TRACE_2("",_target,_foundTargetPos);
|
TRACE_2("",_target,_foundTargetPos);
|
||||||
// @TODO: Configurable lead for seekers
|
|
||||||
private _projectileSpeed = (vectorMagnitude velocity _projectile);
|
|
||||||
private _distanceToTarget = (getPosASL _projectile) vectorDistance _foundTargetPos;
|
private _distanceToTarget = (getPosASL _projectile) vectorDistance _foundTargetPos;
|
||||||
private _eta = _distanceToTarget / _projectileSpeed;
|
|
||||||
|
|
||||||
private _adjustDistance = (velocity _target) vectorMultiply _eta;
|
_targetData set [0, (getPosASL _projectile) vectorFromTo _foundTargetPos];
|
||||||
TRACE_3("leading target",_distanceToTarget,_eta,_adjustDistance);
|
_targetData set [2, _distanceToTarget];
|
||||||
_foundTargetPos = _foundTargetPos vectorAdd _adjustDistance;
|
_targetData set [3, velocity _target];
|
||||||
|
|
||||||
TRACE_2("return",_foundTargetPos,(aimPos _target) distance _foundTargetPos);
|
TRACE_2("return",_foundTargetPos,(aimPos _target) distance _foundTargetPos);
|
||||||
_foundTargetPos;
|
_foundTargetPos;
|
||||||
|
@ -16,13 +16,13 @@
|
|||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
params ["", "_args"];
|
params ["", "_args"];
|
||||||
_args params ["_firedEH", "", "", "_seekerParams", "_stateParams"];
|
_args params ["_firedEH", "", "", "_seekerParams", "_stateParams", "_targetData"];
|
||||||
_firedEH params ["_shooter","_weapon","","","","","_projectile"];
|
_firedEH params ["_shooter","_weapon","","","","","_projectile"];
|
||||||
_seekerParams params ["_seekerAngle"];
|
_seekerParams params ["_seekerAngle"];
|
||||||
_stateParams params ["", "_seekerStateParams"];
|
_stateParams params ["", "_seekerStateParams"];
|
||||||
_seekerStateParams params ["_memoryPointGunnerOptics", "_animationSourceBody", "_animationSourceGun", "_usePilotCamera"];
|
_seekerStateParams params ["_memoryPointGunnerOptics", "_animationSourceBody", "_animationSourceGun", "_usePilotCamera"];
|
||||||
|
|
||||||
private _shooterPos = AGLToASL (_shooter modelToWorld(_shooter selectionPosition _memoryPointGunnerOptics));
|
private _shooterPos = AGLToASL (_shooter modelToWorldVisual (_shooter selectionPosition _memoryPointGunnerOptics));
|
||||||
private _projPos = getPosASL _projectile;
|
private _projPos = getPosASL _projectile;
|
||||||
|
|
||||||
private _lookDirection = if !(_shooter isKindOf "CAManBase" || {_shooter isKindOf "StaticWeapon"}) then {
|
private _lookDirection = if !(_shooter isKindOf "CAManBase" || {_shooter isKindOf "StaticWeapon"}) then {
|
||||||
@ -37,8 +37,9 @@ private _lookDirection = if !(_shooter isKindOf "CAManBase" || {_shooter isKindO
|
|||||||
_shooter vectorModelToWorldVisual getPilotCameraDirection _shooter;
|
_shooter vectorModelToWorldVisual getPilotCameraDirection _shooter;
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
private _gBody = -deg(_shooter animationPhase _animationSourceBody);
|
// use animationSourcePhase
|
||||||
private _gGun = deg(_shooter animationPhase _animationSourceGun);
|
private _gBody = -deg(_shooter animationSourcePhase _animationSourceBody);
|
||||||
|
private _gGun = deg(_shooter animationSourcePhase _animationSourceGun);
|
||||||
_shooter vectorModelToWorldVisual ([1, _gBody, _gGun] call CBA_fnc_polar2vect);
|
_shooter vectorModelToWorldVisual ([1, _gBody, _gGun] call CBA_fnc_polar2vect);
|
||||||
};
|
};
|
||||||
_finalLookDirection
|
_finalLookDirection
|
||||||
@ -58,5 +59,9 @@ if ((_testDotProduct < (cos _seekerAngle)) || {_testIntersections isNotEqualTo [
|
|||||||
[0, 0, 0]
|
[0, 0, 0]
|
||||||
};
|
};
|
||||||
|
|
||||||
_shooterPos vectorAdd (_lookDirection vectorMultiply _distanceToProj);
|
private _returnPos = _shooterPos vectorAdd (_lookDirection vectorMultiply _distanceToProj);
|
||||||
|
|
||||||
|
_targetData set [0, _projPos vectorFromTo _returnPos];
|
||||||
|
_targetData set [2, _returnPos vectorDistance getPosASLVisual _projectile];
|
||||||
|
|
||||||
|
_returnPos
|
||||||
|
@ -16,17 +16,58 @@
|
|||||||
*
|
*
|
||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
|
#define MAX_AVERAGES 15
|
||||||
|
#define MINIMUM_DISTANCE_UNTIL_NEW_POS 1
|
||||||
|
|
||||||
params ["", "_args"];
|
params ["", "_args", "", "", "_timestep"];
|
||||||
_args params ["_firedEH", "_launchParams", "", "_seekerParams"];
|
_args params ["_firedEH", "_launchParams", "", "_seekerParams", "", "_targetData"];
|
||||||
_firedEH params ["","","","","","","_projectile"];
|
_firedEH params ["","","","","","","_projectile"];
|
||||||
_launchParams params ["","","","","","_laserParams"];
|
_launchParams params ["","","","","","_laserParams"];
|
||||||
_seekerParams params ["_seekerAngle", "", "_seekerMaxRange"];
|
_seekerParams params ["_seekerAngle", "", "_seekerMaxRange", "", ["_lastPositions", []], ["_lastPositionIndex", 0], ["_lastPositionSum", [0, 0, 0]]];
|
||||||
_laserParams params ["_code", "_wavelengthMin", "_wavelengthMax"];
|
_laserParams params ["_code", "_wavelengthMin", "_wavelengthMax"];
|
||||||
|
|
||||||
|
|
||||||
private _laserResult = [(getPosASL _projectile), (velocity _projectile), _seekerAngle, _seekerMaxRange, [_wavelengthMin, _wavelengthMax], _code, _projectile] call EFUNC(laser,seekerFindLaserSpot);
|
private _laserResult = [(getPosASL _projectile), (velocity _projectile), _seekerAngle, _seekerMaxRange, [_wavelengthMin, _wavelengthMax], _code, _projectile] call EFUNC(laser,seekerFindLaserSpot);
|
||||||
private _foundTargetPos = _laserResult select 0;
|
private _foundTargetPos = _laserResult select 0;
|
||||||
TRACE_1("Search",_laserResult);
|
TRACE_1("Search",_laserResult);
|
||||||
|
|
||||||
_foundTargetPos;
|
if (isNil "_foundTargetPos") exitWith {
|
||||||
|
[0, 0, 0]
|
||||||
|
};
|
||||||
|
|
||||||
|
// average out any error from laser jump
|
||||||
|
private _positionSum = [0, 0, 0];
|
||||||
|
{
|
||||||
|
_positionSum = _positionSum vectorAdd _x;
|
||||||
|
} forEach _lastPositions;
|
||||||
|
|
||||||
|
if (_foundTargetPos isNotEqualTo [0, 0, 0]) then {
|
||||||
|
_lastPositions set [_lastPositionIndex % MAX_AVERAGES, _foundTargetPos];
|
||||||
|
_seekerParams set [4, _lastPositions];
|
||||||
|
_seekerParams set [5, _lastPositionIndex + 1];
|
||||||
|
};
|
||||||
|
|
||||||
|
private _aproximateVelocity = [0, 0, 0];
|
||||||
|
_positionSum = _positionSum vectorAdd _foundTargetPos;
|
||||||
|
if (MAX_AVERAGES == count _lastPositions) then {
|
||||||
|
_positionSum = _positionSum vectorMultiply (1 / (1 + count _lastPositions));
|
||||||
|
|
||||||
|
// if we are within a meter of the previous average, just use the previous average
|
||||||
|
if (_positionSum distanceSqr _lastPositionSum < MINIMUM_DISTANCE_UNTIL_NEW_POS * MINIMUM_DISTANCE_UNTIL_NEW_POS) then {
|
||||||
|
_positionSum = _lastPositionSum;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_timestep != 0) then {
|
||||||
|
_aproximateVelocity = (_positionSum vectorDiff _lastPositionSum) vectorMultiply (1 / _timestep);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
_positionSum = _positionSum vectorMultiply (1 / count _lastPositions);
|
||||||
|
};
|
||||||
|
|
||||||
|
_seekerParams set [6, _positionSum];
|
||||||
|
|
||||||
|
_targetData set [0, (getPosASL _projectile) vectorFromTo _positionSum];
|
||||||
|
_targetData set [3, _aproximateVelocity];
|
||||||
|
|
||||||
|
TRACE_3("laser target found",_foundTargetPos,_positionSum,count _lastPositions);
|
||||||
|
|
||||||
|
_positionSum
|
||||||
|
@ -45,4 +45,3 @@ _attackProfileStateParams set [4, _maxDistanceSqr]; // max distance squared used
|
|||||||
_attackProfileStateParams set [5, _minDistanceSqr];
|
_attackProfileStateParams set [5, _minDistanceSqr];
|
||||||
_attackProfileStateParams set [6, _wireCutSource];
|
_attackProfileStateParams set [6, _wireCutSource];
|
||||||
_attackProfileStateParams set [7, _distanceAheadOfMissile];
|
_attackProfileStateParams set [7, _distanceAheadOfMissile];
|
||||||
|
|
||||||
|
@ -3,8 +3,9 @@
|
|||||||
#include "\z\ace\addons\main\script_mod.hpp"
|
#include "\z\ace\addons\main\script_mod.hpp"
|
||||||
|
|
||||||
// #define DRAW_GUIDANCE_INFO
|
// #define DRAW_GUIDANCE_INFO
|
||||||
|
// #define ENABLE_PROJECTILE_CAMERA
|
||||||
// #define DEBUG_MODE_FULL
|
// #define DEBUG_MODE_FULL
|
||||||
// #define DISABLE_COMPILE_CACHE
|
#define DISABLE_COMPILE_CACHE
|
||||||
// #define ENABLE_PERFORMANCE_COUNTERS
|
// #define ENABLE_PERFORMANCE_COUNTERS
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED_MISSILEGUIDANCE
|
#ifdef DEBUG_ENABLED_MISSILEGUIDANCE
|
||||||
@ -28,4 +29,3 @@
|
|||||||
#define DEFAULT_LEAD_DISTANCE 5
|
#define DEFAULT_LEAD_DISTANCE 5
|
||||||
#define ACTIVE_RADAR_POLL_FREQUENCY (1 / 7)
|
#define ACTIVE_RADAR_POLL_FREQUENCY (1 / 7)
|
||||||
#define ACTIVE_RADAR_MINIMUM_SCAN_AREA 30
|
#define ACTIVE_RADAR_MINIMUM_SCAN_AREA 30
|
||||||
|
|
||||||
|
@ -27,10 +27,10 @@ Finally, flight profiles and mechanics for realistic missile simulations are als
|
|||||||
|
|
||||||
## 2. Components
|
## 2. Components
|
||||||
|
|
||||||
The framework is broken up into 3 major components: Locking Types, Seeker Types and Attack Profiles. In combination, these components build out the entire process of launching, locking and going terminal flight against targets.
|
The framework is broken up into 3 major components: Navigation Types, Seeker Types and Attack Profiles. In combination, these components build out the entire process of launching, locking and going terminal flight against targets.
|
||||||
|
|
||||||
#### 2.1 Locking Types
|
#### 2.1 Navigation Types
|
||||||
Locking types provide the basic functionality of targeting which will be based to a seeker type, providing target acquisition for seekers. This provides the basic functionality for providing pre-determined targets for a seeker, or allowing the seeker to perform its own target acquisition and locking. Additionally, the seeker may reference back into the locking type in order to re-perform target acquisition.
|
Navigation types define how the missile flies to the designated target. ACE 3 implements the most common ones in use, Proportional Navigation, Augmented Proportional Navigation, and Zero-Effort Miss. These navigation types give an acceleration command to the missile who attempts to satisfy the command by adjusting its pitch and yaw to fly to the target.
|
||||||
|
|
||||||
#### 2.2 Seeker Types
|
#### 2.2 Seeker Types
|
||||||
Each seeker is generally assumed to be the logic for the seeker head unit within any given munition. Seekers within this framework provide the basic targeting functionality for the entire framework. The locking type will provide a generic target to the seeker, or the seeker may aquire a target on its own. The seeker then provides a target, either an object or a ASL position, which is then passed further into the framework. This target (or position) should be the actual current target position for the missiles flight. Seekers are required to perform all limitations and checks within their systems, although various limitations have been provided in this framework such as LOS FOV, laser guidance, etc.
|
Each seeker is generally assumed to be the logic for the seeker head unit within any given munition. Seekers within this framework provide the basic targeting functionality for the entire framework. The locking type will provide a generic target to the seeker, or the seeker may aquire a target on its own. The seeker then provides a target, either an object or a ASL position, which is then passed further into the framework. This target (or position) should be the actual current target position for the missiles flight. Seekers are required to perform all limitations and checks within their systems, although various limitations have been provided in this framework such as LOS FOV, laser guidance, etc.
|
||||||
@ -42,9 +42,9 @@ An attack profile adjusts the current target flight location to create the actua
|
|||||||
|
|
||||||
## 3. How it all ties together
|
## 3. How it all ties together
|
||||||
|
|
||||||
The system is executed in a linear series of calls to each step of the process, and feeding back the return from that step to the next step. Execution is conducted using Locking -> Seeker -> Profile, iteratively every frame of execution. Flight times are adjusted to `accTime` values and FPS lag, giving consistent flight.
|
The system is executed in a linear series of calls to each step of the process, and feeding back the return from that step to the next step. Execution is conducted using Seeker -> Profile -> Navigation, iteratively every frame of execution. Flight times are adjusted to `accTime` values and FPS lag, giving consistent flight.
|
||||||
|
|
||||||
On each step of execution, a target specification array `[targetObj, targetPos]` is passed to the locking type, which then will return a possible modified target array. Next, this modified data is passed to the seeker type - which then, in turn, returns a position vector to the current "seeked" target position (ASL). Last, this target position is passed to the attack profile, which then returns an "adjusted attack position" (ASL), which is the location the missile should *currently* be homing on for flight.
|
On each step of execution, the seeker finds and returns the position of its target (ASL) and, optionally, sets target data specifying the target's direction from the missile, range, velocity and acceleration (if able). Then, this data is passed to the attack profile, which then returns an "adjusted attack position" (ASL), which is the location the missile should *currently* be homing on for flight. Finally, the navigation system processes the seeker's data about the target and returns a "Commanded Acceleration" vector which the missile attempts to satisfy.
|
||||||
|
|
||||||
In the simplest sense, the entire system provides the flight trajectory of the missile homing directly on the "adjusted attack position"; thus, an attack profile would ajust this position to direct the missile. For example, top down attacks return the adjusted attack position high above the target, until entering their terminal stages, which then changes the position to be directly on top of the target - thus "walking the missile" along its flight path and to the impact.
|
In the simplest sense, the entire system provides the flight trajectory of the missile homing directly on the "adjusted attack position"; thus, an attack profile would ajust this position to direct the missile. For example, top down attacks return the adjusted attack position high above the target, until entering their terminal stages, which then changes the position to be directly on top of the target - thus "walking the missile" along its flight path and to the impact.
|
||||||
|
|
||||||
@ -60,28 +60,47 @@ class CfgAmmo {
|
|||||||
|
|
||||||
// Begin ACE guidance Configs
|
// Begin ACE guidance Configs
|
||||||
class ace_missileguidance {
|
class ace_missileguidance {
|
||||||
enabled = 1; // Enable missile guidance (0-disabled, 1-enabled)
|
enabled = 1; // Explicit enabling of the system
|
||||||
|
|
||||||
minDeflection = 0.00025; // Minimum flap deflection for guidance
|
pitchRate = 30; // How many degrees/second the missile can pitch
|
||||||
maxDeflection = 0.001; // Maximum flap deflection for guidance
|
yawRate = 30; // How many degrees/second this missile can yaw
|
||||||
incDeflection = 0.0005; // The increment in which deflection adjusts
|
|
||||||
|
|
||||||
canVanillaLock = 0; // Enable vanilla lock, only applicable to non-cadet modes, 'recruit' always uses vanilla locking (0-disabled, 1-enabled)
|
canVanillaLock = 0; // Can this default vanilla lock? Only applicable to non-cadet mode
|
||||||
|
|
||||||
|
// Guidance type for munitions
|
||||||
defaultSeekerType = "SALH"; // Default seeker type
|
defaultSeekerType = "SALH"; // Default seeker type
|
||||||
seekerTypes[] = {"SALH", "LIDAR", "SARH", "Optic", "Thermal", "GPS", "SACLOS", "MCLOS"}; // Seeker types available
|
seekerTypes[] = { "SALH", "LIDAR", "SARH", "Optic", "Thermal", "GPS", "SACLOS", "MCLOS" };
|
||||||
|
|
||||||
defaultSeekerLockMode = "LOAL"; // Default seeker lock mode
|
defaultSeekerLockMode = "LOAL"; // Default lock mode
|
||||||
seekerLockModes[] = {"LOAL", "LOBL"}; // Seeker lock modes available
|
seekerLockModes[] = { "LOAL", "LOBL" };
|
||||||
|
|
||||||
seekerAngle = 90; // Angle in front of the missile which can be searched
|
defaultNavigationType = "Direct"; // Default navigation type
|
||||||
seekerAccuracy = 1; // Seeker accuracy multiplier
|
navigationTypes[] = { "Direct", "ZeroEffortMiss" }; // Navigation types this missile can use
|
||||||
|
|
||||||
|
seekLastTargetPos = 1; // seek last target position [if seeker loses LOS of target, continue to last known pos]
|
||||||
|
seekerAngle = 70; // Angle in front of the missile which can be searched
|
||||||
|
seekerAccuracy = 1; // seeker accuracy multiplier
|
||||||
|
|
||||||
seekerMinRange = 1; // Minimum range from the missile which the seeker can visually search
|
seekerMinRange = 1; // Minimum range from the missile which the seeker can visually search
|
||||||
seekerMaxRange = 2500; // Maximum from the missile which the seeker can visually search
|
seekerMaxRange = 8000; // Maximum range from the missile which the seeker can visually search
|
||||||
|
|
||||||
defaultAttackProfile = "LIN"; // Default attack profile
|
// Attack profile type selection
|
||||||
attackProfiles[] = {"LIN", "DIR", "MID", "HI"}; // Attack profiles available
|
defaultAttackProfile = "hellfire"; // Default attack profile
|
||||||
|
attackProfiles[] = {"hellfire", "hellfire_hi", "hellfire_lo"}; // Possible attack profiles
|
||||||
|
|
||||||
|
// State machine defining what navigation type to use in this missiles phase
|
||||||
|
class navigationStates {
|
||||||
|
class initial {
|
||||||
|
transitionCondition = "my_fnc_navigationTransition"; // Condition needed to transition to next state
|
||||||
|
navigationType = "Direct"; // Navigation type to use in this state
|
||||||
|
};
|
||||||
|
class terminal {
|
||||||
|
transitionCondition = "";
|
||||||
|
navigationType = "ZeroEffortMiss";
|
||||||
|
};
|
||||||
|
// transitions from initial -> termimal
|
||||||
|
states[] = {"initial", "terminal"};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -95,6 +114,7 @@ class ace_missileguidance_seekerTypes {
|
|||||||
description = ""; // Description
|
description = ""; // Description
|
||||||
|
|
||||||
functionName = "my_fnc_doSeekerType"; // Function that handles the seeker type
|
functionName = "my_fnc_doSeekerType"; // Function that handles the seeker type
|
||||||
|
onFired = "my_fnc_onFired"; // Function that runs when the missile is fired using this seeker
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
@ -109,6 +129,17 @@ class ace_missileguidance_attackProfiles {
|
|||||||
description = ""; // Description
|
description = ""; // Description
|
||||||
|
|
||||||
functionName = "my_fnc_doAttackProfile"; // Function that handles the attack profile
|
functionName = "my_fnc_doAttackProfile"; // Function that handles the attack profile
|
||||||
|
onFired = "my_fnc_onFired"; // Function that runs when missile is fired using this attack profile
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.4 Custom Navigation Type
|
||||||
|
```cpp
|
||||||
|
class ace_missileguidance_navigationTypes {
|
||||||
|
class MyNavigationProfile {
|
||||||
|
functionName = "my_fnc_navigation"; // Function to run for navigation
|
||||||
|
onFired = "my_fnc_onFired"; // Function to run when the missile is fired with this navigation type
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
Loading…
Reference in New Issue
Block a user