From 75d8e5be224502ee24f795ebbdb171cfb80f1243 Mon Sep 17 00:00:00 2001 From: Brett Mayson Date: Mon, 16 Jun 2025 23:32:43 -0600 Subject: [PATCH 01/17] missile defense rewrite --- .hemtt/launch.toml | 12 +- .../missileDefense.Stratis/initServer.sqf | 9 + .../missileDefense.Stratis/mission.sqm | 1472 +++++++++++++++++ .vscode/settings.json | 3 +- addons/missile_defense/$PBOPREFIX$ | 1 + addons/missile_defense/CfgEventHandlers.hpp | 18 + addons/missile_defense/XEH_PREP.hpp | 5 + addons/missile_defense/XEH_postInitServer.sqf | 0 addons/missile_defense/XEH_preInit.sqf | 61 + addons/missile_defense/XEH_preInitServer.sqf | 29 + addons/missile_defense/XEH_preStartServer.sqf | 3 + addons/missile_defense/config.cpp | 18 + .../functions/fnc_createSystem.sqf | 52 + .../functions/fnc_interceptorPFH.sqf | 66 + .../functions/fnc_registerLauncher.sqf | 43 + .../functions/fnc_registerTracker.sqf | 41 + .../functions/fnc_systemPFH.sqf | 135 ++ addons/missile_defense/initSettings.inc.sqf | 49 + addons/missile_defense/script_component.hpp | 22 + addons/missile_defense/stringtable.xml | 41 + 20 files changed, 2077 insertions(+), 3 deletions(-) create mode 100644 .hemtt/missions/missileDefense.Stratis/initServer.sqf create mode 100644 .hemtt/missions/missileDefense.Stratis/mission.sqm create mode 100644 addons/missile_defense/$PBOPREFIX$ create mode 100644 addons/missile_defense/CfgEventHandlers.hpp create mode 100644 addons/missile_defense/XEH_PREP.hpp create mode 100644 addons/missile_defense/XEH_postInitServer.sqf create mode 100644 addons/missile_defense/XEH_preInit.sqf create mode 100644 addons/missile_defense/XEH_preInitServer.sqf create mode 100644 addons/missile_defense/XEH_preStartServer.sqf create mode 100644 addons/missile_defense/config.cpp create mode 100644 addons/missile_defense/functions/fnc_createSystem.sqf create mode 100644 addons/missile_defense/functions/fnc_interceptorPFH.sqf create mode 100644 addons/missile_defense/functions/fnc_registerLauncher.sqf create mode 100644 addons/missile_defense/functions/fnc_registerTracker.sqf create mode 100644 addons/missile_defense/functions/fnc_systemPFH.sqf create mode 100644 addons/missile_defense/initSettings.inc.sqf create mode 100644 addons/missile_defense/script_component.hpp create mode 100644 addons/missile_defense/stringtable.xml diff --git a/.hemtt/launch.toml b/.hemtt/launch.toml index 767dc35bcde..3c7e3eb30b1 100644 --- a/.hemtt/launch.toml +++ b/.hemtt/launch.toml @@ -54,4 +54,14 @@ workshop = [ extends = "cup" workshop = [ "1369691841", # Community Factions Project -] \ No newline at end of file +] + +[zen] +extends = "default" +workshop = [ + "1779063631", # Zeus Enhanced +] + +[missile_defense] +extends = "default" +mission = "missileDefense.Stratis" diff --git a/.hemtt/missions/missileDefense.Stratis/initServer.sqf b/.hemtt/missions/missileDefense.Stratis/initServer.sqf new file mode 100644 index 00000000000..b3f57c9cd1e --- /dev/null +++ b/.hemtt/missions/missileDefense.Stratis/initServer.sqf @@ -0,0 +1,9 @@ +/// Create a system that engages independent side projectiles. +private _defense = [[independent]] call ace_missile_defense_fnc_createSystem; + +[_defense, w_tracker_1] call ace_missile_defense_fnc_registerTracker; +[_defense, w_tracker_2] call ace_missile_defense_fnc_registerTracker; + +[_defense, w_launcher_1] call ace_missile_defense_fnc_registerLauncher; +[_defense, w_launcher_2] call ace_missile_defense_fnc_registerLauncher; +[_defense, w_launcher_3] call ace_missile_defense_fnc_registerLauncher; diff --git a/.hemtt/missions/missileDefense.Stratis/mission.sqm b/.hemtt/missions/missileDefense.Stratis/mission.sqm new file mode 100644 index 00000000000..523a60e43a8 --- /dev/null +++ b/.hemtt/missions/missileDefense.Stratis/mission.sqm @@ -0,0 +1,1472 @@ +version=54; +class EditorData +{ + moveGridStep=1; + angleGridStep=0.2617994; + scaleGridStep=1; + autoGroupingDist=10; + toggles=1; + class ItemIDProvider + { + nextID=71; + }; + class Camera + { + pos[]={6408.251,29.916698,5395.3867}; + dir[]={-0.81033069,-0.28090084,0.51426136}; + up[]={-0.23717296,0.95973581,0.1505174}; + aside[]={0.5358355,-1.382723e-07,0.84432471}; + }; +}; +binarizationWanted=0; +sourceName="missiledefense"; +addons[]= +{ + "A3_Characters_F_Common", + "A3_Static_F_Sams_Radar_System_01", + "A3_Static_F_Jets_SAM_System_01", + "A3_Soft_F_Gamma_Truck_02", + "ace_realisticnames", + "A3_Characters_F", + "A3_Static_F_Mortar_01", + "A3_Characters_F_AoW", + "A3_Armor_F_Gamma_MBT_02" +}; +class AddonsMetaData +{ + class List + { + items=7; + class Item0 + { + className="A3_Characters_F"; + name="Arma 3 Alpha - Characters and Clothing"; + author="Bohemia Interactive"; + url="https://www.arma3.com"; + }; + class Item1 + { + className="A3_Static_F_Sams"; + name="Arma 3 Sams - Turrets"; + author="Bohemia Interactive"; + url="https://www.arma3.com"; + }; + class Item2 + { + className="A3_Static_F_Jets"; + name="Arma 3 Jets - Turrets"; + author="Bohemia Interactive"; + url="https://www.arma3.com"; + }; + class Item3 + { + className="A3_Soft_F_Gamma"; + name="Arma 3 - Unarmored Land Vehicles"; + author="Bohemia Interactive"; + url="https://www.arma3.com"; + }; + class Item4 + { + className="A3_Static_F"; + name="Arma 3 Alpha - Turrets"; + author="Bohemia Interactive"; + url="https://www.arma3.com"; + }; + class Item5 + { + className="A3_Characters_F_AoW"; + name="Arma 3 Art of War - Characters and Clothing"; + author="Bohemia Interactive"; + url="https://www.arma3.com"; + }; + class Item6 + { + className="A3_Armor_F_Gamma"; + name="Arma 3 - Armored Land Vehicles"; + author="Bohemia Interactive"; + url="https://www.arma3.com"; + }; + }; +}; +dlcs[]= +{ + "Jets", + "AoW" +}; +randomSeed=4977539; +class ScenarioData +{ + author="Brett"; +}; +class Mission +{ + class Intel + { + timeOfChanges=1800.0002; + startWeather=0.30000001; + startWind=0.1; + startWaves=0.1; + forecastWeather=0.30000001; + forecastWind=0.1; + forecastWaves=0.1; + forecastLightnings=0.1; + wavesForced=1; + windForced=1; + year=2035; + month=7; + day=6; + hour=12; + minute=0; + startFogDecay=0.014; + forecastFogDecay=0.014; + }; + class Entities + { + items=28; + class Item0 + { + dataType="Group"; + side="West"; + class Entities + { + items=1; + class Item0 + { + dataType="Object"; + class PositionInfo + { + position[]={1841.5955,8.430357,5753.5996}; + angles[]={0,2.2108259,0}; + }; + side="West"; + flags=2; + class Attributes + { + name="w_tracker_1G"; + }; + id=2; + type="B_UAV_AI"; + atlOffset=2.9289188; + }; + }; + class Attributes + { + }; + class CrewLinks + { + class LinkIDProvider + { + nextID=1; + }; + class Links + { + items=1; + class Item0 + { + linkID=0; + item0=2; + item1=1; + class CustomData + { + role=2; + turretPath[]={0}; + }; + }; + }; + }; + id=0; + atlOffset=4.7683716e-07; + }; + class Item1 + { + dataType="Object"; + class PositionInfo + { + position[]={1841.595,8.4289188,5753.5498}; + angles[]={0,2.2108259,0}; + }; + side="West"; + flags=6; + class Attributes + { + name="w_tracker_1"; + reportRemoteTargets=1; + receiveRemoteTargets=1; + reportOwnPosition=1; + aiRadarUsage=1; + }; + id=1; + type="B_Radar_System_01_F"; + atlOffset=4.7683716e-07; + }; + class Item2 + { + dataType="Group"; + side="West"; + class Entities + { + items=1; + class Item0 + { + dataType="Object"; + class PositionInfo + { + position[]={1634.5385,8.430357,5396.5015}; + angles[]={0,2.2108259,0}; + }; + side="West"; + flags=2; + class Attributes + { + name="w_tracker_1G_1"; + }; + id=4; + type="B_UAV_AI"; + atlOffset=2.9289188; + }; + }; + class Attributes + { + }; + class CrewLinks + { + class LinkIDProvider + { + nextID=1; + }; + class Links + { + items=1; + class Item0 + { + linkID=0; + item0=4; + item1=5; + class CustomData + { + role=2; + turretPath[]={0}; + }; + }; + }; + }; + id=3; + atlOffset=4.7683716e-07; + }; + class Item3 + { + dataType="Object"; + class PositionInfo + { + position[]={1672.0404,8.4289188,5380.5679}; + angles[]={0,2.2108259,0}; + }; + side="West"; + flags=6; + class Attributes + { + name="w_tracker_2"; + reportRemoteTargets=1; + receiveRemoteTargets=1; + reportOwnPosition=1; + aiRadarUsage=1; + }; + id=5; + type="B_Radar_System_01_F"; + atlOffset=4.7683716e-07; + }; + class Item4 + { + dataType="Group"; + side="West"; + class Entities + { + items=1; + class Item0 + { + dataType="Object"; + class PositionInfo + { + position[]={1865.6261,7.3601575,5768.5386}; + angles[]={0,2.125968,0.0075049158}; + }; + side="West"; + flags=2; + class Attributes + { + name="w_launcher_1G"; + }; + id=8; + type="B_UAV_AI"; + atlOffset=1.7565231; + }; + }; + class Attributes + { + }; + class CrewLinks + { + class LinkIDProvider + { + nextID=1; + }; + class Links + { + items=1; + class Item0 + { + linkID=0; + item0=8; + item1=7; + class CustomData + { + role=2; + turretPath[]={0}; + }; + }; + }; + }; + id=6; + atlOffset=-4.7683716e-07; + }; + class Item5 + { + dataType="Object"; + class PositionInfo + { + position[]={1860.7798,7.3223705,5771.8071}; + angles[]={0,2.125968,0.0075049158}; + }; + side="West"; + flags=6; + class Attributes + { + name="w_launcher_1"; + reportRemoteTargets=1; + receiveRemoteTargets=1; + reportOwnPosition=1; + aiRadarUsage=1; + }; + id=7; + type="B_SAM_System_01_F"; + atlOffset=-4.7683716e-07; + }; + class Item6 + { + dataType="Group"; + side="West"; + class Entities + { + items=1; + class Item0 + { + dataType="Object"; + class PositionInfo + { + position[]={1853.2793,7.2942109,5573.5566}; + angles[]={0,2.125968,0}; + }; + side="West"; + flags=2; + class Attributes + { + name="w_launcher_1G_1"; + }; + id=10; + type="B_UAV_AI"; + atlOffset=1.7927723; + }; + }; + class Attributes + { + }; + class CrewLinks + { + class LinkIDProvider + { + nextID=1; + }; + class Links + { + items=1; + class Item0 + { + linkID=0; + item0=10; + item1=11; + class CustomData + { + role=2; + turretPath[]={0}; + }; + }; + }; + }; + id=9; + atlOffset=-4.7683716e-07; + }; + class Item7 + { + dataType="Object"; + class PositionInfo + { + position[]={1848.433,7.2564731,5576.8252}; + angles[]={0,2.125968,0}; + }; + side="West"; + flags=6; + class Attributes + { + name="w_launcher_2"; + reportRemoteTargets=1; + receiveRemoteTargets=1; + reportOwnPosition=1; + aiRadarUsage=1; + }; + id=11; + type="B_SAM_System_01_F"; + atlOffset=-4.7683716e-07; + }; + class Item8 + { + dataType="Group"; + side="West"; + class Entities + { + items=1; + class Item0 + { + dataType="Object"; + class PositionInfo + { + position[]={1999.2325,7.4942107,5724.9116}; + angles[]={6.2815661,2.125968,6.2820406}; + }; + side="West"; + flags=2; + class Attributes + { + name="w_launcher_1G_2"; + }; + id=13; + type="B_UAV_AI"; + atlOffset=1.7927723; + }; + }; + class Attributes + { + }; + class CrewLinks + { + class LinkIDProvider + { + nextID=1; + }; + class Links + { + items=1; + class Item0 + { + linkID=0; + item0=13; + item1=14; + class CustomData + { + role=2; + turretPath[]={0}; + }; + }; + }; + }; + id=12; + atlOffset=0.080667496; + }; + class Item9 + { + dataType="Object"; + class PositionInfo + { + position[]={2131.7688,5.7456942,5854.6729}; + angles[]={6.2815661,2.125968,6.2820406}; + }; + side="West"; + flags=6; + class Attributes + { + name="w_launcher_3"; + reportRemoteTargets=1; + receiveRemoteTargets=1; + reportOwnPosition=1; + aiRadarUsage=1; + }; + id=14; + type="B_SAM_System_01_F"; + atlOffset=0.080667496; + }; + class Item10 + { + dataType="Group"; + side="West"; + class Entities + { + items=1; + class Item0 + { + dataType="Object"; + class PositionInfo + { + position[]={2005.0648,4.7820444,5320.2202}; + angles[]={0,2.125968,0.012496647}; + }; + side="West"; + flags=2; + class Attributes + { + name="w_launcher_1G_3"; + }; + id=16; + type="B_UAV_AI"; + atlOffset=1.7961347; + }; + }; + class Attributes + { + }; + class CrewLinks + { + class LinkIDProvider + { + nextID=1; + }; + class Links + { + items=1; + class Item0 + { + linkID=0; + item0=16; + item1=17; + class CustomData + { + role=2; + turretPath[]={0}; + }; + }; + }; + }; + id=15; + atlOffset=-0.00018239021; + }; + class Item11 + { + dataType="Object"; + class PositionInfo + { + position[]={2002.6296,4.7092991,5330.0762}; + angles[]={0,2.125968,0.012496647}; + }; + side="West"; + flags=6; + class Attributes + { + name="w_launcher_4"; + reportRemoteTargets=1; + receiveRemoteTargets=1; + reportOwnPosition=1; + aiRadarUsage=1; + }; + id=17; + type="B_SAM_System_01_F"; + atlOffset=-0.00018239021; + }; + class Item12 + { + dataType="Object"; + class PositionInfo + { + position[]={6348.5483,9.9967537,5395.127}; + angles[]={0.079831354,5.3393812,0.029984757}; + }; + side="Independent"; + flags=4; + class Attributes + { + fuel=0; + name="i_launcher_1"; + }; + id=19; + type="I_Truck_02_MRL_F"; + atlOffset=-0.011143208; + }; + class Item13 + { + dataType="Group"; + side="Independent"; + class Entities + { + items=6; + class Item0 + { + dataType="Object"; + class PositionInfo + { + position[]={4370.0044,226.53734,3808.5708}; + angles[]={0.039985489,5.3393812,0.042481314}; + }; + side="Independent"; + flags=4; + class Attributes + { + name="i_launcher_3D"; + }; + id=23; + type="I_soldier_F"; + atlOffset=-0.057830811; + }; + class Item1 + { + dataType="Object"; + class PositionInfo + { + position[]={4370.0044,229.18925,3808.5576}; + angles[]={0.039985489,5.3393812,0.042481314}; + }; + side="Independent"; + flags=2; + class Attributes + { + name="i_launcher_3G"; + }; + id=24; + type="I_soldier_F"; + atlOffset=2.5948029; + }; + class Item2 + { + dataType="Object"; + class PositionInfo + { + position[]={4368.9648,224.92839,3763.4426}; + angles[]={0.079831354,5.3393812,0.029984757}; + }; + side="Independent"; + flags=4; + class Attributes + { + name="i_launcher_1D"; + }; + id=20; + type="I_soldier_F"; + }; + class Item3 + { + dataType="Object"; + class PositionInfo + { + position[]={4368.9648,227.58031,3763.4294}; + angles[]={0.079831354,5.3393812,0.029984757}; + }; + side="Independent"; + class Attributes + { + name="i_launcher_1G"; + }; + id=21; + type="I_soldier_F"; + atlOffset=2.6519775; + class CustomAttributes + { + class Attribute0 + { + property="speaker"; + expression="_this setspeaker _value;"; + class Value + { + class data + { + singleType="STRING"; + value="Male04GRE"; + }; + }; + }; + class Attribute1 + { + property="pitch"; + expression="_this setpitch _value;"; + class Value + { + class data + { + singleType="SCALAR"; + value=0.99000001; + }; + }; + }; + nAttributes=2; + }; + }; + class Item4 + { + dataType="Object"; + class PositionInfo + { + position[]={4359.6445,225.93385,3791.9194}; + angles[]={0.079831354,5.3393812,0.044977132}; + }; + side="Independent"; + flags=4; + class Attributes + { + name="i_launcher_2D"; + }; + id=27; + type="I_soldier_F"; + atlOffset=-0.13253784; + }; + class Item5 + { + dataType="Object"; + class PositionInfo + { + position[]={4359.6445,228.58577,3791.9063}; + angles[]={0.079831354,5.3393812,0.044977132}; + }; + side="Independent"; + class Attributes + { + name="i_launcher_2G"; + }; + id=28; + type="I_soldier_F"; + atlOffset=2.5202637; + }; + }; + class Attributes + { + }; + class CrewLinks + { + class LinkIDProvider + { + nextID=6; + }; + class Links + { + items=6; + class Item0 + { + linkID=0; + item0=23; + item1=25; + class CustomData + { + role=1; + }; + }; + class Item1 + { + linkID=1; + item0=24; + item1=25; + class CustomData + { + role=2; + turretPath[]={0}; + }; + }; + class Item2 + { + linkID=2; + item0=20; + item1=19; + class CustomData + { + role=1; + }; + }; + class Item3 + { + linkID=3; + item0=21; + item1=19; + class CustomData + { + role=2; + turretPath[]={0}; + }; + }; + class Item4 + { + linkID=4; + item0=27; + item1=29; + class CustomData + { + role=1; + }; + }; + class Item5 + { + linkID=5; + item0=28; + item1=29; + class CustomData + { + role=2; + turretPath[]={0}; + }; + }; + }; + }; + id=22; + atlOffset=-0.010426044; + }; + class Item14 + { + dataType="Object"; + class PositionInfo + { + position[]={6352.0654,5.6805224,5456.207}; + angles[]={0.039985489,5.3393812,0.042481314}; + }; + side="Independent"; + flags=6; + class Attributes + { + fuel=0; + name="i_launcher_3"; + }; + id=25; + type="I_Truck_02_MRL_F"; + atlOffset=-0.010426044; + }; + class Item15 + { + dataType="Object"; + class PositionInfo + { + position[]={6340.3115,7.9278345,5424.2412}; + angles[]={0.079831354,5.3393812,0.044977132}; + }; + side="Independent"; + flags=4; + class Attributes + { + fuel=0; + name="i_launcher_2"; + }; + id=29; + type="I_Truck_02_MRL_F"; + atlOffset=-0.02998209; + }; + class Item16 + { + dataType="Group"; + side="West"; + class Entities + { + items=1; + class Item0 + { + dataType="Object"; + class PositionInfo + { + position[]={3934.6416,116.58717,6344.4492}; + angles[]={0,2.1423652,0}; + }; + side="West"; + flags=7; + class Attributes + { + isPlayer=1; + }; + id=31; + type="B_Competitor_F"; + }; + }; + class Attributes + { + }; + id=30; + }; + class Item17 + { + dataType="Group"; + side="Independent"; + class Entities + { + items=5; + class Item0 + { + dataType="Object"; + class PositionInfo + { + position[]={4084.835,221.95305,4596.6738}; + }; + side="Independent"; + flags=2; + class Attributes + { + }; + id=43; + type="I_soldier_F"; + atlOffset=0.72161865; + }; + class Item1 + { + dataType="Object"; + class PositionInfo + { + position[]={4090.7632,221.95305,4603.2163}; + }; + side="Independent"; + class Attributes + { + }; + id=45; + type="I_soldier_F"; + atlOffset=0.72161865; + }; + class Item2 + { + dataType="Object"; + class PositionInfo + { + position[]={4092.0813,221.95305,4598.0586}; + }; + side="Independent"; + class Attributes + { + }; + id=47; + type="I_soldier_F"; + atlOffset=0.72161865; + }; + class Item3 + { + dataType="Object"; + class PositionInfo + { + position[]={4088.9336,221.9039,4594.4902}; + angles[]={6.22824,0,0.037485532}; + }; + side="Independent"; + class Attributes + { + }; + id=49; + type="I_soldier_F"; + atlOffset=0.72322083; + }; + class Item4 + { + dataType="Object"; + class PositionInfo + { + position[]={4097.4507,221.95305,4596.8687}; + }; + side="Independent"; + class Attributes + { + }; + id=51; + type="I_soldier_F"; + atlOffset=0.72161865; + }; + }; + class Attributes + { + }; + class CrewLinks + { + class LinkIDProvider + { + nextID=5; + }; + class Links + { + items=5; + class Item0 + { + linkID=0; + item0=43; + item1=42; + class CustomData + { + role=2; + turretPath[]={0}; + }; + }; + class Item1 + { + linkID=1; + item0=45; + item1=44; + class CustomData + { + role=2; + turretPath[]={0}; + }; + }; + class Item2 + { + linkID=2; + item0=47; + item1=46; + class CustomData + { + role=2; + turretPath[]={0}; + }; + }; + class Item3 + { + linkID=3; + item0=49; + item1=48; + class CustomData + { + role=2; + turretPath[]={0}; + }; + }; + class Item4 + { + linkID=4; + item0=51; + item1=50; + class CustomData + { + role=2; + turretPath[]={0}; + }; + }; + }; + }; + id=41; + }; + class Item18 + { + dataType="Object"; + class PositionInfo + { + position[]={4084.835,221.95161,4596.624}; + }; + side="Independent"; + flags=6; + class Attributes + { + }; + id=42; + type="I_Mortar_01_F"; + }; + class Item19 + { + dataType="Object"; + class PositionInfo + { + position[]={4090.7632,221.95161,4603.1665}; + }; + side="Independent"; + flags=4; + class Attributes + { + }; + id=44; + type="I_Mortar_01_F"; + }; + class Item20 + { + dataType="Object"; + class PositionInfo + { + position[]={4092.0813,221.95161,4598.0088}; + }; + side="Independent"; + flags=4; + class Attributes + { + }; + id=46; + type="I_Mortar_01_F"; + }; + class Item21 + { + dataType="Object"; + class PositionInfo + { + position[]={4088.9336,221.90247,4594.4404}; + angles[]={6.22824,0,0.037485532}; + }; + side="Independent"; + flags=4; + class Attributes + { + }; + id=48; + type="I_Mortar_01_F"; + }; + class Item22 + { + dataType="Object"; + class PositionInfo + { + position[]={4097.4507,221.95161,4596.8188}; + }; + side="Independent"; + flags=4; + class Attributes + { + }; + id=50; + type="I_Mortar_01_F"; + }; + class Item23 + { + dataType="Group"; + side="West"; + class Entities + { + items=1; + class Item0 + { + dataType="Object"; + class PositionInfo + { + position[]={1908.0338,18.457346,5716.3872}; + angles[]={0,0.35642493,0}; + }; + side="West"; + flags=7; + class Attributes + { + }; + id=53; + type="B_Officer_Parade_F"; + }; + }; + class Attributes + { + }; + id=52; + }; + class Item24 + { + dataType="Object"; + class PositionInfo + { + position[]={6427.9336,10.260787,5430.6284}; + angles[]={0.0099949092,0,6.2756844}; + }; + side="Independent"; + flags=4; + class Attributes + { + }; + id=55; + type="O_MBT_02_arty_F"; + atlOffset=4.2915344e-06; + }; + class Item25 + { + dataType="Object"; + class PositionInfo + { + position[]={6413.8921,10.358639,5425.2012}; + angles[]={0.0075011365,0,6.2731905}; + }; + side="Independent"; + flags=4; + class Attributes + { + }; + id=60; + type="O_MBT_02_arty_F"; + }; + class Item26 + { + dataType="Object"; + class PositionInfo + { + position[]={6421.1738,10.497168,5415.5518}; + angles[]={0.019996032,0,6.2756844}; + }; + side="Independent"; + flags=4; + class Attributes + { + }; + id=65; + type="O_MBT_02_arty_F"; + atlOffset=6.1988831e-06; + }; + class Item27 + { + dataType="Group"; + side="Independent"; + class Entities + { + items=9; + class Item0 + { + dataType="Object"; + class PositionInfo + { + position[]={6427.9116,7.3461146,5430.6489}; + angles[]={0.0099949092,0,6.2756844}; + }; + side="Independent"; + flags=4; + class Attributes + { + }; + id=56; + type="O_crew_F"; + atlOffset=3.8146973e-06; + }; + class Item1 + { + dataType="Object"; + class PositionInfo + { + position[]={6427.9336,10.262226,5430.6782}; + angles[]={0.0099949092,0,6.2756844}; + }; + side="Independent"; + flags=2; + class Attributes + { + }; + id=57; + type="O_crew_F"; + atlOffset=2.9165735; + }; + class Item2 + { + dataType="Object"; + class PositionInfo + { + position[]={6427.9336,10.262226,5430.6782}; + angles[]={0.0099949092,0,6.2756844}; + }; + side="Independent"; + class Attributes + { + }; + id=58; + type="O_crew_F"; + atlOffset=2.9165735; + }; + class Item3 + { + dataType="Object"; + class PositionInfo + { + position[]={6413.8628,7.4439664,5425.229}; + angles[]={0.0075011365,0,6.2731905}; + }; + side="Independent"; + flags=4; + class Attributes + { + }; + id=61; + type="O_crew_F"; + }; + class Item4 + { + dataType="Object"; + class PositionInfo + { + position[]={6413.8921,10.360077,5425.251}; + angles[]={0.0075011365,0,6.2731905}; + }; + side="Independent"; + class Attributes + { + }; + id=62; + type="O_crew_F"; + atlOffset=2.9165688; + }; + class Item5 + { + dataType="Object"; + class PositionInfo + { + position[]={6413.8921,10.360077,5425.251}; + angles[]={0.0075011365,0,6.2731905}; + }; + side="Independent"; + class Attributes + { + }; + id=63; + type="O_crew_F"; + atlOffset=2.9165688; + }; + class Item6 + { + dataType="Object"; + class PositionInfo + { + position[]={6421.1519,7.5829329,5415.5435}; + angles[]={0.019996032,0,6.2756844}; + }; + side="Independent"; + flags=4; + class Attributes + { + }; + id=66; + type="O_crew_F"; + atlOffset=5.7220459e-06; + }; + class Item7 + { + dataType="Object"; + class PositionInfo + { + position[]={6421.1738,10.498606,5415.6016}; + angles[]={0.019996032,0,6.2756844}; + }; + side="Independent"; + class Attributes + { + }; + id=67; + type="O_crew_F"; + atlOffset=2.9170065; + }; + class Item8 + { + dataType="Object"; + class PositionInfo + { + position[]={6421.1738,10.498606,5415.6016}; + angles[]={0.019996032,0,6.2756844}; + }; + side="Independent"; + class Attributes + { + }; + id=68; + type="O_crew_F"; + atlOffset=2.9170065; + }; + }; + class Attributes + { + }; + class CrewLinks + { + class LinkIDProvider + { + nextID=9; + }; + class Links + { + items=9; + class Item0 + { + linkID=0; + item0=56; + item1=55; + class CustomData + { + role=1; + }; + }; + class Item1 + { + linkID=1; + item0=57; + item1=55; + class CustomData + { + role=2; + turretPath[]={0}; + }; + }; + class Item2 + { + linkID=2; + item0=58; + item1=55; + class CustomData + { + role=2; + turretPath[]={0,0}; + }; + }; + class Item3 + { + linkID=3; + item0=61; + item1=60; + class CustomData + { + role=1; + }; + }; + class Item4 + { + linkID=4; + item0=62; + item1=60; + class CustomData + { + role=2; + turretPath[]={0}; + }; + }; + class Item5 + { + linkID=5; + item0=63; + item1=60; + class CustomData + { + role=2; + turretPath[]={0,0}; + }; + }; + class Item6 + { + linkID=6; + item0=66; + item1=65; + class CustomData + { + role=1; + }; + }; + class Item7 + { + linkID=7; + item0=67; + item1=65; + class CustomData + { + role=2; + turretPath[]={0}; + }; + }; + class Item8 + { + linkID=8; + item0=68; + item1=65; + class CustomData + { + role=2; + turretPath[]={0,0}; + }; + }; + }; + }; + id=69; + atlOffset=4.2915344e-06; + }; + }; +}; diff --git a/.vscode/settings.json b/.vscode/settings.json index 490d2309b7d..4b6e57917e0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,6 @@ { "files.exclude": { "**/.hemttout": true, - "**/include": true, "**/extras": true } -} \ No newline at end of file +} diff --git a/addons/missile_defense/$PBOPREFIX$ b/addons/missile_defense/$PBOPREFIX$ new file mode 100644 index 00000000000..5803d666c6e --- /dev/null +++ b/addons/missile_defense/$PBOPREFIX$ @@ -0,0 +1 @@ +z\ace\addons\missile_defense diff --git a/addons/missile_defense/CfgEventHandlers.hpp b/addons/missile_defense/CfgEventHandlers.hpp new file mode 100644 index 00000000000..cbe06d1dc4d --- /dev/null +++ b/addons/missile_defense/CfgEventHandlers.hpp @@ -0,0 +1,18 @@ +class Extended_PreStart_EventHandlers { + class ADDON { + serverInit = QUOTE(call COMPILE_FILE(XEH_preStartServer)); + }; +}; + +class Extended_PreInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_FILE(XEH_preInit)); + serverInit = QUOTE(call COMPILE_FILE(XEH_preInitServer)); + }; +}; + +class Extended_PostInit_EventHandlers { + class ADDON { + serverInit = QUOTE(call COMPILE_SCRIPT(XEH_postInitServer)); + }; +}; diff --git a/addons/missile_defense/XEH_PREP.hpp b/addons/missile_defense/XEH_PREP.hpp new file mode 100644 index 00000000000..5bf111a6f44 --- /dev/null +++ b/addons/missile_defense/XEH_PREP.hpp @@ -0,0 +1,5 @@ +PREP(createSystem); +PREP(registerLauncher); +PREP(registerTracker); +PREP(systemPFH); +PREP(interceptorPFH); diff --git a/addons/missile_defense/XEH_postInitServer.sqf b/addons/missile_defense/XEH_postInitServer.sqf new file mode 100644 index 00000000000..e69de29bb2d diff --git a/addons/missile_defense/XEH_preInit.sqf b/addons/missile_defense/XEH_preInit.sqf new file mode 100644 index 00000000000..367e0be86bc --- /dev/null +++ b/addons/missile_defense/XEH_preInit.sqf @@ -0,0 +1,61 @@ +#include "script_component.hpp" + +ADDON = false; + +#include "initSettings.inc.sqf" + +GVAR(projectilesToIntercept) = []; + +{ + private _simulation = getText (_x >> "simulation"); + if (_simulation isEqualTo "shotMissile" || _simulation isEqualTo "shotShell") then { + GVAR(projectilesToIntercept) pushBack configName _x; + }; + private _submunition = getText (_x >> "submunitionAmmo"); + if (_submunition != "") then { + private _submunitionConfig = configFile >> "CfgAmmo" >> _submunition; + private _simulation = getText (_submunitionConfig >> "simulation"); + if (_simulation isEqualTo "shotMissile" || _simulation isEqualTo "shotShell") then { + GVAR(projectilesToIntercept) pushBack configName _x; + }; + }; +} forEach ("true" configClasses (configFile >> "CfgAmmo")); + +["All", "fired", { + params ["_unit", "", "", "", "", "", "_projectile"]; + TRACE_1("Fired projectile",_projectile); + _projectile setVariable [QGVAR(side), side _unit]; + if (local _projectile && { (typeOf _projectile) in GVAR(projectilesToIntercept) }) then { + [QGVAR(track), [_projectile]] call CBA_fnc_serverEvent; + }; + _projectile addEventHandler ["SubmunitionCreated", { + params ["_projectile", "_submunitionProjectile"]; + if ((getPosATL _submunitionProjectile) select 2 < 500) exitWith {}; + _submunitionProjectile setVariable [QGVAR(side), _projectile getVariable [QGVAR(side), side _projectile]]; + TRACE_1("Submunition created",_submunitionProjectile); + if (local _submunitionProjectile && { (typeOf _submunitionProjectile) in GVAR(projectilesToIntercept) }) then { + [QGVAR(track), [_submunitionProjectile]] call CBA_fnc_serverEvent; + }; + }]; +}] call CBA_fnc_addClassEventHandler; + +[QGVAR(registerLauncher), { + params ["_id", "_launcher"]; + if (local _launcher) then { + _launcher addEventHandler ["Fired", { + params ["_launcher", "", "", "", "", "", "_projectile"]; + private _target = _launcher getVariable [QEGVAR(missileguidance,target), objNull]; + private _system = _launcher getVariable [QGVAR(system), objNull]; + if !(isNull _target) then { + [QGVAR(registerInterceptor), [_system, _projectile, _target]] call CBA_fnc_serverEvent; + }; + }]; + }; +}] call CBA_fnc_addEventHandler; + +[QGVAR(destroyProjectile), { + params ["_projectile"]; + deleteVehicle _projectile; +}] call CBA_fnc_addEventHandler; + +ADDON = true; diff --git a/addons/missile_defense/XEH_preInitServer.sqf b/addons/missile_defense/XEH_preInitServer.sqf new file mode 100644 index 00000000000..f16aa3e8cfe --- /dev/null +++ b/addons/missile_defense/XEH_preInitServer.sqf @@ -0,0 +1,29 @@ +#include "script_component.hpp" + +ADDON = false; + +PREP_RECOMPILE_START; +#include "XEH_PREP.hpp" +PREP_RECOMPILE_END; + +GVAR(systems) = createHashMap; + +[QGVAR(track), { + params ["_projectile"]; + TRACE_1("Tracking projectile",_projectile); + { + (_y getOrDefault ["targets_possible", []]) pushBackUnique _projectile; + } forEach GVAR(systems); +}] call CBA_fnc_addEventHandler; + +[QGVAR(registerInterceptor), { + params ["_id", "_interceptor", "_target"]; + private _system = GVAR(systems) getOrDefault [_id, -1]; + if (_system isEqualTo -1) exitWith { + ERROR_1("Missile defense system with ID '%1' does not exist",_id); + }; + _system getOrDefault ["interceptors", []] pushBack [_interceptor, _target, getPosASLVisual _interceptor, _interceptor distance _target]; + TRACE_2("Registered interceptor",_interceptor,_target); +}] call CBA_fnc_addEventHandler; + +ADDON = true; diff --git a/addons/missile_defense/XEH_preStartServer.sqf b/addons/missile_defense/XEH_preStartServer.sqf new file mode 100644 index 00000000000..022888575ed --- /dev/null +++ b/addons/missile_defense/XEH_preStartServer.sqf @@ -0,0 +1,3 @@ +#include "script_component.hpp" + +#include "XEH_PREP.hpp" diff --git a/addons/missile_defense/config.cpp b/addons/missile_defense/config.cpp new file mode 100644 index 00000000000..a3b64494e97 --- /dev/null +++ b/addons/missile_defense/config.cpp @@ -0,0 +1,18 @@ +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + name = COMPONENT_NAME; + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + // no point having this system without missile guidance: nothing would happen + requiredAddons[] = {"ace_common","ace_missileguidance"}; + author = ECSTRING(common,ACETeam); + authors[] = {"Brett Mayson", "Dani (TCVM)"}; + url = ECSTRING(main,URL); + VERSION_CONFIG; + }; +}; + +#include "CfgEventHandlers.hpp" diff --git a/addons/missile_defense/functions/fnc_createSystem.sqf b/addons/missile_defense/functions/fnc_createSystem.sqf new file mode 100644 index 00000000000..997e1728fb3 --- /dev/null +++ b/addons/missile_defense/functions/fnc_createSystem.sqf @@ -0,0 +1,52 @@ +#include "..\script_component.hpp" +/* + * Author: Brett Mayson + * Create a missile defense system. + * + * Arguments: + * 0: Sides - The sides that the missile defense system will engage. If not provided, it will engage all sides. + * 1: ID - Optional, The ID of the missile defense system to create. + * + * Return Value: + * - The ID of the created missile defense system. + * + * Example: + * [] call ace_missile_defense_createSystem + * + * Public: No + */ + +if (!isServer) exitWith { + ERROR("missile_defense functions only run on server"); +}; + +private _id = if (count _this > 1) then { + _this select 1 +} else { + format ["%1", diag_tickTime] +}; + +if (_id in GVAR(systems)) exitWith { + ERROR_1("Missile defense system with ID '%1' already exists",_id); +}; + +GVAR(systems) set [_id, createHashMapFromArray [ + ["trackers", []], + ["launchers", []], + ["interceptors", []], + ["sides", _this select 0], + ["conditions", []], + ["targets_possible", []], + ["targets_pending", []], + ["targets_tracking", []] +]]; + +if (isNil QGVAR(systemIndex)) then { + GVAR(systemIndex) = 0; + [LINKFUNC(systemPFH)] call CBA_fnc_addPerFrameHandler; + [LINKFUNC(interceptorPFH)] call CBA_fnc_addPerFrameHandler; +}; + +TRACE_1("Registered missile defense system",_id); + +_id diff --git a/addons/missile_defense/functions/fnc_interceptorPFH.sqf b/addons/missile_defense/functions/fnc_interceptorPFH.sqf new file mode 100644 index 00000000000..58bb7aaef48 --- /dev/null +++ b/addons/missile_defense/functions/fnc_interceptorPFH.sqf @@ -0,0 +1,66 @@ +#include "..\script_component.hpp" +/* + * Author: Brett Mayson + * Processes each interceptor + * + * Arguments: + * 0: Args + * 1: Handle + * + * Return Value: + * None + * + * Example: + * [ace_missile_defense_interceptorPFH] call CBA_fnc_addPerFrameHandler + * + * Public: No + */ + +{ + private _interceptors = _y getOrDefault ["interceptors", []]; + { + _x params ["_projectile", "_target", "_lastPosition", "_lastDistance"]; + if (isNull _projectile) then { + _interceptors deleteAt _forEachIndex; + if !(isNull _target) then { + (_system getOrDefault ["targets_tracking", []]) pushBack _target; + TRACE_2("Interceptor no longer exists",_projectile,_target); + }; + continue; + }; + if (isNull _target) then { + // TODO pick a different target? + _interceptors deleteAt _forEachIndex; + continue; + }; + private _currentPosition = getPosASLVisual _projectile; + private _targetPosition = getPosASLVisual _target; + + private _posDiff = (_currentPosition vectorDiff _lastPosition); + private _lengthSqr = _posDiff vectorDotProduct _posDiff; + private _minDistance = if (_lengthSqr - 0.001 <= 0) then { + _lastPosition vectorDistance _targetPosition + } else { + private _d = (_targetPosition vectorDiff _lastPosition) vectorDotProduct (_currentPosition vectorDiff _lastPosition); + private _t = 0 max (1 min (_d / _lengthSqr)); + private _projection = _lastPosition vectorAdd ((_currentPosition vectorDiff _lastPosition) vectorMultiply _t); + _projection vectorDistance _targetPosition; + }; + + _x set [2, _currentPosition]; + _x set [3, _minDistance]; + + if (_minDistance <= GVAR(proximityFuseRange) || { _minDistance > _lastDistance }) then { + triggerAmmo _projectile; + _interceptors deleteAt _forEachIndex; + // if we overshot target, dont take out target + if (_minDistance <= _lastDistance && { GVAR(proximityFuseFailureChance) <= random 1 }) then { + private _explosion = createVehicle ["SmallSecondary", _target, [], 0, "CAN_COLLIDE"]; + [QGVAR(destroyProjectile), [_target]] call CBA_fnc_globalEvent; + } else { + (_system getOrDefault ["targets_tracking", []]) pushBack _target; + TRACE_2("Interceptor failed to intercept target",_projectile,_target); + }; + }; + } forEachReversed _interceptors; +} forEach GVAR(systems); diff --git a/addons/missile_defense/functions/fnc_registerLauncher.sqf b/addons/missile_defense/functions/fnc_registerLauncher.sqf new file mode 100644 index 00000000000..f7a16abfd93 --- /dev/null +++ b/addons/missile_defense/functions/fnc_registerLauncher.sqf @@ -0,0 +1,43 @@ +#include "..\script_component.hpp" +/* + * Author: Brett Mayson + * Register a launcher to a missile defense system. + * + * Arguments: + * 0: ID - The ID of the missile defense system to modify + * 1: Launcher - The launcher object to register. + * + * Return Value: + * None + * + * Example: + * [] call ace_missile_defense_registerLauncher + * + * Public: No + */ + +params ["_id", "_launcher"]; + +if (!isServer) exitWith { + ERROR("missile_defense functions only run on server"); +}; + +private _system = GVAR(systems) getOrDefault [_id, -1]; +if (_system isEqualTo -1) exitWith { + ERROR_1("Missile defense system with ID '%1' does not exist",_id); +}; + +private _launchers = _system getOrDefault ["launchers", []]; +if (_launcher in _launchers) exitWith { + ERROR_1("Missile defense launcher '%1' already registered",_launcher); +}; + +_launcher setVariable [QGVAR(system), _id, true]; +_launcher setVariable [QGVAR(state), LAUNCH_STATE_IDLE]; +_launcher setVariable [QGVAR(lastLaunchTime), 0]; + +_launchers pushBackUnique _launcher; + +[QGVAR(registerLauncher), [_id, _launcher], _launcher] call CBA_fnc_targetEvent; + +TRACE_2("Registered missile defense launcher",_launcher,_id); diff --git a/addons/missile_defense/functions/fnc_registerTracker.sqf b/addons/missile_defense/functions/fnc_registerTracker.sqf new file mode 100644 index 00000000000..41831bfa91c --- /dev/null +++ b/addons/missile_defense/functions/fnc_registerTracker.sqf @@ -0,0 +1,41 @@ +#include "..\script_component.hpp" +/* + * Author: Brett Mayson + * Register a tracker to a missile defense system. + * + * Arguments: + * 0: ID - The ID of the missile defense system to modify + * 1: Tracker - The tracker object to register. + * 2: Range - The range of the tracker in meters. If not provided, defaults to 3000. + * + * Return Value: + * None + * + * Example: + * [] call ace_missile_defense_registerTracker + * + * Public: No + */ + +params ["_id", "_tracker", ["_range", 3000]]; + +if (!isServer) exitWith { + ERROR("missile_defense functions only run on server"); +}; + +private _system = GVAR(systems) getOrDefault [_id, -1]; +if (_system isEqualTo -1) exitWith { + ERROR_1("Missile defense system with ID '%1' does not exist",_id); +}; + +private _trackers = _system getOrDefault ["trackers", []]; +if (_tracker in _trackers) exitWith { + ERROR_1("Missile defense tracker '%1' already registered",_tracker); +}; + +_tracker setVariable [QGVAR(system), _id, true]; +_tracker setVariable [QGVAR(range), _range]; + +_trackers pushBackUnique _tracker; + +TRACE_2("Registered missile defense tracker",_tracker,_id); diff --git a/addons/missile_defense/functions/fnc_systemPFH.sqf b/addons/missile_defense/functions/fnc_systemPFH.sqf new file mode 100644 index 00000000000..82e60441b85 --- /dev/null +++ b/addons/missile_defense/functions/fnc_systemPFH.sqf @@ -0,0 +1,135 @@ +#include "..\script_component.hpp" +/* + * Author: Brett Mayson + * Processes each missile defense system per frame. + * + * Arguments: + * 0: Args + * 1: Handle + * + * Return Value: + * None + * + * Example: + * [ace_missile_defense_systemPFH] call CBA_fnc_addPerFrameHandler + * + * Public: No + */ + +if (GVAR(systemIndex) > count GVAR(systems) - 1) then { + // If the system index is out of bounds, reset it to 0 + GVAR(systemIndex) = 0; +}; +private _system = GVAR(systems) getOrDefault [(keys GVAR(systems)) select GVAR(systemIndex), -1]; +GVAR(systemIndex) = GVAR(systemIndex) + 1; +if (_system isEqualTo -1) exitWith { + GVAR(systemIndex) = 0; +}; + +// Filter out launchers and trackers that are not alive +{ + private _items = _system getOrDefault [_x, []]; + { + if (isNull _x || !alive _x) then { + _items deleteAt _forEachIndex; + }; + } forEachReversed _items; +} forEach ["launchers", "trackers"]; + +// Move the first target from the possible targets to the pending targets for each missile defense system. +private _target = (_system getOrDefault ["targets_possible", []]) deleteAt 0; +if (!isNil "_target" && {!isNull _target}) then { + private _sides = _system getOrDefault ["sides", []]; + private _side = _target getVariable [QGVAR(side), sideUnknown]; + if (_side in _sides) then { + TRACE_1("Moved pending target",_target); + (_system getOrDefault ["targets_pending", []]) pushBack _target; + } else { + TRACE_2("Target side not in missile defense system sides",_target,_side); + }; +}; + +// Check the first pending target for in range +private _target = (_system getOrDefault ["targets_pending", []]) deleteAt 0; +if (!isNil "_target" && {!isNull _target}) then { + private _seen = false; + { + private _range = _x getVariable [QGVAR(range), 3000]; + if (_target distanceSqr _x <= _range * _range) exitWith { + TRACE_2("Tracker sees target, moved to tracking",_x,_target); + (_system getOrDefault ["targets_tracking", []]) pushBack _target; + _seen = true; + }; + } forEach (_system getOrDefault ["trackers", []]); + if (!_seen) then { + (_system getOrDefault ["targets_pending", []]) pushBack _target; + }; +}; + +// If able, fire at the first tracked target +private _tracked = (_system getOrDefault ["targets_tracking", []]) deleteAt 0; +if (!isNil "_tracked" && {!isNull _tracked}) then { + private _launchers = _system getOrDefault ["launchers", []]; + private _launchers = _launchers select { + private _state = _x getVariable [QGVAR(state), LAUNCH_STATE_IDLE]; + _state == LAUNCH_STATE_IDLE && someAmmo _x + }; + if (count _launchers == 0) exitWith { + TRACE_1("No launchers available to fire at tracked target",_tracked); + _system getOrDefault ["targets_tracking", []] pushBack _tracked; + }; + private _launcher = if (count _launchers > 1) then { + private _bestDistance = 1e10; + private _bestLauncher = -1; + { + private _distance = _x distance _tracked; + if (_distance < _bestDistance) then { + _bestDistance = _distance; + _bestLauncher = _x; + }; + } forEach _launchers; + _bestLauncher + } else { + _launchers select 0 + }; + TRACE_2("Launcher selected for tracked target",_launcher,_tracked); + _launcher setVariable [QEGVAR(missileguidance,target), _tracked]; + _launcher setVariable [QGVAR(state), LAUNCH_STATE_TRACKING]; +}; + +// Handle firing and cooldown +{ + private _launcher = _x; + private _state = _launcher getVariable [QGVAR(state), LAUNCH_STATE_IDLE]; + switch (_state) do { + case LAUNCH_STATE_TRACKING: { + private _target = _launcher getVariable [QEGVAR(missileguidance,target), objNull]; + _launcher lookAt getPosVisual _target; + if (isNull _target) then { + _launcher setVariable [QGVAR(state), LAUNCH_STATE_IDLE]; + } else { + private _directionToTarget = (getPosASLVisual _launcher) vectorFromTo (getPosASLVisual _target); + private _turretDirection = _launcher weaponDirection currentWeapon _launcher; + private _localDirection = _launcher vectorWorldToModelVisual _turretDirection; + + private _elevation = 90 - ((_localDirection#1) atan2 (_localDirection#2)); + private _angle = acos (_turretDirection vectorCos _directionToTarget); + + if (_angle <= GVAR(launchAcceptableAngle) && _elevation >= GVAR(launchAcceptableElevation)) then { + _launcher setVariable [QGVAR(state), LAUNCH_STATE_COOLDOWN]; + _launcher setVariable [QGVAR(lastLaunchTime), CBA_missionTime]; + private _turret = [_launcher, (crew _launcher) select 0] call CBA_fnc_turretPath; + [_launcher, _launcher currentWeaponTurret _turret] call BIS_fnc_fire; + private _target = _launcher getVariable QEGVAR(missileguidance,target); + private _engagedTargets = _x getVariable QGVAR(engagedTargets); + }; + }; + }; + case LAUNCH_STATE_COOLDOWN: { + private _lastLaunchTime = _launcher getVariable QGVAR(lastLaunchTime); + if (CBA_missionTime - _lastLaunchTime >= GVAR(timeBetweenLaunches)) then { + _launcher setVariable [QGVAR(state), LAUNCH_STATE_IDLE]; + }; + }; + }; +} forEach (_system getOrDefault ["launchers", []]); diff --git a/addons/missile_defense/initSettings.inc.sqf b/addons/missile_defense/initSettings.inc.sqf new file mode 100644 index 00000000000..e036c2e2db9 --- /dev/null +++ b/addons/missile_defense/initSettings.inc.sqf @@ -0,0 +1,49 @@ +[ + QGVAR(launchAcceptableAngle), "SLIDER", + [LSTRING(launchAcceptableAngle_setting), LSTRING(launchAcceptableAngle_description)], + LSTRING(category), + [1, 60, 20, 0, false], + true, // isGlobal + {[QGVAR(launchAcceptableAngle), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart +] call CBA_fnc_addSetting; + +[ + QGVAR(launchAcceptableElevation), "SLIDER", + [LSTRING(launchAcceptableElevation_setting), LSTRING(launchAcceptableElevation_description)], + LSTRING(category), + [-90, 90, 5, 0, false], + true, // isGlobal + {[QGVAR(launchAcceptableElevation), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart +] call CBA_fnc_addSetting; + +[ + QGVAR(timeBetweenLaunches), "SLIDER", + [LSTRING(timeBetweenLaunches_setting), LSTRING(timeBetweenLaunches_description)], + LSTRING(category), + [0, 60, 1, 0, false], + true, // isGlobal + {[QGVAR(timeBetweenLaunches), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart +] call CBA_fnc_addSetting; + +[ + QGVAR(proximityFuseRange), "SLIDER", + [LSTRING(proximityFuseRange_setting), LSTRING(proximityFuseRange_description)], + LSTRING(category), + [1, 50, 15, 0, false], + true, // isGlobal + {[QGVAR(timeBetweenLaunches), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart +] call CBA_fnc_addSetting; + +[ + QGVAR(proximityFuseFailureChance), "SLIDER", + [LSTRING(proximityFuseFailureChance_setting), LSTRING(proximityFuseFailureChance_description)], + LSTRING(category), + [0, 1, 0, 2, true], + true, // isGlobal + {[QGVAR(proximityFuseFailureChance), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart +] call CBA_fnc_addSetting; diff --git a/addons/missile_defense/script_component.hpp b/addons/missile_defense/script_component.hpp new file mode 100644 index 00000000000..2778ae2922b --- /dev/null +++ b/addons/missile_defense/script_component.hpp @@ -0,0 +1,22 @@ +#define COMPONENT missile_defense +#define COMPONENT_BEAUTIFIED Missile Defense +#include "\z\ace\addons\main\script_mod.hpp" + +// #define DRAW_TRACKING_INFO +#define DEBUG_MODE_FULL +// #define DISABLE_COMPILE_CACHE +// #define ENABLE_PERFORMANCE_COUNTERS + +#ifdef DEBUG_ENABLED_MISSILE_DEFENSE + #define DEBUG_MODE_FULL +#endif + +#ifdef DEBUG_SETTINGS_MISSILE_DEFENSE + #define DEBUG_SETTINGS DEBUG_SETTINGS_MISSILE_DEFENSE +#endif + +#define LAUNCH_STATE_IDLE 0 +#define LAUNCH_STATE_TRACKING 1 +#define LAUNCH_STATE_COOLDOWN 2 + +#include "\z\ace\addons\main\script_macros.hpp" diff --git a/addons/missile_defense/stringtable.xml b/addons/missile_defense/stringtable.xml new file mode 100644 index 00000000000..65fc8b2bdae --- /dev/null +++ b/addons/missile_defense/stringtable.xml @@ -0,0 +1,41 @@ + + + + + ACE Missile Defense + + + Enable the Missile Defense system + + + How many degrees offset the launcher can be before firing + + + Launch Acceptable Angle + + + The minimum number of degrees the launcher has to be pointing up/down before firing + + + Launch Acceptable Elevation + + + Chance for proximity fuse to fail to destroy target + + + Proximity Fuse Failure Chance + + + How close the interceptor has to be to the target in order to detonate + + + Proximity Fuse Range + + + Minimum number of seconds between each launch of an interceptor for a single launcher + + + Time Between Launches + + + From 34a0c15219d4fe723e656dfca753fb2e289d6d35 Mon Sep 17 00:00:00 2001 From: Brett Mayson Date: Mon, 16 Jun 2025 23:43:18 -0600 Subject: [PATCH 02/17] turn off debug mode --- addons/missile_defense/script_component.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/missile_defense/script_component.hpp b/addons/missile_defense/script_component.hpp index 2778ae2922b..750bdc83b1e 100644 --- a/addons/missile_defense/script_component.hpp +++ b/addons/missile_defense/script_component.hpp @@ -3,7 +3,7 @@ #include "\z\ace\addons\main\script_mod.hpp" // #define DRAW_TRACKING_INFO -#define DEBUG_MODE_FULL +// #define DEBUG_MODE_FULL // #define DISABLE_COMPILE_CACHE // #define ENABLE_PERFORMANCE_COUNTERS From 84c0d670fc853d88b6a49846586350bfb8fc3c21 Mon Sep 17 00:00:00 2001 From: Brett Mayson Date: Tue, 17 Jun 2025 00:16:09 -0600 Subject: [PATCH 03/17] some fixes --- addons/missile_defense/XEH_preInit.sqf | 6 ++++-- addons/missile_defense/functions/fnc_interceptorPFH.sqf | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/addons/missile_defense/XEH_preInit.sqf b/addons/missile_defense/XEH_preInit.sqf index 367e0be86bc..2de63f271e9 100644 --- a/addons/missile_defense/XEH_preInit.sqf +++ b/addons/missile_defense/XEH_preInit.sqf @@ -6,16 +6,18 @@ ADDON = false; GVAR(projectilesToIntercept) = []; +#define SIM_TYPES ["shotMissile", "shotShell", "shotRocket"] + { private _simulation = getText (_x >> "simulation"); - if (_simulation isEqualTo "shotMissile" || _simulation isEqualTo "shotShell") then { + if (_simulation in SIM_TYPES) then { GVAR(projectilesToIntercept) pushBack configName _x; }; private _submunition = getText (_x >> "submunitionAmmo"); if (_submunition != "") then { private _submunitionConfig = configFile >> "CfgAmmo" >> _submunition; private _simulation = getText (_submunitionConfig >> "simulation"); - if (_simulation isEqualTo "shotMissile" || _simulation isEqualTo "shotShell") then { + if (_simulation in SIM_TYPES) then { GVAR(projectilesToIntercept) pushBack configName _x; }; }; diff --git a/addons/missile_defense/functions/fnc_interceptorPFH.sqf b/addons/missile_defense/functions/fnc_interceptorPFH.sqf index 58bb7aaef48..9d68f8bd688 100644 --- a/addons/missile_defense/functions/fnc_interceptorPFH.sqf +++ b/addons/missile_defense/functions/fnc_interceptorPFH.sqf @@ -23,7 +23,7 @@ if (isNull _projectile) then { _interceptors deleteAt _forEachIndex; if !(isNull _target) then { - (_system getOrDefault ["targets_tracking", []]) pushBack _target; + (_y getOrDefault ["targets_tracking", []]) pushBack _target; TRACE_2("Interceptor no longer exists",_projectile,_target); }; continue; @@ -58,7 +58,7 @@ private _explosion = createVehicle ["SmallSecondary", _target, [], 0, "CAN_COLLIDE"]; [QGVAR(destroyProjectile), [_target]] call CBA_fnc_globalEvent; } else { - (_system getOrDefault ["targets_tracking", []]) pushBack _target; + (_y getOrDefault ["targets_tracking", []]) pushBack _target; TRACE_2("Interceptor failed to intercept target",_projectile,_target); }; }; From ae54093d2088bc2ddc8d477520c147d319a31b03 Mon Sep 17 00:00:00 2001 From: Brett Mayson Date: Fri, 12 Sep 2025 23:20:39 -0600 Subject: [PATCH 04/17] cleanup from reviews --- .../missileDefense.Stratis/mission.sqm | 8 +- addons/missile_defense/CfgEventHandlers.hpp | 8 +- addons/missile_defense/XEH_postInitServer.sqf | 0 addons/missile_defense/XEH_preInit.sqf | 73 ++++++++----------- addons/missile_defense/XEH_preStart.sqf | 24 ++++++ addons/missile_defense/XEH_preStartServer.sqf | 3 - .../functions/fnc_createSystem.sqf | 2 + .../functions/fnc_interceptorPFH.sqf | 4 +- .../functions/fnc_registerLauncher.sqf | 2 +- .../functions/fnc_registerTracker.sqf | 2 + .../functions/fnc_systemPFH.sqf | 4 +- addons/missile_defense/script_component.hpp | 3 +- 12 files changed, 69 insertions(+), 64 deletions(-) delete mode 100644 addons/missile_defense/XEH_postInitServer.sqf create mode 100644 addons/missile_defense/XEH_preStart.sqf delete mode 100644 addons/missile_defense/XEH_preStartServer.sqf diff --git a/.hemtt/missions/missileDefense.Stratis/mission.sqm b/.hemtt/missions/missileDefense.Stratis/mission.sqm index 523a60e43a8..f1917da6912 100644 --- a/.hemtt/missions/missileDefense.Stratis/mission.sqm +++ b/.hemtt/missions/missileDefense.Stratis/mission.sqm @@ -12,10 +12,10 @@ class EditorData }; class Camera { - pos[]={6408.251,29.916698,5395.3867}; - dir[]={-0.81033069,-0.28090084,0.51426136}; - up[]={-0.23717296,0.95973581,0.1505174}; - aside[]={0.5358355,-1.382723e-07,0.84432471}; + pos[]={3935.8252,120.30548,6351.7534}; + dir[]={-0.53098506,-0.34309506,-0.77483279}; + up[]={-0.19395103,0.93929845,-0.28302035}; + aside[]={-0.82490087,-2.6423368e-07,0.56529593}; }; }; binarizationWanted=0; diff --git a/addons/missile_defense/CfgEventHandlers.hpp b/addons/missile_defense/CfgEventHandlers.hpp index cbe06d1dc4d..ff0f0d6f5e7 100644 --- a/addons/missile_defense/CfgEventHandlers.hpp +++ b/addons/missile_defense/CfgEventHandlers.hpp @@ -1,6 +1,6 @@ class Extended_PreStart_EventHandlers { class ADDON { - serverInit = QUOTE(call COMPILE_FILE(XEH_preStartServer)); + init = QUOTE(call COMPILE_FILE(XEH_preStart)); }; }; @@ -10,9 +10,3 @@ class Extended_PreInit_EventHandlers { serverInit = QUOTE(call COMPILE_FILE(XEH_preInitServer)); }; }; - -class Extended_PostInit_EventHandlers { - class ADDON { - serverInit = QUOTE(call COMPILE_SCRIPT(XEH_postInitServer)); - }; -}; diff --git a/addons/missile_defense/XEH_postInitServer.sqf b/addons/missile_defense/XEH_postInitServer.sqf deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/addons/missile_defense/XEH_preInit.sqf b/addons/missile_defense/XEH_preInit.sqf index 2de63f271e9..6b6460fc14e 100644 --- a/addons/missile_defense/XEH_preInit.sqf +++ b/addons/missile_defense/XEH_preInit.sqf @@ -4,55 +4,40 @@ ADDON = false; #include "initSettings.inc.sqf" -GVAR(projectilesToIntercept) = []; - -#define SIM_TYPES ["shotMissile", "shotShell", "shotRocket"] - -{ - private _simulation = getText (_x >> "simulation"); - if (_simulation in SIM_TYPES) then { - GVAR(projectilesToIntercept) pushBack configName _x; - }; - private _submunition = getText (_x >> "submunitionAmmo"); - if (_submunition != "") then { - private _submunitionConfig = configFile >> "CfgAmmo" >> _submunition; - private _simulation = getText (_submunitionConfig >> "simulation"); - if (_simulation in SIM_TYPES) then { - GVAR(projectilesToIntercept) pushBack configName _x; +GVAR(trackingHandle) = -1; +[QGVAR(startTracking), { + if (GVAR(trackingHandle) != -1) exitWith {}; + GVAR(trackingHandle) = ["All", "fired", { + params ["_unit", "", "", "", "", "", "_projectile"]; + + // Handle interceptors from launchers + if (local _unit) then { + private _system = _unit getVariable [QGVAR(system), ""]; + if (_system != "") then { + private _target = _unit getVariable [QEGVAR(missileguidance,target), objNull]; + if !(isNull _target) then { + [QGVAR(registerInterceptor), [_system, _projectile, _target]] call CBA_fnc_serverEvent; + }; + }; }; - }; -} forEach ("true" configClasses (configFile >> "CfgAmmo")); -["All", "fired", { - params ["_unit", "", "", "", "", "", "_projectile"]; - TRACE_1("Fired projectile",_projectile); - _projectile setVariable [QGVAR(side), side _unit]; - if (local _projectile && { (typeOf _projectile) in GVAR(projectilesToIntercept) }) then { - [QGVAR(track), [_projectile]] call CBA_fnc_serverEvent; - }; - _projectile addEventHandler ["SubmunitionCreated", { - params ["_projectile", "_submunitionProjectile"]; - if ((getPosATL _submunitionProjectile) select 2 < 500) exitWith {}; - _submunitionProjectile setVariable [QGVAR(side), _projectile getVariable [QGVAR(side), side _projectile]]; - TRACE_1("Submunition created",_submunitionProjectile); - if (local _submunitionProjectile && { (typeOf _submunitionProjectile) in GVAR(projectilesToIntercept) }) then { - [QGVAR(track), [_submunitionProjectile]] call CBA_fnc_serverEvent; + // Handle profile that should be tracked + TRACE_1("Fired projectile",_projectile); + _projectile setVariable [QGVAR(side), side _unit]; + private _toIntercept = uiNamespace getVariable QGVAR(projectilesToIntercept); + if (local _projectile && { (typeOf _projectile) in _toIntercept }) then { + [QGVAR(track), [_projectile]] call CBA_fnc_serverEvent; }; - }]; -}] call CBA_fnc_addClassEventHandler; - -[QGVAR(registerLauncher), { - params ["_id", "_launcher"]; - if (local _launcher) then { - _launcher addEventHandler ["Fired", { - params ["_launcher", "", "", "", "", "", "_projectile"]; - private _target = _launcher getVariable [QEGVAR(missileguidance,target), objNull]; - private _system = _launcher getVariable [QGVAR(system), objNull]; - if !(isNull _target) then { - [QGVAR(registerInterceptor), [_system, _projectile, _target]] call CBA_fnc_serverEvent; + _projectile addEventHandler ["SubmunitionCreated", { + params ["_projectile", "_submunitionProjectile"]; + if ((getPosATL _submunitionProjectile) select 2 < 500) exitWith {}; + _submunitionProjectile setVariable [QGVAR(side), _projectile getVariable [QGVAR(side), side _projectile]]; + TRACE_1("Submunition created",_submunitionProjectile); + if (local _submunitionProjectile && { (typeOf _submunitionProjectile) in _toIntercept }) then { + [QGVAR(track), [_submunitionProjectile]] call CBA_fnc_serverEvent; }; }]; - }; + }] call CBA_fnc_addClassEventHandler; }] call CBA_fnc_addEventHandler; [QGVAR(destroyProjectile), { diff --git a/addons/missile_defense/XEH_preStart.sqf b/addons/missile_defense/XEH_preStart.sqf new file mode 100644 index 00000000000..04af2793383 --- /dev/null +++ b/addons/missile_defense/XEH_preStart.sqf @@ -0,0 +1,24 @@ +#include "script_component.hpp" + +#include "XEH_PREP.hpp" + +GVAR(projectilesToIntercept) = createHashMap; + +#define SIM_TYPES ["shotMissile", "shotShell", "shotRocket"] + +{ + private _simulation = getText (_x >> "simulation"); + if (_simulation in SIM_TYPES) then { + GVAR(projectilesToIntercept) set [configName _x, true]; + }; + private _submunition = getText (_x >> "submunitionAmmo"); + if (_submunition != "") then { + private _submunitionConfig = configFile >> "CfgAmmo" >> _submunition; + private _simulation = getText (_submunitionConfig >> "simulation"); + if (_simulation in SIM_TYPES) then { + GVAR(projectilesToIntercept) set [configName _x, true]; + }; + }; +} forEach ("true" configClasses (configFile >> "CfgAmmo")); + +uiNamespace setVariable [QGVAR(projectilesToIntercept), compileFinal GVAR(projectilesToIntercept)]; diff --git a/addons/missile_defense/XEH_preStartServer.sqf b/addons/missile_defense/XEH_preStartServer.sqf deleted file mode 100644 index 022888575ed..00000000000 --- a/addons/missile_defense/XEH_preStartServer.sqf +++ /dev/null @@ -1,3 +0,0 @@ -#include "script_component.hpp" - -#include "XEH_PREP.hpp" diff --git a/addons/missile_defense/functions/fnc_createSystem.sqf b/addons/missile_defense/functions/fnc_createSystem.sqf index 997e1728fb3..9fa1e201ee3 100644 --- a/addons/missile_defense/functions/fnc_createSystem.sqf +++ b/addons/missile_defense/functions/fnc_createSystem.sqf @@ -49,4 +49,6 @@ if (isNil QGVAR(systemIndex)) then { TRACE_1("Registered missile defense system",_id); +[QGVAR(startTracking)] call CBA_fnc_globalEventJIP; + _id diff --git a/addons/missile_defense/functions/fnc_interceptorPFH.sqf b/addons/missile_defense/functions/fnc_interceptorPFH.sqf index 9d68f8bd688..37234fb6b47 100644 --- a/addons/missile_defense/functions/fnc_interceptorPFH.sqf +++ b/addons/missile_defense/functions/fnc_interceptorPFH.sqf @@ -30,6 +30,7 @@ }; if (isNull _target) then { // TODO pick a different target? + TRACE_1("Interceptor target no longer exists, stopping management",_projectile); _interceptors deleteAt _forEachIndex; continue; }; @@ -44,7 +45,7 @@ private _d = (_targetPosition vectorDiff _lastPosition) vectorDotProduct (_currentPosition vectorDiff _lastPosition); private _t = 0 max (1 min (_d / _lengthSqr)); private _projection = _lastPosition vectorAdd ((_currentPosition vectorDiff _lastPosition) vectorMultiply _t); - _projection vectorDistance _targetPosition; + _projection vectorDistance _targetPosition }; _x set [2, _currentPosition]; @@ -57,6 +58,7 @@ if (_minDistance <= _lastDistance && { GVAR(proximityFuseFailureChance) <= random 1 }) then { private _explosion = createVehicle ["SmallSecondary", _target, [], 0, "CAN_COLLIDE"]; [QGVAR(destroyProjectile), [_target]] call CBA_fnc_globalEvent; + TRACE_2("Interceptor detonated on target",_projectile,_target); } else { (_y getOrDefault ["targets_tracking", []]) pushBack _target; TRACE_2("Interceptor failed to intercept target",_projectile,_target); diff --git a/addons/missile_defense/functions/fnc_registerLauncher.sqf b/addons/missile_defense/functions/fnc_registerLauncher.sqf index f7a16abfd93..8eb3aa659fb 100644 --- a/addons/missile_defense/functions/fnc_registerLauncher.sqf +++ b/addons/missile_defense/functions/fnc_registerLauncher.sqf @@ -38,6 +38,6 @@ _launcher setVariable [QGVAR(lastLaunchTime), 0]; _launchers pushBackUnique _launcher; -[QGVAR(registerLauncher), [_id, _launcher], _launcher] call CBA_fnc_targetEvent; +[QGVAR(registerLauncher), [_id, _launcher]] call CBA_fnc_globalEvent; TRACE_2("Registered missile defense launcher",_launcher,_id); diff --git a/addons/missile_defense/functions/fnc_registerTracker.sqf b/addons/missile_defense/functions/fnc_registerTracker.sqf index 41831bfa91c..4da1481479c 100644 --- a/addons/missile_defense/functions/fnc_registerTracker.sqf +++ b/addons/missile_defense/functions/fnc_registerTracker.sqf @@ -38,4 +38,6 @@ _tracker setVariable [QGVAR(range), _range]; _trackers pushBackUnique _tracker; +[QGVAR(registerTracker), [_id, _tracker]] call CBA_fnc_globalEvent; + TRACE_2("Registered missile defense tracker",_tracker,_id); diff --git a/addons/missile_defense/functions/fnc_systemPFH.sqf b/addons/missile_defense/functions/fnc_systemPFH.sqf index 82e60441b85..2f5c8cb1041 100644 --- a/addons/missile_defense/functions/fnc_systemPFH.sqf +++ b/addons/missile_defense/functions/fnc_systemPFH.sqf @@ -120,8 +120,8 @@ if (!isNil "_tracked" && {!isNull _tracked}) then { _launcher setVariable [QGVAR(lastLaunchTime), CBA_missionTime]; private _turret = [_launcher, (crew _launcher) select 0] call CBA_fnc_turretPath; [_launcher, _launcher currentWeaponTurret _turret] call BIS_fnc_fire; - private _target = _launcher getVariable QEGVAR(missileguidance,target); - private _engagedTargets = _x getVariable QGVAR(engagedTargets); + [QGVAR(launcherFired), [_id, _launcher, _target]] call CBA_fnc_globalEvent; + TRACE_2("Launcher fired at target",_launcher,_target); }; }; }; diff --git a/addons/missile_defense/script_component.hpp b/addons/missile_defense/script_component.hpp index 750bdc83b1e..3c81b73728a 100644 --- a/addons/missile_defense/script_component.hpp +++ b/addons/missile_defense/script_component.hpp @@ -2,8 +2,7 @@ #define COMPONENT_BEAUTIFIED Missile Defense #include "\z\ace\addons\main\script_mod.hpp" -// #define DRAW_TRACKING_INFO -// #define DEBUG_MODE_FULL +#define DEBUG_MODE_FULL // #define DISABLE_COMPILE_CACHE // #define ENABLE_PERFORMANCE_COUNTERS From e41fd4cca11e2850af27f2d70786d101eb6d42ed Mon Sep 17 00:00:00 2001 From: Brett Mayson Date: Fri, 12 Sep 2025 23:27:37 -0600 Subject: [PATCH 05/17] disable debug --- addons/missile_defense/script_component.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/missile_defense/script_component.hpp b/addons/missile_defense/script_component.hpp index 3c81b73728a..a0ea87beacb 100644 --- a/addons/missile_defense/script_component.hpp +++ b/addons/missile_defense/script_component.hpp @@ -2,7 +2,7 @@ #define COMPONENT_BEAUTIFIED Missile Defense #include "\z\ace\addons\main\script_mod.hpp" -#define DEBUG_MODE_FULL +// #define DEBUG_MODE_FULL // #define DISABLE_COMPILE_CACHE // #define ENABLE_PERFORMANCE_COUNTERS From f7f6513c8f87e9716210c0de53da3d5e783aa2ca Mon Sep 17 00:00:00 2001 From: Brett Mayson Date: Sat, 13 Sep 2025 00:10:15 -0600 Subject: [PATCH 06/17] take angle into account --- .../missileDefense.Stratis/initServer.sqf | 1 + .../missileDefense.Stratis/mission.sqm | 8 ++--- .../functions/fnc_systemPFH.sqf | 32 ++++++++++++++++--- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/.hemtt/missions/missileDefense.Stratis/initServer.sqf b/.hemtt/missions/missileDefense.Stratis/initServer.sqf index b3f57c9cd1e..491d9d5cbcc 100644 --- a/.hemtt/missions/missileDefense.Stratis/initServer.sqf +++ b/.hemtt/missions/missileDefense.Stratis/initServer.sqf @@ -7,3 +7,4 @@ private _defense = [[independent]] call ace_missile_defense_fnc_createSystem; [_defense, w_launcher_1] call ace_missile_defense_fnc_registerLauncher; [_defense, w_launcher_2] call ace_missile_defense_fnc_registerLauncher; [_defense, w_launcher_3] call ace_missile_defense_fnc_registerLauncher; +[_defense, w_launcher_4] call ace_missile_defense_fnc_registerLauncher; diff --git a/.hemtt/missions/missileDefense.Stratis/mission.sqm b/.hemtt/missions/missileDefense.Stratis/mission.sqm index f1917da6912..d5831b9b8e1 100644 --- a/.hemtt/missions/missileDefense.Stratis/mission.sqm +++ b/.hemtt/missions/missileDefense.Stratis/mission.sqm @@ -12,10 +12,10 @@ class EditorData }; class Camera { - pos[]={3935.8252,120.30548,6351.7534}; - dir[]={-0.53098506,-0.34309506,-0.77483279}; - up[]={-0.19395103,0.93929845,-0.28302035}; - aside[]={-0.82490087,-2.6423368e-07,0.56529593}; + pos[]={3938.1497,121.18645,6352.4463}; + dir[]={-0.48247248,-0.29674312,-0.82411397}; + up[]={-0.14992332,0.95495731,-0.25608489}; + aside[]={-0.86298507,7.4505806e-09,0.50522935}; }; }; binarizationWanted=0; diff --git a/addons/missile_defense/functions/fnc_systemPFH.sqf b/addons/missile_defense/functions/fnc_systemPFH.sqf index 2f5c8cb1041..d6d05189670 100644 --- a/addons/missile_defense/functions/fnc_systemPFH.sqf +++ b/addons/missile_defense/functions/fnc_systemPFH.sqf @@ -79,12 +79,36 @@ if (!isNil "_tracked" && {!isNull _tracked}) then { _system getOrDefault ["targets_tracking", []] pushBack _tracked; }; private _launcher = if (count _launchers > 1) then { - private _bestDistance = 1e10; - private _bestLauncher = -1; + TRACE_1("Scoring launchers for tracked target",_tracked); + private _bestScore = -1; + private _bestLauncher = objNull; { + if (lineIntersects [getPosASLVisual _x, getPosASLVisual _tracked, _x, _tracked]) then { + TRACE_2("Launcher cannot see target, skipping",_x,_tracked); + continue; + }; + private _distance = _x distance _tracked; - if (_distance < _bestDistance) then { - _bestDistance = _distance; + private _distanceFactor = (_distance / 5000) min 1; + + private _trackedDir = getDir _tracked; + private _trackedToLauncher = _tracked getRelDir _x; + + private _angleDiff = abs(_trackedDir - _trackedToLauncher); + if (_angleDiff > 180) then { + _angleDiff = 360 - _angleDiff; + }; + + private _interceptAngle = 180 - _angleDiff; + if (_interceptAngle > 90) then { + _interceptAngle = 180 - _interceptAngle; + }; + private _angleFactor = _interceptAngle / 90; + + private _score = (_angleFactor * 0.7) + (_distanceFactor * 0.3); + TRACE_4("Launcher scoring",_x,_distance,_interceptAngle,_score); + if (_bestScore < 0 || _score < _bestScore) then { + _bestScore = _score; _bestLauncher = _x; }; } forEach _launchers; From c09d13dce282eba698103942414250dfe4c52481 Mon Sep 17 00:00:00 2001 From: Brett Mayson Date: Sat, 13 Sep 2025 03:52:32 -0600 Subject: [PATCH 07/17] handle visiblity better --- .../missile_defense/functions/fnc_systemPFH.sqf | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/addons/missile_defense/functions/fnc_systemPFH.sqf b/addons/missile_defense/functions/fnc_systemPFH.sqf index d6d05189670..539bf406735 100644 --- a/addons/missile_defense/functions/fnc_systemPFH.sqf +++ b/addons/missile_defense/functions/fnc_systemPFH.sqf @@ -83,7 +83,9 @@ if (!isNil "_tracked" && {!isNull _tracked}) then { private _bestScore = -1; private _bestLauncher = objNull; { - if (lineIntersects [getPosASLVisual _x, getPosASLVisual _tracked, _x, _tracked]) then { + private _launcherPos = getPosASLVisual _x; + _launcherPos set [2, (_launcherPos#2) + 2.5]; + if (lineIntersects [_launcherPos, getPosASLVisual _tracked, _x, _tracked]) then { TRACE_2("Launcher cannot see target, skipping",_x,_tracked); continue; }; @@ -116,9 +118,14 @@ if (!isNil "_tracked" && {!isNull _tracked}) then { } else { _launchers select 0 }; - TRACE_2("Launcher selected for tracked target",_launcher,_tracked); - _launcher setVariable [QEGVAR(missileguidance,target), _tracked]; - _launcher setVariable [QGVAR(state), LAUNCH_STATE_TRACKING]; + if (isNull _launcher) then { + TRACE_1("No launchers could see tracked target",_tracked); + _system getOrDefault ["targets_tracking", []] pushBack _tracked; + } else { + TRACE_2("Launcher selected for tracked target",_launcher,_tracked); + _launcher setVariable [QEGVAR(missileguidance,target), _tracked]; + _launcher setVariable [QGVAR(state), LAUNCH_STATE_TRACKING]; + }; }; // Handle firing and cooldown From 022192bccb937289f815edeb7f4907d7c75b7f12 Mon Sep 17 00:00:00 2001 From: Brett Mayson Date: Sat, 13 Sep 2025 04:52:05 -0600 Subject: [PATCH 08/17] handle side better --- addons/missile_defense/XEH_preInit.sqf | 7 ++++--- addons/missile_defense/XEH_preInitServer.sqf | 3 ++- addons/missile_defense/functions/fnc_systemPFH.sqf | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/addons/missile_defense/XEH_preInit.sqf b/addons/missile_defense/XEH_preInit.sqf index 6b6460fc14e..9a252114626 100644 --- a/addons/missile_defense/XEH_preInit.sqf +++ b/addons/missile_defense/XEH_preInit.sqf @@ -26,15 +26,16 @@ GVAR(trackingHandle) = -1; _projectile setVariable [QGVAR(side), side _unit]; private _toIntercept = uiNamespace getVariable QGVAR(projectilesToIntercept); if (local _projectile && { (typeOf _projectile) in _toIntercept }) then { - [QGVAR(track), [_projectile]] call CBA_fnc_serverEvent; + [QGVAR(track), [_projectile, side _unit]] call CBA_fnc_serverEvent; }; _projectile addEventHandler ["SubmunitionCreated", { params ["_projectile", "_submunitionProjectile"]; if ((getPosATL _submunitionProjectile) select 2 < 500) exitWith {}; - _submunitionProjectile setVariable [QGVAR(side), _projectile getVariable [QGVAR(side), side _projectile]]; + private _side = _projectile getVariable [QGVAR(side), side _projectile]; + _submunitionProjectile setVariable [QGVAR(side), _side]; TRACE_1("Submunition created",_submunitionProjectile); if (local _submunitionProjectile && { (typeOf _submunitionProjectile) in _toIntercept }) then { - [QGVAR(track), [_submunitionProjectile]] call CBA_fnc_serverEvent; + [QGVAR(track), [_submunitionProjectile, _side]] call CBA_fnc_serverEvent; }; }]; }] call CBA_fnc_addClassEventHandler; diff --git a/addons/missile_defense/XEH_preInitServer.sqf b/addons/missile_defense/XEH_preInitServer.sqf index f16aa3e8cfe..38cb6dba881 100644 --- a/addons/missile_defense/XEH_preInitServer.sqf +++ b/addons/missile_defense/XEH_preInitServer.sqf @@ -9,7 +9,8 @@ PREP_RECOMPILE_END; GVAR(systems) = createHashMap; [QGVAR(track), { - params ["_projectile"]; + params ["_projectile", "_side"]; + _projectile setVariable [QGVAR(side), _side]; TRACE_1("Tracking projectile",_projectile); { (_y getOrDefault ["targets_possible", []]) pushBackUnique _projectile; diff --git a/addons/missile_defense/functions/fnc_systemPFH.sqf b/addons/missile_defense/functions/fnc_systemPFH.sqf index 539bf406735..0aa719b5b49 100644 --- a/addons/missile_defense/functions/fnc_systemPFH.sqf +++ b/addons/missile_defense/functions/fnc_systemPFH.sqf @@ -40,7 +40,7 @@ if (_system isEqualTo -1) exitWith { private _target = (_system getOrDefault ["targets_possible", []]) deleteAt 0; if (!isNil "_target" && {!isNull _target}) then { private _sides = _system getOrDefault ["sides", []]; - private _side = _target getVariable [QGVAR(side), sideUnknown]; + private _side = _target getVariable [QGVAR(side), side _target]; if (_side in _sides) then { TRACE_1("Moved pending target",_target); (_system getOrDefault ["targets_pending", []]) pushBack _target; From 09f87d00b9d0f6acb7b093936d1a24f08142072f Mon Sep 17 00:00:00 2001 From: Brett Mayson Date: Sat, 13 Sep 2025 06:34:27 -0600 Subject: [PATCH 09/17] more tracing --- .../missile_defense/functions/fnc_systemPFH.sqf | 10 +++++++++- addons/missile_defense/initSettings.inc.sqf | 15 +++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/addons/missile_defense/functions/fnc_systemPFH.sqf b/addons/missile_defense/functions/fnc_systemPFH.sqf index 0aa719b5b49..b61827b51c2 100644 --- a/addons/missile_defense/functions/fnc_systemPFH.sqf +++ b/addons/missile_defense/functions/fnc_systemPFH.sqf @@ -137,6 +137,7 @@ if (!isNil "_tracked" && {!isNull _tracked}) then { private _target = _launcher getVariable [QEGVAR(missileguidance,target), objNull]; _launcher lookAt getPosVisual _target; if (isNull _target) then { + TRACE_1("Lost target, returning to idle",_launcher); _launcher setVariable [QGVAR(state), LAUNCH_STATE_IDLE]; } else { private _directionToTarget = (getPosASLVisual _launcher) vectorFromTo (getPosASLVisual _target); @@ -153,7 +154,14 @@ if (!isNil "_tracked" && {!isNull _tracked}) then { [_launcher, _launcher currentWeaponTurret _turret] call BIS_fnc_fire; [QGVAR(launcherFired), [_id, _launcher, _target]] call CBA_fnc_globalEvent; TRACE_2("Launcher fired at target",_launcher,_target); - }; + } else { + if (_angle > GVAR(launchAcceptableAngle)) then { + TRACE_2("Tracking target, angle too wide",_launcher,_angle); + }; + if (_elevation < GVAR(launchAcceptableElevation)) then { + TRACE_2("Tracking target, elevation too low",_launcher,_elevation); + }; + } }; }; case LAUNCH_STATE_COOLDOWN: { diff --git a/addons/missile_defense/initSettings.inc.sqf b/addons/missile_defense/initSettings.inc.sqf index e036c2e2db9..0b76e66abf1 100644 --- a/addons/missile_defense/initSettings.inc.sqf +++ b/addons/missile_defense/initSettings.inc.sqf @@ -4,8 +4,7 @@ LSTRING(category), [1, 60, 20, 0, false], true, // isGlobal - {[QGVAR(launchAcceptableAngle), _this] call EFUNC(common,cbaSettings_settingChanged)}, - true // Needs mission restart + {[QGVAR(launchAcceptableAngle), _this] call EFUNC(common,cbaSettings_settingChanged)} ] call CBA_fnc_addSetting; [ @@ -14,8 +13,7 @@ LSTRING(category), [-90, 90, 5, 0, false], true, // isGlobal - {[QGVAR(launchAcceptableElevation), _this] call EFUNC(common,cbaSettings_settingChanged)}, - true // Needs mission restart + {[QGVAR(launchAcceptableElevation), _this] call EFUNC(common,cbaSettings_settingChanged)} ] call CBA_fnc_addSetting; [ @@ -24,8 +22,7 @@ LSTRING(category), [0, 60, 1, 0, false], true, // isGlobal - {[QGVAR(timeBetweenLaunches), _this] call EFUNC(common,cbaSettings_settingChanged)}, - true // Needs mission restart + {[QGVAR(timeBetweenLaunches), _this] call EFUNC(common,cbaSettings_settingChanged)} ] call CBA_fnc_addSetting; [ @@ -34,8 +31,7 @@ LSTRING(category), [1, 50, 15, 0, false], true, // isGlobal - {[QGVAR(timeBetweenLaunches), _this] call EFUNC(common,cbaSettings_settingChanged)}, - true // Needs mission restart + {[QGVAR(timeBetweenLaunches), _this] call EFUNC(common,cbaSettings_settingChanged)} ] call CBA_fnc_addSetting; [ @@ -44,6 +40,5 @@ LSTRING(category), [0, 1, 0, 2, true], true, // isGlobal - {[QGVAR(proximityFuseFailureChance), _this] call EFUNC(common,cbaSettings_settingChanged)}, - true // Needs mission restart + {[QGVAR(proximityFuseFailureChance), _this] call EFUNC(common,cbaSettings_settingChanged)} ] call CBA_fnc_addSetting; From 98ab0f08dcc6461f144cc39a2b86acf96460337e Mon Sep 17 00:00:00 2001 From: Brett Mayson Date: Sun, 14 Sep 2025 02:55:27 -0600 Subject: [PATCH 10/17] wip: hoping this fixes mp sync? --- .hemtt/launch.toml | 6 ++++++ addons/missile_defense/functions/fnc_interceptorPFH.sqf | 3 +++ 2 files changed, 9 insertions(+) diff --git a/.hemtt/launch.toml b/.hemtt/launch.toml index 3c7e3eb30b1..8c1d34a5489 100644 --- a/.hemtt/launch.toml +++ b/.hemtt/launch.toml @@ -65,3 +65,9 @@ workshop = [ [missile_defense] extends = "default" mission = "missileDefense.Stratis" + +[adt] +extends = "default" +workshop = [ + "3499977893", # ADT +] diff --git a/addons/missile_defense/functions/fnc_interceptorPFH.sqf b/addons/missile_defense/functions/fnc_interceptorPFH.sqf index 37234fb6b47..9784ad21651 100644 --- a/addons/missile_defense/functions/fnc_interceptorPFH.sqf +++ b/addons/missile_defense/functions/fnc_interceptorPFH.sqf @@ -57,6 +57,9 @@ // if we overshot target, dont take out target if (_minDistance <= _lastDistance && { GVAR(proximityFuseFailureChance) <= random 1 }) then { private _explosion = createVehicle ["SmallSecondary", _target, [], 0, "CAN_COLLIDE"]; + _target enableSimulationGlobal false; + _target hideObjectGlobal true; + deleteVehicle _target; [QGVAR(destroyProjectile), [_target]] call CBA_fnc_globalEvent; TRACE_2("Interceptor detonated on target",_projectile,_target); } else { From 18f62ff57580a9b68d02ac050e133bae9ddbc59d Mon Sep 17 00:00:00 2001 From: Brett Mayson Date: Sun, 14 Sep 2025 03:27:41 -0600 Subject: [PATCH 11/17] wip: hoping this fixes mp sync? --- addons/missile_defense/XEH_preInit.sqf | 3 +++ addons/missile_defense/functions/fnc_interceptorPFH.sqf | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/addons/missile_defense/XEH_preInit.sqf b/addons/missile_defense/XEH_preInit.sqf index 9a252114626..b26a53b7689 100644 --- a/addons/missile_defense/XEH_preInit.sqf +++ b/addons/missile_defense/XEH_preInit.sqf @@ -43,6 +43,9 @@ GVAR(trackingHandle) = -1; [QGVAR(destroyProjectile), { params ["_projectile"]; + TRACE_1("Destroying projectile",_projectile); + _projectile enableSimulation false; + _projectile hideObject true; deleteVehicle _projectile; }] call CBA_fnc_addEventHandler; diff --git a/addons/missile_defense/functions/fnc_interceptorPFH.sqf b/addons/missile_defense/functions/fnc_interceptorPFH.sqf index 9784ad21651..6294127ec6a 100644 --- a/addons/missile_defense/functions/fnc_interceptorPFH.sqf +++ b/addons/missile_defense/functions/fnc_interceptorPFH.sqf @@ -59,8 +59,10 @@ private _explosion = createVehicle ["SmallSecondary", _target, [], 0, "CAN_COLLIDE"]; _target enableSimulationGlobal false; _target hideObjectGlobal true; - deleteVehicle _target; - [QGVAR(destroyProjectile), [_target]] call CBA_fnc_globalEvent; + [QGVAR(hideProjectile), [_target]] call CBA_fnc_globalEvent; + [{ + deleteVehicle _this; + }, _target] call CBA_fnc_execNextFrame; TRACE_2("Interceptor detonated on target",_projectile,_target); } else { (_y getOrDefault ["targets_tracking", []]) pushBack _target; From 2d3d9a1614ec309571ccbb610853f9bfd2272b40 Mon Sep 17 00:00:00 2001 From: Brett Mayson Date: Sun, 14 Sep 2025 03:28:38 -0600 Subject: [PATCH 12/17] wip: hoping this fixes mp sync? --- addons/missile_defense/XEH_preInit.sqf | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/addons/missile_defense/XEH_preInit.sqf b/addons/missile_defense/XEH_preInit.sqf index b26a53b7689..d2f801a1c00 100644 --- a/addons/missile_defense/XEH_preInit.sqf +++ b/addons/missile_defense/XEH_preInit.sqf @@ -41,12 +41,11 @@ GVAR(trackingHandle) = -1; }] call CBA_fnc_addClassEventHandler; }] call CBA_fnc_addEventHandler; -[QGVAR(destroyProjectile), { +[QGVAR(hideProjectile), { params ["_projectile"]; - TRACE_1("Destroying projectile",_projectile); + TRACE_1("Hiding projectile",_projectile); _projectile enableSimulation false; _projectile hideObject true; - deleteVehicle _projectile; }] call CBA_fnc_addEventHandler; ADDON = true; From abdc3db498a215b09ce928bfa02e5bf91520cf39 Mon Sep 17 00:00:00 2001 From: Brett Mayson Date: Sun, 14 Sep 2025 05:17:55 -0600 Subject: [PATCH 13/17] use nearestObject for client vehicle deletion --- addons/missile_defense/CfgEventHandlers.hpp | 1 + addons/missile_defense/XEH_preInit.sqf | 7 ------- addons/missile_defense/XEH_preInitClient.sqf | 21 +++++++++++++++++++ addons/missile_defense/XEH_preInitServer.sqf | 3 --- .../functions/fnc_interceptorPFH.sqf | 8 ++----- .../functions/fnc_systemPFH.sqf | 2 +- 6 files changed, 25 insertions(+), 17 deletions(-) create mode 100644 addons/missile_defense/XEH_preInitClient.sqf diff --git a/addons/missile_defense/CfgEventHandlers.hpp b/addons/missile_defense/CfgEventHandlers.hpp index ff0f0d6f5e7..072d8581374 100644 --- a/addons/missile_defense/CfgEventHandlers.hpp +++ b/addons/missile_defense/CfgEventHandlers.hpp @@ -7,6 +7,7 @@ class Extended_PreStart_EventHandlers { class Extended_PreInit_EventHandlers { class ADDON { init = QUOTE(call COMPILE_FILE(XEH_preInit)); + clientInit = QUOTE(call COMPILE_FILE(XEH_preInitClient)); serverInit = QUOTE(call COMPILE_FILE(XEH_preInitServer)); }; }; diff --git a/addons/missile_defense/XEH_preInit.sqf b/addons/missile_defense/XEH_preInit.sqf index d2f801a1c00..9e3586678d7 100644 --- a/addons/missile_defense/XEH_preInit.sqf +++ b/addons/missile_defense/XEH_preInit.sqf @@ -41,11 +41,4 @@ GVAR(trackingHandle) = -1; }] call CBA_fnc_addClassEventHandler; }] call CBA_fnc_addEventHandler; -[QGVAR(hideProjectile), { - params ["_projectile"]; - TRACE_1("Hiding projectile",_projectile); - _projectile enableSimulation false; - _projectile hideObject true; -}] call CBA_fnc_addEventHandler; - ADDON = true; diff --git a/addons/missile_defense/XEH_preInitClient.sqf b/addons/missile_defense/XEH_preInitClient.sqf new file mode 100644 index 00000000000..9e8c2e961c8 --- /dev/null +++ b/addons/missile_defense/XEH_preInitClient.sqf @@ -0,0 +1,21 @@ +#include "script_component.hpp" + +GVAR(destroyRadius) = 20; + +[QGVAR(destroyProjectile), { + params ["_target", "_type", "_position"]; + if !(isNull _target) then { + deleteVehicle _target; + TRACE_1("Destroyed projectile using object",_target); + exitWith {}; + }; + private _near = nearestObjects [_position, [_type], GVAR(destroyRadius)]; + if (count _near > 0) then { + TRACE_2("Destroying nearby entities of type",_type,_near); + deleteVehicle _near; + } else { + TRACE_2("No nearby entities of type to destroy",_type,_position); + private _nearest = nearestObject [_position, _type]; + deleteVehicle _nearest; + }; +}] call CBA_fnc_addEventHandler; diff --git a/addons/missile_defense/XEH_preInitServer.sqf b/addons/missile_defense/XEH_preInitServer.sqf index 38cb6dba881..ba5dd8c76d3 100644 --- a/addons/missile_defense/XEH_preInitServer.sqf +++ b/addons/missile_defense/XEH_preInitServer.sqf @@ -1,7 +1,5 @@ #include "script_component.hpp" -ADDON = false; - PREP_RECOMPILE_START; #include "XEH_PREP.hpp" PREP_RECOMPILE_END; @@ -27,4 +25,3 @@ GVAR(systems) = createHashMap; TRACE_2("Registered interceptor",_interceptor,_target); }] call CBA_fnc_addEventHandler; -ADDON = true; diff --git a/addons/missile_defense/functions/fnc_interceptorPFH.sqf b/addons/missile_defense/functions/fnc_interceptorPFH.sqf index 6294127ec6a..ce4b6b023ed 100644 --- a/addons/missile_defense/functions/fnc_interceptorPFH.sqf +++ b/addons/missile_defense/functions/fnc_interceptorPFH.sqf @@ -57,12 +57,8 @@ // if we overshot target, dont take out target if (_minDistance <= _lastDistance && { GVAR(proximityFuseFailureChance) <= random 1 }) then { private _explosion = createVehicle ["SmallSecondary", _target, [], 0, "CAN_COLLIDE"]; - _target enableSimulationGlobal false; - _target hideObjectGlobal true; - [QGVAR(hideProjectile), [_target]] call CBA_fnc_globalEvent; - [{ - deleteVehicle _this; - }, _target] call CBA_fnc_execNextFrame; + [QGVAR(destroyProjectile), [_target, typeOf _target, getPos _target]] call CBA_fnc_globalEvent; + deleteVehicle _target; TRACE_2("Interceptor detonated on target",_projectile,_target); } else { (_y getOrDefault ["targets_tracking", []]) pushBack _target; diff --git a/addons/missile_defense/functions/fnc_systemPFH.sqf b/addons/missile_defense/functions/fnc_systemPFH.sqf index b61827b51c2..7553a89997d 100644 --- a/addons/missile_defense/functions/fnc_systemPFH.sqf +++ b/addons/missile_defense/functions/fnc_systemPFH.sqf @@ -152,7 +152,7 @@ if (!isNil "_tracked" && {!isNull _tracked}) then { _launcher setVariable [QGVAR(lastLaunchTime), CBA_missionTime]; private _turret = [_launcher, (crew _launcher) select 0] call CBA_fnc_turretPath; [_launcher, _launcher currentWeaponTurret _turret] call BIS_fnc_fire; - [QGVAR(launcherFired), [_id, _launcher, _target]] call CBA_fnc_globalEvent; + [QGVAR(launcherFired), [_launcher, _target, typeOf _target, getPos _target]] call CBA_fnc_globalEvent; TRACE_2("Launcher fired at target",_launcher,_target); } else { if (_angle > GVAR(launchAcceptableAngle)) then { From c189394034b533dff455924c1e9a4a880ecb3979 Mon Sep 17 00:00:00 2001 From: Brett Mayson Date: Sun, 14 Sep 2025 05:26:52 -0600 Subject: [PATCH 14/17] fix postInitClient --- addons/missile_defense/XEH_preInitClient.sqf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/addons/missile_defense/XEH_preInitClient.sqf b/addons/missile_defense/XEH_preInitClient.sqf index 9e8c2e961c8..9ab3f6223b3 100644 --- a/addons/missile_defense/XEH_preInitClient.sqf +++ b/addons/missile_defense/XEH_preInitClient.sqf @@ -4,10 +4,9 @@ GVAR(destroyRadius) = 20; [QGVAR(destroyProjectile), { params ["_target", "_type", "_position"]; - if !(isNull _target) then { + if !(isNull _target) exitWith { deleteVehicle _target; TRACE_1("Destroyed projectile using object",_target); - exitWith {}; }; private _near = nearestObjects [_position, [_type], GVAR(destroyRadius)]; if (count _near > 0) then { From 430804ced23fe8b90df0faf096651576b89c816a Mon Sep 17 00:00:00 2001 From: BrettMayson Date: Mon, 22 Dec 2025 20:03:22 -0600 Subject: [PATCH 15/17] Apply suggestions from code review Co-authored-by: Filip Maciejewski Co-authored-by: PabstMirror --- addons/missile_defense/XEH_preInit.sqf | 1 + addons/missile_defense/functions/fnc_createSystem.sqf | 2 +- addons/missile_defense/functions/fnc_interceptorPFH.sqf | 4 ++-- addons/missile_defense/functions/fnc_registerLauncher.sqf | 7 +++++-- addons/missile_defense/functions/fnc_systemPFH.sqf | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/addons/missile_defense/XEH_preInit.sqf b/addons/missile_defense/XEH_preInit.sqf index 9e3586678d7..aefe9e2cc6e 100644 --- a/addons/missile_defense/XEH_preInit.sqf +++ b/addons/missile_defense/XEH_preInit.sqf @@ -34,6 +34,7 @@ GVAR(trackingHandle) = -1; private _side = _projectile getVariable [QGVAR(side), side _projectile]; _submunitionProjectile setVariable [QGVAR(side), _side]; TRACE_1("Submunition created",_submunitionProjectile); + private _toIntercept = uiNamespace getVariable QGVAR(projectilesToIntercept); if (local _submunitionProjectile && { (typeOf _submunitionProjectile) in _toIntercept }) then { [QGVAR(track), [_submunitionProjectile, _side]] call CBA_fnc_serverEvent; }; diff --git a/addons/missile_defense/functions/fnc_createSystem.sqf b/addons/missile_defense/functions/fnc_createSystem.sqf index 9fa1e201ee3..b513352c428 100644 --- a/addons/missile_defense/functions/fnc_createSystem.sqf +++ b/addons/missile_defense/functions/fnc_createSystem.sqf @@ -13,7 +13,7 @@ * Example: * [] call ace_missile_defense_createSystem * - * Public: No + * Public: Yes */ if (!isServer) exitWith { diff --git a/addons/missile_defense/functions/fnc_interceptorPFH.sqf b/addons/missile_defense/functions/fnc_interceptorPFH.sqf index ce4b6b023ed..de9845231d3 100644 --- a/addons/missile_defense/functions/fnc_interceptorPFH.sqf +++ b/addons/missile_defense/functions/fnc_interceptorPFH.sqf @@ -40,12 +40,12 @@ private _posDiff = (_currentPosition vectorDiff _lastPosition); private _lengthSqr = _posDiff vectorDotProduct _posDiff; private _minDistance = if (_lengthSqr - 0.001 <= 0) then { - _lastPosition vectorDistance _targetPosition + _lastPosition vectorDistance _targetPosition // return } else { private _d = (_targetPosition vectorDiff _lastPosition) vectorDotProduct (_currentPosition vectorDiff _lastPosition); private _t = 0 max (1 min (_d / _lengthSqr)); private _projection = _lastPosition vectorAdd ((_currentPosition vectorDiff _lastPosition) vectorMultiply _t); - _projection vectorDistance _targetPosition + _projection vectorDistance _targetPosition // return }; _x set [2, _currentPosition]; diff --git a/addons/missile_defense/functions/fnc_registerLauncher.sqf b/addons/missile_defense/functions/fnc_registerLauncher.sqf index 8eb3aa659fb..48efc9cdee2 100644 --- a/addons/missile_defense/functions/fnc_registerLauncher.sqf +++ b/addons/missile_defense/functions/fnc_registerLauncher.sqf @@ -13,10 +13,13 @@ * Example: * [] call ace_missile_defense_registerLauncher * - * Public: No + * Public: Yes */ -params ["_id", "_launcher"]; +params [ + ["_id", "", [""]], + ["_launcher", objNull, [objNull]] +]; if (!isServer) exitWith { ERROR("missile_defense functions only run on server"); diff --git a/addons/missile_defense/functions/fnc_systemPFH.sqf b/addons/missile_defense/functions/fnc_systemPFH.sqf index 7553a89997d..ece0a19244b 100644 --- a/addons/missile_defense/functions/fnc_systemPFH.sqf +++ b/addons/missile_defense/functions/fnc_systemPFH.sqf @@ -30,7 +30,7 @@ if (_system isEqualTo -1) exitWith { { private _items = _system getOrDefault [_x, []]; { - if (isNull _x || !alive _x) then { + if !(alive _x) then { _items deleteAt _forEachIndex; }; } forEachReversed _items; From df69628d04ff8c68c134e5f78a97700e431f6589 Mon Sep 17 00:00:00 2001 From: Brett Mayson Date: Mon, 16 Feb 2026 09:35:28 -0600 Subject: [PATCH 16/17] review comments --- addons/missile_defense/functions/fnc_createSystem.sqf | 10 +++++----- .../missile_defense/functions/fnc_registerTracker.sqf | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/addons/missile_defense/functions/fnc_createSystem.sqf b/addons/missile_defense/functions/fnc_createSystem.sqf index b513352c428..0bdd5318e14 100644 --- a/addons/missile_defense/functions/fnc_createSystem.sqf +++ b/addons/missile_defense/functions/fnc_createSystem.sqf @@ -16,14 +16,14 @@ * Public: Yes */ +params ["_sides", ["_id", ""]]; + if (!isServer) exitWith { ERROR("missile_defense functions only run on server"); }; -private _id = if (count _this > 1) then { - _this select 1 -} else { - format ["%1", diag_tickTime] +if (_id == "") then { + _id = format ["%1-%2", diag_tickTime, count GVAR(systems)]; }; if (_id in GVAR(systems)) exitWith { @@ -34,7 +34,7 @@ GVAR(systems) set [_id, createHashMapFromArray [ ["trackers", []], ["launchers", []], ["interceptors", []], - ["sides", _this select 0], + ["sides", _sides], ["conditions", []], ["targets_possible", []], ["targets_pending", []], diff --git a/addons/missile_defense/functions/fnc_registerTracker.sqf b/addons/missile_defense/functions/fnc_registerTracker.sqf index 4da1481479c..04016240a4f 100644 --- a/addons/missile_defense/functions/fnc_registerTracker.sqf +++ b/addons/missile_defense/functions/fnc_registerTracker.sqf @@ -34,7 +34,7 @@ if (_tracker in _trackers) exitWith { }; _tracker setVariable [QGVAR(system), _id, true]; -_tracker setVariable [QGVAR(range), _range]; +_tracker setVariable [QGVAR(range), _range, true]; _trackers pushBackUnique _tracker; From afeba1dec140c0c6d4fab38111fb449aeece8422 Mon Sep 17 00:00:00 2001 From: Brett Mayson Date: Fri, 20 Mar 2026 14:57:41 -0600 Subject: [PATCH 17/17] kjw suggestions Co-Authored-By: SpicyBagpipes --- addons/missile_defense/functions/fnc_interceptorPFH.sqf | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/addons/missile_defense/functions/fnc_interceptorPFH.sqf b/addons/missile_defense/functions/fnc_interceptorPFH.sqf index de9845231d3..5bebc7dd408 100644 --- a/addons/missile_defense/functions/fnc_interceptorPFH.sqf +++ b/addons/missile_defense/functions/fnc_interceptorPFH.sqf @@ -37,6 +37,9 @@ private _currentPosition = getPosASLVisual _projectile; private _targetPosition = getPosASLVisual _target; + private _proximityFuseRange = _projectile getVariable [QGVAR(proximityFuseRange),GVAR(proximityFuseRange)]; + private _proximityFuseFailureChance = _projectile getVariable [QGVAR(proximityFuseFailureChance),GVAR(proximityFuseFailureChance)]; + private _posDiff = (_currentPosition vectorDiff _lastPosition); private _lengthSqr = _posDiff vectorDotProduct _posDiff; private _minDistance = if (_lengthSqr - 0.001 <= 0) then { @@ -51,11 +54,11 @@ _x set [2, _currentPosition]; _x set [3, _minDistance]; - if (_minDistance <= GVAR(proximityFuseRange) || { _minDistance > _lastDistance }) then { + if (_minDistance <= _proximityFuseRange || { _minDistance > _lastDistance }) then { triggerAmmo _projectile; _interceptors deleteAt _forEachIndex; // if we overshot target, dont take out target - if (_minDistance <= _lastDistance && { GVAR(proximityFuseFailureChance) <= random 1 }) then { + if (_minDistance <= _lastDistance && { _proximityFuseFailureChance <= random 1 }) then { private _explosion = createVehicle ["SmallSecondary", _target, [], 0, "CAN_COLLIDE"]; [QGVAR(destroyProjectile), [_target, typeOf _target, getPos _target]] call CBA_fnc_globalEvent; deleteVehicle _target;