SACLOS and HOT Missiles (#6708)

* abc

* Revert "abc"

This reverts commit bcb4214bd9.

* Update to current commit

* Added HOT1 Missile and SACLOS/Wire guidance

* Added all HOT variants. Added polish to code

* Fixed bug with pylons

* Changed how seeker angle is calculated. When the wire snaps the missile goes haywire. Fixed bug where HOT2/3 missiles weren't getting missile guidance

* Replaced Wiesel FireFIST launcher with  HOT Launcher

* Remove debug defines

* Tweak thrust

* Fix formatting issues. Added true randomness. Added ACE prefixes. Added string table. Tweaked missile dynamics

* Fix bug where attack profile correction was wrong due to magnitude always being 50. Add stringtable values for relevant strings. Added reload time to Wiesel ATGM. Added "onFired" to initialize values

* Moved wire-snapping logic to attack profile

* Missile flight dynamics tweaked

* Add a crosshair offset. The missile sits in this offset relative to the crosshair

* Add LOS checks. Fix bug where wire-cutting didnt work.

* Tweak explosive range for a kill radius of ~20m. Add fragmentation

* Add AI Flags

* Person in control of missile may not be the shooter

* Fix RPT spam on missile out of LOS. Tweak missile dynamics. Add wire break sound cue

* Fix bug where missile didn't go to a fake target in front of it when out of LOS

* Use a better, more generic way to calculate direction camera is facing

* Use ACE Macros for frag values. Get config entry with CBA

* Add Wiki entry

* Add new lines to wiki. Allow for SQF expressions in config for maxCorrectableDistance

* Add CPP code tag

* Fix wiki grammer error

* Re-convert back to CBA_fnc_getConfigEntry

* UAV Gunner support, cleanup

* Fix bug where SACLOS for launcher guided weapons was off

* Add the ability to define how far ahead of the missile the attack profile will seek toward
This commit is contained in:
Brandon Danyluk 2018-12-06 19:27:30 -07:00 committed by PabstMirror
parent de828a2997
commit 1511ecc1c0
19 changed files with 842 additions and 0 deletions

2
addons/hot/$PBOPREFIX$ Normal file
View File

@ -0,0 +1,2 @@
z\ace\addons\hot

View File

@ -0,0 +1,19 @@
class EGVAR(missileguidance,AttackProfiles) {
class WIRE {
name = CSTRING(missileType);
visualName = CSTRING(missileType);
description = CSTRING(missileType_Description);
functionName = QFUNC(attackProfile_WIRE);
};
};
class EGVAR(missileguidance,SeekerTypes) {
class SACLOS {
name = "SACLOS";
visualName = "SACLOS";
description = CSTRING(SACLOS_Description);
functionName = QFUNC(seekerType_SACLOS);
};
};

140
addons/hot/CfgAmmo.hpp Normal file
View File

@ -0,0 +1,140 @@
class CfgAmmo {
class M_Scalpel_AT;
class ammo_Penetrator_Base;
class GVAR(ammo_Penetrator_HOT1): ammo_Penetrator_Base {
caliber = 60;
warheadName = "HEAT";
hit = 720;
};
class GVAR(ammo_Penetrator_HOT2): ammo_Penetrator_Base {
caliber = 65;
warheadName = "HEAT";
hit = 900;
};
class GVAR(ammo_Penetrator_HOT3): ammo_Penetrator_Base {
caliber = 80;
warheadName = "TandemHEAT";
hit = 1000;
};
class GVAR(HOT1): M_Scalpel_AT {
aiAmmoUsageFlags = "128+512";
model = "\A3\Weapons_F_Tank\Launchers\Vorona\Vorona_missile_heat_fly";
proxyShape = "\A3\Weapons_F\Ammo\Missile_AT_03_F";
submunitionAmmo = QGVAR(ammo_Penetrator_HOT1);
submunitionDirectionType = "SubmunitionModelDirection";
submunitionInitSpeed = 1000;
submunitionParentSpeedCoef = 0;
submunitionInitialOffset[] = { 0, 0, -0.2 };
hit = 150;
warheadName = "HEAT";
indirectHit = 25;
indirectHitRange = 3.5;
explosive = 0.8;
displayName = CSTRING(hot1);
displayNameShort = CSTRING(hot1);
description = CSTRING(missileType_Description);
descriptionShort = CSTRING(missileType);
effectsMissile = "missile2";
irLock = 0;
laserLock = 0;
manualControl = 0;
maxSpeed = 240;
thrustTime = 17;
thrust = 125;
timeToLive = 40;
initTime = 0.3;
EGVAR(rearm,caliber) = 178;
class ace_missileguidance {
enabled = 1;
minDeflection = 0; // Minium flap deflection for guidance
maxDeflection = 0.0030; // Maximum flap deflection for guidance
incDeflection = 0.0005; // The incrmeent in which deflection adjusts.
canVanillaLock = 0; // Can this default vanilla lock? Only applicable to non-cadet mode
// Guidance type for munitions
defaultSeekerType = "SACLOS";
seekerTypes[] = { "SACLOS" };
defaultSeekerLockMode = "LOAL";
seekerLockModes[] = { "LOAL", "LOBL" };
onFired = QFUNC(onFired);
seekLastTargetPos = 0; // seek last target position [if seeker loses LOS of target, continue to last known pos]
seekerAngle = 30; // Angle from the shooter's view that can track the missile
seekerAccuracy = 1; // seeker accuracy multiplier
seekerMinRange = 75;
seekerMaxRange = 4000; // Range from the missile which the seeker can visually search
correctionDistance = 15; // distance from center of crosshair where missile slows down
offsetFromCrosshair[] = { 0, 0, 0.5 }; // where the missile wants to stay in relation to the center of the crosshair.
// Attack profile type selection
defaultAttackProfile = "WIRE";
attackProfiles[] = {"WIRE"};
};
};
class GVAR(HOT2): GVAR(HOT1) {
submunitionAmmo = QGVAR(ammo_Penetrator_HOT2);
displayName = CSTRING(hot2);
displayNameShort = CSTRING(hot2);
class ace_missileguidance: ace_missileguidance {
enabled = 1;
};
};
class GVAR(HOT2MP): GVAR(HOT2) {
aiAmmoUsageFlags = "64+128";
submunitionAmmo = "";
warheadName = "HE";
allowAgainstInfantry = 1;
hit = 200;
indirectHit = 200;
indirectHitRange = 5;
explosionEffects = "BombExplosion";
explosive = 0.7;
EGVAR(frag,enabled) = 1;
EGVAR(frag,metal) = 7100; // 1000 steel balls
EGVAR(frag,charge) = 4100;
EGVAR(frag,gurney_c) = 2700;
EGVAR(frag,gurney_k) = 3/5;
EGVAR(frag,classes)[] = {"ACE_frag_small"};
displayName = CSTRING(hot2mp);
displayNameShort = CSTRING(hot2mp);
description = CSTRING(missileType_Description_AP);
class ace_missileguidance: ace_missileguidance {
enabled = 1;
};
};
class GVAR(HOT3): GVAR(HOT2) {
submunitionAmmo = QGVAR(ammo_Penetrator_HOT3);
warheadName = "TandemHEAT";
displayName = CSTRING(hot3);
displayNameShort = CSTRING(hot3);
class ace_missileguidance: ace_missileguidance {
enabled = 1;
seekerMaxRange = 4300;
};
};
};

View File

@ -0,0 +1,12 @@
class Extended_PreStart_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_preStart));
};
};
class Extended_PreInit_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_preInit));
};
};

205
addons/hot/CfgMagazines.hpp Normal file
View File

@ -0,0 +1,205 @@
class CfgMagazines {
class 12Rnd_PG_missiles;
// HOT1 - HEAT (anti-tank)
class GVAR(1_6Rnd): 12Rnd_PG_missiles { // Old style vehicle magazine
count = 6;
initSpeed = 100;
ammo = QGVAR(HOT1);
displayName = CSTRING(hot1);
displayNameShort = CSTRING(hot1);
descriptionShort = CSTRING(missileType);
};
class GVAR(1_2Rnd): GVAR(1_6Rnd) {
count = 2;
};
// 1.70 pylon magazines:
class GVAR(1_PylonMissile_1Rnd): GVAR(1_6Rnd) { // Bare missle
displayName = CSTRING(hot1_1);
count = 1;
mass = 70;
pylonWeapon = QGVAR(1_launcher);
hardpoints[] = {"SCALPEL_1RND"};
model = "\A3\Weapons_F\DynamicLoadout\PylonMissile_1x_Bomb_04_F.p3d";
};
class GVAR(1_PylonRack_1Rnd): GVAR(1_6Rnd) { // 1x Launcher Support Rack
displayName = CSTRING(hot1_1);
count = 1;
mass = 85;
pylonWeapon = QGVAR(1_launcher);
hardpoints[] = {"B_MISSILE_PYLON", "SCALPEL_1RND_EJECTOR", "B_ASRRAM_EJECTOR", "UNI_SCALPEL", "CUP_NATO_HELO_SMALL", "CUP_NATO_HELO_LARGE", "RHS_HP_MELB"};
model = "\A3\Weapons_F\DynamicLoadout\PylonPod_1x_Missile_AA_04_F.p3d";
};
class GVAR(1_PylonRack_3Rnd): GVAR(1_6Rnd) { // 3x Launcher Support Rack
displayName = CSTRING(hot1_3);
count = 3;
mass = 250;
pylonWeapon = QGVAR(1_launcher);
hardpoints[] = {"B_MISSILE_PYLON", "UNI_SCALPEL", "CUP_NATO_HELO_LARGE", "RHS_HP_LONGBOW_RACK"};
model = "\A3\Weapons_F\DynamicLoadout\PylonPod_3x_Missile_LG_scalpel_F.p3d";
mirrorMissilesIndexes[] = {2, 1, 3};
};
class GVAR(1_PylonRack_4Rnd): GVAR(1_6Rnd) { // 4x Launcher Support Rack
displayName = CSTRING(hot1_4);
count = 4;
mass = 340;
pylonWeapon = QGVAR(1_launcher);
hardpoints[] = {"UNI_SCALPEL", "CUP_NATO_HELO_LARGE", "RHS_HP_HELLFIRE_RACK", "RHS_HP_LONGBOW_RACK"};
model = "\A3\Weapons_F\DynamicLoadout\PylonPod_4x_Missile_LG_scalpel_F.p3d";
mirrorMissilesIndexes[] = {2, 1, 4, 3};
};
// HOT2 - HEAT (anti-tank)
class GVAR(2_6Rnd): 12Rnd_PG_missiles { // Old style vehicle magazine
count = 6;
initSpeed = 100;
ammo = QGVAR(HOT2);
displayName = CSTRING(hot2);
displayNameShort = CSTRING(hot2);
descriptionShort = CSTRING(missileType);
};
class GVAR(2_2Rnd): GVAR(2_6Rnd) {
count = 2;
};
// 1.70 pylon magazines:
class GVAR(2_PylonMissile_1Rnd): GVAR(2_6Rnd) { // Bare missle
displayName = CSTRING(hot2_1);
pylonWeapon = QGVAR(2_launcher);
count = 1;
mass = 70;
hardpoints[] = {"SCALPEL_1RND"};
model = "\A3\Weapons_F\DynamicLoadout\PylonMissile_1x_Bomb_04_F.p3d";
};
class GVAR(2_PylonRack_1Rnd): GVAR(2_6Rnd) { // 1x Launcher Support Rack
displayName = CSTRING(hot2_1);
pylonWeapon = QGVAR(2_launcher);
count = 1;
mass = 85;
hardpoints[] = {"B_MISSILE_PYLON", "SCALPEL_1RND_EJECTOR", "B_ASRRAM_EJECTOR", "UNI_SCALPEL", "CUP_NATO_HELO_SMALL", "CUP_NATO_HELO_LARGE", "RHS_HP_MELB"};
model = "\A3\Weapons_F\DynamicLoadout\PylonPod_1x_Missile_AA_04_F.p3d";
};
class GVAR(2_PylonRack_3Rnd): GVAR(2_6Rnd) { // 3x Launcher Support Rack
displayName = CSTRING(hot2_3);
pylonWeapon = QGVAR(2_launcher);
count = 3;
mass = 250;
hardpoints[] = {"B_MISSILE_PYLON", "UNI_SCALPEL", "CUP_NATO_HELO_LARGE", "RHS_HP_LONGBOW_RACK"};
model = "\A3\Weapons_F\DynamicLoadout\PylonPod_3x_Missile_LG_scalpel_F.p3d";
mirrorMissilesIndexes[] = {2, 1, 3};
};
class GVAR(2_PylonRack_4Rnd): GVAR(2_6Rnd) { // 4x Launcher Support Rack
displayName = CSTRING(hot2_4);
pylonWeapon = QGVAR(2_launcher);
count = 4;
mass = 340;
hardpoints[] = {"UNI_SCALPEL", "CUP_NATO_HELO_LARGE", "RHS_HP_HELLFIRE_RACK", "RHS_HP_LONGBOW_RACK"};
model = "\A3\Weapons_F\DynamicLoadout\PylonPod_4x_Missile_LG_scalpel_F.p3d";
mirrorMissilesIndexes[] = {2, 1, 4, 3};
};
// HOT2MP - HE Anti-Infantry
class GVAR(2MP_6Rnd): 12Rnd_PG_missiles { // Old style vehicle magazine
count = 6;
initSpeed = 100;
ammo = QGVAR(HOT2MP);
displayName = CSTRING(hot2mp);
displayNameShort = CSTRING(hot2mp);
descriptionShort = CSTRING(missileType);
};
class GVAR(2MP_2Rnd): GVAR(2MP_6Rnd) {
count = 2;
};
// 1.70 pylon magazines:
class GVAR(2MP_PylonMissile_1Rnd): GVAR(2MP_6Rnd) { // Bare missle
displayName = CSTRING(hot2mp_1);
pylonWeapon = QGVAR(2mp_launcher);
count = 1;
mass = 70;
hardpoints[] = {"SCALPEL_1RND"};
model = "\A3\Weapons_F\DynamicLoadout\PylonMissile_1x_Bomb_04_F.p3d";
};
class GVAR(2MP_PylonRack_1Rnd): GVAR(2MP_6Rnd) { // 1x Launcher Support Rack
displayName = CSTRING(hot2mp_1);
pylonWeapon = QGVAR(2mp_launcher);
count = 1;
mass = 85;
hardpoints[] = {"B_MISSILE_PYLON", "SCALPEL_1RND_EJECTOR", "B_ASRRAM_EJECTOR", "UNI_SCALPEL", "CUP_NATO_HELO_SMALL", "CUP_NATO_HELO_LARGE", "RHS_HP_MELB"};
model = "\A3\Weapons_F\DynamicLoadout\PylonPod_1x_Missile_AA_04_F.p3d";
};
class GVAR(2MP_PylonRack_3Rnd): GVAR(2MP_6Rnd) { // 3x Launcher Support Rack
displayName = CSTRING(hot2mp_3);
pylonWeapon = QGVAR(2mp_launcher);
count = 3;
mass = 250;
hardpoints[] = {"B_MISSILE_PYLON", "UNI_SCALPEL", "CUP_NATO_HELO_LARGE", "RHS_HP_LONGBOW_RACK"};
model = "\A3\Weapons_F\DynamicLoadout\PylonPod_3x_Missile_LG_scalpel_F.p3d";
mirrorMissilesIndexes[] = {2, 1, 3};
};
class GVAR(2MP_PylonRack_4Rnd): GVAR(2MP_6Rnd) { // 4x Launcher Support Rack
displayName = CSTRING(hot2mp_4);
pylonWeapon = QGVAR(2mp_launcher);
count = 4;
mass = 340;
hardpoints[] = {"UNI_SCALPEL", "CUP_NATO_HELO_LARGE", "RHS_HP_HELLFIRE_RACK", "RHS_HP_LONGBOW_RACK"};
model = "\A3\Weapons_F\DynamicLoadout\PylonPod_4x_Missile_LG_scalpel_F.p3d";
mirrorMissilesIndexes[] = {2, 1, 4, 3};
};
// HOT3 - tandem shaped charge HEAT (anti-tank)
class GVAR(3_6Rnd): 12Rnd_PG_missiles { // Old style vehicle magazine
count = 6;
initSpeed = 100;
ammo = QGVAR(HOT3);
displayName = CSTRING(hot3);
displayNameShort = CSTRING(hot3);
descriptionShort = CSTRING(missileType);
};
class GVAR(3_2Rnd): GVAR(3_6Rnd) { // Old style vehicle magazine
count = 2;
};
// 1.70 pylon magazines:
class GVAR(3_PylonMissile_1Rnd): GVAR(3_6Rnd) { // Bare missle
displayName = CSTRING(hot3_1);
pylonWeapon = QGVAR(3_launcher);
count = 1;
mass = 70;
hardpoints[] = {"SCALPEL_1RND"};
model = "\A3\Weapons_F\DynamicLoadout\PylonMissile_1x_Bomb_04_F.p3d";
};
class GVAR(3_PylonRack_1Rnd): GVAR(3_6Rnd) { // 1x Launcher Support Rack
displayName = CSTRING(hot3_1);
pylonWeapon = QGVAR(3_launcher);
count = 1;
mass = 85;
hardpoints[] = {"B_MISSILE_PYLON", "SCALPEL_1RND_EJECTOR", "B_ASRRAM_EJECTOR", "UNI_SCALPEL", "CUP_NATO_HELO_SMALL", "CUP_NATO_HELO_LARGE", "RHS_HP_MELB"};
model = "\A3\Weapons_F\DynamicLoadout\PylonPod_1x_Missile_AA_04_F.p3d";
};
class GVAR(3_PylonRack_3Rnd): GVAR(3_6Rnd) { // 3x Launcher Support Rack
displayName = CSTRING(hot3_3);
pylonWeapon = QGVAR(3_launcher);
count = 3;
mass = 250;
hardpoints[] = {"B_MISSILE_PYLON", "UNI_SCALPEL", "CUP_NATO_HELO_LARGE", "RHS_HP_LONGBOW_RACK"};
model = "\A3\Weapons_F\DynamicLoadout\PylonPod_3x_Missile_LG_scalpel_F.p3d";
mirrorMissilesIndexes[] = {2, 1, 3};
};
class GVAR(3_PylonRack_4Rnd): GVAR(3_6Rnd) { // 4x Launcher Support Rack
displayName = CSTRING(hot3_4);
pylonWeapon = QGVAR(3_launcher);
count = 4;
mass = 340;
hardpoints[] = {"UNI_SCALPEL", "CUP_NATO_HELO_LARGE", "RHS_HP_HELLFIRE_RACK", "RHS_HP_LONGBOW_RACK"};
model = "\A3\Weapons_F\DynamicLoadout\PylonPod_4x_Missile_LG_scalpel_F.p3d";
mirrorMissilesIndexes[] = {2, 1, 4, 3};
};
};

View File

@ -0,0 +1,19 @@
class CfgVehicles {
class Tank;
class Tank_F: Tank {
class Turrets;
};
class LT_01_base_F: Tank_F {
class Turrets: Turrets {
class MainTurret;
};
};
class LT_01_AT_base_F: LT_01_base_F {
class Turrets: Turrets {
class MainTurret: MainTurret {
weapons[] = {"SmokeLauncher","HMG_127",QGVAR(generic_launcher)};
magazines[] = {"SmokeLauncherMag",QGVAR(2_2Rnd),QGVAR(2_2Rnd),QGVAR(2_2Rnd),QGVAR(2MP_2Rnd),"100Rnd_127x99_mag_Tracer_Red","100Rnd_127x99_mag_Tracer_Red","100Rnd_127x99_mag_Tracer_Red","100Rnd_127x99_mag_Tracer_Red"};
};
};
};
};

62
addons/hot/CfgWeapons.hpp Normal file
View File

@ -0,0 +1,62 @@
class CfgWeapons {
class RocketPods;
class MissileLauncher;
class GVAR(1_launcher): RocketPods {
displayName = CSTRING(hot1);
magazines[] = {QGVAR(1_6Rnd), QGVAR(1_2Rnd), QGVAR(1_PylonMissile_1Rnd), QGVAR(1_PylonRack_1Rnd), QGVAR(1_PylonRack_3Rnd), QGVAR(1_PylonRack_4Rnd)};
initSpeed = 100;
autoFire = 0;
canLock = 0;
weaponLockSystem = 0;
lockingTargetSound[] = {"",0,1};
lockedTargetSound[] = {"",0,1};
soundFly[] = {"A3\Sounds_F\weapons\Rockets\rocket_fly_1",1,1.1,700};
nameSound = "MissileLauncher";
sounds[] = {"StandardSound"};
class StandardSound {
begin1[] = {"A3\Sounds_F\weapons\Rockets\missile_1",1.12202,1.3,1000};
soundBegin[] = {"begin1",1};
soundsetshot[] = {"RocketsMedium_Shot_SoundSet"};
};
cursor = "EmptyCursor";
cursorAim = "missile";
showAimCursorInternal = 0;
};
class GVAR(2_launcher): GVAR(1_launcher) {
displayName = CSTRING(hot2);
magazines[] = {QGVAR(2_6Rnd), QGVAR(2_2Rnd), QGVAR(2_PylonMissile_1Rnd), QGVAR(2_PylonRack_1Rnd), QGVAR(2_PylonRack_3Rnd), QGVAR(2_PylonRack_4Rnd)};
};
class GVAR(2mp_launcher): GVAR(1_launcher) {
displayName = CSTRING(hot2mp);
magazines[] = {QGVAR(2MP_6Rnd), QGVAR(2MP_2Rnd), QGVAR(2MP_PylonMissile_1Rnd), QGVAR(2MP_PylonRack_1Rnd), QGVAR(2MP_PylonRack_3Rnd), QGVAR(2MP_PylonRack_4Rnd)};
};
class GVAR(3_launcher): GVAR(1_launcher) {
displayName = CSTRING(hot3);
magazines[] = {QGVAR(3_6Rnd), QGVAR(3_2Rnd), QGVAR(3_PylonMissile_1Rnd), QGVAR(3_PylonRack_1Rnd), QGVAR(3_PylonRack_3Rnd), QGVAR(3_PylonRack_4Rnd)};
};
class GVAR(generic_launcher): MissileLauncher {
displayName = CSTRING(hotMissile);
magazines[] = {QGVAR(1_6Rnd), QGVAR(1_2Rnd), QGVAR(2_6Rnd), QGVAR(2_2Rnd), QGVAR(2MP_6Rnd), QGVAR(2MP_2Rnd), QGVAR(3_6Rnd), QGVAR(3_2Rnd)};
initSpeed = 100;
autoFire = 0;
canLock = 0;
weaponLockSystem = 0;
lockingTargetSound[] = {"",0,1};
lockedTargetSound[] = {"",0,1};
soundFly[] = {"A3\Sounds_F\weapons\Rockets\rocket_fly_1",1,1.1,700};
nameSound = "MissileLauncher";
sounds[] = {"StandardSound"};
class StandardSound {
begin1[] = {"A3\Sounds_F\weapons\Rockets\missile_1",1.12202,1.3,1000};
soundBegin[] = {"begin1",1};
soundsetshot[] = {"RocketsMedium_Shot_SoundSet"};
};
cursor = "EmptyCursor";
cursorAim = "missile";
showAimCursorInternal = 0;
autoReload = 1;
magazineReloadTime = 20;
};
};

12
addons/hot/README.md Normal file
View File

@ -0,0 +1,12 @@
ace_hot
===================
Adds HOT1/2/3 Missiles
## Maintainers
The people responsible for merging changes to this component or answering potential questions.
- [Brandon-TCVM](https://github.com/TheCandianVendingMachine)

4
addons/hot/XEH_PREP.hpp Normal file
View File

@ -0,0 +1,4 @@
PREP(seekerType_SACLOS);
PREP(attackProfile_WIRE);
PREP(onFired);

View File

@ -0,0 +1,10 @@
#include "script_component.hpp"
ADDON = false;
PREP_RECOMPILE_START;
#include "XEH_PREP.hpp"
PREP_RECOMPILE_END;
ADDON = true;

View File

@ -0,0 +1,4 @@
#include "script_component.hpp"
#include "XEH_PREP.hpp"

23
addons/hot/config.cpp Normal file
View File

@ -0,0 +1,23 @@
#include "script_component.hpp"
class CfgPatches {
class ADDON {
name = COMPONENT_NAME;
units[] = {};
weapons[] = {};
requiredVersion = REQUIRED_VERSION;
requiredAddons[] = {"ace_common","ace_missileguidance"};
author = ECSTRING(common,ACETeam);
authors[] = {"Brandon (TCVM)"};
url = ECSTRING(main,URL);
VERSION_CONFIG;
};
};
#include "ACE_GuidanceConfig.hpp"
#include "CfgEventHandlers.hpp"
#include "CfgAmmo.hpp"
#include "CfgMagazines.hpp"
#include "CfgWeapons.hpp"
#include "CfgVehicles.hpp"

View File

@ -0,0 +1,60 @@
#include "script_component.hpp"
/*
* Author: Brandon (TCVM)
* Attack profile: Wire guided
*
* 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_hot_fnc_attackProfile_WIRE;
*
* Public: No
*/
params ["_seekerTargetPos", "_args", "_attackProfileStateParams"];
_args params ["_firedEH"];
_firedEH params ["_shooter","","","","","","_projectile"];
_attackProfileStateParams params["_maxCorrectableDistance", "_wireCut", "_randomVector", "_crosshairOffset", "_seekerMaxRangeSqr", "_wireCutSource"];
private _projectilePos = getPosASL _projectile;
if ((((getPosASL _shooter) vectorDistanceSqr _projectilePos) > _seekerMaxRangeSqr) || { _wireCut }) exitWith {
// wire snap, random direction
if (_randomVector isEqualTo [0, 0, 0]) then {
_randomVector = RANDOM_VECTOR_3D vectorMultiply 300;
_attackProfileStateParams set [1, true];
_attackProfileStateParams set [2, _randomVector];
playSound3D ["a3\sounds_f\air\sfx\SL_rope_break.wss", objNull, false, AGLtoASL (_shooter modelToWorld _wireCutSource), 150, 1, 25];
};
_projectilePos vectorAdd _randomVector
};
if (_seekerTargetPos isEqualTo [0, 0, 0]) exitWith {
// cut wire if its caught on terrain
/*if !(lineIntersectsSurfaces [getPosASL _shooter, _projectilePos, _shooter] isEqualTo []) 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);
_relativeCorrection = _relativeCorrection vectorDiff _crosshairOffset;
private _magnitude = vectorMagnitude [_relativeCorrection select 0, 0, _relativeCorrection select 2];
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;
_projectilePos vectorDiff (_projectile vectorModelToWorld _relativeCorrection);

View File

@ -0,0 +1,53 @@
#include "script_component.hpp"
/*
* Author: Brandon (TCVM)
* Sets up missile guidance state arrays (called from missileGuidance's onFired).
*
* Arguments:
* Guidance Arg Array <ARRAY>
*
* Return Value:
* None
*
* Example:
* [] call ace_hot_fnc_onFired
*
* Public: No
*/
params ["_firedEH", "", "", "_seekerParams", "_stateParams"];
_firedEH params ["_shooter","_weapon","","","","","_projectile", "_gunner"];
_stateParams params ["", "_seekerStateParams", "_attackProfileStateParams"];
_seekerParams params ["", "", "_seekerMaxRange"];
private _config = ([_projectile] call CBA_fnc_getObjectConfig) >> "ace_missileguidance";
private _maxCorrectableDistance = [_config >> "correctionDistance", "NUMBER", DEFAULT_CORRECTION_DISTANCE] call CBA_fnc_getConfigEntry;
private _crosshairOffset = [_config >> "offsetFromCrosshair", "ARRAY", [0, 0, 0]] call CBA_fnc_getConfigEntry;
private _maxDistanceSqr = _seekerMaxRange * _seekerMaxRange;
private _distanceAheadOfMissile = [_config >> "missileLeadDistance", "NUMBER", DEFAULT_LEAD_DISTANCE] call CBA_fnc_getConfigEntry;
// AI don't know how to use the crosshair offset becauze they dum dum
if ((_gunner != ACE_PLAYER) && {_gunner != (ACE_controlledUAV select 1)}) then {
_crosshairOffset = [0, 0, 0];
};
if (_shooter isKindOf "Plane") then {WARNING("SACLOS fired from planes unsupported");};
private _turretPath = [_shooter, _weapon] call CBA_fnc_turretPathWeapon;
private _turretConfig = [_shooter, _turretPath] call CBA_fnc_getTurret;
private _wireCutSource = _shooter selectionPosition getText(_turretConfig >> "missileEnd");
_attackProfileStateParams set [0, _maxCorrectableDistance];
_attackProfileStateParams set [1, false]; // _wireCut
_attackProfileStateParams set [2, [0, 0, 0]]; // _randomVector
_attackProfileStateParams set [3, _crosshairOffset]; // crosshair offset
_attackProfileStateParams set [4, _maxDistanceSqr]; // max distance squared used for wire cut
_attackProfileStateParams set [5, _wireCutSource];
private _memoryPointGunnerOptics = getText(_turretConfig >> "memoryPointGunnerOptics");
private _animationSourceBody = getText(_turretConfig >> "animationSourceBody");
private _animationSourceGun = getText(_turretConfig >> "animationSourceGun");
_seekerStateParams set [0, _memoryPointGunnerOptics];
_seekerStateParams set [1, _animationSourceBody];
_seekerStateParams set [2, _animationSourceGun];
_seekerStateParams set [3, _distanceAheadOfMissile];

View File

@ -0,0 +1,50 @@
#include "script_component.hpp"
/*
* Author: Brandon (TCVM)
* SACLOS seeker
*
* Arguments:
* 1: Guidance Arg Array <ARRAY>
* 2: Seeker State <ARRAY>
*
* Return Value:
* Position of wanted missile pos relative to the camera direction <ARRAY>
*
* Example:
* [] call ace_hot_fnc_seekerType_SACLOS
*
* Public: No
*/
params ["", "_args"];
_args params ["_firedEH", "", "", "_seekerParams", "_stateParams"];
_firedEH params ["_shooter","_weapon","","","","","_projectile"];
_seekerParams params ["_seekerAngle"];
_stateParams params ["", "_seekerStateParams"];
_seekerStateParams params ["_memoryPointGunnerOptics", "_animationSourceBody", "_animationSourceGun", "_distanceAheadOfMissile"];
private _shooterPos = AGLToASL (_shooter modelToWorld(_shooter selectionPosition _memoryPointGunnerOptics));
private _projPos = getPosASL _projectile;
private _lookDirection = if !(_shooter isKindOf "CAManBase") then {
private _gBody = -deg(_shooter animationPhase _animationSourceBody);
private _gGun = deg(_shooter animationPhase _animationSourceGun);
_shooter vectorModelToWorld ([1, _gBody, _gGun] call CBA_fnc_polar2vect);
} else {
_shooterPos = eyePos _shooter;
_shooter weaponDirection _weapon
};
private _distanceToProj = _shooterPos vectorDistance _projPos;
private _testPointVector = vectorNormalized (_projPos vectorDiff _shooterPos);
private _testDotProduct = (_lookDirection vectorDotProduct _testPointVector);
private _testIntersections = lineIntersectsSurfaces [_shooterPos, _projPos, _shooter];
if ((_testDotProduct < (cos _seekerAngle)) || { !(_testIntersections isEqualTo []) }) exitWith {
// out of LOS of seeker
[0, 0, 0]
};
_shooterPos vectorAdd (_lookDirection vectorMultiply (_distanceToProj + _distanceAheadOfMissile));

View File

@ -0,0 +1,2 @@
#include "\z\ace\addons\hot\script_component.hpp"

View File

@ -0,0 +1,28 @@
#define COMPONENT hot
#define COMPONENT_BEAUTIFIED HOT
#include "\z\ace\addons\main\script_mod.hpp"
// #define DEBUG_MODE_FULL
// #define DISABLE_COMPILE_CACHE
// #define ENABLE_PERFORMANCE_COUNTERS
#ifdef DEBUG_ENABLED_HOT
#define DEBUG_MODE_FULL
#endif
#ifdef DEBUG_SETTINGS_HOT
#define DEBUG_SETTINGS DEBUG_SETTINGS_HOT
#endif
#include "\z\ace\addons\main\script_macros.hpp"
#define RANDOM_VECTOR_3D (call {\
private _z = random 2 - 1;\
private _r = sqrt (1 - _z^2);\
private _theta = random 360;\
[_r * cos _theta, _r * sin _theta, _z]\
})
#define DEFAULT_CORRECTION_DISTANCE 10
#define DEFAULT_LEAD_DISTANCE 50

View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<Project name="ACE">
<Package name="HOT">
<Key ID="STR_ACE_HOT_missileType">
<English>Wire-Guided</English>
<German>Drahtgelenkt</German>
</Key>
<Key ID="STR_ACE_HOT_SACLOS_Description">
<English>Semi-automatic command to line of sight</English>
<German>halbautomatische Steuerung über Sichtverbindung (SACLOS)</German>
</Key>
<Key ID="STR_ACE_HOT_missileType_Description">
<English>Wire-Guided Missile</English>
<German>Drahtgelenkte Rakete</German>
</Key>
<Key ID="STR_ACE_HOT_hotMissile">
<English>HOT Missile</English>
</Key>
<Key ID="STR_ACE_HOT_hot1">
<English>HOT 1</English>
</Key>
<Key ID="STR_ACE_HOT_hot2">
<English>HOT 2</English>
</Key>
<Key ID="STR_ACE_HOT_hot2mp">
<English>HOT 2MP</English>
</Key>
<Key ID="STR_ACE_HOT_hot3">
<English>HOT 3</English>
</Key>
<Key ID="STR_ACE_HOT_missileType_Description_AP">
<English>Wire-Guided Missile (Anti-Personnel)</English>
</Key>
<Key ID="STR_ACE_HOT_hot1_1">
<English>1x HOT 1 [ACE]</English>
</Key>
<Key ID="STR_ACE_HOT_hot1_3">
<English>3x HOT 1 [ACE]</English>
</Key>
<Key ID="STR_ACE_HOT_hot1_4">
<English>4x HOT 1 [ACE]</English>
</Key>
<Key ID="STR_ACE_HOT_hot2_1">
<English>1x HOT 2 [ACE]</English>
</Key>
<Key ID="STR_ACE_HOT_hot2_3">
<English>3x HOT 2 [ACE]</English>
</Key>
<Key ID="STR_ACE_HOT_hot2_4">
<English>4x HOT 2 [ACE]</English>
</Key>
<Key ID="STR_ACE_HOT_hot2mp_1">
<English>1x HOT 2MP [ACE]</English>
</Key>
<Key ID="STR_ACE_HOT_hot2mp_3">
<English>3x HOT 2MP [ACE]</English>
</Key>
<Key ID="STR_ACE_HOT_hot2mp_4">
<English>4x HOT 2MP [ACE]</English>
</Key>
<Key ID="STR_ACE_HOT_hot3_1">
<English>1x HOT 3 [ACE]</English>
</Key>
<Key ID="STR_ACE_HOT_hot3_4">
<English>4x HOT 3 [ACE]</English>
</Key>
<Key ID="STR_ACE_HOT_hot3_3">
<English>3x HOT 3 [ACE]</English>
</Key>
</Package>
</Project>

66
docs/wiki/feature/hot.md Normal file
View File

@ -0,0 +1,66 @@
---
layout: wiki
title: HOT
description: HOT 1/2/3 Missiles
group: feature
category: equipment
parent: wiki
mod: ace
version:
major: 3
minor: 13
patch: 0
---
## 1. Overview
### 1.1 Guidance
HOT missile is a wire-guided SACLOS weapon. It requires the shooter to provide constant aiming in order to hit its target.
### 1.2 Attack profiles
The missile requires line of sight to the target at all times. Keep your crosshair on the target as the missile cruises toward it until impact.
If you lose line of sight the missile will stop tracking toward your crosshair and will fly on its current trajectory. You can regain control if the missile re-enters line of sight.
If the missile exceeds its maximum range the wire will snap and it will fly off in a random direction.
### 1.3 Missile Types
There are 4 HOT missiles included
- HOT 1: Able to penetrate around 800mm RHA. Max range is 4000 meters. HEAT
- HOT 2: Able to penetrate around 900mm RHA. Max range is 4000 meters. HEAT
- HOT 2MP: Anti-Infantry. Contains 1000 steel balls that scatter on impact. Also contains a chemical incendiary device which has a kill radius of around 20 meters. Able to penetrate around 350mm RHA. Max range is 4000 meters. HE
- HOT 3: Able to penetrate around 1250mm RHA. Max range is 4300 meters. Tandem HEAT
## 2. Usage
- Select the HOT launcher and aim toward your target. Once you fire the weapon you must keep your crosshair on the target until impact. Note: The HOT missile sits 0.5 meters above the crosshair
- If the missile exceeds 4000 meters (4300 meters for the HOT 3) the wire will snap and you will lose control over the missile.
- If the missile is 30 degrees outside of your current crosshair position the seeker will not be able to find the missile and you will lose control over it.
## 3 Adding to vehicles
- Easiest way to add is via the 1.70 Pylons system.
- HOT missiles can also be added to other vehicles via config or script.
### 3.1 Classnames
- Weapons: `ace_hot_1_launcher`, `2_launcher`, `ace_hot_2mp_launcher`, `ace_hot_3_launcher`, `ace_hot_generic_launcher`
- Magazines: `ace_hot_1_6Rnd`, `ace_hot_1_2Rnd`, `ace_hot_2_6Rnd`, `ace_hot_2_2Rnd`, `ace_hot_2mp_6Rnd`, `ace_hot_2mp_2Rnd`, `ace_hot_3_6Rnd`, `ace_hot_3_2Rnd`
- Pylon Magazines: `ace_hot_1_PylonMissile_1Rnd`, `ace_hot_1_PylonRack_1Rnd`, `ace_hot_1_PylonRack_3Rnd`, `ace_hot_1_PylonRack_4Rnd`, `ace_hot_2_PylonMissile_1Rnd`, `ace_hot_2_PylonRack_1Rnd`, `ace_hot_2_PylonRack_3Rnd`, `ace_hot_2_PylonRack_4Rnd`, `ace_hot_2mp_PylonMissile_1Rnd`, `ace_hot_2mp_PylonRack_1Rnd`, `ace_hot_2mp_PylonRack_3Rnd`, `ace_hot_2mp_PylonRack_4Rnd`, `ace_hot_3_PylonMissile_1Rnd`, `ace_hot_3_PylonRack_1Rnd`, `ace_hot_3_PylonRack_3Rnd`, `ace_hot_3_PylonRack_4Rnd`
### 3.2 Script Example
- Adding HOT to e.g. a Cessna Civilian Plane:
```cpp
if (local this) then {
this addWeaponTurret ["ace_hot_generic_launcher", [-1]];
this addMagazineTurret ["ace_hot_2mp_6Rnd", [-1]];
this addMagazineTurret ["ace_hot_3_6Rnd", [-1]];
};
```
## 4. Dependencies
{% include dependencies_list.md component="hot" %}