mirror of
https://github.com/akaAgar/the-universal-mission-for-dcs-world.git
synced 2025-11-25 19:31:01 +00:00
Compare commits
No commits in common. "main" and "v0.3.250914" have entirely different histories.
main
...
v0.3.25091
@ -11,9 +11,8 @@
|
||||
if not net then net = {} end
|
||||
|
||||
net.allow_unsafe_api = { -- this defines the secure zones where net.dostring_in() can be called from
|
||||
"scripting",
|
||||
}
|
||||
|
||||
net.allow_dostring_in = { -- and this defines the zones that should be addressed from net.dostring_in()
|
||||
"mission",
|
||||
"mission"
|
||||
}
|
||||
|
||||
@ -1,51 +0,0 @@
|
||||
-- do
|
||||
-- Library.factions.tables["NATO"] = {}
|
||||
-- Library.factions.tables["NATO"].theaters = {}
|
||||
-- Library.factions.tables["NATO"].timePeriods = {}
|
||||
|
||||
-- Library.factions.tables["NATO"].units = {}
|
||||
|
||||
-- Library.factions.tables["NATO"].units[DCSEx.enums.timePeriod.WORLD_WAR_2] = {}
|
||||
-- Library.factions.tables["NATO"].units[DCSEx.enums.timePeriod.KOREA_WAR] = {}
|
||||
-- Library.factions.tables["NATO"].units[DCSEx.enums.timePeriod.VIETNAM_WAR] = {}
|
||||
-- Library.factions.tables["NATO"].units[DCSEx.enums.timePeriod.COLD_WAR] = {}
|
||||
|
||||
-- Library.factions.tables["NATO"].units[DCSEx.enums.timePeriod.MODERN] = {
|
||||
-- [DCSEx.enums.unitFamily.AIRDEFENSE_AAA_MOBILE] = { "Gepard", "Vulcan" },
|
||||
-- [DCSEx.enums.unitFamily.AIRDEFENSE_AAA_STATIC] = { "Gepard", "Vulcan" },
|
||||
-- [DCSEx.enums.unitFamily.AIRDEFENSE_MANPADS] = { "Soldier stinger" },
|
||||
-- [DCSEx.enums.unitFamily.AIRDEFENSE_SAM_LONG] = { "*Patriot" },
|
||||
-- [DCSEx.enums.unitFamily.AIRDEFENSE_SAM_MEDIUM] = { "*HAWK", "*NASAMS" },
|
||||
-- [DCSEx.enums.unitFamily.AIRDEFENSE_SAM_SHORT] = { "rapier_fsa", "Roland ADS" },
|
||||
-- [DCSEx.enums.unitFamily.AIRDEFENSE_SAM_SHORT_IR] = { "M6 Linebacker", "M48 Chaparral", "M1097 Avenger" },
|
||||
|
||||
-- [DCSEx.enums.unitFamily.GROUND_APC] = { "AAV7", "Cobra", "LAV-25", "M-2 Bradley", "M-113", "M1045 HMMWV TOW", "M1126 Stryker ICV", "M1128 Stryker MGS", "Marder", "MCV-80", "MLRS FDDM", "TPZ", "CHAP_M1130", "CHAP_MATV" },
|
||||
-- [DCSEx.enums.unitFamily.GROUND_ARTILLERY] = { "M-109", "MLRS", "CHAP_M142_ATACMS_M48", "CHAP_M142_GMLRS_M31" },
|
||||
-- [DCSEx.enums.unitFamily.GROUND_INFANTRY] = { "Soldier M4 GRG", "Soldier M4", "Soldier M249", "Soldier RPG" },
|
||||
-- [DCSEx.enums.unitFamily.GROUND_MBT] = { "Challenger2", "Leclerc", "Leopard-2", "Leopard1A3", "M-1 Abrams", "Merkava_Mk4" },
|
||||
-- [DCSEx.enums.unitFamily.GROUND_SS_MISSILE] = { "Scud_B" },
|
||||
-- [DCSEx.enums.unitFamily.GROUND_UNARMED] = { "Land_Rover_101_FC", "Land_Rover_109_S3", "M 818", "CHAP_M1083" },
|
||||
|
||||
-- [DCSEx.enums.unitFamily.HELICOPTER_ATTACK] = { "AH-1W", "AH-64D", "OH-58D", "SA342L", "SA342M", "SA342Minigun", "SA342Mistral" },
|
||||
-- [DCSEx.enums.unitFamily.HELICOPTER_TRANSPORT] = { "CH-47D", "CH-53E", "SH-60B", "UH-60A" },
|
||||
|
||||
-- [DCSEx.enums.unitFamily.PLANE_ATTACK] = { "A-10C_2" },
|
||||
-- [DCSEx.enums.unitFamily.PLANE_AWACS] = { "E-2C", "E-3A" },
|
||||
-- [DCSEx.enums.unitFamily.PLANE_BOMBER] = { "B-1B Lancer", "B-52H" },
|
||||
-- [DCSEx.enums.unitFamily.PLANE_FIGHTER] = { "F-16C_50", "FA-18C_hornet" },
|
||||
-- [DCSEx.enums.unitFamily.PLANE_TANKER] = { "KC-135", "KC135MPRS" },
|
||||
-- [DCSEx.enums.unitFamily.PLANE_TRANSPORT] = { "C-17A", "C-130" },
|
||||
-- [DCSEx.enums.unitFamily.PLANE_UAV] = { "RQ-1A Predator" },
|
||||
|
||||
-- [DCSEx.enums.unitFamily.SHIP_CARGO] = { "Dry-cargo ship-1", "Dry-cargo ship-2", "ELNYA", "Ship_Tilde_Supply" },
|
||||
-- [DCSEx.enums.unitFamily.SHIP_CARRIER] = { "CVN_71", "CVN_72", "CVN_73", "CVN_75", "hms_invincible", "LHA_Tarawa", "Stennis" },
|
||||
-- [DCSEx.enums.unitFamily.SHIP_CRUISER] = { "TICONDEROG" },
|
||||
-- [DCSEx.enums.unitFamily.SHIP_FRIGATE] = { "PERRY", "USS_Arleigh_Burke_IIa" },
|
||||
-- [DCSEx.enums.unitFamily.SHIP_LIGHT] = { "speedboat" },
|
||||
-- [DCSEx.enums.unitFamily.SHIP_MISSILE_BOAT] = { "CastleClass_01", "La_Combattante_II" },
|
||||
-- [DCSEx.enums.unitFamily.SHIP_SUBMARINE] = { "santafe" },
|
||||
|
||||
-- -- [DCSEx.enums.unitFamily.STATIC_STRUCTURE] = { "af_hq", ".Command Center", "Building01_PBR", "Building02_PBR", "Building03_PBR", "Building04_PBR", "Building05_PBR", "Bunker", "Chemical tank A", "Comms tower M", "FARP Fuel Depot", "outpost", "Sandbox", "Workshop A" },
|
||||
-- [DCSEx.enums.unitFamily.STATIC_STRUCTURE] = { "af_hq", ".Command Center", "Building01_PBR", "Building02_PBR", "Building03_PBR", "Building04_PBR", "Building05_PBR", "Chemical tank A", "Comms tower M", "FARP Fuel Depot", "outpost", "Workshop A" },
|
||||
-- }
|
||||
-- end
|
||||
@ -21,7 +21,7 @@ do
|
||||
[DCSEx.enums.unitFamily.AIRDEFENSE_AAA_MOBILE] = { "Ural-375 ZU-23", "ZSU_57_2", "ZSU-23-4 Shilka" },
|
||||
[DCSEx.enums.unitFamily.AIRDEFENSE_AAA_STATIC] = { "ZU-23 Emplacement Closed", "ZU-23 Emplacement" },
|
||||
[DCSEx.enums.unitFamily.AIRDEFENSE_MANPADS] = { "SA-18 Igla manpad", "SA-18 Igla-S manpad" },
|
||||
-- [DCSEx.enums.unitFamily.AIRDEFENSE_SAM_LONG] = { "*SA-2", "*SA-10" },
|
||||
[DCSEx.enums.unitFamily.AIRDEFENSE_SAM_LONG] = { "*SA-2", "*SA-10" },
|
||||
[DCSEx.enums.unitFamily.AIRDEFENSE_SAM_LONG] = { "*SA-10" },
|
||||
[DCSEx.enums.unitFamily.AIRDEFENSE_SAM_MEDIUM] = { "*SA-3", "*SA-6", "*SA-11" },
|
||||
[DCSEx.enums.unitFamily.AIRDEFENSE_SAM_SHORT] = { "2S6 Tunguska", "Osa 9A33 ln", "Tor 9A331", "CHAP_PantsirS1", "CHAP_TorM2" },
|
||||
@ -45,6 +45,8 @@ do
|
||||
[DCSEx.enums.unitFamily.PLANE_TRANSPORT] = { "An-26B", "An-30M", "IL-76MD" },
|
||||
[DCSEx.enums.unitFamily.PLANE_UAV] = { "WingLoong-I" },
|
||||
|
||||
[DCSEx.enums.unitFamily.HELICOPTER_ATTACK] = { "Ka-50", "Mi-24V", "Mi-28N" },
|
||||
|
||||
[DCSEx.enums.unitFamily.SHIP_CARGO] = { "Dry-cargo ship-1", "Dry-cargo ship-2", "ELNYA", "Ship_Tilde_Supply" },
|
||||
[DCSEx.enums.unitFamily.SHIP_CARRIER] = { "CV_1143_5", "KUZNECOW" },
|
||||
[DCSEx.enums.unitFamily.SHIP_CRUISER] = { "MOSCOW", "PIOTR" },
|
||||
|
||||
@ -10,45 +10,7 @@ do
|
||||
Library.factions.tables["USA"].units[DCSEx.enums.timePeriod.WORLD_WAR_2] = {}
|
||||
Library.factions.tables["USA"].units[DCSEx.enums.timePeriod.KOREA_WAR] = {}
|
||||
Library.factions.tables["USA"].units[DCSEx.enums.timePeriod.VIETNAM_WAR] = {}
|
||||
|
||||
Library.factions.tables["USA"].units[DCSEx.enums.timePeriod.COLD_WAR] = {
|
||||
[DCSEx.enums.unitFamily.AIRDEFENSE_AAA_MOBILE] = { "Gepard", "Vulcan" },
|
||||
[DCSEx.enums.unitFamily.AIRDEFENSE_AAA_STATIC] = { "Gepard", "Vulcan" },
|
||||
[DCSEx.enums.unitFamily.AIRDEFENSE_MANPADS] = { "Soldier stinger" },
|
||||
[DCSEx.enums.unitFamily.AIRDEFENSE_SAM_LONG] = { "*Patriot" },
|
||||
[DCSEx.enums.unitFamily.AIRDEFENSE_SAM_MEDIUM] = { "*HAWK", "*NASAMS" },
|
||||
[DCSEx.enums.unitFamily.AIRDEFENSE_SAM_SHORT] = { "rapier_fsa", "Roland ADS" },
|
||||
[DCSEx.enums.unitFamily.AIRDEFENSE_SAM_SHORT_IR] = { "M6 Linebacker", "M48 Chaparral", "M1097 Avenger" },
|
||||
|
||||
[DCSEx.enums.unitFamily.GROUND_APC] = { "AAV7", "Cobra", "LAV-25", "M-2 Bradley", "M-113", "M1045 HMMWV TOW", "M1126 Stryker ICV", "M1128 Stryker MGS", "Marder", "MCV-80", "MLRS FDDM", "TPZ", "CHAP_M1130", "CHAP_MATV" },
|
||||
[DCSEx.enums.unitFamily.GROUND_ARTILLERY] = { "M-109", "MLRS", "CHAP_M142_ATACMS_M48", "CHAP_M142_GMLRS_M31" },
|
||||
[DCSEx.enums.unitFamily.GROUND_INFANTRY] = { "Soldier M4 GRG", "Soldier M4", "Soldier M249", "Soldier RPG" },
|
||||
[DCSEx.enums.unitFamily.GROUND_MBT] = { "Challenger2", "Leclerc", "Leopard-2", "Leopard1A3", "M-1 Abrams", "Merkava_Mk4" },
|
||||
[DCSEx.enums.unitFamily.GROUND_SS_MISSILE] = { "Scud_B" },
|
||||
[DCSEx.enums.unitFamily.GROUND_UNARMED] = { "Land_Rover_101_FC", "Land_Rover_109_S3", "M 818", "CHAP_M1083" },
|
||||
|
||||
[DCSEx.enums.unitFamily.HELICOPTER_ATTACK] = { "AH-1W", "AH-64D", "OH-58D", "SA342L", "SA342M", "SA342Minigun", "SA342Mistral" },
|
||||
[DCSEx.enums.unitFamily.HELICOPTER_TRANSPORT] = { "CH-47D", "CH-53E", "SH-60B", "UH-60A" },
|
||||
|
||||
[DCSEx.enums.unitFamily.PLANE_ATTACK] = { "A-10C_2" },
|
||||
[DCSEx.enums.unitFamily.PLANE_AWACS] = { "E-2C", "E-3A" },
|
||||
[DCSEx.enums.unitFamily.PLANE_BOMBER] = { "B-1B Lancer", "B-52H" },
|
||||
[DCSEx.enums.unitFamily.PLANE_FIGHTER] = { "F-16C_50", "FA-18C_hornet" },
|
||||
[DCSEx.enums.unitFamily.PLANE_TANKER] = { "KC-135", "KC135MPRS" },
|
||||
[DCSEx.enums.unitFamily.PLANE_TRANSPORT] = { "C-17A", "C-130" },
|
||||
[DCSEx.enums.unitFamily.PLANE_UAV] = { "RQ-1A Predator" },
|
||||
|
||||
[DCSEx.enums.unitFamily.SHIP_CARGO] = { "Dry-cargo ship-1", "Dry-cargo ship-2", "ELNYA", "Ship_Tilde_Supply" },
|
||||
[DCSEx.enums.unitFamily.SHIP_CARRIER] = { "CVN_71", "CVN_72", "CVN_73", "CVN_75", "hms_invincible", "LHA_Tarawa", "Stennis" },
|
||||
[DCSEx.enums.unitFamily.SHIP_CRUISER] = { "TICONDEROG" },
|
||||
[DCSEx.enums.unitFamily.SHIP_FRIGATE] = { "PERRY", "USS_Arleigh_Burke_IIa" },
|
||||
[DCSEx.enums.unitFamily.SHIP_LIGHT] = { "speedboat" },
|
||||
[DCSEx.enums.unitFamily.SHIP_MISSILE_BOAT] = { "CastleClass_01", "La_Combattante_II" },
|
||||
[DCSEx.enums.unitFamily.SHIP_SUBMARINE] = { "santafe" },
|
||||
|
||||
-- [DCSEx.enums.unitFamily.STATIC_STRUCTURE] = { "af_hq", ".Command Center", "Building01_PBR", "Building02_PBR", "Building03_PBR", "Building04_PBR", "Building05_PBR", "Bunker", "Chemical tank A", "Comms tower M", "FARP Fuel Depot", "outpost", "Sandbox", "Workshop A" },
|
||||
[DCSEx.enums.unitFamily.STATIC_STRUCTURE] = { "af_hq", ".Command Center", "Building01_PBR", "Building02_PBR", "Building03_PBR", "Building04_PBR", "Building05_PBR", "Chemical tank A", "Comms tower M", "FARP Fuel Depot", "outpost", "Workshop A" },
|
||||
}
|
||||
Library.factions.tables["USA"].units[DCSEx.enums.timePeriod.COLD_WAR] = {}
|
||||
|
||||
Library.factions.tables["USA"].units[DCSEx.enums.timePeriod.MODERN] = {
|
||||
[DCSEx.enums.unitFamily.AIRDEFENSE_AAA_MOBILE] = { "Gepard", "Vulcan" },
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
-- Library.tasks.helicopterDestroyInfantry = {
|
||||
-- taskFamily = DCSEx.enums.taskFamily.HELICOPTER,
|
||||
-- description =
|
||||
-- {
|
||||
-- briefing = {
|
||||
-- "",
|
||||
-- },
|
||||
-- short = "Neutralize enemy infantry",
|
||||
-- },
|
||||
-- conditions = {
|
||||
-- difficultyMinimum = 0,
|
||||
-- eras = {},
|
||||
-- },
|
||||
-- completionEvent = DCSEx.enums.taskEvent.DESTROY,
|
||||
-- flags = { },
|
||||
-- minimumDistance = DCSEx.converter.nmToMeters(5.0),
|
||||
-- safeRadius = 100,
|
||||
-- surfaceType = nil,
|
||||
-- targetCount = { 6, 8 },
|
||||
-- targetFamilies = { DCSEx.enums.unitFamily.GROUND_INFANTRY },
|
||||
-- waypointInaccuracy = DCSEx.converter.nmToMeters(1.5)
|
||||
-- }
|
||||
@ -1,22 +0,0 @@
|
||||
-- Library.tasks.helicopterPickUpInfantry = {
|
||||
-- taskFamily = DCSEx.enums.taskFamily.HELICOPTER,
|
||||
-- description =
|
||||
-- {
|
||||
-- briefing = {
|
||||
-- "",
|
||||
-- },
|
||||
-- short = "Land and pick up friendly infantry",
|
||||
-- },
|
||||
-- conditions = {
|
||||
-- difficultyMinimum = 0,
|
||||
-- eras = {},
|
||||
-- },
|
||||
-- completionEvent = DCSEx.enums.taskEvent.LAND,
|
||||
-- flags = { DCSEx.enums.taskFlag.FRIENDLY_TARGET },
|
||||
-- minimumDistance = DCSEx.converter.nmToMeters(5.0),
|
||||
-- safeRadius = 100,
|
||||
-- surfaceType = nil,
|
||||
-- targetCount = { 6, 8 },
|
||||
-- targetFamilies = { DCSEx.enums.unitFamily.GROUND_INFANTRY },
|
||||
-- waypointInaccuracy = DCSEx.converter.nmToMeters(1.5)
|
||||
-- }
|
||||
@ -1,25 +0,0 @@
|
||||
Library.tasks.heloHuntAttack = {
|
||||
taskFamily = DCSEx.enums.taskFamily.HELO_HUNT,
|
||||
description =
|
||||
{
|
||||
briefing = {
|
||||
"Locate and neutralize all enemy rotary-wing assets in the area.",
|
||||
"Enemy attack helicopters are staging nearby, you are to eliminate them before they launch their attack.",
|
||||
"Intel confirms a group of hostile gunships in the area. You must render them combat-ineffective.",
|
||||
"Engage and destroy rotary assets nearby, crippling enemy air support.",
|
||||
},
|
||||
short = "Destroy enemy attack helicopters",
|
||||
},
|
||||
conditions = {
|
||||
difficultyMinimum = 0,
|
||||
eras = {},
|
||||
},
|
||||
completionEvent = DCSEx.enums.taskEvent.DESTROY,
|
||||
flags = { },
|
||||
minimumDistance = DCSEx.converter.nmToMeters(10.0),
|
||||
safeRadius = 100,
|
||||
surfaceType = nil,
|
||||
targetCount = { 2, 3 },
|
||||
targetFamilies = { DCSEx.enums.unitFamily.HELICOPTER_ATTACK },
|
||||
waypointInaccuracy = DCSEx.converter.nmToMeters(6.0)
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
Library.tasks.heloHuntTransport = {
|
||||
taskFamily = DCSEx.enums.taskFamily.HELO_HUNT,
|
||||
description =
|
||||
{
|
||||
briefing = {
|
||||
"",
|
||||
},
|
||||
short = "Destroy enemy transport helicopters",
|
||||
},
|
||||
conditions = {
|
||||
difficultyMinimum = 0,
|
||||
eras = {},
|
||||
},
|
||||
completionEvent = DCSEx.enums.taskEvent.DESTROY,
|
||||
flags = { },
|
||||
minimumDistance = DCSEx.converter.nmToMeters(10.0),
|
||||
safeRadius = 100,
|
||||
surfaceType = nil,
|
||||
targetCount = { 2, 3 },
|
||||
targetFamilies = { DCSEx.enums.unitFamily.HELICOPTER_TRANSPORT },
|
||||
waypointInaccuracy = DCSEx.converter.nmToMeters(6.0)
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
-- Library.tasks.ocaAirbase = {
|
||||
-- taskFamily = DCSEx.enums.taskFamily.OCA,
|
||||
-- description =
|
||||
-- {
|
||||
-- briefing = {
|
||||
-- "Neutralizing this enemy airbase will eliminate their ability to conduct sustained air sorties and restore local air superiority.",
|
||||
-- "Taking out this airbase will disrupt their logistics and sortie tempo, buying time for our ground forces to consolidate.",
|
||||
-- "This airbase is the hub of enemy reconnaissance and close air support—removing it reduces battlefield intelligence and strike pressure.",
|
||||
-- "Outlasting enemy air campaign requires degrading that facility's operational capacity to prevent rotational sorties.",
|
||||
-- "Disabling this node of their air network constrains their command-and-control reach and limits coordinated strikes."
|
||||
-- },
|
||||
-- short = "Destroy enemy airbase",
|
||||
-- },
|
||||
-- conditions = {
|
||||
-- difficultyMinimum = 0,
|
||||
-- eras = {},
|
||||
-- },
|
||||
-- completionEvent = DCSEx.enums.taskEvent.DESTROY,
|
||||
-- flags = { DCSEx.enums.taskFlag.ALLOW_JTAC, DCSEx.enums.taskFlag.AIRBASE_TARGET },
|
||||
-- minimumDistance = 0.0,
|
||||
-- safeRadius = 0,
|
||||
-- surfaceType = land.SurfaceType.LAND,
|
||||
-- targetCount = { 1, 1 },
|
||||
-- targetFamilies = { DCSEx.enums.unitFamily.STATIC_SCENERY },
|
||||
-- waypointInaccuracy = 0.0
|
||||
-- }
|
||||
@ -1,25 +0,0 @@
|
||||
-- Library.tasks.ocaFighterStrike = {
|
||||
-- taskFamily = DCSEx.enums.taskFamily.OCA,
|
||||
-- description =
|
||||
-- {
|
||||
-- briefing = {
|
||||
-- "Destroying enemy fighters on the ramp will prevent immediate sortie generation and blunt their ability to provide CAS against our advancing forces.",
|
||||
-- "A ramp strike against enemy aircraft will pre-empt an imminent scramble warning we have intel for, preventing a coordinated mass launch.",
|
||||
-- "Removing enemy fighters on the ramp will degrade enemy air superiority over the battlespace and protects our medevac and resupply corridors.",
|
||||
-- "Priority is to eliminate immediate airborne threats on the ramp to safeguard coalition force freedom of maneuver.",
|
||||
-- },
|
||||
-- short = "Destroy enemy fighter on the ramp",
|
||||
-- },
|
||||
-- conditions = {
|
||||
-- difficultyMinimum = 0,
|
||||
-- eras = {},
|
||||
-- },
|
||||
-- completionEvent = DCSEx.enums.taskEvent.DAMAGE,
|
||||
-- flags = { DCSEx.enums.taskFlag.ALLOW_JTAC, DCSEx.enums.taskFlag.PARKED_AIRCRAFT_TARGET },
|
||||
-- minimumDistance = 0.0,
|
||||
-- safeRadius = 0,
|
||||
-- surfaceType = land.SurfaceType.LAND,
|
||||
-- targetCount = { 1, 1 },
|
||||
-- targetFamilies = { DCSEx.enums.unitFamily.PLANE_FIGHTER },
|
||||
-- waypointInaccuracy = 0.0
|
||||
-- }
|
||||
@ -1,22 +0,0 @@
|
||||
Library.tasks.ocaStrategicAircraftStrike = {
|
||||
taskFamily = DCSEx.enums.taskFamily.OCA,
|
||||
description =
|
||||
{
|
||||
briefing = {
|
||||
""
|
||||
},
|
||||
short = "Destroy enemy aircraft on the ramp",
|
||||
},
|
||||
conditions = {
|
||||
difficultyMinimum = 0,
|
||||
eras = {},
|
||||
},
|
||||
completionEvent = DCSEx.enums.taskEvent.DAMAGE,
|
||||
flags = { DCSEx.enums.taskFlag.ALLOW_JTAC, DCSEx.enums.taskFlag.PARKED_AIRCRAFT_TARGET },
|
||||
minimumDistance = 0.0,
|
||||
safeRadius = 0,
|
||||
surfaceType = land.SurfaceType.LAND,
|
||||
targetCount = { 1, 1 },
|
||||
targetFamilies = { DCSEx.enums.unitFamily.PLANE_BOMBER, DCSEx.enums.unitFamily.PLANE_TRANSPORT },
|
||||
waypointInaccuracy = 0.0
|
||||
}
|
||||
2
Make.bat
2
Make.bat
@ -8,7 +8,7 @@ IF %ERRORLEVEL% NEQ 0 goto ERROR-NO-PHP
|
||||
@REM CREATE SCENARIOS
|
||||
@REM -------------------------------------------
|
||||
set buildConfig=p
|
||||
echo THE UNIVERSAL MISSION BUILDER SCRIPT:
|
||||
echo THE ULTIMATE MISSION BUILDER SCRIPT:
|
||||
echo - Build [P]ersianGulf debug theater only (default)
|
||||
echo - Build all [D]ebug theaters
|
||||
echo - Build all [R]elease theaters
|
||||
|
||||
42
README.md
42
README.md
@ -1,6 +1,6 @@
|
||||
# The Universal Mission for DCS World
|
||||
|
||||
**Current version: open beta 0.3.251019** (see the "version history" section at the end of this file for a list of the latest changes)
|
||||
**Current version: open beta 0.3.250914** (see the "version history" section at the end of this file for a list of the latest changes)
|
||||
|
||||
**This is a BETA version, there may be bugs and there WILL be unbalanced stuff.**
|
||||
|
||||
@ -26,7 +26,7 @@ The Universal Mission for DCS World is a fully dynamic single-player/PvE mission
|
||||
|
||||
**Please read the "planned development" section below for more information.**
|
||||
|
||||
- The current version supports only modern (post-Cold War) units and Caucasus, Germany, Kola, Marianas, Persian Gulf and Syria theaters
|
||||
- The current version supports only modern (post-Cold War) units and Caucasus, Kola, Marianas, Persian Gulf and Syria theaters
|
||||
- Not all mission types are supported yet
|
||||
- Career progress may be lost because of future updates, don't get too attached to it
|
||||
|
||||
@ -42,6 +42,7 @@ The Universal Mission for DCS World is a fully dynamic single-player/PvE mission
|
||||
|
||||
- Download the latest release from this GitHub page.
|
||||
- Copy the provided autoexec.cfg file to your **[Saved Games]\DCS\Config directory**
|
||||
- Please note: as of DCS 2.9.18.12899, it seems the autoexec.cfg file [is no longer needed](https://www.digitalcombatsimulator.com/en/news/changelog/release/2.9.18.12899/) but I advise you to copy it anyway, ED might change its mind again.
|
||||
- Copy the .miz files for your theater(s) of choice to your **[Saved Games]\DCS\Missions directory**
|
||||
- _**(Optional but strongly recommended)**_ Unsanitize the Lua IO module. You don't have to do this, but the persistent career system won't work if you don't. To do it, open the file **[DCS World installation directory]\Scripts\MissionScripting.lua** with a text editor and comment or remove the line "sanitizeModule('io')". Make sure you restart DCS World once you've modified the file.
|
||||
- Please note: should you want to backup, delete or transfer it, career progress is saved in **[DCS World installation directory]\TheUniversalMission.sav**
|
||||
@ -74,17 +75,14 @@ Please also note that PvP is not supported at the moment and that the mission wi
|
||||
|
||||
- Additional content
|
||||
- [ ] More objectives types
|
||||
- [ ] Close air support
|
||||
- [ ] Helicopter-specific tasking (land and pick up units, suppress infantry...)
|
||||
- [ ] Improved OCA missions: bomb enemy airbases
|
||||
- Balance improvements
|
||||
- [ ] Night missions should award more XP
|
||||
- [ ] Tweaked XP requirements for medals/promotions
|
||||
- Bug fixes
|
||||
- [ ] AWACS datalinked contacts not showing on SA pages
|
||||
- Extras
|
||||
- [ ] GitHub page
|
||||
- Improvements
|
||||
- Misc
|
||||
- [ ] Better weather reports (cloud cover, rain, etc)
|
||||
- New features
|
||||
- [ ] Administrative settings menu
|
||||
- [ ] Friendly air defenses
|
||||
@ -96,15 +94,17 @@ Please also note that PvP is not supported at the moment and that the mission wi
|
||||
|
||||
- Additional/improved radio messages
|
||||
- More "flavor" radio messages ("fence in" when player approaches the AO, etc) so the world will feel more alive
|
||||
- Better balancing of the player career awards and promotions
|
||||
- Better use of context for "ambient" radio messages (should only warn of a SAM launch if an AI pilot is there to witness it, etc)
|
||||
- Improved score multiplier taking into account various aspects of mission difficulty (weather, nighttime ops...)
|
||||
- Laser designation of targets by JTAC
|
||||
- New objectives: CAP
|
||||
- New objectives: helicopter (drop/pickup units...), CAP, CAS, OCA (airbase attack)
|
||||
- Support for all missing DCS World theaters
|
||||
- Support for more factions and five different time periods (World War 2, Korea war, Vietnam war, late Cold war, Modern)
|
||||
|
||||
### Medium priority
|
||||
|
||||
- Combined arms support
|
||||
- Combined Arms support
|
||||
- Modded units support (other than player-controlled aircraft, those are already supported: just add them to the mission)
|
||||
- Spawning of tankers for long-range missions
|
||||
- (maybe) Text (not voiceover) localization, if there's enough popular demand
|
||||
@ -154,31 +154,15 @@ The core script is quite simple and small, I probably won't need too much help w
|
||||
|
||||
## Version history
|
||||
|
||||
- **0.3.251019** (10/19/2025)
|
||||
- Additional content
|
||||
- New mission types
|
||||
- "Helicopter hunt" missions: locate and intercept enemy attack and transport helicopters
|
||||
- Offensive counter-air: destroy enemy aircraft on the ramp before they take off **(Requires a target location with at least one enemy land airbase, or mission type will automatically be changed to ground attack)**
|
||||
- Balance improvements
|
||||
- Missions with higher cloud cover and wind speed now award more XP
|
||||
- Bug fixes
|
||||
- AWACS datalinked now showing on SA pages
|
||||
- AWACS can now detect enemy helicopters
|
||||
- Added missing net.allow_unsafe_api value in autoexec.cfg that prevented some advanced scripts from working
|
||||
- "On landing" actions (medal/promotions check, AI wingmen removal, etc) no longer triggered when player lands away from an airfield (e.g. in a Harrier on a helicopter)
|
||||
- Improvements
|
||||
- ATC weather reports now include informations about cloud cover and rain
|
||||
- Misc
|
||||
- AWACS unit now spawned when mission is loaded
|
||||
- **0.3.250914** (09/14/2025)
|
||||
- **MAJOR CHANGE:**
|
||||
- Use of "Client" slots instead of "Player" slots even in single-player missions, allowing the player to respawn on death/ejection instead of having to start the whole mission again
|
||||
- "Player" slots should not be used anymore. Single-player missions must now use a single "Client" slot instead
|
||||
- Use of "Client" slot instead of "Player" slot even in single-player missions, allowing the player to respawn on death/ejection instead of having to start the whole mission again
|
||||
- "Player" should not be used anymore. Single-player missions must use a single "Client" slot instead
|
||||
- Additional content
|
||||
- Added new units (Currenthill unit pack) from DCS 2.9.19.13478
|
||||
- Support for "Cold War Germany" theater
|
||||
- Balance improvements
|
||||
- Enemy CAP respawn rate now decreases as more enemy planes are shot down
|
||||
- Enemy CAP respawn rate now decreases the more enemy planes are shot
|
||||
- Bug fixes
|
||||
- Some player callsigns were causing a script error at startup
|
||||
- Fixed wrong filename in "enemy infantry killed" messages
|
||||
@ -192,7 +176,7 @@ The core script is quite simple and small, I probably won't need too much help w
|
||||
- Mission now autostarts (if it wasn't started yet) when all players have taken off
|
||||
- Quality of life/minor tweaks
|
||||
- Increased AWACS aircraft spawn altitude
|
||||
- Target coordinates radio message displayed for a longer time so players have time to write them down or enter them in their flight computer
|
||||
- Target coordinates radio message displayed for a longer time so players have the time to write them down or enter them in their flight computer
|
||||
- **0.2.250729** (07/29/2025)
|
||||
- **MAJOR CHANGE:** Added all new wingman system
|
||||
- Far for perfect but a lot better than DCS's default wingmen
|
||||
|
||||
@ -29,10 +29,9 @@ DCSEx.enums.lineType = {
|
||||
-- Event to check to see if a task/objective is complete
|
||||
-------------------------------------
|
||||
DCSEx.enums.taskEvent = {
|
||||
DAMAGE = 1,
|
||||
DESTROY = 2,
|
||||
DESTROY_SCENERY = 3,
|
||||
LAND = 4,
|
||||
DESTROY = 1,
|
||||
DESTROY_SCENERY = 2,
|
||||
LAND = 3,
|
||||
}
|
||||
|
||||
-------------------------------------
|
||||
@ -40,29 +39,26 @@ DCSEx.enums.taskEvent = {
|
||||
-------------------------------------
|
||||
DCSEx.enums.taskFamily = {
|
||||
ANTISHIP = 1,
|
||||
-- CAP = XXX,
|
||||
-- CAS = XXX,
|
||||
GROUND_ATTACK = 2,
|
||||
-- HELICOPTER = 3,
|
||||
HELO_HUNT = 3,
|
||||
INTERCEPTION = 4,
|
||||
OCA = 5,
|
||||
SEAD = 6,
|
||||
STRIKE = 7,
|
||||
-- CAP = 2, -- TODO
|
||||
-- CAS = 3, -- TODO
|
||||
GROUND_ATTACK = 2, -- 4
|
||||
-- HELICOPTER = XXX, -- 5
|
||||
-- HELO_HUNT = XXX, -- 6
|
||||
INTERCEPTION = 3, -- 7
|
||||
-- OCA = XXX, -- 8
|
||||
SEAD = 4, --9
|
||||
STRIKE = 5, -- 10
|
||||
}
|
||||
|
||||
-------------------------------------
|
||||
-- Special events for tasks
|
||||
-------------------------------------
|
||||
DCSEx.enums.taskFlag = {
|
||||
AIRBASE_TARGET = 1,
|
||||
ALLOW_JTAC = 2,
|
||||
DESTROY_TRACK_RADARS_ONLY = 3,
|
||||
MOVING = 4,
|
||||
ON_ROADS = 5,
|
||||
PARKED_AIRCRAFT_TARGET = 6,
|
||||
SCENERY_TARGET = 7,
|
||||
FRIENDLY_TARGET = 8
|
||||
ALLOW_JTAC = 1,
|
||||
DESTROY_TRACK_RADARS_ONLY = 2,
|
||||
MOVING = 3,
|
||||
ON_ROADS = 4,
|
||||
SCENERY_TARGET = 5
|
||||
}
|
||||
|
||||
-------------------------------------
|
||||
|
||||
@ -374,14 +374,6 @@ do
|
||||
setAircraftTaskOrbit(groupTable, options)
|
||||
end
|
||||
|
||||
-- For parked aircraft
|
||||
if options.airbaseID and options.parkingID then
|
||||
groupTable.route.points[1].action = "From Parking Area"
|
||||
groupTable.route.points[1].airdromeId = options.airbaseID
|
||||
groupTable.route.points[1].type = "TakeOffParking"
|
||||
groupTable.uncontrolled = true
|
||||
end
|
||||
|
||||
if options.callsign then
|
||||
groupCallsign = options.callsign
|
||||
else
|
||||
@ -457,12 +449,6 @@ do
|
||||
if aircraftDB.properties then
|
||||
unitTable.AddPropAircraft = DCSEx.table.deepCopy(aircraftDB.properties)
|
||||
end
|
||||
|
||||
-- For parked aircraft
|
||||
if options.airbaseID and options.parkingID then
|
||||
unitTable.parking = tostring(options.parkingID)
|
||||
end
|
||||
|
||||
-- Setup datalink
|
||||
local datalinkString = tostring(dataLinkID)
|
||||
if #datalinkString == 3 then
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
-- DCSEX.ZONES - FUNCTIONS RELATED TO MAP TRIGGER ZONES
|
||||
-- ====================================================================================
|
||||
-- DCSEx.zones.drawOnMap(zoneTable, lineColor, fillColor, lineType, drawName, readOnly)
|
||||
-- DCSEx.zones.getAirbases(zone, coalID, allowShips)
|
||||
-- DCSEx.zones.getAll()
|
||||
-- DCSEx.zones.getByName(name)
|
||||
-- DCSEx.zones.getCenter(zoneTable)
|
||||
@ -73,43 +72,6 @@ function DCSEx.zones.drawOnMap(zoneTable, lineColor, fillColor, lineType, drawNa
|
||||
return markerID
|
||||
end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns all airbases in the zone
|
||||
-------------------------------------
|
||||
-- @param zoneTable Table of the zone in which to search
|
||||
-- @param coalID Coalition (from the coalition.side enum) the airbase must belong to. Default is nil, which means "all coalitions"
|
||||
-- @param allowShips Should ships be allowed?
|
||||
-- @return Table of airbases
|
||||
-------------------------------------
|
||||
function DCSEx.zones.getAirbases(zoneTable, coalID, allowShips)
|
||||
coalID = coalID or nil
|
||||
allowShips = allowShips or false
|
||||
|
||||
local coalitionSides = { coalition.side.RED, coalition.side.BLUE }
|
||||
if coalID then coalitionSides = { coalID } end
|
||||
|
||||
local validAirbases = {}
|
||||
for _,side in ipairs(coalitionSides) do
|
||||
for _,ab in ipairs(coalition.getAirbases(side)) do
|
||||
local abDesc = ab:getDesc()
|
||||
local isValid = true
|
||||
|
||||
if ab:getDesc().category == Airbase.Category.HELIPAD then
|
||||
isValid = false
|
||||
elseif ab:getDesc().category == Airbase.Category.SHIP and not allowShips then
|
||||
isValid = false
|
||||
end
|
||||
|
||||
if isValid then
|
||||
if DCSEx.zones.isPointInside(zoneTable, ab:getPoint()) then
|
||||
table.insert(validAirbases, ab)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return validAirbases
|
||||
end
|
||||
|
||||
-------------------------------------
|
||||
-- Returns all trigger zones
|
||||
-------------------------------------
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -167,8 +167,6 @@ function TUM.initialize()
|
||||
timer.scheduleFunction(TUM.onClockTick, nil, timer.getTime() + math.random(10, 15))
|
||||
end
|
||||
end
|
||||
|
||||
TUM.supportAWACS.create()
|
||||
end
|
||||
|
||||
if TUM.administrativeSettings.getValue(TUM.administrativeSettings.INITIALIZE_AUTOMATICALLY) then
|
||||
|
||||
@ -132,17 +132,14 @@ do
|
||||
commonWeatherInfo = commonWeatherInfo.." (day, sunset at "..DCSEx.string.getTimeString(Library.environment.getDayTime(nil, true))..")\n"
|
||||
end
|
||||
|
||||
commonWeatherInfo = commonWeatherInfo.."- Cloud cover: "..TUM.weather.getWeatherName(nil, true).."\n"
|
||||
commonWeatherInfo = commonWeatherInfo.."- Wind: "..TUM.weather.getWindName()..", with avg. speed of "..tostring(math.floor(Library.environment.getWindAverage())).."m/s\n"
|
||||
commonWeatherInfo = commonWeatherInfo.."- Average ground-level temperature is "..getTemperatureCelsiusAndFarenheit(env.mission.weather.season.temperature).."\n"
|
||||
|
||||
local players = coalition.getPlayers(TUM.settings.getPlayerCoalition())
|
||||
for _,p in ipairs(players) do
|
||||
local lTemperature, _ = atmosphere.getTemperatureAndPressure(p:getPoint())
|
||||
|
||||
local localWeatherInfo = ""
|
||||
localWeatherInfo = localWeatherInfo.."- Wind speed at your location is "..tostring(math.floor(DCSEx.math.getLength3D(atmosphere.getWind(p:getPoint())))).."m/s\n"
|
||||
localWeatherInfo = localWeatherInfo.."- Temperature at your location is "..getTemperatureCelsiusAndFarenheit(lTemperature, true).."\n"
|
||||
local localWeatherInfo = "- Average windspeed is "..tostring(math.floor(Library.environment.getWindAverage())).."m/s\n"
|
||||
localWeatherInfo = localWeatherInfo.."- Windspeed at your location is "..DCSEx.math.getLength3D(atmosphere.getWind(p:getPoint())).."m/s\n"
|
||||
localWeatherInfo = localWeatherInfo.."- Average ground-level temperature is "..getTemperatureCelsiusAndFarenheit(env.mission.weather.season.temperature).."\n"
|
||||
localWeatherInfo = localWeatherInfo.."- Temperature at your location is "..getTemperatureCelsiusAndFarenheit(lTemperature, true)
|
||||
|
||||
TUM.radio.playForUnit(DCSEx.dcs.getObjectIDAsNumber(p), "atcWeatherUpdate", { commonWeatherInfo..localWeatherInfo }, "Control", delayRadioAnswer)
|
||||
end
|
||||
|
||||
@ -225,9 +225,11 @@ do
|
||||
if not event.initiator then return end -- No event initiator
|
||||
if Object.getCategory(event.initiator) ~= Object.Category.UNIT then return end -- Initiator isn't an unit
|
||||
if event.initiator:getCoalition() ~= TUM.settings.getPlayerCoalition() then return end -- Not a friendly
|
||||
if not event.place then return end -- Not landed at an airbase (e.g. helicopter landing on the ground)
|
||||
|
||||
local baseName = event.place:getName():upper()
|
||||
local baseName = "AIRBASE"
|
||||
if event.place then
|
||||
baseName = event.place:getName():upper()
|
||||
end
|
||||
|
||||
if TUM.settings.getValue(TUM.settings.id.MULTIPLAYER) or not event.initiator:getPlayerName() then
|
||||
doAmbientChatter("atcSafeLanding", {event.initiator:getCallsign(), baseName}, baseName.." ATC", 1)
|
||||
|
||||
@ -32,7 +32,7 @@ do
|
||||
end
|
||||
|
||||
|
||||
-- Called when an unit is destroyed
|
||||
-- Called when a unit is destroyed
|
||||
local function onEventDead(event)
|
||||
if not event.initiator then return end -- Nothing was hit
|
||||
|
||||
@ -53,17 +53,6 @@ do
|
||||
)
|
||||
end
|
||||
|
||||
-- Called when an unit takes damage
|
||||
local function onEventHit(event)
|
||||
if not event.initiator then return end -- Nothing was hit
|
||||
if Object.getCategory(event.initiator) ~= Object.Category.UNIT then return end -- Target wasn't an unit
|
||||
if event.initiator:getCoalition() ~= TUM.settings.getEnemyCoalition() then return end -- Unit is not an enemy
|
||||
if event.initiator:getDesc().category ~= Unit.Category.AIRPLANE and event.initiator:getDesc().category ~= Unit.Category.HELICOPTER then return end -- Wasn't an aircraft
|
||||
if event.initiator:inAir() then return end -- Unit is currently in air
|
||||
|
||||
trigger.action.explosion(event.initiator:getPoint(), 100) -- Detonate the parked aircraft, to make it easier to kill
|
||||
end
|
||||
|
||||
function TUM.ambientWorld.removeAll()
|
||||
for _,id in ipairs(groupIDs) do
|
||||
DCSEx.world.destroyGroupByID(id)
|
||||
@ -81,8 +70,6 @@ do
|
||||
|
||||
if event.id == world.event.S_EVENT_DEAD then
|
||||
onEventDead(event)
|
||||
elseif event.id == world.event.S_EVENT_HIT then
|
||||
onEventHit(event)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -68,10 +68,7 @@ do
|
||||
local runwayTouchEvent = { id = world.event.S_EVENT_RUNWAY_TOUCH, initiator = playerUnit }
|
||||
TUM.onEvent(runwayTouchEvent)
|
||||
|
||||
local friendlyAirbases = coalition.getAirbases(TUM.settings.getPlayerCoalition())
|
||||
if not friendlyAirbases or #friendlyAirbases == 0 then return end
|
||||
|
||||
local landingEvent = { id = world.event.S_EVENT_LAND, place = friendlyAirbases[1], initiator = playerUnit }
|
||||
local landingEvent = { id = world.event.S_EVENT_LAND, initiator = playerUnit }
|
||||
timer.scheduleFunction(TUM.onEvent, landingEvent, timer.getTime() + 1)
|
||||
end
|
||||
|
||||
|
||||
@ -69,16 +69,7 @@ do
|
||||
end
|
||||
end
|
||||
|
||||
-- If an OCA mission has been selected and the selected target zone doesn't contain any enemy airfield, default to ground attack
|
||||
if TUM.settings.getValue(TUM.settings.id.TASKING) == DCSEx.enums.taskFamily.OCA then
|
||||
local zone = DCSEx.zones.getByName(TUM.settings.getValue(TUM.settings.id.TARGET_LOCATION, true))
|
||||
if #DCSEx.zones.getAirbases(zone, TUM.settings.getEnemyCoalition()) == 0 then
|
||||
trigger.action.outText("OCA tasking selected in a zone without any enemy airfields, defaulting to GROUND ATTACK tasking.", 3)
|
||||
TUM.settings.setValue(TUM.settings.id.TASKING, DCSEx.enums.taskFamily.GROUND_ATTACK, true)
|
||||
end
|
||||
end
|
||||
|
||||
trigger.action.outText("Generating mission and loading assets, this can take some time...", 3)
|
||||
trigger.action.outText("Generating mission and loading assets, this can take some time...", 5)
|
||||
|
||||
-- Add a little delay for the "Generating mission..." message be printed out. Once generation begins, the main DCS thread will be to busy to output anything.
|
||||
timer.scheduleFunction(TUM.mission.beginMission, false, timer.getTime() + 1)
|
||||
|
||||
@ -62,7 +62,6 @@ do
|
||||
closeMission(true)
|
||||
TUM.intermission.removeMissionZonesMarkers()
|
||||
|
||||
TUM.objectivesMaker.clear()
|
||||
for _=1,TUM.settings.getValue(TUM.settings.id.TARGET_COUNT) do
|
||||
TUM.objectives.add()
|
||||
end
|
||||
@ -73,7 +72,7 @@ do
|
||||
return
|
||||
end
|
||||
|
||||
-- TUM.supportAWACS.create() -- Create the AWACS aircraft if it wasn't airborne already
|
||||
TUM.supportAWACS.create() -- Create the AWACS aircraft if it wasn't airborne already
|
||||
TUM.enemyAirDefense.create() -- Must be called once objectives have been created
|
||||
TUM.airForce.create() -- Must be called once objectives have been created
|
||||
TUM.missionMenu.create() -- Must be called once objectives have been created
|
||||
|
||||
@ -15,6 +15,7 @@ do
|
||||
-- @param event A DCS World event, possibly a S_EVENT_LAND event
|
||||
-------------------------------------
|
||||
local function removeAIAircraftOnLandEvent(event)
|
||||
if event.id ~= world.event.S_EVENT_LAND then return end
|
||||
if not event.initiator then return end
|
||||
if Object.getCategory(event.initiator) ~= Object.Category.UNIT then return end -- Not an unit
|
||||
if event.initiator:getPlayerName() then return end -- Don't remove player aircraft, that would cause horrendous bugs
|
||||
@ -72,8 +73,6 @@ do
|
||||
-- @param event The DCS World event
|
||||
-------------------------------------
|
||||
function TUM.mizCleaner.onEvent(event)
|
||||
if event.id == world.event.S_EVENT_LAND and event.place then
|
||||
removeAIAircraftOnLandEvent(event)
|
||||
end
|
||||
removeAIAircraftOnLandEvent(event)
|
||||
end
|
||||
end
|
||||
|
||||
@ -168,44 +168,13 @@ do
|
||||
end
|
||||
|
||||
local function onObjectiveEvent(index, event)
|
||||
if not event.initiator then return end
|
||||
|
||||
if index < 1 or index > #objectives then return end -- Out of bounds
|
||||
if objectives[index].completed then return end -- Objective already completed
|
||||
|
||||
local completionEvent = Library.tasks[objectives[index].taskID].completionEvent
|
||||
if event.id ~= world.event.S_EVENT_DEAD and event.id ~= world.event.S_EVENT_UNIT_LOST then return end
|
||||
if not event.initiator then return end
|
||||
|
||||
if completionEvent == DCSEx.enums.taskEvent.DAMAGE then
|
||||
if event.id ~= world.event.S_EVENT_DEAD and event.id ~= world.event.S_EVENT_HIT and event.id ~= world.event.S_EVENT_UNIT_LOST then return end
|
||||
elseif completionEvent == DCSEx.enums.taskEvent.DESTROY then
|
||||
if event.id ~= world.event.S_EVENT_DEAD and event.id ~= world.event.S_EVENT_UNIT_LOST then return end
|
||||
elseif completionEvent == DCSEx.enums.taskEvent.LAND then
|
||||
if event.id ~= world.event.S_EVENT_LAND then return end
|
||||
if Object.getCategory(event.initiator) ~= Object.Category.UNIT then return end
|
||||
if event.initiator:getDesc().category ~= Unit.Category.HELICOPTER then return end
|
||||
if event.initiator:getCoalition() ~= TUM.settings.getPlayerCoalition() then return end
|
||||
if DCSEx.math.getDistance2D(DCSEx.math.vec3ToVec2(event.initiator:getPoint()), objectives[index].point2) > 500 then return end -- Too far from objective
|
||||
|
||||
-- Remove target group if it exists (to simulate it was picked up/captured)
|
||||
if objectives[index].groupID then
|
||||
local targetGroup = DCSEx.world.getGroupByID(objectives[index].groupID)
|
||||
if targetGroup then
|
||||
targetGroup:destroy()
|
||||
end
|
||||
end
|
||||
|
||||
timer.scheduleFunction(markObjectiveAsComplete, index, timer.getTime() + 3)
|
||||
updateObjectiveText(index)
|
||||
return
|
||||
end
|
||||
|
||||
if objectives[index].isAirbaseTarget then
|
||||
if Object.getCategory(event.initiator) == Object.Category.BASE then
|
||||
if DCSEx.math.isSamePoint(event.initiator:getPoint(), objectives[index].point3) then
|
||||
timer.scheduleFunction(markObjectiveAsComplete, index, timer.getTime() + 3)
|
||||
end
|
||||
end
|
||||
elseif objectives[index].isSceneryTarget then
|
||||
if objectives[index].isSceneryTarget then
|
||||
if Object.getCategory(event.initiator) == Object.Category.SCENERY then
|
||||
if DCSEx.math.isSamePoint(event.initiator:getPoint(), objectives[index].point3) then
|
||||
timer.scheduleFunction(markObjectiveAsComplete, index, timer.getTime() + 3)
|
||||
|
||||
@ -6,8 +6,6 @@
|
||||
TUM.objectivesMaker = {}
|
||||
|
||||
do
|
||||
local usedParkingSpots = {}
|
||||
|
||||
local function pickRandomTask()
|
||||
local taskFamily = TUM.settings.getValue(TUM.settings.id.TASKING)
|
||||
|
||||
@ -43,10 +41,6 @@ do
|
||||
return possiblePoints[1]
|
||||
end
|
||||
|
||||
function TUM.objectivesMaker.clear()
|
||||
usedParkingSpots = {}
|
||||
end
|
||||
|
||||
function TUM.objectivesMaker.create()
|
||||
local zone = DCSEx.zones.getByName(TUM.settings.getValue(TUM.settings.id.TARGET_LOCATION, true))
|
||||
|
||||
@ -57,10 +51,8 @@ do
|
||||
end
|
||||
local objectiveDB = Library.tasks[taskID]
|
||||
|
||||
local parkingInfo = nil
|
||||
local spawnPoint2 = nil
|
||||
local spawnPoint3 = nil
|
||||
local isAirbaseTarget = false
|
||||
local isSceneryTarget = false
|
||||
|
||||
if DCSEx.table.contains(objectiveDB.flags, DCSEx.enums.taskFlag.SCENERY_TARGET) then
|
||||
@ -74,40 +66,6 @@ do
|
||||
spawnPoint3 = DCSEx.table.deepCopy(pickedScenery:getPoint())
|
||||
spawnPoint2 = DCSEx.math.vec3ToVec2(spawnPoint3)
|
||||
isSceneryTarget = true
|
||||
elseif DCSEx.table.contains(objectiveDB.flags, DCSEx.enums.taskFlag.AIRBASE_TARGET) then
|
||||
local validAirbases = DCSEx.zones.getAirbases(zone, TUM.settings.getEnemyCoalition())
|
||||
if #validAirbases == 0 then
|
||||
TUM.log("Failed to find a valid airbase to use as target.", TUM.logger.logLevel.WARNING)
|
||||
return nil
|
||||
end
|
||||
local pickedAirbase = DCSEx.table.getRandom(validAirbases)
|
||||
spawnPoint3 = DCSEx.table.deepCopy(pickedAirbase:getPoint())
|
||||
spawnPoint2 = DCSEx.math.vec3ToVec2(spawnPoint3)
|
||||
isAirbaseTarget = true
|
||||
elseif DCSEx.table.contains(objectiveDB.flags, DCSEx.enums.taskFlag.PARKED_AIRCRAFT_TARGET) then
|
||||
local validAirbases = DCSEx.zones.getAirbases(zone, TUM.settings.getEnemyCoalition())
|
||||
if #validAirbases == 0 then
|
||||
TUM.log("Failed to find a valid airbase to use as target.", TUM.logger.logLevel.WARNING)
|
||||
return nil
|
||||
end
|
||||
local pickedAirbase = DCSEx.table.getRandom(validAirbases)
|
||||
local parkings = pickedAirbase:getParking()
|
||||
local validParkings = {}
|
||||
for _,p in pairs(parkings) do
|
||||
local parkingUniqueID = pickedAirbase:getID() * 10000 + p.Term_Index
|
||||
if p.Term_Type == 104 and not DCSEx.table.contains(usedParkingSpots, parkingUniqueID) then
|
||||
table.insert(validParkings, p)
|
||||
end
|
||||
end
|
||||
if #validParkings == 0 then
|
||||
TUM.log("Failed to find a valid airbase parking to spawn a target.", TUM.logger.logLevel.WARNING)
|
||||
return nil
|
||||
end
|
||||
local pickedParking = DCSEx.table.getRandom(validParkings)
|
||||
table.insert(usedParkingSpots, pickedAirbase:getID() * 10000 + pickedParking.Term_Index) -- Mark parking spot as used so it won't be taken by another objective
|
||||
parkingInfo = { airbaseID = pickedAirbase:getID(), parkingID = pickedParking.Term_Index }
|
||||
spawnPoint3 = pickedParking.vTerminalPos
|
||||
spawnPoint2 = DCSEx.math.vec3ToVec2(spawnPoint3)
|
||||
elseif objectiveDB.surfaceType == land.SurfaceType.WATER then
|
||||
spawnPoint2 = pickWaterPoint(zone)
|
||||
if not spawnPoint2 then
|
||||
@ -131,12 +89,10 @@ do
|
||||
local objective = {
|
||||
completed = false,
|
||||
completedUnitsID = {},
|
||||
isAirbaseTarget = isAirbaseTarget,
|
||||
isSceneryTarget = isSceneryTarget,
|
||||
markerID = DCSEx.world.getNextMarkerID(),
|
||||
markerTextID = DCSEx.world.getNextMarkerID(),
|
||||
name = Library.objectiveNames.get():upper(),
|
||||
parkingInfo = parkingInfo,
|
||||
point2 = DCSEx.table.deepCopy(spawnPoint2),
|
||||
point3 = DCSEx.table.deepCopy(spawnPoint3),
|
||||
preciseCoordinates = objectiveDB.waypointInaccuracy <= 0,
|
||||
@ -152,7 +108,7 @@ do
|
||||
objective.waypoint3 = DCSEx.math.vec2ToVec3(objective.waypoint2, "land")
|
||||
end
|
||||
|
||||
if not isAirbaseTarget and not isSceneryTarget then
|
||||
if not DCSEx.table.contains(objectiveDB.flags, DCSEx.enums.taskFlag.SCENERY_TARGET) then
|
||||
-- Check group options
|
||||
local groupOptions = {}
|
||||
if DCSEx.table.contains(objectiveDB.flags, DCSEx.enums.taskFlag.MOVING) then
|
||||
@ -167,26 +123,7 @@ do
|
||||
end
|
||||
end
|
||||
|
||||
-- Parked aircraft only
|
||||
if parkingInfo then
|
||||
groupOptions.airbaseID = parkingInfo.airbaseID
|
||||
groupOptions.invisible = true -- Not ideal because wingmen can't be tasked with attacking targets, but only way I've found to prevent friendly CAP from attacking parked aircraft
|
||||
groupOptions.parkingID = parkingInfo.parkingID
|
||||
end
|
||||
|
||||
-- Target group belongs to the enemy coalition, unless DCSEx.enums.taskFlag.FRIENDLY_TARGET is set
|
||||
local groupCoalition = TUM.settings.getEnemyCoalition()
|
||||
local groupFaction = TUM.settings.getEnemyFaction()
|
||||
if DCSEx.table.contains(objectiveDB.flags, DCSEx.enums.taskFlag.FRIENDLY_TARGET) then
|
||||
groupCoalition = TUM.settings.getPlayerCoalition()
|
||||
groupFaction = TUM.settings.getPlayerFaction()
|
||||
|
||||
-- Friendly target groups are immortal and invisible, so AI won't kill them before the player got a chance to interact with them
|
||||
groupOptions.immortal = true
|
||||
groupOptions.invisible = true
|
||||
end
|
||||
|
||||
local units = Library.factions.getUnits(groupFaction, objectiveDB.targetFamilies, math.random(objectiveDB.targetCount[1], objectiveDB.targetCount[2]))
|
||||
local units = Library.factions.getUnits(TUM.settings.getEnemyFaction(), objectiveDB.targetFamilies, math.random(objectiveDB.targetCount[1], objectiveDB.targetCount[2]))
|
||||
|
||||
local groupInfo = nil
|
||||
if objectiveDB.targetFamilies[1] == DCSEx.enums.unitFamily.STATIC_STRUCTURE then
|
||||
@ -195,7 +132,7 @@ do
|
||||
groupInfo.unitsID = { DCSEx.unitGroupMaker.createStatic(TUM.settings.getEnemyCoalition(), objective.point2, units[1], "") }
|
||||
end
|
||||
else
|
||||
groupInfo = DCSEx.unitGroupMaker.create(groupCoalition, DCSEx.dcs.getUnitCategoryFromFamily(objectiveDB.targetFamilies[1]), objective.point2, units, groupOptions)
|
||||
groupInfo = DCSEx.unitGroupMaker.create(TUM.settings.getEnemyCoalition(), DCSEx.dcs.getUnitCategoryFromFamily(objectiveDB.targetFamilies[1]), objective.point2, units, groupOptions)
|
||||
end
|
||||
|
||||
if not groupInfo then
|
||||
|
||||
@ -55,12 +55,7 @@ do
|
||||
if not objectDesc or not objectDesc.attributes then return 10 end -- No description, assume a default value of 10 points
|
||||
|
||||
local groundMultiplier = 1
|
||||
if not killedObject:inAir() then
|
||||
-- Aircraft killed on the ground are worth less points, except AWACS, bombers and transports
|
||||
if not objectDesc.attributes["AWACS"] and not objectDesc.attributes["Transports"] and not objectDesc.attributes["Strategic bombers"] then
|
||||
groundMultiplier = 0.5
|
||||
end
|
||||
end
|
||||
if not killedObject:inAir() then groundMultiplier = 0.5 end -- Aircraft killed on the ground are worth less points
|
||||
|
||||
-- Misc
|
||||
if objectDesc.attributes["Missiles"] then return 10 end
|
||||
@ -73,8 +68,8 @@ do
|
||||
if objectDesc.attributes["Planes"] then return math.floor(25 * groundMultiplier) end
|
||||
|
||||
-- Rotary wing
|
||||
if objectDesc.attributes["Attack helicopters"] then return math.floor(25 * groundMultiplier) end
|
||||
if objectDesc.attributes["Helicopters"] then return math.floor(15 * groundMultiplier) end
|
||||
if objectDesc.attributes["Attack helicopters"] then return math.floor(30 * groundMultiplier) end
|
||||
if objectDesc.attributes["Helicopters"] then return math.floor(25 * groundMultiplier) end
|
||||
|
||||
-- Default air
|
||||
if objectDesc.attributes["Air"] then return math.floor(20 * groundMultiplier) end
|
||||
@ -300,18 +295,11 @@ do
|
||||
if not DCSEx.io.canReadAndWrite() then return 1.0 end -- IO disabled, career and scoring disabled
|
||||
if TUM.settings.getValue(TUM.settings.id.MULTIPLAYER) then return 1.0 end -- No scoring in multiplayer
|
||||
|
||||
-- Base XP multiplier is 1.0 (100%)
|
||||
local scoreMultiplier = 1.0
|
||||
|
||||
-- Add XP multipliers for game settings
|
||||
for _,v in pairs(TUM.settings.id) do
|
||||
scoreMultiplier = scoreMultiplier + (TUM.playerScore.getScoreMultiplier(v) or 0.0)
|
||||
end
|
||||
|
||||
-- Add XP multipliers for weather
|
||||
scoreMultiplier = scoreMultiplier + TUM.weather.getWeatherXPModifier()
|
||||
scoreMultiplier = scoreMultiplier + TUM.weather.getWindXPModifier()
|
||||
|
||||
return math.max(0.0, scoreMultiplier)
|
||||
end
|
||||
|
||||
@ -347,7 +335,7 @@ do
|
||||
return
|
||||
end
|
||||
|
||||
if event.id == world.event.S_EVENT_LAND and event.place then
|
||||
if event.id == world.event.S_EVENT_LAND then
|
||||
onLandEvent(event)
|
||||
return
|
||||
end
|
||||
|
||||
@ -52,8 +52,7 @@ do
|
||||
[TUM.settings.id.PLAYER_COALITION] = { "Red", "Blue" }, -- Must match values in the coalition.side enum
|
||||
[TUM.settings.id.TARGET_COUNT] = { "1", "2", "3", "4" },
|
||||
[TUM.settings.id.TARGET_LOCATION] = { },
|
||||
-- [TUM.settings.id.TASKING] = { "Antiship strike", "Ground attack", "Helicopter-specific tasks", "Helo hunt", "Interception", "Offensive counter-air", "SEAD", "Strike" }, -- Must match values in the DCSEx.enums.taskFamily enum
|
||||
[TUM.settings.id.TASKING] = { "Antiship strike", "Ground attack", "Helo hunt", "Interception", "Offensive counter-air", "SEAD", "Strike" }, -- Must match values in the DCSEx.enums.taskFamily enum
|
||||
[TUM.settings.id.TASKING] = { "Antiship strike", "Ground attack", "Interception", "SEAD", "Strike" }, -- Must match values in the DCSEx.enums.taskFamily enum
|
||||
[TUM.settings.id.TIME_PERIOD] = { "World War 2", "Korea War", "Vietnam War", "Late Cold War", "Modern" }, -- Must match values in the DCSEx.enums.timePeriod enum
|
||||
[TUM.settings.id.WINGMEN] = { "None", "1", "2", "3" }
|
||||
}
|
||||
@ -194,10 +193,6 @@ do
|
||||
end
|
||||
end
|
||||
|
||||
-- Weather
|
||||
summary = summary.."\n\nWEATHER: "..TUM.weather.getWeatherName().." (+"..tostring(math.ceil(TUM.weather.getWeatherXPModifier() * 100)).."% xp)"
|
||||
summary = summary.."\nWIND: "..DCSEx.string.firstToUpper(TUM.weather.getWindName()).." (+"..tostring(math.ceil(TUM.weather.getWindXPModifier() * 100)).."% xp)"
|
||||
|
||||
if showScoreMultiplier then
|
||||
summary = summary.."\n\nTotal XP modifier: "..tostring(math.ceil(TUM.playerScore.getTotalScoreMultiplier() * 100)).."%"
|
||||
end
|
||||
|
||||
@ -43,15 +43,6 @@ do
|
||||
end
|
||||
end
|
||||
end
|
||||
detectedGroups = coalition.getGroups(TUM.settings.getEnemyCoalition(), Group.Category.HELICOPTER)
|
||||
for _,g in pairs(detectedGroups) do
|
||||
local units = g:getUnits()
|
||||
for _,u in pairs(units) do
|
||||
if u:inAir() then
|
||||
table.insert(detectedAircraft, u)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- No aircraft on picture
|
||||
if #detectedAircraft == 0 then
|
||||
|
||||
@ -60,7 +60,7 @@ do
|
||||
return
|
||||
end
|
||||
|
||||
if obj.isAirbaseTarget or obj.isSceneryTarget then
|
||||
if obj.isSceneryTarget then
|
||||
TUM.radio.playForCoalition(TUM.settings.getPlayerCoalition(), "jtacSmokeOK", { jtacName[index], smokeColorName }, jtacName[index], true, spawnSmoke, { point3 = obj.point3, smokeColor = smokeColor })
|
||||
else
|
||||
for _,id in ipairs(obj.unitsID) do
|
||||
|
||||
@ -1,322 +0,0 @@
|
||||
-- ====================================================================================
|
||||
-- TUM.WEATHER - HANDLES THE MISSION'S WEATHER SETTINGS
|
||||
-- ====================================================================================
|
||||
-- ====================================================================================
|
||||
|
||||
TUM.weather = {}
|
||||
|
||||
do
|
||||
local cloudPresets = {
|
||||
-- "Light Scattered 1",
|
||||
Preset1 = {
|
||||
readableName = "Few scattered clouds (METAR: FEW/SCT 7/8)",
|
||||
readableNameShort = "Light scattered",
|
||||
xpBonus = 0,
|
||||
},
|
||||
|
||||
-- "Light Scattered 2",
|
||||
Preset2 = {
|
||||
readableName = "Two layers few and scattered (METAR: FEW/SCT 8/10 SCT 23/24)",
|
||||
readableNameShort = "Light scattered",
|
||||
xpBonus = 0,
|
||||
},
|
||||
|
||||
-- "High Scattered 1",
|
||||
Preset3 = {
|
||||
readableName = "Two layers scattered (METAR: SCT 8/9 FEW 21)",
|
||||
readableNameShort = "High Scattered",
|
||||
xpBonus = 0,
|
||||
},
|
||||
|
||||
-- "High Scattered 2",
|
||||
Preset4 = {
|
||||
readableName = "Two layers scattered (METAR: SCT 8/10 FEW/SCT 24/26)",
|
||||
readableNameShort = "High Scattered",
|
||||
xpBonus = 0,
|
||||
},
|
||||
|
||||
-- "Scattered 1",
|
||||
Preset5 = {
|
||||
readableName = "Three layers high altitude scattered (METAR: SCT 14/17 FEW 27/29 BKN 40)",
|
||||
readableNameShort = "Scattered",
|
||||
xpBonus = 0,
|
||||
},
|
||||
|
||||
-- "Scattered 2",
|
||||
Preset6 = {
|
||||
readableName = "One layer scattered/broken (METAR: SCT/BKN 8/10 FEW 40)",
|
||||
readableNameShort = "Scattered",
|
||||
xpBonus = 0,
|
||||
},
|
||||
|
||||
-- "Scattered 3",
|
||||
Preset7 = {
|
||||
readableName = "Two layers scattered/broken (METAR: BKN 7.5/12 SCT/BKN 21/23 SCT 40)",
|
||||
readableNameShort = "Scattered",
|
||||
xpBonus = 0,
|
||||
},
|
||||
|
||||
-- "High Scattered 3",
|
||||
Preset8 = {
|
||||
readableName = "Two layers scattered/broken high altitude (METAR: SCT/BKN 18/20 FEW 36/38 FEW 40)",
|
||||
readableNameShort = "High Scattered",
|
||||
xpBonus = 0,
|
||||
},
|
||||
|
||||
-- "Scattered 4",
|
||||
Preset9 = {
|
||||
readableName = "Two layers broken/scattered (METAR: BKN 7.5/10 SCT 20/22 FEW41)",
|
||||
readableNameShort = "Scattered",
|
||||
xpBonus = 0,
|
||||
},
|
||||
|
||||
-- "Scattered 5",
|
||||
Preset10 = {
|
||||
readableName = "Two layers scattered large thick clouds (METAR: SCT/BKN 18/20 FEW36/38 FEW 40)",
|
||||
readableNameShort = "Scattered",
|
||||
xpBonus = 0,
|
||||
},
|
||||
|
||||
-- "Scattered 6",
|
||||
Preset11 = {
|
||||
readableName = "Two layers scattered large clouds high ceiling (METAR: BKN 18/20 BKN 32/33 FEW 41)",
|
||||
readableNameShort = "Scattered",
|
||||
xpBonus = 0,
|
||||
},
|
||||
|
||||
-- "Scattered 7",
|
||||
Preset12 = {
|
||||
readableName = "Two layers scattered large clouds high ceiling (METAR: BKN 12/14 SCT 22/23 FEW 41)",
|
||||
readableNameShort = "Scattered",
|
||||
xpBonus = 0,
|
||||
},
|
||||
|
||||
-- "Broken 1",
|
||||
Preset13 = {
|
||||
readableName = "Two layers broken clouds (METAR: BKN 12/14 BKN 26/28 FEW 41)",
|
||||
readableNameShort = "Broken",
|
||||
xpBonus = 0.05,
|
||||
},
|
||||
|
||||
-- "Broken 2",
|
||||
Preset14 = {
|
||||
readableName = "Broken thick low layer with few high layers\nMETAR: BKN LYR 7/16 FEW 41)",
|
||||
readableNameShort = "Broken",
|
||||
xpBonus = 0.05,
|
||||
},
|
||||
|
||||
-- "Broken 3",
|
||||
Preset15 = {
|
||||
readableName = "Two layers broken large clouds (METAR: SCT/BKN 14/18 BKN 24/27 FEW 40)",
|
||||
readableNameShort = "Broken",
|
||||
xpBonus = 0.05,
|
||||
},
|
||||
|
||||
-- "Broken 4",
|
||||
Preset16 = {
|
||||
readableName = "Two layers broken large clouds (METAR: BKN 14/18 BKN 28/30 FEW 40)",
|
||||
readableNameShort = "Broken",
|
||||
xpBonus = 0.05,
|
||||
},
|
||||
|
||||
-- "Broken 5",
|
||||
Preset17 = {
|
||||
readableName = "Three layers broken/overcast (METAR: BKN/OVC LYR 7/13 20/22 32/34)",
|
||||
readableNameShort = "Broken",
|
||||
xpBonus = 0.05,
|
||||
},
|
||||
|
||||
-- "Broken 6",
|
||||
Preset18 = {
|
||||
readableName = "Three layers broken/overcast (METAR: BKN/OVC LYR 13/15 25/29 38/41)",
|
||||
readableNameShort = "Broken",
|
||||
xpBonus = 0.05,
|
||||
},
|
||||
|
||||
-- "Broken 7",
|
||||
Preset19 = {
|
||||
readableName = "Three layers overcast at low level (METAR: OVC 9/16 BKN/OVC LYR 23/24 31/33)",
|
||||
readableNameShort = "Broken",
|
||||
xpBonus = 0.05,
|
||||
},
|
||||
|
||||
-- "Broken 8",
|
||||
Preset20 = {
|
||||
readableName = "Three layers overcast low level (METAR: BKN/OVC 13/18 BKN 28/30 SCT FEW 38)",
|
||||
readableNameShort = "Broken",
|
||||
xpBonus = 0.05,
|
||||
},
|
||||
|
||||
-- "Overcast 1",
|
||||
Preset21 = {
|
||||
readableName = "Overcast low level (METAR: BKN/OVC LYR 7/8 17/19)",
|
||||
readableNameShort = "Overcast",
|
||||
xpBonus = 0.10,
|
||||
},
|
||||
|
||||
-- "Overcast 2",
|
||||
Preset22 = {
|
||||
readableName = "Overcast low level (METAR: BKN LYR 7/10 17/20)",
|
||||
readableNameShort = "Overcast",
|
||||
xpBonus = 0.10,
|
||||
},
|
||||
|
||||
-- "Overcast 3",
|
||||
Preset23 = {
|
||||
readableName = "Three layers broken low level scattered high (METAR: BKN LYR 11/14 18/25 SCT 32/35)",
|
||||
readableNameShort = "Overcast",
|
||||
xpBonus = 0.10,
|
||||
},
|
||||
|
||||
-- "Overcast 4",
|
||||
Preset24 = {
|
||||
readableName = "Three layers overcast (METAR: BKN/OVC 3/7 17/22 BKN 34)",
|
||||
readableNameShort = "Overcast",
|
||||
xpBonus = 0.10,
|
||||
},
|
||||
|
||||
-- "Overcast 5",
|
||||
Preset25 = {
|
||||
readableName = "Three layers overcast (METAR: OVC LYR 12/14 22/25 40/42)",
|
||||
readableNameShort = "Overcast",
|
||||
xpBonus = 0.10,
|
||||
},
|
||||
|
||||
-- "Overcast 6",
|
||||
Preset26 = {
|
||||
readableName = "Three layers overcast (METAR: OVC 9/15 BKN 23/25 SCT 32)",
|
||||
readableNameShort = "Overcast",
|
||||
xpBonus = 0.10,
|
||||
},
|
||||
|
||||
-- "Overcast 7",
|
||||
Preset27 = {
|
||||
readableName = "Three layer overcast (METAR: OVC 8/15 SCT/BKN 25/26 34/36)",
|
||||
readableNameShort = "Overcast",
|
||||
xpBonus = 0.10,
|
||||
},
|
||||
|
||||
-- "Overcast And Rain 1",
|
||||
RainyPreset1 = {
|
||||
readableName = "Overcast with rain (METAR: VIS 3-5KM RA OVC 3/15 28/30 FEW 40)",
|
||||
readableNameShort = "Overcast and rain",
|
||||
xpBonus = 0.25,
|
||||
},
|
||||
|
||||
-- "Overcast And Rain 2",
|
||||
RainyPreset2 = {
|
||||
readableName = "Overcast with rain (METAR: VIS 1-5KM RA BKN/OVC 3/11 SCT 18/29 FEW 40)",
|
||||
readableNameShort = "Overcast and rain",
|
||||
xpBonus = 0.25,
|
||||
},
|
||||
|
||||
-- "Overcast And Rain 3",
|
||||
RainyPreset3 = {
|
||||
readableName = "Overcast with rain (METAR: VIS 3-5KM RA OVC LYR 6/18 19/21 SCT 34)",
|
||||
readableNameShort = "Overcast and rain",
|
||||
xpBonus = 0.25,
|
||||
},
|
||||
|
||||
-- "Light Rain 1",
|
||||
RainyPreset4 = {
|
||||
readableName = "Two layers scattered large thick clouds (METAR: SCT/BKN 18/20 FEW36/38 FEW 40)",
|
||||
readableNameShort = "Light rain",
|
||||
xpBonus = 0.15,
|
||||
},
|
||||
|
||||
-- "Light Rain 2",
|
||||
RainyPreset5 = {
|
||||
readableName = "Three layers broken/overcast (METAR: BKN/OVC LYR 7/13 20/22 32/34)",
|
||||
readableNameShort = "Light rain",
|
||||
xpBonus = 0.15,
|
||||
},
|
||||
|
||||
-- "Light Rain 3",
|
||||
RainyPreset6 = {
|
||||
readableName = "Three layers overcast at low level (METAR: OVC 9/16 BKN/OVC LYR 23/24 31/33)",
|
||||
readableNameShort = "Light rain",
|
||||
xpBonus = 0.15,
|
||||
},
|
||||
|
||||
-- "Light Rain 4",
|
||||
NEWRAINPRESET4 = {
|
||||
readableName = "Two layers overcast at low level (METAR: OVC 9/16 BKN/OVC LYR 23/24 31/33)",
|
||||
readableNameShort = "Light rain",
|
||||
xpBonus = 0.15,
|
||||
},
|
||||
}
|
||||
|
||||
local function getWindBeaufortScale(speedInMS)
|
||||
local speedInKMH = DCSEx.converter.mpsToKmph(speedInMS or Library.environment.getWindAverage())
|
||||
|
||||
if speedInKMH < 1 then return 0
|
||||
elseif speedInKMH <= 5 then return 1
|
||||
elseif speedInKMH <= 11 then return 2
|
||||
elseif speedInKMH <= 19 then return 3
|
||||
elseif speedInKMH <= 28 then return 4
|
||||
elseif speedInKMH <= 38 then return 5
|
||||
elseif speedInKMH <= 49 then return 6
|
||||
elseif speedInKMH <= 61 then return 7
|
||||
elseif speedInKMH <= 74 then return 8
|
||||
elseif speedInKMH <= 88 then return 9
|
||||
elseif speedInKMH <= 102 then return 10
|
||||
elseif speedInKMH <= 117 then return 11
|
||||
else return 12
|
||||
end
|
||||
end
|
||||
|
||||
function TUM.weather.getWeatherName(presetID, longForm)
|
||||
presetID = presetID or env.mission.weather.clouds.preset
|
||||
longForm = longForm or false
|
||||
|
||||
if cloudPresets[presetID] == nil then return "Unknown" end
|
||||
if longForm then return cloudPresets[presetID].readableName end
|
||||
return cloudPresets[presetID].readableNameShort
|
||||
end
|
||||
|
||||
function TUM.weather.getWeatherXPModifier(presetID)
|
||||
presetID = presetID or env.mission.weather.clouds.preset
|
||||
|
||||
if cloudPresets[presetID] == nil then return 0 end
|
||||
|
||||
return cloudPresets[presetID].xpBonus
|
||||
end
|
||||
|
||||
function TUM.weather.getWindName(speedInMS)
|
||||
local windBeaufort = getWindBeaufortScale(speedInMS)
|
||||
|
||||
if windBeaufort == 0 then return "calm"
|
||||
elseif windBeaufort == 1 then return "light air"
|
||||
elseif windBeaufort == 2 then return "light breeze"
|
||||
elseif windBeaufort == 3 then return "gentle breeze"
|
||||
elseif windBeaufort == 4 then return "moderate breeze"
|
||||
elseif windBeaufort == 5 then return "fresh breeze"
|
||||
elseif windBeaufort == 6 then return "strong breeze"
|
||||
elseif windBeaufort == 7 then return "moderate gale"
|
||||
elseif windBeaufort == 8 then return "fresh gale"
|
||||
elseif windBeaufort == 9 then return "strong gale"
|
||||
elseif windBeaufort == 10 then return "storm"
|
||||
elseif windBeaufort == 11 then return "violent storm"
|
||||
elseif windBeaufort == 12 then return "hurricane"
|
||||
end
|
||||
end
|
||||
|
||||
function TUM.weather.getWindXPModifier(speedInMS)
|
||||
local windBeaufort = getWindBeaufortScale(speedInMS)
|
||||
|
||||
if windBeaufort == 0 then return 0.00
|
||||
elseif windBeaufort == 1 then return 0.02
|
||||
elseif windBeaufort == 2 then return 0.04
|
||||
elseif windBeaufort == 3 then return 0.08
|
||||
elseif windBeaufort == 4 then return 0.10
|
||||
elseif windBeaufort == 5 then return 0.12
|
||||
elseif windBeaufort == 6 then return 0.15
|
||||
elseif windBeaufort == 7 then return 0.18
|
||||
elseif windBeaufort == 8 then return 0.21
|
||||
elseif windBeaufort == 9 then return 0.24
|
||||
elseif windBeaufort == 10 then return 0.27
|
||||
elseif windBeaufort == 11 then return 0.30
|
||||
elseif windBeaufort == 12 then return 0.33
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -23,11 +23,11 @@ do
|
||||
elseif taskingID == DCSEx.enums.taskFamily.GROUND_ATTACK then
|
||||
return "attack"
|
||||
-- elseif taskingID == DCSEx.enums.taskFamily.HELICOPTER then
|
||||
elseif taskingID == DCSEx.enums.taskFamily.HELO_HUNT then
|
||||
-- elseif taskingID == DCSEx.enums.taskFamily.HELO_HUN then
|
||||
elseif taskingID == DCSEx.enums.taskFamily.INTERCEPTION then
|
||||
return "cap"
|
||||
elseif taskingID == DCSEx.enums.taskFamily.SEAD then
|
||||
-- elseif taskingID == DCSEx.enums.taskFamily.OCA then
|
||||
elseif taskingID == DCSEx.enums.taskFamily.SEAD then
|
||||
return "sead"
|
||||
-- elseif taskingID == DCSEx.enums.taskFamily.STRIKE then
|
||||
-- return "strike"
|
||||
@ -177,7 +177,7 @@ do
|
||||
if not event.initiator:getPlayerName() then return end
|
||||
if TUM.mission.getStatus() == TUM.mission.status.NONE then return end -- Mission not in progress, no wingman needed
|
||||
TUM.wingmen.create()
|
||||
elseif event.id == world.event.S_EVENT_LAND and event.place then -- Remove wingmen on player landing
|
||||
elseif event.id == world.event.S_EVENT_LAND then -- Remove wingmen on player landing
|
||||
if not event.initiator:getPlayerName() then return end
|
||||
TUM.wingmen.removeAll()
|
||||
elseif event.id == world.event.S_EVENT_PLAYER_ENTER_UNIT then -- Remove wingmen when player takes control of a new unit
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
User's manual
|
||||
</p>
|
||||
<p class="heavy">
|
||||
The Universal Mission v0.3.251019<br />
|
||||
The Universal Mission v0.3.250914<br />
|
||||
Created and maintained by Ambroise Garel (<a href='mailto:akaagarmail@gmail.com'>akaagarmail@gmail.com</a>)
|
||||
</p>
|
||||
<p class="heavy">
|
||||
@ -73,6 +73,7 @@ I hope you'll like it.
|
||||
|
||||
- Download the latest release from this GitHub page.
|
||||
- Copy the provided autoexec.cfg file to your **[Saved Games]\DCS\Config directory**
|
||||
- Please note: as of DCS 2.9.18.12899, it seems the autoexec.cfg file [is no longer needed](https://www.digitalcombatsimulator.com/en/news/changelog/release/2.9.18.12899/) but I advise you to copy it anyway, ED might change its mind again.
|
||||
- Copy the .miz files for your theater(s) of choice to your **[Saved Games]\DCS\Missions directory**
|
||||
- _**(Optional but strongly recommended)**_ Unsanitize the Lua IO module. You don't have to do this, but the persistent career system won't work if you don't. To do it, open the file **[DCS World installation directory]\Scripts\MissionScripting.lua** with a text editor and comment or remove the line "sanitizeModule('io')". Make sure you restart DCS World once you've modified the file.
|
||||
- Please note: should you want to backup, delete or transfer it, career progress is saved in **[DCS World installation directory]\TheUniversalMission.sav**
|
||||
@ -112,10 +113,7 @@ The exact content of the menu will depend on the current phase of the mission.
|
||||
- **Mission type**: What will your mission be?
|
||||
- **Antiship strike**: Sink enemy warships and cargo ships.
|
||||
- **Ground attack**: Interdiction missions against armor, artillery and convoys.
|
||||
- **Helicopter-specific tasks**: Tasks specifically designed for helicopters (lift/pick up friendly units, suppress infantry...)
|
||||
- **Helicopter hunt**: Shoot down enemy transport and attack helicopters.
|
||||
- **Interception**: Shoot down strategic airplanes (bombers, transports...) and enemy attack planes on interdiction missions.
|
||||
- **Offensive counter-air**: Bomb enemy airbases and destroy parked aircraft. **(Requires a target area with at least one enemy land airbase, or mission type will automatically be changed to ground attack)**
|
||||
- **SEAD**: Destroy enemy SAM sites.
|
||||
- **Strike**: Destroy enemy structures and civilian buildings occupied by enemy forces.
|
||||
- **Target location**: Where on the map will the targets be spawned? Approximate distance to possible regions is displayed in the menu.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user