diff --git a/game/data/aaa_db.py b/game/data/aaa_db.py
index 1aa7d597..d7e7d101 100644
--- a/game/data/aaa_db.py
+++ b/game/data/aaa_db.py
@@ -17,5 +17,5 @@ AAA_UNITS = [
AirDefence.AAA_Flak_Vierling_38,
AirDefence.AAA_Kdo_G_40,
AirDefence.AAA_8_8cm_Flak_41,
- AirDefence.AAA_Bofors_40mm
-]
\ No newline at end of file
+ AirDefence.AAA_Bofors_40mm,
+]
diff --git a/game/data/building_data.py b/game/data/building_data.py
index ae4e2236..5331ebbd 100644
--- a/game/data/building_data.py
+++ b/game/data/building_data.py
@@ -1,17 +1,70 @@
import inspect
import dcs
-DEFAULT_AVAILABLE_BUILDINGS = ['fuel', 'ammo', 'comms', 'oil', 'ware', 'farp', 'fob', 'power', 'factory', 'derrick']
+DEFAULT_AVAILABLE_BUILDINGS = [
+ "fuel",
+ "ammo",
+ "comms",
+ "oil",
+ "ware",
+ "farp",
+ "fob",
+ "power",
+ "factory",
+ "derrick",
+]
-WW2_FREE = ['fuel', 'factory', 'ware', 'fob']
-WW2_GERMANY_BUILDINGS = ['fuel', 'factory', 'ww2bunker', 'ww2bunker', 'ww2bunker', 'allycamp', 'allycamp', 'fob']
-WW2_ALLIES_BUILDINGS = ['fuel', 'factory', 'allycamp', 'allycamp', 'allycamp', 'allycamp', 'allycamp', 'fob']
+WW2_FREE = ["fuel", "factory", "ware", "fob"]
+WW2_GERMANY_BUILDINGS = [
+ "fuel",
+ "factory",
+ "ww2bunker",
+ "ww2bunker",
+ "ww2bunker",
+ "allycamp",
+ "allycamp",
+ "fob",
+]
+WW2_ALLIES_BUILDINGS = [
+ "fuel",
+ "factory",
+ "allycamp",
+ "allycamp",
+ "allycamp",
+ "allycamp",
+ "allycamp",
+ "fob",
+]
-FORTIFICATION_BUILDINGS = ['Siegfried Line', 'Concertina wire', 'Concertina Wire', 'Czech hedgehogs 1', 'Czech hedgehogs 2',
- 'Dragonteeth 1', 'Dragonteeth 2', 'Dragonteeth 3', 'Dragonteeth 4', 'Dragonteeth 5',
- 'Haystack 1', 'Haystack 2', 'Haystack 3', 'Haystack 4', 'Hemmkurvenvenhindernis',
- 'Log posts 1', 'Log posts 2', 'Log posts 3', 'Log ramps 1', 'Log ramps 2', 'Log ramps 3',
- 'Belgian Gate', 'Container white']
+FORTIFICATION_BUILDINGS = [
+ "Siegfried Line",
+ "Concertina wire",
+ "Concertina Wire",
+ "Czech hedgehogs 1",
+ "Czech hedgehogs 2",
+ "Dragonteeth 1",
+ "Dragonteeth 2",
+ "Dragonteeth 3",
+ "Dragonteeth 4",
+ "Dragonteeth 5",
+ "Haystack 1",
+ "Haystack 2",
+ "Haystack 3",
+ "Haystack 4",
+ "Hemmkurvenvenhindernis",
+ "Log posts 1",
+ "Log posts 2",
+ "Log posts 3",
+ "Log ramps 1",
+ "Log ramps 2",
+ "Log ramps 3",
+ "Belgian Gate",
+ "Container white",
+]
-FORTIFICATION_UNITS = [c for c in vars(dcs.vehicles.Fortification).values() if inspect.isclass(c)]
-FORTIFICATION_UNITS_ID = [c.id for c in vars(dcs.vehicles.Fortification).values() if inspect.isclass(c)]
\ No newline at end of file
+FORTIFICATION_UNITS = [
+ c for c in vars(dcs.vehicles.Fortification).values() if inspect.isclass(c)
+]
+FORTIFICATION_UNITS_ID = [
+ c.id for c in vars(dcs.vehicles.Fortification).values() if inspect.isclass(c)
+]
diff --git a/game/data/cap_capabilities_db.py b/game/data/cap_capabilities_db.py
index 1ee3f075..160faede 100644
--- a/game/data/cap_capabilities_db.py
+++ b/game/data/cap_capabilities_db.py
@@ -16,7 +16,7 @@ from dcs.planes import (
P_51D,
P_51D_30_NA,
SpitfireLFMkIX,
- SpitfireLFMkIXCW
+ SpitfireLFMkIXCW,
)
from pydcs_extensions.a4ec.a4ec import A_4E_C
@@ -26,7 +26,6 @@ This list contains the aircraft that do not use the guns as the last resort weap
They'll RTB when they don't have gun ammo left
"""
GUNFIGHTERS = [
-
# Cold War
MiG_15bis,
MiG_19P,
@@ -34,11 +33,9 @@ GUNFIGHTERS = [
F_86F_Sabre,
A_4E_C,
F_5E_3,
-
# Trainers
C_101CC,
L_39ZA,
-
# WW2
P_51D_30_NA,
P_51D,
@@ -51,5 +48,4 @@ GUNFIGHTERS = [
FW_190D9,
FW_190A8,
I_16,
-
-]
\ No newline at end of file
+]
diff --git a/game/data/radar_db.py b/game/data/radar_db.py
index 4e90d56c..10e38f42 100644
--- a/game/data/radar_db.py
+++ b/game/data/radar_db.py
@@ -23,7 +23,6 @@ from dcs.ships import (
from dcs.vehicles import AirDefence
UNITS_WITH_RADAR = [
-
# Radars
AirDefence.SAM_SA_15_Tor_9A331,
AirDefence.SAM_SA_11_Buk_CC_9S470M1,
@@ -49,7 +48,6 @@ UNITS_WITH_RADAR = [
AirDefence.SAM_SA_3_S_125_TR_SNR,
AirDefence.SAM_SA_2_TR_SNR_75_Fan_Song,
AirDefence.HQ_7_Self_Propelled_STR,
-
# Ships
CVN_70_Carl_Vinson,
Oliver_Hazzard_Perry_class,
@@ -70,5 +68,5 @@ UNITS_WITH_RADAR = [
LHA_1_Tarawa,
Type_052B_Destroyer,
Type_054A_Frigate,
- Type_052C_Destroyer
-]
\ No newline at end of file
+ Type_052C_Destroyer,
+]
diff --git a/game/data/weapons.py b/game/data/weapons.py
index acbd9456..b42112fa 100644
--- a/game/data/weapons.py
+++ b/game/data/weapons.py
@@ -28,7 +28,8 @@ class Weapon:
introduction_year = WEAPON_INTRODUCTION_YEARS.get(self)
if introduction_year is None:
logging.warning(
- f"No introduction year for {self}, assuming always available")
+ f"No introduction year for {self}, assuming always available"
+ )
return True
return date >= datetime.date(introduction_year, 1, 1)
@@ -52,7 +53,7 @@ class Weapon:
return cls(
cast(str, weapon_data["clsid"]),
cast(str, weapon_data["name"]),
- cast(int, weapon_data["weight"])
+ cast(int, weapon_data["weight"]),
)
@classmethod
@@ -88,8 +89,11 @@ class Pylon:
def for_aircraft(cls, aircraft: Type[FlyingType], number: int) -> Pylon:
# In pydcs these are all arbitrary inner classes of the aircraft type.
# The only way to identify them is by their name.
- pylons = [v for v in aircraft.__dict__.values() if
- inspect.isclass(v) and v.__name__.startswith("Pylon")]
+ pylons = [
+ v
+ for v in aircraft.__dict__.values()
+ if inspect.isclass(v) and v.__name__.startswith("Pylon")
+ ]
# And that Pylon class has members with irrelevant names that have
# values of (pylon number, allowed weapon).
@@ -117,112 +121,92 @@ _WEAPON_FALLBACKS = [
(Weapons.ADM_141A_, None),
(Weapons.ADM_141A__, None),
(Weapons.ADM_141B, None),
-
# AGM-114K Hellfire
- (Weapons.AGM114x2_OH_58, Weapons.M260_HYDRA), # assuming OH-58 and not MQ-9
- (Weapons.AGM_114K, None), # Only for RQ-1
+ (Weapons.AGM114x2_OH_58, Weapons.M260_HYDRA), # assuming OH-58 and not MQ-9
+ (Weapons.AGM_114K, None), # Only for RQ-1
(Weapons.AGM_114K___4, Weapons.LAU_61___19_2_75__rockets_MK151_HE),
-
# AGM-119 Penguin
(Weapons.AGM_119B_Penguin, Weapons.Mk_82),
-
# AGM-122 Sidearm
- (Weapons.AGM_122, None), # No known aircraft carries this
- (Weapons.AGM_122_Sidearm, Weapons.GBU_12), # outer pylons harrier
- (Weapons.AGM_122_Sidearm_, Weapons.LAU_117_AGM_65E), # internal pylons harrier
-
+ (Weapons.AGM_122, None), # No known aircraft carries this
+ (Weapons.AGM_122_Sidearm, Weapons.GBU_12), # outer pylons harrier
+ (Weapons.AGM_122_Sidearm_, Weapons.LAU_117_AGM_65E), # internal pylons harrier
# AGM-154 JSOW
(Weapons.AGM_154A, Weapons.GBU_12),
(Weapons.BRU_55___2_x_AGM_154A, Weapons.BRU_33___2_x_GBU_12),
- (Weapons.BRU_57___2_x_AGM_154A, None), # doesn't exist on any aircraft yet
-
+ (Weapons.BRU_57___2_x_AGM_154A, None), # doesn't exist on any aircraft yet
(Weapons.AGM_154B, Weapons.CBU_105),
-
(Weapons.AGM_154C, Weapons.GBU_12),
(Weapons.AGM_154C_4, Weapons.GBU_31_8),
(Weapons.BRU_55___2_x_AGM_154C, Weapons.BRU_33___2_x_GBU_12),
-
# AGM-45 Shrike
(Weapons.AGM_45A, None),
(Weapons.AGM_45B, Weapons.AGM_45A),
(Weapons.AGM_45B_, Weapons.AGM_45A),
-
# AGM-62 Walleye
(Weapons.AGM_62, Weapons.Mk_84),
-
# AGM-65 Maverick
- (Weapons.AGM_65D, None), # doesn't exist
- (Weapons.AGM_65E, None), # doesn't exist
- (Weapons.AGM_65K, None), # doesn't exist
- (Weapons.LAU_117_AGM_65A, None), # doesn't exist
- (Weapons.LAU_117_AGM_65B, None), # doesn't exist
-
- (Weapons.LAU_117_AGM_65D, Weapons.AGM_62), # Walleye is the predecessor to the maverick
+ (Weapons.AGM_65D, None), # doesn't exist
+ (Weapons.AGM_65E, None), # doesn't exist
+ (Weapons.AGM_65K, None), # doesn't exist
+ (Weapons.LAU_117_AGM_65A, None), # doesn't exist
+ (Weapons.LAU_117_AGM_65B, None), # doesn't exist
+ (
+ Weapons.LAU_117_AGM_65D,
+ Weapons.AGM_62,
+ ), # Walleye is the predecessor to the maverick
(Weapons.LAU_117_AGM_65E, None),
(Weapons.LAU_117_AGM_65F, Weapons.LAU_117_AGM_65D),
(Weapons.LAU_117_AGM_65G, Weapons.LAU_117_AGM_65D),
(Weapons.LAU_117_AGM_65H, Weapons.LAU_117_AGM_65D),
(Weapons.LAU_117_AGM_65K, Weapons.LAU_117_AGM_65D),
(Weapons.LAU_117_AGM_65L, None),
-
(Weapons.LAU_88_AGM_65D_2, None),
(Weapons.LAU_88_AGM_65D_2_, None),
(Weapons.LAU_88_AGM_65D_3, None),
(Weapons.LAU_88_AGM_65D_ONE, None),
-
(Weapons.LAU_88_AGM_65E_2, Weapons.LAU_88_AGM_65D_2),
(Weapons.LAU_88_AGM_65E_2_, Weapons.LAU_88_AGM_65D_2_),
(Weapons.LAU_88_AGM_65E_3, Weapons.LAU_88_AGM_65D_3),
-
(Weapons.LAU_88_AGM_65H, Weapons.LAU_88_AGM_65D_2),
(Weapons.LAU_88_AGM_65H_2_L, Weapons.LAU_88_AGM_65D_2_),
(Weapons.LAU_88_AGM_65H_2_R, Weapons.LAU_88_AGM_65D_2_),
(Weapons.LAU_88_AGM_65H_3, Weapons.LAU_88_AGM_65D_3),
-
(Weapons.LAU_88_AGM_65K_2, Weapons.LAU_88_AGM_65D_2),
(Weapons.LAU_88_AGM_65K_2_, Weapons.LAU_88_AGM_65D_2_),
(Weapons.LAU_88_AGM_65K_3, Weapons.LAU_88_AGM_65D_3),
-
# AGM-84 Harpoon
- (Weapons.AGM_84, None), # doesn't exist
+ (Weapons.AGM_84, None), # doesn't exist
(Weapons.AGM_84A, Weapons.Mk_82),
(Weapons.AGM_84A_8, Weapons._27_Mk_82),
(Weapons.AGM_84D, Weapons.AGM_62),
(Weapons.AGM_84E, Weapons.LAU_117_AGM_65F),
(Weapons.AGM_84H, Weapons.AGM_84E),
-
# AGM-86 ALCM
(Weapons.AGM_86C, Weapons._27_Mk_82),
(Weapons.AGM_86C_20, Weapons._27_Mk_82),
(Weapons.AGM_86C_8, Weapons._27_Mk_82),
(Weapons.MER_6_AGM_86C, Weapons.MER_12_Mk_82),
-
# AGM-88 HARM
(Weapons.AGM_88C, Weapons.AGM_65D),
(Weapons.AGM_88C_, Weapons.AGM_65D),
-
- # AIM-120 AMRAAM
+ # AIM-120 AMRAAM
(Weapons.AIM_120B, Weapons.AIM_7MH),
(Weapons.LAU_115___AIM_120B, Weapons.LAU_115C_AIM_7MH),
(Weapons.LAU_115_2_LAU_127_AIM_120B, Weapons.LAU_115C_AIM_7MH),
-
(Weapons.AIM_120C, Weapons.AIM_120B),
(Weapons.LAU_115___AIM_120C, Weapons.LAU_115___AIM_120B),
(Weapons.LAU_115_2_LAU_127_AIM_120C, Weapons.LAU_115_2_LAU_127_AIM_120B),
-
# AIM-54 Phoenix
(Weapons.AIM_54A_Mk47, None),
(Weapons.AIM_54A_Mk47_, None),
(Weapons.AIM_54A_Mk47__, None),
-
(Weapons.AIM_54A_Mk60, Weapons.AIM_54A_Mk47),
(Weapons.AIM_54A_Mk60_, Weapons.AIM_54A_Mk47_),
(Weapons.AIM_54A_Mk60__, Weapons.AIM_54A_Mk47__),
-
(Weapons.AIM_54C_Mk47, Weapons.AIM_54A_Mk60),
(Weapons.AIM_54C_Mk47_, Weapons.AIM_54A_Mk60_),
(Weapons.AIM_54C_Mk47__, Weapons.AIM_54A_Mk60__),
-
# AIM-7 Sparrow
(Weapons.AIM_7E, None),
(Weapons.AIM_7F, Weapons.AIM_7E),
@@ -234,62 +218,61 @@ _WEAPON_FALLBACKS = [
(Weapons.AIM_7MH, Weapons.AIM_7M),
(Weapons.AIM_7MH_, Weapons.AIM_7M_),
(Weapons.AIM_7MH__, Weapons.AIM_7M__),
-
(Weapons.LAU_115C_AIM_7E, None),
(Weapons.LAU_115C_AIM_7F, Weapons.LAU_115C_AIM_7E),
(Weapons.LAU_115___AIM_7M, Weapons.LAU_115C_AIM_7F),
(Weapons.LAU_115C_AIM_7MH, Weapons.LAU_115___AIM_7M),
-
# AIM-9 Sidewinder
(Weapons.AIM_9L_Sidewinder_IR_AAM, None),
(Weapons.AIM_9M_Sidewinder_IR_AAM, Weapons.AIM_9P5_Sidewinder_IR_AAM),
(Weapons.AIM_9P5_Sidewinder_IR_AAM, Weapons.AIM_9P_Sidewinder_IR_AAM),
(Weapons.AIM_9P_Sidewinder_IR_AAM, Weapons.AIM_9L_Sidewinder_IR_AAM),
(Weapons.AIM_9X_Sidewinder_IR_AAM, Weapons.AIM_9P_Sidewinder_IR_AAM),
-
(Weapons.LAU_105_1_AIM_9L_L, None),
(Weapons.LAU_105_1_AIM_9L_R, None),
(Weapons.LAU_105_1_AIM_9M_L, Weapons.LAU_105_1_AIM_9L_L),
(Weapons.LAU_105_1_AIM_9M_R, Weapons.LAU_105_1_AIM_9L_R),
-
(Weapons.LAU_105_2_AIM_9L, None),
(Weapons.LAU_105_2_AIM_9P5, Weapons.LAU_105___2_AIM_9P_Sidewinder_IR_AAM),
-
(Weapons.LAU_105___2_AIM_9M_Sidewinder_IR_AAM, Weapons.LAU_105_2_AIM_9L),
- (Weapons.LAU_105___2_AIM_9P_Sidewinder_IR_AAM, Weapons.LAU_105___2_AIM_9M_Sidewinder_IR_AAM),
-
+ (
+ Weapons.LAU_105___2_AIM_9P_Sidewinder_IR_AAM,
+ Weapons.LAU_105___2_AIM_9M_Sidewinder_IR_AAM,
+ ),
(Weapons.LAU_115_2_LAU_127_AIM_9L, None),
(Weapons.LAU_115_2_LAU_127_AIM_9M, Weapons.LAU_115_2_LAU_127_AIM_9L),
(Weapons.LAU_115_2_LAU_127_AIM_9X, Weapons.LAU_115_2_LAU_127_AIM_9M),
-
(Weapons.LAU_115_LAU_127_AIM_9L, None),
(Weapons.LAU_115_LAU_127_AIM_9M, Weapons.LAU_115_LAU_127_AIM_9L),
(Weapons.LAU_115_LAU_127_AIM_9X, Weapons.LAU_115_LAU_127_AIM_9M),
-
(Weapons.LAU_127_AIM_9L, None),
(Weapons.LAU_127_AIM_9M, Weapons.LAU_127_AIM_9L),
(Weapons.LAU_127_AIM_9X, Weapons.LAU_127_AIM_9M),
-
(Weapons.LAU_138_AIM_9L, None),
(Weapons.LAU_138_AIM_9M, Weapons.LAU_138_AIM_9L),
-
(Weapons.LAU_7_AIM_9L, None),
(Weapons.LAU_7_AIM_9M, Weapons.LAU_7_AIM_9L),
(Weapons.LAU_7_AIM_9M_Sidewinder_IR_AAM, Weapons.LAU_7_AIM_9P5_Sidewinder_IR_AAM),
(Weapons.LAU_7_AIM_9P5_Sidewinder_IR_AAM, Weapons.LAU_7_AIM_9P_Sidewinder_IR_AAM),
(Weapons.LAU_7_AIM_9P_Sidewinder_IR_AAM, Weapons.LAU_7_AIM_9L),
(Weapons.LAU_7_AIM_9X_Sidewinder_IR_AAM, Weapons.LAU_7_AIM_9M_Sidewinder_IR_AAM),
-
(Weapons.LAU_7___2_AIM_9L_Sidewinder_IR_AAM, None),
- (Weapons.LAU_7___2_AIM_9M_Sidewinder_IR_AAM, Weapons.LAU_7___2_AIM_9P5_Sidewinder_IR_AAM),
- (Weapons.LAU_7___2_AIM_9P5_Sidewinder_IR_AAM, Weapons.LAU_7___2_AIM_9P_Sidewinder_IR_AAM),
- (Weapons.LAU_7___2_AIM_9P_Sidewinder_IR_AAM, Weapons.LAU_7___2_AIM_9L_Sidewinder_IR_AAM),
-
+ (
+ Weapons.LAU_7___2_AIM_9M_Sidewinder_IR_AAM,
+ Weapons.LAU_7___2_AIM_9P5_Sidewinder_IR_AAM,
+ ),
+ (
+ Weapons.LAU_7___2_AIM_9P5_Sidewinder_IR_AAM,
+ Weapons.LAU_7___2_AIM_9P_Sidewinder_IR_AAM,
+ ),
+ (
+ Weapons.LAU_7___2_AIM_9P_Sidewinder_IR_AAM,
+ Weapons.LAU_7___2_AIM_9L_Sidewinder_IR_AAM,
+ ),
# ALQ ECM Pods
(Weapons.ALQ_131, None),
(Weapons.ALQ_184, Weapons.ALQ_131),
(Weapons.AN_ALQ_164_DECM_Pod, None),
-
# TGP Pods
(Weapons.AN_AAQ_28_LITENING_, None),
(Weapons.AN_AAQ_28_LITENING, Weapons.Lantirn_F_16),
@@ -300,17 +283,14 @@ _WEAPON_FALLBACKS = [
(Weapons.Lantirn_F_16, None),
(Weapons.Lantirn_Target_Pod, None),
(Weapons.Pavetack_F_111, None),
-
# BLU-107
(Weapons.BLU_107, None),
(Weapons.MER_6_BLU_107, Weapons.MER_6_Mk_82),
-
# GBU-10 LGB
(Weapons.DIS_GBU_10, Weapons.Mk_84),
(Weapons.GBU_10, Weapons.Mk_84),
(Weapons.GBU_10_, Weapons.Mk_84),
(Weapons.GBU_10_2, Weapons.Mk_84),
-
# GBU-12 LGB
(Weapons.AUF2_GBU_12_x_2, None),
(Weapons.BRU_33___2_x_GBU_12, Weapons.BRU_33___2_x_Mk_82_),
@@ -328,29 +308,23 @@ _WEAPON_FALLBACKS = [
(Weapons._2_GBU_12, Weapons._2_Mk_82),
(Weapons._2_GBU_12_, Weapons._2_Mk_82_),
(Weapons._3_GBU_12, Weapons._3_Mk_82_),
-
# GBU-15 LGB
(Weapons.GBU_15, Weapons.Mk_84),
-
# GBU-16 LGB
(Weapons.BRU_33___2_x_GBU_16, None),
- (Weapons.DIS_GBU_16, Weapons.Mk_83),
- (Weapons.GBU_16, Weapons.Mk_83),
- (Weapons.GBU_16_, Weapons.Mk_83_),
-
+ (Weapons.DIS_GBU_16, Weapons.Mk_83),
+ (Weapons.GBU_16, Weapons.Mk_83),
+ (Weapons.GBU_16_, Weapons.Mk_83_),
# GBU-24 LGB
(Weapons.GBU_24, Weapons.GBU_10),
(Weapons.GBU_24_, Weapons.GBU_10_),
(Weapons.GBU_24__, Weapons.GBU_10_),
-
# GBU-27 LGB
(Weapons.GBU_24, Weapons.GBU_10),
(Weapons.GBU_24_, Weapons.GBU_10_),
(Weapons.GBU_24__, Weapons.GBU_10_),
-
# GBU-28 LGB
(Weapons.GBU_28, Weapons.GBU_15),
-
# GBU-31 JDAM
(Weapons.GBU_31V3B_8, Weapons.B_1B_Mk_84_8),
(Weapons.GBU_31_8, Weapons.B_1B_Mk_84_8),
@@ -358,150 +332,127 @@ _WEAPON_FALLBACKS = [
(Weapons.GBU_31_V_2_B, Weapons.GBU_24_),
(Weapons.GBU_31_V_3_B, Weapons.GBU_24_),
(Weapons.GBU_31_V_4_B, Weapons.GBU_24_),
-
# GBU-32 JDAM
(Weapons.GBU_32_V_2_B, Weapons.GBU_16),
-
# GBU-32 JDAM
(Weapons.BRU_55___2_x_GBU_38, Weapons.BRU_33___2_x_Mk_82_),
- (Weapons.BRU_57___2_x_GBU_38, None), # Doesn't exist
+ (Weapons.BRU_57___2_x_GBU_38, None), # Doesn't exist
(Weapons.GBU_38, Weapons.Mk_82),
(Weapons.GBU_38_16, Weapons.MK_82_28),
(Weapons._2_GBU_38, Weapons._2_Mk_82),
(Weapons._2_GBU_38_, Weapons._2_Mk_82_),
(Weapons._3_GBU_38, Weapons._3_Mk_82_),
-
# GBU-54 LJDAM
(Weapons.GBU_54_V_1_B, Weapons.GBU_38),
(Weapons._2_GBU_54_V_1_B, Weapons._2_GBU_38),
(Weapons._2_GBU_54_V_1_B_, Weapons._2_GBU_38_),
(Weapons._3_GBU_54_V_1_B, Weapons._3_GBU_38),
-
# CBU-52
(Weapons.CBU_52B, None),
-
# CBU-87 CEM
(Weapons.CBU_87, Weapons.Mk_82),
(Weapons.TER_9A___2_x_CBU_87, Weapons.TER_9A___2_x_Mk_82),
(Weapons.TER_9A___2_x_CBU_87_, Weapons.TER_9A___2_x_Mk_82_),
(Weapons.TER_9A___3_x_CBU_87, Weapons.TER_9A___3_x_Mk_82),
-
# CBU-97
(Weapons.CBU_97, Weapons.Mk_82),
(Weapons.TER_9A___2_x_CBU_97, Weapons.TER_9A___2_x_Mk_82),
(Weapons.TER_9A___2_x_CBU_97_, Weapons.TER_9A___2_x_Mk_82_),
(Weapons.TER_9A___3_x_CBU_97, Weapons.TER_9A___3_x_Mk_82),
-
# CBU-99 (It's a bomb made in 1968, I'm not bothering right now with backups)
-
# CBU-103
- (Weapons.BRU_57___2_x_CBU_103, None), # doesn't exist...
+ (Weapons.BRU_57___2_x_CBU_103, None), # doesn't exist...
(Weapons.CBU_103, Weapons.CBU_87),
-
# CBU-105
- (Weapons.BRU_57___2_x_CBU_105, None), # doesn't exist...
+ (Weapons.BRU_57___2_x_CBU_105, None), # doesn't exist...
(Weapons.CBU_105, Weapons.CBU_97),
-
- (Weapons.LAU_131_pod___7_x_2_75__Hydra___Laser_Guided_Rkts_M151___HE_APKWS, Weapons.LAU_131___7_2_75__rockets_M151__HE_),
- (Weapons.LAU_131_pod___7_x_2_75__Hydra___Laser_Guided_Rkts_M282___MPP_APKWS, Weapons.LAU_131___7_2_75__rockets_M151__HE_),
- (Weapons._3_x_LAU_131_pods___21_x_2_75__Hydra___Laser_Guided_M151___HE_APKWS, Weapons.LAU_68_3___7_2_75__rockets_M151__HE_),
- (Weapons._3_x_LAU_131_pods___21_x_2_75__Hydra___Laser_Guided_M282___MPP_APKWS, Weapons.LAU_68_3___7_2_75__rockets_M151__HE_),
-
+ (
+ Weapons.LAU_131_pod___7_x_2_75__Hydra___Laser_Guided_Rkts_M151___HE_APKWS,
+ Weapons.LAU_131___7_2_75__rockets_M151__HE_,
+ ),
+ (
+ Weapons.LAU_131_pod___7_x_2_75__Hydra___Laser_Guided_Rkts_M282___MPP_APKWS,
+ Weapons.LAU_131___7_2_75__rockets_M151__HE_,
+ ),
+ (
+ Weapons._3_x_LAU_131_pods___21_x_2_75__Hydra___Laser_Guided_M151___HE_APKWS,
+ Weapons.LAU_68_3___7_2_75__rockets_M151__HE_,
+ ),
+ (
+ Weapons._3_x_LAU_131_pods___21_x_2_75__Hydra___Laser_Guided_M282___MPP_APKWS,
+ Weapons.LAU_68_3___7_2_75__rockets_M151__HE_,
+ ),
# Russia
# KAB-1500
(Weapons.KAB_1500Kr, None),
(Weapons.KAB_1500LG_Pr, Weapons.KAB_1500Kr),
(Weapons.KAB_1500L, Weapons.KAB_1500LG_Pr),
-
# KAB-500
(Weapons.KAB_500kr, Weapons.FAB_500_M62),
(Weapons.KAB_500L, Weapons.KAB_500kr),
(Weapons.KAB_500S, Weapons.KAB_500L),
-
# KH Series
(Weapons.Kh_22N, None),
(Weapons.Kh_23L, None),
-
(Weapons.Kh_25ML, None),
(Weapons.Kh_25ML_, None),
(Weapons.Kh_25ML__, None),
-
(Weapons.Kh_25MP, None),
(Weapons.Kh_25MPU, Weapons.Kh_25MP),
-
(Weapons.Kh_25MR, None),
(Weapons.Kh_25MR_, None),
-
(Weapons.Kh_28__AS_9_Kyle_, None),
-
(Weapons.Kh_29L, Weapons.Kh_25ML),
(Weapons.Kh_29L_, Weapons.Kh_25ML_),
(Weapons.Kh_29L__, Weapons.Kh_25ML__),
(Weapons.Kh_29T, Weapons.Kh_25MR),
(Weapons.Kh_29T_, Weapons.Kh_25MR_),
(Weapons.Kh_29T_, Weapons.Kh_25MR_),
-
(Weapons.Kh_31A, None),
(Weapons.Kh_31A_, None),
(Weapons.Kh_31A__, None),
(Weapons.Kh_31P, Weapons.Kh_25MP),
(Weapons.Kh_31P_, Weapons.Kh_25MP),
(Weapons.Kh_31P__, Weapons.Kh_25MP),
-
(Weapons.Kh_35, Weapons.Kh_31A),
(Weapons.Kh_35_, Weapons.Kh_31A_),
(Weapons.Kh_35_6, None),
-
(Weapons.Kh_41, None),
-
(Weapons.Kh_58U, Weapons.Kh_31P),
(Weapons.Kh_58U_, Weapons.Kh_31P_),
-
(Weapons.Kh_59M, Weapons.Kh_31A),
-
(Weapons.Kh_65, None),
(Weapons.Kh_65_6, None),
(Weapons.Kh_65_8, None),
-
(Weapons.Kh_66_Grom__21__APU_68, None),
-
# ECM
(Weapons.L175V_Khibiny_ECM_pod, None),
-
# R-13
(Weapons.R_13M, None),
(Weapons.R_13M1, Weapons.R_13M),
-
# R-24
(Weapons.R_24R, None),
(Weapons.R_24T, None),
-
# R-27
(Weapons.R_27T, Weapons.R_24T),
(Weapons.R_27R, Weapons.R_24R),
(Weapons.R_27ER, Weapons.R_27R),
(Weapons.R_27ET, Weapons.R_27T),
-
# R-33
(Weapons.R_33, None),
-
# R-3
(Weapons.R_3S, Weapons.R_13M),
(Weapons.R_3R, Weapons.R_3S),
-
# R-40
(Weapons.R_40R, None),
(Weapons.R_40T, None),
-
# R-55
(Weapons.R_55, None),
(Weapons.RS2US, None),
-
# R-60
(Weapons.R_60, Weapons.R_13M1),
(Weapons.R_60_x_2, Weapons.R_13M1),
(Weapons.R_60_x_2_, Weapons.R_13M1),
-
(Weapons.APU_60_1_R_60M, Weapons.R_3S),
(Weapons.R_60M, Weapons.R_60),
(Weapons.R_60M_, Weapons.R_60),
@@ -509,44 +460,39 @@ _WEAPON_FALLBACKS = [
(Weapons.R_60M_2_, Weapons.R_60M),
(Weapons.R_60M_x_2, Weapons.R_60M),
(Weapons.R_60M_x_2_, Weapons.R_60M),
-
# R-73
(Weapons.R_73, Weapons.R_60M),
(Weapons.R_73_, None),
-
# R-77
(Weapons.R_77, Weapons.R_27ER),
(Weapons.R_77_, None),
-
# UK
# ALARM
(Weapons.ALARM, None),
(Weapons.ALARM_2, None),
-
# France
# BLG-66 Belouga
(Weapons.AUF2_BLG_66_AC_x_2, Weapons.AUF2_MK_82_x_2),
(Weapons.BLG_66_AC_Belouga, Weapons.Mk_82),
(Weapons.BLG_66_AC_Belouga_, Weapons.Mk_82),
-
# HOT-3
(Weapons.HOT3, None),
(Weapons.HOT3_, None),
-
# Magic 2
(Weapons.Matra_Magic_II, None),
(Weapons.R_550_Magic_2, None),
-
# Super 530D
(Weapons.Matra_Super_530D, Weapons.Matra_Magic_II),
- (Weapons.Super_530D, None)
-
+ (Weapons.Super_530D, None),
]
WEAPON_FALLBACK_MAP: Dict[Weapon, Optional[Weapon]] = defaultdict(
lambda: cast(Optional[Weapon], None),
- ((Weapon.from_pydcs(a), b if b is None else Weapon.from_pydcs(b))
- for a, b in _WEAPON_FALLBACKS))
+ (
+ (Weapon.from_pydcs(a), b if b is None else Weapon.from_pydcs(b))
+ for a, b in _WEAPON_FALLBACKS
+ ),
+)
WEAPON_INTRODUCTION_YEARS = {
@@ -556,44 +502,34 @@ WEAPON_INTRODUCTION_YEARS = {
Weapon.from_pydcs(Weapons.ADM_141A_): 1987,
Weapon.from_pydcs(Weapons.ADM_141A__): 1987,
Weapon.from_pydcs(Weapons.ADM_141B): 1987,
-
# AGM-114K Hellfire
Weapon.from_pydcs(Weapons.AGM114x2_OH_58): 1993,
Weapon.from_pydcs(Weapons.AGM_114K): 1993,
Weapon.from_pydcs(Weapons.AGM_114K___4): 1993,
-
# AGM-119 Penguin
Weapon.from_pydcs(Weapons.AGM_119B_Penguin): 1972,
-
# AGM-122 Sidearm
Weapon.from_pydcs(Weapons.AGM_122): 1986,
Weapon.from_pydcs(Weapons.AGM_122_Sidearm): 1986,
Weapon.from_pydcs(Weapons.AGM_122_Sidearm_): 1986,
-
# AGM-154 JSOW
Weapon.from_pydcs(Weapons.AGM_154A): 1998,
Weapon.from_pydcs(Weapons.BRU_55___2_x_AGM_154A): 1998,
Weapon.from_pydcs(Weapons.BRU_57___2_x_AGM_154A): 1998,
-
Weapon.from_pydcs(Weapons.AGM_154B): 2005,
-
Weapon.from_pydcs(Weapons.AGM_154C): 2005,
Weapon.from_pydcs(Weapons.AGM_154C_4): 2005,
Weapon.from_pydcs(Weapons.BRU_55___2_x_AGM_154C): 2005,
-
# AGM-45 Shrike
Weapon.from_pydcs(Weapons.AGM_45A): 1965,
Weapon.from_pydcs(Weapons.AGM_45B): 1970,
Weapon.from_pydcs(Weapons.AGM_45B_): 1970,
-
# AGM-62 Walleye
Weapon.from_pydcs(Weapons.AGM_62): 1972,
-
# AGM-65 Maverick
Weapon.from_pydcs(Weapons.AGM_65D): 1983,
Weapon.from_pydcs(Weapons.AGM_65E): 1985,
Weapon.from_pydcs(Weapons.AGM_65K): 2007,
-
Weapon.from_pydcs(Weapons.LAU_117_AGM_65A): 1972,
Weapon.from_pydcs(Weapons.LAU_117_AGM_65B): 1972,
Weapon.from_pydcs(Weapons.LAU_117_AGM_65D): 1986,
@@ -603,25 +539,20 @@ WEAPON_INTRODUCTION_YEARS = {
Weapon.from_pydcs(Weapons.LAU_117_AGM_65H): 2002,
Weapon.from_pydcs(Weapons.LAU_117_AGM_65K): 2002,
Weapon.from_pydcs(Weapons.LAU_117_AGM_65L): 1985,
-
Weapon.from_pydcs(Weapons.LAU_88_AGM_65D_2): 1983,
Weapon.from_pydcs(Weapons.LAU_88_AGM_65D_2_): 1983,
Weapon.from_pydcs(Weapons.LAU_88_AGM_65D_3): 1983,
Weapon.from_pydcs(Weapons.LAU_88_AGM_65D_ONE): 1983,
-
Weapon.from_pydcs(Weapons.LAU_88_AGM_65E_2): 1985,
Weapon.from_pydcs(Weapons.LAU_88_AGM_65E_2_): 1985,
Weapon.from_pydcs(Weapons.LAU_88_AGM_65E_3): 1985,
-
Weapon.from_pydcs(Weapons.LAU_88_AGM_65H): 2007,
Weapon.from_pydcs(Weapons.LAU_88_AGM_65H_2_L): 2007,
Weapon.from_pydcs(Weapons.LAU_88_AGM_65H_2_R): 2007,
Weapon.from_pydcs(Weapons.LAU_88_AGM_65H_3): 2007,
-
Weapon.from_pydcs(Weapons.LAU_88_AGM_65K_2): 2007,
Weapon.from_pydcs(Weapons.LAU_88_AGM_65K_2_): 2007,
Weapon.from_pydcs(Weapons.LAU_88_AGM_65K_3): 2007,
-
# AGM-84 Harpoon
Weapon.from_pydcs(Weapons.AGM_84): 1979,
Weapon.from_pydcs(Weapons.AGM_84A): 1979,
@@ -630,41 +561,33 @@ WEAPON_INTRODUCTION_YEARS = {
Weapon.from_pydcs(Weapons.AGM_84E): 1990,
Weapon.from_pydcs(Weapons.AGM_84E_SLAM): 1990,
Weapon.from_pydcs(Weapons.AGM_84H): 1998,
-
# AGM-86 ALCM
Weapon.from_pydcs(Weapons.AGM_86C): 1986,
Weapon.from_pydcs(Weapons.AGM_86C_20): 1986,
Weapon.from_pydcs(Weapons.AGM_86C_8): 1986,
Weapon.from_pydcs(Weapons.MER_6_AGM_86C): 1986,
-
# AGM-88 HARM
Weapon.from_pydcs(Weapons.AGM_88C): 1983,
Weapon.from_pydcs(Weapons.AGM_88C_): 1983,
# for future reference: 1983 is the A model IOC. B model in 1986 and C model in 1994.
-
# AIM-120 AMRAAM
Weapon.from_pydcs(Weapons.AIM_120B): 1994,
Weapon.from_pydcs(Weapons.AIM_120C): 1996,
-
Weapon.from_pydcs(Weapons.LAU_115_2_LAU_127_AIM_120B): 1994,
Weapon.from_pydcs(Weapons.LAU_115___AIM_120B): 1994,
Weapon.from_pydcs(Weapons.LAU_115_2_LAU_127_AIM_120C): 1996,
Weapon.from_pydcs(Weapons.LAU_115___AIM_120C): 1996,
-
# AIM-54 Phoenix
Weapon.from_pydcs(Weapons.AIM_54A_Mk47): 1974,
Weapon.from_pydcs(Weapons.AIM_54A_Mk47_): 1974,
Weapon.from_pydcs(Weapons.AIM_54A_Mk47__): 1974,
-
Weapon.from_pydcs(Weapons.AIM_54A_Mk60): 1974,
Weapon.from_pydcs(Weapons.AIM_54A_Mk60_): 1974,
Weapon.from_pydcs(Weapons.AIM_54A_Mk60__): 1974,
-
Weapon.from_pydcs(Weapons.AIM_54C): 1974,
Weapon.from_pydcs(Weapons.AIM_54C_Mk47): 1974,
Weapon.from_pydcs(Weapons.AIM_54C_Mk47_): 1974,
Weapon.from_pydcs(Weapons.AIM_54C_Mk47__): 1974,
-
# AIM-7 Sparrow
Weapon.from_pydcs(Weapons.AIM_7E): 1963,
Weapon.from_pydcs(Weapons.AIM_7F): 1976,
@@ -676,62 +599,49 @@ WEAPON_INTRODUCTION_YEARS = {
Weapon.from_pydcs(Weapons.AIM_7MH): 1987,
Weapon.from_pydcs(Weapons.AIM_7MH_): 1987,
Weapon.from_pydcs(Weapons.AIM_7MH__): 1987,
-
Weapon.from_pydcs(Weapons.LAU_115C_AIM_7E): 1963,
Weapon.from_pydcs(Weapons.LAU_115C_AIM_7F): 1976,
Weapon.from_pydcs(Weapons.LAU_115___AIM_7M): 1982,
Weapon.from_pydcs(Weapons.LAU_115C_AIM_7MH): 1987,
-
# AIM-9 Sidewinder
Weapon.from_pydcs(Weapons.AIM_9L_Sidewinder_IR_AAM): 1977,
Weapon.from_pydcs(Weapons.AIM_9M_Sidewinder_IR_AAM): 1982,
Weapon.from_pydcs(Weapons.AIM_9P5_Sidewinder_IR_AAM): 1980,
Weapon.from_pydcs(Weapons.AIM_9P_Sidewinder_IR_AAM): 1978,
Weapon.from_pydcs(Weapons.AIM_9X_Sidewinder_IR_AAM): 2003,
-
Weapon.from_pydcs(Weapons.LAU_105_1_AIM_9L_L): 1977,
Weapon.from_pydcs(Weapons.LAU_105_1_AIM_9L_R): 1977,
Weapon.from_pydcs(Weapons.LAU_105_1_AIM_9M_L): 1982,
Weapon.from_pydcs(Weapons.LAU_105_1_AIM_9M_R): 1982,
-
Weapon.from_pydcs(Weapons.LAU_105_2_AIM_9L): 1977,
Weapon.from_pydcs(Weapons.LAU_105_2_AIM_9P5): 1980,
-
Weapon.from_pydcs(Weapons.LAU_105___2_AIM_9M_Sidewinder_IR_AAM): 1982,
Weapon.from_pydcs(Weapons.LAU_105___2_AIM_9P_Sidewinder_IR_AAM): 1978,
-
Weapon.from_pydcs(Weapons.LAU_115_2_LAU_127_AIM_9L): 1977,
Weapon.from_pydcs(Weapons.LAU_115_2_LAU_127_AIM_9M): 1982,
Weapon.from_pydcs(Weapons.LAU_115_2_LAU_127_AIM_9X): 2003,
-
Weapon.from_pydcs(Weapons.LAU_115_LAU_127_AIM_9L): 1977,
Weapon.from_pydcs(Weapons.LAU_115_LAU_127_AIM_9M): 1982,
Weapon.from_pydcs(Weapons.LAU_115_LAU_127_AIM_9X): 2003,
-
Weapon.from_pydcs(Weapons.LAU_127_AIM_9L): 1977,
Weapon.from_pydcs(Weapons.LAU_127_AIM_9M): 1982,
Weapon.from_pydcs(Weapons.LAU_127_AIM_9X): 2003,
-
Weapon.from_pydcs(Weapons.LAU_138_AIM_9L): 1977,
Weapon.from_pydcs(Weapons.LAU_138_AIM_9M): 1982,
-
Weapon.from_pydcs(Weapons.LAU_7_AIM_9L): 1977,
Weapon.from_pydcs(Weapons.LAU_7_AIM_9M): 1982,
Weapon.from_pydcs(Weapons.LAU_7_AIM_9M_Sidewinder_IR_AAM): 1982,
Weapon.from_pydcs(Weapons.LAU_7_AIM_9P5_Sidewinder_IR_AAM): 1980,
Weapon.from_pydcs(Weapons.LAU_7_AIM_9P_Sidewinder_IR_AAM): 1978,
Weapon.from_pydcs(Weapons.LAU_7_AIM_9X_Sidewinder_IR_AAM): 2003,
-
Weapon.from_pydcs(Weapons.LAU_7___2_AIM_9L_Sidewinder_IR_AAM): 1977,
Weapon.from_pydcs(Weapons.LAU_7___2_AIM_9M_Sidewinder_IR_AAM): 1982,
Weapon.from_pydcs(Weapons.LAU_7___2_AIM_9P5_Sidewinder_IR_AAM): 1980,
Weapon.from_pydcs(Weapons.LAU_7___2_AIM_9P_Sidewinder_IR_AAM): 1978,
-
# ALQ ECM Pods
Weapon.from_pydcs(Weapons.ALQ_131): 1970,
Weapon.from_pydcs(Weapons.ALQ_184): 1989,
Weapon.from_pydcs(Weapons.AN_ALQ_164_DECM_Pod): 1984,
-
# TGP Pods
Weapon.from_pydcs(Weapons.AN_AAQ_28_LITENING): 1995,
Weapon.from_pydcs(Weapons.AN_AAQ_28_LITENING_): 1995,
@@ -742,17 +652,14 @@ WEAPON_INTRODUCTION_YEARS = {
Weapon.from_pydcs(Weapons.Lantirn_F_16): 1985,
Weapon.from_pydcs(Weapons.Lantirn_Target_Pod): 1985,
Weapon.from_pydcs(Weapons.Pavetack_F_111): 1982,
-
# BLU-107
Weapon.from_pydcs(Weapons.BLU_107): 1983,
Weapon.from_pydcs(Weapons.MER_6_BLU_107): 1983,
-
# GBU-10 LGB
Weapon.from_pydcs(Weapons.DIS_GBU_10): 1976,
Weapon.from_pydcs(Weapons.GBU_10): 1976,
Weapon.from_pydcs(Weapons.GBU_10_): 1976,
Weapon.from_pydcs(Weapons.GBU_10_2): 1976,
-
# GBU-12 LGB
Weapon.from_pydcs(Weapons.AUF2_GBU_12_x_2): 1976,
Weapon.from_pydcs(Weapons.BRU_33___2_x_GBU_12): 1976,
@@ -770,10 +677,8 @@ WEAPON_INTRODUCTION_YEARS = {
Weapon.from_pydcs(Weapons._2_GBU_12): 1976,
Weapon.from_pydcs(Weapons._2_GBU_12_): 1976,
Weapon.from_pydcs(Weapons._3_GBU_12): 1976,
-
# GBU-15 LGB
Weapon.from_pydcs(Weapons.GBU_15): 1975,
-
# GBU-16 LGB
Weapon.from_pydcs(Weapons.BRU_33___2_x_GBU_16): 1976,
Weapon.from_pydcs(Weapons.DIS_GBU_16): 1976,
@@ -783,20 +688,16 @@ WEAPON_INTRODUCTION_YEARS = {
Weapon.from_pydcs(Weapons._2_GBU_16_): 1976,
Weapon.from_pydcs(Weapons._3_GBU_16): 1976,
Weapon.from_pydcs(Weapons._3_GBU_16_): 1976,
-
# GBU-24 LGB
Weapon.from_pydcs(Weapons.GBU_24): 1986,
Weapon.from_pydcs(Weapons.GBU_24_): 1986,
Weapon.from_pydcs(Weapons.GBU_24__): 1986,
-
# GBU-27 LGB
Weapon.from_pydcs(Weapons.GBU_27): 1991,
Weapon.from_pydcs(Weapons.GBU_27_2): 1991,
Weapon.from_pydcs(Weapons.GBU_27_4): 1991,
-
# GBU-28
Weapon.from_pydcs(Weapons.GBU_28): 1991,
-
# GBU-31 JDAM
Weapon.from_pydcs(Weapons.GBU_31V3B_8): 2001,
Weapon.from_pydcs(Weapons.GBU_31_8): 2001,
@@ -804,10 +705,8 @@ WEAPON_INTRODUCTION_YEARS = {
Weapon.from_pydcs(Weapons.GBU_31_V_2_B): 2001,
Weapon.from_pydcs(Weapons.GBU_31_V_3_B): 2001,
Weapon.from_pydcs(Weapons.GBU_31_V_4_B): 2001,
-
# GBU-32 JDAM
Weapon.from_pydcs(Weapons.GBU_32_V_2_B): 2002,
-
# GBU-38 JDAM
Weapon.from_pydcs(Weapons.BRU_55___2_x_GBU_38): 2005,
Weapon.from_pydcs(Weapons.BRU_57___2_x_GBU_38): 2005,
@@ -816,53 +715,40 @@ WEAPON_INTRODUCTION_YEARS = {
Weapon.from_pydcs(Weapons._2_GBU_38): 2005,
Weapon.from_pydcs(Weapons._2_GBU_38_): 2005,
Weapon.from_pydcs(Weapons._3_GBU_38): 2005,
-
# GBU-54 LJDAM
Weapon.from_pydcs(Weapons.GBU_54_V_1_B): 2008,
Weapon.from_pydcs(Weapons._2_GBU_54_V_1_B): 2008,
Weapon.from_pydcs(Weapons._2_GBU_54_V_1_B_): 2008,
Weapon.from_pydcs(Weapons._3_GBU_54_V_1_B): 2008,
-
# CBU-52
Weapon.from_pydcs(Weapons.CBU_52B): 1970,
-
# CBU-87 CEM
Weapon.from_pydcs(Weapons.CBU_87): 1986,
Weapon.from_pydcs(Weapons.TER_9A___2_x_CBU_87): 1986,
Weapon.from_pydcs(Weapons.TER_9A___2_x_CBU_87_): 1986,
Weapon.from_pydcs(Weapons.TER_9A___3_x_CBU_87): 1986,
-
# CBU-97
Weapon.from_pydcs(Weapons.CBU_97): 1992,
Weapon.from_pydcs(Weapons.TER_9A___2_x_CBU_97): 1992,
Weapon.from_pydcs(Weapons.TER_9A___2_x_CBU_97_): 1992,
Weapon.from_pydcs(Weapons.TER_9A___3_x_CBU_97): 1992,
-
# CBU-99
Weapon.from_pydcs(Weapons.BRU_33___2_x_CBU_99): 1968,
Weapon.from_pydcs(Weapons.CBU_99): 1968,
-
Weapon.from_pydcs(Weapons.BRU_33___2_x_Mk_20_Rockeye): 1968,
-
Weapon.from_pydcs(Weapons.DIS_MK_20): 1968,
Weapon.from_pydcs(Weapons.DIS_MK_20_DUAL_L): 1968,
Weapon.from_pydcs(Weapons.DIS_MK_20_DUAL_R): 1968,
-
Weapon.from_pydcs(Weapons.HSAB_9_Mk_20_Rockeye): 1968,
-
Weapon.from_pydcs(Weapons.MAK79_2_MK_20): 1968,
Weapon.from_pydcs(Weapons.MAK79_2_MK_20_): 1968,
-
Weapon.from_pydcs(Weapons.MAK79_MK_20): 1968,
Weapon.from_pydcs(Weapons.MAK79_MK_20_): 1968,
-
Weapon.from_pydcs(Weapons.MER_6_Mk_20_Rockeye): 1968,
-
Weapon.from_pydcs(Weapons.Mk_20): 1968,
Weapon.from_pydcs(Weapons.Mk_20_): 1968,
Weapon.from_pydcs(Weapons.Mk_20_18): 1968,
Weapon.from_pydcs(Weapons.Mk_20_Rockeye__6): 1968,
-
Weapon.from_pydcs(Weapons._2_MK_20): 1968,
Weapon.from_pydcs(Weapons._2_MK_20_): 1968,
Weapon.from_pydcs(Weapons._2_MK_20__): 1968,
@@ -872,123 +758,100 @@ WEAPON_INTRODUCTION_YEARS = {
Weapon.from_pydcs(Weapons._2_Mk_20_Rockeye): 1968,
Weapon.from_pydcs(Weapons._2_Mk_20_Rockeye_): 1968,
Weapon.from_pydcs(Weapons._2_Mk_20_Rockeye__): 1968,
-
Weapon.from_pydcs(Weapons._3_Mk_20_Rockeye): 1968,
Weapon.from_pydcs(Weapons._3_Mk_20_Rockeye_): 1968,
-
# CBU-103
Weapon.from_pydcs(Weapons.BRU_57___2_x_CBU_103): 2000,
Weapon.from_pydcs(Weapons.CBU_103): 2000,
-
# CBU-105
Weapon.from_pydcs(Weapons.BRU_57___2_x_CBU_105): 2000,
Weapon.from_pydcs(Weapons.CBU_105): 2000,
-
# APKWS
- Weapon.from_pydcs(Weapons.LAU_131_pod___7_x_2_75__Hydra___Laser_Guided_Rkts_M151___HE_APKWS): 2016,
- Weapon.from_pydcs(Weapons.LAU_131_pod___7_x_2_75__Hydra___Laser_Guided_Rkts_M282___MPP_APKWS): 2016,
- Weapon.from_pydcs(Weapons._3_x_LAU_131_pods___21_x_2_75__Hydra___Laser_Guided_M151___HE_APKWS): 2016,
- Weapon.from_pydcs(Weapons._3_x_LAU_131_pods___21_x_2_75__Hydra___Laser_Guided_M282___MPP_APKWS): 2016,
-
+ Weapon.from_pydcs(
+ Weapons.LAU_131_pod___7_x_2_75__Hydra___Laser_Guided_Rkts_M151___HE_APKWS
+ ): 2016,
+ Weapon.from_pydcs(
+ Weapons.LAU_131_pod___7_x_2_75__Hydra___Laser_Guided_Rkts_M282___MPP_APKWS
+ ): 2016,
+ Weapon.from_pydcs(
+ Weapons._3_x_LAU_131_pods___21_x_2_75__Hydra___Laser_Guided_M151___HE_APKWS
+ ): 2016,
+ Weapon.from_pydcs(
+ Weapons._3_x_LAU_131_pods___21_x_2_75__Hydra___Laser_Guided_M282___MPP_APKWS
+ ): 2016,
# Russia
-
# KAB-1500
Weapon.from_pydcs(Weapons.KAB_1500Kr): 1985,
Weapon.from_pydcs(Weapons.KAB_1500L): 1995,
Weapon.from_pydcs(Weapons.KAB_1500LG_Pr): 1990,
-
# KAB-500
Weapon.from_pydcs(Weapons.KAB_500kr): 1980,
Weapon.from_pydcs(Weapons.KAB_500L): 1995,
Weapon.from_pydcs(Weapons.KAB_500S): 2000,
-
# Kh Series
Weapon.from_pydcs(Weapons.Kh_22N): 1962,
Weapon.from_pydcs(Weapons.Kh_23L): 1975,
-
Weapon.from_pydcs(Weapons.Kh_25ML): 1975,
Weapon.from_pydcs(Weapons.Kh_25ML_): 1975,
Weapon.from_pydcs(Weapons.Kh_25ML__): 1975,
-
Weapon.from_pydcs(Weapons.Kh_25MP): 1975,
-
Weapon.from_pydcs(Weapons.Kh_25MPU): 1980,
Weapon.from_pydcs(Weapons.Kh_25MPU_): 1980,
Weapon.from_pydcs(Weapons.Kh_25MPU__): 1980,
-
Weapon.from_pydcs(Weapons.Kh_25MR): 1975,
Weapon.from_pydcs(Weapons.Kh_25MR_): 1975,
-
Weapon.from_pydcs(Weapons.Kh_28__AS_9_Kyle_): 1973,
-
Weapon.from_pydcs(Weapons.Kh_29L): 1980,
Weapon.from_pydcs(Weapons.Kh_29L_): 1980,
Weapon.from_pydcs(Weapons.Kh_29L__): 1980,
Weapon.from_pydcs(Weapons.Kh_29T): 1980,
Weapon.from_pydcs(Weapons.Kh_29T_): 1980,
Weapon.from_pydcs(Weapons.Kh_29T__): 1980,
-
Weapon.from_pydcs(Weapons.Kh_31A): 1980,
Weapon.from_pydcs(Weapons.Kh_31A_): 1980,
Weapon.from_pydcs(Weapons.Kh_31A__): 1980,
Weapon.from_pydcs(Weapons.Kh_31P): 1980,
Weapon.from_pydcs(Weapons.Kh_31P_): 1980,
Weapon.from_pydcs(Weapons.Kh_31P__): 1980,
-
Weapon.from_pydcs(Weapons.Kh_35): 2003,
Weapon.from_pydcs(Weapons.Kh_35_): 2003,
Weapon.from_pydcs(Weapons.Kh_35_6): 2003,
-
Weapon.from_pydcs(Weapons.Kh_41): 1984,
-
Weapon.from_pydcs(Weapons.Kh_58U): 1985,
Weapon.from_pydcs(Weapons.Kh_58U_): 1985,
-
Weapon.from_pydcs(Weapons.Kh_59M): 1990,
-
Weapon.from_pydcs(Weapons.Kh_65): 1992,
Weapon.from_pydcs(Weapons.Kh_65_6): 1992,
Weapon.from_pydcs(Weapons.Kh_65_8): 1992,
-
Weapon.from_pydcs(Weapons.Kh_66_Grom__21__APU_68): 1968,
-
# ECM
Weapon.from_pydcs(Weapons.L175V_Khibiny_ECM_pod): 1982,
-
# R-13
Weapon.from_pydcs(Weapons.R_13M): 1961,
Weapon.from_pydcs(Weapons.R_13M1): 1965,
-
# R-24
Weapon.from_pydcs(Weapons.R_24R): 1981,
Weapon.from_pydcs(Weapons.R_24T): 1981,
-
# R-27
Weapon.from_pydcs(Weapons.R_27ER): 1983,
Weapon.from_pydcs(Weapons.R_27ET): 1986,
Weapon.from_pydcs(Weapons.R_27R): 1983,
Weapon.from_pydcs(Weapons.R_27T): 1983,
-
# R-33
Weapon.from_pydcs(Weapons.R_33): 1981,
-
# R-3
Weapon.from_pydcs(Weapons.R_3R): 1966,
Weapon.from_pydcs(Weapons.R_3S): 1962,
-
# R-40
Weapon.from_pydcs(Weapons.R_40R): 1976,
Weapon.from_pydcs(Weapons.R_40T): 1976,
-
# R-55
Weapon.from_pydcs(Weapons.R_55): 1957,
Weapon.from_pydcs(Weapons.RS2US): 1957,
-
# R-60
Weapon.from_pydcs(Weapons.R_60): 1973,
Weapon.from_pydcs(Weapons.R_60_x_2): 1973,
Weapon.from_pydcs(Weapons.R_60_x_2_): 1973,
-
Weapon.from_pydcs(Weapons.APU_60_1_R_60M): 1982,
Weapon.from_pydcs(Weapons.R_60M): 1982,
Weapon.from_pydcs(Weapons.R_60M_): 1982,
@@ -996,36 +859,28 @@ WEAPON_INTRODUCTION_YEARS = {
Weapon.from_pydcs(Weapons.R_60M_2_): 1982,
Weapon.from_pydcs(Weapons.R_60M_x_2): 1982,
Weapon.from_pydcs(Weapons.R_60M_x_2_): 1982,
-
# R-73
Weapon.from_pydcs(Weapons.R_73): 1984,
Weapon.from_pydcs(Weapons.R_73_): 1984,
-
# R-77
Weapon.from_pydcs(Weapons.R_77): 2002,
Weapon.from_pydcs(Weapons.R_77_): 2002,
-
# UK
# ALARM
Weapon.from_pydcs(Weapons.ALARM): 1990,
Weapon.from_pydcs(Weapons.ALARM_2): 1990,
-
# France
# BLG-66 Belouga
Weapon.from_pydcs(Weapons.AUF2_BLG_66_AC_x_2): 1979,
Weapon.from_pydcs(Weapons.BLG_66_AC_Belouga): 1979,
Weapon.from_pydcs(Weapons.BLG_66_AC_Belouga_): 1979,
-
# HOT-3
Weapon.from_pydcs(Weapons.HOT3): 1998,
Weapon.from_pydcs(Weapons.HOT3_): 1998,
-
# Magic 2
Weapon.from_pydcs(Weapons.Matra_Magic_II): 1986,
Weapon.from_pydcs(Weapons.R_550_Magic_2): 1986,
-
# Super 530D
Weapon.from_pydcs(Weapons.Matra_Super_530D): 1988,
Weapon.from_pydcs(Weapons.Super_530D): 1988,
-
}
diff --git a/game/db.py b/game/db.py
index 0314d0cb..04a092b2 100644
--- a/game/db.py
+++ b/game/db.py
@@ -25,6 +25,7 @@ from dcs.helicopters import (
helicopter_map,
)
from dcs.mapping import Point
+
# mypy can't resolve these if they're wildcard imports for some reason.
from dcs.planes import (
AJS37,
@@ -112,7 +113,7 @@ from dcs.planes import (
WingLoong_I,
Yak_40,
plane_map,
- I_16
+ I_16,
)
from dcs.ships import (
Armed_speedboat,
@@ -166,6 +167,7 @@ from dcs.vehicles import (
import pydcs_extensions.frenchpack.frenchpack as frenchpack
import pydcs_extensions.highdigitsams.highdigitsams as highdigitsams
+
# PATCH pydcs data with MODS
from game.factions.faction_loader import FactionLoader
from pydcs_extensions.a4ec.a4ec import A_4E_C
@@ -222,46 +224,122 @@ vehicle_map["Kamikaze"] = frenchpack.DIM__KAMIKAZE
vehicle_map[highdigitsams.AAA_SON_9_Fire_Can.id] = highdigitsams.AAA_SON_9_Fire_Can
vehicle_map[highdigitsams.AAA_100mm_KS_19.id] = highdigitsams.AAA_100mm_KS_19
-vehicle_map[highdigitsams.SAM_SA_10B_S_300PS_54K6_CP.id] = highdigitsams.SAM_SA_10B_S_300PS_54K6_CP
-vehicle_map[highdigitsams.SAM_SA_10B_S_300PS_5P85SE_LN.id] = highdigitsams.SAM_SA_10B_S_300PS_5P85SE_LN
-vehicle_map[highdigitsams.SAM_SA_10B_S_300PS_5P85SU_LN.id] = highdigitsams.SAM_SA_10B_S_300PS_5P85SU_LN
-vehicle_map[highdigitsams.SAM_SA_10__5V55RUD__S_300PS_LN_5P85CE.id] = highdigitsams.SAM_SA_10__5V55RUD__S_300PS_LN_5P85CE
-vehicle_map[highdigitsams.SAM_SA_10__5V55RUD__S_300PS_LN_5P85DE.id] = highdigitsams.SAM_SA_10__5V55RUD__S_300PS_LN_5P85DE
-vehicle_map[highdigitsams.SAM_SA_10B_S_300PS_30N6_TR.id] = highdigitsams.SAM_SA_10B_S_300PS_30N6_TR
-vehicle_map[highdigitsams.SAM_SA_10B_S_300PS_40B6M_TR.id] = highdigitsams.SAM_SA_10B_S_300PS_40B6M_TR
-vehicle_map[highdigitsams.SAM_SA_10B_S_300PS_40B6MD_SR.id] = highdigitsams.SAM_SA_10B_S_300PS_40B6MD_SR
-vehicle_map[highdigitsams.SAM_SA_10B_S_300PS_64H6E_SR.id] = highdigitsams.SAM_SA_10B_S_300PS_64H6E_SR
-vehicle_map[highdigitsams.SAM_SA_20_S_300PMU1_CP_54K6.id] = highdigitsams.SAM_SA_20_S_300PMU1_CP_54K6
-vehicle_map[highdigitsams.SAM_SA_20_S_300PMU1_TR_30N6E.id] = highdigitsams.SAM_SA_20_S_300PMU1_TR_30N6E
-vehicle_map[highdigitsams.SAM_SA_20_S_300PMU1_TR_30N6E_truck.id] = highdigitsams.SAM_SA_20_S_300PMU1_TR_30N6E_truck
-vehicle_map[highdigitsams.SAM_SA_20_S_300PMU1_SR_5N66E.id] = highdigitsams.SAM_SA_20_S_300PMU1_SR_5N66E
-vehicle_map[highdigitsams.SAM_SA_20_S_300PMU1_SR_64N6E.id] = highdigitsams.SAM_SA_20_S_300PMU1_SR_64N6E
-vehicle_map[highdigitsams.SAM_SA_20_S_300PMU1_LN_5P85CE.id] = highdigitsams.SAM_SA_20_S_300PMU1_LN_5P85CE
-vehicle_map[highdigitsams.SAM_SA_20_S_300PMU1_LN_5P85DE.id] = highdigitsams.SAM_SA_20_S_300PMU1_LN_5P85DE
-vehicle_map[highdigitsams.SAM_SA_20B_S_300PMU2_CP_54K6E2.id] = highdigitsams.SAM_SA_20B_S_300PMU2_CP_54K6E2
-vehicle_map[highdigitsams.SAM_SA_20B_S_300PMU2_TR_92H6E_truck.id] = highdigitsams.SAM_SA_20B_S_300PMU2_TR_92H6E_truck
-vehicle_map[highdigitsams.SAM_SA_20B_S_300PMU2_SR_64N6E2.id] = highdigitsams.SAM_SA_20B_S_300PMU2_SR_64N6E2
-vehicle_map[highdigitsams.SAM_SA_20B_S_300PMU2_LN_5P85SE2.id] = highdigitsams.SAM_SA_20B_S_300PMU2_LN_5P85SE2
-vehicle_map[highdigitsams.SAM_SA_12_S_300V_9S457_CP.id] = highdigitsams.SAM_SA_12_S_300V_9S457_CP
-vehicle_map[highdigitsams.SAM_SA_12_S_300V_9A82_LN.id] = highdigitsams.SAM_SA_12_S_300V_9A82_LN
-vehicle_map[highdigitsams.SAM_SA_12_S_300V_9A83_LN.id] = highdigitsams.SAM_SA_12_S_300V_9A83_LN
-vehicle_map[highdigitsams.SAM_SA_12_S_300V_9S15_SR.id] = highdigitsams.SAM_SA_12_S_300V_9S15_SR
-vehicle_map[highdigitsams.SAM_SA_12_S_300V_9S19_SR.id] = highdigitsams.SAM_SA_12_S_300V_9S19_SR
-vehicle_map[highdigitsams.SAM_SA_12_S_300V_9S32_TR.id] = highdigitsams.SAM_SA_12_S_300V_9S32_TR
-vehicle_map[highdigitsams.SAM_SA_23_S_300VM_9S457ME_CP.id] = highdigitsams.SAM_SA_23_S_300VM_9S457ME_CP
-vehicle_map[highdigitsams.SAM_SA_23_S_300VM_9S15M2_SR.id] = highdigitsams.SAM_SA_23_S_300VM_9S15M2_SR
-vehicle_map[highdigitsams.SAM_SA_23_S_300VM_9S19M2_SR.id] = highdigitsams.SAM_SA_23_S_300VM_9S19M2_SR
-vehicle_map[highdigitsams.SAM_SA_23_S_300VM_9S32ME_TR.id] = highdigitsams.SAM_SA_23_S_300VM_9S32ME_TR
-vehicle_map[highdigitsams.SAM_SA_23_S_300VM_9A83ME_LN.id] = highdigitsams.SAM_SA_23_S_300VM_9A83ME_LN
-vehicle_map[highdigitsams.SAM_SA_23_S_300VM_9A82ME_LN.id] = highdigitsams.SAM_SA_23_S_300VM_9A82ME_LN
-vehicle_map[highdigitsams.SAM_SA_17_Buk_M1_2_LN_9A310M1_2.id] = highdigitsams.SAM_SA_17_Buk_M1_2_LN_9A310M1_2
-vehicle_map[highdigitsams.SAM_SA_2__V759__LN_SM_90.id] = highdigitsams.SAM_SA_2__V759__LN_SM_90
+vehicle_map[
+ highdigitsams.SAM_SA_10B_S_300PS_54K6_CP.id
+] = highdigitsams.SAM_SA_10B_S_300PS_54K6_CP
+vehicle_map[
+ highdigitsams.SAM_SA_10B_S_300PS_5P85SE_LN.id
+] = highdigitsams.SAM_SA_10B_S_300PS_5P85SE_LN
+vehicle_map[
+ highdigitsams.SAM_SA_10B_S_300PS_5P85SU_LN.id
+] = highdigitsams.SAM_SA_10B_S_300PS_5P85SU_LN
+vehicle_map[
+ highdigitsams.SAM_SA_10__5V55RUD__S_300PS_LN_5P85CE.id
+] = highdigitsams.SAM_SA_10__5V55RUD__S_300PS_LN_5P85CE
+vehicle_map[
+ highdigitsams.SAM_SA_10__5V55RUD__S_300PS_LN_5P85DE.id
+] = highdigitsams.SAM_SA_10__5V55RUD__S_300PS_LN_5P85DE
+vehicle_map[
+ highdigitsams.SAM_SA_10B_S_300PS_30N6_TR.id
+] = highdigitsams.SAM_SA_10B_S_300PS_30N6_TR
+vehicle_map[
+ highdigitsams.SAM_SA_10B_S_300PS_40B6M_TR.id
+] = highdigitsams.SAM_SA_10B_S_300PS_40B6M_TR
+vehicle_map[
+ highdigitsams.SAM_SA_10B_S_300PS_40B6MD_SR.id
+] = highdigitsams.SAM_SA_10B_S_300PS_40B6MD_SR
+vehicle_map[
+ highdigitsams.SAM_SA_10B_S_300PS_64H6E_SR.id
+] = highdigitsams.SAM_SA_10B_S_300PS_64H6E_SR
+vehicle_map[
+ highdigitsams.SAM_SA_20_S_300PMU1_CP_54K6.id
+] = highdigitsams.SAM_SA_20_S_300PMU1_CP_54K6
+vehicle_map[
+ highdigitsams.SAM_SA_20_S_300PMU1_TR_30N6E.id
+] = highdigitsams.SAM_SA_20_S_300PMU1_TR_30N6E
+vehicle_map[
+ highdigitsams.SAM_SA_20_S_300PMU1_TR_30N6E_truck.id
+] = highdigitsams.SAM_SA_20_S_300PMU1_TR_30N6E_truck
+vehicle_map[
+ highdigitsams.SAM_SA_20_S_300PMU1_SR_5N66E.id
+] = highdigitsams.SAM_SA_20_S_300PMU1_SR_5N66E
+vehicle_map[
+ highdigitsams.SAM_SA_20_S_300PMU1_SR_64N6E.id
+] = highdigitsams.SAM_SA_20_S_300PMU1_SR_64N6E
+vehicle_map[
+ highdigitsams.SAM_SA_20_S_300PMU1_LN_5P85CE.id
+] = highdigitsams.SAM_SA_20_S_300PMU1_LN_5P85CE
+vehicle_map[
+ highdigitsams.SAM_SA_20_S_300PMU1_LN_5P85DE.id
+] = highdigitsams.SAM_SA_20_S_300PMU1_LN_5P85DE
+vehicle_map[
+ highdigitsams.SAM_SA_20B_S_300PMU2_CP_54K6E2.id
+] = highdigitsams.SAM_SA_20B_S_300PMU2_CP_54K6E2
+vehicle_map[
+ highdigitsams.SAM_SA_20B_S_300PMU2_TR_92H6E_truck.id
+] = highdigitsams.SAM_SA_20B_S_300PMU2_TR_92H6E_truck
+vehicle_map[
+ highdigitsams.SAM_SA_20B_S_300PMU2_SR_64N6E2.id
+] = highdigitsams.SAM_SA_20B_S_300PMU2_SR_64N6E2
+vehicle_map[
+ highdigitsams.SAM_SA_20B_S_300PMU2_LN_5P85SE2.id
+] = highdigitsams.SAM_SA_20B_S_300PMU2_LN_5P85SE2
+vehicle_map[
+ highdigitsams.SAM_SA_12_S_300V_9S457_CP.id
+] = highdigitsams.SAM_SA_12_S_300V_9S457_CP
+vehicle_map[
+ highdigitsams.SAM_SA_12_S_300V_9A82_LN.id
+] = highdigitsams.SAM_SA_12_S_300V_9A82_LN
+vehicle_map[
+ highdigitsams.SAM_SA_12_S_300V_9A83_LN.id
+] = highdigitsams.SAM_SA_12_S_300V_9A83_LN
+vehicle_map[
+ highdigitsams.SAM_SA_12_S_300V_9S15_SR.id
+] = highdigitsams.SAM_SA_12_S_300V_9S15_SR
+vehicle_map[
+ highdigitsams.SAM_SA_12_S_300V_9S19_SR.id
+] = highdigitsams.SAM_SA_12_S_300V_9S19_SR
+vehicle_map[
+ highdigitsams.SAM_SA_12_S_300V_9S32_TR.id
+] = highdigitsams.SAM_SA_12_S_300V_9S32_TR
+vehicle_map[
+ highdigitsams.SAM_SA_23_S_300VM_9S457ME_CP.id
+] = highdigitsams.SAM_SA_23_S_300VM_9S457ME_CP
+vehicle_map[
+ highdigitsams.SAM_SA_23_S_300VM_9S15M2_SR.id
+] = highdigitsams.SAM_SA_23_S_300VM_9S15M2_SR
+vehicle_map[
+ highdigitsams.SAM_SA_23_S_300VM_9S19M2_SR.id
+] = highdigitsams.SAM_SA_23_S_300VM_9S19M2_SR
+vehicle_map[
+ highdigitsams.SAM_SA_23_S_300VM_9S32ME_TR.id
+] = highdigitsams.SAM_SA_23_S_300VM_9S32ME_TR
+vehicle_map[
+ highdigitsams.SAM_SA_23_S_300VM_9A83ME_LN.id
+] = highdigitsams.SAM_SA_23_S_300VM_9A83ME_LN
+vehicle_map[
+ highdigitsams.SAM_SA_23_S_300VM_9A82ME_LN.id
+] = highdigitsams.SAM_SA_23_S_300VM_9A82ME_LN
+vehicle_map[
+ highdigitsams.SAM_SA_17_Buk_M1_2_LN_9A310M1_2.id
+] = highdigitsams.SAM_SA_17_Buk_M1_2_LN_9A310M1_2
+vehicle_map[
+ highdigitsams.SAM_SA_2__V759__LN_SM_90.id
+] = highdigitsams.SAM_SA_2__V759__LN_SM_90
vehicle_map[highdigitsams.SAM_HQ_2_LN_SM_90.id] = highdigitsams.SAM_HQ_2_LN_SM_90
-vehicle_map[highdigitsams.SAM_SA_3__V_601P__LN_5P73.id] = highdigitsams.SAM_SA_3__V_601P__LN_5P73
-vehicle_map[highdigitsams.SAM_SA_24_Igla_S_manpad.id] = highdigitsams.SAM_SA_24_Igla_S_manpad
-vehicle_map[highdigitsams.SAM_SA_14_Strela_3_manpad.id] = highdigitsams.SAM_SA_14_Strela_3_manpad
+vehicle_map[
+ highdigitsams.SAM_SA_3__V_601P__LN_5P73.id
+] = highdigitsams.SAM_SA_3__V_601P__LN_5P73
+vehicle_map[
+ highdigitsams.SAM_SA_24_Igla_S_manpad.id
+] = highdigitsams.SAM_SA_24_Igla_S_manpad
+vehicle_map[
+ highdigitsams.SAM_SA_14_Strela_3_manpad.id
+] = highdigitsams.SAM_SA_14_Strela_3_manpad
vehicle_map[highdigitsams.Polyana_D4M1_C2_node.id] = highdigitsams.Polyana_D4M1_C2_node
-vehicle_map[highdigitsams._34Ya6E_Gazetchik_E_decoy.id] = highdigitsams._34Ya6E_Gazetchik_E_decoy
+vehicle_map[
+ highdigitsams._34Ya6E_Gazetchik_E_decoy.id
+] = highdigitsams._34Ya6E_Gazetchik_E_decoy
"""
---------- BEGINNING OF CONFIGURATION SECTION
@@ -308,7 +386,6 @@ PRICES = {
JF_17: 20,
Su_30: 24,
Su_57: 40,
-
SpitfireLFMkIX: 14,
SpitfireLFMkIXCW: 14,
I_16: 10,
@@ -317,7 +394,6 @@ PRICES = {
FW_190A8: 14,
A_20G: 22,
Ju_88A4: 24,
-
F_5E_3: 8,
MiG_15bis: 4,
MiG_19P: 6,
@@ -328,7 +404,6 @@ PRICES = {
C_101CC: 6,
A_4E_C: 8,
MB_339PAN: 6,
-
AV8BNA: 14,
M_2000C: 16,
Mirage_2000_5: 20,
@@ -342,7 +417,6 @@ PRICES = {
F_22A: 40,
Tornado_IDS: 20,
Tornado_GR4: 20,
-
# bomber
Su_17M4: 10,
Su_25: 15,
@@ -352,12 +426,10 @@ PRICES = {
Su_24M: 20,
Su_24MR: 24,
MiG_27K: 20,
-
A_10A: 16,
A_10C: 22,
A_10C_2: 24,
S_3B: 10,
-
# heli
Ka_50: 13,
SA342M: 8,
@@ -373,7 +445,6 @@ PRICES = {
AH_64D: 30,
OH_58D: 6,
SH_60B: 6,
-
# Bombers
B_52H: 35,
B_1B: 50,
@@ -382,7 +453,6 @@ PRICES = {
Tu_22M3: 40,
Tu_95MS: 35,
F_111F: 21,
-
# special
IL_76MD: 30,
An_26B: 25,
@@ -393,14 +463,12 @@ PRICES = {
KC_135: 25,
KC130: 25,
KC135MPRS: 25,
-
A_50: 50,
KJ_2000: 50,
E_3A: 50,
E_2C: 50,
C_130: 25,
Hercules: 25,
-
# WW2
P_51D_30_NA: 18,
P_51D: 16,
@@ -408,17 +476,14 @@ PRICES = {
P_47D_30bl1: 16,
P_47D_40: 18,
B_17G: 30,
-
# Drones
MQ_9_Reaper: 12,
RQ_1A_Predator: 6,
WingLoong_I: 6,
-
# Modded
Rafale_M: 26,
Rafale_A_S: 26,
Rafale_B: 26,
-
# armor
Armor.APC_MTLB: 4,
Armor.FDDM_Grad: 4,
@@ -437,7 +502,6 @@ PRICES = {
Armor.IFV_BMP_3: 18,
Armor.ZBD_04A: 12,
Armor.ZTZ_96B: 30,
-
Armor.APC_Cobra: 4,
Armor.APC_M113: 6,
Armor.APC_M1043_HMMWV_Armament: 2,
@@ -457,10 +521,8 @@ PRICES = {
Armor.IFV_Marder: 10,
Armor.IFV_MCV_80: 10,
Armor.IFV_LAV_25: 7,
-
Artillery.MLRS_M270: 55,
Artillery.SPH_M109_Paladin: 25,
-
Artillery.SPH_2S9_Nona: 12,
Artillery.SPH_2S1_Gvozdika: 18,
Artillery.SPH_2S3_Akatsia: 24,
@@ -470,14 +532,11 @@ PRICES = {
Artillery.MLRS_9A52_Smerch: 40,
Artillery._2B11_mortar: 4,
Artillery.SpGH_Dana: 26,
-
Unarmed.Transport_UAZ_469: 3,
Unarmed.Transport_Ural_375: 3,
Infantry.Infantry_M4: 1,
Infantry.Soldier_AK: 1,
-
Unarmed.Transport_M818: 3,
-
# WW2
Armor.MT_Pz_Kpfw_V_Panther_Ausf_G: 24,
Armor.MT_Pz_Kpfw_IV_Ausf_H: 16,
@@ -504,22 +563,18 @@ PRICES = {
Armor.Daimler_Armoured_Car: 8,
Armor.LT_Mk_VII_Tetrarch: 8,
Armor.M4_Tractor: 2,
-
# ship
CV_1143_5_Admiral_Kuznetsov: 100,
CVN_74_John_C__Stennis: 100,
LHA_1_Tarawa: 50,
-
Bulk_cargo_ship_Yakushev: 10,
Armed_speedboat: 10,
Dry_cargo_ship_Ivanov: 10,
Tanker_Elnya_160: 10,
-
# Air Defence units
AirDefence.SAM_SA_19_Tunguska_2S6: 30,
AirDefence.SAM_SA_6_Kub_LN_2P25: 20,
AirDefence.SAM_SA_3_S_125_LN_5P73: 6,
-
AirDefence.SAM_SA_11_Buk_LN_9A310M1: 30,
AirDefence.SAM_SA_11_Buk_CC_9S470M1: 25,
AirDefence.SAM_SA_11_Buk_SR_9S18M1: 28,
@@ -558,7 +613,6 @@ PRICES = {
AirDefence.SAM_SA_18_Igla_S_comm: 8,
AirDefence.EWR_1L13: 30,
AirDefence.SAM_SA_6_Kub_STR_9S91: 22,
-
AirDefence.EWR_55G6: 30,
AirDefence.CP_9S80M1_Sborka: 10,
AirDefence.SAM_Hawk_TR_AN_MPQ_46: 14,
@@ -589,7 +643,6 @@ PRICES = {
AirDefence.AAA_M1_37mm: 7,
AirDefence.AAA_M45_Quadmount: 4,
AirDefence.AA_gun_QF_3_7: 10,
-
# FRENCH PACK MOD
frenchpack.AMX_10RCR: 10,
frenchpack.AMX_10RCR_SEPAR: 12,
@@ -619,7 +672,6 @@ PRICES = {
frenchpack.DIM__TOYOTA_GREEN: 2,
frenchpack.DIM__TOYOTA_DESERT: 2,
frenchpack.DIM__KAMIKAZE: 6,
-
# SA-10
AirDefence.SAM_SA_10_S_300PS_CP_54K6: 18,
AirDefence.SAM_SA_10_S_300PS_TR_30N6: 24,
@@ -627,11 +679,9 @@ PRICES = {
AirDefence.SAM_SA_10_S_300PS_SR_64H6E: 30,
AirDefence.SAM_SA_10_S_300PS_LN_5P85C: 22,
AirDefence.SAM_SA_10_S_300PS_LN_5P85D: 22,
-
# High digit sams mod
highdigitsams.AAA_SON_9_Fire_Can: 8,
highdigitsams.AAA_100mm_KS_19: 10,
-
highdigitsams.SAM_SA_10B_S_300PS_54K6_CP: 20,
highdigitsams.SAM_SA_10B_S_300PS_5P85SE_LN: 24,
highdigitsams.SAM_SA_10B_S_300PS_5P85SU_LN: 24,
@@ -641,14 +691,12 @@ PRICES = {
highdigitsams.SAM_SA_10B_S_300PS_40B6M_TR: 26,
highdigitsams.SAM_SA_10B_S_300PS_40B6MD_SR: 32,
highdigitsams.SAM_SA_10B_S_300PS_64H6E_SR: 32,
-
highdigitsams.SAM_SA_12_S_300V_9S457_CP: 22,
highdigitsams.SAM_SA_12_S_300V_9A82_LN: 26,
highdigitsams.SAM_SA_12_S_300V_9A83_LN: 26,
highdigitsams.SAM_SA_12_S_300V_9S15_SR: 34,
highdigitsams.SAM_SA_12_S_300V_9S19_SR: 34,
highdigitsams.SAM_SA_12_S_300V_9S32_TR: 28,
-
highdigitsams.SAM_SA_20_S_300PMU1_CP_54K6: 26,
highdigitsams.SAM_SA_20_S_300PMU1_TR_30N6E: 30,
highdigitsams.SAM_SA_20_S_300PMU1_TR_30N6E_truck: 32,
@@ -656,21 +704,17 @@ PRICES = {
highdigitsams.SAM_SA_20_S_300PMU1_SR_64N6E: 38,
highdigitsams.SAM_SA_20_S_300PMU1_LN_5P85CE: 28,
highdigitsams.SAM_SA_20_S_300PMU1_LN_5P85DE: 28,
-
highdigitsams.SAM_SA_20B_S_300PMU2_CP_54K6E2: 27,
highdigitsams.SAM_SA_20B_S_300PMU2_TR_92H6E_truck: 33,
highdigitsams.SAM_SA_20B_S_300PMU2_SR_64N6E2: 40,
highdigitsams.SAM_SA_20B_S_300PMU2_LN_5P85SE2: 30,
-
highdigitsams.SAM_SA_23_S_300VM_9S457ME_CP: 30,
highdigitsams.SAM_SA_23_S_300VM_9S15M2_SR: 45,
highdigitsams.SAM_SA_23_S_300VM_9S19M2_SR: 45,
highdigitsams.SAM_SA_23_S_300VM_9S32ME_TR: 35,
highdigitsams.SAM_SA_23_S_300VM_9A83ME_LN: 32,
highdigitsams.SAM_SA_23_S_300VM_9A82ME_LN: 32,
-
highdigitsams.SAM_SA_17_Buk_M1_2_LN_9A310M1_2: 40,
-
}
"""
@@ -728,7 +772,7 @@ UNIT_BY_TASK = {
SpitfireLFMkIX,
A_4E_C,
Rafale_M,
- SA342Mistral
+ SA342Mistral,
],
CAS: [
AH_1W,
@@ -779,18 +823,12 @@ UNIT_BY_TASK = {
Tu_160,
Tu_22M3,
Tu_95MS,
- UH_1H,
+ UH_1H,
SH_60B,
WingLoong_I,
- Hercules
- ],
- Transport: [
- IL_76MD,
- An_26B,
- An_30M,
- Yak_40,
- C_130
+ Hercules,
],
+ Transport: [IL_76MD, An_26B, An_30M, Yak_40, C_130],
Refueling: [
IL_78M,
KC_135,
@@ -798,12 +836,7 @@ UNIT_BY_TASK = {
S_3B_Tanker,
KC135MPRS,
],
- AWACS: [
- E_3A,
- E_2C,
- A_50,
- KJ_2000
- ],
+ AWACS: [E_3A, E_2C, A_50, KJ_2000],
PinpointStrike: [
Armor.APC_MTLB,
Armor.APC_MTLB,
@@ -851,7 +884,6 @@ UNIT_BY_TASK = {
Armor.MBT_T_80U,
Armor.MBT_T_90,
Armor.ZTZ_96B,
-
Armor.APC_Cobra,
Armor.APC_Cobra,
Armor.APC_Cobra,
@@ -895,7 +927,6 @@ UNIT_BY_TASK = {
Armor.MBT_Leopard_2,
Armor.MBT_Challenger_II,
Armor.MBT_Merkava_Mk__4,
-
Armor.MT_Pz_Kpfw_V_Panther_Ausf_G,
Armor.MT_Pz_Kpfw_IV_Ausf_H,
Armor.HT_Pz_Kpfw_VI_Tiger_I,
@@ -945,7 +976,6 @@ UNIT_BY_TASK = {
Artillery.Sturmpanzer_IV_Brummbär,
Armor.Daimler_Armoured_Car,
Armor.LT_Mk_VII_Tetrarch,
-
Artillery.MLRS_M270,
Artillery.SPH_M109_Paladin,
Artillery.SPH_2S9_Nona,
@@ -959,7 +989,6 @@ UNIT_BY_TASK = {
Artillery.SpGH_Dana,
Artillery.M12_GMC,
Artillery.Sturmpanzer_IV_Brummbär,
-
AirDefence.AAA_ZU_23_on_Ural_375,
AirDefence.AAA_ZU_23_Insurgent_on_Ural_375,
AirDefence.AAA_ZSU_57_2,
@@ -983,12 +1012,10 @@ UNIT_BY_TASK = {
AirDefence.AAA_Bofors_40mm,
AirDefence.AAA_M1_37mm,
AirDefence.AA_gun_QF_3_7,
-
frenchpack.DIM__TOYOTA_BLUE,
frenchpack.DIM__TOYOTA_DESERT,
frenchpack.DIM__TOYOTA_GREEN,
frenchpack.DIM__KAMIKAZE,
-
frenchpack.AMX_10RCR,
frenchpack.AMX_10RCR_SEPAR,
frenchpack.ERC_90,
@@ -1006,15 +1033,29 @@ UNIT_BY_TASK = {
frenchpack.DIM__TOYOTA_GREEN,
frenchpack.DIM__TOYOTA_DESERT,
frenchpack.DIM__KAMIKAZE,
-
],
- AirDefence: [
+ AirDefence: [],
+ Reconnaissance: [
+ Unarmed.Transport_M818,
+ Unarmed.Transport_Ural_375,
+ Unarmed.Transport_UAZ_469,
+ ],
+ Nothing: [
+ Infantry.Infantry_M4,
+ Infantry.Soldier_AK,
],
- Reconnaissance: [Unarmed.Transport_M818, Unarmed.Transport_Ural_375, Unarmed.Transport_UAZ_469],
- Nothing: [Infantry.Infantry_M4, Infantry.Soldier_AK, ],
Embarking: [],
- Carriage: [CVN_74_John_C__Stennis, LHA_1_Tarawa, CV_1143_5_Admiral_Kuznetsov, ],
- CargoTransportation: [Dry_cargo_ship_Ivanov, Bulk_cargo_ship_Yakushev, Tanker_Elnya_160, Armed_speedboat, ]
+ Carriage: [
+ CVN_74_John_C__Stennis,
+ LHA_1_Tarawa,
+ CV_1143_5_Admiral_Kuznetsov,
+ ],
+ CargoTransportation: [
+ Dry_cargo_ship_Ivanov,
+ Bulk_cargo_ship_Yakushev,
+ Tanker_Elnya_160,
+ Armed_speedboat,
+ ],
}
"""
@@ -1022,7 +1063,6 @@ Units from AirDefense category of UNIT_BY_TASK that will be removed from use if
"""
SAM_BAN = [
AirDefence.SAM_Linebacker_M6,
-
AirDefence.SAM_SA_9_Strela_1_9P31,
AirDefence.SAM_SA_8_Osa_9A33,
AirDefence.SAM_SA_19_Tunguska_2S6,
@@ -1051,20 +1091,19 @@ SAM_CONVERT = {
AirDefence.SAM_Hawk_TR_AN_MPQ_46: AirDefence.SAM_Hawk_PCP,
AirDefence.SAM_Hawk_SR_AN_MPQ_50: AirDefence.SAM_Hawk_PCP,
AirDefence.SAM_Hawk_LN_M192: AirDefence.SAM_Hawk_PCP,
- 'except': {
+ "except": {
# this radar is shared between the two S300's. if we attempt to find a SAM site at a base and can't find one
# model, we can safely assume the other was deployed
# well, perhaps not safely, but we'll make the assumption anyway :p
AirDefence.SAM_SA_10_S_300PS_TR_30N6: AirDefence.SAM_SA_10_S_300PS_CP_54K6,
- AirDefence.SAM_SR_P_19: AirDefence.SAM_SA_2_LN_SM_90
- }
+ AirDefence.SAM_SR_P_19: AirDefence.SAM_SA_2_LN_SM_90,
+ },
}
"""
Units that will always be spawned in the air
"""
-TAKEOFF_BAN: List[Type[FlyingType]] = [
-]
+TAKEOFF_BAN: List[Type[FlyingType]] = []
"""
Units that will be always spawned in the air if launched from the carrier
@@ -1117,7 +1156,7 @@ COMMON_OVERRIDE = {
GroundAttack: "STRIKE",
Escort: "CAP",
RunwayAttack: "RUNWAY_ATTACK",
- FighterSweep: "CAP"
+ FighterSweep: "CAP",
}
"""
@@ -1134,19 +1173,18 @@ EXPANDED_TASK_PAYLOAD_OVERRIDE = {
"BARCAP": ("CAP HEAVY", "CAP"),
"CAS": ("CAS MAVERICK F", "CAS"),
"INTERCEPTION": ("CAP HEAVY", "CAP"),
- "STRIKE": ("STRIKE",),
+ "STRIKE": ("STRIKE",),
"ANTISHIP": ("ANTISHIP",),
"SEAD": ("SEAD",),
"DEAD": ("SEAD",),
"ESCORT": ("CAP HEAVY", "CAP"),
- "BAI": ( "BAI", "CAS MAVERICK F", "CAS"),
+ "BAI": ("BAI", "CAS MAVERICK F", "CAS"),
"SWEEP": ("CAP HEAVY", "CAP"),
- "OCA_RUNWAY": ("RUNWAY_ATTACK","RUNWAY_STRIKE","STRIKE"),
- "OCA_AIRCRAFT": ("OCA","CAS MAVERICK F", "CAS")
+ "OCA_RUNWAY": ("RUNWAY_ATTACK", "RUNWAY_STRIKE", "STRIKE"),
+ "OCA_AIRCRAFT": ("OCA", "CAS MAVERICK F", "CAS"),
}
PLANE_PAYLOAD_OVERRIDES: Dict[Type[PlaneType], Dict[Type[Task], str]] = {
-
B_1B: COMMON_OVERRIDE,
B_52H: COMMON_OVERRIDE,
F_117A: COMMON_OVERRIDE,
@@ -1253,11 +1291,9 @@ PLANE_PAYLOAD_OVERRIDES: Dict[Type[PlaneType], Dict[Type[Task], str]] = {
AH_64A: COMMON_OVERRIDE,
SH_60B: COMMON_OVERRIDE,
Hercules: COMMON_OVERRIDE,
-
Su_25TM: {
SEAD: "Kh-31P*2_Kh-25ML*4_R-73*2_L-081_MPS410",
},
-
}
"""
@@ -1318,9 +1354,17 @@ TIME_PERIODS = {
}
REWARDS = {
- "power": 4, "warehouse": 2, "ware": 2, "fuel": 2, "ammo": 2,
- "farp": 1, "fob": 1, "factory": 10, "comms": 10, "oil": 10,
- "derrick": 8
+ "power": 4,
+ "warehouse": 2,
+ "ware": 2,
+ "fuel": 2,
+ "ammo": 2,
+ "farp": 1,
+ "fob": 1,
+ "factory": 10,
+ "comms": 10,
+ "oil": 10,
+ "derrick": 8,
}
CARRIER_CAPABLE = [
@@ -1332,7 +1376,6 @@ CARRIER_CAPABLE = [
A_4E_C,
Rafale_M,
S_3B,
-
UH_1H,
Mi_8MT,
Ka_50,
@@ -1340,7 +1383,6 @@ CARRIER_CAPABLE = [
OH_58D,
UH_60A,
SH_60B,
-
SA342L,
SA342M,
SA342Minigun,
@@ -1349,7 +1391,6 @@ CARRIER_CAPABLE = [
LHA_CAPABLE = [
AV8BNA,
-
UH_1H,
Mi_8MT,
Ka_50,
@@ -1357,11 +1398,10 @@ LHA_CAPABLE = [
OH_58D,
UH_60A,
SH_60B,
-
SA342L,
SA342M,
SA342Minigun,
- SA342Mistral
+ SA342Mistral,
]
"""
@@ -1418,27 +1458,50 @@ def find_unittype(for_task: Task, country_name: str) -> List[Type[UnitType]]:
MANPADS: List[VehicleType] = [
AirDefence.SAM_SA_18_Igla_MANPADS,
AirDefence.SAM_SA_18_Igla_S_MANPADS,
- AirDefence.Stinger_MANPADS
+ AirDefence.Stinger_MANPADS,
]
INFANTRY: List[VehicleType] = [
- Infantry.Paratrooper_AKS, Infantry.Paratrooper_AKS, Infantry.Paratrooper_AKS, Infantry.Paratrooper_AKS,
+ Infantry.Paratrooper_AKS,
+ Infantry.Paratrooper_AKS,
+ Infantry.Paratrooper_AKS,
+ Infantry.Paratrooper_AKS,
Infantry.Paratrooper_AKS,
Infantry.Soldier_RPG,
- Infantry.Infantry_M4, Infantry.Infantry_M4, Infantry.Infantry_M4, Infantry.Infantry_M4, Infantry.Infantry_M4,
+ Infantry.Infantry_M4,
+ Infantry.Infantry_M4,
+ Infantry.Infantry_M4,
+ Infantry.Infantry_M4,
+ Infantry.Infantry_M4,
Infantry.Soldier_M249,
Artillery._2B11_mortar,
- Infantry.Soldier_AK, Infantry.Soldier_AK, Infantry.Soldier_AK, Infantry.Soldier_AK, Infantry.Soldier_AK,
+ Infantry.Soldier_AK,
+ Infantry.Soldier_AK,
+ Infantry.Soldier_AK,
+ Infantry.Soldier_AK,
+ Infantry.Soldier_AK,
Infantry.Paratrooper_RPG_16,
- Infantry.Georgian_soldier_with_M4, Infantry.Georgian_soldier_with_M4, Infantry.Georgian_soldier_with_M4,
Infantry.Georgian_soldier_with_M4,
- Infantry.Infantry_Soldier_Rus, Infantry.Infantry_Soldier_Rus, Infantry.Infantry_Soldier_Rus,
+ Infantry.Georgian_soldier_with_M4,
+ Infantry.Georgian_soldier_with_M4,
+ Infantry.Georgian_soldier_with_M4,
Infantry.Infantry_Soldier_Rus,
- Infantry.Infantry_SMLE_No_4_Mk_1, Infantry.Infantry_SMLE_No_4_Mk_1, Infantry.Infantry_SMLE_No_4_Mk_1,
- Infantry.Infantry_Mauser_98, Infantry.Infantry_Mauser_98, Infantry.Infantry_Mauser_98,
+ Infantry.Infantry_Soldier_Rus,
+ Infantry.Infantry_Soldier_Rus,
+ Infantry.Infantry_Soldier_Rus,
+ Infantry.Infantry_SMLE_No_4_Mk_1,
+ Infantry.Infantry_SMLE_No_4_Mk_1,
+ Infantry.Infantry_SMLE_No_4_Mk_1,
Infantry.Infantry_Mauser_98,
- Infantry.Infantry_M1_Garand, Infantry.Infantry_M1_Garand, Infantry.Infantry_M1_Garand,
- Infantry.Infantry_Soldier_Insurgents, Infantry.Infantry_Soldier_Insurgents, Infantry.Infantry_Soldier_Insurgents
+ Infantry.Infantry_Mauser_98,
+ Infantry.Infantry_Mauser_98,
+ Infantry.Infantry_Mauser_98,
+ Infantry.Infantry_M1_Garand,
+ Infantry.Infantry_M1_Garand,
+ Infantry.Infantry_M1_Garand,
+ Infantry.Infantry_Soldier_Insurgents,
+ Infantry.Infantry_Soldier_Insurgents,
+ Infantry.Infantry_Soldier_Insurgents,
]
@@ -1461,6 +1524,7 @@ def unit_type_name(unit_type) -> str:
def unit_type_name_2(unit_type) -> str:
return unit_type.name and unit_type.name or unit_type.id
+
def unit_get_expanded_info(country_name: str, unit_type, request_type: str) -> str:
original_name = unit_type.name and unit_type.name or unit_type.id
default_value = None
@@ -1489,6 +1553,7 @@ def unit_get_expanded_info(country_name: str, unit_type, request_type: str) -> s
return default_value
return faction_value
+
def unit_type_from_name(name: str) -> Optional[Type[UnitType]]:
if name in vehicle_map:
return vehicle_map[name]
@@ -1522,9 +1587,13 @@ def task_name(task) -> str:
return task.name
-def choose_units(for_task: Task, factor: float, count: int, country: str) -> List[UnitType]:
+def choose_units(
+ for_task: Task, factor: float, count: int, country: str
+) -> List[UnitType]:
suitable_unittypes = find_unittype(for_task, country)
- suitable_unittypes = [x for x in suitable_unittypes if x not in helicopter_map.values()]
+ suitable_unittypes = [
+ x for x in suitable_unittypes if x not in helicopter_map.values()
+ ]
suitable_unittypes.sort(key=lambda x: PRICES[x])
idx = int(len(suitable_unittypes) * factor)
@@ -1572,7 +1641,10 @@ def unitdict_restrict_count(unit_dict: UnitsDict, total_count: int) -> UnitsDict
def assigned_units_split(fd: AssignedUnitsDict) -> Tuple[PlaneDict, PlaneDict]:
- return {k: v1 for k, (v1, v2) in fd.items()}, {k: v2 for k, (v1, v2) in fd.items()},
+ return (
+ {k: v1 for k, (v1, v2) in fd.items()},
+ {k: v2 for k, (v1, v2) in fd.items()},
+ )
def assigned_units_from(d: PlaneDict) -> AssignedUnitsDict:
@@ -1616,7 +1688,9 @@ def _validate_db():
total_set = set()
for t, unit_collection in UNIT_BY_TASK.items():
for unit_type in set(unit_collection):
- assert unit_type not in total_set, "{} is duplicate for task {}".format(unit_type, t)
+ assert unit_type not in total_set, "{} is duplicate for task {}".format(
+ unit_type, t
+ )
total_set.add(unit_type)
# check prices
diff --git a/game/debriefing.py b/game/debriefing.py
index 59477ba4..c0221838 100644
--- a/game/debriefing.py
+++ b/game/debriefing.py
@@ -96,13 +96,14 @@ class StateData:
# them when they've already dead. Dedup.
killed_ground_units=list(set(data["killed_ground_units"])),
destroyed_statics=data["destroyed_objects_positions"],
- base_capture_events=data["base_capture_events"]
+ base_capture_events=data["base_capture_events"],
)
class Debriefing:
- def __init__(self, state_data: Dict[str, Any], game: Game,
- unit_map: UnitMap) -> None:
+ def __init__(
+ self, state_data: Dict[str, Any], game: Game, unit_map: UnitMap
+ ) -> None:
self.state_data = StateData.from_json(state_data)
self.unit_map = unit_map
@@ -135,12 +136,9 @@ class Debriefing:
yield from self.ground_losses.enemy_airfields
def casualty_count(self, control_point: ControlPoint) -> int:
- return len(
- [x for x in self.front_line_losses if x.origin == control_point]
- )
+ return len([x for x in self.front_line_losses if x.origin == control_point])
- def front_line_losses_by_type(
- self, player: bool) -> Dict[Type[UnitType], int]:
+ def front_line_losses_by_type(self, player: bool) -> Dict[Type[UnitType], int]:
losses_by_type: Dict[Type[UnitType], int] = defaultdict(int)
if player:
losses = self.ground_losses.player_front_line
@@ -221,8 +219,10 @@ class Debriefing:
# deaths, so we expect to see quite a few unclaimed dead ground
# units. We should start tracking those and covert this to a
# warning.
- logging.debug(f"Death of untracked ground unit {unit_name} will "
- "have no effect. This may be normal behavior.")
+ logging.debug(
+ f"Death of untracked ground unit {unit_name} will "
+ "have no effect. This may be normal behavior."
+ )
return losses
@@ -234,15 +234,16 @@ class Debriefing:
for idx, base in enumerate(i.split("||")[0] for i in reversed_captures):
if base not in [x[1] for x in last_base_cap_indexes]:
last_base_cap_indexes.append((idx, base))
- return [reversed_captures[idx[0]] for idx in last_base_cap_indexes]
+ return [reversed_captures[idx[0]] for idx in last_base_cap_indexes]
class PollDebriefingFileThread(threading.Thread):
"""Thread class with a stop() method. The thread itself has to check
regularly for the stopped() condition."""
- def __init__(self, callback: Callable[[Debriefing], None],
- game: Game, unit_map: UnitMap) -> None:
+ def __init__(
+ self, callback: Callable[[Debriefing], None], game: Game, unit_map: UnitMap
+ ) -> None:
super().__init__()
self._stop_event = threading.Event()
self.callback = callback
@@ -261,7 +262,10 @@ class PollDebriefingFileThread(threading.Thread):
else:
last_modified = 0
while not self.stopped():
- if os.path.isfile("state.json") and os.path.getmtime("state.json") > last_modified:
+ if (
+ os.path.isfile("state.json")
+ and os.path.getmtime("state.json") > last_modified
+ ):
with open("state.json", "r") as json_file:
json_data = json.load(json_file)
debriefing = Debriefing(json_data, self.game, self.unit_map)
@@ -270,8 +274,9 @@ class PollDebriefingFileThread(threading.Thread):
time.sleep(5)
-def wait_for_debriefing(callback: Callable[[Debriefing], None],
- game: Game, unit_map) -> PollDebriefingFileThread:
+def wait_for_debriefing(
+ callback: Callable[[Debriefing], None], game: Game, unit_map
+) -> PollDebriefingFileThread:
thread = PollDebriefingFileThread(callback, game, unit_map)
thread.start()
return thread
diff --git a/game/event/event.py b/game/event/event.py
index 92e646b8..ea7f0e17 100644
--- a/game/event/event.py
+++ b/game/event/event.py
@@ -37,7 +37,15 @@ class Event:
to_cp = None # type: ControlPoint
difficulty = 1 # type: int
- def __init__(self, game, from_cp: ControlPoint, target_cp: ControlPoint, location: Point, attacker_name: str, defender_name: str):
+ def __init__(
+ self,
+ game,
+ from_cp: ControlPoint,
+ target_cp: ControlPoint,
+ location: Point,
+ attacker_name: str,
+ defender_name: str,
+ ):
self.game = game
self.from_cp = from_cp
self.to_cp = target_cp
@@ -57,12 +65,14 @@ class Event:
Operation.prepare(self.game)
unit_map = Operation.generate()
Operation.current_mission.save(
- persistency.mission_path_for("liberation_nextturn.miz"))
+ persistency.mission_path_for("liberation_nextturn.miz")
+ )
return unit_map
@staticmethod
- def _transfer_aircraft(ato: AirTaskingOrder, losses: AirLosses,
- for_player: bool) -> None:
+ def _transfer_aircraft(
+ ato: AirTaskingOrder, losses: AirLosses, for_player: bool
+ ) -> None:
for package in ato.packages:
for flight in package.flights:
# No need to transfer to the same location.
@@ -77,13 +87,16 @@ class Event:
if flight.arrival.captured != for_player:
logging.info(
f"Not transferring {flight} because {flight.arrival} "
- "was captured")
+ "was captured"
+ )
continue
transfer_count = losses.surviving_flight_members(flight)
if transfer_count < 0:
- logging.error(f"{flight} had {flight.count} aircraft but "
- f"{transfer_count} losses were recorded.")
+ logging.error(
+ f"{flight} had {flight.count} aircraft but "
+ f"{transfer_count} losses were recorded."
+ )
continue
aircraft = flight.unit_type
@@ -91,7 +104,8 @@ class Event:
if available < transfer_count:
logging.error(
f"Found killed {aircraft} from {flight.departure} but "
- f"that airbase has only {available} available.")
+ f"that airbase has only {available} available."
+ )
continue
flight.departure.base.aircraft[aircraft] -= transfer_count
@@ -101,10 +115,12 @@ class Event:
flight.arrival.base.aircraft[aircraft] += transfer_count
def complete_aircraft_transfers(self, debriefing: Debriefing) -> None:
- self._transfer_aircraft(self.game.blue_ato, debriefing.air_losses,
- for_player=True)
- self._transfer_aircraft(self.game.red_ato, debriefing.air_losses,
- for_player=False)
+ self._transfer_aircraft(
+ self.game.blue_ato, debriefing.air_losses, for_player=True
+ )
+ self._transfer_aircraft(
+ self.game.red_ato, debriefing.air_losses, for_player=False
+ )
@staticmethod
def commit_air_losses(debriefing: Debriefing) -> None:
@@ -115,7 +131,8 @@ class Event:
if available <= 0:
logging.error(
f"Found killed {aircraft} from {cp} but that airbase has "
- "none available.")
+ "none available."
+ )
continue
logging.info(f"{aircraft} destroyed from {cp}")
@@ -130,7 +147,8 @@ class Event:
if available <= 0:
logging.error(
f"Found killed {unit_type} from {control_point} but that "
- "airbase has none available.")
+ "airbase has none available."
+ )
continue
logging.info(f"{unit_type} destroyed from {control_point}")
@@ -149,11 +167,14 @@ class Event:
def commit_building_losses(self, debriefing: Debriefing) -> None:
for loss in debriefing.building_losses:
loss.ground_object.kill()
- self.game.informations.append(Information(
- "Building destroyed",
- f"{loss.ground_object.dcs_identifier} has been destroyed at "
- f"location {loss.ground_object.obj_name}", self.game.turn
- ))
+ self.game.informations.append(
+ Information(
+ "Building destroyed",
+ f"{loss.ground_object.dcs_identifier} has been destroyed at "
+ f"location {loss.ground_object.obj_name}",
+ self.game.turn,
+ )
+ )
@staticmethod
def commit_damaged_runways(debriefing: Debriefing) -> None:
@@ -171,9 +192,9 @@ class Event:
# ------------------------------
# Captured bases
- #if self.game.player_country in db.BLUEFOR_FACTIONS:
- coalition = 2 # Value in DCS mission event for BLUE
- #else:
+ # if self.game.player_country in db.BLUEFOR_FACTIONS:
+ coalition = 2 # Value in DCS mission event for BLUE
+ # else:
# coalition = 1 # Value in DCS mission event for RED
for captured in debriefing.base_capture_events:
@@ -187,12 +208,22 @@ class Event:
if cp.captured and new_owner_coalition != coalition:
for_player = False
- info = Information(cp.name + " lost !", "The ennemy took control of " + cp.name + "\nShame on us !", self.game.turn)
+ info = Information(
+ cp.name + " lost !",
+ "The ennemy took control of "
+ + cp.name
+ + "\nShame on us !",
+ self.game.turn,
+ )
self.game.informations.append(info)
captured_cps.append(cp)
- elif not(cp.captured) and new_owner_coalition == coalition:
+ elif not (cp.captured) and new_owner_coalition == coalition:
for_player = True
- info = Information(cp.name + " captured !", "We took control of " + cp.name + "! Great job !", self.game.turn)
+ info = Information(
+ cp.name + " captured !",
+ "We took control of " + cp.name + "! Great job !",
+ self.game.turn,
+ )
self.game.informations.append(info)
captured_cps.append(cp)
else:
@@ -218,7 +249,12 @@ class Event:
for cp in self.game.theater.player_points():
enemy_cps = [e for e in cp.connected_points if not e.captured]
for enemy_cp in enemy_cps:
- print("Compute frontline progression for : " + cp.name + " to " + enemy_cp.name)
+ print(
+ "Compute frontline progression for : "
+ + cp.name
+ + " to "
+ + enemy_cp.name
+ )
delta = 0.0
player_won = True
@@ -234,7 +270,11 @@ class Event:
ratio = (1.0 + enemy_casualties) / (1.0 + ally_casualties)
- player_aggresive = cp.stances[enemy_cp.id] in [CombatStance.AGGRESSIVE, CombatStance.ELIMINATION, CombatStance.BREAKTHROUGH]
+ player_aggresive = cp.stances[enemy_cp.id] in [
+ CombatStance.AGGRESSIVE,
+ CombatStance.ELIMINATION,
+ CombatStance.BREAKTHROUGH,
+ ]
if ally_units_alive == 0:
player_won = False
@@ -259,11 +299,17 @@ class Event:
delta = DEFEAT_INFLUENCE
elif ally_casualties > enemy_casualties:
- if ally_units_alive > 2*enemy_units_alive and player_aggresive:
+ if (
+ ally_units_alive > 2 * enemy_units_alive
+ and player_aggresive
+ ):
# Even with casualties if the enemy is overwhelmed, they are going to lose ground
player_won = True
delta = MINOR_DEFEAT_INFLUENCE
- elif ally_units_alive > 3*enemy_units_alive and player_aggresive:
+ elif (
+ ally_units_alive > 3 * enemy_units_alive
+ and player_aggresive
+ ):
player_won = True
delta = STRONG_DEFEAT_INFLUENCE
else:
@@ -275,7 +321,10 @@ class Event:
delta = STRONG_DEFEAT_INFLUENCE
# No progress with defensive strategies
- if player_won and cp.stances[enemy_cp.id] in [CombatStance.DEFENSIVE, CombatStance.AMBUSH]:
+ if player_won and cp.stances[enemy_cp.id] in [
+ CombatStance.DEFENSIVE,
+ CombatStance.AMBUSH,
+ ]:
print("Defensive stance, progress is limited")
delta = MINOR_DEFEAT_INFLUENCE
@@ -283,28 +332,40 @@ class Event:
print(cp.name + " won ! factor > " + str(delta))
cp.base.affect_strength(delta)
enemy_cp.base.affect_strength(-delta)
- info = Information("Frontline Report",
- "Our ground forces from " + cp.name + " are making progress toward " + enemy_cp.name,
- self.game.turn)
+ info = Information(
+ "Frontline Report",
+ "Our ground forces from "
+ + cp.name
+ + " are making progress toward "
+ + enemy_cp.name,
+ self.game.turn,
+ )
self.game.informations.append(info)
else:
print(cp.name + " lost ! factor > " + str(delta))
enemy_cp.base.affect_strength(delta)
cp.base.affect_strength(-delta)
- info = Information("Frontline Report",
- "Our ground forces from " + cp.name + " are losing ground against the enemy forces from " + enemy_cp.name,
- self.game.turn)
+ info = Information(
+ "Frontline Report",
+ "Our ground forces from "
+ + cp.name
+ + " are losing ground against the enemy forces from "
+ + enemy_cp.name,
+ self.game.turn,
+ )
self.game.informations.append(info)
def redeploy_units(self, cp: ControlPoint) -> None:
- """"
+ """ "
Auto redeploy units to newly captured base
"""
- ally_connected_cps = [ocp for ocp in cp.connected_points if
- cp.captured == ocp.captured]
- enemy_connected_cps = [ocp for ocp in cp.connected_points if
- cp.captured != ocp.captured]
+ ally_connected_cps = [
+ ocp for ocp in cp.connected_points if cp.captured == ocp.captured
+ ]
+ enemy_connected_cps = [
+ ocp for ocp in cp.connected_points if cp.captured != ocp.captured
+ ]
# If the newly captured cp does not have enemy connected cp,
# then it is not necessary to redeploy frontline units there.
@@ -315,8 +376,7 @@ class Event:
for ally_cp in ally_connected_cps:
self.redeploy_between(cp, ally_cp)
- def redeploy_between(self, destination: ControlPoint,
- source: ControlPoint) -> None:
+ def redeploy_between(self, destination: ControlPoint, source: ControlPoint) -> None:
total_units_redeployed = 0
moved_units = {}
@@ -333,8 +393,7 @@ class Event:
for frontline_unit, count in source.base.armor.items():
moved_units[frontline_unit] = int(count * move_factor)
- total_units_redeployed = total_units_redeployed + int(
- count * move_factor)
+ total_units_redeployed = total_units_redeployed + int(count * move_factor)
destination.base.commision_units(moved_units)
source.base.commit_losses(moved_units)
@@ -362,7 +421,6 @@ class Event:
class UnitsDeliveryEvent:
-
def __init__(self, control_point: ControlPoint) -> None:
self.to_cp = control_point
self.units: Dict[Type[UnitType], int] = {}
@@ -390,8 +448,7 @@ class UnitsDeliveryEvent:
logging.error(f"Could not refund {unit_type.id}, price unknown")
continue
- logging.info(
- f"Refunding {count} {unit_type.id} at {self.to_cp.name}")
+ logging.info(f"Refunding {count} {unit_type.id} at {self.to_cp.name}")
game.adjust_budget(price * count, player=self.to_cp.captured)
def available_next_turn(self, unit_type: Type[UnitType]) -> int:
@@ -409,13 +466,13 @@ class UnitsDeliveryEvent:
aircraft = unit_type.id
name = self.to_cp.name
if count >= 0:
- bought_units[unit_type] = count
+ bought_units[unit_type] = count
game.message(
- f"{coalition} reinforcements: {aircraft} x {count} at {name}")
+ f"{coalition} reinforcements: {aircraft} x {count} at {name}"
+ )
else:
sold_units[unit_type] = -count
- game.message(
- f"{coalition} sold: {aircraft} x {-count} at {name}")
+ game.message(f"{coalition} sold: {aircraft} x {-count} at {name}")
self.to_cp.base.commision_units(bought_units)
self.to_cp.base.commit_losses(sold_units)
self.units = {}
diff --git a/game/event/frontlineattack.py b/game/event/frontlineattack.py
index 6dab825d..d7749a2a 100644
--- a/game/event/frontlineattack.py
+++ b/game/event/frontlineattack.py
@@ -7,5 +7,6 @@ class FrontlineAttackEvent(Event):
Currently the same as its parent, but here for legacy compatibility as well as to allow for
future unique Event handling
"""
+
def __str__(self):
return "Frontline attack"
diff --git a/game/factions/faction.py b/game/factions/faction.py
index d3b14134..4ed2ada6 100644
--- a/game/factions/faction.py
+++ b/game/factions/faction.py
@@ -10,8 +10,18 @@ from dcs.planes import plane_map
from dcs.unittype import FlyingType, ShipType, VehicleType, UnitType
from dcs.vehicles import Armor, Unarmed, Infantry, Artillery, AirDefence
-from game.data.building_data import WW2_ALLIES_BUILDINGS, DEFAULT_AVAILABLE_BUILDINGS, WW2_GERMANY_BUILDINGS, WW2_FREE
-from game.data.doctrine import Doctrine, MODERN_DOCTRINE, COLDWAR_DOCTRINE, WWII_DOCTRINE
+from game.data.building_data import (
+ WW2_ALLIES_BUILDINGS,
+ DEFAULT_AVAILABLE_BUILDINGS,
+ WW2_GERMANY_BUILDINGS,
+ WW2_FREE,
+)
+from game.data.doctrine import (
+ Doctrine,
+ MODERN_DOCTRINE,
+ COLDWAR_DOCTRINE,
+ WWII_DOCTRINE,
+)
from pydcs_extensions.mod_units import MODDED_VEHICLES, MODDED_AIRPLANES
@@ -103,8 +113,7 @@ class Faction:
building_set: List[str] = field(default_factory=list)
# List of default livery overrides
- liveries_overrides: Dict[Type[UnitType], List[str]] = field(
- default_factory=dict)
+ liveries_overrides: Dict[Type[UnitType], List[str]] = field(default_factory=dict)
#: Set to True if the faction should force the "Unrestricted satnav" option
#: for the mission. This option enables GPS for capable aircraft regardless
@@ -122,7 +131,11 @@ class Faction:
faction.country = json.get("country", "/")
if faction.country not in [c.name for c in country_dict.values()]:
- raise AssertionError("Faction's country (\"{}\") is not a valid DCS country ID".format(faction.country))
+ raise AssertionError(
+ 'Faction\'s country ("{}") is not a valid DCS country ID'.format(
+ faction.country
+ )
+ )
faction.name = json.get("name", "")
if not faction.name:
@@ -135,14 +148,10 @@ class Faction:
faction.awacs = load_all_aircraft(json.get("awacs", []))
faction.tankers = load_all_aircraft(json.get("tankers", []))
- faction.frontline_units = load_all_vehicles(
- json.get("frontline_units", []))
- faction.artillery_units = load_all_vehicles(
- json.get("artillery_units", []))
- faction.infantry_units = load_all_vehicles(
- json.get("infantry_units", []))
- faction.logistics_units = load_all_vehicles(
- json.get("logistics_units", []))
+ faction.frontline_units = load_all_vehicles(json.get("frontline_units", []))
+ faction.artillery_units = load_all_vehicles(json.get("artillery_units", []))
+ faction.infantry_units = load_all_vehicles(json.get("infantry_units", []))
+ faction.logistics_units = load_all_vehicles(json.get("logistics_units", []))
faction.ewrs = json.get("ewrs", [])
@@ -156,13 +165,10 @@ class Faction:
faction.requirements = json.get("requirements", {})
faction.carrier_names = json.get("carrier_names", [])
- faction.helicopter_carrier_names = json.get(
- "helicopter_carrier_names", [])
+ faction.helicopter_carrier_names = json.get("helicopter_carrier_names", [])
faction.navy_generators = json.get("navy_generators", [])
- faction.aircraft_carrier = load_all_ships(
- json.get("aircraft_carrier", []))
- faction.helicopter_carrier = load_all_ships(
- json.get("helicopter_carrier", []))
+ faction.aircraft_carrier = load_all_ships(json.get("aircraft_carrier", []))
+ faction.helicopter_carrier = load_all_ships(json.get("helicopter_carrier", []))
faction.destroyers = load_all_ships(json.get("destroyers", []))
faction.cruisers = load_all_ships(json.get("cruisers", []))
faction.has_jtac = json.get("has_jtac", False)
@@ -212,13 +218,18 @@ class Faction:
@property
def units(self) -> List[Type[UnitType]]:
- return (self.infantry_units + self.aircrafts + self.awacs +
- self.artillery_units + self.frontline_units +
- self.tankers + self.logistics_units)
+ return (
+ self.infantry_units
+ + self.aircrafts
+ + self.awacs
+ + self.artillery_units
+ + self.frontline_units
+ + self.tankers
+ + self.logistics_units
+ )
-def unit_loader(
- unit: str, class_repository: List[Any]) -> Optional[Type[UnitType]]:
+def unit_loader(unit: str, class_repository: List[Any]) -> Optional[Type[UnitType]]:
"""
Find unit by name
:param unit: Unit name as string
@@ -242,9 +253,10 @@ def unit_loader(
def load_aircraft(name: str) -> Optional[Type[FlyingType]]:
- return cast(Optional[FlyingType], unit_loader(
- name, [dcs.planes, dcs.helicopters, MODDED_AIRPLANES]
- ))
+ return cast(
+ Optional[FlyingType],
+ unit_loader(name, [dcs.planes, dcs.helicopters, MODDED_AIRPLANES]),
+ )
def load_all_aircraft(data) -> List[Type[FlyingType]]:
@@ -257,9 +269,12 @@ def load_all_aircraft(data) -> List[Type[FlyingType]]:
def load_vehicle(name: str) -> Optional[Type[VehicleType]]:
- return cast(Optional[FlyingType], unit_loader(
- name, [Infantry, Unarmed, Armor, AirDefence, Artillery, MODDED_VEHICLES]
- ))
+ return cast(
+ Optional[FlyingType],
+ unit_loader(
+ name, [Infantry, Unarmed, Armor, AirDefence, Artillery, MODDED_VEHICLES]
+ ),
+ )
def load_all_vehicles(data) -> List[Type[VehicleType]]:
diff --git a/game/game.py b/game/game.py
index 2ec47e4d..743a5380 100644
--- a/game/game.py
+++ b/game/game.py
@@ -78,10 +78,16 @@ class TurnState(Enum):
class Game:
- def __init__(self, player_name: str, enemy_name: str,
- theater: ConflictTheater, start_date: datetime,
- settings: Settings, player_budget: float,
- enemy_budget: float) -> None:
+ def __init__(
+ self,
+ player_name: str,
+ enemy_name: str,
+ theater: ConflictTheater,
+ start_date: datetime,
+ settings: Settings,
+ player_budget: float,
+ enemy_budget: float,
+ ) -> None:
self.settings = settings
self.events: List[Event] = []
self.theater = theater
@@ -112,9 +118,7 @@ class Game:
self.blue_ato = AirTaskingOrder()
self.red_ato = AirTaskingOrder()
- self.aircraft_inventory = GlobalAircraftInventory(
- self.theater.controlpoints
- )
+ self.aircraft_inventory = GlobalAircraftInventory(self.theater.controlpoints)
self.sanitize_sides()
@@ -147,8 +151,9 @@ class Game:
self.on_load()
def generate_conditions(self) -> Conditions:
- return Conditions.generate(self.theater, self.date,
- self.current_turn_time_of_day, self.settings)
+ return Conditions.generate(
+ self.theater, self.date, self.current_turn_time_of_day, self.settings
+ )
def sanitize_sides(self):
"""
@@ -184,13 +189,24 @@ class Game:
return random.randint(1, 100) <= prob * mult
def _generate_player_event(self, event_class, player_cp, enemy_cp):
- self.events.append(event_class(self, player_cp, enemy_cp, enemy_cp.position, self.player_name, self.enemy_name))
+ self.events.append(
+ event_class(
+ self,
+ player_cp,
+ enemy_cp,
+ enemy_cp.position,
+ self.player_name,
+ self.enemy_name,
+ )
+ )
def _generate_events(self):
for front_line in self.theater.conflicts(True):
- self._generate_player_event(FrontlineAttackEvent,
- front_line.control_point_a,
- front_line.control_point_b)
+ self._generate_player_event(
+ FrontlineAttackEvent,
+ front_line.control_point_a,
+ front_line.control_point_b,
+ )
def adjust_budget(self, amount: float, player: bool) -> None:
if player:
@@ -208,7 +224,7 @@ class Game:
self.enemy_budget += Income(self, player=False).total
def initiate_event(self, event: Event) -> UnitMap:
- #assert event in self.events
+ # assert event in self.events
logging.info("Generating {} (regular)".format(event))
return event.generate()
@@ -223,7 +239,11 @@ class Game:
def is_player_attack(self, event):
if isinstance(event, Event):
- return event and event.attacker_name and event.attacker_name == self.player_name
+ return (
+ event
+ and event.attacker_name
+ and event.attacker_name == self.player_name
+ )
else:
raise RuntimeError(f"{event} was passed when an Event type was expected")
@@ -235,7 +255,9 @@ class Game:
def pass_turn(self, no_action: bool = False) -> None:
logging.info("Pass turn")
- self.informations.append(Information("End of turn #" + str(self.turn), "-" * 40, 0))
+ self.informations.append(
+ Information("End of turn #" + str(self.turn), "-" * 40, 0)
+ )
self.turn += 1
for control_point in self.theater.controlpoints:
@@ -281,7 +303,7 @@ class Game:
# Check for win or loss condition
turn_state = self.check_win_loss()
- if turn_state in (TurnState.LOSS,TurnState.WIN):
+ if turn_state in (TurnState.LOSS, TurnState.WIN):
return self.process_win_loss(turn_state)
# Plan flights & combat for next turn
@@ -305,8 +327,11 @@ class Game:
self.plan_procurement(blue_planner, red_planner)
- def plan_procurement(self, blue_planner: CoalitionMissionPlanner,
- red_planner: CoalitionMissionPlanner) -> None:
+ def plan_procurement(
+ self,
+ blue_planner: CoalitionMissionPlanner,
+ red_planner: CoalitionMissionPlanner,
+ ) -> None:
# The first turn needs to buy a *lot* of aircraft to fill CAPs, so it
# gets much more of the budget that turn. Otherwise budget (after
# repairs) is split evenly between air and ground. For the default
@@ -320,7 +345,7 @@ class Game:
manage_runways=self.settings.automate_runway_repair,
manage_front_line=self.settings.automate_front_line_reinforcements,
manage_aircraft=self.settings.automate_aircraft_reinforcements,
- front_line_budget_share=ground_portion
+ front_line_budget_share=ground_portion,
).spend_budget(self.budget, blue_planner.procurement_requests)
self.enemy_budget = ProcurementAi(
@@ -330,7 +355,7 @@ class Game:
manage_runways=True,
manage_front_line=True,
manage_aircraft=True,
- front_line_budget_share=ground_portion
+ front_line_budget_share=ground_portion,
).spend_budget(self.enemy_budget, red_planner.procurement_requests)
def message(self, text: str) -> None:
@@ -361,10 +386,12 @@ class Game:
def compute_threat_zones(self) -> None:
self.blue_threat_zone = ThreatZones.for_faction(self, player=True)
self.red_threat_zone = ThreatZones.for_faction(self, player=False)
- self.blue_navmesh = NavMesh.from_threat_zones(self.red_threat_zone,
- self.theater)
- self.red_navmesh = NavMesh.from_threat_zones(self.blue_threat_zone,
- self.theater)
+ self.blue_navmesh = NavMesh.from_threat_zones(
+ self.red_threat_zone, self.theater
+ )
+ self.red_navmesh = NavMesh.from_threat_zones(
+ self.blue_threat_zone, self.theater
+ )
def threat_zone_for(self, player: bool) -> ThreatZones:
if player:
@@ -386,9 +413,9 @@ class Game:
# By default, use the existing frontline conflict position
for front_line in self.theater.conflicts():
- position = Conflict.frontline_position(front_line.control_point_a,
- front_line.control_point_b,
- self.theater)
+ position = Conflict.frontline_position(
+ front_line.control_point_a, front_line.control_point_b, self.theater
+ )
zones.append(position[0])
zones.append(front_line.control_point_a.position)
zones.append(front_line.control_point_b.position)
@@ -413,7 +440,10 @@ class Game:
d = cp.position.distance_to_point(cp2.position)
if d < min_distance:
min_distance = d
- cpoint = Point((cp.position.x + cp2.position.x) / 2, (cp.position.y + cp2.position.y) / 2)
+ cpoint = Point(
+ (cp.position.x + cp2.position.x) / 2,
+ (cp.position.y + cp2.position.y) / 2,
+ )
zones.append(cp.position)
zones.append(cp2.position)
break
@@ -422,8 +452,7 @@ class Game:
if cpoint is not None:
zones.append(cpoint)
- packages = itertools.chain(self.blue_ato.packages,
- self.red_ato.packages)
+ packages = itertools.chain(self.blue_ato.packages, self.red_ato.packages)
for package in packages:
if package.primary_task is FlightType.BARCAP:
# BARCAPs will be planned at most locations on smaller theaters,
@@ -460,7 +489,10 @@ class Game:
return False
else:
for z in self.__culling_zones:
- if z.distance_to_point(pos) < self.settings.perf_culling_distance * 1000:
+ if (
+ z.distance_to_point(pos)
+ < self.settings.perf_culling_distance * 1000
+ ):
return False
for p in self.__culling_points:
if p.distance_to_point(pos) < 2500:
@@ -502,6 +534,10 @@ class Game:
def process_win_loss(self, turn_state: TurnState):
if turn_state is TurnState.WIN:
- return self.message("Congratulations, you are victorious! Start a new campaign to continue.")
+ return self.message(
+ "Congratulations, you are victorious! Start a new campaign to continue."
+ )
elif turn_state is TurnState.LOSS:
- return self.message("Game Over, you lose. Start a new campaign to continue.")
+ return self.message(
+ "Game Over, you lose. Start a new campaign to continue."
+ )
diff --git a/game/income.py b/game/income.py
index d4e05993..dd2be887 100644
--- a/game/income.py
+++ b/game/income.py
@@ -46,10 +46,10 @@ class Income:
for tgo in tgos:
if not tgo.is_dead:
count += 1
- self.buildings.append(BuildingIncome(name, category, count,
- REWARDS[category]))
+ self.buildings.append(
+ BuildingIncome(name, category, count, REWARDS[category])
+ )
self.from_bases = sum(cp.income_per_turn for cp in self.control_points)
self.total_buildings = sum(b.income for b in self.buildings)
- self.total = ((self.total_buildings + self.from_bases) *
- self.multiplier)
+ self.total = (self.total_buildings + self.from_bases) * self.multiplier
diff --git a/game/infos/information.py b/game/infos/information.py
index 35e94f92..1c132d46 100644
--- a/game/infos/information.py
+++ b/game/infos/information.py
@@ -1,7 +1,7 @@
import datetime
-class Information():
+class Information:
def __init__(self, title="", text="", turn=0):
self.title = title
self.text = text
@@ -9,9 +9,11 @@ class Information():
self.timestamp = datetime.datetime.now()
def __str__(self):
- return '[{}][{}] {} {}'.format(
- self.timestamp.strftime("%Y-%m-%d %H:%M:%S") if self.timestamp is not None else '',
+ return "[{}][{}] {} {}".format(
+ self.timestamp.strftime("%Y-%m-%d %H:%M:%S")
+ if self.timestamp is not None
+ else "",
self.turn,
self.title,
- self.text
- )
\ No newline at end of file
+ self.text,
+ )
diff --git a/game/inventory.py b/game/inventory.py
index b369ad8b..651b80a8 100644
--- a/game/inventory.py
+++ b/game/inventory.py
@@ -79,6 +79,7 @@ class ControlPointAircraftInventory:
class GlobalAircraftInventory:
"""Game-wide aircraft inventory."""
+
def __init__(self, control_points: Iterable[ControlPoint]) -> None:
self.inventories: Dict[ControlPoint, ControlPointAircraftInventory] = {
cp: ControlPointAircraftInventory(cp) for cp in control_points
@@ -100,8 +101,8 @@ class GlobalAircraftInventory:
inventory.add_aircraft(aircraft, count)
def for_control_point(
- self,
- control_point: ControlPoint) -> ControlPointAircraftInventory:
+ self, control_point: ControlPoint
+ ) -> ControlPointAircraftInventory:
"""Returns the inventory specific to the given control point."""
return self.inventories[control_point]
diff --git a/game/models/destroyed_units.py b/game/models/destroyed_units.py
index ade75cc4..7d0de042 100644
--- a/game/models/destroyed_units.py
+++ b/game/models/destroyed_units.py
@@ -7,8 +7,7 @@ class DestroyedUnit:
y: int
name: str
- def __init__(self, x , y, name):
+ def __init__(self, x, y, name):
self.x = x
self.y = y
self.name = name
-
diff --git a/game/models/frontline_data.py b/game/models/frontline_data.py
index 586ebd58..f60d5ccd 100644
--- a/game/models/frontline_data.py
+++ b/game/models/frontline_data.py
@@ -6,7 +6,7 @@ class FrontlineData:
This Data structure will store information about an existing frontline
"""
- def __init__(self, from_cp:ControlPoint, to_cp: ControlPoint):
+ def __init__(self, from_cp: ControlPoint, to_cp: ControlPoint):
self.to_cp = to_cp
self.from_cp = from_cp
self.enemy_units_position = []
diff --git a/game/models/game_stats.py b/game/models/game_stats.py
index e6d628f4..a4d8e623 100644
--- a/game/models/game_stats.py
+++ b/game/models/game_stats.py
@@ -1,5 +1,6 @@
from typing import List
+
class FactionTurnMetadata:
"""
Store metadata about a faction
@@ -20,8 +21,8 @@ class GameTurnMetadata:
Store metadata about a game turn
"""
- allied_units:FactionTurnMetadata
- enemy_units:FactionTurnMetadata
+ allied_units: FactionTurnMetadata
+ enemy_units: FactionTurnMetadata
def __init__(self):
self.allied_units = FactionTurnMetadata()
@@ -53,4 +54,3 @@ class GameStats:
turn_data.enemy_units.vehicles_count += sum(cp.base.armor.values())
self.data_per_turn.append(turn_data)
-
diff --git a/game/navmesh.py b/game/navmesh.py
index c1ac6ab0..bcef8191 100644
--- a/game/navmesh.py
+++ b/game/navmesh.py
@@ -114,9 +114,11 @@ class NavMesh:
return self.travel_cost(a, b)
@staticmethod
- def reconstruct_path(came_from: Dict[NavPoint, Optional[NavPoint]],
- origin: NavPoint,
- destination: NavPoint) -> List[Point]:
+ def reconstruct_path(
+ came_from: Dict[NavPoint, Optional[NavPoint]],
+ origin: NavPoint,
+ destination: NavPoint,
+ ) -> List[Point]:
current = destination
path: List[Point] = []
while current != origin:
@@ -141,16 +143,14 @@ class NavMesh:
raise ValueError(f"Origin point {origin} is outside the navmesh")
destination_poly = self.localize(destination)
if destination_poly is None:
- raise ValueError(
- f"Origin point {destination} is outside the navmesh")
+ raise ValueError(f"Origin point {destination} is outside the navmesh")
return self._shortest_path(
NavPoint(self.dcs_to_shapely_point(origin), origin_poly),
- NavPoint(self.dcs_to_shapely_point(destination), destination_poly)
+ NavPoint(self.dcs_to_shapely_point(destination), destination_poly),
)
- def _shortest_path(self, origin: NavPoint,
- destination: NavPoint) -> List[Point]:
+ def _shortest_path(self, origin: NavPoint, destination: NavPoint) -> List[Point]:
# Adapted from
# https://www.redblobgames.com/pathfinding/a-star/implementation.py.
frontier = NavFrontier()
@@ -167,9 +167,7 @@ class NavMesh:
if current.poly == destination.poly:
# Made it to the correct nav poly. Add the leg from the border
# to the target.
- cost = best_known[current] + self.travel_cost(
- current, destination
- )
+ cost = best_known[current] + self.travel_cost(current, destination)
if cost < best_known[destination]:
best_known[destination] = cost
estimated = cost
@@ -185,14 +183,10 @@ class NavMesh:
raise RuntimeError
_, neighbor_point = nearest_points(current.point, boundary)
neighbor_nav = NavPoint(neighbor_point, neighbor)
- cost = best_known[current] + self.travel_cost(
- current, neighbor_nav
- )
+ cost = best_known[current] + self.travel_cost(current, neighbor_nav)
if cost < best_known[neighbor_nav]:
best_known[neighbor_nav] = cost
- estimated = cost + self.travel_heuristic(
- neighbor_nav, destination
- )
+ estimated = cost + self.travel_heuristic(neighbor_nav, destination)
frontier.push(neighbor_nav, estimated)
came_from[neighbor_nav] = current
@@ -209,13 +203,16 @@ class NavMesh:
# threatened airbases at the map edges have room to retreat from the
# threat without running off the navmesh.
return box(*LineString(points).bounds).buffer(
- nautical_miles(100).meters, resolution=1)
+ nautical_miles(100).meters, resolution=1
+ )
@staticmethod
- def create_navpolys(polys: List[Polygon],
- threat_zones: ThreatZones) -> List[NavMeshPoly]:
- return [NavMeshPoly(i, p, threat_zones.threatened(p))
- for i, p in enumerate(polys)]
+ def create_navpolys(
+ polys: List[Polygon], threat_zones: ThreatZones
+ ) -> List[NavMeshPoly]:
+ return [
+ NavMeshPoly(i, p, threat_zones.threatened(p)) for i, p in enumerate(polys)
+ ]
@staticmethod
def associate_neighbors(polys: List[NavMeshPoly]) -> None:
@@ -234,8 +231,7 @@ class NavMesh:
point = (int(x), int(y))
neighbors = {}
for potential_neighbor in points_map[point]:
- intersection = navpoly.poly.intersection(
- potential_neighbor.poly)
+ intersection = navpoly.poly.intersection(potential_neighbor.poly)
if not intersection.is_empty:
potential_neighbor.neighbors[navpoly] = intersection
neighbors[potential_neighbor] = intersection
@@ -243,8 +239,9 @@ class NavMesh:
points_map[point].add(navpoly)
@classmethod
- def from_threat_zones(cls, threat_zones: ThreatZones,
- theater: ConflictTheater) -> NavMesh:
+ def from_threat_zones(
+ cls, threat_zones: ThreatZones, theater: ConflictTheater
+ ) -> NavMesh:
# Simplify the threat poly to reduce the number of nav zones. Increase
# the size of the zone and then simplify it with the buffer size as the
# error margin. This will create a simpler poly around the threat zone.
diff --git a/game/operation/operation.py b/game/operation/operation.py
index 98aea571..fc190510 100644
--- a/game/operation/operation.py
+++ b/game/operation/operation.py
@@ -41,6 +41,7 @@ if TYPE_CHECKING:
class Operation:
"""Static class for managing the final Mission generation"""
+
current_mission = None # type: Mission
airgen = None # type: AircraftConflictGenerator
triggersgen = None # type: TriggersGenerator
@@ -84,7 +85,7 @@ class Operation:
cls.game.enemy_name,
cls.game.player_country,
cls.game.enemy_country,
- frontline.position
+ frontline.position,
)
@classmethod
@@ -93,7 +94,7 @@ class Operation:
player_cp, enemy_cp = cls.game.theater.closest_opposing_control_points()
mid_point = player_cp.position.point_from_heading(
player_cp.position.heading_between_point(enemy_cp.position),
- player_cp.position.distance_to_point(enemy_cp.position) / 2
+ player_cp.position.distance_to_point(enemy_cp.position) / 2,
)
return Conflict(
cls.game.theater,
@@ -103,7 +104,7 @@ class Operation:
cls.game.enemy_name,
cls.game.player_country,
cls.game.enemy_country,
- mid_point
+ mid_point,
)
@classmethod
@@ -118,9 +119,11 @@ class Operation:
p_country = cls.game.player_country
e_country = cls.game.enemy_country
cls.current_mission.coalition["blue"].add_country(
- country_dict[db.country_id_from_name(p_country)]())
+ country_dict[db.country_id_from_name(p_country)]()
+ )
cls.current_mission.coalition["red"].add_country(
- country_dict[db.country_id_from_name(e_country)]())
+ country_dict[db.country_id_from_name(e_country)]()
+ )
@classmethod
def inject_lua_trigger(cls, contents: str, comment: str) -> None:
@@ -133,12 +136,11 @@ class Operation:
cls.plugin_scripts.append(mnemonic)
@classmethod
- def inject_plugin_script(cls, plugin_mnemonic: str, script: str,
- script_mnemonic: str) -> None:
+ def inject_plugin_script(
+ cls, plugin_mnemonic: str, script: str, script_mnemonic: str
+ ) -> None:
if script_mnemonic in cls.plugin_scripts:
- logging.debug(
- f"Skipping already loaded {script} for {plugin_mnemonic}"
- )
+ logging.debug(f"Skipping already loaded {script} for {plugin_mnemonic}")
else:
cls.plugin_scripts.append(script_mnemonic)
@@ -146,15 +148,12 @@ class Operation:
script_path = Path(plugin_path, script)
if not script_path.exists():
- logging.error(
- f"Cannot find {script_path} for plugin {plugin_mnemonic}"
- )
+ logging.error(f"Cannot find {script_path} for plugin {plugin_mnemonic}")
return
trigger = TriggerStart(comment=f"Load {script_mnemonic}")
filename = script_path.resolve()
- fileref = cls.current_mission.map_resource.add_resource_file(
- filename)
+ fileref = cls.current_mission.map_resource.add_resource_file(filename)
trigger.add_action(DoScriptFile(fileref))
cls.current_mission.triggerrules.triggers.append(trigger)
@@ -166,11 +165,10 @@ class Operation:
jtacs: List[JtacInfo],
airgen: AircraftConflictGenerator,
):
- """Generates subscribed MissionInfoGenerator objects (currently kneeboards and briefings)
- """
+ """Generates subscribed MissionInfoGenerator objects (currently kneeboards and briefings)"""
gens: List[MissionInfoGenerator] = [
KneeboardGenerator(cls.current_mission, cls.game),
- BriefingGenerator(cls.current_mission, cls.game)
+ BriefingGenerator(cls.current_mission, cls.game),
]
for gen in gens:
for dynamic_runway in groundobjectgen.runways.values():
@@ -208,8 +206,9 @@ class Operation:
cls.radio_registry.reserve(frequency)
@classmethod
- def assign_channels_to_flights(cls, flights: List[FlightData],
- air_support: AirSupport) -> None:
+ def assign_channels_to_flights(
+ cls, flights: List[FlightData], air_support: AirSupport
+ ) -> None:
"""Assigns preset radio channels for client flights."""
for flight in flights:
if not flight.client_units:
@@ -217,8 +216,7 @@ class Operation:
cls.assign_channels_to_flight(flight, air_support)
@staticmethod
- def assign_channels_to_flight(flight: FlightData,
- air_support: AirSupport) -> None:
+ def assign_channels_to_flight(flight: FlightData, air_support: AirSupport) -> None:
"""Assigns preset radio channels for a client flight."""
airframe = flight.aircraft_type
@@ -234,7 +232,9 @@ class Operation:
)
@classmethod
- def _create_tacan_registry(cls, unique_map_frequencies: Set[RadioFrequency]) -> None:
+ def _create_tacan_registry(
+ cls, unique_map_frequencies: Set[RadioFrequency]
+ ) -> None:
"""
Dedup beacon/radio frequencies, since some maps have some frequencies
used multiple times.
@@ -246,13 +246,14 @@ class Operation:
unique_map_frequencies.add(beacon.frequency)
if beacon.is_tacan:
if beacon.channel is None:
- logging.error(
- f"TACAN beacon has no channel: {beacon.callsign}")
+ logging.error(f"TACAN beacon has no channel: {beacon.callsign}")
else:
cls.tacan_registry.reserve(beacon.tacan_channel)
@classmethod
- def _create_radio_registry(cls, unique_map_frequencies: Set[RadioFrequency]) -> None:
+ def _create_radio_registry(
+ cls, unique_map_frequencies: Set[RadioFrequency]
+ ) -> None:
cls.radio_registry = RadioRegistry()
for data in AIRFIELD_DATA.values():
if data.theater == cls.game.theater.terrain.name and data.atc:
@@ -270,7 +271,7 @@ class Operation:
cls.game,
cls.radio_registry,
cls.tacan_registry,
- cls.unit_map
+ cls.unit_map,
)
cls.groundobjectgen.generate()
@@ -284,10 +285,13 @@ class Operation:
continue
pos = Point(d["x"], d["z"])
- if utype is not None and not cls.game.position_culled(pos) and cls.game.settings.perf_destroyed_units:
+ if (
+ utype is not None
+ and not cls.game.position_culled(pos)
+ and cls.game.settings.perf_destroyed_units
+ ):
cls.current_mission.static_group(
- country=cls.current_mission.country(
- cls.game.player_country),
+ country=cls.current_mission.country(cls.game.player_country),
name="",
_type=utype,
hidden=True,
@@ -302,13 +306,13 @@ class Operation:
cls.create_unit_map()
cls.create_radio_registries()
# Set mission time and weather conditions.
- EnvironmentGenerator(cls.current_mission,
- cls.game.conditions).generate()
+ EnvironmentGenerator(cls.current_mission, cls.game.conditions).generate()
cls._generate_ground_units()
cls._generate_destroyed_units()
cls._generate_air_units()
- cls.assign_channels_to_flights(cls.airgen.flights,
- cls.airsupportgen.air_support)
+ cls.assign_channels_to_flights(
+ cls.airgen.flights, cls.airsupportgen.air_support
+ )
cls._generate_ground_conflicts()
# Triggers
@@ -317,14 +321,16 @@ class Operation:
# Setup combined arms parameters
cls.current_mission.groundControl.pilot_can_control_vehicles = cls.ca_slots > 0
- if cls.game.player_country in [country.name for country in cls.current_mission.coalition["blue"].countries.values()]:
+ if cls.game.player_country in [
+ country.name
+ for country in cls.current_mission.coalition["blue"].countries.values()
+ ]:
cls.current_mission.groundControl.blue_tactical_commander = cls.ca_slots
else:
cls.current_mission.groundControl.red_tactical_commander = cls.ca_slots
# Options
- forcedoptionsgen = ForcedOptionsGenerator(
- cls.current_mission, cls.game)
+ forcedoptionsgen = ForcedOptionsGenerator(cls.current_mission, cls.game)
forcedoptionsgen.generate()
# Generate Visuals Smoke Effects
@@ -341,13 +347,11 @@ class Operation:
plugin.inject_scripts(cls)
plugin.inject_configuration(cls)
- cls.assign_channels_to_flights(cls.airgen.flights,
- cls.airsupportgen.air_support)
+ cls.assign_channels_to_flights(
+ cls.airgen.flights, cls.airsupportgen.air_support
+ )
cls.notify_info_generators(
- cls.groundobjectgen,
- cls.airsupportgen,
- cls.jtacs,
- cls.airgen
+ cls.groundobjectgen, cls.airsupportgen, cls.jtacs, cls.airgen
)
cls.reset_naming_ids()
return cls.unit_map
@@ -359,29 +363,38 @@ class Operation:
# Air Support (Tanker & Awacs)
assert cls.radio_registry and cls.tacan_registry
cls.airsupportgen = AirSupportConflictGenerator(
- cls.current_mission, cls.air_conflict(), cls.game, cls.radio_registry,
- cls.tacan_registry)
+ cls.current_mission,
+ cls.air_conflict(),
+ cls.game,
+ cls.radio_registry,
+ cls.tacan_registry,
+ )
cls.airsupportgen.generate()
# Generate Aircraft Activity on the map
cls.airgen = AircraftConflictGenerator(
- cls.current_mission, cls.game.settings, cls.game,
- cls.radio_registry, cls.unit_map)
+ cls.current_mission,
+ cls.game.settings,
+ cls.game,
+ cls.radio_registry,
+ cls.unit_map,
+ )
cls.airgen.clear_parking_slots()
cls.airgen.generate_flights(
cls.current_mission.country(cls.game.player_country),
cls.game.blue_ato,
- cls.groundobjectgen.runways
+ cls.groundobjectgen.runways,
)
cls.airgen.generate_flights(
cls.current_mission.country(cls.game.enemy_country),
cls.game.red_ato,
- cls.groundobjectgen.runways
+ cls.groundobjectgen.runways,
)
cls.airgen.spawn_unused_aircraft(
cls.current_mission.country(cls.game.player_country),
- cls.current_mission.country(cls.game.enemy_country))
+ cls.current_mission.country(cls.game.enemy_country),
+ )
@classmethod
def _generate_ground_conflicts(cls) -> None:
@@ -396,17 +409,19 @@ class Operation:
cls.current_mission.country(cls.game.enemy_country),
player_cp,
enemy_cp,
- cls.game.theater
+ cls.game.theater,
)
# Generate frontline ops
player_gp = cls.game.ground_planners[player_cp.id].units_per_cp[enemy_cp.id]
enemy_gp = cls.game.ground_planners[enemy_cp.id].units_per_cp[player_cp.id]
ground_conflict_gen = GroundConflictGenerator(
cls.current_mission,
- conflict, cls.game,
- player_gp, enemy_gp,
+ conflict,
+ cls.game,
+ player_gp,
+ enemy_gp,
player_cp.stances[enemy_cp.id],
- cls.unit_map
+ cls.unit_map,
)
ground_conflict_gen.generate()
cls.jtacs.extend(ground_conflict_gen.jtacs)
@@ -416,9 +431,12 @@ class Operation:
namegen.reset_numbers()
@classmethod
- def generate_lua(cls, airgen: AircraftConflictGenerator,
- airsupportgen: AirSupportConflictGenerator,
- jtacs: List[JtacInfo]) -> None:
+ def generate_lua(
+ cls,
+ airgen: AircraftConflictGenerator,
+ airsupportgen: AirSupportConflictGenerator,
+ jtacs: List[JtacInfo],
+ ) -> None:
# TODO: Refactor this
luaData = {
"AircraftCarriers": {},
@@ -434,7 +452,7 @@ class Operation:
"callsign": tanker.callsign,
"variant": tanker.variant,
"radio": tanker.freq.mhz,
- "tacan": str(tanker.tacan.number) + tanker.tacan.band.name
+ "tacan": str(tanker.tacan.number) + tanker.tacan.band.name,
}
if airsupportgen.air_support.awacs:
@@ -442,7 +460,7 @@ class Operation:
luaData["AWACs"][awacs.callsign] = {
"dcsGroupName": awacs.dcsGroupName,
"callsign": awacs.callsign,
- "radio": awacs.freq.mhz
+ "radio": awacs.freq.mhz,
}
for jtac in jtacs:
@@ -451,14 +469,16 @@ class Operation:
"callsign": jtac.callsign,
"zone": jtac.region,
"dcsUnit": jtac.unit_name,
- "laserCode": jtac.code
+ "laserCode": jtac.code,
}
for flight in airgen.flights:
- if flight.friendly and flight.flight_type in [FlightType.ANTISHIP,
- FlightType.DEAD,
- FlightType.SEAD,
- FlightType.STRIKE]:
+ if flight.friendly and flight.flight_type in [
+ FlightType.ANTISHIP,
+ FlightType.DEAD,
+ FlightType.SEAD,
+ FlightType.STRIKE,
+ ]:
flightType = str(flight.flight_type)
flightTarget = flight.package.target
if flightTarget:
@@ -466,23 +486,27 @@ class Operation:
flightTargetType = None
if isinstance(flightTarget, TheaterGroundObject):
flightTargetName = flightTarget.obj_name
- flightTargetType = flightType + \
- f" TGT ({flightTarget.category})"
- elif hasattr(flightTarget, 'name'):
+ flightTargetType = (
+ flightType + f" TGT ({flightTarget.category})"
+ )
+ elif hasattr(flightTarget, "name"):
flightTargetName = flightTarget.name
flightTargetType = flightType + " TGT (Airbase)"
luaData["TargetPoints"][flightTargetName] = {
"name": flightTargetName,
"type": flightTargetType,
- "position": {"x": flightTarget.position.x,
- "y": flightTarget.position.y}
+ "position": {
+ "x": flightTarget.position.x,
+ "y": flightTarget.position.y,
+ },
}
# set a LUA table with data from Liberation that we want to set
# at the moment it contains Liberation's install path, and an overridable definition for the JTACAutoLase function
# later, we'll add data about the units and points having been generated, in order to facilitate the configuration of the plugin lua scripts
state_location = "[[" + os.path.abspath(".") + "]]"
- lua = """
+ lua = (
+ """
-- setting configuration table
env.info("DCSLiberation|: setting configuration table")
@@ -490,9 +514,12 @@ class Operation:
dcsLiberation = {}
-- the base location for state.json; if non-existent, it'll be replaced with LIBERATION_EXPORT_DIR, TEMP, or DCS working directory
- dcsLiberation.installPath=""" + state_location + """
+ dcsLiberation.installPath="""
+ + state_location
+ + """
"""
+ )
# Process the tankers
lua += """
diff --git a/game/persistency.py b/game/persistency.py
index 38bd5550..8e15ece3 100644
--- a/game/persistency.py
+++ b/game/persistency.py
@@ -67,4 +67,3 @@ def autosave(game) -> bool:
except Exception:
logging.exception("Could not save game")
return False
-
diff --git a/game/plugins/luaplugin.py b/game/plugins/luaplugin.py
index f14d9e08..b58446a9 100644
--- a/game/plugins/luaplugin.py
+++ b/game/plugins/luaplugin.py
@@ -14,9 +14,9 @@ if TYPE_CHECKING:
class LuaPluginWorkOrder:
-
- def __init__(self, parent_mnemonic: str, filename: str, mnemonic: str,
- disable: bool) -> None:
+ def __init__(
+ self, parent_mnemonic: str, filename: str, mnemonic: str, disable: bool
+ ) -> None:
self.parent_mnemonic = parent_mnemonic
self.filename = filename
self.mnemonic = mnemonic
@@ -26,8 +26,9 @@ class LuaPluginWorkOrder:
if self.disable:
operation.bypass_plugin_script(self.mnemonic)
else:
- operation.inject_plugin_script(self.parent_mnemonic, self.filename,
- self.mnemonic)
+ operation.inject_plugin_script(
+ self.parent_mnemonic, self.filename, self.mnemonic
+ )
class PluginSettings:
@@ -45,8 +46,7 @@ class PluginSettings:
# Plugin options are saved in the game's Settings, but it's possible for
# plugins to change across loads. If new plugins are added or new
# options added to those plugins, initialize the new settings.
- self.settings.initialize_plugin_option(self.identifier,
- self.enabled_by_default)
+ self.settings.initialize_plugin_option(self.identifier, self.enabled_by_default)
@property
def enabled(self) -> bool:
@@ -57,8 +57,7 @@ class PluginSettings:
class LuaPluginOption(PluginSettings):
- def __init__(self, identifier: str, name: str,
- enabled_by_default: bool) -> None:
+ def __init__(self, identifier: str, name: str, enabled_by_default: bool) -> None:
super().__init__(identifier, enabled_by_default)
self.name = name
@@ -80,24 +79,34 @@ class LuaPluginDefinition:
options = []
for option in data.get("specificOptions"):
option_id = option["mnemonic"]
- options.append(LuaPluginOption(
- identifier=f"{name}.{option_id}",
- name=option.get("nameInUI", name),
- enabled_by_default=option.get("defaultValue")
- ))
+ options.append(
+ LuaPluginOption(
+ identifier=f"{name}.{option_id}",
+ name=option.get("nameInUI", name),
+ enabled_by_default=option.get("defaultValue"),
+ )
+ )
work_orders = []
for work_order in data.get("scriptsWorkOrders"):
- work_orders.append(LuaPluginWorkOrder(
- name, work_order.get("file"), work_order["mnemonic"],
- work_order.get("disable", False)
- ))
+ work_orders.append(
+ LuaPluginWorkOrder(
+ name,
+ work_order.get("file"),
+ work_order["mnemonic"],
+ work_order.get("disable", False),
+ )
+ )
config_work_orders = []
for work_order in data.get("configurationWorkOrders"):
- config_work_orders.append(LuaPluginWorkOrder(
- name, work_order.get("file"), work_order["mnemonic"],
- work_order.get("disable", False)
- ))
+ config_work_orders.append(
+ LuaPluginWorkOrder(
+ name,
+ work_order.get("file"),
+ work_order["mnemonic"],
+ work_order.get("disable", False),
+ )
+ )
return cls(
identifier=name,
@@ -106,16 +115,14 @@ class LuaPluginDefinition:
enabled_by_default=data.get("defaultValue", False),
options=options,
work_orders=work_orders,
- config_work_orders=config_work_orders
+ config_work_orders=config_work_orders,
)
class LuaPlugin(PluginSettings):
-
def __init__(self, definition: LuaPluginDefinition) -> None:
self.definition = definition
- super().__init__(self.definition.identifier,
- self.definition.enabled_by_default)
+ super().__init__(self.definition.identifier, self.definition.enabled_by_default)
@property
def name(self) -> str:
@@ -155,12 +162,12 @@ class LuaPlugin(PluginSettings):
for option in self.options:
enabled = str(option.enabled).lower()
name = option.identifier
- option_decls.append(
- f" dcsLiberation.plugins.{name} = {enabled}")
+ option_decls.append(f" dcsLiberation.plugins.{name} = {enabled}")
joined_options = "\n".join(option_decls)
- lua = textwrap.dedent(f"""\
+ lua = textwrap.dedent(
+ f"""\
-- {self.identifier} plugin configuration.
if dcsLiberation then
@@ -171,10 +178,10 @@ class LuaPlugin(PluginSettings):
{joined_options}
end
- """)
+ """
+ )
- operation.inject_lua_trigger(
- lua, f"{self.identifier} plugin configuration")
+ operation.inject_lua_trigger(lua, f"{self.identifier} plugin configuration")
for work_order in self.definition.config_work_orders:
work_order.work(operation)
diff --git a/game/plugins/manager.py b/game/plugins/manager.py
index 19b87118..7b6eabba 100644
--- a/game/plugins/manager.py
+++ b/game/plugins/manager.py
@@ -27,7 +27,8 @@ class LuaPluginManager:
if not plugin_path.exists():
raise RuntimeError(
f"Invalid plugin configuration: required plugin {name} "
- f"does not exist at {plugin_path}")
+ f"does not exist at {plugin_path}"
+ )
logging.info(f"Loading plugin {name} from {plugin_path}")
plugin = LuaPlugin.from_json(name, plugin_path)
if plugin is not None:
diff --git a/game/procurement.py b/game/procurement.py
index 0122ab59..0ff83155 100644
--- a/game/procurement.py
+++ b/game/procurement.py
@@ -35,9 +35,16 @@ class AircraftProcurementRequest:
class ProcurementAi:
- def __init__(self, game: Game, for_player: bool, faction: Faction,
- manage_runways: bool, manage_front_line: bool,
- manage_aircraft: bool, front_line_budget_share: float) -> None:
+ def __init__(
+ self,
+ game: Game,
+ for_player: bool,
+ faction: Faction,
+ manage_runways: bool,
+ manage_front_line: bool,
+ manage_aircraft: bool,
+ front_line_budget_share: float,
+ ) -> None:
if front_line_budget_share > 1.0:
raise ValueError
@@ -51,8 +58,8 @@ class ProcurementAi:
self.threat_zones = self.game.threat_zone_for(not self.is_player)
def spend_budget(
- self, budget: float,
- aircraft_requests: List[AircraftProcurementRequest]) -> float:
+ self, budget: float, aircraft_requests: List[AircraftProcurementRequest]
+ ) -> float:
if self.manage_runways:
budget = self.repair_runways(budget)
if self.manage_front_line:
@@ -100,25 +107,30 @@ class ProcurementAi:
budget -= db.RUNWAY_REPAIR_COST
if self.is_player:
self.game.message(
- "OPFOR has begun repairing the runway at "
- f"{control_point}"
+ "OPFOR has begun repairing the runway at " f"{control_point}"
)
else:
self.game.message(
- "We have begun repairing the runway at "
- f"{control_point}"
+ "We have begun repairing the runway at " f"{control_point}"
)
return budget
def random_affordable_ground_unit(
- self, budget: float,
- cp: ControlPoint) -> Optional[Type[VehicleType]]:
- affordable_units = [u for u in self.faction.frontline_units + self.faction.artillery_units if
- db.PRICES[u] <= budget]
+ self, budget: float, cp: ControlPoint
+ ) -> Optional[Type[VehicleType]]:
+ affordable_units = [
+ u
+ for u in self.faction.frontline_units + self.faction.artillery_units
+ if db.PRICES[u] <= budget
+ ]
- total_number_aa = cp.base.total_frontline_aa + cp.pending_frontline_aa_deliveries_count
- total_non_aa = cp.base.total_armor + cp.pending_deliveries_count - total_number_aa
- max_aa = math.ceil(total_non_aa/8)
+ total_number_aa = (
+ cp.base.total_frontline_aa + cp.pending_frontline_aa_deliveries_count
+ )
+ total_non_aa = (
+ cp.base.total_armor + cp.pending_deliveries_count - total_number_aa
+ )
+ max_aa = math.ceil(total_non_aa / 8)
# Limit the number of AA units the AI will buy
if not total_number_aa < max_aa:
@@ -150,8 +162,12 @@ class ProcurementAi:
return budget
def _affordable_aircraft_of_types(
- self, types: List[Type[FlyingType]], airbase: ControlPoint,
- number: int, max_price: float) -> Optional[Type[FlyingType]]:
+ self,
+ types: List[Type[FlyingType]],
+ airbase: ControlPoint,
+ number: int,
+ max_price: float,
+ ) -> Optional[Type[FlyingType]]:
best_choice: Optional[Type[FlyingType]] = None
for unit in [u for u in self.faction.aircrafts if u in types]:
if db.PRICES[unit] * number > max_price:
@@ -168,15 +184,15 @@ class ProcurementAi:
return best_choice
def affordable_aircraft_for(
- self, request: AircraftProcurementRequest,
- airbase: ControlPoint, budget: float) -> Optional[Type[FlyingType]]:
+ self, request: AircraftProcurementRequest, airbase: ControlPoint, budget: float
+ ) -> Optional[Type[FlyingType]]:
return self._affordable_aircraft_of_types(
- aircraft_for_task(request.task_capability),
- airbase, request.number, budget)
+ aircraft_for_task(request.task_capability), airbase, request.number, budget
+ )
def purchase_aircraft(
- self, budget: float,
- aircraft_requests: List[AircraftProcurementRequest]) -> float:
+ self, budget: float, aircraft_requests: List[AircraftProcurementRequest]
+ ) -> float:
for request in aircraft_requests:
for airbase in self.best_airbases_for(request):
unit = self.affordable_aircraft_for(request, airbase, budget)
@@ -201,11 +217,9 @@ class ProcurementAi:
return self.game.theater.enemy_points()
def best_airbases_for(
- self,
- request: AircraftProcurementRequest) -> Iterator[ControlPoint]:
- distance_cache = ObjectiveDistanceCache.get_closest_airfields(
- request.near
- )
+ self, request: AircraftProcurementRequest
+ ) -> Iterator[ControlPoint]:
+ distance_cache = ObjectiveDistanceCache.get_closest_airfields(request.near)
threatened = []
for cp in distance_cache.airfields_within(request.range):
if not cp.is_friendly(self.is_player):
diff --git a/game/settings.py b/game/settings.py
index d5872e91..366fe613 100644
--- a/game/settings.py
+++ b/game/settings.py
@@ -58,8 +58,7 @@ class Settings:
def plugin_settings_key(identifier: str) -> str:
return f"plugins.{identifier}"
- def initialize_plugin_option(self, identifier: str,
- default_value: bool) -> None:
+ def initialize_plugin_option(self, identifier: str, default_value: bool) -> None:
try:
self.plugin_option(identifier)
except KeyError:
diff --git a/game/theater/base.py b/game/theater/base.py
index 28fd5666..7ad7e762 100644
--- a/game/theater/base.py
+++ b/game/theater/base.py
@@ -22,7 +22,6 @@ BASE_MIN_STRENGTH = 0
class Base:
-
def __init__(self):
self.aircraft: Dict[Type[FlyingType], int] = {}
self.armor: Dict[Type[VehicleType], int] = {}
@@ -57,23 +56,43 @@ class Base:
return sum(self.aa.values())
def total_units(self, task: Task) -> int:
- return sum([c for t, c in itertools.chain(self.aircraft.items(), self.armor.items(), self.aa.items()) if t in db.UNIT_BY_TASK[task]])
+ return sum(
+ [
+ c
+ for t, c in itertools.chain(
+ self.aircraft.items(), self.armor.items(), self.aa.items()
+ )
+ if t in db.UNIT_BY_TASK[task]
+ ]
+ )
def total_units_of_type(self, unit_type) -> int:
- return sum([c for t, c in itertools.chain(self.aircraft.items(), self.armor.items(), self.aa.items()) if t == unit_type])
+ return sum(
+ [
+ c
+ for t, c in itertools.chain(
+ self.aircraft.items(), self.armor.items(), self.aa.items()
+ )
+ if t == unit_type
+ ]
+ )
@property
def all_units(self):
- return itertools.chain(self.aircraft.items(), self.armor.items(), self.aa.items())
+ return itertools.chain(
+ self.aircraft.items(), self.armor.items(), self.aa.items()
+ )
- def _find_best_unit(self, available_units: Dict[UnitType, int],
- for_type: Task, count: int) -> Dict[UnitType, int]:
+ def _find_best_unit(
+ self, available_units: Dict[UnitType, int], for_type: Task, count: int
+ ) -> Dict[UnitType, int]:
if count <= 0:
logging.warning("{}: no units for {}".format(self, for_type))
return {}
- sorted_units = [key for key in available_units if
- key in db.UNIT_BY_TASK[for_type]]
+ sorted_units = [
+ key for key in available_units if key in db.UNIT_BY_TASK[for_type]
+ ]
sorted_units.sort(key=lambda x: db.PRICES[x], reverse=True)
result: Dict[UnitType, int] = {}
@@ -94,14 +113,18 @@ class Base:
logging.info("{} for {} ({}): {}".format(self, for_type, count, result))
return result
- def _find_best_planes(self, for_type: Task, count: int) -> typing.Dict[FlyingType, int]:
+ def _find_best_planes(
+ self, for_type: Task, count: int
+ ) -> typing.Dict[FlyingType, int]:
return self._find_best_unit(self.aircraft, for_type, count)
def _find_best_armor(self, for_type: Task, count: int) -> typing.Dict[Armor, int]:
return self._find_best_unit(self.armor, for_type, count)
def append_commision_points(self, for_type, points: float) -> int:
- self.commision_points[for_type] = self.commision_points.get(for_type, 0) + points
+ self.commision_points[for_type] = (
+ self.commision_points.get(for_type, 0) + points
+ )
points = self.commision_points[for_type]
if points >= 1:
self.commision_points[for_type] = points - math.floor(points)
@@ -110,7 +133,9 @@ class Base:
return 0
def filter_units(self, applicable_units: typing.Collection):
- self.aircraft = {k: v for k, v in self.aircraft.items() if k in applicable_units}
+ self.aircraft = {
+ k: v for k, v in self.aircraft.items() if k in applicable_units
+ }
self.armor = {k: v for k, v in self.armor.items() if k in applicable_units}
def commision_units(self, units: typing.Dict[typing.Any, int]):
@@ -149,7 +174,7 @@ class Base:
if unit_type not in target_array:
print("Base didn't find event type {}".format(unit_type))
continue
-
+
target_array[unit_type] = max(target_array[unit_type] - count, 0)
if target_array[unit_type] == 0:
del target_array[unit_type]
@@ -166,12 +191,20 @@ class Base:
def scramble_count(self, multiplier: float, task: Task = None) -> int:
if task:
- count = sum([v for k, v in self.aircraft.items() if db.unit_task(k) == task])
+ count = sum(
+ [v for k, v in self.aircraft.items() if db.unit_task(k) == task]
+ )
else:
count = self.total_aircraft
count = int(math.ceil(count * PLANES_SCRAMBLE_FACTOR * self.strength))
- return min(min(max(count, PLANES_SCRAMBLE_MIN_BASE), int(PLANES_SCRAMBLE_MAX_BASE * multiplier)), count)
+ return min(
+ min(
+ max(count, PLANES_SCRAMBLE_MIN_BASE),
+ int(PLANES_SCRAMBLE_MAX_BASE * multiplier),
+ ),
+ count,
+ )
def assemble_count(self):
return int(self.total_armor * 0.5)
@@ -202,4 +235,8 @@ class Base:
return self._find_best_armor(PinpointStrike, count)
def assemble_aa(self, count=None) -> typing.Dict[AirDefence, int]:
- return self._find_best_unit(self.aa, AirDefence, count and min(count, self.total_aa) or self.assemble_aa_count())
+ return self._find_best_unit(
+ self.aa,
+ AirDefence,
+ count and min(count, self.total_aa) or self.assemble_aa_count(),
+ )
diff --git a/game/theater/conflicttheater.py b/game/theater/conflicttheater.py
index 419f216e..5004de81 100644
--- a/game/theater/conflicttheater.py
+++ b/game/theater/conflicttheater.py
@@ -71,6 +71,7 @@ IMPORTANCE_HIGH = 1.4
FRONTLINE_MIN_CP_DISTANCE = 5000
+
def pairwise(iterable):
"""
itertools recipe
@@ -156,7 +157,8 @@ class MizCampaignLoader:
def country(self, blue: bool) -> Country:
country = self.mission.country(
- self.BLUE_COUNTRY.name if blue else self.RED_COUNTRY.name)
+ self.BLUE_COUNTRY.name if blue else self.RED_COUNTRY.name
+ )
# Should be guaranteed because we initialized them.
assert country
return country
@@ -183,7 +185,7 @@ class MizCampaignLoader:
for group in self.country(blue).ship_group:
if group.units[0].type == self.LHA_UNIT_TYPE:
yield group
-
+
def fobs(self, blue: bool) -> Iterator[VehicleGroup]:
for group in self.country(blue).vehicle_group:
if group.units[0].type == self.FOB_UNIT_TYPE:
@@ -253,22 +255,23 @@ class MizCampaignLoader:
for blue in (False, True):
for group in self.off_map_spawns(blue):
- control_point = OffMapSpawn(next(self.control_point_id),
- str(group.name), group.position)
+ control_point = OffMapSpawn(
+ next(self.control_point_id), str(group.name), group.position
+ )
control_point.captured = blue
control_point.captured_invert = group.late_activation
control_points[control_point.id] = control_point
for group in self.carriers(blue):
# TODO: Name the carrier.
control_point = Carrier(
- "carrier", group.position, next(self.control_point_id))
+ "carrier", group.position, next(self.control_point_id)
+ )
control_point.captured = blue
control_point.captured_invert = group.late_activation
control_points[control_point.id] = control_point
for group in self.lhas(blue):
# TODO: Name the LHA.
- control_point = Lha(
- "lha", group.position, next(self.control_point_id))
+ control_point = Lha("lha", group.position, next(self.control_point_id))
control_point.captured = blue
control_point.captured_invert = group.late_activation
control_points[control_point.id] = control_point
@@ -297,24 +300,24 @@ class MizCampaignLoader:
# final waypoint at the destination CP. Intermediate waypoints
# define the curve of the front line.
waypoints = [p.position for p in group.points]
- origin = self.theater.closest_control_point(waypoints[0])
+ origin = self.theater.closest_control_point(waypoints[0])
if origin is None:
raise RuntimeError(
- f"No control point near the first waypoint of {group.name}")
+ f"No control point near the first waypoint of {group.name}"
+ )
destination = self.theater.closest_control_point(waypoints[-1])
if destination is None:
raise RuntimeError(
- f"No control point near the final waypoint of {group.name}")
+ f"No control point near the final waypoint of {group.name}"
+ )
# Snap the begin and end points to the control points.
waypoints[0] = origin.position
waypoints[-1] = destination.position
front_line_id = f"{origin.id}|{destination.id}"
front_lines[front_line_id] = ComplexFrontLine(origin, waypoints)
- self.control_points[origin.id].connect(
- self.control_points[destination.id])
- self.control_points[destination.id].connect(
- self.control_points[origin.id])
+ self.control_points[origin.id].connect(self.control_points[destination.id])
+ self.control_points[destination.id].connect(self.control_points[origin.id])
return front_lines
def objective_info(self, group: Group) -> Tuple[ControlPoint, Distance]:
@@ -328,8 +331,7 @@ class MizCampaignLoader:
if distance < self.BASE_DEFENSE_RADIUS:
closest.preset_locations.base_garrisons.append(group.position)
else:
- logging.warning(
- f"Found garrison unit too far from base: {group.name}")
+ logging.warning(f"Found garrison unit too far from base: {group.name}")
for group in self.sams:
closest, distance = self.objective_info(group)
@@ -344,8 +346,7 @@ class MizCampaignLoader:
for group in self.offshore_strike_targets:
closest, distance = self.objective_info(group)
- closest.preset_locations.offshore_strike_locations.append(
- group.position)
+ closest.preset_locations.offshore_strike_locations.append(group.position)
for group in self.ships:
closest, distance = self.objective_info(group)
@@ -361,15 +362,11 @@ class MizCampaignLoader:
for group in self.required_long_range_sams:
closest, distance = self.objective_info(group)
- closest.preset_locations.required_long_range_sams.append(
- group.position
- )
+ closest.preset_locations.required_long_range_sams.append(group.position)
for group in self.required_medium_range_sams:
closest, distance = self.objective_info(group)
- closest.preset_locations.required_medium_range_sams.append(
- group.position
- )
+ closest.preset_locations.required_medium_range_sams.append(group.position)
def populate_theater(self) -> None:
for control_point in self.control_points.values():
@@ -423,8 +420,9 @@ class ConflictTheater:
logging.warning("Replacing existing frontline data")
self._frontline_data = data
- def add_controlpoint(self, point: ControlPoint,
- connected_to: Optional[List[ControlPoint]] = None):
+ def add_controlpoint(
+ self, point: ControlPoint, connected_to: Optional[List[ControlPoint]] = None
+ ):
if connected_to is None:
connected_to = []
for connected_point in connected_to:
@@ -486,8 +484,8 @@ class ConflictTheater:
for inclusion_zone in self.landmap.inclusion_zones:
nearest_pair = ops.nearest_points(point, inclusion_zone)
nearest_points.append(nearest_pair[1])
- min_distance = point.distance(nearest_points[0]) # type: geometry.Point
- nearest_point = nearest_points[0] # type: geometry.Point
+ min_distance = point.distance(nearest_points[0]) # type: geometry.Point
+ nearest_point = nearest_points[0] # type: geometry.Point
for pt in nearest_points[1:]:
distance = point.distance(pt)
if distance < min_distance:
@@ -498,7 +496,7 @@ class ConflictTheater:
nearest_point = Point(nearest_point.x, nearest_point.y)
new_point = point.point_from_heading(
point.heading_between_point(nearest_point),
- point.distance_to_point(nearest_point) + extend_dist
+ point.distance_to_point(nearest_point) + extend_dist,
)
return new_point
@@ -512,7 +510,9 @@ class ConflictTheater:
def conflicts(self, from_player=True) -> Iterator[FrontLine]:
for cp in [x for x in self.controlpoints if x.captured == from_player]:
- for connected_point in [x for x in cp.connected_points if x.captured != from_player]:
+ for connected_point in [
+ x for x in cp.connected_points if x.captured != from_player
+ ]:
yield FrontLine(cp, connected_point, self)
def enemy_points(self) -> List[ControlPoint]:
@@ -547,7 +547,7 @@ class ConflictTheater:
closest = conflict
closest_distance = distance
return closest
-
+
def closest_opposing_control_points(self) -> Tuple[ControlPoint, ControlPoint]:
"""
Returns a tuple of the two nearest opposing ControlPoints in theater.
@@ -567,17 +567,22 @@ class ConflictTheater:
distances[cp.id] = dist
closest_cp_id = min(distances, key=distances.get) # type: ignore
- all_cp_min_distances[(control_point.id, closest_cp_id)] = distances[closest_cp_id]
+ all_cp_min_distances[(control_point.id, closest_cp_id)] = distances[
+ closest_cp_id
+ ]
closest_opposing_cps = [
self.find_control_point_by_id(i)
- for i
- in min(all_cp_min_distances, key=all_cp_min_distances.get) # type: ignore
- ] # type: List[ControlPoint]
+ for i in min(
+ all_cp_min_distances, key=all_cp_min_distances.get
+ ) # type: ignore
+ ] # type: List[ControlPoint]
assert len(closest_opposing_cps) == 2
if closest_opposing_cps[0].captured:
return cast(Tuple[ControlPoint, ControlPoint], tuple(closest_opposing_cps))
else:
- return cast(Tuple[ControlPoint, ControlPoint], tuple(reversed(closest_opposing_cps)))
+ return cast(
+ Tuple[ControlPoint, ControlPoint], tuple(reversed(closest_opposing_cps))
+ )
def find_control_point_by_id(self, id: int) -> ControlPoint:
for i in self.controlpoints:
@@ -613,7 +618,7 @@ class ConflictTheater:
cp.captured_invert = False
return cp
-
+
@staticmethod
def from_json(directory: Path, data: Dict[str, Any]) -> ConflictTheater:
theaters = {
@@ -649,7 +654,7 @@ class ConflictTheater:
cps[l[1]].connect(cps[l[0]])
return t
-
+
class CaucasusTheater(ConflictTheater):
terrain = caucasus.Caucasus()
@@ -672,8 +677,7 @@ class PersianGulfTheater(ConflictTheater):
terrain = persiangulf.PersianGulf()
overview_image = "persiangulf.gif"
reference_points = (
- ReferencePoint(persiangulf.Jiroft_Airport.position,
- Point(1692, 1343)),
+ ReferencePoint(persiangulf.Jiroft_Airport.position, Point(1692, 1343)),
ReferencePoint(persiangulf.Liwa_Airbase.position, Point(358, 3238)),
)
landmap = load_landmap("resources\\gulflandmap.p")
@@ -722,7 +726,7 @@ class TheChannelTheater(ConflictTheater):
overview_image = "thechannel.gif"
reference_points = (
ReferencePoint(thechannel.Abbeville_Drucat.position, Point(2005, 2390)),
- ReferencePoint(thechannel.Detling.position, Point(706, 382))
+ ReferencePoint(thechannel.Detling.position, Point(706, 382)),
)
landmap = load_landmap("resources\\channellandmap.p")
daytime_map = {
@@ -791,7 +795,7 @@ class FrontLine(MissionTarget):
self,
control_point_a: ControlPoint,
control_point_b: ControlPoint,
- theater: ConflictTheater
+ theater: ConflictTheater,
) -> None:
self.control_point_a = control_point_a
self.control_point_b = control_point_b
@@ -935,10 +939,9 @@ class FrontLine(MissionTarget):
)
)
-
@staticmethod
def load_json_frontlines(
- theater: ConflictTheater
+ theater: ConflictTheater,
) -> Optional[Dict[str, ComplexFrontLine]]:
"""Load complex frontlines from json"""
try:
diff --git a/game/theater/controlpoint.py b/game/theater/controlpoint.py
index 66a534f6..90bae500 100644
--- a/game/theater/controlpoint.py
+++ b/game/theater/controlpoint.py
@@ -231,10 +231,17 @@ class ControlPoint(MissionTarget, ABC):
# TODO: Only airbases have IDs.
# TODO: has_frontline is only reasonable for airbases.
# TODO: cptype is obsolete.
- def __init__(self, cp_id: int, name: str, position: Point,
- at: db.StartingPosition, size: int,
- importance: float, has_frontline=True,
- cptype=ControlPointType.AIRBASE):
+ def __init__(
+ self,
+ cp_id: int,
+ name: str,
+ position: Point,
+ at: db.StartingPosition,
+ size: int,
+ importance: float,
+ has_frontline=True,
+ cptype=ControlPointType.AIRBASE,
+ ):
super().__init__(name, position)
# TODO: Should be Airbase specific.
self.id = cp_id
@@ -257,17 +264,17 @@ class ControlPoint(MissionTarget, ABC):
# TODO: Should be Airbase specific.
self.stances: Dict[int, CombatStance] = {}
from ..event import UnitsDeliveryEvent
+
self.pending_unit_deliveries = UnitsDeliveryEvent(self)
self.target_position: Optional[Point] = None
-
+
def __repr__(self):
return f"<{__class__}: {self.name}>"
@property
def ground_objects(self) -> List[TheaterGroundObject]:
- return list(
- itertools.chain(self.connected_objectives, self.base_defenses))
+ return list(itertools.chain(self.connected_objectives, self.base_defenses))
@property
@abstractmethod
@@ -342,15 +349,18 @@ class ControlPoint(MissionTarget, ABC):
Get the carrier group name if the airbase is a carrier
:return: Carrier group name
"""
- if self.cptype in [ControlPointType.AIRCRAFT_CARRIER_GROUP,
- ControlPointType.LHA_GROUP]:
+ if self.cptype in [
+ ControlPointType.AIRCRAFT_CARRIER_GROUP,
+ ControlPointType.LHA_GROUP,
+ ]:
for g in self.ground_objects:
if g.dcs_identifier == "CARRIER":
for group in g.groups:
for u in group.units:
if db.unit_type_from_name(u.type) in [
- CVN_74_John_C__Stennis,
- CV_1143_5_Admiral_Kuznetsov]:
+ CVN_74_John_C__Stennis,
+ CV_1143_5_Admiral_Kuznetsov,
+ ]:
return group.name
elif g.dcs_identifier == "LHA":
for group in g.groups:
@@ -379,17 +389,15 @@ class ControlPoint(MissionTarget, ABC):
if isinstance(base_defense, EwrGroundObject):
self.preset_locations.ewrs.append(base_defense.position)
elif isinstance(base_defense, SamGroundObject):
- self.preset_locations.base_air_defense.append(
- base_defense.position)
+ self.preset_locations.base_air_defense.append(base_defense.position)
elif isinstance(base_defense, VehicleGroupGroundObject):
- self.preset_locations.base_garrisons.append(
- base_defense.position)
+ self.preset_locations.base_garrisons.append(base_defense.position)
else:
logging.error(
"Could not determine preset location type for "
- f"{base_defense}. Assuming garrison type.")
- self.preset_locations.base_garrisons.append(
- base_defense.position)
+ f"{base_defense}. Assuming garrison type."
+ )
+ self.preset_locations.base_garrisons.append(base_defense.position)
self.base_defenses = []
def capture_equipment(self, game: Game) -> None:
@@ -398,15 +406,18 @@ class ControlPoint(MissionTarget, ABC):
game.adjust_budget(total, player=not self.captured)
game.message(
f"{self.name} is not connected to any friendly points. Ground "
- f"vehicles have been captured and sold for ${total}M.")
+ f"vehicles have been captured and sold for ${total}M."
+ )
def retreat_ground_units(self, game: Game):
# When there are multiple valid destinations, deliver units to whichever
# base is least defended first. The closest approximation of unit
# strength we have is price
- destinations = [GroundUnitDestination(cp)
- for cp in self.connected_points
- if cp.captured == self.captured]
+ destinations = [
+ GroundUnitDestination(cp)
+ for cp in self.connected_points
+ if cp.captured == self.captured
+ ]
if not destinations:
self.capture_equipment(game)
return
@@ -419,8 +430,9 @@ class ControlPoint(MissionTarget, ABC):
destination.control_point.base.commision_units({unit_type: 1})
destination = heapq.heappushpop(destinations, destination)
- def capture_aircraft(self, game: Game, airframe: Type[FlyingType],
- count: int) -> None:
+ def capture_aircraft(
+ self, game: Game, airframe: Type[FlyingType], count: int
+ ) -> None:
try:
value = PRICES[airframe] * count
except KeyError:
@@ -431,11 +443,12 @@ class ControlPoint(MissionTarget, ABC):
game.message(
f"No valid retreat destination in range of {self.name} for "
f"{airframe.id}. {count} aircraft have been captured and sold for "
- f"${value}M.")
+ f"${value}M."
+ )
def aircraft_retreat_destination(
- self, game: Game,
- airframe: Type[FlyingType]) -> Optional[ControlPoint]:
+ self, game: Game, airframe: Type[FlyingType]
+ ) -> Optional[ControlPoint]:
closest = ObjectiveDistanceCache.get_closest_airfields(self)
# TODO: Should be airframe dependent.
max_retreat_distance = nautical_miles(200)
@@ -451,8 +464,9 @@ class ControlPoint(MissionTarget, ABC):
return airbase
return None
- def _retreat_air_units(self, game: Game, airframe: Type[FlyingType],
- count: int) -> None:
+ def _retreat_air_units(
+ self, game: Game, airframe: Type[FlyingType], count: int
+ ) -> None:
while count:
logging.debug(f"Retreating {count} {airframe.id} from {self.name}")
destination = self.aircraft_retreat_destination(game, airframe)
@@ -485,6 +499,7 @@ class ControlPoint(MissionTarget, ABC):
self.clear_base_defenses()
from .start_generator import BaseDefenseGenerator
+
BaseDefenseGenerator(game, self).generate()
@abstractmethod
@@ -514,16 +529,19 @@ class ControlPoint(MissionTarget, ABC):
if issubclass(unit_bought, FlyingType):
on_order += self.pending_unit_deliveries.units[unit_bought]
- return PendingOccupancy(self.base.total_aircraft, on_order,
- self.aircraft_transferring(game))
+ return PendingOccupancy(
+ self.base.total_aircraft, on_order, self.aircraft_transferring(game)
+ )
def unclaimed_parking(self, game: Game) -> int:
- return (self.total_aircraft_parking -
- self.expected_aircraft_next_turn(game).total)
+ return (
+ self.total_aircraft_parking - self.expected_aircraft_next_turn(game).total
+ )
@abstractmethod
- def active_runway(self, conditions: Conditions,
- dynamic_runways: Dict[str, RunwayData]) -> RunwayData:
+ def active_runway(
+ self, conditions: Conditions, dynamic_runways: Dict[str, RunwayData]
+ ) -> RunwayData:
...
@property
@@ -574,7 +592,13 @@ class ControlPoint(MissionTarget, ABC):
Get number of pending frontline aa units
"""
if self.pending_unit_deliveries:
- return sum([v for k,v in self.pending_unit_deliveries.units.items() if k in TYPE_SHORAD])
+ return sum(
+ [
+ v
+ for k, v in self.pending_unit_deliveries.units.items()
+ if k in TYPE_SHORAD
+ ]
+ )
else:
return 0
@@ -598,9 +622,12 @@ class ControlPoint(MissionTarget, ABC):
continue
on_order += self.pending_unit_deliveries.units[unit_bought]
- return PendingOccupancy(self.base.total_armor, on_order,
- # Ground unit transfers not yet implemented.
- transferring=0)
+ return PendingOccupancy(
+ self.base.total_armor,
+ on_order,
+ # Ground unit transfers not yet implemented.
+ transferring=0,
+ )
@property
def income_per_turn(self) -> int:
@@ -608,16 +635,23 @@ class ControlPoint(MissionTarget, ABC):
@property
def has_active_frontline(self) -> bool:
- return any(
- not c.is_friendly(self.captured) for c in self.connected_points)
+ return any(not c.is_friendly(self.captured) for c in self.connected_points)
+
class Airfield(ControlPoint):
-
- def __init__(self, airport: Airport, size: int,
- importance: float, has_frontline=True):
- super().__init__(airport.id, airport.name, airport.position, airport,
- size, importance, has_frontline,
- cptype=ControlPointType.AIRBASE)
+ def __init__(
+ self, airport: Airport, size: int, importance: float, has_frontline=True
+ ):
+ super().__init__(
+ airport.id,
+ airport.name,
+ airport.position,
+ airport,
+ size,
+ importance,
+ has_frontline,
+ cptype=ControlPointType.AIRBASE,
+ )
self.airport = airport
self._runway_status = RunwayStatus()
@@ -631,6 +665,7 @@ class Airfield(ControlPoint):
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
from gen.flights.flight import FlightType
+
if self.is_friendly(for_player):
yield from [
# TODO: FlightType.INTERCEPTION
@@ -661,8 +696,9 @@ class Airfield(ControlPoint):
def damage_runway(self) -> None:
self.runway_status.damage()
- def active_runway(self, conditions: Conditions,
- dynamic_runways: Dict[str, RunwayData]) -> RunwayData:
+ def active_runway(
+ self, conditions: Conditions, dynamic_runways: Dict[str, RunwayData]
+ ) -> RunwayData:
assigner = RunwayAssigner(conditions)
return assigner.get_preferred_runway(self.airport)
@@ -680,13 +716,13 @@ class Airfield(ControlPoint):
class NavalControlPoint(ControlPoint, ABC):
-
@property
def is_fleet(self) -> bool:
return True
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
from gen.flights.flight import FlightType
+
if self.is_friendly(for_player):
yield from [
# TODO: FlightType.INTERCEPTION
@@ -710,14 +746,17 @@ class NavalControlPoint(ControlPoint, ABC):
for group in g.groups:
for u in group.units:
if db.unit_type_from_name(u.type) in [
- CVN_74_John_C__Stennis, LHA_1_Tarawa,
- CV_1143_5_Admiral_Kuznetsov,
- Type_071_Amphibious_Transport_Dock]:
+ CVN_74_John_C__Stennis,
+ LHA_1_Tarawa,
+ CV_1143_5_Admiral_Kuznetsov,
+ Type_071_Amphibious_Transport_Dock,
+ ]:
return True
return False
- def active_runway(self, conditions: Conditions,
- dynamic_runways: Dict[str, RunwayData]) -> RunwayData:
+ def active_runway(
+ self, conditions: Conditions, dynamic_runways: Dict[str, RunwayData]
+ ) -> RunwayData:
# TODO: Assign TACAN and ICLS earlier so we don't need this.
fallback = RunwayData(self.full_name, runway_heading=0, runway_name="")
return dynamic_runways.get(self.name, fallback)
@@ -740,12 +779,19 @@ class NavalControlPoint(ControlPoint, ABC):
class Carrier(NavalControlPoint):
-
def __init__(self, name: str, at: Point, cp_id: int):
import game.theater.conflicttheater
- super().__init__(cp_id, name, at, at,
- game.theater.conflicttheater.SIZE_SMALL, 1,
- has_frontline=False, cptype=ControlPointType.AIRCRAFT_CARRIER_GROUP)
+
+ super().__init__(
+ cp_id,
+ name,
+ at,
+ at,
+ game.theater.conflicttheater.SIZE_SMALL,
+ 1,
+ has_frontline=False,
+ cptype=ControlPointType.AIRCRAFT_CARRIER_GROUP,
+ )
def capture(self, game: Game, for_player: bool) -> None:
raise RuntimeError("Carriers cannot be captured")
@@ -763,12 +809,19 @@ class Carrier(NavalControlPoint):
class Lha(NavalControlPoint):
-
def __init__(self, name: str, at: Point, cp_id: int):
import game.theater.conflicttheater
- super().__init__(cp_id, name, at, at,
- game.theater.conflicttheater.SIZE_SMALL, 1,
- has_frontline=False, cptype=ControlPointType.LHA_GROUP)
+
+ super().__init__(
+ cp_id,
+ name,
+ at,
+ at,
+ game.theater.conflicttheater.SIZE_SMALL,
+ 1,
+ has_frontline=False,
+ cptype=ControlPointType.LHA_GROUP,
+ )
def capture(self, game: Game, for_player: bool) -> None:
raise RuntimeError("LHAs cannot be captured")
@@ -786,15 +839,22 @@ class Lha(NavalControlPoint):
class OffMapSpawn(ControlPoint):
-
def runway_is_operational(self) -> bool:
return True
def __init__(self, cp_id: int, name: str, position: Point):
from . import IMPORTANCE_MEDIUM, SIZE_REGULAR
- super().__init__(cp_id, name, position, at=position,
- size=SIZE_REGULAR, importance=IMPORTANCE_MEDIUM,
- has_frontline=False, cptype=ControlPointType.OFF_MAP)
+
+ super().__init__(
+ cp_id,
+ name,
+ position,
+ at=position,
+ size=SIZE_REGULAR,
+ importance=IMPORTANCE_MEDIUM,
+ has_frontline=False,
+ cptype=ControlPointType.OFF_MAP,
+ )
def capture(self, game: Game, for_player: bool) -> None:
raise RuntimeError("Off map control points cannot be captured")
@@ -813,8 +873,9 @@ class OffMapSpawn(ControlPoint):
def heading(self) -> int:
return 0
- def active_runway(self, conditions: Conditions,
- dynamic_runways: Dict[str, RunwayData]) -> RunwayData:
+ def active_runway(
+ self, conditions: Conditions, dynamic_runways: Dict[str, RunwayData]
+ ) -> RunwayData:
logging.warning("TODO: Off map spawns have no runways.")
return RunwayData(self.full_name, runway_heading=0, runway_name="")
@@ -828,19 +889,27 @@ class OffMapSpawn(ControlPoint):
class Fob(ControlPoint):
-
def __init__(self, name: str, at: Point, cp_id: int):
import game.theater.conflicttheater
- super().__init__(cp_id, name, at, at,
- game.theater.conflicttheater.SIZE_SMALL, 1,
- has_frontline=True, cptype=ControlPointType.FOB)
+
+ super().__init__(
+ cp_id,
+ name,
+ at,
+ at,
+ game.theater.conflicttheater.SIZE_SMALL,
+ 1,
+ has_frontline=True,
+ cptype=ControlPointType.FOB,
+ )
self.name = name
-
+
def runway_is_operational(self) -> bool:
return False
-
- def active_runway(self, conditions: Conditions,
- dynamic_runways: Dict[str, RunwayData]) -> RunwayData:
+
+ def active_runway(
+ self, conditions: Conditions, dynamic_runways: Dict[str, RunwayData]
+ ) -> RunwayData:
logging.warning("TODO: FOBs have no runways.")
return RunwayData(self.full_name, runway_heading=0, runway_name="")
@@ -850,6 +919,7 @@ class Fob(ControlPoint):
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
from gen.flights.flight import FlightType
+
if self.is_friendly(for_player):
yield from [
FlightType.BARCAP,
diff --git a/game/theater/landmap.py b/game/theater/landmap.py
index c5b422ad..29d551b3 100644
--- a/game/theater/landmap.py
+++ b/game/theater/landmap.py
@@ -46,4 +46,3 @@ def poly_centroid(poly) -> Tuple[float, float]:
x = sum(x_list) / len(poly)
y = sum(y_list) / len(poly)
return (x, y)
-
diff --git a/game/theater/missiontarget.py b/game/theater/missiontarget.py
index c442fe42..9a5fe8cd 100644
--- a/game/theater/missiontarget.py
+++ b/game/theater/missiontarget.py
@@ -29,6 +29,7 @@ class MissionTarget:
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
from gen.flights.flight import FlightType
+
if self.is_friendly(for_player):
yield FlightType.BARCAP
else:
diff --git a/game/theater/start_generator.py b/game/theater/start_generator.py
index 118861d1..39905bb4 100644
--- a/game/theater/start_generator.py
+++ b/game/theater/start_generator.py
@@ -76,9 +76,14 @@ class GeneratorSettings:
class GameGenerator:
- def __init__(self, player: str, enemy: str, theater: ConflictTheater,
- settings: Settings,
- generator_settings: GeneratorSettings) -> None:
+ def __init__(
+ self,
+ player: str,
+ enemy: str,
+ theater: ConflictTheater,
+ settings: Settings,
+ generator_settings: GeneratorSettings,
+ ) -> None:
self.player = player
self.enemy = enemy
self.theater = theater
@@ -96,7 +101,7 @@ class GameGenerator:
start_date=self.generator_settings.start_date,
settings=self.settings,
player_budget=self.generator_settings.player_budget,
- enemy_budget=self.generator_settings.enemy_budget
+ enemy_budget=self.generator_settings.enemy_budget,
)
GroundObjectGenerator(game, self.generator_settings).generate()
@@ -108,7 +113,7 @@ class GameGenerator:
# Auto-capture half the bases if midgame.
if self.generator_settings.midgame:
control_points = self.theater.controlpoints
- for control_point in control_points[:len(control_points) // 2]:
+ for control_point in control_points[: len(control_points) // 2]:
control_point.captured = True
# Remove carrier and lha, invert situation if needed
@@ -140,28 +145,37 @@ class LocationFinder:
self.game = game
self.control_point = control_point
self.miz_data = MizDataLocationFinder.compute_possible_locations(
- game.theater.terrain.name, control_point.full_name)
+ game.theater.terrain.name, control_point.full_name
+ )
def location_for(self, location_type: LocationType) -> Optional[Point]:
position = self.control_point.preset_locations.random_for(location_type)
if position is not None:
return position
- logging.warning(f"No campaign location for %s at %s",
- location_type.value, self.control_point)
+ logging.warning(
+ f"No campaign location for %s at %s",
+ location_type.value,
+ self.control_point,
+ )
position = self.random_from_miz_data(
- location_type == LocationType.OffshoreStrikeTarget)
+ location_type == LocationType.OffshoreStrikeTarget
+ )
if position is not None:
return position
- logging.debug(f"No mizdata location for %s at %s", location_type.value,
- self.control_point)
+ logging.debug(
+ f"No mizdata location for %s at %s", location_type.value, self.control_point
+ )
position = self.random_position(location_type)
if position is not None:
return position
- logging.error(f"Could not find position for %s at %s",
- location_type.value, self.control_point)
+ logging.error(
+ f"Could not find position for %s at %s",
+ location_type.value,
+ self.control_point,
+ )
return None
def random_from_miz_data(self, offshore: bool) -> Optional[Point]:
@@ -177,8 +191,11 @@ class LocationFinder:
def random_position(self, location_type: LocationType) -> Optional[Point]:
# TODO: Flesh out preset locations so we never hit this case.
- logging.warning("Falling back to random location for %s at %s",
- location_type.value, self.control_point)
+ logging.warning(
+ "Falling back to random location for %s at %s",
+ location_type.value,
+ self.control_point,
+ )
is_base_defense = location_type in {
LocationType.BaseAirDefense,
@@ -212,23 +229,28 @@ class LocationFinder:
min_range = 10000
max_range = 40000
- position = self._find_random_position(min_range, max_range,
- on_land, is_base_defense,
- avoid_others)
+ position = self._find_random_position(
+ min_range, max_range, on_land, is_base_defense, avoid_others
+ )
# Retry once, searching a bit further (On some big airbases, 3200 is too
# short (Ex : Incirlik)), but searching farther on every base would be
# problematic, as some base defense units would end up very far away
# from small airfields.
if position is None and is_base_defense:
- position = self._find_random_position(3200, 4800,
- on_land, is_base_defense,
- avoid_others)
+ position = self._find_random_position(
+ 3200, 4800, on_land, is_base_defense, avoid_others
+ )
return position
- def _find_random_position(self, min_range: int, max_range: int,
- on_ground: bool, is_base_defense: bool,
- avoid_others: bool) -> Optional[Point]:
+ def _find_random_position(
+ self,
+ min_range: int,
+ max_range: int,
+ on_ground: bool,
+ is_base_defense: bool,
+ avoid_others: bool,
+ ) -> Optional[Point]:
"""
Find a valid ground object location
:param on_ground: Whether it should be on ground or on sea (True = on
@@ -279,8 +301,12 @@ class LocationFinder:
class ControlPointGroundObjectGenerator:
- def __init__(self, game: Game, generator_settings: GeneratorSettings,
- control_point: ControlPoint) -> None:
+ def __init__(
+ self,
+ game: Game,
+ generator_settings: GeneratorSettings,
+ control_point: ControlPoint,
+ ) -> None:
self.game = game
self.generator_settings = generator_settings
self.control_point = control_point
@@ -321,15 +347,15 @@ class ControlPointGroundObjectGenerator:
self.generate_ship()
def generate_ship(self) -> None:
- point = self.location_finder.location_for(
- LocationType.OffshoreStrikeTarget)
+ point = self.location_finder.location_for(LocationType.OffshoreStrikeTarget)
if point is None:
return
group_id = self.game.next_group_id()
- g = ShipGroundObject(namegen.random_objective_name(), group_id, point,
- self.control_point)
+ g = ShipGroundObject(
+ namegen.random_objective_name(), group_id, point, self.control_point
+ )
group = generate_ship_group(self.game, g, self.faction_name)
g.groups = []
@@ -352,13 +378,15 @@ class CarrierGroundObjectGenerator(ControlPointGroundObjectGenerator):
if not carrier_names:
logging.info(
f"Skipping generation of {self.control_point.name} because "
- f"{self.faction_name} has no carriers")
+ f"{self.faction_name} has no carriers"
+ )
return False
# Create ground object group
group_id = self.game.next_group_id()
- g = CarrierGroundObject(namegen.random_objective_name(), group_id,
- self.control_point)
+ g = CarrierGroundObject(
+ namegen.random_objective_name(), group_id, self.control_point
+ )
group = generate_carrier_group(self.faction_name, self.game, g)
g.groups = []
if group is not None:
@@ -377,13 +405,15 @@ class LhaGroundObjectGenerator(ControlPointGroundObjectGenerator):
if not lha_names:
logging.info(
f"Skipping generation of {self.control_point.name} because "
- f"{self.faction_name} has no LHAs")
+ f"{self.faction_name} has no LHAs"
+ )
return False
# Create ground object group
group_id = self.game.next_group_id()
- g = LhaGroundObject(namegen.random_objective_name(), group_id,
- self.control_point)
+ g = LhaGroundObject(
+ namegen.random_objective_name(), group_id, self.control_point
+ )
group = generate_lha_group(self.faction_name, self.game, g)
g.groups = []
if group is not None:
@@ -422,8 +452,9 @@ class BaseDefenseGenerator:
group_id = self.game.next_group_id()
- g = EwrGroundObject(namegen.random_objective_name(), group_id,
- position, self.control_point)
+ g = EwrGroundObject(
+ namegen.random_objective_name(), group_id, position, self.control_point
+ )
group = generate_ewr_group(self.game, g, self.faction)
if group is None:
@@ -454,28 +485,35 @@ class BaseDefenseGenerator:
group_id = self.game.next_group_id()
- g = VehicleGroupGroundObject(namegen.random_objective_name(), group_id,
- position, self.control_point,
- for_airbase=True)
+ g = VehicleGroupGroundObject(
+ namegen.random_objective_name(),
+ group_id,
+ position,
+ self.control_point,
+ for_airbase=True,
+ )
group = generate_armor_group(self.faction_name, self.game, g)
if group is None:
- logging.error(
- f"Could not generate garrison at {self.control_point}")
+ logging.error(f"Could not generate garrison at {self.control_point}")
return
g.groups.append(group)
self.control_point.base_defenses.append(g)
def generate_sam(self) -> None:
- position = self.location_finder.location_for(
- LocationType.BaseAirDefense)
+ position = self.location_finder.location_for(LocationType.BaseAirDefense)
if position is None:
return
group_id = self.game.next_group_id()
- g = SamGroundObject(namegen.random_objective_name(), group_id,
- position, self.control_point, for_airbase=True)
+ g = SamGroundObject(
+ namegen.random_objective_name(),
+ group_id,
+ position,
+ self.control_point,
+ for_airbase=True,
+ )
groups = generate_anti_air_group(self.game, g, self.faction)
if not groups:
@@ -485,21 +523,25 @@ class BaseDefenseGenerator:
self.control_point.base_defenses.append(g)
def generate_shorad(self) -> None:
- position = self.location_finder.location_for(
- LocationType.BaseAirDefense)
+ position = self.location_finder.location_for(LocationType.BaseAirDefense)
if position is None:
return
group_id = self.game.next_group_id()
- g = SamGroundObject(namegen.random_objective_name(), group_id,
- position, self.control_point, for_airbase=True)
+ g = SamGroundObject(
+ namegen.random_objective_name(),
+ group_id,
+ position,
+ self.control_point,
+ for_airbase=True,
+ )
- groups = generate_anti_air_group(self.game, g, self.faction,
- ranges=[{AirDefenseRange.Short}])
+ groups = generate_anti_air_group(
+ self.game, g, self.faction, ranges=[{AirDefenseRange.Short}]
+ )
if not groups:
- logging.error(
- f"Could not generate SHORAD group at {self.control_point}")
+ logging.error(f"Could not generate SHORAD group at {self.control_point}")
return
g.groups = groups
self.control_point.base_defenses.append(g)
@@ -509,7 +551,7 @@ class FobDefenseGenerator(BaseDefenseGenerator):
def generate(self) -> None:
self.generate_garrison()
self.generate_fob_defenses()
-
+
def generate_fob_defenses(self):
# First group has a 1/2 chance of being a SHORAD,
# and a 1/2 chance of a garrison.
@@ -528,9 +570,13 @@ class FobDefenseGenerator(BaseDefenseGenerator):
class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
- def __init__(self, game: Game, generator_settings: GeneratorSettings,
- control_point: ControlPoint,
- templates: GroundObjectTemplates) -> None:
+ def __init__(
+ self,
+ game: Game,
+ generator_settings: GeneratorSettings,
+ control_point: ControlPoint,
+ templates: GroundObjectTemplates,
+ ) -> None:
super().__init__(game, generator_settings, control_point)
self.templates = templates
@@ -576,18 +622,25 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
"""
presets = self.control_point.preset_locations
for position in presets.required_long_range_sams:
- self.generate_aa_at(position, ranges=[
- {AirDefenseRange.Long},
- {AirDefenseRange.Medium},
- {AirDefenseRange.Short},
- ])
+ self.generate_aa_at(
+ position,
+ ranges=[
+ {AirDefenseRange.Long},
+ {AirDefenseRange.Medium},
+ {AirDefenseRange.Short},
+ ],
+ )
for position in presets.required_medium_range_sams:
- self.generate_aa_at(position, ranges=[
- {AirDefenseRange.Medium},
- {AirDefenseRange.Short},
- ])
- return (len(presets.required_long_range_sams) +
- len(presets.required_medium_range_sams))
+ self.generate_aa_at(
+ position,
+ ranges=[
+ {AirDefenseRange.Medium},
+ {AirDefenseRange.Short},
+ ],
+ )
+ return len(presets.required_long_range_sams) + len(
+ presets.required_medium_range_sams
+ )
def generate_ground_point(self) -> None:
try:
@@ -618,8 +671,15 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
template_point = Point(unit["offset"].x, unit["offset"].y)
g = BuildingGroundObject(
- obj_name, category, group_id, object_id, point + template_point,
- unit["heading"], self.control_point, unit["type"])
+ obj_name,
+ category,
+ group_id,
+ object_id,
+ point + template_point,
+ unit["heading"],
+ self.control_point,
+ unit["type"],
+ )
self.control_point.connected_objectives.append(g)
@@ -627,23 +687,34 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
position = self.location_finder.location_for(LocationType.Sam)
if position is None:
return
- self.generate_aa_at(position, ranges=[
- # Prefer to use proper SAMs, but fall back to SHORADs if needed.
- {AirDefenseRange.Long, AirDefenseRange.Medium},
- {AirDefenseRange.Short},
- ])
+ self.generate_aa_at(
+ position,
+ ranges=[
+ # Prefer to use proper SAMs, but fall back to SHORADs if needed.
+ {AirDefenseRange.Long, AirDefenseRange.Medium},
+ {AirDefenseRange.Short},
+ ],
+ )
def generate_aa_at(
- self, position: Point,
- ranges: Iterable[Set[AirDefenseRange]]) -> None:
+ self, position: Point, ranges: Iterable[Set[AirDefenseRange]]
+ ) -> None:
group_id = self.game.next_group_id()
- g = SamGroundObject(namegen.random_objective_name(), group_id,
- position, self.control_point, for_airbase=False)
+ g = SamGroundObject(
+ namegen.random_objective_name(),
+ group_id,
+ position,
+ self.control_point,
+ for_airbase=False,
+ )
groups = generate_anti_air_group(self.game, g, self.faction, ranges)
if not groups:
- logging.error("Could not generate air defense group for %s at %s",
- g.name, self.control_point)
+ logging.error(
+ "Could not generate air defense group for %s at %s",
+ g.name,
+ self.control_point,
+ )
return
g.groups = groups
self.control_point.connected_objectives.append(g)
@@ -659,8 +730,9 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
group_id = self.game.next_group_id()
- g = MissileSiteGroundObject(namegen.random_objective_name(), group_id,
- position, self.control_point)
+ g = MissileSiteGroundObject(
+ namegen.random_objective_name(), group_id, position, self.control_point
+ )
group = generate_missile_group(self.game, g, self.faction_name)
g.groups = []
if group is not None:
@@ -678,7 +750,7 @@ class FobGroundObjectGenerator(AirbaseGroundObjectGenerator):
def generate_fob(self) -> None:
try:
- category = self.faction.building_set[self.faction.building_set.index('fob')]
+ category = self.faction.building_set[self.faction.building_set.index("fob")]
except IndexError:
logging.exception("Faction has no fob buildings defined")
return
@@ -696,14 +768,21 @@ class FobGroundObjectGenerator(AirbaseGroundObjectGenerator):
template_point = Point(unit["offset"].x, unit["offset"].y)
g = BuildingGroundObject(
- obj_name, category, group_id, object_id, point + template_point,
- unit["heading"], self.control_point, unit["type"], airbase_group=True)
+ obj_name,
+ category,
+ group_id,
+ object_id,
+ point + template_point,
+ unit["heading"],
+ self.control_point,
+ unit["type"],
+ airbase_group=True,
+ )
self.control_point.connected_objectives.append(g)
class GroundObjectGenerator:
- def __init__(self, game: Game,
- generator_settings: GeneratorSettings) -> None:
+ def __init__(self, game: Game, generator_settings: GeneratorSettings) -> None:
self.game = game
self.generator_settings = generator_settings
with open("resources/groundobject_templates.p", "rb") as f:
@@ -721,19 +800,22 @@ class GroundObjectGenerator:
generator: ControlPointGroundObjectGenerator
if control_point.cptype == ControlPointType.AIRCRAFT_CARRIER_GROUP:
generator = CarrierGroundObjectGenerator(
- self.game, self.generator_settings, control_point)
+ self.game, self.generator_settings, control_point
+ )
elif control_point.cptype == ControlPointType.LHA_GROUP:
generator = LhaGroundObjectGenerator(
- self.game, self.generator_settings, control_point)
+ self.game, self.generator_settings, control_point
+ )
elif isinstance(control_point, OffMapSpawn):
generator = NoOpGroundObjectGenerator(
- self.game, self.generator_settings, control_point)
+ self.game, self.generator_settings, control_point
+ )
elif isinstance(control_point, Fob):
generator = FobGroundObjectGenerator(
- self.game, self.generator_settings, control_point,
- self.templates)
+ self.game, self.generator_settings, control_point, self.templates
+ )
else:
generator = AirbaseGroundObjectGenerator(
- self.game, self.generator_settings, control_point,
- self.templates)
+ self.game, self.generator_settings, control_point, self.templates
+ )
return generator.generate()
diff --git a/game/theater/theatergroundobject.py b/game/theater/theatergroundobject.py
index 701f8c9a..1dcfd3d5 100644
--- a/game/theater/theatergroundobject.py
+++ b/game/theater/theatergroundobject.py
@@ -33,7 +33,7 @@ NAME_BY_CATEGORY = {
"ww2bunker": "Bunker",
"village": "Village",
"allycamp": "Camp",
- "EWR":"EWR",
+ "EWR": "EWR",
}
ABBREV_NAME = {
@@ -54,34 +54,59 @@ ABBREV_NAME = {
}
CATEGORY_MAP = {
-
# Special cases
"CARRIER": ["CARRIER"],
"LHA": ["LHA"],
"aa": ["AA"],
-
# Buildings
- "power": ["Workshop A", "Electric power box", "Garage small A", "Farm B", "Repair workshop", "Garage B"],
+ "power": [
+ "Workshop A",
+ "Electric power box",
+ "Garage small A",
+ "Farm B",
+ "Repair workshop",
+ "Garage B",
+ ],
"ware": ["Warehouse", "Hangar A"],
"fuel": ["Tank", "Tank 2", "Tank 3", "Fuel tank"],
"ammo": [".Ammunition depot", "Hangar B"],
- "farp": ["FARP Tent", "FARP Ammo Dump Coating", "FARP Fuel Depot", "FARP Command Post", "FARP CP Blindage"],
+ "farp": [
+ "FARP Tent",
+ "FARP Ammo Dump Coating",
+ "FARP Fuel Depot",
+ "FARP Command Post",
+ "FARP CP Blindage",
+ ],
"fob": ["Bunker 2", "Bunker 1", "Garage small B", ".Command Center", "Barracks 2"],
"factory": ["Tech combine", "Tech hangar A"],
"comms": ["TV tower", "Comms tower M"],
"oil": ["Oil platform"],
"derrick": ["Oil derrick", "Pump station", "Subsidiary structure 2"],
- "ww2bunker": ["Siegfried Line", "Fire Control Bunker", "SK_C_28_naval_gun", "Concertina Wire", "Czech hedgehogs 1"],
+ "ww2bunker": [
+ "Siegfried Line",
+ "Fire Control Bunker",
+ "SK_C_28_naval_gun",
+ "Concertina Wire",
+ "Czech hedgehogs 1",
+ ],
"village": ["Small house 1B", "Small House 1A", "Small warehouse 1"],
"allycamp": [],
}
class TheaterGroundObject(MissionTarget):
-
- def __init__(self, name: str, category: str, group_id: int, position: Point,
- heading: int, control_point: ControlPoint, dcs_identifier: str,
- airbase_group: bool, sea_object: bool) -> None:
+ def __init__(
+ self,
+ name: str,
+ category: str,
+ group_id: int,
+ position: Point,
+ heading: int,
+ control_point: ControlPoint,
+ dcs_identifier: str,
+ airbase_group: bool,
+ sea_object: bool,
+ ) -> None:
super().__init__(name, position)
self.category = category
self.group_id = group_id
@@ -131,6 +156,7 @@ class TheaterGroundObject(MissionTarget):
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
from gen.flights.flight import FlightType
+
if self.is_friendly(for_player):
yield from [
# TODO: FlightType.LOGISTICS
@@ -193,9 +219,18 @@ class TheaterGroundObject(MissionTarget):
class BuildingGroundObject(TheaterGroundObject):
- def __init__(self, name: str, category: str, group_id: int, object_id: int,
- position: Point, heading: int, control_point: ControlPoint,
- dcs_identifier: str, airbase_group=False) -> None:
+ def __init__(
+ self,
+ name: str,
+ category: str,
+ group_id: int,
+ object_id: int,
+ position: Point,
+ heading: int,
+ control_point: ControlPoint,
+ dcs_identifier: str,
+ airbase_group=False,
+ ) -> None:
super().__init__(
name=name,
category=category,
@@ -205,7 +240,7 @@ class BuildingGroundObject(TheaterGroundObject):
control_point=control_point,
dcs_identifier=dcs_identifier,
airbase_group=airbase_group,
- sea_object=False
+ sea_object=False,
)
self.object_id = object_id
# Other TGOs track deadness based on the number of alive units, but
@@ -234,6 +269,7 @@ class BuildingGroundObject(TheaterGroundObject):
class NavalGroundObject(TheaterGroundObject):
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
from gen.flights.flight import FlightType
+
if not self.is_friendly(for_player):
yield FlightType.ANTISHIP
yield from super().mission_types(for_player)
@@ -249,8 +285,7 @@ class GenericCarrierGroundObject(NavalGroundObject):
# TODO: Why is this both a CP and a TGO?
class CarrierGroundObject(GenericCarrierGroundObject):
- def __init__(self, name: str, group_id: int,
- control_point: ControlPoint) -> None:
+ def __init__(self, name: str, group_id: int, control_point: ControlPoint) -> None:
super().__init__(
name=name,
category="CARRIER",
@@ -260,7 +295,7 @@ class CarrierGroundObject(GenericCarrierGroundObject):
control_point=control_point,
dcs_identifier="CARRIER",
airbase_group=True,
- sea_object=True
+ sea_object=True,
)
@property
@@ -272,8 +307,7 @@ class CarrierGroundObject(GenericCarrierGroundObject):
# TODO: Why is this both a CP and a TGO?
class LhaGroundObject(GenericCarrierGroundObject):
- def __init__(self, name: str, group_id: int,
- control_point: ControlPoint) -> None:
+ def __init__(self, name: str, group_id: int, control_point: ControlPoint) -> None:
super().__init__(
name=name,
category="LHA",
@@ -283,7 +317,7 @@ class LhaGroundObject(GenericCarrierGroundObject):
control_point=control_point,
dcs_identifier="LHA",
airbase_group=True,
- sea_object=True
+ sea_object=True,
)
@property
@@ -294,8 +328,9 @@ class LhaGroundObject(GenericCarrierGroundObject):
class MissileSiteGroundObject(TheaterGroundObject):
- def __init__(self, name: str, group_id: int, position: Point,
- control_point: ControlPoint) -> None:
+ def __init__(
+ self, name: str, group_id: int, position: Point, control_point: ControlPoint
+ ) -> None:
super().__init__(
name=name,
category="aa",
@@ -305,7 +340,7 @@ class MissileSiteGroundObject(TheaterGroundObject):
control_point=control_point,
dcs_identifier="AA",
airbase_group=False,
- sea_object=False
+ sea_object=False,
)
@@ -317,8 +352,14 @@ class BaseDefenseGroundObject(TheaterGroundObject):
# This type gets used both for AA sites (SAM, AAA, or SHORAD). These should each
# be split into their own types.
class SamGroundObject(BaseDefenseGroundObject):
- def __init__(self, name: str, group_id: int, position: Point,
- control_point: ControlPoint, for_airbase: bool) -> None:
+ def __init__(
+ self,
+ name: str,
+ group_id: int,
+ position: Point,
+ control_point: ControlPoint,
+ for_airbase: bool,
+ ) -> None:
super().__init__(
name=name,
category="aa",
@@ -328,7 +369,7 @@ class SamGroundObject(BaseDefenseGroundObject):
control_point=control_point,
dcs_identifier="AA",
airbase_group=for_airbase,
- sea_object=False
+ sea_object=False,
)
# Set by the SAM unit generator if the generated group is compatible
# with Skynet.
@@ -345,6 +386,7 @@ class SamGroundObject(BaseDefenseGroundObject):
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
from gen.flights.flight import FlightType
+
if not self.is_friendly(for_player):
yield FlightType.DEAD
yield from super().mission_types(for_player)
@@ -355,8 +397,14 @@ class SamGroundObject(BaseDefenseGroundObject):
class VehicleGroupGroundObject(BaseDefenseGroundObject):
- def __init__(self, name: str, group_id: int, position: Point,
- control_point: ControlPoint, for_airbase: bool) -> None:
+ def __init__(
+ self,
+ name: str,
+ group_id: int,
+ position: Point,
+ control_point: ControlPoint,
+ for_airbase: bool,
+ ) -> None:
super().__init__(
name=name,
category="aa",
@@ -366,13 +414,14 @@ class VehicleGroupGroundObject(BaseDefenseGroundObject):
control_point=control_point,
dcs_identifier="AA",
airbase_group=for_airbase,
- sea_object=False
+ sea_object=False,
)
class EwrGroundObject(BaseDefenseGroundObject):
- def __init__(self, name: str, group_id: int, position: Point,
- control_point: ControlPoint) -> None:
+ def __init__(
+ self, name: str, group_id: int, position: Point, control_point: ControlPoint
+ ) -> None:
super().__init__(
name=name,
category="EWR",
@@ -382,7 +431,7 @@ class EwrGroundObject(BaseDefenseGroundObject):
control_point=control_point,
dcs_identifier="EWR",
airbase_group=True,
- sea_object=False
+ sea_object=False,
)
@property
@@ -392,6 +441,7 @@ class EwrGroundObject(BaseDefenseGroundObject):
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
from gen.flights.flight import FlightType
+
if not self.is_friendly(for_player):
yield FlightType.DEAD
yield from super().mission_types(for_player)
@@ -402,8 +452,9 @@ class EwrGroundObject(BaseDefenseGroundObject):
class ShipGroundObject(NavalGroundObject):
- def __init__(self, name: str, group_id: int, position: Point,
- control_point: ControlPoint) -> None:
+ def __init__(
+ self, name: str, group_id: int, position: Point, control_point: ControlPoint
+ ) -> None:
super().__init__(
name=name,
category="aa",
@@ -413,7 +464,7 @@ class ShipGroundObject(NavalGroundObject):
control_point=control_point,
dcs_identifier="AA",
airbase_group=False,
- sea_object=True
+ sea_object=True,
)
@property
diff --git a/game/threatzones.py b/game/threatzones.py
index 17f4df96..865acf2f 100644
--- a/game/threatzones.py
+++ b/game/threatzones.py
@@ -32,8 +32,9 @@ class ThreatZones:
self.all = unary_union([airbases, air_defenses])
def closest_boundary(self, point: DcsPoint) -> DcsPoint:
- boundary, _ = nearest_points(self.all.boundary,
- self.dcs_to_shapely_point(point))
+ boundary, _ = nearest_points(
+ self.all.boundary, self.dcs_to_shapely_point(point)
+ )
return DcsPoint(boundary.x, boundary.y)
@singledispatchmethod
@@ -49,8 +50,9 @@ class ThreatZones:
return self.all.intersects(self.dcs_to_shapely_point(position))
def path_threatened(self, a: DcsPoint, b: DcsPoint) -> bool:
- return self.threatened(LineString(
- [self.dcs_to_shapely_point(a), self.dcs_to_shapely_point(b)]))
+ return self.threatened(
+ LineString([self.dcs_to_shapely_point(a), self.dcs_to_shapely_point(b)])
+ )
@singledispatchmethod
def threatened_by_aircraft(self, target) -> bool:
@@ -62,9 +64,9 @@ class ThreatZones:
@threatened_by_aircraft.register
def _threatened_by_aircraft_flight(self, flight: Flight) -> bool:
- return self.threatened_by_aircraft(LineString((
- self.dcs_to_shapely_point(p.position) for p in flight.points
- )))
+ return self.threatened_by_aircraft(
+ LineString((self.dcs_to_shapely_point(p.position) for p in flight.points))
+ )
@singledispatchmethod
def threatened_by_air_defense(self, target) -> bool:
@@ -76,13 +78,14 @@ class ThreatZones:
@threatened_by_air_defense.register
def _threatened_by_air_defense_flight(self, flight: Flight) -> bool:
- return self.threatened_by_air_defense(LineString((
- self.dcs_to_shapely_point(p.position) for p in flight.points
- )))
+ return self.threatened_by_air_defense(
+ LineString((self.dcs_to_shapely_point(p.position) for p in flight.points))
+ )
@classmethod
- def closest_enemy_airbase(cls, location: ControlPoint,
- max_distance: Distance) -> Optional[ControlPoint]:
+ def closest_enemy_airbase(
+ cls, location: ControlPoint, max_distance: Distance
+ ) -> Optional[ControlPoint]:
airfields = ObjectiveDistanceCache.get_closest_airfields(location)
for airfield in airfields.airfields_within(max_distance):
if airfield.captured != location.captured:
@@ -90,13 +93,14 @@ class ThreatZones:
return None
@classmethod
- def barcap_threat_range(cls, game: Game,
- control_point: ControlPoint) -> Distance:
+ def barcap_threat_range(cls, game: Game, control_point: ControlPoint) -> Distance:
doctrine = game.faction_for(control_point.captured).doctrine
- cap_threat_range = (doctrine.cap_max_distance_from_cp +
- doctrine.cap_engagement_range)
- opposing_airfield = cls.closest_enemy_airbase(control_point,
- cap_threat_range * 2)
+ cap_threat_range = (
+ doctrine.cap_max_distance_from_cp + doctrine.cap_engagement_range
+ )
+ opposing_airfield = cls.closest_enemy_airbase(
+ control_point, cap_threat_range * 2
+ )
if opposing_airfield is None:
return cap_threat_range
@@ -133,8 +137,7 @@ class ThreatZones:
if control_point.captured != player:
continue
if control_point.runway_is_operational():
- point = ShapelyPoint(control_point.position.x,
- control_point.position.y)
+ point = ShapelyPoint(control_point.position.x, control_point.position.y)
cap_threat_range = cls.barcap_threat_range(game, control_point)
airbases.append(point.buffer(cap_threat_range.meters))
@@ -149,10 +152,9 @@ class ThreatZones:
air_defenses.append(threat_zone)
return cls(
- airbases=unary_union(airbases),
- air_defenses=unary_union(air_defenses)
+ airbases=unary_union(airbases), air_defenses=unary_union(air_defenses)
)
@staticmethod
def dcs_to_shapely_point(point: DcsPoint) -> ShapelyPoint:
- return ShapelyPoint(point.x, point.y)
\ No newline at end of file
+ return ShapelyPoint(point.x, point.y)
diff --git a/game/unitmap.py b/game/unitmap.py
index d8aeaa65..149cba40 100644
--- a/game/unitmap.py
+++ b/game/unitmap.py
@@ -70,15 +70,19 @@ class UnitMap:
raise RuntimeError(f"Unknown unit type: {unit.type}")
if not issubclass(unit_type, VehicleType):
raise RuntimeError(
- f"{name} is a {unit_type.__name__}, expected a VehicleType")
+ f"{name} is a {unit_type.__name__}, expected a VehicleType"
+ )
self.front_line_units[name] = FrontLineUnit(unit_type, origin)
def front_line_unit(self, name: str) -> Optional[FrontLineUnit]:
return self.front_line_units.get(name, None)
- def add_ground_object_units(self, ground_object: TheaterGroundObject,
- persistence_group: Group,
- miz_group: Group) -> None:
+ def add_ground_object_units(
+ self,
+ ground_object: TheaterGroundObject,
+ persistence_group: Group,
+ miz_group: Group,
+ ) -> None:
"""Adds a group associated with a TGO to the unit map.
Args:
@@ -103,13 +107,13 @@ class UnitMap:
if name in self.ground_object_units:
raise RuntimeError(f"Duplicate TGO unit: {name}")
self.ground_object_units[name] = GroundObjectUnit(
- ground_object, persistence_group, persistent_unit)
+ ground_object, persistence_group, persistent_unit
+ )
def ground_object_unit(self, name: str) -> Optional[GroundObjectUnit]:
return self.ground_object_units.get(name, None)
- def add_building(self, ground_object: BuildingGroundObject,
- group: Group) -> None:
+ def add_building(self, ground_object: BuildingGroundObject, group: Group) -> None:
# The actual name is a String (the pydcs translatable string), which
# doesn't define __eq__.
# The name of the initiator in the DCS dead event will have " object"
@@ -119,8 +123,9 @@ class UnitMap:
raise RuntimeError(f"Duplicate TGO unit: {name}")
self.buildings[name] = Building(ground_object)
- def add_fortification(self, ground_object: BuildingGroundObject,
- group: VehicleGroup) -> None:
+ def add_fortification(
+ self, ground_object: BuildingGroundObject, group: VehicleGroup
+ ) -> None:
if len(group.units) != 1:
raise ValueError("Fortification groups must have exactly one unit.")
unit = group.units[0]
diff --git a/game/weather.py b/game/weather.py
index ae9a6fd2..c7d33c39 100644
--- a/game/weather.py
+++ b/game/weather.py
@@ -58,7 +58,7 @@ class Weather:
return None
return Fog(
visibility=meters(random.randint(2500, 5000)),
- thickness=random.randint(100, 500)
+ thickness=random.randint(100, 500),
)
def generate_wind(self) -> WindConditions:
@@ -76,7 +76,7 @@ class Weather:
# Always some wind to make the smoke move a bit.
at_0m=Wind(wind_direction, max(1, base_wind * at_0m_factor)),
at_2000m=Wind(wind_direction, base_wind * at_2000m_factor),
- at_8000m=Wind(wind_direction, base_wind * at_8000m_factor)
+ at_8000m=Wind(wind_direction, base_wind * at_8000m_factor),
)
@staticmethod
@@ -105,7 +105,7 @@ class Cloudy(Weather):
base=self.random_cloud_base(),
density=random.randint(1, 8),
thickness=self.random_cloud_thickness(),
- precipitation=PydcsWeather.Preceptions.None_
+ precipitation=PydcsWeather.Preceptions.None_,
)
def generate_wind(self) -> WindConditions:
@@ -118,7 +118,7 @@ class Raining(Weather):
base=self.random_cloud_base(),
density=random.randint(5, 8),
thickness=self.random_cloud_thickness(),
- precipitation=PydcsWeather.Preceptions.Rain
+ precipitation=PydcsWeather.Preceptions.Rain,
)
def generate_wind(self) -> WindConditions:
@@ -131,7 +131,7 @@ class Thunderstorm(Weather):
base=self.random_cloud_base(),
density=random.randint(9, 10),
thickness=self.random_cloud_thickness(),
- precipitation=PydcsWeather.Preceptions.Thunderstorm
+ precipitation=PydcsWeather.Preceptions.Thunderstorm,
)
def generate_wind(self) -> WindConditions:
@@ -145,20 +145,29 @@ class Conditions:
weather: Weather
@classmethod
- def generate(cls, theater: ConflictTheater, day: datetime.date,
- time_of_day: TimeOfDay, settings: Settings) -> Conditions:
+ def generate(
+ cls,
+ theater: ConflictTheater,
+ day: datetime.date,
+ time_of_day: TimeOfDay,
+ settings: Settings,
+ ) -> Conditions:
return cls(
time_of_day=time_of_day,
start_time=cls.generate_start_time(
theater, day, time_of_day, settings.night_disabled
),
- weather=cls.generate_weather()
+ weather=cls.generate_weather(),
)
@classmethod
- def generate_start_time(cls, theater: ConflictTheater, day: datetime.date,
- time_of_day: TimeOfDay,
- night_disabled: bool) -> datetime.datetime:
+ def generate_start_time(
+ cls,
+ theater: ConflictTheater,
+ day: datetime.date,
+ time_of_day: TimeOfDay,
+ night_disabled: bool,
+ ) -> datetime.datetime:
if night_disabled:
logging.info("Skip Night mission due to user settings")
time_range = {
@@ -181,6 +190,7 @@ class Conditions:
Cloudy: 60,
ClearSkies: 20,
}
- weather_type = random.choices(list(chances.keys()),
- weights=list(chances.values()))[0]
+ weather_type = random.choices(
+ list(chances.keys()), weights=list(chances.values())
+ )[0]
return weather_type()
diff --git a/gen/aircraft.py b/gen/aircraft.py
index 70ab9d67..08744489 100644
--- a/gen/aircraft.py
+++ b/gen/aircraft.py
@@ -129,10 +129,10 @@ HELICOPTER_CHANNEL = MHz(127)
UHF_FALLBACK_CHANNEL = MHz(251)
TARGET_WAYPOINTS = (
- FlightWaypointType.TARGET_GROUP_LOC,
- FlightWaypointType.TARGET_POINT,
- FlightWaypointType.TARGET_SHIP,
- )
+ FlightWaypointType.TARGET_GROUP_LOC,
+ FlightWaypointType.TARGET_POINT,
+ FlightWaypointType.TARGET_SHIP,
+)
# TODO: Get radio information for all the special cases.
def get_fallback_channel(unit_type: UnitType) -> RadioFrequency:
@@ -302,14 +302,23 @@ class FlightData:
joker_fuel: Optional[int]
- def __init__(self, package: Package, country: str, flight_type: FlightType,
- units: List[FlyingUnit], size: int, friendly: bool,
- departure_delay: timedelta, departure: RunwayData,
- arrival: RunwayData, divert: Optional[RunwayData],
- waypoints: List[FlightWaypoint],
- intra_flight_channel: RadioFrequency,
- bingo_fuel: Optional[int],
- joker_fuel: Optional[int]) -> None:
+ def __init__(
+ self,
+ package: Package,
+ country: str,
+ flight_type: FlightType,
+ units: List[FlyingUnit],
+ size: int,
+ friendly: bool,
+ departure_delay: timedelta,
+ departure: RunwayData,
+ arrival: RunwayData,
+ divert: Optional[RunwayData],
+ waypoints: List[FlightWaypoint],
+ intra_flight_channel: RadioFrequency,
+ bingo_fuel: Optional[int],
+ joker_fuel: Optional[int],
+ ) -> None:
self.package = package
self.country = country
self.flight_type = flight_type
@@ -342,13 +351,13 @@ class FlightData:
# Note: pydcs only initializes the radio presets for client slots.
return self.client_units[0].num_radio_channels(radio_id)
- def channel_for(
- self, frequency: RadioFrequency) -> Optional[ChannelAssignment]:
+ def channel_for(self, frequency: RadioFrequency) -> Optional[ChannelAssignment]:
"""Returns the radio and channel number for the given frequency."""
return self.frequency_to_channel_map.get(frequency, None)
- def assign_channel(self, radio_id: int, channel_id: int,
- frequency: RadioFrequency) -> None:
+ def assign_channel(
+ self, radio_id: int, channel_id: int, frequency: RadioFrequency
+ ) -> None:
"""Assigns a preset radio channel to the given frequency."""
for unit in self.client_units:
unit.set_radio_channel_preset(radio_id, channel_id, frequency.mhz)
@@ -365,8 +374,9 @@ class FlightData:
class RadioChannelAllocator:
"""Base class for radio channel allocators."""
- def assign_channels_for_flight(self, flight: FlightData,
- air_support: AirSupport) -> None:
+ def assign_channels_for_flight(
+ self, flight: FlightData, air_support: AirSupport
+ ) -> None:
"""Assigns mission frequencies to preset channels for the flight."""
raise NotImplementedError
@@ -388,11 +398,13 @@ class CommonRadioChannelAllocator(RadioChannelAllocator):
#: index of the panel_radio field of the pydcs.dcs.planes object.
intra_flight_radio_index: Optional[int]
- def assign_channels_for_flight(self, flight: FlightData,
- air_support: AirSupport) -> None:
+ def assign_channels_for_flight(
+ self, flight: FlightData, air_support: AirSupport
+ ) -> None:
if self.intra_flight_radio_index is not None:
flight.assign_channel(
- self.intra_flight_radio_index, 1, flight.intra_flight_channel)
+ self.intra_flight_radio_index, 1, flight.intra_flight_channel
+ )
if self.inter_flight_radio_index is None:
return
@@ -410,26 +422,22 @@ class CommonRadioChannelAllocator(RadioChannelAllocator):
channel_alloc = iter(range(first_channel, last_channel + 1))
if flight.departure.atc is not None:
- flight.assign_channel(radio_id, next(channel_alloc),
- flight.departure.atc)
+ flight.assign_channel(radio_id, next(channel_alloc), flight.departure.atc)
# TODO: If there ever are multiple AWACS, limit to mission relevant.
for awacs in air_support.awacs:
flight.assign_channel(radio_id, next(channel_alloc), awacs.freq)
if flight.arrival != flight.departure and flight.arrival.atc is not None:
- flight.assign_channel(radio_id, next(channel_alloc),
- flight.arrival.atc)
+ flight.assign_channel(radio_id, next(channel_alloc), flight.arrival.atc)
try:
# TODO: Skip incompatible tankers.
for tanker in air_support.tankers:
- flight.assign_channel(
- radio_id, next(channel_alloc), tanker.freq)
+ flight.assign_channel(radio_id, next(channel_alloc), tanker.freq)
if flight.divert is not None and flight.divert.atc is not None:
- flight.assign_channel(radio_id, next(channel_alloc),
- flight.divert.atc)
+ flight.assign_channel(radio_id, next(channel_alloc), flight.divert.atc)
except StopIteration:
# Any remaining channels are nice-to-haves, but not necessary for
# the few aircraft with a small number of channels available.
@@ -440,8 +448,9 @@ class CommonRadioChannelAllocator(RadioChannelAllocator):
class NoOpChannelAllocator(RadioChannelAllocator):
"""Channel allocator for aircraft that don't support preset channels."""
- def assign_channels_for_flight(self, flight: FlightData,
- air_support: AirSupport) -> None:
+ def assign_channels_for_flight(
+ self, flight: FlightData, air_support: AirSupport
+ ) -> None:
pass
@@ -449,8 +458,9 @@ class NoOpChannelAllocator(RadioChannelAllocator):
class FarmerRadioChannelAllocator(RadioChannelAllocator):
"""Preset channel allocator for the MiG-19P."""
- def assign_channels_for_flight(self, flight: FlightData,
- air_support: AirSupport) -> None:
+ def assign_channels_for_flight(
+ self, flight: FlightData, air_support: AirSupport
+ ) -> None:
# The Farmer only has 6 preset channels. It also only has a VHF radio,
# and currently our ATC data and AWACS are only in the UHF band.
radio_id = 1
@@ -463,8 +473,9 @@ class FarmerRadioChannelAllocator(RadioChannelAllocator):
class ViggenRadioChannelAllocator(RadioChannelAllocator):
"""Preset channel allocator for the AJS37."""
- def assign_channels_for_flight(self, flight: FlightData,
- air_support: AirSupport) -> None:
+ def assign_channels_for_flight(
+ self, flight: FlightData, air_support: AirSupport
+ ) -> None:
# The Viggen's preset channels are handled differently from other
# aircraft. The aircraft automatically configures channels for every
# allied flight in the game (including AWACS) and for every airfield. As
@@ -488,8 +499,9 @@ class ViggenRadioChannelAllocator(RadioChannelAllocator):
class SCR522RadioChannelAllocator(RadioChannelAllocator):
"""Preset channel allocator for the SCR522 WW2 radios. (4 channels)"""
- def assign_channels_for_flight(self, flight: FlightData,
- air_support: AirSupport) -> None:
+ def assign_channels_for_flight(
+ self, flight: FlightData, air_support: AirSupport
+ ) -> None:
radio_id = 1
flight.assign_channel(radio_id, 1, flight.intra_flight_channel)
if flight.departure.atc is not None:
@@ -526,9 +538,8 @@ AIRCRAFT_DATA: Dict[str, AircraftData] = {
# VHF for intraflight is not accepted anymore by DCS
# (see https://forums.eagle.ru/showthread.php?p=4499738).
intra_flight_radio=get_radio("AN/ARC-164"),
- channel_allocator=NoOpChannelAllocator()
+ channel_allocator=NoOpChannelAllocator(),
),
-
"AJS37": AircraftData(
# The AJS37 has somewhat unique radio configuration. Two backup radio
# (FR 24) can only operate simultaneously with the main radio in guard
@@ -537,40 +548,33 @@ AIRCRAFT_DATA: Dict[str, AircraftData] = {
inter_flight_radio=get_radio("FR 22"),
intra_flight_radio=get_radio("FR 22"),
channel_allocator=ViggenRadioChannelAllocator(),
- channel_namer=ViggenChannelNamer
+ channel_namer=ViggenChannelNamer,
),
-
"AV8BNA": AircraftData(
inter_flight_radio=get_radio("AN/ARC-210"),
intra_flight_radio=get_radio("AN/ARC-210"),
channel_allocator=CommonRadioChannelAllocator(
- inter_flight_radio_index=2,
- intra_flight_radio_index=1
- )
+ inter_flight_radio_index=2, intra_flight_radio_index=1
+ ),
),
-
"F-14B": AircraftData(
inter_flight_radio=get_radio("AN/ARC-159"),
intra_flight_radio=get_radio("AN/ARC-182"),
channel_allocator=CommonRadioChannelAllocator(
- inter_flight_radio_index=1,
- intra_flight_radio_index=2
+ inter_flight_radio_index=1, intra_flight_radio_index=2
),
- channel_namer=TomcatChannelNamer
+ channel_namer=TomcatChannelNamer,
),
-
"F-16C_50": AircraftData(
inter_flight_radio=get_radio("AN/ARC-164"),
intra_flight_radio=get_radio("AN/ARC-222"),
# COM2 is the AN/ARC-222, which is the VHF radio we want to use for
# intra-flight communication to leave COM1 open for UHF inter-flight.
channel_allocator=CommonRadioChannelAllocator(
- inter_flight_radio_index=1,
- intra_flight_radio_index=2
+ inter_flight_radio_index=1, intra_flight_radio_index=2
),
- channel_namer=ViperChannelNamer
+ channel_namer=ViperChannelNamer,
),
-
"FA-18C_hornet": AircraftData(
inter_flight_radio=get_radio("AN/ARC-210"),
intra_flight_radio=get_radio("AN/ARC-210"),
@@ -579,22 +583,18 @@ AIRCRAFT_DATA: Dict[str, AircraftData] = {
# AN/ARC-210s, radio 1 will be compatible regardless of which frequency
# is assigned, so we must use radio 1 for the intra-flight radio.
channel_allocator=CommonRadioChannelAllocator(
- inter_flight_radio_index=2,
- intra_flight_radio_index=1
- )
+ inter_flight_radio_index=2, intra_flight_radio_index=1
+ ),
),
-
"JF-17": AircraftData(
inter_flight_radio=get_radio("R&S M3AR UHF"),
intra_flight_radio=get_radio("R&S M3AR VHF"),
channel_allocator=CommonRadioChannelAllocator(
- inter_flight_radio_index=1,
- intra_flight_radio_index=1
+ inter_flight_radio_index=1, intra_flight_radio_index=1
),
# Same naming pattern as the Viper, so just reuse that.
- channel_namer=ViperChannelNamer
+ channel_namer=ViperChannelNamer,
),
-
"Ka-50": AircraftData(
inter_flight_radio=get_radio("R-800L1"),
intra_flight_radio=get_radio("R-800L1"),
@@ -603,50 +603,41 @@ AIRCRAFT_DATA: Dict[str, AircraftData] = {
# radios assigned, so no channels to configure.
channel_allocator=NoOpChannelAllocator(),
),
-
"M-2000C": AircraftData(
inter_flight_radio=get_radio("TRT ERA 7000 V/UHF"),
intra_flight_radio=get_radio("TRT ERA 7200 UHF"),
channel_allocator=CommonRadioChannelAllocator(
- inter_flight_radio_index=1,
- intra_flight_radio_index=2
+ inter_flight_radio_index=1, intra_flight_radio_index=2
),
- channel_namer=MirageChannelNamer
+ channel_namer=MirageChannelNamer,
),
-
"MiG-15bis": AircraftData(
inter_flight_radio=get_radio("RSI-6K HF"),
intra_flight_radio=get_radio("RSI-6K HF"),
channel_allocator=NoOpChannelAllocator(),
),
-
"MiG-19P": AircraftData(
inter_flight_radio=get_radio("RSIU-4V"),
intra_flight_radio=get_radio("RSIU-4V"),
channel_allocator=FarmerRadioChannelAllocator(),
- channel_namer=SingleRadioChannelNamer
+ channel_namer=SingleRadioChannelNamer,
),
-
"MiG-21Bis": AircraftData(
inter_flight_radio=get_radio("RSIU-5V"),
intra_flight_radio=get_radio("RSIU-5V"),
channel_allocator=CommonRadioChannelAllocator(
- inter_flight_radio_index=1,
- intra_flight_radio_index=1
+ inter_flight_radio_index=1, intra_flight_radio_index=1
),
channel_namer=SingleRadioChannelNamer,
),
-
"P-51D": AircraftData(
inter_flight_radio=get_radio("SCR522"),
intra_flight_radio=get_radio("SCR522"),
channel_allocator=CommonRadioChannelAllocator(
- inter_flight_radio_index=1,
- intra_flight_radio_index=1
+ inter_flight_radio_index=1, intra_flight_radio_index=1
),
- channel_namer=SCR522ChannelNamer
+ channel_namer=SCR522ChannelNamer,
),
-
"UH-1H": AircraftData(
inter_flight_radio=get_radio("AN/ARC-51BX"),
# Ideally this would use the AN/ARC-131 because that radio is supposed
@@ -654,11 +645,10 @@ AIRCRAFT_DATA: Dict[str, AircraftData] = {
# frequency, nor will it allow the AN/ARC-134.
intra_flight_radio=get_radio("AN/ARC-51BX"),
channel_allocator=CommonRadioChannelAllocator(
- inter_flight_radio_index=1,
- intra_flight_radio_index=1
+ inter_flight_radio_index=1, intra_flight_radio_index=1
),
- channel_namer=HueyChannelNamer
- )
+ channel_namer=HueyChannelNamer,
+ ),
}
AIRCRAFT_DATA["A-10C_2"] = AIRCRAFT_DATA["A-10C"]
AIRCRAFT_DATA["P-51D-30-NA"] = AIRCRAFT_DATA["P-51D"]
@@ -666,8 +656,14 @@ AIRCRAFT_DATA["P-47D-30"] = AIRCRAFT_DATA["P-51D"]
class AircraftConflictGenerator:
- def __init__(self, mission: Mission, settings: Settings, game: Game,
- radio_registry: RadioRegistry, unit_map: UnitMap) -> None:
+ def __init__(
+ self,
+ mission: Mission,
+ settings: Settings,
+ game: Game,
+ radio_registry: RadioRegistry,
+ unit_map: UnitMap,
+ ) -> None:
self.m = mission
self.game = game
self.settings = settings
@@ -701,8 +697,7 @@ class AircraftConflictGenerator:
"""
try:
aircraft_data = AIRCRAFT_DATA[airframe.id]
- return self.radio_registry.alloc_for_radio(
- aircraft_data.intra_flight_radio)
+ return self.radio_registry.alloc_for_radio(aircraft_data.intra_flight_radio)
except KeyError:
return get_fallback_channel(airframe)
@@ -714,9 +709,14 @@ class AircraftConflictGenerator:
return StartType.Cold
return StartType.Warm
- def _setup_group(self, group: FlyingGroup, for_task: Type[Task],
- package: Package, flight: Flight,
- dynamic_runways: Dict[str, RunwayData]) -> None:
+ def _setup_group(
+ self,
+ group: FlyingGroup,
+ for_task: Type[Task],
+ package: Package,
+ flight: Flight,
+ dynamic_runways: Dict[str, RunwayData],
+ ) -> None:
did_load_loadout = False
unit_type = group.units[0].unit_type
@@ -731,11 +731,21 @@ class AircraftConflictGenerator:
group.load_loadout(payload_name)
if not group.units[0].pylons and for_task == RunwayAttack:
if PinpointStrike in db.PLANE_PAYLOAD_OVERRIDES[unit_type]:
- logging.warning("No loadout for \"Runway Attack\" for the {}, defaulting to Strike loadout".format(str(unit_type)))
- payload_name = db.PLANE_PAYLOAD_OVERRIDES[unit_type][PinpointStrike]
+ logging.warning(
+ 'No loadout for "Runway Attack" for the {}, defaulting to Strike loadout'.format(
+ str(unit_type)
+ )
+ )
+ payload_name = db.PLANE_PAYLOAD_OVERRIDES[unit_type][
+ PinpointStrike
+ ]
group.load_loadout(payload_name)
did_load_loadout = True
- logging.info("Loaded overridden payload for {} - {} for task {}".format(unit_type, payload_name, for_task))
+ logging.info(
+ "Loaded overridden payload for {} - {} for task {}".format(
+ unit_type, payload_name, for_task
+ )
+ )
if not did_load_loadout:
group.load_task_default_loadout(for_task)
@@ -770,45 +780,55 @@ class AircraftConflictGenerator:
if unit_type is F_14B:
unit.set_property(F_14B.Properties.INSAlignmentStored.id, True)
- group.points[0].tasks.append(OptReactOnThreat(OptReactOnThreat.Values.EvadeFire))
+ group.points[0].tasks.append(
+ OptReactOnThreat(OptReactOnThreat.Values.EvadeFire)
+ )
channel = self.get_intra_flight_channel(unit_type)
group.set_frequency(channel.mhz)
divert = None
if flight.divert is not None:
- divert = flight.divert.active_runway(self.game.conditions,
- dynamic_runways)
+ divert = flight.divert.active_runway(self.game.conditions, dynamic_runways)
- self.flights.append(FlightData(
- package=package,
- country=faction.country,
- flight_type=flight.flight_type,
- units=group.units,
- size=len(group.units),
- friendly=flight.from_cp.captured,
- # Set later.
- departure_delay=timedelta(),
- departure=flight.departure.active_runway(self.game.conditions,
- dynamic_runways),
- arrival=flight.arrival.active_runway(self.game.conditions,
- dynamic_runways),
- divert=divert,
- # Waypoints are added later, after they've had their TOTs set.
- waypoints=[],
- intra_flight_channel=channel,
- bingo_fuel=flight.flight_plan.bingo_fuel,
- joker_fuel=flight.flight_plan.joker_fuel
- ))
+ self.flights.append(
+ FlightData(
+ package=package,
+ country=faction.country,
+ flight_type=flight.flight_type,
+ units=group.units,
+ size=len(group.units),
+ friendly=flight.from_cp.captured,
+ # Set later.
+ departure_delay=timedelta(),
+ departure=flight.departure.active_runway(
+ self.game.conditions, dynamic_runways
+ ),
+ arrival=flight.arrival.active_runway(
+ self.game.conditions, dynamic_runways
+ ),
+ divert=divert,
+ # Waypoints are added later, after they've had their TOTs set.
+ waypoints=[],
+ intra_flight_channel=channel,
+ bingo_fuel=flight.flight_plan.bingo_fuel,
+ joker_fuel=flight.flight_plan.joker_fuel,
+ )
+ )
# Special case so Su 33 and C101 can take off
if unit_type in [Su_33, C_101EB, C_101CC]:
self.set_reduced_fuel(flight, group, unit_type)
- def _generate_at_airport(self, name: str, side: Country,
- unit_type: Type[FlyingType], count: int,
- start_type: str,
- airport: Optional[Airport] = None) -> FlyingGroup:
+ def _generate_at_airport(
+ self,
+ name: str,
+ side: Country,
+ unit_type: Type[FlyingType],
+ count: int,
+ start_type: str,
+ airport: Optional[Airport] = None,
+ ) -> FlyingGroup:
assert count > 0
logging.info("airgen: {} for {} at {}".format(unit_type, side.id, airport))
@@ -820,10 +840,12 @@ class AircraftConflictGenerator:
maintask=None,
start_type=self._start_type(start_type),
group_size=count,
- parking_slots=None)
+ parking_slots=None,
+ )
- def _generate_inflight(self, name: str, side: Country, flight: Flight,
- origin: ControlPoint) -> FlyingGroup:
+ def _generate_inflight(
+ self, name: str, side: Country, flight: Flight, origin: ControlPoint
+ ) -> FlyingGroup:
assert flight.count > 0
at = origin.position
@@ -841,8 +863,10 @@ class AircraftConflictGenerator:
pos = Point(at.x + random.randint(100, 1000), at.y + random.randint(100, 1000))
logging.info(
- "airgen: {} for {} at {} at {}".format(flight.unit_type, side.id,
- alt, int(speed.kph)))
+ "airgen: {} for {} at {} at {}".format(
+ flight.unit_type, side.id, alt, int(speed.kph)
+ )
+ )
group = self.m.flight_group(
country=side,
name=name,
@@ -852,15 +876,21 @@ class AircraftConflictGenerator:
altitude=alt.meters,
speed=speed.kph,
maintask=None,
- group_size=flight.count)
+ group_size=flight.count,
+ )
group.points[0].alt_type = alt_type
return group
- def _generate_at_group(self, name: str, side: Country,
- unit_type: Type[FlyingType], count: int,
- start_type: str,
- at: Union[ShipGroup, StaticGroup]) -> FlyingGroup:
+ def _generate_at_group(
+ self,
+ name: str,
+ side: Country,
+ unit_type: Type[FlyingType],
+ count: int,
+ start_type: str,
+ at: Union[ShipGroup, StaticGroup],
+ ) -> FlyingGroup:
assert count > 0
logging.info("airgen: {} for {} at unit {}".format(unit_type, side.id, at))
@@ -871,17 +901,22 @@ class AircraftConflictGenerator:
pad_group=at,
maintask=None,
start_type=self._start_type(start_type),
- group_size=count)
+ group_size=count,
+ )
- def _add_radio_waypoint(self, group: FlyingGroup, position,
- altitude: Distance,
- airspeed: int = 600) -> MovingPoint:
+ def _add_radio_waypoint(
+ self, group: FlyingGroup, position, altitude: Distance, airspeed: int = 600
+ ) -> MovingPoint:
point = group.add_waypoint(position, altitude.meters, airspeed)
point.alt_type = "RADIO"
return point
- def _rtb_for(self, group: FlyingGroup, cp: ControlPoint,
- at: Optional[db.StartingPosition] = None):
+ def _rtb_for(
+ self,
+ group: FlyingGroup,
+ cp: ControlPoint,
+ at: Optional[db.StartingPosition] = None,
+ ):
if at is None:
at = cp.at
position = at if isinstance(at, Point) else at.position
@@ -892,8 +927,7 @@ class AircraftConflictGenerator:
tod_location = position.point_from_heading(heading, RTB_DISTANCE)
self._add_radio_waypoint(group, tod_location, last_waypoint.alt)
- destination_waypoint = self._add_radio_waypoint(group, position,
- RTB_ALTITUDE)
+ destination_waypoint = self._add_radio_waypoint(group, position, RTB_ALTITUDE)
if isinstance(at, Airport):
group.land_at(at)
return destination_waypoint
@@ -923,8 +957,7 @@ class AircraftConflictGenerator:
pylon = Pylon.for_aircraft(flight.unit_type, pylon_number)
pylon.equip(group, weapon)
- def _degrade_payload_to_era(self, flight: Flight,
- group: FlyingGroup) -> None:
+ def _degrade_payload_to_era(self, flight: Flight, group: FlyingGroup) -> None:
loadout = dict(group.units[0].pylons)
for pylon_number, clsid in loadout.items():
weapon = Weapon.from_clsid(clsid["CLSID"])
@@ -947,22 +980,23 @@ class AircraftConflictGenerator:
for parking_slot in cp.parking_slots:
parking_slot.unit_id = None
- def generate_flights(self, country, ato: AirTaskingOrder,
- dynamic_runways: Dict[str, RunwayData]) -> None:
+ def generate_flights(
+ self, country, ato: AirTaskingOrder, dynamic_runways: Dict[str, RunwayData]
+ ) -> None:
for package in ato.packages:
if not package.flights:
continue
for flight in package.flights:
logging.info(f"Generating flight: {flight.unit_type}")
- group = self.generate_planned_flight(flight.from_cp, country,
- flight)
+ group = self.generate_planned_flight(flight.from_cp, country, flight)
self.unit_map.add_aircraft(group, flight)
self.setup_flight_group(group, package, flight, dynamic_runways)
self.create_waypoints(group, package, flight)
- def spawn_unused_aircraft(self, player_country: Country,
- enemy_country: Country) -> None:
+ def spawn_unused_aircraft(
+ self, player_country: Country, enemy_country: Country
+ ) -> None:
inventories = self.game.aircraft_inventory.inventories
for control_point, inventory in inventories.items():
if not isinstance(control_point, Airfield):
@@ -977,30 +1011,45 @@ class AircraftConflictGenerator:
for aircraft, available in inventory.all_aircraft:
try:
- self._spawn_unused_at(control_point, country, faction, aircraft,
- available)
+ self._spawn_unused_at(
+ control_point, country, faction, aircraft, available
+ )
except NoParkingSlotError:
# If we run out of parking, stop spawning aircraft.
return
- def _spawn_unused_at(self, control_point: Airfield, country: Country, faction: Faction,
- aircraft: Type[FlyingType], number: int) -> None:
+ def _spawn_unused_at(
+ self,
+ control_point: Airfield,
+ country: Country,
+ faction: Faction,
+ aircraft: Type[FlyingType],
+ number: int,
+ ) -> None:
for _ in range(number):
# Creating a flight even those this isn't a fragged mission lets us
# reuse the existing debriefing code.
# TODO: Special flight type?
- flight = Flight(Package(control_point), faction.country, aircraft, 1,
- FlightType.BARCAP, "Cold", departure=control_point,
- arrival=control_point, divert=None)
+ flight = Flight(
+ Package(control_point),
+ faction.country,
+ aircraft,
+ 1,
+ FlightType.BARCAP,
+ "Cold",
+ departure=control_point,
+ arrival=control_point,
+ divert=None,
+ )
group = self._generate_at_airport(
- name=namegen.next_aircraft_name(country, control_point.id,
- flight),
+ name=namegen.next_aircraft_name(country, control_point.id, flight),
side=country,
unit_type=aircraft,
count=1,
start_type="Cold",
- airport=control_point.airport)
+ airport=control_point.airport,
+ )
if aircraft in faction.liveries_overrides:
livery = random.choice(faction.liveries_overrides[aircraft])
@@ -1010,8 +1059,9 @@ class AircraftConflictGenerator:
group.uncontrolled = True
self.unit_map.add_aircraft(group, flight)
- def set_activation_time(self, flight: Flight, group: FlyingGroup,
- delay: timedelta) -> None:
+ def set_activation_time(
+ self, flight: Flight, group: FlyingGroup, delay: timedelta
+ ) -> None:
# Note: Late activation causes the waypoint TOTs to look *weird* in the
# mission editor. Waypoint times will be relative to the group
# activation time rather than in absolute local time. A flight delayed
@@ -1020,31 +1070,31 @@ class AircraftConflictGenerator:
group.late_activation = True
activation_trigger = TriggerOnce(
- Event.NoEvent, f"FlightLateActivationTrigger{group.id}")
- activation_trigger.add_condition(
- TimeAfter(seconds=int(delay.total_seconds())))
+ Event.NoEvent, f"FlightLateActivationTrigger{group.id}"
+ )
+ activation_trigger.add_condition(TimeAfter(seconds=int(delay.total_seconds())))
self.prevent_spawn_at_hostile_airbase(flight, activation_trigger)
activation_trigger.add_action(ActivateGroup(group.id))
self.m.triggerrules.triggers.append(activation_trigger)
- def set_startup_time(self, flight: Flight, group: FlyingGroup,
- delay: timedelta) -> None:
+ def set_startup_time(
+ self, flight: Flight, group: FlyingGroup, delay: timedelta
+ ) -> None:
# Uncontrolled causes the AI unit to spawn, but not begin startup.
group.uncontrolled = True
- activation_trigger = TriggerOnce(Event.NoEvent,
- f"FlightStartTrigger{group.id}")
- activation_trigger.add_condition(
- TimeAfter(seconds=int(delay.total_seconds())))
+ activation_trigger = TriggerOnce(Event.NoEvent, f"FlightStartTrigger{group.id}")
+ activation_trigger.add_condition(TimeAfter(seconds=int(delay.total_seconds())))
self.prevent_spawn_at_hostile_airbase(flight, activation_trigger)
group.add_trigger_action(StartCommand())
activation_trigger.add_action(AITaskPush(group.id, len(group.tasks)))
self.m.triggerrules.triggers.append(activation_trigger)
- def prevent_spawn_at_hostile_airbase(self, flight: Flight,
- trigger: TriggerRule) -> None:
+ def prevent_spawn_at_hostile_airbase(
+ self, flight: Flight, trigger: TriggerRule
+ ) -> None:
# Prevent delayed flights from spawning at airbases if they were
# captured before they've spawned.
if flight.from_cp.cptype != ControlPointType.AIRBASE:
@@ -1055,18 +1105,15 @@ class AircraftConflictGenerator:
else:
coalition = self.game.get_enemy_coalition_id()
- trigger.add_condition(
- CoalitionHasAirdrome(coalition, flight.from_cp.id))
+ trigger.add_condition(CoalitionHasAirdrome(coalition, flight.from_cp.id))
- def generate_planned_flight(self, cp, country, flight:Flight):
+ def generate_planned_flight(self, cp, country, flight: Flight):
name = namegen.next_aircraft_name(country, cp.id, flight)
try:
if flight.start_type == "In Flight":
group = self._generate_inflight(
- name=name,
- side=country,
- flight=flight,
- origin=cp)
+ name=name, side=country, flight=flight, origin=cp
+ )
elif isinstance(cp, NavalControlPoint):
group_name = cp.get_carrier_group_name()
group = self._generate_at_group(
@@ -1075,34 +1122,39 @@ class AircraftConflictGenerator:
unit_type=flight.unit_type,
count=flight.count,
start_type=flight.start_type,
- at=self.m.find_group(group_name))
+ at=self.m.find_group(group_name),
+ )
else:
if not isinstance(cp, Airfield):
raise RuntimeError(
- f"Attempted to spawn at airfield for non-airfield {cp}")
+ f"Attempted to spawn at airfield for non-airfield {cp}"
+ )
group = self._generate_at_airport(
name=name,
side=country,
unit_type=flight.unit_type,
count=flight.count,
start_type=flight.start_type,
- airport=cp.airport)
+ airport=cp.airport,
+ )
except Exception as e:
# Generated when there is no place on Runway or on Parking Slots
logging.error(e)
- logging.warning("No room on runway or parking slots. Starting from the air.")
+ logging.warning(
+ "No room on runway or parking slots. Starting from the air."
+ )
flight.start_type = "In Flight"
group = self._generate_inflight(
- name=name,
- side=country,
- flight=flight,
- origin=cp)
+ name=name, side=country, flight=flight, origin=cp
+ )
group.points[0].alt = 1500
return group
@staticmethod
- def set_reduced_fuel(flight: Flight, group: FlyingGroup, unit_type: Type[PlaneType]) -> None:
+ def set_reduced_fuel(
+ flight: Flight, group: FlyingGroup, unit_type: Type[PlaneType]
+ ) -> None:
if unit_type is Su_33:
for unit in group.units:
if flight.flight_type is not CAP:
@@ -1117,11 +1169,12 @@ class AircraftConflictGenerator:
@staticmethod
def configure_behavior(
- group: FlyingGroup,
- react_on_threat: Optional[OptReactOnThreat.Values] = None,
- roe: Optional[OptROE.Values] = None,
- rtb_winchester: Optional[OptRTBOnOutOfAmmo.Values] = None,
- restrict_jettison: Optional[bool] = None) -> None:
+ group: FlyingGroup,
+ react_on_threat: Optional[OptReactOnThreat.Values] = None,
+ roe: Optional[OptROE.Values] = None,
+ rtb_winchester: Optional[OptRTBOnOutOfAmmo.Values] = None,
+ restrict_jettison: Optional[bool] = None,
+ ) -> None:
group.points[0].tasks.clear()
if react_on_threat is not None:
group.points[0].tasks.append(OptReactOnThreat(react_on_threat))
@@ -1138,13 +1191,17 @@ class AircraftConflictGenerator:
@staticmethod
def configure_eplrs(group: FlyingGroup, flight: Flight) -> None:
- if hasattr(flight.unit_type, 'eplrs'):
+ if hasattr(flight.unit_type, "eplrs"):
if flight.unit_type.eplrs:
group.points[0].tasks.append(EPLRS(group.id))
- def configure_cap(self, group: FlyingGroup, package: Package,
- flight: Flight,
- dynamic_runways: Dict[str, RunwayData]) -> None:
+ def configure_cap(
+ self,
+ group: FlyingGroup,
+ package: Package,
+ flight: Flight,
+ dynamic_runways: Dict[str, RunwayData],
+ ) -> None:
group.task = CAP.name
self._setup_group(group, CAP, package, flight, dynamic_runways)
@@ -1155,9 +1212,13 @@ class AircraftConflictGenerator:
self.configure_behavior(group, rtb_winchester=ammo_type)
- def configure_sweep(self, group: FlyingGroup, package: Package,
- flight: Flight,
- dynamic_runways: Dict[str, RunwayData]) -> None:
+ def configure_sweep(
+ self,
+ group: FlyingGroup,
+ package: Package,
+ flight: Flight,
+ dynamic_runways: Dict[str, RunwayData],
+ ) -> None:
group.task = FighterSweep.name
self._setup_group(group, FighterSweep, package, flight, dynamic_runways)
@@ -1168,9 +1229,13 @@ class AircraftConflictGenerator:
self.configure_behavior(group, rtb_winchester=ammo_type)
- def configure_cas(self, group: FlyingGroup, package: Package,
- flight: Flight,
- dynamic_runways: Dict[str, RunwayData]) -> None:
+ def configure_cas(
+ self,
+ group: FlyingGroup,
+ package: Package,
+ flight: Flight,
+ dynamic_runways: Dict[str, RunwayData],
+ ) -> None:
group.task = CAS.name
self._setup_group(group, CAS, package, flight, dynamic_runways)
self.configure_behavior(
@@ -1178,11 +1243,16 @@ class AircraftConflictGenerator:
react_on_threat=OptReactOnThreat.Values.EvadeFire,
roe=OptROE.Values.OpenFire,
rtb_winchester=OptRTBOnOutOfAmmo.Values.Unguided,
- restrict_jettison=True)
+ restrict_jettison=True,
+ )
- def configure_dead(self, group: FlyingGroup, package: Package,
- flight: Flight,
- dynamic_runways: Dict[str, RunwayData]) -> None:
+ def configure_dead(
+ self,
+ group: FlyingGroup,
+ package: Package,
+ flight: Flight,
+ dynamic_runways: Dict[str, RunwayData],
+ ) -> None:
group.task = SEAD.name
self._setup_group(group, SEAD, package, flight, dynamic_runways)
self.configure_behavior(
@@ -1190,11 +1260,16 @@ class AircraftConflictGenerator:
react_on_threat=OptReactOnThreat.Values.EvadeFire,
roe=OptROE.Values.OpenFire,
rtb_winchester=OptRTBOnOutOfAmmo.Values.ASM,
- restrict_jettison=True)
+ restrict_jettison=True,
+ )
- def configure_sead(self, group: FlyingGroup, package: Package,
- flight: Flight,
- dynamic_runways: Dict[str, RunwayData]) -> None:
+ def configure_sead(
+ self,
+ group: FlyingGroup,
+ package: Package,
+ flight: Flight,
+ dynamic_runways: Dict[str, RunwayData],
+ ) -> None:
group.task = SEAD.name
self._setup_group(group, SEAD, package, flight, dynamic_runways)
self.configure_behavior(
@@ -1202,75 +1277,106 @@ class AircraftConflictGenerator:
react_on_threat=OptReactOnThreat.Values.EvadeFire,
roe=OptROE.Values.OpenFire,
rtb_winchester=OptRTBOnOutOfAmmo.Values.ASM,
- restrict_jettison=True)
+ restrict_jettison=True,
+ )
- def configure_strike(self, group: FlyingGroup, package: Package,
- flight: Flight,
- dynamic_runways: Dict[str, RunwayData]) -> None:
+ def configure_strike(
+ self,
+ group: FlyingGroup,
+ package: Package,
+ flight: Flight,
+ dynamic_runways: Dict[str, RunwayData],
+ ) -> None:
group.task = GroundAttack.name
self._setup_group(group, GroundAttack, package, flight, dynamic_runways)
self.configure_behavior(
group,
react_on_threat=OptReactOnThreat.Values.EvadeFire,
roe=OptROE.Values.OpenFire,
- restrict_jettison=True)
+ restrict_jettison=True,
+ )
- def configure_anti_ship(self, group: FlyingGroup, package: Package,
- flight: Flight,
- dynamic_runways: Dict[str, RunwayData]) -> None:
+ def configure_anti_ship(
+ self,
+ group: FlyingGroup,
+ package: Package,
+ flight: Flight,
+ dynamic_runways: Dict[str, RunwayData],
+ ) -> None:
group.task = AntishipStrike.name
- self._setup_group(group, AntishipStrike, package, flight,
- dynamic_runways)
+ self._setup_group(group, AntishipStrike, package, flight, dynamic_runways)
self.configure_behavior(
group,
react_on_threat=OptReactOnThreat.Values.EvadeFire,
roe=OptROE.Values.OpenFire,
- restrict_jettison=True)
+ restrict_jettison=True,
+ )
def configure_runway_attack(
- self, group: FlyingGroup, package: Package, flight: Flight,
- dynamic_runways: Dict[str, RunwayData]) -> None:
+ self,
+ group: FlyingGroup,
+ package: Package,
+ flight: Flight,
+ dynamic_runways: Dict[str, RunwayData],
+ ) -> None:
group.task = RunwayAttack.name
self._setup_group(group, RunwayAttack, package, flight, dynamic_runways)
self.configure_behavior(
group,
react_on_threat=OptReactOnThreat.Values.EvadeFire,
roe=OptROE.Values.OpenFire,
- restrict_jettison=True)
+ restrict_jettison=True,
+ )
def configure_oca_strike(
- self, group: FlyingGroup, package: Package, flight: Flight,
- dynamic_runways: Dict[str, RunwayData]) -> None:
+ self,
+ group: FlyingGroup,
+ package: Package,
+ flight: Flight,
+ dynamic_runways: Dict[str, RunwayData],
+ ) -> None:
group.task = CAS.name
self._setup_group(group, CAS, package, flight, dynamic_runways)
self.configure_behavior(
group,
react_on_threat=OptReactOnThreat.Values.EvadeFire,
roe=OptROE.Values.OpenFire,
- restrict_jettison=True)
+ restrict_jettison=True,
+ )
- def configure_escort(self, group: FlyingGroup, package: Package,
- flight: Flight,
- dynamic_runways: Dict[str, RunwayData]) -> None:
+ def configure_escort(
+ self,
+ group: FlyingGroup,
+ package: Package,
+ flight: Flight,
+ dynamic_runways: Dict[str, RunwayData],
+ ) -> None:
# Escort groups are actually given the CAP task so they can perform the
# Search Then Engage task, which we have to use instead of the Escort
# task for the reasons explained in JoinPointBuilder.
group.task = CAP.name
self._setup_group(group, CAP, package, flight, dynamic_runways)
- self.configure_behavior(group, roe=OptROE.Values.OpenFire,
- restrict_jettison=True)
+ self.configure_behavior(
+ group, roe=OptROE.Values.OpenFire, restrict_jettison=True
+ )
- def configure_unknown_task(self, group: FlyingGroup,
- flight: Flight) -> None:
+ def configure_unknown_task(self, group: FlyingGroup, flight: Flight) -> None:
logging.error(f"Unhandled flight type: {flight.flight_type}")
self.configure_behavior(group)
- def setup_flight_group(self, group: FlyingGroup, package: Package,
- flight: Flight,
- dynamic_runways: Dict[str, RunwayData]) -> None:
+ def setup_flight_group(
+ self,
+ group: FlyingGroup,
+ package: Package,
+ flight: Flight,
+ dynamic_runways: Dict[str, RunwayData],
+ ) -> None:
flight_type = flight.flight_type
- if flight_type in [FlightType.BARCAP, FlightType.TARCAP,
- FlightType.INTERCEPTION]:
+ if flight_type in [
+ FlightType.BARCAP,
+ FlightType.TARCAP,
+ FlightType.INTERCEPTION,
+ ]:
self.configure_cap(group, package, flight, dynamic_runways)
elif flight_type == FlightType.SWEEP:
self.configure_sweep(group, package, flight, dynamic_runways)
@@ -1287,8 +1393,7 @@ class AircraftConflictGenerator:
elif flight_type == FlightType.ESCORT:
self.configure_escort(group, package, flight, dynamic_runways)
elif flight_type == FlightType.OCA_RUNWAY:
- self.configure_runway_attack(group, package, flight,
- dynamic_runways)
+ self.configure_runway_attack(group, package, flight, dynamic_runways)
elif flight_type == FlightType.OCA_AIRCRAFT:
self.configure_oca_strike(group, package, flight, dynamic_runways)
else:
@@ -1297,13 +1402,13 @@ class AircraftConflictGenerator:
self.configure_eplrs(group, flight)
def create_waypoints(
- self, group: FlyingGroup, package: Package, flight: Flight) -> None:
+ self, group: FlyingGroup, package: Package, flight: Flight
+ ) -> None:
for waypoint in flight.points:
waypoint.tot = None
- takeoff_point = FlightWaypoint.from_pydcs(group.points[0],
- flight.from_cp)
+ takeoff_point = FlightWaypoint.from_pydcs(group.points[0], flight.from_cp)
self.set_takeoff_time(takeoff_point, package, flight, group)
filtered_points = [] # type: List[FlightWaypoint]
@@ -1319,15 +1424,22 @@ class AircraftConflictGenerator:
# this could be updated to make it pick the "best" two targets in the group.
if flight.unit_type is AJS37 and flight.client_count:
viggen_target_points = [
- (idx, point) for idx, point in enumerate(filtered_points) if point.waypoint_type in TARGET_WAYPOINTS
+ (idx, point)
+ for idx, point in enumerate(filtered_points)
+ if point.waypoint_type in TARGET_WAYPOINTS
]
if viggen_target_points:
- keep_target = viggen_target_points[random.randint(0, len(viggen_target_points) - 1)]
+ keep_target = viggen_target_points[
+ random.randint(0, len(viggen_target_points) - 1)
+ ]
filtered_points = [
- point for idx, point in enumerate(filtered_points) if (
- point.waypoint_type not in TARGET_WAYPOINTS or idx == keep_target[0]
- )
- ]
+ point
+ for idx, point in enumerate(filtered_points)
+ if (
+ point.waypoint_type not in TARGET_WAYPOINTS
+ or idx == keep_target[0]
+ )
+ ]
for idx, point in enumerate(filtered_points):
PydcsWaypointBuilder.for_waypoint(
@@ -1341,8 +1453,7 @@ class AircraftConflictGenerator:
if self.game.settings.restrict_weapons_by_date:
self._degrade_payload_to_era(flight, group)
- def should_delay_flight(self, flight: Flight,
- start_time: timedelta) -> bool:
+ def should_delay_flight(self, flight: Flight, start_time: timedelta) -> bool:
if start_time.total_seconds() <= 0:
return False
@@ -1357,8 +1468,13 @@ class AircraftConflictGenerator:
return not self.settings.never_delay_player_flights
- def set_takeoff_time(self, waypoint: FlightWaypoint, package: Package,
- flight: Flight, group: FlyingGroup) -> None:
+ def set_takeoff_time(
+ self,
+ waypoint: FlightWaypoint,
+ package: Package,
+ flight: Flight,
+ group: FlyingGroup,
+ ) -> None:
estimator = TotEstimator(package)
start_time = estimator.mission_start_time(flight)
@@ -1397,9 +1513,14 @@ class AircraftConflictGenerator:
class PydcsWaypointBuilder:
- def __init__(self, waypoint: FlightWaypoint, group: FlyingGroup,
- package: Package, flight: Flight,
- mission: Mission) -> None:
+ def __init__(
+ self,
+ waypoint: FlightWaypoint,
+ group: FlyingGroup,
+ package: Package,
+ flight: Flight,
+ mission: Mission,
+ ) -> None:
self.waypoint = waypoint
self.group = group
self.package = package
@@ -1410,7 +1531,8 @@ class PydcsWaypointBuilder:
waypoint = self.group.add_waypoint(
Point(self.waypoint.x, self.waypoint.y),
self.waypoint.alt.meters,
- name=self.mission.string(self.waypoint.name))
+ name=self.mission.string(self.waypoint.name),
+ )
if self.waypoint.flyover:
waypoint.action = PointAction.FlyOverPoint
@@ -1432,9 +1554,14 @@ class PydcsWaypointBuilder:
waypoint.speed_locked = False
@classmethod
- def for_waypoint(cls, waypoint: FlightWaypoint, group: FlyingGroup,
- package: Package, flight: Flight,
- mission: Mission) -> PydcsWaypointBuilder:
+ def for_waypoint(
+ cls,
+ waypoint: FlightWaypoint,
+ group: FlyingGroup,
+ package: Package,
+ flight: Flight,
+ mission: Mission,
+ ) -> PydcsWaypointBuilder:
builders = {
FlightWaypointType.INGRESS_BAI: BaiIngressBuilder,
FlightWaypointType.INGRESS_CAS: CasIngressBuilder,
@@ -1457,9 +1584,8 @@ class PydcsWaypointBuilder:
"""Viggen player aircraft consider any waypoint with a TOT set to be a target ("M") waypoint.
If the flight is a player controlled Viggen flight, no TOT should be set on any waypoint except actual target waypoints.
"""
- if (
- (self.flight.client_count > 0 and self.flight.unit_type == AJS37) and
- (self.waypoint.waypoint_type not in TARGET_WAYPOINTS)
+ if (self.flight.client_count > 0 and self.flight.unit_type == AJS37) and (
+ self.waypoint.waypoint_type not in TARGET_WAYPOINTS
):
return True
else:
@@ -1481,10 +1607,9 @@ class DefaultWaypointBuilder(PydcsWaypointBuilder):
class HoldPointBuilder(PydcsWaypointBuilder):
def build(self) -> MovingPoint:
waypoint = super().build()
- loiter = ControlledTask(OrbitAction(
- altitude=waypoint.alt,
- pattern=OrbitAction.OrbitPattern.Circle
- ))
+ loiter = ControlledTask(
+ OrbitAction(altitude=waypoint.alt, pattern=OrbitAction.OrbitPattern.Circle)
+ )
if not isinstance(self.flight.flight_plan, LoiterFlightPlan):
flight_plan_type = self.flight.flight_plan.__class__.__name__
logging.error(
@@ -1515,11 +1640,14 @@ class BaiIngressBuilder(PydcsWaypointBuilder):
task.params["groupAttack"] = True
waypoint.tasks.append(task)
else:
- logging.error("Could not find group for BAI mission %s",
- target_group.group_name)
+ logging.error(
+ "Could not find group for BAI mission %s", target_group.group_name
+ )
else:
- logging.error("Unexpected target type for BAI mission: %s",
- target_group.__class__.__name__)
+ logging.error(
+ "Unexpected target type for BAI mission: %s",
+ target_group.__class__.__name__,
+ )
return waypoint
@@ -1527,25 +1655,28 @@ class CasIngressBuilder(PydcsWaypointBuilder):
def build(self) -> MovingPoint:
waypoint = super().build()
if isinstance(self.flight.flight_plan, CasFlightPlan):
- waypoint.add_task(EngageTargetsInZone(
- position=self.flight.flight_plan.target,
- radius=int(self.flight.flight_plan.engagement_distance.meters),
- targets=[
- Targets.All.GroundUnits.GroundVehicles,
- Targets.All.GroundUnits.AirDefence.AAA,
- Targets.All.GroundUnits.Infantry,
- ])
+ waypoint.add_task(
+ EngageTargetsInZone(
+ position=self.flight.flight_plan.target,
+ radius=int(self.flight.flight_plan.engagement_distance.meters),
+ targets=[
+ Targets.All.GroundUnits.GroundVehicles,
+ Targets.All.GroundUnits.AirDefence.AAA,
+ Targets.All.GroundUnits.Infantry,
+ ],
+ )
)
else:
- logging.error(
- "No CAS waypoint found. Falling back to search and engage")
- waypoint.add_task(EngageTargets(
- max_distance=int(nautical_miles(10).meters),
- targets=[
- Targets.All.GroundUnits.GroundVehicles,
- Targets.All.GroundUnits.AirDefence.AAA,
- Targets.All.GroundUnits.Infantry,
- ])
+ logging.error("No CAS waypoint found. Falling back to search and engage")
+ waypoint.add_task(
+ EngageTargets(
+ max_distance=int(nautical_miles(10).meters),
+ targets=[
+ Targets.All.GroundUnits.GroundVehicles,
+ Targets.All.GroundUnits.AirDefence.AAA,
+ Targets.All.GroundUnits.Infantry,
+ ],
+ )
)
return waypoint
@@ -1566,7 +1697,9 @@ class DeadIngressBuilder(PydcsWaypointBuilder):
task.params["groupAttack"] = True
waypoint.tasks.append(task)
else:
- logging.error(f"Could not find group for DEAD mission {target_group.group_name}")
+ logging.error(
+ f"Could not find group for DEAD mission {target_group.group_name}"
+ )
self.register_special_waypoints(self.waypoint.targets)
return waypoint
@@ -1579,7 +1712,8 @@ class OcaAircraftIngressBuilder(PydcsWaypointBuilder):
if not isinstance(target, Airfield):
logging.error(
"Unexpected target type for OCA Strike mission: %s",
- target.__class__.__name__)
+ target.__class__.__name__,
+ )
return waypoint
task = EngageTargetsInZone(
@@ -1587,7 +1721,7 @@ class OcaAircraftIngressBuilder(PydcsWaypointBuilder):
# Al Dhafra is 4 nm across at most. Add a little wiggle room in case
# the airport position from DCS is not centered.
radius=int(nautical_miles(3).meters),
- targets=[Targets.All.Air]
+ targets=[Targets.All.Air],
)
task.params["attackQtyLimit"] = False
task.params["directionEnabled"] = False
@@ -1605,11 +1739,13 @@ class OcaRunwayIngressBuilder(PydcsWaypointBuilder):
if not isinstance(target, Airfield):
logging.error(
"Unexpected target type for runway bombing mission: %s",
- target.__class__.__name__)
+ target.__class__.__name__,
+ )
return waypoint
waypoint.tasks.append(
- BombingRunway(airport_id=target.airport.id, group_attack=True))
+ BombingRunway(airport_id=target.airport.id, group_attack=True)
+ )
return waypoint
@@ -1621,15 +1757,19 @@ class SeadIngressBuilder(PydcsWaypointBuilder):
if isinstance(target_group, TheaterGroundObject):
tgroup = self.mission.find_group(target_group.group_name)
if tgroup is not None:
- waypoint.add_task(EngageTargetsInZone(
- position=tgroup.position,
- radius=int(nautical_miles(30).meters),
- targets=[
- Targets.All.GroundUnits.AirDefence,
- ])
- )
+ waypoint.add_task(
+ EngageTargetsInZone(
+ position=tgroup.position,
+ radius=int(nautical_miles(30).meters),
+ targets=[
+ Targets.All.GroundUnits.AirDefence,
+ ],
+ )
+ )
else:
- logging.error(f"Could not find group for DEAD mission {target_group.group_name}")
+ logging.error(
+ f"Could not find group for DEAD mission {target_group.group_name}"
+ )
self.register_special_waypoints(self.waypoint.targets)
return waypoint
@@ -1701,12 +1841,16 @@ class SweepIngressBuilder(PydcsWaypointBuilder):
flight_plan_type = self.flight.flight_plan.__class__.__name__
logging.error(
f"Cannot create sweep for {self.flight} because "
- f"{flight_plan_type} is not a sweep flight plan.")
+ f"{flight_plan_type} is not a sweep flight plan."
+ )
return waypoint
- waypoint.tasks.append(EngageTargets(
- max_distance=int(nautical_miles(50).meters),
- targets=[Targets.All.Air.Planes.Fighters]))
+ waypoint.tasks.append(
+ EngageTargets(
+ max_distance=int(nautical_miles(50).meters),
+ targets=[Targets.All.Air.Planes.Fighters],
+ )
+ )
return waypoint
@@ -1746,11 +1890,15 @@ class JoinPointBuilder(PydcsWaypointBuilder):
# the strike aircraft finish their attack task.
#
# https://forums.eagle.ru/forum/english/digital-combat-simulator/dcs-world-2-5/bugs-and-problems-ai/ai-ad/250183-task-follow-and-escort-temporarily-aborted
- waypoint.add_task(ControlledTask(EngageTargets(
- # TODO: From doctrine.
- max_distance=int(nautical_miles(30).meters),
- targets=[Targets.All.Air.Planes.Fighters]
- )))
+ waypoint.add_task(
+ ControlledTask(
+ EngageTargets(
+ # TODO: From doctrine.
+ max_distance=int(nautical_miles(30).meters),
+ targets=[Targets.All.Air.Planes.Fighters],
+ )
+ )
+ )
# We could set this task to end at the split point. pydcs doesn't
# currently support that task end condition though, and we don't really
@@ -1775,7 +1923,8 @@ class RaceTrackBuilder(PydcsWaypointBuilder):
flight_plan_type = flight_plan.__class__.__name__
logging.error(
f"Cannot create race track for {self.flight} because "
- f"{flight_plan_type} does not define a patrol.")
+ f"{flight_plan_type} does not define a patrol."
+ )
return waypoint
# NB: It's important that the engage task comes before the orbit task.
@@ -1792,16 +1941,18 @@ class RaceTrackBuilder(PydcsWaypointBuilder):
if self.flight.flight_type in cap_types:
engagement_distance = int(flight_plan.engagement_distance.meters)
waypoint.tasks.append(
- EngageTargets(max_distance=engagement_distance,
- targets=[Targets.All.Air]))
+ EngageTargets(
+ max_distance=engagement_distance, targets=[Targets.All.Air]
+ )
+ )
- racetrack = ControlledTask(OrbitAction(
- altitude=waypoint.alt,
- pattern=OrbitAction.OrbitPattern.RaceTrack
- ))
+ racetrack = ControlledTask(
+ OrbitAction(
+ altitude=waypoint.alt, pattern=OrbitAction.OrbitPattern.RaceTrack
+ )
+ )
self.set_waypoint_tot(waypoint, flight_plan.patrol_start_time)
- racetrack.stop_after_time(
- int(flight_plan.patrol_end_time.total_seconds()))
+ racetrack.stop_after_time(int(flight_plan.patrol_end_time.total_seconds()))
waypoint.add_task(racetrack)
return waypoint
@@ -1815,7 +1966,8 @@ class RaceTrackEndBuilder(PydcsWaypointBuilder):
flight_plan_type = self.flight.flight_plan.__class__.__name__
logging.error(
f"Cannot create race track for {self.flight} because "
- f"{flight_plan_type} does not define a patrol.")
+ f"{flight_plan_type} does not define a patrol."
+ )
return waypoint
self.waypoint.departure_time = self.flight.flight_plan.patrol_end_time
diff --git a/gen/airfields.py b/gen/airfields.py
index 14a40840..d0bb4d54 100644
--- a/gen/airfields.py
+++ b/gen/airfields.py
@@ -23,6 +23,7 @@ class AtcData:
@dataclass
class AirfieldData:
"""Additional airfield data not included in pydcs."""
+
#: Name of the theater the airport is in.
theater: str
@@ -73,7 +74,6 @@ class AirfieldData:
# TODO: Add more airfields.
AIRFIELD_DATA = {
# Caucasus
-
"Batumi": AirfieldData(
theater="Caucasus",
icao="UGSB",
@@ -86,7 +86,6 @@ AIRFIELD_DATA = {
"13": ("ILU", MHz(110, 300)),
},
),
-
"Kobuleti": AirfieldData(
theater="Caucasus",
icao="UG5X",
@@ -105,7 +104,6 @@ AIRFIELD_DATA = {
"07": ("T", MHz(490, 0)),
},
),
-
"Senaki-Kolkhi": AirfieldData(
theater="Caucasus",
icao="UGKS",
@@ -124,7 +122,6 @@ AIRFIELD_DATA = {
"09": ("I", MHz(688, 0)),
},
),
-
"Kutaisi": AirfieldData(
theater="Caucasus",
icao="UGKO",
@@ -137,7 +134,6 @@ AIRFIELD_DATA = {
"08": ("IKS", MHz(109, 750)),
},
),
-
"Sukhumi-Babushara": AirfieldData(
theater="Caucasus",
icao="UGSS",
@@ -151,7 +147,6 @@ AIRFIELD_DATA = {
"30": ("A", MHz(995, 0)),
},
),
-
"Gudauta": AirfieldData(
theater="Caucasus",
icao="UG23",
@@ -159,7 +154,6 @@ AIRFIELD_DATA = {
runway_length=7839,
atc=AtcData(MHz(4, 200), MHz(120, 0), MHz(40, 200), MHz(259, 0)),
),
-
"Sochi-Adler": AirfieldData(
theater="Caucasus",
icao="URSS",
@@ -170,7 +164,6 @@ AIRFIELD_DATA = {
"06": ("ISO", MHz(111, 100)),
},
),
-
"Gelendzhik": AirfieldData(
theater="Caucasus",
icao="URKG",
@@ -179,7 +172,6 @@ AIRFIELD_DATA = {
vor=("GN", MHz(114, 30)),
atc=AtcData(MHz(4, 0), MHz(126, 0), MHz(39, 400), MHz(255, 0)),
),
-
"Novorossiysk": AirfieldData(
theater="Caucasus",
icao="URKN",
@@ -187,7 +179,6 @@ AIRFIELD_DATA = {
runway_length=5639,
atc=AtcData(MHz(3, 850), MHz(123, 0), MHz(38, 800), MHz(252, 0)),
),
-
"Anapa-Vityazevo": AirfieldData(
theater="Caucasus",
icao="URKA",
@@ -203,7 +194,6 @@ AIRFIELD_DATA = {
"04": ("N", MHz(215)),
},
),
-
"Krymsk": AirfieldData(
theater="Caucasus",
icao="URKW",
@@ -224,7 +214,6 @@ AIRFIELD_DATA = {
"22": ("K", MHz(803, 0)),
},
),
-
"Krasnodar-Center": AirfieldData(
theater="Caucasus",
icao="URKL",
@@ -244,7 +233,6 @@ AIRFIELD_DATA = {
"27": ("C", MHz(303, 0)),
},
),
-
"Krasnodar-Pashkovsky": AirfieldData(
theater="Caucasus",
icao="URKK",
@@ -261,7 +249,6 @@ AIRFIELD_DATA = {
"05": ("K", MHz(240, 0)),
},
),
-
"Maykop-Khanskaya": AirfieldData(
theater="Caucasus",
icao="URKH",
@@ -281,7 +268,6 @@ AIRFIELD_DATA = {
"22": ("R", MHz(591, 0)),
},
),
-
"Mineralnye Vody": AirfieldData(
theater="Caucasus",
icao="URMM",
@@ -302,7 +288,6 @@ AIRFIELD_DATA = {
"12": ("D", MHz(283, 0)),
},
),
-
"Nalchik": AirfieldData(
theater="Caucasus",
icao="URMN",
@@ -319,7 +304,6 @@ AIRFIELD_DATA = {
"24": ("N", MHz(350, 0)),
},
),
-
"Mozdok": AirfieldData(
theater="Caucasus",
icao="XRMF",
@@ -338,9 +322,8 @@ AIRFIELD_DATA = {
inner_ndb={
"26": ("R", MHz(1, 6)),
"8": ("D", MHz(1, 6)),
- }
+ },
),
-
"Beslan": AirfieldData(
theater="Caucasus",
icao="URMO",
@@ -355,9 +338,8 @@ AIRFIELD_DATA = {
},
inner_ndb={
"10": ("C", MHz(250, 0)),
- }
+ },
),
-
"Tbilisi-Lochini": AirfieldData(
theater="Caucasus",
icao="UGTB",
@@ -379,7 +361,6 @@ AIRFIELD_DATA = {
"30": ("N", MHz(435, 0)),
},
),
-
"Soganlung": AirfieldData(
theater="Caucasus",
icao="UG24",
@@ -389,7 +370,6 @@ AIRFIELD_DATA = {
tacan_callsign="GTB",
atc=AtcData(MHz(4, 650), MHz(139, 0), MHz(42, 0), MHz(268, 0)),
),
-
"Vaziani": AirfieldData(
theater="Caucasus",
icao="UG27",
@@ -403,7 +383,6 @@ AIRFIELD_DATA = {
"31": ("IVZ", MHz(108, 750)),
},
),
-
# TODO : PERSIAN GULF MAP
"Liwa Airbase": AirfieldData(
theater="Persian Gulf",
@@ -412,10 +391,9 @@ AIRFIELD_DATA = {
runway_length=10768,
tacan=TacanChannel(121, TacanBand.X),
tacan_callsign="OMLW",
- vor=("OMLW", MHz(117,400)),
+ vor=("OMLW", MHz(117, 400)),
atc=AtcData(MHz(4, 225), MHz(39, 350), MHz(119, 300), MHz(250, 950)),
),
-
"Al Dhafra AB": AirfieldData(
theater="Persian Gulf",
icao="OMAM",
@@ -430,7 +408,6 @@ AIRFIELD_DATA = {
"31": ("IMA", MHz(109, 100)),
},
),
-
"Al-Bateen Airport": AirfieldData(
theater="Persian Gulf",
icao="OMAD",
@@ -439,7 +416,6 @@ AIRFIELD_DATA = {
vor=("ALB", MHz(114, 0)),
atc=AtcData(MHz(4, 25), MHz(38, 950), MHz(119, 900), MHz(250, 550)),
),
-
"Sas Al Nakheel Airport": AirfieldData(
theater="Persian Gulf",
icao="OMNK",
@@ -448,7 +424,6 @@ AIRFIELD_DATA = {
vor=("SAS", MHz(128, 930)),
atc=AtcData(MHz(3, 975), MHz(38, 850), MHz(128, 900), MHz(250, 450)),
),
-
"Abu Dhabi International Airport": AirfieldData(
theater="Persian Gulf",
icao="OMAA",
@@ -457,7 +432,6 @@ AIRFIELD_DATA = {
vor=("ADV", MHz(114, 250)),
atc=AtcData(MHz(4, 000), MHz(38, 900), MHz(119, 200), MHz(250, 500)),
),
-
"Al Ain International Airport": AirfieldData(
theater="Persian Gulf",
icao="OMAL",
@@ -466,7 +440,6 @@ AIRFIELD_DATA = {
vor=("ALN", MHz(112, 600)),
atc=AtcData(MHz(4, 75), MHz(39, 50), MHz(119, 850), MHz(250, 650)),
),
-
"Al Maktoum Intl": AirfieldData(
theater="Persian Gulf",
icao="OMDW",
@@ -478,7 +451,6 @@ AIRFIELD_DATA = {
"12": ("IMA", MHz(111, 750)),
},
),
-
"Al Minhad Intl": AirfieldData(
theater="Persian Gulf",
icao="OMDM",
@@ -492,7 +464,6 @@ AIRFIELD_DATA = {
"9": ("IMNW", MHz(110, 700)),
},
),
-
"Dubai Intl": AirfieldData(
theater="Persian Gulf",
icao="OMDB",
@@ -504,7 +475,6 @@ AIRFIELD_DATA = {
"12": ("IDBR", MHz(110, 100)),
},
),
-
"Sharjah Intl": AirfieldData(
theater="Persian Gulf",
icao="OMSJ",
@@ -516,7 +486,6 @@ AIRFIELD_DATA = {
"12": ("ISRE", MHz(108, 550)),
},
),
-
"Fujairah Intl": AirfieldData(
theater="Persian Gulf",
icao="OMFJ",
@@ -528,7 +497,6 @@ AIRFIELD_DATA = {
"29": ("IFJR", MHz(111, 500)),
},
),
-
"Ras AL Khaimah": AirfieldData(
theater="Persian Gulf",
icao="OMRK",
@@ -537,7 +505,6 @@ AIRFIELD_DATA = {
vor=("OMRK", MHz(113, 600)),
atc=AtcData(MHz(4, 150), MHz(39, 200), MHz(121, 600), MHz(250, 800)),
),
-
"Khasab": AirfieldData(
theater="Persian Gulf",
icao="OOKB",
@@ -548,14 +515,9 @@ AIRFIELD_DATA = {
"19": ("IBKS", MHz(110, 300)),
},
),
-
"Sir Abu Nuayr": AirfieldData(
- theater="Persian Gulf",
- icao="OMSN",
- elevation=25,
- runway_length=2229
+ theater="Persian Gulf", icao="OMSN", elevation=25, runway_length=2229
),
-
"Sirri Island": AirfieldData(
theater="Persian Gulf",
icao="OIBS",
@@ -564,7 +526,6 @@ AIRFIELD_DATA = {
vor=("SIR", MHz(113, 750)),
atc=AtcData(MHz(3, 875), MHz(38, 650), MHz(135, 50), MHz(250, 250)),
),
-
"Abu Musa Island Airport": AirfieldData(
theater="Persian Gulf",
icao="OIBA",
@@ -572,7 +533,6 @@ AIRFIELD_DATA = {
runway_length=7616,
atc=AtcData(MHz(3, 950), MHz(38, 800), MHz(122, 900), MHz(250, 400)),
),
-
"Tunb Kochak": AirfieldData(
theater="Persian Gulf",
icao="OITK",
@@ -581,14 +541,12 @@ AIRFIELD_DATA = {
tacan=TacanChannel(89, TacanBand.X),
tacan_callsign="KCK",
),
-
"Tunb Island AFB": AirfieldData(
theater="Persian Gulf",
icao="OIGI",
elevation=42,
runway_length=6099,
),
-
"Qeshm Island": AirfieldData(
theater="Persian Gulf",
icao="OIKQ",
@@ -597,7 +555,6 @@ AIRFIELD_DATA = {
vor=("KHM", MHz(117, 100)),
atc=AtcData(MHz(3, 825), MHz(38, 550), MHz(118, 50), MHz(250, 150)),
),
-
"Bandar-e-Jask airfield": AirfieldData(
theater="Persian Gulf",
icao="OIZJ",
@@ -606,7 +563,6 @@ AIRFIELD_DATA = {
vor=("KHM", MHz(116, 300)),
atc=AtcData(MHz(3, 825), MHz(38, 550), MHz(118, 50), MHz(250, 150)),
),
-
"Bandar Lengeh": AirfieldData(
theater="Persian Gulf",
icao="OIBL",
@@ -615,7 +571,6 @@ AIRFIELD_DATA = {
vor=("LEN", MHz(114, 800)),
atc=AtcData(MHz(4, 225), MHz(39, 350), MHz(121, 700), MHz(250, 950)),
),
-
"Kish International Airport": AirfieldData(
theater="Persian Gulf",
icao="OIBK",
@@ -625,7 +580,6 @@ AIRFIELD_DATA = {
tacan_callsign="KIH",
atc=AtcData(MHz(4, 50), MHz(39, 000), MHz(121, 650), MHz(250, 600)),
),
-
"Lavan Island Airport": AirfieldData(
theater="Persian Gulf",
icao="OIBV",
@@ -634,7 +588,6 @@ AIRFIELD_DATA = {
vor=("LVA", MHz(116, 850)),
atc=AtcData(MHz(4, 100), MHz(39, 100), MHz(128, 550), MHz(250, 700)),
),
-
"Lar Airbase": AirfieldData(
theater="Persian Gulf",
icao="OISL",
@@ -643,7 +596,6 @@ AIRFIELD_DATA = {
vor=("LAR", MHz(117, 900)),
atc=AtcData(MHz(3, 775), MHz(38, 450), MHz(127, 350), MHz(250, 50)),
),
-
"Havadarya": AirfieldData(
theater="Persian Gulf",
icao="OIKP",
@@ -656,7 +608,6 @@ AIRFIELD_DATA = {
"8": ("IBHD", MHz(108, 900)),
},
),
-
"Bandar Abbas Intl": AirfieldData(
theater="Persian Gulf",
icao="OIKB",
@@ -670,7 +621,6 @@ AIRFIELD_DATA = {
"21": ("IBND", MHz(333, 800)),
},
),
-
"Jiroft Airport": AirfieldData(
theater="Persian Gulf",
icao="OIKJ",
@@ -678,7 +628,6 @@ AIRFIELD_DATA = {
runway_length=9160,
atc=AtcData(MHz(4, 125), MHz(39, 120), MHz(136, 0), MHz(250, 750)),
),
-
"Kerman Airport": AirfieldData(
theater="Persian Gulf",
icao="OIKK",
@@ -689,7 +638,6 @@ AIRFIELD_DATA = {
vor=("KER", MHz(112, 0)),
atc=AtcData(MHz(3, 900), MHz(38, 700), MHz(118, 250), MHz(250, 300)),
),
-
"Shiraz International Airport": AirfieldData(
theater="Persian Gulf",
icao="OISS",
@@ -700,7 +648,6 @@ AIRFIELD_DATA = {
vor=("SYZ", MHz(112, 0)),
atc=AtcData(MHz(3, 925), MHz(38, 750), MHz(121, 900), MHz(250, 350)),
),
-
# Syria Map
"Adana Sakirpasa": AirfieldData(
theater="Syria",
@@ -713,7 +660,6 @@ AIRFIELD_DATA = {
"05": ("IADA", MHz(108, 700)),
},
),
-
"Incirlik": AirfieldData(
theater="Syria",
icao="LTAG",
@@ -728,7 +674,6 @@ AIRFIELD_DATA = {
"23": ("DANM", MHz(111, 700)),
},
),
-
"Minakh": AirfieldData(
theater="Syria",
icao="OS71",
@@ -736,7 +681,6 @@ AIRFIELD_DATA = {
runway_length=4648,
atc=AtcData(MHz(4, 125), MHz(39, 150), MHz(120, 600), MHz(250, 700)),
),
-
"Hatay": AirfieldData(
theater="Syria",
icao="LTDA",
@@ -749,7 +693,6 @@ AIRFIELD_DATA = {
"04": ("IHAT", MHz(108, 900)),
},
),
-
"Kuweires": AirfieldData(
theater="Syria",
icao="OS66",
@@ -757,7 +700,6 @@ AIRFIELD_DATA = {
runway_length=6662,
atc=AtcData(MHz(4, 275), MHz(39, 450), MHz(120, 500), MHz(251)),
),
-
"Aleppo": AirfieldData(
theater="Syria",
icao="OSAP",
@@ -769,7 +711,6 @@ AIRFIELD_DATA = {
"23": ("DANM", MHz(111, 700)),
},
),
-
"Jirah": AirfieldData(
theater="Syria",
icao="OS62",
@@ -777,14 +718,12 @@ AIRFIELD_DATA = {
runway_length=9090,
atc=AtcData(MHz(3, 875), MHz(38, 650), MHz(118, 100), MHz(250, 200)),
),
-
"Taftanaz": AirfieldData(
theater="Syria",
elevation=1020,
runway_length=2705,
atc=AtcData(MHz(4, 375), MHz(39, 650), MHz(122, 800), MHz(251, 200)),
),
-
"Tabqa": AirfieldData(
theater="Syria",
icao="OS59",
@@ -792,7 +731,6 @@ AIRFIELD_DATA = {
runway_length=9036,
atc=AtcData(MHz(4, 350), MHz(39, 600), MHz(118, 500), MHz(251, 150)),
),
-
"Abu al-Dahur": AirfieldData(
theater="Syria",
icao="OS57",
@@ -800,7 +738,6 @@ AIRFIELD_DATA = {
runway_length=8728,
atc=AtcData(MHz(3, 950), MHz(38, 800), MHz(122, 200), MHz(250, 350)),
),
-
"Bassel Al-Assad": AirfieldData(
theater="Syria",
icao="OSLK",
@@ -812,7 +749,6 @@ AIRFIELD_DATA = {
"17": ("IBA", MHz(109, 100)),
},
),
-
"Hama": AirfieldData(
theater="Syria",
icao="OS58",
@@ -820,7 +756,6 @@ AIRFIELD_DATA = {
runway_length=7957,
atc=AtcData(MHz(3, 800), MHz(38, 500), MHz(118, 50), MHz(250, 100)),
),
-
"Rene Mouawad": AirfieldData(
theater="Syria",
icao="OLKA",
@@ -828,7 +763,6 @@ AIRFIELD_DATA = {
runway_length=8614,
atc=AtcData(MHz(4, 325), MHz(39, 550), MHz(129, 500), MHz(251, 100)),
),
-
"Al Quasayr": AirfieldData(
theater="Syria",
icao="OS70",
@@ -836,7 +770,6 @@ AIRFIELD_DATA = {
runway_length=8585,
atc=AtcData(MHz(4, 400), MHz(39, 700), MHz(119, 200), MHz(251, 250)),
),
-
"Palmyra": AirfieldData(
theater="Syria",
icao="OSPR",
@@ -844,7 +777,6 @@ AIRFIELD_DATA = {
runway_length=8704,
atc=AtcData(MHz(4, 175), MHz(39, 250), MHz(121, 900), MHz(250, 800)),
),
-
"Wujah Al Hajar": AirfieldData(
theater="Syria",
icao="Z19O",
@@ -853,7 +785,6 @@ AIRFIELD_DATA = {
vor=("CAK", MHz(116, 200)),
atc=AtcData(MHz(4, 425), MHz(39, 750), MHz(121, 500), MHz(251, 300)),
),
-
"An Nasiriyah": AirfieldData(
theater="Syria",
icao="OS64",
@@ -861,7 +792,6 @@ AIRFIELD_DATA = {
runway_length=8172,
atc=AtcData(MHz(4, 450), MHz(39, 800), MHz(122, 300), MHz(251, 350)),
),
-
"Rayak": AirfieldData(
theater="Syria",
icao="OLRA",
@@ -870,7 +800,6 @@ AIRFIELD_DATA = {
vor=("HTY", MHz(124, 400)),
atc=AtcData(MHz(4, 300), MHz(39, 500), MHz(124, 400), MHz(251, 50)),
),
-
"Beirut-Rafic Hariri": AirfieldData(
theater="Syria",
icao="OLBA",
@@ -882,7 +811,6 @@ AIRFIELD_DATA = {
"17": ("BIL", MHz(109, 500)),
},
),
-
"Al-Dumayr": AirfieldData(
theater="Syria",
icao="OS61",
@@ -890,21 +818,18 @@ AIRFIELD_DATA = {
runway_length=8902,
atc=AtcData(MHz(4, 550), MHz(40), MHz(120, 300), MHz(251, 550)),
),
-
"Marj as Sultan North": AirfieldData(
theater="Syria",
elevation=2007,
runway_length=268,
atc=AtcData(MHz(4, 25), MHz(38, 950), MHz(122, 700), MHz(250, 500)),
),
-
"Marj as Sultan South": AirfieldData(
theater="Syria",
elevation=2007,
runway_length=166,
atc=AtcData(MHz(4, 525), MHz(39, 950), MHz(122, 900), MHz(251, 500)),
),
-
"Mezzeh": AirfieldData(
theater="Syria",
icao="OS67",
@@ -912,14 +837,12 @@ AIRFIELD_DATA = {
runway_length=7522,
atc=AtcData(MHz(4, 100), MHz(39, 100), MHz(120, 700), MHz(250, 650)),
),
-
"Qabr as Sitt": AirfieldData(
theater="Syria",
elevation=2134,
runway_length=489,
atc=AtcData(MHz(4, 200), MHz(39, 300), MHz(122, 600), MHz(250, 850)),
),
-
"Damascus": AirfieldData(
theater="Syria",
icao="OSDI",
@@ -931,7 +854,6 @@ AIRFIELD_DATA = {
"24": ("IDA", MHz(109, 900)),
},
),
-
"Marj Ruhayyil": AirfieldData(
theater="Syria",
icao="OS63",
@@ -939,7 +861,6 @@ AIRFIELD_DATA = {
runway_length=7576,
atc=AtcData(MHz(4, 50), MHz(39), MHz(120, 800), MHz(250, 550)),
),
-
"Kiryat Shmona": AirfieldData(
theater="Syria",
icao="LLKS",
@@ -947,7 +868,6 @@ AIRFIELD_DATA = {
runway_length=3258,
atc=AtcData(MHz(3, 975), MHz(38, 850), MHz(118, 400), MHz(250, 400)),
),
-
"Khalkhalah": AirfieldData(
theater="Syria",
icao="OS69",
@@ -955,7 +875,6 @@ AIRFIELD_DATA = {
runway_length=8248,
atc=AtcData(MHz(3, 900), MHz(38, 700), MHz(122, 500), MHz(250, 250)),
),
-
"Haifa": AirfieldData(
theater="Syria",
icao="LLHA",
@@ -963,7 +882,6 @@ AIRFIELD_DATA = {
runway_length=3253,
atc=AtcData(MHz(3, 775), MHz(38, 450), MHz(127, 800), MHz(250, 50)),
),
-
"Ramat David": AirfieldData(
theater="Syria",
icao="LLRD",
@@ -971,7 +889,6 @@ AIRFIELD_DATA = {
runway_length=7037,
atc=AtcData(MHz(4, 250), MHz(39, 400), MHz(118, 600), MHz(250, 950)),
),
-
"Megiddo": AirfieldData(
theater="Syria",
icao="LLMG",
@@ -979,7 +896,6 @@ AIRFIELD_DATA = {
runway_length=6098,
atc=AtcData(MHz(4, 75), MHz(39, 50), MHz(119, 900), MHz(250, 600)),
),
-
"Eyn Shemer": AirfieldData(
theater="Syria",
icao="LLES",
@@ -987,7 +903,6 @@ AIRFIELD_DATA = {
runway_length=3562,
atc=AtcData(MHz(3, 750), MHz(38, 400), MHz(123, 400), MHz(250)),
),
-
"King Hussein Air College": AirfieldData(
theater="Syria",
icao="OJMF",
@@ -995,21 +910,18 @@ AIRFIELD_DATA = {
runway_length=8595,
atc=AtcData(MHz(3, 925), MHz(38, 750), MHz(118, 300), MHz(250, 300)),
),
-
# NTTR
"Mina Airport 3Q0": AirfieldData(
theater="NTTR",
elevation=4562,
runway_length=4222,
),
-
"Tonopah Airport": AirfieldData(
theater="NTTR",
icao="KTPH",
elevation=5394,
runway_length=6715,
),
-
"Tonopah Test Range Airfield": AirfieldData(
theater="NTTR",
icao="KTNX",
@@ -1023,20 +935,17 @@ AIRFIELD_DATA = {
"14": ("I-RVP", MHz(108, 300)),
},
),
-
"Beatty Airport": AirfieldData(
theater="NTTR",
icao="KBTY",
elevation=3173,
runway_length=5380,
),
-
"Pahute Mesa Airstrip": AirfieldData(
theater="NTTR",
elevation=5056,
runway_length=5420,
),
-
"Groom Lake AFB": AirfieldData(
theater="NTTR",
icao="KXTA",
@@ -1049,20 +958,17 @@ AIRFIELD_DATA = {
"32": ("GLRI", MHz(109, 300)),
},
),
-
"Lincoln County": AirfieldData(
theater="NTTR",
elevation=4815,
runway_length=4408,
),
-
"Mesquite": AirfieldData(
theater="NTTR",
icao="67L",
elevation=1858,
runway_length=4937,
),
-
"Creech AFB": AirfieldData(
theater="NTTR",
icao="KINS",
@@ -1075,7 +981,6 @@ AIRFIELD_DATA = {
"8": ("ICRR", MHz(108, 700)),
},
),
-
"Echo Bay": AirfieldData(
theater="NTTR",
icao="OL9",
@@ -1085,7 +990,6 @@ AIRFIELD_DATA = {
tacan_callsign="INS",
atc=AtcData(MHz(3, 825), MHz(118, 300), MHz(38, 550), MHz(360, 600)),
),
-
"Nellis AFB": AirfieldData(
theater="NTTR",
icao="KLSV",
@@ -1098,7 +1002,6 @@ AIRFIELD_DATA = {
"21": ("IDIQ", MHz(109, 100)),
},
),
-
"North Las Vegas": AirfieldData(
theater="NTTR",
icao="KVGT",
@@ -1106,7 +1009,6 @@ AIRFIELD_DATA = {
runway_length=4734,
atc=AtcData(MHz(3, 775), MHz(125, 700), MHz(38, 450), MHz(360, 750)),
),
-
"McCarran International Airport": AirfieldData(
theater="NTTR",
icao="KLAS",
@@ -1119,7 +1021,6 @@ AIRFIELD_DATA = {
"25": ("I-LAS", MHz(110, 300)),
},
),
-
"Henderson Executive Airport": AirfieldData(
theater="NTTR",
icao="KHND",
@@ -1127,20 +1028,17 @@ AIRFIELD_DATA = {
runway_length=5999,
atc=AtcData(MHz(3, 925), MHz(125, 100), MHz(38, 750), MHz(250, 100)),
),
-
"Boulder City Airport": AirfieldData(
theater="NTTR",
icao="KBVU",
elevation=2121,
runway_length=4612,
),
-
"Jean Airport": AirfieldData(
theater="NTTR",
elevation=2824,
runway_length=4053,
),
-
"Laughlin Airport": AirfieldData(
theater="NTTR",
icao="KIFP",
@@ -1148,44 +1046,37 @@ AIRFIELD_DATA = {
runway_length=7139,
atc=AtcData(MHz(3, 750), MHz(123, 900), MHz(38, 400), MHz(250, 0)),
),
-
# Normandy
-
"Needs Oar Point": AirfieldData(
theater="Normandy",
elevation=30,
runway_length=5259,
atc=AtcData(MHz(4, 225), MHz(118, 950), MHz(39, 350), MHz(250, 950)),
),
-
"Funtington": AirfieldData(
theater="Normandy",
elevation=164,
runway_length=5080,
atc=AtcData(MHz(4, 250), MHz(119, 000), MHz(39, 400), MHz(251, 000)),
),
-
"Tangmere": AirfieldData(
theater="Normandy",
elevation=47,
runway_length=4296,
atc=AtcData(MHz(4, 300), MHz(119, 100), MHz(39, 500), MHz(251, 100)),
),
-
"Ford_AF": AirfieldData(
theater="Normandy",
elevation=29,
runway_length=4296,
atc=AtcData(MHz(4, 325), MHz(119, 150), MHz(39, 550), MHz(251, 150)),
),
-
"Chailey": AirfieldData(
theater="Normandy",
elevation=134,
runway_length=5080,
atc=AtcData(MHz(4, 200), MHz(118, 900), MHz(39, 300), MHz(250, 900)),
),
-
"Maupertus": AirfieldData(
theater="Normandy",
icao="A-15",
@@ -1193,7 +1084,6 @@ AIRFIELD_DATA = {
runway_length=4666,
atc=AtcData(MHz(4, 550), MHz(119, 600), MHz(40, 000), MHz(251, 600)),
),
-
"Azeville": AirfieldData(
theater="Normandy",
icao="A-7",
@@ -1201,7 +1091,6 @@ AIRFIELD_DATA = {
runway_length=3357,
atc=AtcData(MHz(3, 875), MHz(118, 250), MHz(38, 650), MHz(250, 250)),
),
-
"Biniville": AirfieldData(
theater="Normandy",
icao="A-24",
@@ -1209,7 +1098,6 @@ AIRFIELD_DATA = {
runway_length=3283,
atc=AtcData(MHz(3, 750), MHz(118, 000), MHz(38, 400), MHz(250, 000)),
),
-
"Beuzeville": AirfieldData(
theater="Normandy",
icao="A-6",
@@ -1217,7 +1105,6 @@ AIRFIELD_DATA = {
runway_length=3840,
atc=AtcData(MHz(3, 850), MHz(118, 200), MHz(38, 600), MHz(250, 200)),
),
-
"Picauville": AirfieldData(
theater="Normandy",
icao="A-8",
@@ -1225,7 +1112,6 @@ AIRFIELD_DATA = {
runway_length=3840,
atc=AtcData(MHz(3, 900), MHz(118, 300), MHz(38, 700), MHz(250, 300)),
),
-
"Brucheville": AirfieldData(
theater="Normandy",
icao="A-16",
@@ -1233,7 +1119,6 @@ AIRFIELD_DATA = {
runway_length=3413,
atc=AtcData(MHz(4, 575), MHz(119, 650), MHz(40, 50), MHz(251, 650)),
),
-
"Cretteville": AirfieldData(
theater="Normandy",
icao="A-14",
@@ -1241,7 +1126,6 @@ AIRFIELD_DATA = {
runway_length=4594,
atc=AtcData(MHz(4, 500), MHz(119, 500), MHz(39, 900), MHz(251, 500)),
),
-
"Meautis": AirfieldData(
theater="Normandy",
icao="A-17",
@@ -1249,7 +1133,6 @@ AIRFIELD_DATA = {
runway_length=3840,
atc=AtcData(MHz(4, 600), MHz(119, 700), MHz(40, 100), MHz(251, 700)),
),
-
"Lessay": AirfieldData(
theater="Normandy",
icao="A-20",
@@ -1257,7 +1140,6 @@ AIRFIELD_DATA = {
runway_length=5080,
atc=AtcData(MHz(4, 650), MHz(119, 800), MHz(40, 200), MHz(251, 800)),
),
-
"Cardonville": AirfieldData(
theater="Normandy",
icao="A-3",
@@ -1265,7 +1147,6 @@ AIRFIELD_DATA = {
runway_length=4541,
atc=AtcData(MHz(3, 775), MHz(118, 50), MHz(38, 450), MHz(250, 50)),
),
-
"Cricqueville-en-Bessin": AirfieldData(
theater="Normandy",
icao="A-2",
@@ -1273,7 +1154,6 @@ AIRFIELD_DATA = {
runway_length=3459,
atc=AtcData(MHz(4, 625), MHz(119, 750), MHz(40, 150), MHz(251, 750)),
),
-
"Deux Jumeaux": AirfieldData(
theater="Normandy",
icao="A-4",
@@ -1281,7 +1161,6 @@ AIRFIELD_DATA = {
runway_length=4628,
atc=AtcData(MHz(3, 800), MHz(118, 100), MHz(38, 500), MHz(250, 100)),
),
-
"Saint Pierre du Mont": AirfieldData(
theater="Normandy",
icao="A-1",
@@ -1289,7 +1168,6 @@ AIRFIELD_DATA = {
runway_length=4737,
atc=AtcData(MHz(4, 000), MHz(118, 500), MHz(38, 900), MHz(250, 500)),
),
-
"Sainte-Laurent-sur-Mer": AirfieldData(
theater="Normandy",
icao="A-21",
@@ -1297,7 +1175,6 @@ AIRFIELD_DATA = {
runway_length=4561,
atc=AtcData(MHz(4, 675), MHz(119, 850), MHz(40, 250), MHz(251, 850)),
),
-
"Longues-sur-Mer": AirfieldData(
theater="Normandy",
icao="B-11",
@@ -1305,7 +1182,6 @@ AIRFIELD_DATA = {
runway_length=3155,
atc=AtcData(MHz(3, 950), MHz(118, 400), MHz(38, 800), MHz(250, 400)),
),
-
"Chippelle": AirfieldData(
theater="Normandy",
icao="A-5",
@@ -1313,7 +1189,6 @@ AIRFIELD_DATA = {
runway_length=4643,
atc=AtcData(MHz(3, 825), MHz(118, 150), MHz(38, 550), MHz(250, 150)),
),
-
"Le Molay": AirfieldData(
theater="Normandy",
icao="A-9",
@@ -1321,7 +1196,6 @@ AIRFIELD_DATA = {
runway_length=3840,
atc=AtcData(MHz(3, 925), MHz(118, 350), MHz(38, 750), MHz(250, 350)),
),
-
"Lignerolles": AirfieldData(
theater="Normandy",
icao="A-12",
@@ -1329,7 +1203,6 @@ AIRFIELD_DATA = {
runway_length=3436,
atc=AtcData(MHz(4, 275), MHz(119, 50), MHz(39, 450), MHz(251, 50)),
),
-
"Sommervieu": AirfieldData(
theater="Normandy",
icao="B-8",
@@ -1337,7 +1210,6 @@ AIRFIELD_DATA = {
runway_length=3840,
atc=AtcData(MHz(4, 125), MHz(118, 750), MHz(39, 150), MHz(250, 750)),
),
-
"Bazenville": AirfieldData(
theater="Normandy",
icao="B-2",
@@ -1345,7 +1217,6 @@ AIRFIELD_DATA = {
runway_length=3800,
atc=AtcData(MHz(4, 25), MHz(118, 550), MHz(38, 950), MHz(250, 550)),
),
-
"Rucqueville": AirfieldData(
theater="Normandy",
icao="B-7",
@@ -1353,7 +1224,6 @@ AIRFIELD_DATA = {
runway_length=4561,
atc=AtcData(MHz(4, 100), MHz(118, 700), MHz(39, 100), MHz(250, 700)),
),
-
"Lantheuil": AirfieldData(
theater="Normandy",
icao="B-9",
@@ -1361,7 +1231,6 @@ AIRFIELD_DATA = {
runway_length=3597,
atc=AtcData(MHz(4, 150), MHz(118, 800), MHz(39, 200), MHz(250, 800)),
),
-
"Sainte-Croix-sur-Mer": AirfieldData(
theater="Normandy",
icao="B-3",
@@ -1369,7 +1238,6 @@ AIRFIELD_DATA = {
runway_length=3840,
atc=AtcData(MHz(4, 50), MHz(118, 600), MHz(39, 000), MHz(250, 600)),
),
-
"Beny-sur-Mer": AirfieldData(
theater="Normandy",
icao="B-4",
@@ -1377,7 +1245,6 @@ AIRFIELD_DATA = {
runway_length=3155,
atc=AtcData(MHz(4, 75), MHz(118, 650), MHz(39, 50), MHz(250, 650)),
),
-
"Carpiquet": AirfieldData(
theater="Normandy",
icao="B-17",
@@ -1385,63 +1252,54 @@ AIRFIELD_DATA = {
runway_length=3799,
atc=AtcData(MHz(3, 975), MHz(118, 450), MHz(38, 850), MHz(250, 450)),
),
-
"Goulet": AirfieldData(
theater="Normandy",
elevation=616,
runway_length=3283,
atc=AtcData(MHz(4, 375), MHz(119, 250), MHz(39, 650), MHz(251, 250)),
),
-
"Argentan": AirfieldData(
theater="Normandy",
elevation=639,
runway_length=3283,
atc=AtcData(MHz(4, 350), MHz(119, 200), MHz(39, 600), MHz(251, 200)),
),
-
"Vrigny": AirfieldData(
theater="Normandy",
elevation=590,
runway_length=3283,
atc=AtcData(MHz(4, 475), MHz(119, 450), MHz(39, 850), MHz(251, 450)),
),
-
"Hauterive": AirfieldData(
theater="Normandy",
elevation=476,
runway_length=3283,
atc=AtcData(MHz(4, 450), MHz(119, 400), MHz(39, 800), MHz(251, 400)),
),
-
"Essay": AirfieldData(
theater="Normandy",
elevation=507,
runway_length=3283,
atc=AtcData(MHz(4, 425), MHz(119, 350), MHz(39, 750), MHz(251, 350)),
),
-
"Barville": AirfieldData(
theater="Normandy",
elevation=462,
runway_length=3493,
atc=AtcData(MHz(4, 400), MHz(119, 300), MHz(39, 700), MHz(251, 300)),
),
-
"Conches": AirfieldData(
theater="Normandy",
elevation=541,
runway_length=4199,
atc=AtcData(MHz(4, 525), MHz(119, 550), MHz(39, 950), MHz(251, 550)),
),
-
"Evreux": AirfieldData(
theater="Normandy",
elevation=423,
runway_length=4296,
atc=AtcData(MHz(4, 175), MHz(118, 850), MHz(39, 250), MHz(250, 850)),
),
-
# Channel Map
"Detling": AirfieldData(
theater="Channel",
@@ -1449,56 +1307,48 @@ AIRFIELD_DATA = {
runway_length=2557,
atc=AtcData(MHz(3, 950), MHz(118, 400), MHz(38, 800), MHz(250, 400)),
),
-
"High Halden": AirfieldData(
theater="Channel",
elevation=104,
runway_length=3296,
atc=AtcData(MHz(3, 750), MHz(118, 800), MHz(38, 400), MHz(250, 0)),
),
-
"Lympne": AirfieldData(
theater="Channel",
elevation=351,
runway_length=2548,
atc=AtcData(MHz(3, 925), MHz(118, 350), MHz(38, 750), MHz(250, 350)),
),
-
"Hawkinge": AirfieldData(
theater="Channel",
elevation=524,
runway_length=3013,
atc=AtcData(MHz(3, 900), MHz(118, 300), MHz(38, 700), MHz(250, 300)),
),
-
"Manston": AirfieldData(
theater="Channel",
elevation=160,
runway_length=8626,
atc=AtcData(MHz(3, 875), MHz(118, 250), MHz(38, 650), MHz(250, 250)),
),
-
"Dunkirk Mardyck": AirfieldData(
theater="Channel",
elevation=16,
runway_length=1737,
atc=AtcData(MHz(3, 850), MHz(118, 200), MHz(38, 600), MHz(250, 200)),
),
-
"Saint Omer Longuenesse": AirfieldData(
theater="Channel",
elevation=219,
runway_length=1929,
atc=AtcData(MHz(3, 825), MHz(118, 150), MHz(38, 550), MHz(250, 150)),
),
-
"Merville Calonne": AirfieldData(
theater="Channel",
elevation=52,
runway_length=7580,
atc=AtcData(MHz(3, 800), MHz(118, 100), MHz(38, 500), MHz(250, 100)),
),
-
"Abbeville Drucat": AirfieldData(
theater="Channel",
elevation=183,
diff --git a/gen/airsupportgen.py b/gen/airsupportgen.py
index ed13d830..9cdd4a34 100644
--- a/gen/airsupportgen.py
+++ b/gen/airsupportgen.py
@@ -32,6 +32,7 @@ AWACS_ALT = 13000
@dataclass
class AwacsInfo:
"""AWACS information for the kneeboard."""
+
dcsGroupName: str
callsign: str
freq: RadioFrequency
@@ -40,6 +41,7 @@ class AwacsInfo:
@dataclass
class TankerInfo:
"""Tanker information for the kneeboard."""
+
dcsGroupName: str
callsign: str
variant: str
@@ -54,10 +56,14 @@ class AirSupport:
class AirSupportConflictGenerator:
-
- def __init__(self, mission: Mission, conflict: Conflict, game,
- radio_registry: RadioRegistry,
- tacan_registry: TacanRegistry) -> None:
+ def __init__(
+ self,
+ mission: Mission,
+ conflict: Conflict,
+ game,
+ radio_registry: RadioRegistry,
+ tacan_registry: TacanRegistry,
+ ) -> None:
self.mission = mission
self.conflict = conflict
self.game = game
@@ -78,22 +84,37 @@ class AirSupportConflictGenerator:
elif unit_type is KC135MPRS:
return (TANKER_ALT + 500, 596)
return (TANKER_ALT, 574)
-
+
def generate(self):
- player_cp = self.conflict.from_cp if self.conflict.from_cp.captured else self.conflict.to_cp
+ player_cp = (
+ self.conflict.from_cp
+ if self.conflict.from_cp.captured
+ else self.conflict.to_cp
+ )
fallback_tanker_number = 0
- for i, tanker_unit_type in enumerate(db.find_unittype(Refueling, self.conflict.attackers_side)):
+ for i, tanker_unit_type in enumerate(
+ db.find_unittype(Refueling, self.conflict.attackers_side)
+ ):
alt, airspeed = self._get_tanker_params(tanker_unit_type)
- variant = db.unit_type_name(tanker_unit_type)
+ variant = db.unit_type_name(tanker_unit_type)
freq = self.radio_registry.alloc_uhf()
tacan = self.tacan_registry.alloc_for_band(TacanBand.Y)
- tanker_heading = self.conflict.to_cp.position.heading_between_point(self.conflict.from_cp.position) + TANKER_HEADING_OFFSET * i
- tanker_position = player_cp.position.point_from_heading(tanker_heading, TANKER_DISTANCE)
+ tanker_heading = (
+ self.conflict.to_cp.position.heading_between_point(
+ self.conflict.from_cp.position
+ )
+ + TANKER_HEADING_OFFSET * i
+ )
+ tanker_position = player_cp.position.point_from_heading(
+ tanker_heading, TANKER_DISTANCE
+ )
tanker_group = self.mission.refuel_flight(
country=self.mission.country(self.game.player_country),
- name=namegen.next_tanker_name(self.mission.country(self.game.player_country), tanker_unit_type),
+ name=namegen.next_tanker_name(
+ self.mission.country(self.game.player_country), tanker_unit_type
+ ),
airport=None,
plane_type=tanker_unit_type,
position=tanker_position,
@@ -124,28 +145,41 @@ class AirSupportConflictGenerator:
if tanker_unit_type != IL_78M:
# Override PyDCS tacan channel.
tanker_group.points[0].tasks.pop()
- tanker_group.points[0].tasks.append(ActivateBeaconCommand(
- tacan.number, tacan.band.value, tacan_callsign, True,
- tanker_group.units[0].id, True))
+ tanker_group.points[0].tasks.append(
+ ActivateBeaconCommand(
+ tacan.number,
+ tacan.band.value,
+ tacan_callsign,
+ True,
+ tanker_group.units[0].id,
+ True,
+ )
+ )
tanker_group.points[0].tasks.append(SetInvisibleCommand(True))
tanker_group.points[0].tasks.append(SetImmortalCommand(True))
- self.air_support.tankers.append(TankerInfo(str(tanker_group.name), callsign, variant, freq, tacan))
+ self.air_support.tankers.append(
+ TankerInfo(str(tanker_group.name), callsign, variant, freq, tacan)
+ )
possible_awacs = db.find_unittype(AWACS, self.conflict.attackers_side)
if len(possible_awacs) > 0:
awacs_unit = possible_awacs[0]
freq = self.radio_registry.alloc_uhf()
-
+
awacs_flight = self.mission.awacs_flight(
country=self.mission.country(self.game.player_country),
- name=namegen.next_awacs_name(self.mission.country(self.game.player_country)),
+ name=namegen.next_awacs_name(
+ self.mission.country(self.game.player_country)
+ ),
plane_type=awacs_unit,
altitude=AWACS_ALT,
airport=None,
- position=self.conflict.position.random_point_within(AWACS_DISTANCE, AWACS_DISTANCE),
+ position=self.conflict.position.random_point_within(
+ AWACS_DISTANCE, AWACS_DISTANCE
+ ),
frequency=freq.mhz,
start_type=StartType.Warm,
)
@@ -154,7 +188,12 @@ class AirSupportConflictGenerator:
awacs_flight.points[0].tasks.append(SetInvisibleCommand(True))
awacs_flight.points[0].tasks.append(SetImmortalCommand(True))
- self.air_support.awacs.append(AwacsInfo(
- str(awacs_flight.name), callsign_for_support_unit(awacs_flight), freq))
+ self.air_support.awacs.append(
+ AwacsInfo(
+ str(awacs_flight.name),
+ callsign_for_support_unit(awacs_flight),
+ freq,
+ )
+ )
else:
- logging.warning("No AWACS for faction")
\ No newline at end of file
+ logging.warning("No AWACS for faction")
diff --git a/gen/armor.py b/gen/armor.py
index 48311bdc..8f075d38 100644
--- a/gen/armor.py
+++ b/gen/armor.py
@@ -12,9 +12,17 @@ from dcs.country import Country
from dcs.mapping import Point
from dcs.planes import MQ_9_Reaper
from dcs.point import PointAction
-from dcs.task import (EPLRS, AttackGroup, ControlledTask, FireAtPoint,
- GoToWaypoint, Hold, OrbitAction, SetImmortalCommand,
- SetInvisibleCommand)
+from dcs.task import (
+ EPLRS,
+ AttackGroup,
+ ControlledTask,
+ FireAtPoint,
+ GoToWaypoint,
+ Hold,
+ OrbitAction,
+ SetImmortalCommand,
+ SetInvisibleCommand,
+)
from dcs.triggers import Event, TriggerOnce
from dcs.unit import Vehicle
from dcs.unitgroup import VehicleGroup
@@ -24,8 +32,11 @@ from game.unitmap import UnitMap
from game.utils import heading_sum, opposite_heading
from game.theater.controlpoint import ControlPoint
-from gen.ground_forces.ai_ground_planner import (DISTANCE_FROM_FRONTLINE,
- CombatGroup, CombatGroupRole)
+from gen.ground_forces.ai_ground_planner import (
+ DISTANCE_FROM_FRONTLINE,
+ CombatGroup,
+ CombatGroupRole,
+)
from .callsigns import callsign_for_support_unit
from .conflictgen import Conflict
@@ -56,6 +67,7 @@ INFANTRY_GROUP_SIZE = 5
@dataclass(frozen=True)
class JtacInfo:
"""JTAC information."""
+
dcsGroupName: str
unit_name: str
callsign: str
@@ -65,16 +77,16 @@ class JtacInfo:
class GroundConflictGenerator:
-
def __init__(
- self,
- mission: Mission,
- conflict: Conflict,
- game: Game,
- player_planned_combat_groups: List[CombatGroup],
- enemy_planned_combat_groups: List[CombatGroup],
- player_stance: CombatStance,
- unit_map: UnitMap) -> None:
+ self,
+ mission: Mission,
+ conflict: Conflict,
+ game: Game,
+ player_planned_combat_groups: List[CombatGroup],
+ enemy_planned_combat_groups: List[CombatGroup],
+ player_stance: CombatStance,
+ unit_map: UnitMap,
+ ) -> None:
self.mission = mission
self.conflict = conflict
self.enemy_planned_combat_groups = enemy_planned_combat_groups
@@ -87,14 +99,16 @@ class GroundConflictGenerator:
def _enemy_stance(self):
"""Picks the enemy stance according to the number of planned groups on the frontline for each side"""
- if len(self.enemy_planned_combat_groups) > len(self.player_planned_combat_groups):
+ if len(self.enemy_planned_combat_groups) > len(
+ self.player_planned_combat_groups
+ ):
return random.choice(
[
CombatStance.AGGRESSIVE,
CombatStance.AGGRESSIVE,
CombatStance.AGGRESSIVE,
CombatStance.ELIMINATION,
- CombatStance.BREAKTHROUGH
+ CombatStance.BREAKTHROUGH,
]
)
else:
@@ -104,31 +118,37 @@ class GroundConflictGenerator:
CombatStance.DEFENSIVE,
CombatStance.DEFENSIVE,
CombatStance.AMBUSH,
- CombatStance.AGGRESSIVE
+ CombatStance.AGGRESSIVE,
]
)
@staticmethod
def _group_point(point: Point, base_distance) -> Point:
distance = random.randint(
- int(base_distance * SPREAD_DISTANCE_FACTOR[0]),
- int(base_distance * SPREAD_DISTANCE_FACTOR[1]),
- )
- return point.random_point_within(distance, base_distance * SPREAD_DISTANCE_SIZE_FACTOR)
+ int(base_distance * SPREAD_DISTANCE_FACTOR[0]),
+ int(base_distance * SPREAD_DISTANCE_FACTOR[1]),
+ )
+ return point.random_point_within(
+ distance, base_distance * SPREAD_DISTANCE_SIZE_FACTOR
+ )
def generate(self):
- position = Conflict.frontline_position(self.conflict.from_cp, self.conflict.to_cp, self.game.theater)
+ position = Conflict.frontline_position(
+ self.conflict.from_cp, self.conflict.to_cp, self.game.theater
+ )
frontline_vector = Conflict.frontline_vector(
- self.conflict.from_cp,
- self.conflict.to_cp,
- self.game.theater
- )
+ self.conflict.from_cp, self.conflict.to_cp, self.game.theater
+ )
# Create player groups at random position
- player_groups = self._generate_groups(self.player_planned_combat_groups, frontline_vector, True)
+ player_groups = self._generate_groups(
+ self.player_planned_combat_groups, frontline_vector, True
+ )
# Create enemy groups at random position
- enemy_groups = self._generate_groups(self.enemy_planned_combat_groups, frontline_vector, False)
+ enemy_groups = self._generate_groups(
+ self.enemy_planned_combat_groups, frontline_vector, False
+ )
# Plan combat actions for groups
self.plan_action_for_groups(
@@ -137,7 +157,7 @@ class GroundConflictGenerator:
enemy_groups,
self.conflict.heading + 90,
self.conflict.from_cp,
- self.conflict.to_cp
+ self.conflict.to_cp,
)
self.plan_action_for_groups(
self.enemy_stance,
@@ -145,7 +165,7 @@ class GroundConflictGenerator:
player_groups,
self.conflict.heading - 90,
self.conflict.to_cp,
- self.conflict.from_cp
+ self.conflict.from_cp,
)
# Add JTAC
@@ -157,34 +177,38 @@ class GroundConflictGenerator:
if self.game.player_faction.jtac_unit is not None:
utype = self.game.player_faction.jtac_unit
- jtac = self.mission.flight_group(country=self.mission.country(self.game.player_country),
- name=n,
- aircraft_type=utype,
- position=position[0],
- airport=None,
- altitude=5000)
+ jtac = self.mission.flight_group(
+ country=self.mission.country(self.game.player_country),
+ name=n,
+ aircraft_type=utype,
+ position=position[0],
+ airport=None,
+ altitude=5000,
+ )
jtac.points[0].tasks.append(SetInvisibleCommand(True))
jtac.points[0].tasks.append(SetImmortalCommand(True))
- jtac.points[0].tasks.append(OrbitAction(5000, 300, OrbitAction.OrbitPattern.Circle))
- frontline = f"Frontline {self.conflict.from_cp.name}/{self.conflict.to_cp.name}"
+ jtac.points[0].tasks.append(
+ OrbitAction(5000, 300, OrbitAction.OrbitPattern.Circle)
+ )
+ frontline = (
+ f"Frontline {self.conflict.from_cp.name}/{self.conflict.to_cp.name}"
+ )
# Note: Will need to change if we ever add ground based JTAC.
callsign = callsign_for_support_unit(jtac)
- self.jtacs.append(JtacInfo(str(jtac.name), n, callsign, frontline, str(code)))
+ self.jtacs.append(
+ JtacInfo(str(jtac.name), n, callsign, frontline, str(code))
+ )
def gen_infantry_group_for_group(
- self,
- group: VehicleGroup,
- is_player: bool,
- side: Country,
- forward_heading: int
+ self, group: VehicleGroup, is_player: bool, side: Country, forward_heading: int
) -> None:
infantry_position = self.conflict.find_ground_position(
group.points[0].position.random_point_within(250, 50),
500,
forward_heading,
- self.conflict.theater
- )
+ self.conflict.theater,
+ )
if not infantry_position:
logging.warning("Could not find infantry position")
return
@@ -208,44 +232,50 @@ class GroundConflictGenerator:
u = random.choice(manpads)
self.mission.vehicle_group(
side,
- namegen.next_infantry_name(side, cp.id, u), u,
+ namegen.next_infantry_name(side, cp.id, u),
+ u,
position=infantry_position,
group_size=1,
heading=forward_heading,
- move_formation=PointAction.OffRoad)
+ move_formation=PointAction.OffRoad,
+ )
return
- possible_infantry_units = db.find_infantry(faction, allow_manpad=self.game.settings.manpads)
+ possible_infantry_units = db.find_infantry(
+ faction, allow_manpad=self.game.settings.manpads
+ )
if len(possible_infantry_units) == 0:
return
u = random.choice(possible_infantry_units)
self.mission.vehicle_group(
- side,
- namegen.next_infantry_name(side, cp.id, u), u,
- position=infantry_position,
- group_size=1,
- heading=forward_heading,
- move_formation=PointAction.OffRoad)
+ side,
+ namegen.next_infantry_name(side, cp.id, u),
+ u,
+ position=infantry_position,
+ group_size=1,
+ heading=forward_heading,
+ move_formation=PointAction.OffRoad,
+ )
for i in range(INFANTRY_GROUP_SIZE):
u = random.choice(possible_infantry_units)
position = infantry_position.random_point_within(55, 5)
self.mission.vehicle_group(
side,
- namegen.next_infantry_name(side, cp.id, u), u,
+ namegen.next_infantry_name(side, cp.id, u),
+ u,
position=position,
group_size=1,
heading=forward_heading,
- move_formation=PointAction.OffRoad)
+ move_formation=PointAction.OffRoad,
+ )
def _set_reform_waypoint(
- self,
- dcs_group: VehicleGroup,
- forward_heading: int
+ self, dcs_group: VehicleGroup, forward_heading: int
) -> None:
"""Setting a waypoint close to the spawn position allows the group to reform gracefully
- rather than spin
+ rather than spin
"""
reform_point = dcs_group.position.point_from_heading(forward_heading, 50)
dcs_group.add_waypoint(reform_point)
@@ -256,7 +286,7 @@ class GroundConflictGenerator:
gen_group: CombatGroup,
dcs_group: VehicleGroup,
forward_heading: int,
- target: Point
+ target: Point,
) -> bool:
"""
Handles adding the DCS tasks for artillery groups for all combat stances.
@@ -269,7 +299,9 @@ class GroundConflictGenerator:
dcs_group.add_trigger_action(hold_task)
# Artillery strike random start
- artillery_trigger = TriggerOnce(Event.NoEvent, "ArtilleryFireTask #" + str(dcs_group.id))
+ artillery_trigger = TriggerOnce(
+ Event.NoEvent, "ArtilleryFireTask #" + str(dcs_group.id)
+ )
artillery_trigger.add_condition(TimeAfter(seconds=random.randint(1, 45) * 60))
# TODO: Update to fire at group instead of point
fire_task = FireAtPoint(target, len(gen_group.units) * 10, 100)
@@ -283,12 +315,19 @@ class GroundConflictGenerator:
# Hold position
dcs_group.points[1].tasks.append(Hold())
- retreat = self.find_retreat_point(dcs_group, forward_heading, (int)(RETREAT_DISTANCE/3))
- dcs_group.add_waypoint(dcs_group.position.point_from_heading(forward_heading, 1), PointAction.OffRoad)
+ retreat = self.find_retreat_point(
+ dcs_group, forward_heading, (int)(RETREAT_DISTANCE / 3)
+ )
+ dcs_group.add_waypoint(
+ dcs_group.position.point_from_heading(forward_heading, 1),
+ PointAction.OffRoad,
+ )
dcs_group.points[2].tasks.append(Hold())
dcs_group.add_waypoint(retreat, PointAction.OffRoad)
- artillery_fallback = TriggerOnce(Event.NoEvent, "ArtilleryRetreat #" + str(dcs_group.id))
+ artillery_fallback = TriggerOnce(
+ Event.NoEvent, "ArtilleryRetreat #" + str(dcs_group.id)
+ )
for i, u in enumerate(dcs_group.units):
artillery_fallback.add_condition(UnitDamaged(u.id))
if i < len(dcs_group.units) - 1:
@@ -302,7 +341,9 @@ class GroundConflictGenerator:
retreat_task.number = 4
dcs_group.add_trigger_action(retreat_task)
- artillery_fallback.add_action(AITaskPush(dcs_group.id, len(dcs_group.tasks)))
+ artillery_fallback.add_action(
+ AITaskPush(dcs_group.id, len(dcs_group.tasks))
+ )
self.mission.triggerrules.triggers.append(artillery_fallback)
for u in dcs_group.units:
@@ -330,12 +371,8 @@ class GroundConflictGenerator:
target = self.find_nearest_enemy_group(dcs_group, enemy_groups)
if target is not None:
rand_offset = Point(
- random.randint(
- -RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK
- ),
- random.randint(
- -RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK
- )
+ random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK),
+ random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK),
)
target_point = self.conflict.theater.nearest_land_pos(
target.points[0].position + rand_offset
@@ -345,8 +382,7 @@ class GroundConflictGenerator:
if (
to_cp.position.distance_to_point(dcs_group.points[0].position)
- <=
- AGGRESIVE_MOVE_DISTANCE
+ <= AGGRESIVE_MOVE_DISTANCE
):
attack_point = self.conflict.theater.nearest_land_pos(
to_cp.position.random_point_within(500, 0)
@@ -358,16 +394,16 @@ class GroundConflictGenerator:
if offset_heading < 0:
offset_heading = 358
attack_point = self.find_offensive_point(
- dcs_group,
- offset_heading,
- AGGRESIVE_MOVE_DISTANCE
+ dcs_group, offset_heading, AGGRESIVE_MOVE_DISTANCE
)
dcs_group.add_waypoint(attack_point, PointAction.OffRoad)
elif stance == CombatStance.BREAKTHROUGH:
# In breakthrough mode, the units will move forward
# If the enemy base is close enough, the units will attack the base
- if to_cp.position.distance_to_point(
- dcs_group.points[0].position) <= BREAKTHROUGH_OFFENSIVE_DISTANCE:
+ if (
+ to_cp.position.distance_to_point(dcs_group.points[0].position)
+ <= BREAKTHROUGH_OFFENSIVE_DISTANCE
+ ):
attack_point = self.conflict.theater.nearest_land_pos(
to_cp.position.random_point_within(500, 0)
)
@@ -377,27 +413,27 @@ class GroundConflictGenerator:
offset_heading = forward_heading - 1
if offset_heading < 0:
offset_heading = 359
- attack_point = self.find_offensive_point(dcs_group, offset_heading, BREAKTHROUGH_OFFENSIVE_DISTANCE)
+ attack_point = self.find_offensive_point(
+ dcs_group, offset_heading, BREAKTHROUGH_OFFENSIVE_DISTANCE
+ )
dcs_group.add_waypoint(attack_point, PointAction.OffRoad)
elif stance == CombatStance.ELIMINATION:
# In elimination mode, the units focus on destroying as much enemy groups as possible
targets = self.find_n_nearest_enemy_groups(dcs_group, enemy_groups, 3)
for i, target in enumerate(targets, start=1):
rand_offset = Point(
- random.randint(
- -RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK
- ),
- random.randint(
- -RANDOM_OFFSET_ATTACK,
- RANDOM_OFFSET_ATTACK
- )
+ random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK),
+ random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK),
)
target_point = self.conflict.theater.nearest_land_pos(
- target.points[0].position+rand_offset
+ target.points[0].position + rand_offset
)
dcs_group.add_waypoint(target_point, PointAction.OffRoad)
dcs_group.points[i + 1].tasks.append(AttackGroup(target.id))
- if to_cp.position.distance_to_point(dcs_group.points[0].position) <= AGGRESIVE_MOVE_DISTANCE:
+ if (
+ to_cp.position.distance_to_point(dcs_group.points[0].position)
+ <= AGGRESIVE_MOVE_DISTANCE
+ ):
attack_point = self.conflict.theater.nearest_land_pos(
to_cp.position.random_point_within(500, 0)
)
@@ -420,12 +456,23 @@ class GroundConflictGenerator:
Returns True if tasking was added, returns False if the stance was not a combat stance.
"""
self._set_reform_waypoint(dcs_group, forward_heading)
- if stance in [CombatStance.AGGRESSIVE, CombatStance.BREAKTHROUGH, CombatStance.ELIMINATION]:
+ if stance in [
+ CombatStance.AGGRESSIVE,
+ CombatStance.BREAKTHROUGH,
+ CombatStance.ELIMINATION,
+ ]:
# APC & ATGM will never move too much forward, but will follow along any offensive
- if to_cp.position.distance_to_point(dcs_group.points[0].position) <= AGGRESIVE_MOVE_DISTANCE:
- attack_point = self.conflict.theater.nearest_land_pos(to_cp.position.random_point_within(500, 0))
+ if (
+ to_cp.position.distance_to_point(dcs_group.points[0].position)
+ <= AGGRESIVE_MOVE_DISTANCE
+ ):
+ attack_point = self.conflict.theater.nearest_land_pos(
+ to_cp.position.random_point_within(500, 0)
+ )
else:
- attack_point = self.find_offensive_point(dcs_group, forward_heading, AGGRESIVE_MOVE_DISTANCE)
+ attack_point = self.find_offensive_point(
+ dcs_group, forward_heading, AGGRESIVE_MOVE_DISTANCE
+ )
dcs_group.add_waypoint(attack_point, PointAction.OffRoad)
if stance != CombatStance.RETREAT:
@@ -434,29 +481,36 @@ class GroundConflictGenerator:
return False
def plan_action_for_groups(
- self, stance: CombatStance,
+ self,
+ stance: CombatStance,
ally_groups: List[Tuple[VehicleGroup, CombatGroup]],
enemy_groups: List[Tuple[VehicleGroup, CombatGroup]],
forward_heading: int,
from_cp: ControlPoint,
- to_cp: ControlPoint
+ to_cp: ControlPoint,
) -> None:
if not self.game.settings.perf_moving_units:
return
for dcs_group, group in ally_groups:
- if hasattr(group.units[0], 'eplrs') and group.units[0].eplrs:
+ if hasattr(group.units[0], "eplrs") and group.units[0].eplrs:
dcs_group.points[0].tasks.append(EPLRS(dcs_group.id))
if group.role == CombatGroupRole.ARTILLERY:
if self.game.settings.perf_artillery:
- target = self.get_artillery_target_in_range(dcs_group, group, enemy_groups)
+ target = self.get_artillery_target_in_range(
+ dcs_group, group, enemy_groups
+ )
if target is not None:
- self._plan_artillery_action(stance, group, dcs_group, forward_heading, target)
+ self._plan_artillery_action(
+ stance, group, dcs_group, forward_heading, target
+ )
elif group.role in [CombatGroupRole.TANK, CombatGroupRole.IFV]:
- self._plan_tank_ifv_action(stance, enemy_groups, dcs_group, forward_heading, to_cp)
+ self._plan_tank_ifv_action(
+ stance, enemy_groups, dcs_group, forward_heading, to_cp
+ )
elif group.role in [CombatGroupRole.APC, CombatGroupRole.ATGM]:
self._plan_apc_atgm_action(stance, dcs_group, forward_heading, to_cp)
@@ -464,11 +518,16 @@ class GroundConflictGenerator:
if stance == CombatStance.RETREAT:
# In retreat mode, the units will fall back
# If the ally base is close enough, the units will even regroup there
- if from_cp.position.distance_to_point(dcs_group.points[0].position) <= RETREAT_DISTANCE:
+ if (
+ from_cp.position.distance_to_point(dcs_group.points[0].position)
+ <= RETREAT_DISTANCE
+ ):
retreat_point = from_cp.position.random_point_within(500, 250)
else:
retreat_point = self.find_retreat_point(dcs_group, forward_heading)
- reposition_point = retreat_point.point_from_heading(forward_heading, 10) # Another point to make the unit face the enemy
+ reposition_point = retreat_point.point_from_heading(
+ forward_heading, 10
+ ) # Another point to make the unit face the enemy
dcs_group.add_waypoint(retreat_point, PointAction.OffRoad)
dcs_group.add_waypoint(reposition_point, PointAction.OffRoad)
@@ -490,8 +549,10 @@ class GroundConflictGenerator:
# We add a new retreat waypoint
dcs_group.add_waypoint(
- self.find_retreat_point(dcs_group, forward_heading, (int)(RETREAT_DISTANCE / 8)),
- PointAction.OffRoad
+ self.find_retreat_point(
+ dcs_group, forward_heading, (int)(RETREAT_DISTANCE / 8)
+ ),
+ PointAction.OffRoad,
)
# Fallback task
@@ -515,7 +576,7 @@ class GroundConflictGenerator:
self,
dcs_group: VehicleGroup,
frontline_heading: int,
- distance: int = RETREAT_DISTANCE
+ distance: int = RETREAT_DISTANCE,
) -> Point:
"""
Find a point to retreat to
@@ -523,17 +584,15 @@ class GroundConflictGenerator:
:param frontline_heading: Heading of the frontline
:return: dcs.mapping.Point object with the desired position
"""
- desired_point = dcs_group.points[0].position.point_from_heading(heading_sum(frontline_heading, +180), distance)
+ desired_point = dcs_group.points[0].position.point_from_heading(
+ heading_sum(frontline_heading, +180), distance
+ )
if self.conflict.theater.is_on_land(desired_point):
return desired_point
return self.conflict.theater.nearest_land_pos(desired_point)
-
def find_offensive_point(
- self,
- dcs_group: VehicleGroup,
- frontline_heading: int,
- distance: int
+ self, dcs_group: VehicleGroup, frontline_heading: int, distance: int
) -> Point:
"""
Find a point to attack
@@ -542,7 +601,9 @@ class GroundConflictGenerator:
:param distance: Distance of the offensive (how far unit should move)
:return: dcs.mapping.Point object with the desired position
"""
- desired_point = dcs_group.points[0].position.point_from_heading(frontline_heading, distance)
+ desired_point = dcs_group.points[0].position.point_from_heading(
+ frontline_heading, distance
+ )
if self.conflict.theater.is_on_land(desired_point):
return desired_point
return self.conflict.theater.nearest_land_pos(desired_point)
@@ -551,7 +612,7 @@ class GroundConflictGenerator:
def find_n_nearest_enemy_groups(
player_group: VehicleGroup,
enemy_groups: List[Tuple[VehicleGroup, CombatGroup]],
- n: int
+ n: int,
) -> List[VehicleGroup]:
"""
Return the nearest enemy group for the player group
@@ -562,7 +623,9 @@ class GroundConflictGenerator:
targets = [] # type: List[Optional[VehicleGroup]]
sorted_list = sorted(
enemy_groups,
- key=lambda group: player_group.points[0].position.distance_to_point(group[0].points[0].position)
+ key=lambda group: player_group.points[0].position.distance_to_point(
+ group[0].points[0].position
+ ),
)
for i in range(n):
# TODO: Is this supposed to return no groups if enemy_groups is less than n?
@@ -574,8 +637,7 @@ class GroundConflictGenerator:
@staticmethod
def find_nearest_enemy_group(
- player_group: VehicleGroup,
- enemy_groups: List[Tuple[VehicleGroup, CombatGroup]]
+ player_group: VehicleGroup, enemy_groups: List[Tuple[VehicleGroup, CombatGroup]]
) -> Optional[VehicleGroup]:
"""
Search the enemy groups for a potential target suitable to armored assault
@@ -585,7 +647,9 @@ class GroundConflictGenerator:
min_distance = 99999999
target = None
for dcs_group, _ in enemy_groups:
- dist = player_group.points[0].position.distance_to_point(dcs_group.points[0].position)
+ dist = player_group.points[0].position.distance_to_point(
+ dcs_group.points[0].position
+ )
if dist < min_distance:
min_distance = dist
target = dcs_group
@@ -595,7 +659,7 @@ class GroundConflictGenerator:
def get_artillery_target_in_range(
dcs_group: VehicleGroup,
group: CombatGroup,
- enemy_groups: List[Tuple[VehicleGroup, CombatGroup]]
+ enemy_groups: List[Tuple[VehicleGroup, CombatGroup]],
) -> Optional[Point]:
"""
Search the enemy groups for a potential target suitable to an artillery unit
@@ -606,7 +670,9 @@ class GroundConflictGenerator:
return None
for _ in range(10):
potential_target = random.choice(enemy_groups)[0]
- distance_to_target = dcs_group.points[0].position.distance_to_point(potential_target.points[0].position)
+ distance_to_target = dcs_group.points[0].position.distance_to_point(
+ potential_target.points[0].position
+ )
if distance_to_target < rng:
return potential_target.points[0].position
return None
@@ -620,12 +686,12 @@ class GroundConflictGenerator:
if rg > DISTANCE_FROM_FRONTLINE[CombatGroupRole.ARTILLERY][1]:
rg = random.randint(
DISTANCE_FROM_FRONTLINE[CombatGroupRole.ARTILLERY][0],
- DISTANCE_FROM_FRONTLINE[CombatGroupRole.ARTILLERY][1]
+ DISTANCE_FROM_FRONTLINE[CombatGroupRole.ARTILLERY][1],
)
elif rg < DISTANCE_FROM_FRONTLINE[CombatGroupRole.ARTILLERY][1]:
rg = random.randint(
DISTANCE_FROM_FRONTLINE[CombatGroupRole.TANK][0],
- DISTANCE_FROM_FRONTLINE[CombatGroupRole.TANK][1]
+ DISTANCE_FROM_FRONTLINE[CombatGroupRole.TANK][1],
)
return rg
@@ -635,42 +701,46 @@ class GroundConflictGenerator:
combat_width: int,
distance_from_frontline: int,
heading: int,
- spawn_heading: int
+ spawn_heading: int,
):
- shifted = conflict_position.point_from_heading(heading, random.randint(0, combat_width))
- desired_point = shifted.point_from_heading(
- spawn_heading,
- distance_from_frontline
+ shifted = conflict_position.point_from_heading(
+ heading, random.randint(0, combat_width)
+ )
+ desired_point = shifted.point_from_heading(
+ spawn_heading, distance_from_frontline
+ )
+ return Conflict.find_ground_position(
+ desired_point, combat_width, heading, self.conflict.theater
)
- return Conflict.find_ground_position(desired_point, combat_width, heading, self.conflict.theater)
-
def _generate_groups(
self,
groups: List[CombatGroup],
frontline_vector: Tuple[Point, int, int],
- is_player: bool
+ is_player: bool,
) -> List[Tuple[VehicleGroup, CombatGroup]]:
"""Finds valid positions for planned groups and generates a pydcs group for them"""
positioned_groups = []
position, heading, combat_width = frontline_vector
- spawn_heading = int(heading_sum(heading, -90)) if is_player else int(heading_sum(heading, 90))
+ spawn_heading = (
+ int(heading_sum(heading, -90))
+ if is_player
+ else int(heading_sum(heading, 90))
+ )
country = self.game.player_country if is_player else self.game.enemy_country
for group in groups:
if group.role == CombatGroupRole.ARTILLERY:
- distance_from_frontline = self.get_artilery_group_distance_from_frontline(group)
+ distance_from_frontline = (
+ self.get_artilery_group_distance_from_frontline(group)
+ )
else:
distance_from_frontline = random.randint(
- DISTANCE_FROM_FRONTLINE[group.role][0],
- DISTANCE_FROM_FRONTLINE[group.role][1]
+ DISTANCE_FROM_FRONTLINE[group.role][0],
+ DISTANCE_FROM_FRONTLINE[group.role][1],
)
final_position = self.get_valid_position_for_group(
- position,
- combat_width,
- distance_from_frontline,
- heading,
- spawn_heading
+ position, combat_width, distance_from_frontline, heading, spawn_heading
)
if final_position is not None:
@@ -693,7 +763,7 @@ class GroundConflictGenerator:
g,
is_player,
self.mission.country(country),
- opposite_heading(spawn_heading)
+ opposite_heading(spawn_heading),
)
else:
logging.warning(f"Unable to get valid position for {group}")
@@ -718,12 +788,14 @@ class GroundConflictGenerator:
logging.info("armorgen: {} for {}".format(unit, side.id))
group = self.mission.vehicle_group(
- side,
- namegen.next_unit_name(side, cp.id, unit), unit,
- position=at,
- group_size=count,
- heading=heading,
- move_formation=move_formation)
+ side,
+ namegen.next_unit_name(side, cp.id, unit),
+ unit,
+ position=at,
+ group_size=count,
+ heading=heading,
+ move_formation=move_formation,
+ )
self.unit_map.add_front_line_units(group, cp)
diff --git a/gen/ato.py b/gen/ato.py
index 99a76789..f76e667a 100644
--- a/gen/ato.py
+++ b/gen/ato.py
@@ -96,7 +96,8 @@ class Package:
if tot is None:
logging.error(
f"{flight} requested escort at {waypoint} but that "
- "waypoint has no TOT. It may not be escorted.")
+ "waypoint has no TOT. It may not be escorted."
+ )
continue
times.append(tot)
if times:
@@ -117,7 +118,8 @@ class Package:
logging.error(
f"{flight} dismissed escort at {waypoint} but that "
"waypoint has no TOT or departure time. It may not be "
- "escorted.")
+ "escorted."
+ )
continue
times.append(tot)
if times:
diff --git a/gen/briefinggen.py b/gen/briefinggen.py
index 14cef8de..b1246c78 100644
--- a/gen/briefinggen.py
+++ b/gen/briefinggen.py
@@ -23,9 +23,11 @@ from .runways import RunwayData
if TYPE_CHECKING:
from game import Game
+
@dataclass
class CommInfo:
"""Communications information for the kneeboard."""
+
name: str
freq: RadioFrequency
@@ -37,10 +39,13 @@ class FrontLineInfo:
self.enemy_base: ControlPoint = front_line.control_point_b
self.player_zero: bool = self.player_base.base.total_armor == 0
self.enemy_zero: bool = self.enemy_base.base.total_armor == 0
- self.advantage: bool = self.player_base.base.total_armor > self.enemy_base.base.total_armor
+ self.advantage: bool = (
+ self.player_base.base.total_armor > self.enemy_base.base.total_armor
+ )
self.stance: CombatStance = self.player_base.stances[self.enemy_base.id]
self.combat_stances = CombatStance
+
class MissionInfoGenerator:
"""Base type for generators of mission information for the player.
@@ -131,7 +136,6 @@ def format_waypoint_time(waypoint: FlightWaypoint, depart_prefix: str) -> str:
class BriefingGenerator(MissionInfoGenerator):
-
def __init__(self, mission: Mission, game: Game):
super().__init__(mission, game)
self.allied_flights_by_departure: Dict[str, List[FlightData]] = {}
@@ -141,36 +145,36 @@ class BriefingGenerator(MissionInfoGenerator):
disabled_extensions=("",),
default_for_string=True,
default=True,
- ),
+ ),
trim_blocks=True,
lstrip_blocks=True,
- )
+ )
env.filters["waypoint_timing"] = format_waypoint_time
self.template = env.get_template("briefingtemplate_EN.j2")
def generate(self) -> None:
- """Generate the mission briefing
- """
+ """Generate the mission briefing"""
self._generate_frontline_info()
self.generate_allied_flights_by_departure()
self.mission.set_description_text(self.template.render(vars(self)))
- self.mission.add_picture_blue(os.path.abspath(
- "./resources/ui/splash_screen.png"))
+ self.mission.add_picture_blue(
+ os.path.abspath("./resources/ui/splash_screen.png")
+ )
def _generate_frontline_info(self) -> None:
- """Build FrontLineInfo objects from FrontLine type and append to briefing.
- """
+ """Build FrontLineInfo objects from FrontLine type and append to briefing."""
for front_line in self.game.theater.conflicts(from_player=True):
self.add_frontline(FrontLineInfo(front_line))
# TODO: This should determine if runway is friendly through a method more robust than the existing string match
def generate_allied_flights_by_departure(self) -> None:
- """Create iterable to display allied flights grouped by departure airfield.
- """
+ """Create iterable to display allied flights grouped by departure airfield."""
for flight in self.flights:
if not flight.client_units and flight.friendly:
name = flight.departure.airfield_name
- if name in self.allied_flights_by_departure: # where else can we get this?
+ if (
+ name in self.allied_flights_by_departure
+ ): # where else can we get this?
self.allied_flights_by_departure[name].append(flight)
else:
self.allied_flights_by_departure[name] = [flight]
diff --git a/gen/conflictgen.py b/gen/conflictgen.py
index b050e028..25e1fed3 100644
--- a/gen/conflictgen.py
+++ b/gen/conflictgen.py
@@ -12,19 +12,21 @@ from game.utils import heading_sum, opposite_heading
FRONTLINE_LENGTH = 80000
+
class Conflict:
- def __init__(self,
- theater: ConflictTheater,
- from_cp: ControlPoint,
- to_cp: ControlPoint,
- attackers_side: str,
- defenders_side: str,
- attackers_country: Country,
- defenders_country: Country,
- position: Point,
- heading: Optional[int] = None,
- size: Optional[int] = None
- ):
+ def __init__(
+ self,
+ theater: ConflictTheater,
+ from_cp: ControlPoint,
+ to_cp: ControlPoint,
+ attackers_side: str,
+ defenders_side: str,
+ attackers_country: Country,
+ defenders_country: Country,
+ position: Point,
+ heading: Optional[int] = None,
+ size: Optional[int] = None,
+ ):
self.attackers_side = attackers_side
self.defenders_side = defenders_side
@@ -43,27 +45,49 @@ class Conflict:
return from_cp.has_frontline and to_cp.has_frontline
@classmethod
- def frontline_position(cls, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater) -> Tuple[Point, int]:
+ def frontline_position(
+ cls, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater
+ ) -> Tuple[Point, int]:
frontline = FrontLine(from_cp, to_cp, theater)
attack_heading = frontline.attack_heading
- position = cls.find_ground_position(frontline.position, FRONTLINE_LENGTH, heading_sum(attack_heading, 90), theater)
+ position = cls.find_ground_position(
+ frontline.position,
+ FRONTLINE_LENGTH,
+ heading_sum(attack_heading, 90),
+ theater,
+ )
return position, opposite_heading(attack_heading)
@classmethod
- def frontline_vector(cls, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater) -> Tuple[Point, int, int]:
+ def frontline_vector(
+ cls, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater
+ ) -> Tuple[Point, int, int]:
"""
Returns a vector for a valid frontline location avoiding exclusion zones.
"""
center_position, heading = cls.frontline_position(from_cp, to_cp, theater)
left_heading = heading_sum(heading, -90)
right_heading = heading_sum(heading, 90)
- left_position = cls.extend_ground_position(center_position, int(FRONTLINE_LENGTH / 2), left_heading, theater)
- right_position = cls.extend_ground_position(center_position, int(FRONTLINE_LENGTH / 2), right_heading, theater)
+ left_position = cls.extend_ground_position(
+ center_position, int(FRONTLINE_LENGTH / 2), left_heading, theater
+ )
+ right_position = cls.extend_ground_position(
+ center_position, int(FRONTLINE_LENGTH / 2), right_heading, theater
+ )
distance = int(left_position.distance_to_point(right_position))
return left_position, right_heading, distance
@classmethod
- def frontline_cas_conflict(cls, attacker_name: str, defender_name: str, attacker: Country, defender: Country, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater):
+ def frontline_cas_conflict(
+ cls,
+ attacker_name: str,
+ defender_name: str,
+ attacker: Country,
+ defender: Country,
+ from_cp: ControlPoint,
+ to_cp: ControlPoint,
+ theater: ConflictTheater,
+ ):
assert cls.has_frontline_between(from_cp, to_cp)
position, heading, distance = cls.frontline_vector(from_cp, to_cp, theater)
conflict = cls(
@@ -76,12 +100,14 @@ class Conflict:
defenders_side=defender_name,
attackers_country=attacker,
defenders_country=defender,
- size=distance
+ size=distance,
)
return conflict
@classmethod
- def extend_ground_position(cls, initial: Point, max_distance: int, heading: int, theater: ConflictTheater) -> Point:
+ def extend_ground_position(
+ cls, initial: Point, max_distance: int, heading: int, theater: ConflictTheater
+ ) -> Point:
"""Finds the first intersection with an exclusion zone in one heading from an initial point up to max_distance"""
extended = initial.point_from_heading(heading, max_distance)
if theater.landmap is None:
@@ -92,8 +118,7 @@ class Conflict:
p1 = ShapelyPoint(extended.x, extended.y)
line = LineString([p0, p1])
- intersection = line.intersection(
- theater.landmap.inclusion_zone_only.boundary)
+ intersection = line.intersection(theater.landmap.inclusion_zone_only.boundary)
if intersection.is_empty:
# Max extent does not intersect with the boundary of the inclusion
# zone, so the full front line is usable. This does assume that the
@@ -104,7 +129,14 @@ class Conflict:
return initial.point_from_heading(heading, p0.distance(intersection))
@classmethod
- def find_ground_position(cls, initial: Point, max_distance: int, heading: int, theater: ConflictTheater, coerce=True) -> Optional[Point]:
+ def find_ground_position(
+ cls,
+ initial: Point,
+ max_distance: int,
+ heading: int,
+ theater: ConflictTheater,
+ coerce=True,
+ ) -> Optional[Point]:
"""
Finds the nearest valid ground position along a provided heading and it's inverse up to max_distance.
`coerce=True` will return the closest land position to `initial` regardless of heading or distance
@@ -123,4 +155,3 @@ class Conflict:
return pos
logging.error("Didn't find ground position ({})!".format(initial))
return None
-
diff --git a/gen/defenses/armor_group_generator.py b/gen/defenses/armor_group_generator.py
index c8bc472c..fe429e72 100644
--- a/gen/defenses/armor_group_generator.py
+++ b/gen/defenses/armor_group_generator.py
@@ -3,15 +3,20 @@ import random
from dcs.vehicles import Armor
from game import db
-from gen.defenses.armored_group_generator import ArmoredGroupGenerator, FixedSizeArmorGroupGenerator
+from gen.defenses.armored_group_generator import (
+ ArmoredGroupGenerator,
+ FixedSizeArmorGroupGenerator,
+)
-def generate_armor_group(faction:str, game, ground_object):
+def generate_armor_group(faction: str, game, ground_object):
"""
This generate a group of ground units
:return: Generated group
"""
- possible_unit = [u for u in db.FACTIONS[faction].frontline_units if u in Armor.__dict__.values()]
+ possible_unit = [
+ u for u in db.FACTIONS[faction].frontline_units if u in Armor.__dict__.values()
+ ]
if len(possible_unit) > 0:
unit_type = random.choice(possible_unit)
return generate_armor_group_of_type(game, ground_object, unit_type)
@@ -36,4 +41,3 @@ def generate_armor_group_of_type_and_size(game, ground_object, unit_type, size:
generator = FixedSizeArmorGroupGenerator(game, ground_object, unit_type, size)
generator.generate()
return generator.get_generated_group()
-
diff --git a/gen/defenses/armored_group_generator.py b/gen/defenses/armored_group_generator.py
index 3b81a1dd..e25f5c74 100644
--- a/gen/defenses/armored_group_generator.py
+++ b/gen/defenses/armored_group_generator.py
@@ -4,7 +4,6 @@ from gen.sam.group_generator import GroupGenerator
class ArmoredGroupGenerator(GroupGenerator):
-
def __init__(self, game, ground_object, unit_type):
super(ArmoredGroupGenerator, self).__init__(game, ground_object)
self.unit_type = unit_type
@@ -20,13 +19,16 @@ class ArmoredGroupGenerator(GroupGenerator):
for i in range(grid_x):
for j in range(grid_y):
index = index + 1
- self.add_unit(self.unit_type, "Armor#" + str(index),
- self.position.x + spacing * i,
- self.position.y + spacing * j, self.heading)
+ self.add_unit(
+ self.unit_type,
+ "Armor#" + str(index),
+ self.position.x + spacing * i,
+ self.position.y + spacing * j,
+ self.heading,
+ )
class FixedSizeArmorGroupGenerator(GroupGenerator):
-
def __init__(self, game, ground_object, unit_type, size):
super(FixedSizeArmorGroupGenerator, self).__init__(game, ground_object)
self.unit_type = unit_type
@@ -38,7 +40,10 @@ class FixedSizeArmorGroupGenerator(GroupGenerator):
index = 0
for i in range(self.size):
index = index + 1
- self.add_unit(self.unit_type, "Armor#" + str(index),
- self.position.x + spacing * i,
- self.position.y, self.heading)
-
+ self.add_unit(
+ self.unit_type,
+ "Armor#" + str(index),
+ self.position.x + spacing * i,
+ self.position.y,
+ self.heading,
+ )
diff --git a/gen/fleet/carrier_group.py b/gen/fleet/carrier_group.py
index a06ebaee..2ecf869f 100644
--- a/gen/fleet/carrier_group.py
+++ b/gen/fleet/carrier_group.py
@@ -4,23 +4,48 @@ from gen.sam.group_generator import ShipGroupGenerator
class CarrierGroupGenerator(ShipGroupGenerator):
-
def generate(self):
# Add carrier
if len(self.faction.aircraft_carrier) > 0:
carrier_type = random.choice(self.faction.aircraft_carrier)
- self.add_unit(carrier_type, "Carrier", self.position.x, self.position.y, self.heading)
+ self.add_unit(
+ carrier_type, "Carrier", self.position.x, self.position.y, self.heading
+ )
else:
return
# Add destroyers escort
if len(self.faction.destroyers) > 0:
dd_type = random.choice(self.faction.destroyers)
- self.add_unit(dd_type, "DD1", self.position.x + 2500, self.position.y + 4500, self.heading)
- self.add_unit(dd_type, "DD2", self.position.x + 2500, self.position.y - 4500, self.heading)
+ self.add_unit(
+ dd_type,
+ "DD1",
+ self.position.x + 2500,
+ self.position.y + 4500,
+ self.heading,
+ )
+ self.add_unit(
+ dd_type,
+ "DD2",
+ self.position.x + 2500,
+ self.position.y - 4500,
+ self.heading,
+ )
- self.add_unit(dd_type, "DD3", self.position.x + 4500, self.position.y + 8500, self.heading)
- self.add_unit(dd_type, "DD4", self.position.x + 4500, self.position.y - 8500, self.heading)
+ self.add_unit(
+ dd_type,
+ "DD3",
+ self.position.x + 4500,
+ self.position.y + 8500,
+ self.heading,
+ )
+ self.add_unit(
+ dd_type,
+ "DD4",
+ self.position.x + 4500,
+ self.position.y - 8500,
+ self.heading,
+ )
self.get_generated_group().points[0].speed = 20
diff --git a/gen/fleet/cn_dd_group.py b/gen/fleet/cn_dd_group.py
index 8a20ae10..0878e61b 100644
--- a/gen/fleet/cn_dd_group.py
+++ b/gen/fleet/cn_dd_group.py
@@ -20,7 +20,6 @@ if TYPE_CHECKING:
class ChineseNavyGroupGenerator(ShipGroupGenerator):
-
def generate(self):
include_frigate = random.choice([True, True, False])
@@ -30,17 +29,45 @@ class ChineseNavyGroupGenerator(ShipGroupGenerator):
include_frigate = True
if include_frigate:
- self.add_unit(Type_054A_Frigate, "FF1", self.position.x + 1200, self.position.y + 900, self.heading)
- self.add_unit(Type_054A_Frigate, "FF2", self.position.x + 1200, self.position.y - 900, self.heading)
+ self.add_unit(
+ Type_054A_Frigate,
+ "FF1",
+ self.position.x + 1200,
+ self.position.y + 900,
+ self.heading,
+ )
+ self.add_unit(
+ Type_054A_Frigate,
+ "FF2",
+ self.position.x + 1200,
+ self.position.y - 900,
+ self.heading,
+ )
if include_dd:
dd_type = random.choice([Type_052C_Destroyer, Type_052B_Destroyer])
- self.add_unit(dd_type, "DD1", self.position.x + 2400, self.position.y + 900, self.heading)
- self.add_unit(dd_type, "DD2", self.position.x + 2400, self.position.y - 900, self.heading)
+ self.add_unit(
+ dd_type,
+ "DD1",
+ self.position.x + 2400,
+ self.position.y + 900,
+ self.heading,
+ )
+ self.add_unit(
+ dd_type,
+ "DD2",
+ self.position.x + 2400,
+ self.position.y - 900,
+ self.heading,
+ )
self.get_generated_group().points[0].speed = 20
class Type54GroupGenerator(DDGroupGenerator):
- def __init__(self, game: Game, ground_object: TheaterGroundObject, faction: Faction):
- super(Type54GroupGenerator, self).__init__(game, ground_object, faction, Type_054A_Frigate)
+ def __init__(
+ self, game: Game, ground_object: TheaterGroundObject, faction: Faction
+ ):
+ super(Type54GroupGenerator, self).__init__(
+ game, ground_object, faction, Type_054A_Frigate
+ )
diff --git a/gen/fleet/dd_group.py b/gen/fleet/dd_group.py
index c6a3e115..767eb52a 100644
--- a/gen/fleet/dd_group.py
+++ b/gen/fleet/dd_group.py
@@ -13,22 +13,47 @@ if TYPE_CHECKING:
class DDGroupGenerator(ShipGroupGenerator):
-
- def __init__(self, game: Game, ground_object: TheaterGroundObject, faction: Faction, ddtype: ShipType):
+ def __init__(
+ self,
+ game: Game,
+ ground_object: TheaterGroundObject,
+ faction: Faction,
+ ddtype: ShipType,
+ ):
super(DDGroupGenerator, self).__init__(game, ground_object, faction)
self.ddtype = ddtype
def generate(self):
- self.add_unit(self.ddtype, "DD1", self.position.x + 500, self.position.y + 900, self.heading)
- self.add_unit(self.ddtype, "DD2", self.position.x + 500, self.position.y - 900, self.heading)
+ self.add_unit(
+ self.ddtype,
+ "DD1",
+ self.position.x + 500,
+ self.position.y + 900,
+ self.heading,
+ )
+ self.add_unit(
+ self.ddtype,
+ "DD2",
+ self.position.x + 500,
+ self.position.y - 900,
+ self.heading,
+ )
self.get_generated_group().points[0].speed = 20
class OliverHazardPerryGroupGenerator(DDGroupGenerator):
- def __init__(self, game: Game, ground_object: TheaterGroundObject, faction: Faction):
- super(OliverHazardPerryGroupGenerator, self).__init__(game, ground_object, faction, Oliver_Hazzard_Perry_class)
+ def __init__(
+ self, game: Game, ground_object: TheaterGroundObject, faction: Faction
+ ):
+ super(OliverHazardPerryGroupGenerator, self).__init__(
+ game, ground_object, faction, Oliver_Hazzard_Perry_class
+ )
class ArleighBurkeGroupGenerator(DDGroupGenerator):
- def __init__(self, game: Game, ground_object: TheaterGroundObject, faction: Faction):
- super(ArleighBurkeGroupGenerator, self).__init__(game, ground_object, faction, USS_Arleigh_Burke_IIa)
+ def __init__(
+ self, game: Game, ground_object: TheaterGroundObject, faction: Faction
+ ):
+ super(ArleighBurkeGroupGenerator, self).__init__(
+ game, ground_object, faction, USS_Arleigh_Burke_IIa
+ )
diff --git a/gen/fleet/lha_group.py b/gen/fleet/lha_group.py
index cfbafcbb..a1a78d37 100644
--- a/gen/fleet/lha_group.py
+++ b/gen/fleet/lha_group.py
@@ -4,18 +4,31 @@ from gen.sam.group_generator import ShipGroupGenerator
class LHAGroupGenerator(ShipGroupGenerator):
-
def generate(self):
# Add carrier
if len(self.faction.helicopter_carrier) > 0:
carrier_type = random.choice(self.faction.helicopter_carrier)
- self.add_unit(carrier_type, "LHA", self.position.x, self.position.y, self.heading)
+ self.add_unit(
+ carrier_type, "LHA", self.position.x, self.position.y, self.heading
+ )
# Add destroyers escort
if len(self.faction.destroyers) > 0:
dd_type = random.choice(self.faction.destroyers)
- self.add_unit(dd_type, "DD1", self.position.x + 1250, self.position.y + 1450, self.heading)
- self.add_unit(dd_type, "DD2", self.position.x + 1250, self.position.y - 1450, self.heading)
+ self.add_unit(
+ dd_type,
+ "DD1",
+ self.position.x + 1250,
+ self.position.y + 1450,
+ self.heading,
+ )
+ self.add_unit(
+ dd_type,
+ "DD2",
+ self.position.x + 1250,
+ self.position.y - 1450,
+ self.heading,
+ )
self.get_generated_group().points[0].speed = 20
diff --git a/gen/fleet/ru_dd_group.py b/gen/fleet/ru_dd_group.py
index ee08577f..e13c8bb2 100644
--- a/gen/fleet/ru_dd_group.py
+++ b/gen/fleet/ru_dd_group.py
@@ -9,7 +9,7 @@ from dcs.ships import (
FF_1135M_Rezky,
CG_1164_Moskva,
SSK_877,
- SSK_641B
+ SSK_641B,
)
from gen.fleet.dd_group import DDGroupGenerator
@@ -23,7 +23,6 @@ if TYPE_CHECKING:
class RussianNavyGroupGenerator(ShipGroupGenerator):
-
def generate(self):
include_frigate = random.choice([True, True, False])
@@ -39,37 +38,79 @@ class RussianNavyGroupGenerator(ShipGroupGenerator):
if include_frigate:
frigate_type = random.choice([FFL_1124_4_Grisha, FSG_1241_1MP_Molniya])
- self.add_unit(frigate_type, "FF1", self.position.x + 1200, self.position.y + 900, self.heading)
- self.add_unit(frigate_type, "FF2", self.position.x + 1200, self.position.y - 900, self.heading)
+ self.add_unit(
+ frigate_type,
+ "FF1",
+ self.position.x + 1200,
+ self.position.y + 900,
+ self.heading,
+ )
+ self.add_unit(
+ frigate_type,
+ "FF2",
+ self.position.x + 1200,
+ self.position.y - 900,
+ self.heading,
+ )
if include_dd:
dd_type = random.choice([FFG_11540_Neustrashimy, FF_1135M_Rezky])
- self.add_unit(dd_type, "DD1", self.position.x + 2400, self.position.y + 900, self.heading)
- self.add_unit(dd_type, "DD2", self.position.x + 2400, self.position.y - 900, self.heading)
+ self.add_unit(
+ dd_type,
+ "DD1",
+ self.position.x + 2400,
+ self.position.y + 900,
+ self.heading,
+ )
+ self.add_unit(
+ dd_type,
+ "DD2",
+ self.position.x + 2400,
+ self.position.y - 900,
+ self.heading,
+ )
if include_cc:
# Only include the Moskva for now, the Pyotry Velikiy is an unkillable monster.
# See https://github.com/Khopa/dcs_liberation/issues/567
- self.add_unit(CG_1164_Moskva, "CC1", self.position.x, self.position.y, self.heading)
+ self.add_unit(
+ CG_1164_Moskva, "CC1", self.position.x, self.position.y, self.heading
+ )
self.get_generated_group().points[0].speed = 20
class GrishaGroupGenerator(DDGroupGenerator):
- def __init__(self, game: Game, ground_object: TheaterGroundObject, faction: Faction):
- super(GrishaGroupGenerator, self).__init__(game, ground_object, faction, FFL_1124_4_Grisha)
+ def __init__(
+ self, game: Game, ground_object: TheaterGroundObject, faction: Faction
+ ):
+ super(GrishaGroupGenerator, self).__init__(
+ game, ground_object, faction, FFL_1124_4_Grisha
+ )
class MolniyaGroupGenerator(DDGroupGenerator):
- def __init__(self, game: Game, ground_object: TheaterGroundObject, faction: Faction):
- super(MolniyaGroupGenerator, self).__init__(game, ground_object, faction, FSG_1241_1MP_Molniya)
+ def __init__(
+ self, game: Game, ground_object: TheaterGroundObject, faction: Faction
+ ):
+ super(MolniyaGroupGenerator, self).__init__(
+ game, ground_object, faction, FSG_1241_1MP_Molniya
+ )
class KiloSubGroupGenerator(DDGroupGenerator):
- def __init__(self, game: Game, ground_object: TheaterGroundObject, faction: Faction):
- super(KiloSubGroupGenerator, self).__init__(game, ground_object, faction, SSK_877)
+ def __init__(
+ self, game: Game, ground_object: TheaterGroundObject, faction: Faction
+ ):
+ super(KiloSubGroupGenerator, self).__init__(
+ game, ground_object, faction, SSK_877
+ )
class TangoSubGroupGenerator(DDGroupGenerator):
- def __init__(self, game: Game, ground_object: TheaterGroundObject, faction: Faction):
- super(TangoSubGroupGenerator, self).__init__(game, ground_object, faction, SSK_641B)
+ def __init__(
+ self, game: Game, ground_object: TheaterGroundObject, faction: Faction
+ ):
+ super(TangoSubGroupGenerator, self).__init__(
+ game, ground_object, faction, SSK_641B
+ )
diff --git a/gen/fleet/schnellboot.py b/gen/fleet/schnellboot.py
index 3de8783e..83a83fdf 100644
--- a/gen/fleet/schnellboot.py
+++ b/gen/fleet/schnellboot.py
@@ -6,10 +6,15 @@ from gen.sam.group_generator import ShipGroupGenerator
class SchnellbootGroupGenerator(ShipGroupGenerator):
-
def generate(self):
for i in range(random.randint(2, 4)):
- self.add_unit(Schnellboot_type_S130, "Schnellboot" + str(i), self.position.x + i * random.randint(100, 250), self.position.y + (random.randint(100, 200)-100), self.heading)
+ self.add_unit(
+ Schnellboot_type_S130,
+ "Schnellboot" + str(i),
+ self.position.x + i * random.randint(100, 250),
+ self.position.y + (random.randint(100, 200) - 100),
+ self.heading,
+ )
self.get_generated_group().points[0].speed = 20
diff --git a/gen/fleet/ship_group_generator.py b/gen/fleet/ship_group_generator.py
index db0a78cd..cf495524 100644
--- a/gen/fleet/ship_group_generator.py
+++ b/gen/fleet/ship_group_generator.py
@@ -4,10 +4,18 @@ import random
from game import db
from gen.fleet.carrier_group import CarrierGroupGenerator
from gen.fleet.cn_dd_group import ChineseNavyGroupGenerator, Type54GroupGenerator
-from gen.fleet.dd_group import ArleighBurkeGroupGenerator, OliverHazardPerryGroupGenerator
+from gen.fleet.dd_group import (
+ ArleighBurkeGroupGenerator,
+ OliverHazardPerryGroupGenerator,
+)
from gen.fleet.lha_group import LHAGroupGenerator
-from gen.fleet.ru_dd_group import RussianNavyGroupGenerator, GrishaGroupGenerator, MolniyaGroupGenerator, \
- KiloSubGroupGenerator, TangoSubGroupGenerator
+from gen.fleet.ru_dd_group import (
+ RussianNavyGroupGenerator,
+ GrishaGroupGenerator,
+ MolniyaGroupGenerator,
+ KiloSubGroupGenerator,
+ TangoSubGroupGenerator,
+)
from gen.fleet.schnellboot import SchnellbootGroupGenerator
from gen.fleet.uboat import UBoatGroupGenerator
from gen.fleet.ww2lst import WW2LSTGroupGenerator
@@ -25,7 +33,7 @@ SHIP_MAP = {
"MolniyaGroupGenerator": MolniyaGroupGenerator,
"KiloSubGroupGenerator": KiloSubGroupGenerator,
"TangoSubGroupGenerator": TangoSubGroupGenerator,
- "Type54GroupGenerator": Type54GroupGenerator
+ "Type54GroupGenerator": Type54GroupGenerator,
}
@@ -42,7 +50,11 @@ def generate_ship_group(game, ground_object, faction_name: str):
generator.generate()
return generator.get_generated_group()
else:
- logging.info("Unable to generate ship group, generator : " + str(gen) + "does not exists")
+ logging.info(
+ "Unable to generate ship group, generator : "
+ + str(gen)
+ + "does not exists"
+ )
return None
diff --git a/gen/fleet/uboat.py b/gen/fleet/uboat.py
index 8d2e9cc0..bb736d1e 100644
--- a/gen/fleet/uboat.py
+++ b/gen/fleet/uboat.py
@@ -6,10 +6,15 @@ from gen.sam.group_generator import ShipGroupGenerator
class UBoatGroupGenerator(ShipGroupGenerator):
-
def generate(self):
for i in range(random.randint(1, 4)):
- self.add_unit(Uboat_VIIC_U_flak, "Uboat" + str(i), self.position.x + i * random.randint(100, 250), self.position.y + (random.randint(100, 200)-100), self.heading)
+ self.add_unit(
+ Uboat_VIIC_U_flak,
+ "Uboat" + str(i),
+ self.position.x + i * random.randint(100, 250),
+ self.position.y + (random.randint(100, 200) - 100),
+ self.heading,
+ )
- self.get_generated_group().points[0].speed = 20
\ No newline at end of file
+ self.get_generated_group().points[0].speed = 20
diff --git a/gen/fleet/ww2lst.py b/gen/fleet/ww2lst.py
index e0512009..db7deb69 100644
--- a/gen/fleet/ww2lst.py
+++ b/gen/fleet/ww2lst.py
@@ -6,13 +6,24 @@ from gen.sam.group_generator import ShipGroupGenerator
class WW2LSTGroupGenerator(ShipGroupGenerator):
-
def generate(self):
# Add LS Samuel Chase
- self.add_unit(LS_Samuel_Chase, "SamuelChase", self.position.x, self.position.y, self.heading)
+ self.add_unit(
+ LS_Samuel_Chase,
+ "SamuelChase",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
for i in range(1, random.randint(3, 4)):
- self.add_unit(LST_Mk_II, "LST" + str(i), self.position.x + i * random.randint(800, 1200), self.position.y, self.heading)
+ self.add_unit(
+ LST_Mk_II,
+ "LST" + str(i),
+ self.position.x + i * random.randint(800, 1200),
+ self.position.y,
+ self.heading,
+ )
- self.get_generated_group().points[0].speed = 20
\ No newline at end of file
+ self.get_generated_group().points[0].speed = 20
diff --git a/gen/flights/ai_flight_planner.py b/gen/flights/ai_flight_planner.py
index 2267fcb4..4dde50ce 100644
--- a/gen/flights/ai_flight_planner.py
+++ b/gen/flights/ai_flight_planner.py
@@ -109,22 +109,25 @@ class ProposedMission:
flights: List[ProposedFlight]
def __str__(self) -> str:
- flights = ', '.join([str(f) for f in self.flights])
+ flights = ", ".join([str(f) for f in self.flights])
return f"{self.location.name}: {flights}"
class AircraftAllocator:
"""Finds suitable aircraft for proposed missions."""
- def __init__(self, closest_airfields: ClosestAirfields,
- global_inventory: GlobalAircraftInventory,
- is_player: bool) -> None:
+ def __init__(
+ self,
+ closest_airfields: ClosestAirfields,
+ global_inventory: GlobalAircraftInventory,
+ is_player: bool,
+ ) -> None:
self.closest_airfields = closest_airfields
self.global_inventory = global_inventory
self.is_player = is_player
def find_aircraft_for_flight(
- self, flight: ProposedFlight
+ self, flight: ProposedFlight
) -> Optional[Tuple[ControlPoint, Type[FlyingType]]]:
"""Finds aircraft suitable for the given mission.
@@ -144,12 +147,12 @@ class AircraftAllocator:
on subsequent calls. If the found aircraft are not used, the caller is
responsible for returning them to the inventory.
"""
- return self.find_aircraft_of_type(
- flight, aircraft_for_task(flight.task)
- )
+ return self.find_aircraft_of_type(flight, aircraft_for_task(flight.task))
def find_aircraft_of_type(
- self, flight: ProposedFlight, types: List[Type[FlyingType]],
+ self,
+ flight: ProposedFlight,
+ types: List[Type[FlyingType]],
) -> Optional[Tuple[ControlPoint, Type[FlyingType]]]:
airfields_in_range = self.closest_airfields.airfields_within(
flight.max_distance
@@ -171,18 +174,22 @@ class AircraftAllocator:
class PackageBuilder:
"""Builds a Package for the flights it receives."""
- def __init__(self, location: MissionTarget,
- closest_airfields: ClosestAirfields,
- global_inventory: GlobalAircraftInventory,
- is_player: bool,
- package_country: str,
- start_type: str) -> None:
+ def __init__(
+ self,
+ location: MissionTarget,
+ closest_airfields: ClosestAirfields,
+ global_inventory: GlobalAircraftInventory,
+ is_player: bool,
+ package_country: str,
+ start_type: str,
+ ) -> None:
self.closest_airfields = closest_airfields
self.is_player = is_player
self.package_country = package_country
self.package = Package(location)
- self.allocator = AircraftAllocator(closest_airfields, global_inventory,
- is_player)
+ self.allocator = AircraftAllocator(
+ closest_airfields, global_inventory, is_player
+ )
self.global_inventory = global_inventory
self.start_type = start_type
@@ -203,14 +210,23 @@ class PackageBuilder:
else:
start_type = self.start_type
- flight = Flight(self.package, self.package_country, aircraft, plan.num_aircraft, plan.task,
- start_type, departure=airfield, arrival=airfield,
- divert=self.find_divert_field(aircraft, airfield))
+ flight = Flight(
+ self.package,
+ self.package_country,
+ aircraft,
+ plan.num_aircraft,
+ plan.task,
+ start_type,
+ departure=airfield,
+ arrival=airfield,
+ divert=self.find_divert_field(aircraft, airfield),
+ )
self.package.add_flight(flight)
return True
- def find_divert_field(self, aircraft: Type[FlyingType],
- arrival: ControlPoint) -> Optional[ControlPoint]:
+ def find_divert_field(
+ self, aircraft: Type[FlyingType], arrival: ControlPoint
+ ) -> Optional[ControlPoint]:
divert_limit = nautical_miles(150)
for airfield in self.closest_airfields.airfields_within(divert_limit):
if airfield.captured != self.is_player:
@@ -323,8 +339,8 @@ class ObjectiveFinder:
return self._targets_by_range(self.enemy_ships())
def _targets_by_range(
- self,
- targets: Iterable[MissionTarget]) -> Iterator[MissionTarget]:
+ self, targets: Iterable[MissionTarget]
+ ) -> Iterator[MissionTarget]:
target_ranges: List[Tuple[MissionTarget, int]] = []
for target in targets:
ranges: List[int] = []
@@ -430,13 +446,17 @@ class ObjectiveFinder:
def friendly_control_points(self) -> Iterator[ControlPoint]:
"""Iterates over all friendly control points."""
- return (c for c in self.game.theater.controlpoints if
- c.is_friendly(self.is_player))
+ return (
+ c for c in self.game.theater.controlpoints if c.is_friendly(self.is_player)
+ )
def enemy_control_points(self) -> Iterator[ControlPoint]:
"""Iterates over all enemy control points."""
- return (c for c in self.game.theater.controlpoints if
- not c.is_friendly(self.is_player))
+ return (
+ c
+ for c in self.game.theater.controlpoints
+ if not c.is_friendly(self.is_player)
+ )
def all_possible_targets(self) -> Iterator[MissionTarget]:
"""Iterates over all possible mission targets in the theater.
@@ -510,23 +530,36 @@ class CoalitionMissionPlanner:
for cp in self.objective_finder.vulnerable_control_points():
# Plan three rounds of CAP to give ~90 minutes coverage. Spacing
# these out appropriately is done in stagger_missions.
- yield ProposedMission(cp, [
- ProposedFlight(FlightType.BARCAP, 2, self.MAX_CAP_RANGE),
- ])
- yield ProposedMission(cp, [
- ProposedFlight(FlightType.BARCAP, 2, self.MAX_CAP_RANGE),
- ])
- yield ProposedMission(cp, [
- ProposedFlight(FlightType.BARCAP, 2, self.MAX_CAP_RANGE),
- ])
+ yield ProposedMission(
+ cp,
+ [
+ ProposedFlight(FlightType.BARCAP, 2, self.MAX_CAP_RANGE),
+ ],
+ )
+ yield ProposedMission(
+ cp,
+ [
+ ProposedFlight(FlightType.BARCAP, 2, self.MAX_CAP_RANGE),
+ ],
+ )
+ yield ProposedMission(
+ cp,
+ [
+ ProposedFlight(FlightType.BARCAP, 2, self.MAX_CAP_RANGE),
+ ],
+ )
# Find front lines, plan CAS.
for front_line in self.objective_finder.front_lines():
- yield ProposedMission(front_line, [
- ProposedFlight(FlightType.CAS, 2, self.MAX_CAS_RANGE),
- ProposedFlight(FlightType.TARCAP, 2, self.MAX_CAP_RANGE,
- EscortType.AirToAir),
- ])
+ yield ProposedMission(
+ front_line,
+ [
+ ProposedFlight(FlightType.CAS, 2, self.MAX_CAS_RANGE),
+ ProposedFlight(
+ FlightType.TARCAP, 2, self.MAX_CAP_RANGE, EscortType.AirToAir
+ ),
+ ],
+ )
def propose_missions(self) -> Iterator[ProposedMission]:
"""Identifies and iterates over potential mission in priority order."""
@@ -537,30 +570,46 @@ class CoalitionMissionPlanner:
# Find enemy SAM sites with ranges that extend to within 50 nmi of
# friendly CPs, front, lines, or objects, plan DEAD.
for sam in self.objective_finder.threatening_sams():
- yield ProposedMission(sam, [
- ProposedFlight(FlightType.DEAD, 2, self.MAX_SEAD_RANGE),
- # TODO: Max escort range.
- ProposedFlight(FlightType.ESCORT, 2, self.MAX_SEAD_RANGE,
- EscortType.AirToAir),
- ])
+ yield ProposedMission(
+ sam,
+ [
+ ProposedFlight(FlightType.DEAD, 2, self.MAX_SEAD_RANGE),
+ # TODO: Max escort range.
+ ProposedFlight(
+ FlightType.ESCORT, 2, self.MAX_SEAD_RANGE, EscortType.AirToAir
+ ),
+ ],
+ )
for group in self.objective_finder.threatening_ships():
- yield ProposedMission(group, [
- ProposedFlight(FlightType.ANTISHIP, 2, self.MAX_ANTISHIP_RANGE),
- # TODO: Max escort range.
- ProposedFlight(FlightType.ESCORT, 2, self.MAX_ANTISHIP_RANGE,
- EscortType.AirToAir),
- ])
+ yield ProposedMission(
+ group,
+ [
+ ProposedFlight(FlightType.ANTISHIP, 2, self.MAX_ANTISHIP_RANGE),
+ # TODO: Max escort range.
+ ProposedFlight(
+ FlightType.ESCORT,
+ 2,
+ self.MAX_ANTISHIP_RANGE,
+ EscortType.AirToAir,
+ ),
+ ],
+ )
for group in self.objective_finder.threatening_vehicle_groups():
- yield ProposedMission(group, [
- ProposedFlight(FlightType.BAI, 2, self.MAX_BAI_RANGE),
- # TODO: Max escort range.
- ProposedFlight(FlightType.ESCORT, 2, self.MAX_BAI_RANGE,
- EscortType.AirToAir),
- ProposedFlight(FlightType.SEAD, 2, self.MAX_OCA_RANGE,
- EscortType.Sead),
- ])
+ yield ProposedMission(
+ group,
+ [
+ ProposedFlight(FlightType.BAI, 2, self.MAX_BAI_RANGE),
+ # TODO: Max escort range.
+ ProposedFlight(
+ FlightType.ESCORT, 2, self.MAX_BAI_RANGE, EscortType.AirToAir
+ ),
+ ProposedFlight(
+ FlightType.SEAD, 2, self.MAX_OCA_RANGE, EscortType.Sead
+ ),
+ ],
+ )
for target in self.objective_finder.oca_targets(min_aircraft=20):
flights = [
@@ -569,27 +618,37 @@ class CoalitionMissionPlanner:
if self.game.settings.default_start_type == "Cold":
# Only schedule if the default start type is Cold. If the player
# has set anything else there are no targets to hit.
- flights.append(ProposedFlight(FlightType.OCA_AIRCRAFT, 2,
- self.MAX_OCA_RANGE))
- flights.extend([
- # TODO: Max escort range.
- ProposedFlight(FlightType.ESCORT, 2, self.MAX_OCA_RANGE,
- EscortType.AirToAir),
- ProposedFlight(FlightType.SEAD, 2, self.MAX_OCA_RANGE,
- EscortType.Sead),
- ])
+ flights.append(
+ ProposedFlight(FlightType.OCA_AIRCRAFT, 2, self.MAX_OCA_RANGE)
+ )
+ flights.extend(
+ [
+ # TODO: Max escort range.
+ ProposedFlight(
+ FlightType.ESCORT, 2, self.MAX_OCA_RANGE, EscortType.AirToAir
+ ),
+ ProposedFlight(
+ FlightType.SEAD, 2, self.MAX_OCA_RANGE, EscortType.Sead
+ ),
+ ]
+ )
yield ProposedMission(target, flights)
# Plan strike missions.
for target in self.objective_finder.strike_targets():
- yield ProposedMission(target, [
- ProposedFlight(FlightType.STRIKE, 2, self.MAX_STRIKE_RANGE),
- # TODO: Max escort range.
- ProposedFlight(FlightType.ESCORT, 2, self.MAX_STRIKE_RANGE,
- EscortType.AirToAir),
- ProposedFlight(FlightType.SEAD, 2, self.MAX_STRIKE_RANGE,
- EscortType.Sead),
- ])
+ yield ProposedMission(
+ target,
+ [
+ ProposedFlight(FlightType.STRIKE, 2, self.MAX_STRIKE_RANGE),
+ # TODO: Max escort range.
+ ProposedFlight(
+ FlightType.ESCORT, 2, self.MAX_STRIKE_RANGE, EscortType.AirToAir
+ ),
+ ProposedFlight(
+ FlightType.SEAD, 2, self.MAX_STRIKE_RANGE, EscortType.Sead
+ ),
+ ],
+ )
def plan_missions(self) -> None:
"""Identifies and plans mission for the turn."""
@@ -604,19 +663,23 @@ class CoalitionMissionPlanner:
for cp in self.objective_finder.friendly_control_points():
inventory = self.game.aircraft_inventory.for_control_point(cp)
for aircraft, available in inventory.all_aircraft:
- self.message("Unused aircraft",
- f"{available} {aircraft.id} from {cp}")
+ self.message("Unused aircraft", f"{available} {aircraft.id} from {cp}")
- def plan_flight(self, mission: ProposedMission, flight: ProposedFlight,
- builder: PackageBuilder, missing_types: Set[FlightType],
- for_reserves: bool) -> None:
+ def plan_flight(
+ self,
+ mission: ProposedMission,
+ flight: ProposedFlight,
+ builder: PackageBuilder,
+ missing_types: Set[FlightType],
+ for_reserves: bool,
+ ) -> None:
if not builder.plan_flight(flight):
missing_types.add(flight.task)
purchase_order = AircraftProcurementRequest(
near=mission.location,
range=flight.max_distance,
task_capability=flight.task,
- number=flight.num_aircraft
+ number=flight.num_aircraft,
)
if for_reserves:
# Reserves are planned for critical missions, so prioritize
@@ -626,26 +689,28 @@ class CoalitionMissionPlanner:
self.procurement_requests.append(purchase_order)
def scrub_mission_missing_aircraft(
- self, mission: ProposedMission, builder: PackageBuilder,
- missing_types: Set[FlightType],
- not_attempted: Iterable[ProposedFlight],
- reserves: bool) -> None:
+ self,
+ mission: ProposedMission,
+ builder: PackageBuilder,
+ missing_types: Set[FlightType],
+ not_attempted: Iterable[ProposedFlight],
+ reserves: bool,
+ ) -> None:
# Try to plan the rest of the mission just so we can count the missing
# types to buy.
for flight in not_attempted:
self.plan_flight(mission, flight, builder, missing_types, reserves)
- missing_types_str = ", ".join(
- sorted([t.name for t in missing_types]))
+ missing_types_str = ", ".join(sorted([t.name for t in missing_types]))
builder.release_planned_aircraft()
desc = "reserve aircraft" if reserves else "aircraft"
self.message(
"Insufficient aircraft",
f"Not enough {desc} in range for {mission.location.name} "
- f"capable of: {missing_types_str}")
+ f"capable of: {missing_types_str}",
+ )
- def check_needed_escorts(
- self, builder: PackageBuilder) -> Dict[EscortType, bool]:
+ def check_needed_escorts(self, builder: PackageBuilder) -> Dict[EscortType, bool]:
threats = defaultdict(bool)
for flight in builder.package.flights:
if self.threat_zones.threatened_by_aircraft(flight):
@@ -654,8 +719,7 @@ class CoalitionMissionPlanner:
threats[EscortType.Sead] = True
return threats
- def plan_mission(self, mission: ProposedMission,
- reserves: bool = False) -> None:
+ def plan_mission(self, mission: ProposedMission, reserves: bool = False) -> None:
"""Allocates aircraft for a proposed mission and adds it to the ATO."""
if self.is_player:
@@ -669,7 +733,7 @@ class CoalitionMissionPlanner:
self.game.aircraft_inventory,
self.is_player,
package_country,
- self.game.settings.default_start_type
+ self.game.settings.default_start_type,
)
# Attempt to plan all the main elements of the mission first. Escorts
@@ -683,12 +747,12 @@ class CoalitionMissionPlanner:
# If the package does not need escorts they may be pruned.
escorts.append(proposed_flight)
continue
- self.plan_flight(mission, proposed_flight, builder, missing_types,
- reserves)
+ self.plan_flight(mission, proposed_flight, builder, missing_types, reserves)
if missing_types:
- self.scrub_mission_missing_aircraft(mission, builder, missing_types,
- escorts, reserves)
+ self.scrub_mission_missing_aircraft(
+ mission, builder, missing_types, escorts, reserves
+ )
return
# Create flight plans for the main flights of the package so we can
@@ -697,8 +761,9 @@ class CoalitionMissionPlanner:
# flights that will rendezvous with their package will be affected by
# the other flights in the package. Escorts will not be able to
# contribute to this.
- flight_plan_builder = FlightPlanBuilder(self.game, builder.package,
- self.is_player)
+ flight_plan_builder = FlightPlanBuilder(
+ self.game, builder.package, self.is_player
+ )
for flight in builder.package.flights:
flight_plan_builder.populate_flight_plan(flight)
@@ -708,14 +773,14 @@ class CoalitionMissionPlanner:
# impossible.
assert escort.escort_type is not None
if needed_escorts[escort.escort_type]:
- self.plan_flight(mission, escort, builder, missing_types,
- reserves)
+ self.plan_flight(mission, escort, builder, missing_types, reserves)
# Check again for unavailable aircraft. If the escort was required and
# none were found, scrub the mission.
if missing_types:
- self.scrub_mission_missing_aircraft(mission, builder, missing_types,
- escorts, reserves)
+ self.scrub_mission_missing_aircraft(
+ mission, builder, missing_types, escorts, reserves
+ )
return
if reserves:
@@ -732,8 +797,9 @@ class CoalitionMissionPlanner:
self.ato.add_package(package)
def stagger_missions(self) -> None:
- def start_time_generator(count: int, earliest: int, latest: int,
- margin: int) -> Iterator[timedelta]:
+ def start_time_generator(
+ count: int, earliest: int, latest: int, margin: int
+ ) -> Iterator[timedelta]:
interval = (latest - earliest) // count
for time in range(earliest, latest, interval):
error = random.randint(-margin, margin)
@@ -744,17 +810,13 @@ class CoalitionMissionPlanner:
FlightType.TARCAP,
}
- previous_cap_end_time: Dict[MissionTarget, timedelta] = defaultdict(
- timedelta
- )
- non_dca_packages = [p for p in self.ato.packages if
- p.primary_task not in dca_types]
+ previous_cap_end_time: Dict[MissionTarget, timedelta] = defaultdict(timedelta)
+ non_dca_packages = [
+ p for p in self.ato.packages if p.primary_task not in dca_types
+ ]
start_time = start_time_generator(
- count=len(non_dca_packages),
- earliest=5,
- latest=90,
- margin=5
+ count=len(non_dca_packages), earliest=5, latest=90, margin=5
)
for package in self.ato.packages:
tot = TotEstimator(package).earliest_tot()
@@ -771,8 +833,7 @@ class CoalitionMissionPlanner:
departure_time = package.mission_departure_time
# Should be impossible for CAPs
if departure_time is None:
- logging.error(
- f"Could not determine mission end time for {package}")
+ logging.error(f"Could not determine mission end time for {package}")
continue
previous_cap_end_time[package.target] = departure_time
else:
@@ -791,8 +852,6 @@ class CoalitionMissionPlanner:
message to the info panel.
"""
if self.is_player:
- self.game.informations.append(
- Information(title, text, self.game.turn)
- )
+ self.game.informations.append(Information(title, text, self.game.turn))
else:
logging.info(f"{title}: {text}")
diff --git a/gen/flights/ai_flight_planner_db.py b/gen/flights/ai_flight_planner_db.py
index 99782aba..11ae08d3 100644
--- a/gen/flights/ai_flight_planner_db.py
+++ b/gen/flights/ai_flight_planner_db.py
@@ -13,7 +13,7 @@ from dcs.helicopters import (
SA342L,
SA342M,
UH_1H,
- SH_60B
+ SH_60B,
)
from dcs.planes import (
AJS37,
@@ -83,7 +83,7 @@ from dcs.planes import (
Tu_22M3,
Tu_95MS,
WingLoong_I,
- I_16
+ I_16,
)
from dcs.unittype import FlyingType
@@ -367,11 +367,7 @@ TRANSPORT_CAPABLE = [
UH_1H,
]
-DRONES = [
- MQ_9_Reaper,
- RQ_1A_Predator,
- WingLoong_I
-]
+DRONES = [MQ_9_Reaper, RQ_1A_Predator, WingLoong_I]
def aircraft_for_task(task: FlightType) -> List[Type[FlyingType]]:
diff --git a/gen/flights/closestairfields.py b/gen/flights/closestairfields.py
index 7dfab22f..76662c81 100644
--- a/gen/flights/closestairfields.py
+++ b/gen/flights/closestairfields.py
@@ -12,8 +12,9 @@ if TYPE_CHECKING:
class ClosestAirfields:
"""Precalculates which control points are closes to the given target."""
- def __init__(self, target: MissionTarget,
- all_control_points: List[ControlPoint]) -> None:
+ def __init__(
+ self, target: MissionTarget, all_control_points: List[ControlPoint]
+ ) -> None:
self.target = target
# This cache is configured once on load, so it's important that it is
# complete and deterministic to avoid different behaviors across loads.
@@ -52,9 +53,7 @@ class ObjectiveDistanceCache:
@classmethod
def get_closest_airfields(cls, location: MissionTarget) -> ClosestAirfields:
if cls.theater is None:
- raise RuntimeError(
- "Call ObjectiveDistanceCache.set_theater before using"
- )
+ raise RuntimeError("Call ObjectiveDistanceCache.set_theater before using")
if location.name not in cls.closest_airfields:
cls.closest_airfields[location.name] = ClosestAirfields(
diff --git a/gen/flights/flight.py b/gen/flights/flight.py
index 06ed2c8b..8a5985fc 100644
--- a/gen/flights/flight.py
+++ b/gen/flights/flight.py
@@ -39,22 +39,22 @@ class FlightType(Enum):
class FlightWaypointType(Enum):
- TAKEOFF = 0 # Take off point
- ASCEND_POINT = 1 # Ascension point after take off
- PATROL = 2 # Patrol point
- PATROL_TRACK = 3 # Patrol race track
- NAV = 4 # Nav point
- INGRESS_STRIKE = 5 # Ingress strike (For generator, means that this should have bombing on next TARGET_POINT points)
- INGRESS_SEAD = 6 # Ingress sead (For generator, means that this should attack groups on TARGET_GROUP_LOC points)
- INGRESS_CAS = 7 # Ingress cas (should start CAS task)
- CAS = 8 # Should do CAS there
- EGRESS = 9 # Should stop attack
- DESCENT_POINT = 10 # Should start descending to pattern alt
- LANDING_POINT = 11 # Should land there
- TARGET_POINT = 12 # A target building or static object, position
- TARGET_GROUP_LOC = 13 # A target group approximate location
- TARGET_SHIP = 14 # A target ship known location
- CUSTOM = 15 # User waypoint (no specific behaviour)
+ TAKEOFF = 0 # Take off point
+ ASCEND_POINT = 1 # Ascension point after take off
+ PATROL = 2 # Patrol point
+ PATROL_TRACK = 3 # Patrol race track
+ NAV = 4 # Nav point
+ INGRESS_STRIKE = 5 # Ingress strike (For generator, means that this should have bombing on next TARGET_POINT points)
+ INGRESS_SEAD = 6 # Ingress sead (For generator, means that this should attack groups on TARGET_GROUP_LOC points)
+ INGRESS_CAS = 7 # Ingress cas (should start CAS task)
+ CAS = 8 # Should do CAS there
+ EGRESS = 9 # Should stop attack
+ DESCENT_POINT = 10 # Should start descending to pattern alt
+ LANDING_POINT = 11 # Should land there
+ TARGET_POINT = 12 # A target building or static object, position
+ TARGET_GROUP_LOC = 13 # A target group approximate location
+ TARGET_SHIP = 14 # A target ship known location
+ CUSTOM = 15 # User waypoint (no specific behaviour)
JOIN = 16
SPLIT = 17
LOITER = 18
@@ -68,9 +68,13 @@ class FlightWaypointType(Enum):
class FlightWaypoint:
-
- def __init__(self, waypoint_type: FlightWaypointType, x: float, y: float,
- alt: Distance = meters(0)) -> None:
+ def __init__(
+ self,
+ waypoint_type: FlightWaypointType,
+ x: float,
+ y: float,
+ alt: Distance = meters(0),
+ ) -> None:
"""Creates a flight waypoint.
Args:
@@ -108,10 +112,13 @@ class FlightWaypoint:
return Point(self.x, self.y)
@classmethod
- def from_pydcs(cls, point: MovingPoint,
- from_cp: ControlPoint) -> "FlightWaypoint":
- waypoint = FlightWaypoint(FlightWaypointType.NAV, point.position.x,
- point.position.y, meters(point.alt))
+ def from_pydcs(cls, point: MovingPoint, from_cp: ControlPoint) -> "FlightWaypoint":
+ waypoint = FlightWaypoint(
+ FlightWaypointType.NAV,
+ point.position.x,
+ point.position.y,
+ meters(point.alt),
+ )
waypoint.alt_type = point.alt_type
# Other actions exist... but none of them *should* be the first
# waypoint for a flight.
@@ -135,12 +142,19 @@ class FlightWaypoint:
class Flight:
-
- def __init__(self, package: Package, country: str, unit_type: Type[FlyingType],
- count: int, flight_type: FlightType, start_type: str,
- departure: ControlPoint, arrival: ControlPoint,
- divert: Optional[ControlPoint],
- custom_name: Optional[str] = None) -> None:
+ def __init__(
+ self,
+ package: Package,
+ country: str,
+ unit_type: Type[FlyingType],
+ count: int,
+ flight_type: FlightType,
+ start_type: str,
+ departure: ControlPoint,
+ arrival: ControlPoint,
+ divert: Optional[ControlPoint],
+ custom_name: Optional[str] = None,
+ ) -> None:
self.package = package
self.country = country
self.unit_type = unit_type
@@ -161,10 +175,9 @@ class Flight:
# FlightPlanBuilder, but an empty flight plan the flight begins with an
# empty flight plan.
from gen.flights.flightplan import CustomFlightPlan
+
self.flight_plan: FlightPlan = CustomFlightPlan(
- package=package,
- flight=self,
- custom_waypoints=[]
+ package=package, flight=self, custom_waypoints=[]
)
@property
@@ -182,7 +195,7 @@ class Flight:
return f"[{self.flight_type}] {self.count} x {name}"
def __str__(self):
- name = db.unit_get_expanded_info(self.country, self.unit_type, 'name')
+ name = db.unit_get_expanded_info(self.country, self.unit_type, "name")
if self.custom_name:
return f"{self.custom_name} {self.count} x {name}"
return f"[{self.flight_type}] {self.count} x {name}"
diff --git a/gen/flights/flightplan.py b/gen/flights/flightplan.py
index bbf45b1f..8be4264a 100644
--- a/gen/flights/flightplan.py
+++ b/gen/flights/flightplan.py
@@ -75,7 +75,7 @@ class FlightPlan:
raise NotImplementedError
def edges(
- self, until: Optional[FlightWaypoint] = None
+ self, until: Optional[FlightWaypoint] = None
) -> Iterator[Tuple[FlightWaypoint, FlightWaypoint]]:
"""A list of all paths between waypoints, in order."""
waypoints = self.waypoints
@@ -86,8 +86,9 @@ class FlightPlan:
return zip(self.waypoints[:last_index], self.waypoints[1:last_index])
- def best_speed_between_waypoints(self, a: FlightWaypoint,
- b: FlightWaypoint) -> Speed:
+ def best_speed_between_waypoints(
+ self, a: FlightWaypoint, b: FlightWaypoint
+ ) -> Speed:
"""Desired ground speed between points a and b."""
factor = 1.0
if b.waypoint_type == FlightWaypointType.ASCEND_POINT:
@@ -108,8 +109,7 @@ class FlightPlan:
# near 2000 ft MSL.
return GroundSpeed.for_flight(self.flight, min(a.alt, b.alt)) * factor
- def speed_between_waypoints(self, a: FlightWaypoint,
- b: FlightWaypoint) -> Speed:
+ def speed_between_waypoints(self, a: FlightWaypoint, b: FlightWaypoint) -> Speed:
return self.best_speed_between_waypoints(a, b)
@property
@@ -121,11 +121,10 @@ class FlightPlan:
failed to generate. Nevertheless, we have to defend against it.
"""
raise NotImplementedError
-
+
@cached_property
def bingo_fuel(self) -> int:
- """Bingo fuel value for the FlightPlan
- """
+ """Bingo fuel value for the FlightPlan"""
distance_to_arrival = self.max_distance_from(self.flight.arrival)
bingo = 1000.0 # Minimum Emergency Fuel
@@ -142,18 +141,18 @@ class FlightPlan:
@cached_property
def joker_fuel(self) -> int:
- """Joker fuel value for the FlightPlan
- """
+ """Joker fuel value for the FlightPlan"""
return self.bingo_fuel + 1000
-
+
def max_distance_from(self, cp: ControlPoint) -> Distance:
"""Returns the farthest waypoint of the flight plan from a ControlPoint.
:arg cp The ControlPoint to measure distance from.
"""
if not self.waypoints:
return meters(0)
- return max([meters(cp.position.distance_to_point(w.position)) for w in
- self.waypoints])
+ return max(
+ [meters(cp.position.distance_to_point(w.position)) for w in self.waypoints]
+ )
@property
def tot_offset(self) -> timedelta:
@@ -164,30 +163,30 @@ class FlightPlan:
"""
return timedelta()
- def _travel_time_to_waypoint(
- self, destination: FlightWaypoint) -> timedelta:
+ def _travel_time_to_waypoint(self, destination: FlightWaypoint) -> timedelta:
total = timedelta()
if destination not in self.waypoints:
raise PlanningError(
f"Did not find destination waypoint {destination} in "
- f"waypoints for {self.flight}")
+ f"waypoints for {self.flight}"
+ )
for previous_waypoint, waypoint in self.edges(until=destination):
- total += self.travel_time_between_waypoints(previous_waypoint,
- waypoint)
+ total += self.travel_time_between_waypoints(previous_waypoint, waypoint)
return total
- def travel_time_between_waypoints(self, a: FlightWaypoint,
- b: FlightWaypoint) -> timedelta:
- return TravelTime.between_points(a.position, b.position,
- self.speed_between_waypoints(a, b))
+ def travel_time_between_waypoints(
+ self, a: FlightWaypoint, b: FlightWaypoint
+ ) -> timedelta:
+ return TravelTime.between_points(
+ a.position, b.position, self.speed_between_waypoints(a, b)
+ )
def tot_for_waypoint(self, waypoint: FlightWaypoint) -> Optional[timedelta]:
raise NotImplementedError
- def depart_time_for_waypoint(
- self, waypoint: FlightWaypoint) -> Optional[timedelta]:
+ def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> Optional[timedelta]:
raise NotImplementedError
def request_escort_at(self) -> Optional[FlightWaypoint]:
@@ -212,8 +211,7 @@ class FlightPlan:
if takeoff_time is None:
return None
- start_time = (takeoff_time - self.estimate_startup() -
- self.estimate_ground_ops())
+ start_time = takeoff_time - self.estimate_startup() - self.estimate_ground_ops()
# In case FP math has given us some barely below zero time, round to
# zero.
@@ -269,14 +267,14 @@ class LoiterFlightPlan(FlightPlan):
def push_time(self) -> timedelta:
raise NotImplementedError
- def depart_time_for_waypoint(
- self, waypoint: FlightWaypoint) -> Optional[timedelta]:
+ def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> Optional[timedelta]:
if waypoint == self.hold:
return self.push_time
return None
- def travel_time_between_waypoints(self, a: FlightWaypoint,
- b: FlightWaypoint) -> timedelta:
+ def travel_time_between_waypoints(
+ self, a: FlightWaypoint, b: FlightWaypoint
+ ) -> timedelta:
travel_time = super().travel_time_between_waypoints(a, b)
if a != self.hold:
return travel_time
@@ -321,12 +319,12 @@ class FormationFlightPlan(LoiterFlightPlan):
speeds = []
for previous_waypoint, waypoint in self.edges():
if waypoint in self.package_speed_waypoints:
- speeds.append(self.best_speed_between_waypoints(
- previous_waypoint, waypoint))
+ speeds.append(
+ self.best_speed_between_waypoints(previous_waypoint, waypoint)
+ )
return min(speeds)
- def speed_between_waypoints(self, a: FlightWaypoint,
- b: FlightWaypoint) -> Speed:
+ def speed_between_waypoints(self, a: FlightWaypoint, b: FlightWaypoint) -> Speed:
if b in self.package_speed_waypoints:
# Should be impossible, as any package with at least one
# FormationFlightPlan flight needs a formation speed.
@@ -359,7 +357,7 @@ class FormationFlightPlan(LoiterFlightPlan):
return self.join_time - TravelTime.between_points(
self.hold.position,
self.join.position,
- GroundSpeed.for_flight(self.flight, self.hold.alt)
+ GroundSpeed.for_flight(self.flight, self.hold.alt),
)
@property
@@ -399,8 +397,7 @@ class PatrollingFlightPlan(FlightPlan):
return self.patrol_start_time
return None
- def depart_time_for_waypoint(
- self, waypoint: FlightWaypoint) -> Optional[timedelta]:
+ def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> Optional[timedelta]:
if waypoint == self.patrol_end:
return self.patrol_end_time
return None
@@ -490,8 +487,7 @@ class TarCapFlightPlan(PatrollingFlightPlan):
def tot_offset(self) -> timedelta:
return -self.lead_time
- def depart_time_for_waypoint(
- self, waypoint: FlightWaypoint) -> Optional[timedelta]:
+ def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> Optional[timedelta]:
if waypoint == self.patrol_end:
return self.patrol_end_time
return super().depart_time_for_waypoint(waypoint)
@@ -542,13 +538,12 @@ class StrikeFlightPlan(FormationFlightPlan):
@property
def package_speed_waypoints(self) -> Set[FlightWaypoint]:
return {
- self.ingress,
- self.egress,
- self.split,
+ self.ingress,
+ self.egress,
+ self.split,
} | set(self.targets)
- def speed_between_waypoints(self, a: FlightWaypoint,
- b: FlightWaypoint) -> Speed:
+ def speed_between_waypoints(self, a: FlightWaypoint, b: FlightWaypoint) -> Speed:
# FlightWaypoint is only comparable by identity, so adding
# target_area_waypoint to package_speed_waypoints is useless.
if b.waypoint_type == FlightWaypointType.TARGET_GROUP_LOC:
@@ -564,10 +559,12 @@ class StrikeFlightPlan(FormationFlightPlan):
@property
def target_area_waypoint(self) -> FlightWaypoint:
- return FlightWaypoint(FlightWaypointType.TARGET_GROUP_LOC,
- self.package.target.position.x,
- self.package.target.position.y,
- meters(0))
+ return FlightWaypoint(
+ FlightWaypointType.TARGET_GROUP_LOC,
+ self.package.target.position.x,
+ self.package.target.position.y,
+ meters(0),
+ )
@property
def travel_time_to_target(self) -> timedelta:
@@ -581,14 +578,15 @@ class StrikeFlightPlan(FormationFlightPlan):
# package we need to use the travel time to the same position as
# the others.
total += self.travel_time_between_waypoints(
- previous_waypoint, self.target_area_waypoint)
+ previous_waypoint, self.target_area_waypoint
+ )
break
- total += self.travel_time_between_waypoints(previous_waypoint,
- waypoint)
+ total += self.travel_time_between_waypoints(previous_waypoint, waypoint)
else:
raise PlanningError(
f"Did not find destination waypoint {destination} in "
- f"waypoints for {self.flight}")
+ f"waypoints for {self.flight}"
+ )
return total
@property
@@ -597,28 +595,28 @@ class StrikeFlightPlan(FormationFlightPlan):
@property
def join_time(self) -> timedelta:
- travel_time = self.travel_time_between_waypoints(
- self.join, self.ingress)
+ travel_time = self.travel_time_between_waypoints(self.join, self.ingress)
return self.ingress_time - travel_time
@property
def split_time(self) -> timedelta:
- travel_time = self.travel_time_between_waypoints(
- self.egress, self.split)
+ travel_time = self.travel_time_between_waypoints(self.egress, self.split)
return self.egress_time + travel_time
@property
def ingress_time(self) -> timedelta:
tot = self.package.time_over_target
travel_time = self.travel_time_between_waypoints(
- self.ingress, self.target_area_waypoint)
+ self.ingress, self.target_area_waypoint
+ )
return tot - travel_time
@property
def egress_time(self) -> timedelta:
tot = self.package.time_over_target
travel_time = self.travel_time_between_waypoints(
- self.target_area_waypoint, self.egress)
+ self.target_area_waypoint, self.egress
+ )
return tot + travel_time
def tot_for_waypoint(self, waypoint: FlightWaypoint) -> Optional[timedelta]:
@@ -664,7 +662,8 @@ class SweepFlightPlan(LoiterFlightPlan):
@property
def sweep_start_time(self) -> timedelta:
travel_time = self.travel_time_between_waypoints(
- self.sweep_start, self.sweep_end)
+ self.sweep_start, self.sweep_end
+ )
return self.sweep_end_time - travel_time
@property
@@ -678,8 +677,7 @@ class SweepFlightPlan(LoiterFlightPlan):
return self.sweep_end_time
return None
- def depart_time_for_waypoint(
- self, waypoint: FlightWaypoint) -> Optional[timedelta]:
+ def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> Optional[timedelta]:
if waypoint == self.hold:
return self.push_time
return None
@@ -689,7 +687,7 @@ class SweepFlightPlan(LoiterFlightPlan):
return self.sweep_end_time - TravelTime.between_points(
self.hold.position,
self.sweep_end.position,
- GroundSpeed.for_flight(self.flight, self.hold.alt)
+ GroundSpeed.for_flight(self.flight, self.hold.alt),
)
def mission_departure_time(self) -> timedelta:
@@ -721,8 +719,7 @@ class CustomFlightPlan(FlightPlan):
return self.package.time_over_target
return None
- def depart_time_for_waypoint(
- self, waypoint: FlightWaypoint) -> Optional[timedelta]:
+ def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> Optional[timedelta]:
return None
@property
@@ -752,9 +749,11 @@ class FlightPlanBuilder:
self.threat_zones = self.game.threat_zone_for(not self.is_player)
def populate_flight_plan(
- self, flight: Flight,
- # TODO: Custom targets should be an attribute of the flight.
- custom_targets: Optional[List[Unit]] = None) -> None:
+ self,
+ flight: Flight,
+ # TODO: Custom targets should be an attribute of the flight.
+ custom_targets: Optional[List[Unit]] = None,
+ ) -> None:
"""Creates a default flight plan for the given mission."""
if flight not in self.package.flights:
raise RuntimeError("Flight must be a part of the package")
@@ -763,8 +762,8 @@ class FlightPlanBuilder:
flight.flight_plan = self.generate_flight_plan(flight, custom_targets)
def generate_flight_plan(
- self, flight: Flight,
- custom_targets: Optional[List[Unit]]) -> FlightPlan:
+ self, flight: Flight, custom_targets: Optional[List[Unit]]
+ ) -> FlightPlan:
# TODO: Flesh out mission types.
task = flight.flight_type
if task == FlightType.ANTISHIP:
@@ -791,8 +790,7 @@ class FlightPlanBuilder:
return self.generate_sweep(flight)
elif task == FlightType.TARCAP:
return self.generate_tarcap(flight)
- raise PlanningError(
- f"{task} flight plan generation not implemented")
+ raise PlanningError(f"{task} flight plan generation not implemented")
def regenerate_package_waypoints(self) -> None:
# The simple case is where the target is greater than the ingress
@@ -829,6 +827,7 @@ class FlightPlanBuilder:
# | | | |
# +--------------+ +---------------+
from gen.ato import PackageWaypoints
+
target = self.package.target.position
join_point = self.preferred_join_point()
@@ -862,10 +861,9 @@ class FlightPlanBuilder:
def legacy_package_waypoints_impl(self) -> None:
from gen.ato import PackageWaypoints
- ingress_point = self._ingress_point(
- self._target_heading_to_package_airfield())
- egress_point = self._egress_point(
- self._target_heading_to_package_airfield())
+
+ ingress_point = self._ingress_point(self._target_heading_to_package_airfield())
+ egress_point = self._egress_point(self._target_heading_to_package_airfield())
join_point = self._rendezvous_point(ingress_point)
split_point = self._rendezvous_point(egress_point)
self.package.waypoints = PackageWaypoints(
@@ -877,7 +875,8 @@ class FlightPlanBuilder:
def preferred_join_point(self) -> Optional[Point]:
path = self.game.navmesh_for(self.is_player).shortest_path(
- self.package_airfield().position, self.package.target.position)
+ self.package_airfield().position, self.package.target.position
+ )
for point in reversed(path):
if not self.threat_zones.threatened(point):
return point
@@ -917,9 +916,9 @@ class FlightPlanBuilder:
targets.append(StrikeTarget(building.category, building))
- return self.strike_flightplan(flight, location,
- FlightWaypointType.INGRESS_STRIKE,
- targets)
+ return self.strike_flightplan(
+ flight, location, FlightWaypointType.INGRESS_STRIKE, targets
+ )
def generate_bai(self, flight: Flight) -> StrikeFlightPlan:
"""Generates a BAI flight plan.
@@ -934,11 +933,11 @@ class FlightPlanBuilder:
targets: List[StrikeTarget] = []
for group in location.groups:
- targets.append(
- StrikeTarget(f"{group.name} at {location.name}", group))
+ targets.append(StrikeTarget(f"{group.name} at {location.name}", group))
- return self.strike_flightplan(flight, location,
- FlightWaypointType.INGRESS_BAI, targets)
+ return self.strike_flightplan(
+ flight, location, FlightWaypointType.INGRESS_BAI, targets
+ )
def generate_anti_ship(self, flight: Flight) -> StrikeFlightPlan:
"""Generates an anti-ship flight plan.
@@ -960,11 +959,11 @@ class FlightPlanBuilder:
targets: List[StrikeTarget] = []
for group in location.groups:
- targets.append(
- StrikeTarget(f"{group.name} at {location.name}", group))
+ targets.append(StrikeTarget(f"{group.name} at {location.name}", group))
- return self.strike_flightplan(flight, location,
- FlightWaypointType.INGRESS_BAI, targets)
+ return self.strike_flightplan(
+ flight, location, FlightWaypointType.INGRESS_BAI, targets
+ )
def generate_barcap(self, flight: Flight) -> BarCapFlightPlan:
"""Generate a BARCAP flight at a given location.
@@ -978,10 +977,12 @@ class FlightPlanBuilder:
raise InvalidObjectiveLocation(flight.flight_type, location)
start, end = self.racetrack_for_objective(location, barcap=True)
- patrol_alt = meters(random.randint(
- int(self.doctrine.min_patrol_altitude.meters),
- int(self.doctrine.max_patrol_altitude.meters)
- ))
+ patrol_alt = meters(
+ random.randint(
+ int(self.doctrine.min_patrol_altitude.meters),
+ int(self.doctrine.max_patrol_altitude.meters),
+ )
+ )
builder = WaypointBuilder(flight, self.game, self.is_player)
start, end = builder.race_track(start, end, patrol_alt)
@@ -992,14 +993,16 @@ class FlightPlanBuilder:
patrol_duration=self.doctrine.cap_duration,
engagement_distance=self.doctrine.cap_engagement_range,
takeoff=builder.takeoff(flight.departure),
- nav_to=builder.nav_path(flight.departure.position, start.position,
- patrol_alt),
- nav_from=builder.nav_path(end.position, flight.arrival.position,
- patrol_alt),
+ nav_to=builder.nav_path(
+ flight.departure.position, start.position, patrol_alt
+ ),
+ nav_from=builder.nav_path(
+ end.position, flight.arrival.position, patrol_alt
+ ),
patrol_start=start,
patrol_end=end,
land=builder.land(flight.arrival),
- divert=builder.divert(flight.divert)
+ divert=builder.divert(flight.divert),
)
def generate_sweep(self, flight: Flight) -> SweepFlightPlan:
@@ -1012,12 +1015,10 @@ class FlightPlanBuilder:
target = self.package.target.position
heading = self.package.waypoints.join.heading_between_point(target)
- start = target.point_from_heading(heading,
- -self.doctrine.sweep_distance.meters)
+ start = target.point_from_heading(heading, -self.doctrine.sweep_distance.meters)
builder = WaypointBuilder(flight, self.game, self.is_player)
- start, end = builder.sweep(start, target,
- self.doctrine.ingress_altitude)
+ start, end = builder.sweep(start, target, self.doctrine.ingress_altitude)
hold = builder.hold(self._hold_point(flight))
@@ -1028,18 +1029,21 @@ class FlightPlanBuilder:
takeoff=builder.takeoff(flight.departure),
hold=hold,
hold_duration=timedelta(minutes=5),
- nav_to=builder.nav_path(hold.position, start.position,
- self.doctrine.ingress_altitude),
- nav_from=builder.nav_path(end.position, flight.arrival.position,
- self.doctrine.ingress_altitude),
+ nav_to=builder.nav_path(
+ hold.position, start.position, self.doctrine.ingress_altitude
+ ),
+ nav_from=builder.nav_path(
+ end.position, flight.arrival.position, self.doctrine.ingress_altitude
+ ),
sweep_start=start,
sweep_end=end,
land=builder.land(flight.arrival),
- divert=builder.divert(flight.divert)
+ divert=builder.divert(flight.divert),
)
- def racetrack_for_objective(self, location: MissionTarget,
- barcap: bool) -> Tuple[Point, Point]:
+ def racetrack_for_objective(
+ self, location: MissionTarget, barcap: bool
+ ) -> Tuple[Point, Point]:
closest_cache = ObjectiveDistanceCache.get_closest_airfields(location)
for airfield in closest_cache.operational_airfields:
# If the mission is a BARCAP of an enemy airfield, find the *next*
@@ -1052,20 +1056,21 @@ class FlightPlanBuilder:
else:
raise PlanningError("Could not find any enemy airfields")
- heading = location.position.heading_between_point(
- closest_airfield.position
- )
+ heading = location.position.heading_between_point(closest_airfield.position)
- position = ShapelyPoint(self.package.target.position.x,
- self.package.target.position.y)
+ position = ShapelyPoint(
+ self.package.target.position.x, self.package.target.position.y
+ )
if barcap:
# BARCAPs should remain far enough back from the enemy that their
# commit range does not enter the enemy's threat zone. Include a 5nm
# buffer.
- distance_to_no_fly = meters(
- position.distance(self.threat_zones.all)
- ) - self.doctrine.cap_engagement_range - nautical_miles(5)
+ distance_to_no_fly = (
+ meters(position.distance(self.threat_zones.all))
+ - self.doctrine.cap_engagement_range
+ - nautical_miles(5)
+ )
else:
# Other race tracks (TARCAPs, currently) just try to keep some
# distance from the nearest enemy airbase, but since they are by
@@ -1075,28 +1080,31 @@ class FlightPlanBuilder:
distance_to_airfield = meters(
closest_airfield.position.distance_to_point(
self.package.target.position
- ))
+ )
+ )
distance_to_no_fly = distance_to_airfield - min_distance_from_enemy
- min_cap_distance = min(self.doctrine.cap_min_distance_from_cp,
- distance_to_no_fly)
- max_cap_distance = min(self.doctrine.cap_max_distance_from_cp,
- distance_to_no_fly)
+ min_cap_distance = min(
+ self.doctrine.cap_min_distance_from_cp, distance_to_no_fly
+ )
+ max_cap_distance = min(
+ self.doctrine.cap_max_distance_from_cp, distance_to_no_fly
+ )
end = location.position.point_from_heading(
heading,
- random.randint(int(min_cap_distance.meters),
- int(max_cap_distance.meters))
+ random.randint(int(min_cap_distance.meters), int(max_cap_distance.meters)),
)
diameter = random.randint(
int(self.doctrine.cap_min_track_length.meters),
- int(self.doctrine.cap_max_track_length.meters)
+ int(self.doctrine.cap_max_track_length.meters),
)
start = end.point_from_heading(heading - 180, diameter)
return start, end
- def racetrack_for_frontline(self, origin: Point,
- front_line: FrontLine) -> Tuple[Point, Point]:
+ def racetrack_for_frontline(
+ self, origin: Point, front_line: FrontLine
+ ) -> Tuple[Point, Point]:
ally_cp, enemy_cp = front_line.control_points
# Find targets waypoints
@@ -1105,8 +1113,10 @@ class FlightPlanBuilder:
)
center = ingress.point_from_heading(heading, distance / 2)
orbit_center = center.point_from_heading(
- heading - 90, random.randint(int(nautical_miles(6).meters),
- int(nautical_miles(15).meters))
+ heading - 90,
+ random.randint(
+ int(nautical_miles(6).meters), int(nautical_miles(15).meters)
+ ),
)
combat_width = distance / 2
@@ -1132,18 +1142,21 @@ class FlightPlanBuilder:
location = self.package.target
patrol_alt = meters(
- random.randint(int(self.doctrine.min_patrol_altitude.meters),
- int(self.doctrine.max_patrol_altitude.meters)))
+ random.randint(
+ int(self.doctrine.min_patrol_altitude.meters),
+ int(self.doctrine.max_patrol_altitude.meters),
+ )
+ )
# Create points
builder = WaypointBuilder(flight, self.game, self.is_player)
if isinstance(location, FrontLine):
orbit0p, orbit1p = self.racetrack_for_frontline(
- flight.departure.position, location)
+ flight.departure.position, location
+ )
else:
- orbit0p, orbit1p = self.racetrack_for_objective(location,
- barcap=False)
+ orbit0p, orbit1p = self.racetrack_for_objective(location, barcap=False)
start, end = builder.race_track(orbit0p, orbit1p, patrol_alt)
return TarCapFlightPlan(
@@ -1157,18 +1170,17 @@ class FlightPlanBuilder:
patrol_duration=self.doctrine.cap_duration,
engagement_distance=self.doctrine.cap_engagement_range,
takeoff=builder.takeoff(flight.departure),
- nav_to=builder.nav_path(flight.departure.position, orbit0p,
- patrol_alt),
- nav_from=builder.nav_path(orbit1p, flight.arrival.position,
- patrol_alt),
+ nav_to=builder.nav_path(flight.departure.position, orbit0p, patrol_alt),
+ nav_from=builder.nav_path(orbit1p, flight.arrival.position, patrol_alt),
patrol_start=start,
patrol_end=end,
land=builder.land(flight.arrival),
- divert=builder.divert(flight.divert)
+ divert=builder.divert(flight.divert),
)
- def generate_dead(self, flight: Flight,
- custom_targets: Optional[List[Unit]]) -> StrikeFlightPlan:
+ def generate_dead(
+ self, flight: Flight, custom_targets: Optional[List[Unit]]
+ ) -> StrikeFlightPlan:
"""Generate a DEAD flight at a given location.
Args:
@@ -1181,7 +1193,8 @@ class FlightPlanBuilder:
is_sam = isinstance(location, SamGroundObject)
if not is_ewr and not is_sam:
logging.exception(
- f"Invalid Objective Location for DEAD flight {flight=} at {location=}")
+ f"Invalid Objective Location for DEAD flight {flight=} at {location=}"
+ )
raise InvalidObjectiveLocation(flight.flight_type, location)
# TODO: Unify these.
@@ -1193,8 +1206,9 @@ class FlightPlanBuilder:
for target in custom_targets:
targets.append(StrikeTarget(location.name, target))
- return self.strike_flightplan(flight, location,
- FlightWaypointType.INGRESS_DEAD, targets)
+ return self.strike_flightplan(
+ flight, location, FlightWaypointType.INGRESS_DEAD, targets
+ )
def generate_oca_strike(self, flight: Flight) -> StrikeFlightPlan:
"""Generate an OCA Strike flight plan at a given location.
@@ -1207,11 +1221,13 @@ class FlightPlanBuilder:
if not isinstance(location, Airfield):
logging.exception(
f"Invalid Objective Location for OCA Strike flight "
- f"{flight=} at {location=}.")
+ f"{flight=} at {location=}."
+ )
raise InvalidObjectiveLocation(flight.flight_type, location)
- return self.strike_flightplan(flight, location,
- FlightWaypointType.INGRESS_OCA_AIRCRAFT)
+ return self.strike_flightplan(
+ flight, location, FlightWaypointType.INGRESS_OCA_AIRCRAFT
+ )
def generate_runway_attack(self, flight: Flight) -> StrikeFlightPlan:
"""Generate a runway attack flight plan at a given location.
@@ -1224,14 +1240,17 @@ class FlightPlanBuilder:
if not isinstance(location, Airfield):
logging.exception(
f"Invalid Objective Location for runway bombing flight "
- f"{flight=} at {location=}.")
+ f"{flight=} at {location=}."
+ )
raise InvalidObjectiveLocation(flight.flight_type, location)
- return self.strike_flightplan(flight, location,
- FlightWaypointType.INGRESS_OCA_RUNWAY)
+ return self.strike_flightplan(
+ flight, location, FlightWaypointType.INGRESS_OCA_RUNWAY
+ )
- def generate_sead(self, flight: Flight,
- custom_targets: Optional[List[Unit]]) -> StrikeFlightPlan:
+ def generate_sead(
+ self, flight: Flight, custom_targets: Optional[List[Unit]]
+ ) -> StrikeFlightPlan:
"""Generate a SEAD flight at a given location.
Args:
@@ -1249,16 +1268,19 @@ class FlightPlanBuilder:
for target in custom_targets:
targets.append(StrikeTarget(location.name, target))
- return self.strike_flightplan(flight, location,
- FlightWaypointType.INGRESS_SEAD, targets)
+ return self.strike_flightplan(
+ flight, location, FlightWaypointType.INGRESS_SEAD, targets
+ )
def generate_escort(self, flight: Flight) -> StrikeFlightPlan:
assert self.package.waypoints is not None
builder = WaypointBuilder(flight, self.game, self.is_player)
ingress, target, egress = builder.escort(
- self.package.waypoints.ingress, self.package.target,
- self.package.waypoints.egress)
+ self.package.waypoints.ingress,
+ self.package.target,
+ self.package.waypoints.egress,
+ )
hold = builder.hold(self._hold_point(flight))
join = builder.join(self.package.waypoints.join)
split = builder.split(self.package.waypoints.split)
@@ -1269,17 +1291,19 @@ class FlightPlanBuilder:
takeoff=builder.takeoff(flight.departure),
hold=hold,
hold_duration=timedelta(minutes=5),
- nav_to=builder.nav_path(hold.position, join.position,
- self.doctrine.ingress_altitude),
+ nav_to=builder.nav_path(
+ hold.position, join.position, self.doctrine.ingress_altitude
+ ),
join=join,
ingress=ingress,
targets=[target],
egress=egress,
split=split,
- nav_from=builder.nav_path(split.position, flight.arrival.position,
- self.doctrine.ingress_altitude),
+ nav_from=builder.nav_path(
+ split.position, flight.arrival.position, self.doctrine.ingress_altitude
+ ),
land=builder.land(flight.arrival),
- divert=builder.divert(flight.divert)
+ divert=builder.divert(flight.divert),
)
def generate_cas(self, flight: Flight) -> CasFlightPlan:
@@ -1294,8 +1318,7 @@ class FlightPlanBuilder:
raise InvalidObjectiveLocation(flight.flight_type, location)
ingress, heading, distance = Conflict.frontline_vector(
- location.control_points[0], location.control_points[1],
- self.game.theater
+ location.control_points[0], location.control_points[1], self.game.theater
)
center = ingress.point_from_heading(heading, distance / 2)
egress = ingress.point_from_heading(heading, distance)
@@ -1312,22 +1335,26 @@ class FlightPlanBuilder:
flight=flight,
patrol_duration=self.doctrine.cas_duration,
takeoff=builder.takeoff(flight.departure),
- nav_to=builder.nav_path(flight.departure.position, ingress,
- self.doctrine.ingress_altitude),
- nav_from=builder.nav_path(egress, flight.arrival.position,
- self.doctrine.ingress_altitude),
- patrol_start=builder.ingress(FlightWaypointType.INGRESS_CAS,
- ingress, location),
+ nav_to=builder.nav_path(
+ flight.departure.position, ingress, self.doctrine.ingress_altitude
+ ),
+ nav_from=builder.nav_path(
+ egress, flight.arrival.position, self.doctrine.ingress_altitude
+ ),
+ patrol_start=builder.ingress(
+ FlightWaypointType.INGRESS_CAS, ingress, location
+ ),
engagement_distance=meters(FRONTLINE_LENGTH) / 2,
target=builder.cas(center),
patrol_end=builder.egress(egress, location),
land=builder.land(flight.arrival),
- divert=builder.divert(flight.divert)
+ divert=builder.divert(flight.divert),
)
@staticmethod
- def target_waypoint(flight: Flight, builder: WaypointBuilder,
- target: StrikeTarget) -> FlightWaypoint:
+ def target_waypoint(
+ flight: Flight, builder: WaypointBuilder, target: StrikeTarget
+ ) -> FlightWaypoint:
if flight.flight_type in {FlightType.ANTISHIP, FlightType.BAI}:
return builder.bai_group(target)
elif flight.flight_type == FlightType.DEAD:
@@ -1338,8 +1365,9 @@ class FlightPlanBuilder:
return builder.strike_point(target)
@staticmethod
- def target_area_waypoint(flight: Flight, location: MissionTarget,
- builder: WaypointBuilder) -> FlightWaypoint:
+ def target_area_waypoint(
+ flight: Flight, location: MissionTarget, builder: WaypointBuilder
+ ) -> FlightWaypoint:
if flight.flight_type == FlightType.DEAD:
return builder.dead_area(location)
elif flight.flight_type == FlightType.SEAD:
@@ -1360,12 +1388,14 @@ class FlightPlanBuilder:
# If the origin airfield is closer to the target than the join
# point, plan the hold point such that it retreats from the origin
# airfield.
- return join.point_from_heading(target.heading_between_point(origin),
- self.doctrine.push_distance.meters)
+ return join.point_from_heading(
+ target.heading_between_point(origin), self.doctrine.push_distance.meters
+ )
heading_to_join = origin.heading_between_point(join)
hold_point = origin.point_from_heading(
- heading_to_join, self.doctrine.push_distance.meters)
+ heading_to_join, self.doctrine.push_distance.meters
+ )
hold_distance = meters(hold_point.distance_to_point(join))
if hold_distance >= self.doctrine.push_distance:
# Hold point is between the origin airfield and the join point and
@@ -1379,26 +1409,27 @@ class FlightPlanBuilder:
# properly.
origin_to_join = origin.distance_to_point(join)
cos_theta = (
- (self.doctrine.hold_distance.meters ** 2 +
- origin_to_join ** 2 -
- self.doctrine.join_distance.meters ** 2) /
- (2 * self.doctrine.hold_distance.meters * origin_to_join)
- )
+ self.doctrine.hold_distance.meters ** 2
+ + origin_to_join ** 2
+ - self.doctrine.join_distance.meters ** 2
+ ) / (2 * self.doctrine.hold_distance.meters * origin_to_join)
try:
theta = math.acos(cos_theta)
except ValueError:
# No solution that maintains hold and join distances. Extend the
# hold point away from the target.
return origin.point_from_heading(
- target.heading_between_point(origin),
- self.doctrine.hold_distance.meters)
+ target.heading_between_point(origin), self.doctrine.hold_distance.meters
+ )
- return origin.point_from_heading(heading_to_join - theta,
- self.doctrine.hold_distance.meters)
+ return origin.point_from_heading(
+ heading_to_join - theta, self.doctrine.hold_distance.meters
+ )
# TODO: Make a model for the waypoint builder and use that in the UI.
- def generate_rtb_waypoint(self, flight: Flight,
- arrival: ControlPoint) -> FlightWaypoint:
+ def generate_rtb_waypoint(
+ self, flight: Flight, arrival: ControlPoint
+ ) -> FlightWaypoint:
"""Generate RTB landing point.
Args:
@@ -1409,20 +1440,23 @@ class FlightPlanBuilder:
return builder.land(arrival)
def strike_flightplan(
- self, flight: Flight, location: MissionTarget,
- ingress_type: FlightWaypointType,
- targets: Optional[List[StrikeTarget]] = None) -> StrikeFlightPlan:
+ self,
+ flight: Flight,
+ location: MissionTarget,
+ ingress_type: FlightWaypointType,
+ targets: Optional[List[StrikeTarget]] = None,
+ ) -> StrikeFlightPlan:
assert self.package.waypoints is not None
builder = WaypointBuilder(flight, self.game, self.is_player, targets)
target_waypoints: List[FlightWaypoint] = []
if targets is not None:
for target in targets:
- target_waypoints.append(
- self.target_waypoint(flight, builder, target))
+ target_waypoints.append(self.target_waypoint(flight, builder, target))
else:
target_waypoints.append(
- self.target_area_waypoint(flight, location, builder))
+ self.target_area_waypoint(flight, location, builder)
+ )
hold = builder.hold(self._hold_point(flight))
join = builder.join(self.package.waypoints.join)
@@ -1434,32 +1468,38 @@ class FlightPlanBuilder:
takeoff=builder.takeoff(flight.departure),
hold=hold,
hold_duration=timedelta(minutes=5),
- nav_to=builder.nav_path(hold.position, join.position,
- self.doctrine.ingress_altitude),
+ nav_to=builder.nav_path(
+ hold.position, join.position, self.doctrine.ingress_altitude
+ ),
join=join,
- ingress=builder.ingress(ingress_type,
- self.package.waypoints.ingress, location),
+ ingress=builder.ingress(
+ ingress_type, self.package.waypoints.ingress, location
+ ),
targets=target_waypoints,
egress=builder.egress(self.package.waypoints.egress, location),
split=split,
- nav_from=builder.nav_path(split.position, flight.arrival.position,
- self.doctrine.ingress_altitude),
+ nav_from=builder.nav_path(
+ split.position, flight.arrival.position, self.doctrine.ingress_altitude
+ ),
land=builder.land(flight.arrival),
- divert=builder.divert(flight.divert)
+ divert=builder.divert(flight.divert),
)
def _retreating_rendezvous_point(self, attack_transition: Point) -> Point:
"""Creates a rendezvous point that retreats from the origin airfield."""
return attack_transition.point_from_heading(
self.package.target.position.heading_between_point(
- self.package_airfield().position),
- self.doctrine.join_distance.meters)
+ self.package_airfield().position
+ ),
+ self.doctrine.join_distance.meters,
+ )
def _advancing_rendezvous_point(self, attack_transition: Point) -> Point:
"""Creates a rendezvous point that advances toward the target."""
heading = self._heading_to_package_airfield(attack_transition)
return attack_transition.point_from_heading(
- heading, -self.doctrine.join_distance.meters)
+ heading, -self.doctrine.join_distance.meters
+ )
def _rendezvous_should_retreat(self, attack_transition: Point) -> bool:
transition_target_distance = attack_transition.distance_to_point(
@@ -1514,13 +1554,9 @@ class FlightPlanBuilder:
# The package airfield is either the flight's airfield (when there is no
# package) or the closest airfield to the objective that is the
# departure airfield for some flight in the package.
- cache = ObjectiveDistanceCache.get_closest_airfields(
- self.package.target
- )
+ cache = ObjectiveDistanceCache.get_closest_airfields(self.package.target)
for airfield in cache.operational_airfields:
for flight in self.package.flights:
if flight.departure == airfield:
return airfield
- raise RuntimeError(
- "Could not find any airfield assigned to this package"
- )
+ raise RuntimeError("Could not find any airfield assigned to this package")
diff --git a/gen/flights/traveltime.py b/gen/flights/traveltime.py
index 3311fe22..98e74fac 100644
--- a/gen/flights/traveltime.py
+++ b/gen/flights/traveltime.py
@@ -23,7 +23,6 @@ if TYPE_CHECKING:
class GroundSpeed:
-
@classmethod
def for_flight(cls, flight: Flight, altitude: Distance) -> Speed:
if not issubclass(flight.unit_type, FlyingType):
@@ -55,13 +54,11 @@ class TravelTime:
def between_points(a: Point, b: Point, speed: Speed) -> timedelta:
error_factor = 1.1
distance = meters(a.distance_to_point(b))
- return timedelta(
- hours=distance.nautical_miles / speed.knots * error_factor)
+ return timedelta(hours=distance.nautical_miles / speed.knots * error_factor)
# TODO: Most if not all of this should move into FlightPlan.
class TotEstimator:
-
def __init__(self, package: Package) -> None:
self.package = package
@@ -75,9 +72,9 @@ class TotEstimator:
return startup_time
def earliest_tot(self) -> timedelta:
- earliest_tot = max((
- self.earliest_tot_for_flight(f) for f in self.package.flights
- ))
+ earliest_tot = max(
+ (self.earliest_tot_for_flight(f) for f in self.package.flights)
+ )
# Trim microseconds. DCS doesn't handle sub-second resolution for tasks,
# and they're not interesting from a mission planning perspective so we
diff --git a/gen/flights/waypointbuilder.py b/gen/flights/waypointbuilder.py
index 2d5ca9d8..d9058538 100644
--- a/gen/flights/waypointbuilder.py
+++ b/gen/flights/waypointbuilder.py
@@ -36,8 +36,13 @@ class StrikeTarget:
class WaypointBuilder:
- def __init__(self, flight: Flight, game: Game, player: bool,
- targets: Optional[List[StrikeTarget]] = None) -> None:
+ def __init__(
+ self,
+ flight: Flight,
+ game: Game,
+ player: bool,
+ targets: Optional[List[StrikeTarget]] = None,
+ ) -> None:
self.flight = flight
self.conditions = game.conditions
self.doctrine = game.faction_for(player).doctrine
@@ -65,9 +70,7 @@ class WaypointBuilder:
FlightWaypointType.NAV,
position.x,
position.y,
- meters(
- 500
- ) if self.is_helo else self.doctrine.rendezvous_altitude
+ meters(500) if self.is_helo else self.doctrine.rendezvous_altitude,
)
waypoint.name = "NAV"
waypoint.alt_type = "BARO"
@@ -75,10 +78,7 @@ class WaypointBuilder:
waypoint.pretty_name = "Enter theater"
else:
waypoint = FlightWaypoint(
- FlightWaypointType.TAKEOFF,
- position.x,
- position.y,
- meters(0)
+ FlightWaypointType.TAKEOFF, position.x, position.y, meters(0)
)
waypoint.name = "TAKEOFF"
waypoint.alt_type = "RADIO"
@@ -98,9 +98,7 @@ class WaypointBuilder:
FlightWaypointType.NAV,
position.x,
position.y,
- meters(
- 500
- ) if self.is_helo else self.doctrine.rendezvous_altitude
+ meters(500) if self.is_helo else self.doctrine.rendezvous_altitude,
)
waypoint.name = "NAV"
waypoint.alt_type = "BARO"
@@ -108,10 +106,7 @@ class WaypointBuilder:
waypoint.pretty_name = "Exit theater"
else:
waypoint = FlightWaypoint(
- FlightWaypointType.LANDING_POINT,
- position.x,
- position.y,
- meters(0)
+ FlightWaypointType.LANDING_POINT, position.x, position.y, meters(0)
)
waypoint.name = "LANDING"
waypoint.alt_type = "RADIO"
@@ -119,8 +114,7 @@ class WaypointBuilder:
waypoint.pretty_name = "Land"
return waypoint
- def divert(self,
- divert: Optional[ControlPoint]) -> Optional[FlightWaypoint]:
+ def divert(self, divert: Optional[ControlPoint]) -> Optional[FlightWaypoint]:
"""Create divert waypoint for the given arrival airfield or carrier.
Args:
@@ -141,10 +135,7 @@ class WaypointBuilder:
altitude_type = "RADIO"
waypoint = FlightWaypoint(
- FlightWaypointType.DIVERT,
- position.x,
- position.y,
- altitude
+ FlightWaypointType.DIVERT, position.x, position.y, altitude
)
waypoint.alt_type = altitude_type
waypoint.name = "DIVERT"
@@ -158,9 +149,7 @@ class WaypointBuilder:
FlightWaypointType.LOITER,
position.x,
position.y,
- meters(
- 500
- ) if self.is_helo else self.doctrine.rendezvous_altitude
+ meters(500) if self.is_helo else self.doctrine.rendezvous_altitude,
)
waypoint.pretty_name = "Hold"
waypoint.description = "Wait until push time"
@@ -172,9 +161,7 @@ class WaypointBuilder:
FlightWaypointType.JOIN,
position.x,
position.y,
- meters(
- 500
- ) if self.is_helo else self.doctrine.ingress_altitude
+ meters(500) if self.is_helo else self.doctrine.ingress_altitude,
)
waypoint.pretty_name = "Join"
waypoint.description = "Rendezvous with package"
@@ -186,24 +173,24 @@ class WaypointBuilder:
FlightWaypointType.SPLIT,
position.x,
position.y,
- meters(
- 500
- ) if self.is_helo else self.doctrine.ingress_altitude
+ meters(500) if self.is_helo else self.doctrine.ingress_altitude,
)
waypoint.pretty_name = "Split"
waypoint.description = "Depart from package"
waypoint.name = "SPLIT"
return waypoint
- def ingress(self, ingress_type: FlightWaypointType, position: Point,
- objective: MissionTarget) -> FlightWaypoint:
+ def ingress(
+ self,
+ ingress_type: FlightWaypointType,
+ position: Point,
+ objective: MissionTarget,
+ ) -> FlightWaypoint:
waypoint = FlightWaypoint(
ingress_type,
position.x,
position.y,
- meters(
- 500
- ) if self.is_helo else self.doctrine.ingress_altitude
+ meters(500) if self.is_helo else self.doctrine.ingress_altitude,
)
waypoint.pretty_name = "INGRESS on " + objective.name
waypoint.description = "INGRESS on " + objective.name
@@ -217,9 +204,7 @@ class WaypointBuilder:
FlightWaypointType.EGRESS,
position.x,
position.y,
- meters(
- 500
- ) if self.is_helo else self.doctrine.ingress_altitude
+ meters(500) if self.is_helo else self.doctrine.ingress_altitude,
)
waypoint.pretty_name = "EGRESS from " + target.name
waypoint.description = "EGRESS from " + target.name
@@ -244,7 +229,7 @@ class WaypointBuilder:
FlightWaypointType.TARGET_POINT,
target.target.position.x,
target.target.position.y,
- meters(0)
+ meters(0),
)
waypoint.description = description
waypoint.pretty_name = description
@@ -269,13 +254,14 @@ class WaypointBuilder:
return self._target_area(f"ATTACK {target.name}", target, flyover=True)
@staticmethod
- def _target_area(name: str, location: MissionTarget,
- flyover: bool = False) -> FlightWaypoint:
+ def _target_area(
+ name: str, location: MissionTarget, flyover: bool = False
+ ) -> FlightWaypoint:
waypoint = FlightWaypoint(
FlightWaypointType.TARGET_GROUP_LOC,
location.position.x,
location.position.y,
- meters(0)
+ meters(0),
)
waypoint.description = name
waypoint.pretty_name = name
@@ -300,7 +286,7 @@ class WaypointBuilder:
FlightWaypointType.CAS,
position.x,
position.y,
- meters(500) if self.is_helo else meters(1000)
+ meters(500) if self.is_helo else meters(1000),
)
waypoint.alt_type = "RADIO"
waypoint.description = "Provide CAS"
@@ -317,10 +303,7 @@ class WaypointBuilder:
altitude: Altitude of the racetrack.
"""
waypoint = FlightWaypoint(
- FlightWaypointType.PATROL_TRACK,
- position.x,
- position.y,
- altitude
+ FlightWaypointType.PATROL_TRACK, position.x, position.y, altitude
)
waypoint.name = "RACETRACK START"
waypoint.description = "Orbit between this point and the next point"
@@ -336,18 +319,16 @@ class WaypointBuilder:
altitude: Altitude of the racetrack.
"""
waypoint = FlightWaypoint(
- FlightWaypointType.PATROL,
- position.x,
- position.y,
- altitude
+ FlightWaypointType.PATROL, position.x, position.y, altitude
)
waypoint.name = "RACETRACK END"
waypoint.description = "Orbit between this point and the previous point"
waypoint.pretty_name = "Race-track end"
return waypoint
- def race_track(self, start: Point, end: Point,
- altitude: Distance) -> Tuple[FlightWaypoint, FlightWaypoint]:
+ def race_track(
+ self, start: Point, end: Point, altitude: Distance
+ ) -> Tuple[FlightWaypoint, FlightWaypoint]:
"""Creates two waypoint for a racetrack orbit.
Args:
@@ -355,8 +336,10 @@ class WaypointBuilder:
end: The ending racetrack waypoint.
altitude: The racetrack altitude.
"""
- return (self.race_track_start(start, altitude),
- self.race_track_end(end, altitude))
+ return (
+ self.race_track_start(start, altitude),
+ self.race_track_end(end, altitude),
+ )
@staticmethod
def sweep_start(position: Point, altitude: Distance) -> FlightWaypoint:
@@ -367,10 +350,7 @@ class WaypointBuilder:
altitude: Altitude of the sweep in meters.
"""
waypoint = FlightWaypoint(
- FlightWaypointType.INGRESS_SWEEP,
- position.x,
- position.y,
- altitude
+ FlightWaypointType.INGRESS_SWEEP, position.x, position.y, altitude
)
waypoint.name = "SWEEP START"
waypoint.description = "Proceed to the target and engage enemy aircraft"
@@ -386,18 +366,16 @@ class WaypointBuilder:
altitude: Altitude of the sweep in meters.
"""
waypoint = FlightWaypoint(
- FlightWaypointType.EGRESS,
- position.x,
- position.y,
- altitude
+ FlightWaypointType.EGRESS, position.x, position.y, altitude
)
waypoint.name = "SWEEP END"
waypoint.description = "End of sweep"
waypoint.pretty_name = "Sweep end"
return waypoint
- def sweep(self, start: Point, end: Point,
- altitude: Distance) -> Tuple[FlightWaypoint, FlightWaypoint]:
+ def sweep(
+ self, start: Point, end: Point, altitude: Distance
+ ) -> Tuple[FlightWaypoint, FlightWaypoint]:
"""Creates two waypoint for a racetrack orbit.
Args:
@@ -405,11 +383,11 @@ class WaypointBuilder:
end: The end of the sweep.
altitude: The sweep altitude.
"""
- return (self.sweep_start(start, altitude),
- self.sweep_end(end, altitude))
+ return (self.sweep_start(start, altitude), self.sweep_end(end, altitude))
- def escort(self, ingress: Point, target: MissionTarget, egress: Point) -> \
- Tuple[FlightWaypoint, FlightWaypoint, FlightWaypoint]:
+ def escort(
+ self, ingress: Point, target: MissionTarget, egress: Point
+ ) -> Tuple[FlightWaypoint, FlightWaypoint, FlightWaypoint]:
"""Creates the waypoints needed to escort the package.
Args:
@@ -423,16 +401,13 @@ class WaypointBuilder:
# description in gen.aircraft.JoinPointBuilder), so instead we give
# the escort flights a flight plan including the ingress point, target
# area, and egress point.
- ingress = self.ingress(FlightWaypointType.INGRESS_ESCORT, ingress,
- target)
+ ingress = self.ingress(FlightWaypointType.INGRESS_ESCORT, ingress, target)
waypoint = FlightWaypoint(
FlightWaypointType.TARGET_GROUP_LOC,
target.position.x,
target.position.y,
- meters(
- 500
- ) if self.is_helo else self.doctrine.ingress_altitude
+ meters(500) if self.is_helo else self.doctrine.ingress_altitude,
)
waypoint.name = "TARGET"
waypoint.description = "Escort the package"
@@ -450,18 +425,14 @@ class WaypointBuilder:
altitude: Altitude of the waypoint.
"""
waypoint = FlightWaypoint(
- FlightWaypointType.NAV,
- position.x,
- position.y,
- altitude
+ FlightWaypointType.NAV, position.x, position.y, altitude
)
waypoint.name = "NAV"
waypoint.description = "NAV"
waypoint.pretty_name = "Nav"
return waypoint
- def nav_path(self, a: Point, b: Point,
- altitude: Distance) -> List[FlightWaypoint]:
+ def nav_path(self, a: Point, b: Point, altitude: Distance) -> List[FlightWaypoint]:
path = self.clean_nav_points(self.navmesh.shortest_path(a, b))
return [self.nav(self.perturb(p), altitude) for p in path]
@@ -488,10 +459,8 @@ class WaypointBuilder:
previous = current
current = nxt
- def nav_point_prunable(self, previous: Point, current: Point,
- nxt: Point) -> bool:
- previous_threatened = self.threat_zones.path_threatened(previous,
- current)
+ def nav_point_prunable(self, previous: Point, current: Point, nxt: Point) -> bool:
+ previous_threatened = self.threat_zones.path_threatened(previous, current)
next_threatened = self.threat_zones.path_threatened(current, nxt)
pruned_threatened = self.threat_zones.path_threatened(previous, nxt)
previous_distance = meters(previous.distance_to_point(current))
diff --git a/gen/forcedoptionsgen.py b/gen/forcedoptionsgen.py
index 19421942..bbae0eb2 100644
--- a/gen/forcedoptionsgen.py
+++ b/gen/forcedoptionsgen.py
@@ -15,11 +15,15 @@ class ForcedOptionsGenerator:
self.game = game
def _set_options_view(self) -> None:
- self.mission.forced_options.options_view = self.game.settings.map_coalition_visibility
+ self.mission.forced_options.options_view = (
+ self.game.settings.map_coalition_visibility
+ )
def _set_external_views(self) -> None:
if not self.game.settings.external_views_allowed:
- self.mission.forced_options.external_views = self.game.settings.external_views_allowed
+ self.mission.forced_options.external_views = (
+ self.game.settings.external_views_allowed
+ )
def _set_labels(self) -> None:
# TODO: Fix settings to use the real type.
diff --git a/gen/ground_forces/ai_ground_planner.py b/gen/ground_forces/ai_ground_planner.py
index e98d82d2..777efd01 100644
--- a/gen/ground_forces/ai_ground_planner.py
+++ b/gen/ground_forces/ai_ground_planner.py
@@ -39,12 +39,11 @@ GROUP_SIZES_BY_COMBAT_STANCE = {
CombatStance.RETREAT: [2, 4, 6, 8],
CombatStance.BREAKTHROUGH: [4, 6, 6, 8],
CombatStance.ELIMINATION: [2, 4, 4, 4, 6],
- CombatStance.AMBUSH: [1, 1, 2, 2, 2, 2, 4]
+ CombatStance.AMBUSH: [1, 1, 2, 2, 2, 2, 4],
}
class CombatGroup:
-
def __init__(self, role: CombatGroupRole):
self.units: List[VehicleType] = []
self.role = role
@@ -60,11 +59,12 @@ class CombatGroup:
class GroundPlanner:
-
- def __init__(self, cp:ControlPoint, game):
+ def __init__(self, cp: ControlPoint, game):
self.cp = cp
self.game = game
- self.connected_enemy_cp = [cp for cp in self.cp.connected_points if cp.captured != self.cp.captured]
+ self.connected_enemy_cp = [
+ cp for cp in self.cp.connected_points if cp.captured != self.cp.captured
+ ]
self.tank_groups: List[CombatGroup] = []
self.apc_group: List[CombatGroup] = []
self.ifv_group: List[CombatGroup] = []
@@ -80,7 +80,7 @@ class GroundPlanner:
def plan_groundwar(self):
- if hasattr(self.cp, 'stance'):
+ if hasattr(self.cp, "stance"):
group_size_choice = GROUP_SIZES_BY_COMBAT_STANCE[self.cp.stance]
else:
self.cp.stance = CombatStance.DEFENSIVE
@@ -152,12 +152,3 @@ class GroundPlanner:
print("For : #" + str(key))
for group in self.units_per_cp[key]:
print(str(group))
-
-
-
-
-
-
-
-
-
diff --git a/gen/ground_forces/ai_ground_planner_db.py b/gen/ground_forces/ai_ground_planner_db.py
index c448611d..b34b055b 100644
--- a/gen/ground_forces/ai_ground_planner_db.py
+++ b/gen/ground_forces/ai_ground_planner_db.py
@@ -16,7 +16,6 @@ TYPE_TANKS = [
Armor.MBT_M60A3_Patton,
Armor.MBT_Merkava_Mk__4,
Armor.ZTZ_96B,
-
# WW2
Armor.MT_Pz_Kpfw_V_Panther_Ausf_G,
Armor.MT_Pz_Kpfw_IV_Ausf_H,
@@ -29,36 +28,30 @@ TYPE_TANKS = [
Armor.CT_Cromwell_IV,
Armor.HIT_Churchill_VII,
Armor.LT_Mk_VII_Tetrarch,
-
# Mods
frenchpack.DIM__TOYOTA_BLUE,
frenchpack.DIM__TOYOTA_GREEN,
frenchpack.DIM__TOYOTA_DESERT,
frenchpack.DIM__KAMIKAZE,
-
frenchpack.AMX_10RCR,
frenchpack.AMX_10RCR_SEPAR,
frenchpack.AMX_30B2,
frenchpack.Leclerc_Serie_XXI,
-
]
TYPE_ATGM = [
Armor.ATGM_M1045_HMMWV_TOW,
Armor.ATGM_M1134_Stryker,
Armor.IFV_BMP_2,
-
# WW2 (Tank Destroyers)
Armor.M30_Cargo_Carrier,
Armor.TD_Jagdpanzer_IV,
Armor.TD_Jagdpanther_G1,
Armor.TD_M10_GMC,
-
# Mods
frenchpack.VBAE_CRAB_MMP,
frenchpack.VAB_MEPHISTO,
frenchpack.TRM_2000_PAMELA,
-
]
TYPE_IFV = [
@@ -73,17 +66,14 @@ TYPE_IFV = [
Armor.IFV_M2A2_Bradley,
Armor.IFV_BMD_1,
Armor.ZBD_04A,
-
# WW2
Armor.AC_Sd_Kfz_234_2_Puma,
Armor.LAC_M8_Greyhound,
Armor.Daimler_Armoured_Car,
-
# Mods
frenchpack.ERC_90,
frenchpack.VBAE_CRAB,
- frenchpack.VAB_T20_13
-
+ frenchpack.VAB_T20_13,
]
TYPE_APC = [
@@ -101,16 +91,13 @@ TYPE_APC = [
Armor.ARV_BRDM_2,
Armor.ARV_BTR_RD,
Armor.FDDM_Grad,
-
# WW2
Armor.APC_M2A1,
Armor.APC_Sd_Kfz_251,
-
# Mods
frenchpack.VAB__50,
frenchpack.VBL__50,
frenchpack.VBL_AANF1,
-
]
TYPE_ARTILLERY = [
@@ -125,10 +112,9 @@ TYPE_ARTILLERY = [
Artillery.SpGH_Dana,
Artillery.SPH_2S19_Msta,
Artillery.MLRS_FDDM,
-
# WW2
Artillery.Sturmpanzer_IV_Brummbär,
- Artillery.M12_GMC
+ Artillery.M12_GMC,
]
TYPE_LOGI = [
@@ -147,11 +133,9 @@ TYPE_LOGI = [
Unarmed.Willys_MB,
Unarmed.Land_Rover_109_S3,
Unarmed.Land_Rover_101_FC,
-
# Mods
frenchpack.VBL,
frenchpack.VAB,
-
]
TYPE_INFANTRY = [
@@ -179,7 +163,6 @@ TYPE_SHORAD = [
AirDefence.SAM_SA_13_Strela_10M3_9A35M3,
AirDefence.SAM_SA_15_Tor_9A331,
AirDefence.SAM_SA_19_Tunguska_2S6,
-
AirDefence.SPAAA_Gepard,
AirDefence.AAA_Vulcan_M163,
AirDefence.SAM_Linebacker_M6,
@@ -187,7 +170,6 @@ TYPE_SHORAD = [
AirDefence.SAM_Avenger_M1097,
AirDefence.SAM_Roland_ADS,
AirDefence.HQ_7_Self_Propelled_LN,
-
AirDefence.AAA_8_8cm_Flak_18,
AirDefence.AAA_8_8cm_Flak_36,
AirDefence.AAA_8_8cm_Flak_37,
@@ -195,5 +177,4 @@ TYPE_SHORAD = [
AirDefence.AAA_Bofors_40mm,
AirDefence.AAA_M1_37mm,
AirDefence.AA_gun_QF_3_7,
-
]
diff --git a/gen/ground_forces/combat_stance.py b/gen/ground_forces/combat_stance.py
index 604ec508..26e959eb 100644
--- a/gen/ground_forces/combat_stance.py
+++ b/gen/ground_forces/combat_stance.py
@@ -2,10 +2,11 @@ from enum import Enum
class CombatStance(Enum):
- DEFENSIVE = 0 # Unit will adopt defensive stance with medium group of units
- AGGRESSIVE = 1 # Unit will attempt to make progress with medium sized group of units
- RETREAT = 2 # Unit will retreat
- BREAKTHROUGH = 3 # Unit will attempt a breakthrough, rushing forward very aggresively with big group of armored units, and even less armored units will move aggresively
+ DEFENSIVE = 0 # Unit will adopt defensive stance with medium group of units
+ AGGRESSIVE = (
+ 1 # Unit will attempt to make progress with medium sized group of units
+ )
+ RETREAT = 2 # Unit will retreat
+ BREAKTHROUGH = 3 # Unit will attempt a breakthrough, rushing forward very aggresively with big group of armored units, and even less armored units will move aggresively
ELIMINATION = 4 # Unit will progress aggresively toward anemy units, attempting to eliminate the ennemy force
- AMBUSH = 5 # Units will adopt a defensive stance a bit different from 'DEFENSIVE', ATGM & INFANTRY with RPG will be located on frontline with the armored units. (The groups of units will be smaller)
-
+ AMBUSH = 5 # Units will adopt a defensive stance a bit different from 'DEFENSIVE', ATGM & INFANTRY with RPG will be located on frontline with the armored units. (The groups of units will be smaller)
diff --git a/gen/groundobjectsgen.py b/gen/groundobjectsgen.py
index a19f38ae..cf7f371d 100644
--- a/gen/groundobjectsgen.py
+++ b/gen/groundobjectsgen.py
@@ -18,7 +18,8 @@ from dcs.task import (
ActivateBeaconCommand,
ActivateICLSCommand,
EPLRS,
- OptAlarmState, FireAtPoint,
+ OptAlarmState,
+ FireAtPoint,
)
from dcs.unit import Ship, Unit, Vehicle
from dcs.unitgroup import Group, ShipGroup, StaticGroup, VehicleGroup
@@ -30,9 +31,12 @@ from game.data.building_data import FORTIFICATION_UNITS, FORTIFICATION_UNITS_ID
from game.db import unit_type_from_name
from game.theater import ControlPoint, TheaterGroundObject
from game.theater.theatergroundobject import (
- BuildingGroundObject, CarrierGroundObject,
+ BuildingGroundObject,
+ CarrierGroundObject,
GenericCarrierGroundObject,
- LhaGroundObject, ShipGroundObject, MissileSiteGroundObject,
+ LhaGroundObject,
+ ShipGroundObject,
+ MissileSiteGroundObject,
)
from game.unitmap import UnitMap
from game.utils import knots, mps
@@ -53,8 +57,15 @@ class GenericGroundObjectGenerator:
Currently used only for SAM
"""
- def __init__(self, ground_object: TheaterGroundObject, country: Country,
- game: Game, mission: Mission, unit_map: UnitMap) -> None:
+
+ def __init__(
+ self,
+ ground_object: TheaterGroundObject,
+ country: Country,
+ game: Game,
+ mission: Mission,
+ unit_map: UnitMap,
+ ) -> None:
self.ground_object = ground_object
self.country = country
self.game = game
@@ -72,18 +83,22 @@ class GenericGroundObjectGenerator:
unit_type = unit_type_from_name(group.units[0].type)
if unit_type is None:
- raise RuntimeError(
- f"Unrecognized unit type: {group.units[0].type}")
+ raise RuntimeError(f"Unrecognized unit type: {group.units[0].type}")
- vg = self.m.vehicle_group(self.country, group.name, unit_type,
- position=group.position,
- heading=group.units[0].heading)
+ vg = self.m.vehicle_group(
+ self.country,
+ group.name,
+ unit_type,
+ position=group.position,
+ heading=group.units[0].heading,
+ )
vg.units[0].name = self.m.string(group.units[0].name)
vg.units[0].player_can_drive = True
for i, u in enumerate(group.units):
if i > 0:
- vehicle = Vehicle(self.m.next_unit_id(),
- self.m.string(u.name), u.type)
+ vehicle = Vehicle(
+ self.m.next_unit_id(), self.m.string(u.name), u.type
+ )
vehicle.position.x = u.position.x
vehicle.position.y = u.position.y
vehicle.heading = u.heading
@@ -96,7 +111,7 @@ class GenericGroundObjectGenerator:
@staticmethod
def enable_eplrs(group: Group, unit_type: Type[UnitType]) -> None:
- if hasattr(unit_type, 'eplrs'):
+ if hasattr(unit_type, "eplrs"):
if unit_type.eplrs:
group.points[0].tasks.append(EPLRS(group.id))
@@ -106,14 +121,13 @@ class GenericGroundObjectGenerator:
else:
group.points[0].tasks.append(OptAlarmState(1))
- def _register_unit_group(self, persistence_group: Group,
- miz_group: Group) -> None:
- self.unit_map.add_ground_object_units(self.ground_object,
- persistence_group, miz_group)
+ def _register_unit_group(self, persistence_group: Group, miz_group: Group) -> None:
+ self.unit_map.add_ground_object_units(
+ self.ground_object, persistence_group, miz_group
+ )
class MissileSiteGenerator(GenericGroundObjectGenerator):
-
def generate(self) -> None:
super(MissileSiteGenerator, self).generate()
# Note : Only the SCUD missiles group can fire (V1 site cannot fire in game right now)
@@ -125,13 +139,19 @@ class MissileSiteGenerator(GenericGroundObjectGenerator):
targets = self.possible_missile_targets(vg)
if targets:
target = random.choice(targets)
- real_target = target.point_from_heading(random.randint(0, 360), random.randint(0, 2500))
+ real_target = target.point_from_heading(
+ random.randint(0, 360), random.randint(0, 2500)
+ )
vg.points[0].add_task(FireAtPoint(real_target))
logging.info("Set up fire task for missile group.")
else:
- logging.info("Couldn't setup missile site to fire, no valid target in range.")
+ logging.info(
+ "Couldn't setup missile site to fire, no valid target in range."
+ )
else:
- logging.info("Couldn't setup missile site to fire, group was not generated.")
+ logging.info(
+ "Couldn't setup missile site to fire, group was not generated."
+ )
def possible_missile_targets(self, vg: Group) -> List[Point]:
"""
@@ -190,7 +210,8 @@ class BuildingSiteGenerator(GenericGroundObjectGenerator):
break
else:
logging.error(
- f"{self.ground_object.dcs_identifier} not found in static maps")
+ f"{self.ground_object.dcs_identifier} not found in static maps"
+ )
def generate_vehicle_group(self, unit_type: UnitType) -> None:
if not self.ground_object.is_dead:
@@ -228,11 +249,20 @@ class GenericCarrierGenerator(GenericGroundObjectGenerator):
Used by both CV(N) groups and LHA groups.
"""
- def __init__(self, ground_object: GenericCarrierGroundObject,
- control_point: ControlPoint, country: Country, game: Game,
- mission: Mission, radio_registry: RadioRegistry,
- tacan_registry: TacanRegistry, icls_alloc: Iterator[int],
- runways: Dict[str, RunwayData], unit_map: UnitMap) -> None:
+
+ def __init__(
+ self,
+ ground_object: GenericCarrierGroundObject,
+ control_point: ControlPoint,
+ country: Country,
+ game: Game,
+ mission: Mission,
+ radio_registry: RadioRegistry,
+ tacan_registry: TacanRegistry,
+ icls_alloc: Iterator[int],
+ runways: Dict[str, RunwayData],
+ unit_map: UnitMap,
+ ) -> None:
super().__init__(ground_object, country, game, mission, unit_map)
self.ground_object = ground_object
self.control_point = control_point
@@ -245,8 +275,7 @@ class GenericCarrierGenerator(GenericGroundObjectGenerator):
# TODO: Require single group?
for group in self.ground_object.groups:
if not group.units:
- logging.warning(
- f"Found empty carrier group in {self.control_point}")
+ logging.warning(f"Found empty carrier group in {self.control_point}")
continue
atc = self.radio_registry.alloc_uhf()
@@ -270,25 +299,29 @@ class GenericCarrierGenerator(GenericGroundObjectGenerator):
def get_carrier_type(self, group: Group) -> Type[UnitType]:
unit_type = unit_type_from_name(group.units[0].type)
if unit_type is None:
- raise RuntimeError(
- f"Unrecognized carrier name: {group.units[0].type}")
+ raise RuntimeError(f"Unrecognized carrier name: {group.units[0].type}")
return unit_type
- def configure_carrier(self, group: Group,
- atc_channel: RadioFrequency) -> ShipGroup:
+ def configure_carrier(self, group: Group, atc_channel: RadioFrequency) -> ShipGroup:
unit_type = self.get_carrier_type(group)
- ship_group = self.m.ship_group(self.country, group.name, unit_type,
- position=group.position,
- heading=group.units[0].heading)
+ ship_group = self.m.ship_group(
+ self.country,
+ group.name,
+ unit_type,
+ position=group.position,
+ heading=group.units[0].heading,
+ )
ship_group.set_frequency(atc_channel.hertz)
ship_group.units[0].name = self.m.string(group.units[0].name)
return ship_group
def create_ship(self, unit: Unit, atc_channel: RadioFrequency) -> Ship:
- ship = Ship(self.m.next_unit_id(),
- self.m.string(unit.name),
- unit_type_from_name(unit.type))
+ ship = Ship(
+ self.m.next_unit_id(),
+ self.m.string(unit.name),
+ unit_type_from_name(unit.type),
+ )
ship.position.x = unit.position.x
ship.position.y = unit.position.y
ship.heading = unit.heading
@@ -303,7 +336,8 @@ class GenericCarrierGenerator(GenericGroundObjectGenerator):
carrier_speed = knots(25) - mps(wind.speed)
for attempt in range(5):
point = group.points[0].position.point_from_heading(
- brc, 100000 - attempt * 20000)
+ brc, 100000 - attempt * 20000
+ )
if self.game.theater.is_in_sea(point):
group.points[0].speed = carrier_speed.meters_per_second
group.add_waypoint(point, carrier_speed.kph)
@@ -314,21 +348,30 @@ class GenericCarrierGenerator(GenericGroundObjectGenerator):
raise NotImplementedError
@staticmethod
- def activate_beacons(group: ShipGroup, tacan: TacanChannel,
- callsign: str, icls: int) -> None:
- group.points[0].tasks.append(ActivateBeaconCommand(
- channel=tacan.number,
- modechannel=tacan.band.value,
- callsign=callsign,
- unit_id=group.units[0].id,
- aa=False
- ))
- group.points[0].tasks.append(ActivateICLSCommand(
- icls, unit_id=group.units[0].id
- ))
+ def activate_beacons(
+ group: ShipGroup, tacan: TacanChannel, callsign: str, icls: int
+ ) -> None:
+ group.points[0].tasks.append(
+ ActivateBeaconCommand(
+ channel=tacan.number,
+ modechannel=tacan.band.value,
+ callsign=callsign,
+ unit_id=group.units[0].id,
+ aa=False,
+ )
+ )
+ group.points[0].tasks.append(
+ ActivateICLSCommand(icls, unit_id=group.units[0].id)
+ )
- def add_runway_data(self, brc: int, atc: RadioFrequency,
- tacan: TacanChannel, callsign: str, icls: int) -> None:
+ def add_runway_data(
+ self,
+ brc: int,
+ atc: RadioFrequency,
+ tacan: TacanChannel,
+ callsign: str,
+ icls: int,
+ ) -> None:
# TODO: Make unit name usable.
# This relies on one control point mapping exactly
# to one LHA, carrier, or other usable "runway".
@@ -354,24 +397,25 @@ class CarrierGenerator(GenericCarrierGenerator):
def get_carrier_type(self, group: Group) -> UnitType:
unit_type = super().get_carrier_type(group)
if self.game.settings.supercarrier:
- unit_type = db.upgrade_to_supercarrier(unit_type,
- self.control_point.name)
+ unit_type = db.upgrade_to_supercarrier(unit_type, self.control_point.name)
return unit_type
def tacan_callsign(self) -> str:
# TODO: Assign these properly.
- return random.choice([
- "STE",
- "CVN",
- "CVH",
- "CCV",
- "ACC",
- "ARC",
- "GER",
- "ABR",
- "LIN",
- "TRU",
- ])
+ return random.choice(
+ [
+ "STE",
+ "CVN",
+ "CVH",
+ "CCV",
+ "ACC",
+ "ARC",
+ "GER",
+ "ABR",
+ "LIN",
+ "TRU",
+ ]
+ )
class LhaGenerator(GenericCarrierGenerator):
@@ -379,14 +423,16 @@ class LhaGenerator(GenericCarrierGenerator):
def tacan_callsign(self) -> str:
# TODO: Assign these properly.
- return random.choice([
- "LHD",
- "LHA",
- "LHB",
- "LHC",
- "LHD",
- "LDS",
- ])
+ return random.choice(
+ [
+ "LHD",
+ "LHA",
+ "LHB",
+ "LHC",
+ "LHD",
+ "LDS",
+ ]
+ )
class ShipObjectGenerator(GenericGroundObjectGenerator):
@@ -403,22 +449,23 @@ class ShipObjectGenerator(GenericGroundObjectGenerator):
unit_type = unit_type_from_name(group.units[0].type)
if unit_type is None:
- raise RuntimeError(
- f"Unrecognized unit type: {group.units[0].type}")
+ raise RuntimeError(f"Unrecognized unit type: {group.units[0].type}")
self.generate_group(group, unit_type)
- def generate_group(self, group_def: Group,
- first_unit_type: Type[UnitType]) -> None:
- group = self.m.ship_group(self.country, group_def.name, first_unit_type,
- position=group_def.position,
- heading=group_def.units[0].heading)
+ def generate_group(self, group_def: Group, first_unit_type: Type[UnitType]) -> None:
+ group = self.m.ship_group(
+ self.country,
+ group_def.name,
+ first_unit_type,
+ position=group_def.position,
+ heading=group_def.units[0].heading,
+ )
group.units[0].name = self.m.string(group_def.units[0].name)
# TODO: Skipping the first unit looks like copy pasta from the carrier.
for unit in group_def.units[1:]:
unit_type = unit_type_from_name(unit.type)
- ship = Ship(self.m.next_unit_id(),
- self.m.string(unit.name), unit_type)
+ ship = Ship(self.m.next_unit_id(), self.m.string(unit.name), unit_type)
ship.position.x = unit.position.x
ship.position.y = unit.position.y
ship.heading = unit.heading
@@ -436,9 +483,14 @@ class GroundObjectsGenerator:
the appropriate generators.
"""
- def __init__(self, mission: Mission, game: Game,
- radio_registry: RadioRegistry, tacan_registry: TacanRegistry,
- unit_map: UnitMap) -> None:
+ def __init__(
+ self,
+ mission: Mission,
+ game: Game,
+ radio_registry: RadioRegistry,
+ tacan_registry: TacanRegistry,
+ unit_map: UnitMap,
+ ) -> None:
self.m = mission
self.game = game
self.radio_registry = radio_registry
@@ -458,28 +510,44 @@ class GroundObjectsGenerator:
for ground_object in cp.ground_objects:
if isinstance(ground_object, BuildingGroundObject):
generator = BuildingSiteGenerator(
- ground_object, country, self.game, self.m,
- self.unit_map)
+ ground_object, country, self.game, self.m, self.unit_map
+ )
elif isinstance(ground_object, CarrierGroundObject):
generator = CarrierGenerator(
- ground_object, cp, country, self.game, self.m,
- self.radio_registry, self.tacan_registry,
- self.icls_alloc, self.runways, self.unit_map)
+ ground_object,
+ cp,
+ country,
+ self.game,
+ self.m,
+ self.radio_registry,
+ self.tacan_registry,
+ self.icls_alloc,
+ self.runways,
+ self.unit_map,
+ )
elif isinstance(ground_object, LhaGroundObject):
generator = CarrierGenerator(
- ground_object, cp, country, self.game, self.m,
- self.radio_registry, self.tacan_registry,
- self.icls_alloc, self.runways, self.unit_map)
+ ground_object,
+ cp,
+ country,
+ self.game,
+ self.m,
+ self.radio_registry,
+ self.tacan_registry,
+ self.icls_alloc,
+ self.runways,
+ self.unit_map,
+ )
elif isinstance(ground_object, ShipGroundObject):
generator = ShipObjectGenerator(
- ground_object, country, self.game, self.m,
- self.unit_map)
+ ground_object, country, self.game, self.m, self.unit_map
+ )
elif isinstance(ground_object, MissileSiteGroundObject):
generator = MissileSiteGenerator(
- ground_object, country, self.game, self.m,
- self.unit_map)
+ ground_object, country, self.game, self.m, self.unit_map
+ )
else:
generator = GenericGroundObjectGenerator(
- ground_object, country, self.game, self.m,
- self.unit_map)
+ ground_object, country, self.game, self.m, self.unit_map
+ )
generator.generate()
diff --git a/gen/kneeboard.py b/gen/kneeboard.py
index 97442c59..cfc8416e 100644
--- a/gen/kneeboard.py
+++ b/gen/kneeboard.py
@@ -49,7 +49,7 @@ class KneeboardPageWriter:
"""Creates kneeboard images."""
def __init__(self, page_margin: int = 24, line_spacing: int = 12) -> None:
- self.image = Image.new('RGB', (768, 1024), (0xff, 0xff, 0xff))
+ self.image = Image.new("RGB", (768, 1024), (0xFF, 0xFF, 0xFF))
# These font sizes create a relatively full page for current sorties. If
# we start generating more complicated flight plans, or start including
# more information in the comm ladder (the latter of which we should
@@ -58,8 +58,7 @@ class KneeboardPageWriter:
self.title_font = ImageFont.truetype("arial.ttf", 32)
self.heading_font = ImageFont.truetype("arial.ttf", 24)
self.content_font = ImageFont.truetype("arial.ttf", 20)
- self.table_font = ImageFont.truetype(
- "resources/fonts/Inconsolata.otf", 20)
+ self.table_font = ImageFont.truetype("resources/fonts/Inconsolata.otf", 20)
self.draw = ImageDraw.Draw(self.image)
self.x = page_margin
self.y = page_margin
@@ -69,8 +68,9 @@ class KneeboardPageWriter:
def position(self) -> Tuple[int, int]:
return self.x, self.y
- def text(self, text: str, font=None,
- fill: Tuple[int, int, int] = (0, 0, 0)) -> None:
+ def text(
+ self, text: str, font=None, fill: Tuple[int, int, int] = (0, 0, 0)
+ ) -> None:
if font is None:
font = self.content_font
@@ -84,8 +84,9 @@ class KneeboardPageWriter:
def heading(self, text: str) -> None:
self.text(text, font=self.heading_font)
- def table(self, cells: List[List[str]],
- headers: Optional[List[str]] = None) -> None:
+ def table(
+ self, cells: List[List[str]], headers: Optional[List[str]] = None
+ ) -> None:
if headers is None:
headers = []
table = tabulate(cells, headers=headers, numalign="right")
@@ -157,29 +158,34 @@ class FlightPlanBuilder:
first_waypoint_num = self.target_points[0].number
last_waypoint_num = self.target_points[-1].number
- self.rows.append([
- f"{first_waypoint_num}-{last_waypoint_num}",
- "Target points",
- "0",
- self._waypoint_distance(self.target_points[0].waypoint),
- self._ground_speed(self.target_points[0].waypoint),
- self._format_time(self.target_points[0].waypoint.tot),
- self._format_time(self.target_points[0].waypoint.departure_time),
- ])
+ self.rows.append(
+ [
+ f"{first_waypoint_num}-{last_waypoint_num}",
+ "Target points",
+ "0",
+ self._waypoint_distance(self.target_points[0].waypoint),
+ self._ground_speed(self.target_points[0].waypoint),
+ self._format_time(self.target_points[0].waypoint.tot),
+ self._format_time(self.target_points[0].waypoint.departure_time),
+ ]
+ )
self.last_waypoint = self.target_points[-1].waypoint
def add_waypoint_row(self, waypoint: NumberedWaypoint) -> None:
- self.rows.append([
- str(waypoint.number),
- KneeboardPageWriter.wrap_line(
- waypoint.waypoint.pretty_name,
- FlightPlanBuilder.WAYPOINT_DESC_MAX_LEN),
- str(int(waypoint.waypoint.alt.feet)),
- self._waypoint_distance(waypoint.waypoint),
- self._ground_speed(waypoint.waypoint),
- self._format_time(waypoint.waypoint.tot),
- self._format_time(waypoint.waypoint.departure_time),
- ])
+ self.rows.append(
+ [
+ str(waypoint.number),
+ KneeboardPageWriter.wrap_line(
+ waypoint.waypoint.pretty_name,
+ FlightPlanBuilder.WAYPOINT_DESC_MAX_LEN,
+ ),
+ str(int(waypoint.waypoint.alt.feet)),
+ self._waypoint_distance(waypoint.waypoint),
+ self._ground_speed(waypoint.waypoint),
+ self._format_time(waypoint.waypoint.tot),
+ self._format_time(waypoint.waypoint.departure_time),
+ ]
+ )
def _format_time(self, time: Optional[datetime.timedelta]) -> str:
if time is None:
@@ -191,9 +197,9 @@ class FlightPlanBuilder:
if self.last_waypoint is None:
return "-"
- distance = meters(self.last_waypoint.position.distance_to_point(
- waypoint.position
- ))
+ distance = meters(
+ self.last_waypoint.position.distance_to_point(waypoint.position)
+ )
return f"{distance.nautical_miles:.1f} NM"
def _ground_speed(self, waypoint: FlightWaypoint) -> str:
@@ -210,9 +216,9 @@ class FlightPlanBuilder:
else:
return "-"
- distance = meters(self.last_waypoint.position.distance_to_point(
- waypoint.position
- ))
+ distance = meters(
+ self.last_waypoint.position.distance_to_point(waypoint.position)
+ )
duration = (waypoint.tot - last_time).total_seconds() / 3600
return f"{int(distance.nautical_miles / duration)} kt"
@@ -222,9 +228,16 @@ class FlightPlanBuilder:
class BriefingPage(KneeboardPage):
"""A kneeboard page containing briefing information."""
- def __init__(self, flight: FlightData, comms: List[CommInfo],
- awacs: List[AwacsInfo], tankers: List[TankerInfo],
- jtacs: List[JtacInfo], start_time: datetime.datetime) -> None:
+
+ def __init__(
+ self,
+ flight: FlightData,
+ comms: List[CommInfo],
+ awacs: List[AwacsInfo],
+ tankers: List[TankerInfo],
+ jtacs: List[JtacInfo],
+ start_time: datetime.datetime,
+ ) -> None:
self.flight = flight
self.comms = list(comms)
self.awacs = awacs
@@ -239,49 +252,59 @@ class BriefingPage(KneeboardPage):
# TODO: Handle carriers.
writer.heading("Airfield Info")
- writer.table([
- self.airfield_info_row("Departure", self.flight.departure),
- self.airfield_info_row("Arrival", self.flight.arrival),
- self.airfield_info_row("Divert", self.flight.divert),
- ], headers=["", "Airbase", "ATC", "TCN", "I(C)LS", "RWY"])
+ writer.table(
+ [
+ self.airfield_info_row("Departure", self.flight.departure),
+ self.airfield_info_row("Arrival", self.flight.arrival),
+ self.airfield_info_row("Divert", self.flight.divert),
+ ],
+ headers=["", "Airbase", "ATC", "TCN", "I(C)LS", "RWY"],
+ )
writer.heading("Flight Plan")
flight_plan_builder = FlightPlanBuilder(self.start_time)
for num, waypoint in enumerate(self.flight.waypoints):
flight_plan_builder.add_waypoint(num, waypoint)
- writer.table(flight_plan_builder.build(), headers=[
- "#", "Action", "Alt", "Dist", "GSPD", "Time", "Departure"
- ])
+ writer.table(
+ flight_plan_builder.build(),
+ headers=["#", "Action", "Alt", "Dist", "GSPD", "Time", "Departure"],
+ )
flight_plan_builder
- writer.table([
- ["{}lbs".format(self.flight.bingo_fuel), "{}lbs".format(self.flight.joker_fuel)]
- ], ['Bingo', 'Joker'])
+ writer.table(
+ [
+ [
+ "{}lbs".format(self.flight.bingo_fuel),
+ "{}lbs".format(self.flight.joker_fuel),
+ ]
+ ],
+ ["Bingo", "Joker"],
+ )
# Package Section
writer.heading("Comm ladder")
comm_ladder = []
for comm in self.comms:
- comm_ladder.append([comm.name, '', '', '', self.format_frequency(comm.freq)])
+ comm_ladder.append(
+ [comm.name, "", "", "", self.format_frequency(comm.freq)]
+ )
for a in self.awacs:
- comm_ladder.append([
- a.callsign,
- 'AWACS',
- '',
- '',
- self.format_frequency(a.freq)
- ])
+ comm_ladder.append(
+ [a.callsign, "AWACS", "", "", self.format_frequency(a.freq)]
+ )
for tanker in self.tankers:
- comm_ladder.append([
- tanker.callsign,
- "Tanker",
- tanker.variant,
- str(tanker.tacan),
- self.format_frequency(tanker.freq),
- ])
-
- writer.table(comm_ladder, headers=["Callsign","Task", "Type", "TACAN", "FREQ"])
+ comm_ladder.append(
+ [
+ tanker.callsign,
+ "Tanker",
+ tanker.variant,
+ str(tanker.tacan),
+ self.format_frequency(tanker.freq),
+ ]
+ )
+
+ writer.table(comm_ladder, headers=["Callsign", "Task", "Type", "TACAN", "FREQ"])
writer.heading("JTAC")
jtacs = []
@@ -291,8 +314,9 @@ class BriefingPage(KneeboardPage):
writer.write(path)
- def airfield_info_row(self, row_title: str,
- runway: Optional[RunwayData]) -> List[str]:
+ def airfield_info_row(
+ self, row_title: str, runway: Optional[RunwayData]
+ ) -> List[str]:
"""Creates a table row for a given airfield.
Args:
@@ -372,7 +396,8 @@ class KneeboardGenerator(MissionInfoGenerator):
if not flight.client_units:
continue
all_flights[flight.aircraft_type].extend(
- self.generate_flight_kneeboard(flight))
+ self.generate_flight_kneeboard(flight)
+ )
return all_flights
def generate_flight_kneeboard(self, flight: FlightData) -> List[KneeboardPage]:
@@ -384,6 +409,6 @@ class KneeboardGenerator(MissionInfoGenerator):
self.awacs,
self.tankers,
self.jtacs,
- self.mission.start_time
+ self.mission.start_time,
),
]
diff --git a/gen/locations/preset_location_finder.py b/gen/locations/preset_location_finder.py
index 4df32466..94202294 100644
--- a/gen/locations/preset_location_finder.py
+++ b/gen/locations/preset_location_finder.py
@@ -9,9 +9,10 @@ from gen.locations.preset_locations import PresetLocation
class MizDataLocationFinder:
-
@staticmethod
- def compute_possible_locations(terrain_name: str, cp_name: str) -> PresetControlPointLocations:
+ def compute_possible_locations(
+ terrain_name: str, cp_name: str
+ ) -> PresetControlPointLocations:
"""
Extract the list of preset locations from miz data
:param terrain_name: Terrain/Map name
@@ -32,28 +33,54 @@ class MizDataLocationFinder:
for vehicle_group in m.country("USA").vehicle_group:
if len(vehicle_group.units) > 0:
- ashore_locations.append(PresetLocation(vehicle_group.position,
- vehicle_group.units[0].heading,
- vehicle_group.name))
+ ashore_locations.append(
+ PresetLocation(
+ vehicle_group.position,
+ vehicle_group.units[0].heading,
+ vehicle_group.name,
+ )
+ )
for ship_group in m.country("USA").ship_group:
- if len(ship_group.units) > 0 and ship_group.units[0].type == ships.Oliver_Hazzard_Perry_class.id:
- offshore_locations.append(PresetLocation(ship_group.position,
- ship_group.units[0].heading,
- ship_group.name))
+ if (
+ len(ship_group.units) > 0
+ and ship_group.units[0].type == ships.Oliver_Hazzard_Perry_class.id
+ ):
+ offshore_locations.append(
+ PresetLocation(
+ ship_group.position,
+ ship_group.units[0].heading,
+ ship_group.name,
+ )
+ )
for static_group in m.country("USA").static_group:
if len(static_group.units) > 0:
- powerplants_locations.append(PresetLocation(static_group.position,
- static_group.units[0].heading,
- static_group.name))
+ powerplants_locations.append(
+ PresetLocation(
+ static_group.position,
+ static_group.units[0].heading,
+ static_group.name,
+ )
+ )
if m.country("Iran") is not None:
for vehicle_group in m.country("Iran").vehicle_group:
- if len(vehicle_group.units) > 0 and vehicle_group.units[0].type == MissilesSS.SS_N_2_Silkworm.id:
- antiship_locations.append(PresetLocation(vehicle_group.position,
- vehicle_group.units[0].heading,
- vehicle_group.name))
+ if (
+ len(vehicle_group.units) > 0
+ and vehicle_group.units[0].type == MissilesSS.SS_N_2_Silkworm.id
+ ):
+ antiship_locations.append(
+ PresetLocation(
+ vehicle_group.position,
+ vehicle_group.units[0].heading,
+ vehicle_group.name,
+ )
+ )
- return PresetControlPointLocations(ashore_locations, offshore_locations,
- antiship_locations, powerplants_locations)
+ return PresetControlPointLocations(
+ ashore_locations,
+ offshore_locations,
+ antiship_locations,
+ powerplants_locations,
+ )
diff --git a/gen/locations/preset_locations.py b/gen/locations/preset_locations.py
index 2d8872c3..89bdffbc 100644
--- a/gen/locations/preset_locations.py
+++ b/gen/locations/preset_locations.py
@@ -6,10 +6,16 @@ from dcs import Point
@dataclass
class PresetLocation:
"""A preset location"""
+
position: Point
heading: int
id: str
def __str__(self):
- return "-" * 10 + "X: {}\n Y: {}\nHdg: {}°\nId: {}".format(self.position.x, self.position.y, self.heading,
- self.id) + "-" * 10
+ return (
+ "-" * 10
+ + "X: {}\n Y: {}\nHdg: {}°\nId: {}".format(
+ self.position.x, self.position.y, self.heading, self.id
+ )
+ + "-" * 10
+ )
diff --git a/gen/missiles/missiles_group_generator.py b/gen/missiles/missiles_group_generator.py
index 3b84037d..0ea877c1 100644
--- a/gen/missiles/missiles_group_generator.py
+++ b/gen/missiles/missiles_group_generator.py
@@ -4,10 +4,7 @@ from game import db
from gen.missiles.scud_site import ScudGenerator
from gen.missiles.v1_group import V1GroupGenerator
-MISSILES_MAP = {
- "V1GroupGenerator": V1GroupGenerator,
- "ScudGenerator": ScudGenerator
-}
+MISSILES_MAP = {"V1GroupGenerator": V1GroupGenerator, "ScudGenerator": ScudGenerator}
def generate_missile_group(game, ground_object, faction_name: str):
@@ -25,5 +22,9 @@ def generate_missile_group(game, ground_object, faction_name: str):
generator.generate()
return generator.get_generated_group()
else:
- logging.info("Unable to generate missile group, generator : " + str(gen) + "does not exists")
- return None
\ No newline at end of file
+ logging.info(
+ "Unable to generate missile group, generator : "
+ + str(gen)
+ + "does not exists"
+ )
+ return None
diff --git a/gen/missiles/scud_site.py b/gen/missiles/scud_site.py
index 6b050c84..eb548c19 100644
--- a/gen/missiles/scud_site.py
+++ b/gen/missiles/scud_site.py
@@ -6,7 +6,6 @@ from gen.sam.group_generator import GroupGenerator
class ScudGenerator(GroupGenerator):
-
def __init__(self, game, ground_object, faction):
super(ScudGenerator, self).__init__(game, ground_object)
self.faction = faction
@@ -14,17 +13,50 @@ class ScudGenerator(GroupGenerator):
def generate(self):
# Scuds
- self.add_unit(MissilesSS.SRBM_SS_1C_Scud_B_9K72_LN_9P117M, "V1#0", self.position.x, self.position.y + random.randint(1, 8), self.heading)
- self.add_unit(MissilesSS.SRBM_SS_1C_Scud_B_9K72_LN_9P117M, "V1#1", self.position.x + 50, self.position.y + random.randint(1, 8), self.heading)
- self.add_unit(MissilesSS.SRBM_SS_1C_Scud_B_9K72_LN_9P117M, "V1#2", self.position.x + 100, self.position.y + random.randint(1, 8), self.heading)
+ self.add_unit(
+ MissilesSS.SRBM_SS_1C_Scud_B_9K72_LN_9P117M,
+ "V1#0",
+ self.position.x,
+ self.position.y + random.randint(1, 8),
+ self.heading,
+ )
+ self.add_unit(
+ MissilesSS.SRBM_SS_1C_Scud_B_9K72_LN_9P117M,
+ "V1#1",
+ self.position.x + 50,
+ self.position.y + random.randint(1, 8),
+ self.heading,
+ )
+ self.add_unit(
+ MissilesSS.SRBM_SS_1C_Scud_B_9K72_LN_9P117M,
+ "V1#2",
+ self.position.x + 100,
+ self.position.y + random.randint(1, 8),
+ self.heading,
+ )
# Commander
- self.add_unit(Unarmed.Transport_UAZ_469, "Kubel#0", self.position.x - 35, self.position.y - 20,
- self.heading)
+ self.add_unit(
+ Unarmed.Transport_UAZ_469,
+ "Kubel#0",
+ self.position.x - 35,
+ self.position.y - 20,
+ self.heading,
+ )
# Shorad
- self.add_unit(AirDefence.SPAAA_ZSU_23_4_Shilka, "SHILKA#0", self.position.x - 55, self.position.y - 38,
- self.heading)
+ self.add_unit(
+ AirDefence.SPAAA_ZSU_23_4_Shilka,
+ "SHILKA#0",
+ self.position.x - 55,
+ self.position.y - 38,
+ self.heading,
+ )
- self.add_unit(AirDefence.SAM_SA_9_Strela_1_9P31, "STRELA#0",
- self.position.x + 200, self.position.y + 15, 90)
\ No newline at end of file
+ self.add_unit(
+ AirDefence.SAM_SA_9_Strela_1_9P31,
+ "STRELA#0",
+ self.position.x + 200,
+ self.position.y + 15,
+ 90,
+ )
diff --git a/gen/missiles/v1_group.py b/gen/missiles/v1_group.py
index a099da08..bf1511a6 100644
--- a/gen/missiles/v1_group.py
+++ b/gen/missiles/v1_group.py
@@ -6,7 +6,6 @@ from gen.sam.group_generator import GroupGenerator
class V1GroupGenerator(GroupGenerator):
-
def __init__(self, game, ground_object, faction):
super(V1GroupGenerator, self).__init__(game, ground_object)
self.faction = faction
@@ -14,19 +13,54 @@ class V1GroupGenerator(GroupGenerator):
def generate(self):
# Ramps
- self.add_unit(MissilesSS.V_1_ramp, "V1#0", self.position.x, self.position.y + random.randint(1, 8), self.heading)
- self.add_unit(MissilesSS.V_1_ramp, "V1#1", self.position.x + 50, self.position.y + random.randint(1, 8), self.heading)
- self.add_unit(MissilesSS.V_1_ramp, "V1#2", self.position.x + 100, self.position.y + random.randint(1, 8), self.heading)
+ self.add_unit(
+ MissilesSS.V_1_ramp,
+ "V1#0",
+ self.position.x,
+ self.position.y + random.randint(1, 8),
+ self.heading,
+ )
+ self.add_unit(
+ MissilesSS.V_1_ramp,
+ "V1#1",
+ self.position.x + 50,
+ self.position.y + random.randint(1, 8),
+ self.heading,
+ )
+ self.add_unit(
+ MissilesSS.V_1_ramp,
+ "V1#2",
+ self.position.x + 100,
+ self.position.y + random.randint(1, 8),
+ self.heading,
+ )
# Commander
- self.add_unit(Unarmed.Kübelwagen_82, "Kubel#0", self.position.x - 35, self.position.y - 20,
- self.heading)
+ self.add_unit(
+ Unarmed.Kübelwagen_82,
+ "Kubel#0",
+ self.position.x - 35,
+ self.position.y - 20,
+ self.heading,
+ )
# Self defense flak
- flak_unit = random.choice([AirDefence.AAA_Flak_Vierling_38, AirDefence.AAA_Flak_38])
+ flak_unit = random.choice(
+ [AirDefence.AAA_Flak_Vierling_38, AirDefence.AAA_Flak_38]
+ )
- self.add_unit(flak_unit, "FLAK#0", self.position.x - 55, self.position.y - 38,
- self.heading)
+ self.add_unit(
+ flak_unit,
+ "FLAK#0",
+ self.position.x - 55,
+ self.position.y - 38,
+ self.heading,
+ )
- self.add_unit(Unarmed.Blitz_3_6_6700A, "Blitz#0",
- self.position.x + 200, self.position.y + 15, 90)
\ No newline at end of file
+ self.add_unit(
+ Unarmed.Blitz_3_6_6700A,
+ "Blitz#0",
+ self.position.x + 200,
+ self.position.y + 15,
+ 90,
+ )
diff --git a/gen/naming.py b/gen/naming.py
index 3e59bbc7..0f65d024 100644
--- a/gen/naming.py
+++ b/gen/naming.py
@@ -9,39 +9,242 @@ from game import db
from gen.flights.flight import Flight
-ALPHA_MILITARY = ["Alpha", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot",
- "Golf", "Hotel", "India", "Juliet", "Kilo", "Lima", "Mike",
- "November", "Oscar", "Papa", "Quebec", "Romeo", "Sierra",
- "Tango", "Uniform", "Victor", "Whisky", "XRay", "Yankee",
- "Zulu", "Zero"]
+ALPHA_MILITARY = [
+ "Alpha",
+ "Bravo",
+ "Charlie",
+ "Delta",
+ "Echo",
+ "Foxtrot",
+ "Golf",
+ "Hotel",
+ "India",
+ "Juliet",
+ "Kilo",
+ "Lima",
+ "Mike",
+ "November",
+ "Oscar",
+ "Papa",
+ "Quebec",
+ "Romeo",
+ "Sierra",
+ "Tango",
+ "Uniform",
+ "Victor",
+ "Whisky",
+ "XRay",
+ "Yankee",
+ "Zulu",
+ "Zero",
+]
ANIMALS = [
- "SHARK", "TORTOISE", "BAT", "PANGOLIN", "AARDWOLF",
- "MONKEY", "BUFFALO", "DOG", "BOBCAT", "LYNX", "PANTHER", "TIGER",
- "LION", "OWL", "BUTTERFLY", "BISON", "DUCK", "COBRA", "MAMBA",
- "DOLPHIN", "PHEASANT", "ARMADILLLO", "RACOON", "ZEBRA", "COW", "COYOTE", "FOX",
- "LIGHTFOOT", "COTTONMOUTH", "TAURUS", "VIPER", "CASTOR", "GIRAFFE", "SNAKE",
- "MONSTER", "ALBATROSS", "HAWK", "DOVE", "MOCKINGBIRD", "GECKO", "ORYX", "GORILLA",
- "HARAMBE", "GOOSE", "MAVERICK", "HARE", "JACKAL", "LEOPARD", "CAT", "MUSK", "ORCA",
- "OCELOT", "BEAR", "PANDA", "GULL", "PENGUIN", "PYTHON", "RAVEN", "DEER", "MOOSE",
- "REINDEER", "SHEEP", "GAZELLE", "INSECT", "VULTURE", "WALLABY", "KANGAROO", "KOALA",
- "KIWI", "WHALE", "FISH", "RHINO", "HIPPO", "RAT", "WOODPECKER", "WORM", "BABOON",
- "YAK", "SCORPIO", "HORSE", "POODLE", "CENTIPEDE", "CHICKEN", "CHEETAH", "CHAMELEON",
- "CATFISH", "CATERPILLAR", "CARACAL", "CAMEL", "CAIMAN", "BARRACUDA", "BANDICOOT",
- "ALLIGATOR", "BONGO", "CORAL", "ELEPHANT", "ANTELOPE", "CRAB", "DACHSHUND", "DODO",
- "FLAMINGO", "FERRET", "FALCON", "BULLDOG", "DONKEY", "IGUANA", "TAMARIN", "HARRIER",
- "GRIZZLY", "GREYHOUND", "GRASSHOPPER", "JAGUAR", "LADYBUG", "KOMODO", "DRAGON", "LIZARD",
- "LLAMA", "LOBSTER", "OCTOPUS", "MANATEE", "MAGPIE", "MACAW", "OSTRICH", "OYSTER",
- "MOLE", "MULE", "MOTH", "MONGOOSE", "MOLLY", "MEERKAT", "MOUSE", "PEACOCK", "PIKE", "ROBIN",
- "RAGDOLL", "PLATYPUS", "PELICAN", "PARROT", "PORCUPINE", "PIRANHA", "PUMA", "PUG", "TAPIR",
- "TERMITE", "URCHIN", "SHRIMP", "TURKEY", "TOUCAN", "TETRA", "HUSKY", "STARFISH", "SWAN",
- "FROG", "SQUIRREL", "WALRUS", "WARTHOG", "CORGI", "WEASEL", "WOMBAT", "WOLVERINE", "MAMMOTH",
- "TOAD", "WOLF", "ZEBU", "SEAL", "SKATE", "JELLYFISH", "MOSQUITO", "LOCUST", "SLUG", "SNAIL",
- "HEDGEHOG", "PIGLET", "FENNEC", "BADGER", "ALPACA", "DINGO", "COLT", "SKUNK", "BUNNY", "IMPALA",
- "GUANACO", "CAPYBARA", "ELK", "MINK", "PRONGHORN", "CROW", "BUMBLEBEE", "FAWN", "OTTER", "WATERBUCK",
- "JERBOA", "KITTEN", "ARGALI", "OX", "MARE", "FINCH", "BASILISK", "GOPHER", "HAMSTER", "CANARY", "WOODCHUCK",
- "ANACONDA"
- ]
+ "SHARK",
+ "TORTOISE",
+ "BAT",
+ "PANGOLIN",
+ "AARDWOLF",
+ "MONKEY",
+ "BUFFALO",
+ "DOG",
+ "BOBCAT",
+ "LYNX",
+ "PANTHER",
+ "TIGER",
+ "LION",
+ "OWL",
+ "BUTTERFLY",
+ "BISON",
+ "DUCK",
+ "COBRA",
+ "MAMBA",
+ "DOLPHIN",
+ "PHEASANT",
+ "ARMADILLLO",
+ "RACOON",
+ "ZEBRA",
+ "COW",
+ "COYOTE",
+ "FOX",
+ "LIGHTFOOT",
+ "COTTONMOUTH",
+ "TAURUS",
+ "VIPER",
+ "CASTOR",
+ "GIRAFFE",
+ "SNAKE",
+ "MONSTER",
+ "ALBATROSS",
+ "HAWK",
+ "DOVE",
+ "MOCKINGBIRD",
+ "GECKO",
+ "ORYX",
+ "GORILLA",
+ "HARAMBE",
+ "GOOSE",
+ "MAVERICK",
+ "HARE",
+ "JACKAL",
+ "LEOPARD",
+ "CAT",
+ "MUSK",
+ "ORCA",
+ "OCELOT",
+ "BEAR",
+ "PANDA",
+ "GULL",
+ "PENGUIN",
+ "PYTHON",
+ "RAVEN",
+ "DEER",
+ "MOOSE",
+ "REINDEER",
+ "SHEEP",
+ "GAZELLE",
+ "INSECT",
+ "VULTURE",
+ "WALLABY",
+ "KANGAROO",
+ "KOALA",
+ "KIWI",
+ "WHALE",
+ "FISH",
+ "RHINO",
+ "HIPPO",
+ "RAT",
+ "WOODPECKER",
+ "WORM",
+ "BABOON",
+ "YAK",
+ "SCORPIO",
+ "HORSE",
+ "POODLE",
+ "CENTIPEDE",
+ "CHICKEN",
+ "CHEETAH",
+ "CHAMELEON",
+ "CATFISH",
+ "CATERPILLAR",
+ "CARACAL",
+ "CAMEL",
+ "CAIMAN",
+ "BARRACUDA",
+ "BANDICOOT",
+ "ALLIGATOR",
+ "BONGO",
+ "CORAL",
+ "ELEPHANT",
+ "ANTELOPE",
+ "CRAB",
+ "DACHSHUND",
+ "DODO",
+ "FLAMINGO",
+ "FERRET",
+ "FALCON",
+ "BULLDOG",
+ "DONKEY",
+ "IGUANA",
+ "TAMARIN",
+ "HARRIER",
+ "GRIZZLY",
+ "GREYHOUND",
+ "GRASSHOPPER",
+ "JAGUAR",
+ "LADYBUG",
+ "KOMODO",
+ "DRAGON",
+ "LIZARD",
+ "LLAMA",
+ "LOBSTER",
+ "OCTOPUS",
+ "MANATEE",
+ "MAGPIE",
+ "MACAW",
+ "OSTRICH",
+ "OYSTER",
+ "MOLE",
+ "MULE",
+ "MOTH",
+ "MONGOOSE",
+ "MOLLY",
+ "MEERKAT",
+ "MOUSE",
+ "PEACOCK",
+ "PIKE",
+ "ROBIN",
+ "RAGDOLL",
+ "PLATYPUS",
+ "PELICAN",
+ "PARROT",
+ "PORCUPINE",
+ "PIRANHA",
+ "PUMA",
+ "PUG",
+ "TAPIR",
+ "TERMITE",
+ "URCHIN",
+ "SHRIMP",
+ "TURKEY",
+ "TOUCAN",
+ "TETRA",
+ "HUSKY",
+ "STARFISH",
+ "SWAN",
+ "FROG",
+ "SQUIRREL",
+ "WALRUS",
+ "WARTHOG",
+ "CORGI",
+ "WEASEL",
+ "WOMBAT",
+ "WOLVERINE",
+ "MAMMOTH",
+ "TOAD",
+ "WOLF",
+ "ZEBU",
+ "SEAL",
+ "SKATE",
+ "JELLYFISH",
+ "MOSQUITO",
+ "LOCUST",
+ "SLUG",
+ "SNAIL",
+ "HEDGEHOG",
+ "PIGLET",
+ "FENNEC",
+ "BADGER",
+ "ALPACA",
+ "DINGO",
+ "COLT",
+ "SKUNK",
+ "BUNNY",
+ "IMPALA",
+ "GUANACO",
+ "CAPYBARA",
+ "ELK",
+ "MINK",
+ "PRONGHORN",
+ "CROW",
+ "BUMBLEBEE",
+ "FAWN",
+ "OTTER",
+ "WATERBUCK",
+ "JERBOA",
+ "KITTEN",
+ "ARGALI",
+ "OX",
+ "MARE",
+ "FINCH",
+ "BASILISK",
+ "GOPHER",
+ "HAMSTER",
+ "CANARY",
+ "WOODCHUCK",
+ "ANACONDA",
+]
+
class NameGenerator:
number = 0
@@ -72,21 +275,36 @@ class NameGenerator:
name_str = flight.custom_name
else:
name_str = "{} {}".format(
- flight.package.target.name, flight.flight_type)
+ flight.package.target.name, flight.flight_type
+ )
except AttributeError: # Here to maintain save compatibility with 2.3
- name_str = "{} {}".format(
- flight.package.target.name, flight.flight_type)
- return "{}|{}|{}|{}|{}|".format(name_str, country.id, cls.aircraft_number, parent_base_id, db.unit_type_name(flight.unit_type))
+ name_str = "{} {}".format(flight.package.target.name, flight.flight_type)
+ return "{}|{}|{}|{}|{}|".format(
+ name_str,
+ country.id,
+ cls.aircraft_number,
+ parent_base_id,
+ db.unit_type_name(flight.unit_type),
+ )
@classmethod
def next_unit_name(cls, country: Country, parent_base_id: int, unit_type: UnitType):
cls.number += 1
- return "unit|{}|{}|{}|{}|".format(country.id, cls.number, parent_base_id, db.unit_type_name(unit_type))
+ return "unit|{}|{}|{}|{}|".format(
+ country.id, cls.number, parent_base_id, db.unit_type_name(unit_type)
+ )
@classmethod
- def next_infantry_name(cls, country: Country, parent_base_id: int, unit_type: UnitType):
+ def next_infantry_name(
+ cls, country: Country, parent_base_id: int, unit_type: UnitType
+ ):
cls.infantry_number += 1
- return "infantry|{}|{}|{}|{}|".format(country.id, cls.infantry_number, parent_base_id, db.unit_type_name(unit_type))
+ return "infantry|{}|{}|{}|{}|".format(
+ country.id,
+ cls.infantry_number,
+ parent_base_id,
+ db.unit_type_name(unit_type),
+ )
@staticmethod
def next_basedefense_name():
@@ -100,7 +318,9 @@ class NameGenerator:
@classmethod
def next_tanker_name(cls, country: Country, unit_type: UnitType):
cls.number += 1
- return "tanker|{}|{}|0|{}".format(country.id, cls.number, db.unit_type_name(unit_type))
+ return "tanker|{}|{}|0|{}".format(
+ country.id, cls.number, db.unit_type_name(unit_type)
+ )
@classmethod
def next_carrier_name(cls, country: Country):
@@ -112,7 +332,11 @@ class NameGenerator:
if len(cls.ANIMALS) == 0:
for i in range(10):
new_name_generated = True
- alpha_mil_name = random.choice(ALPHA_MILITARY).upper() + "#" + str(random.randint(0, 100))
+ alpha_mil_name = (
+ random.choice(ALPHA_MILITARY).upper()
+ + "#"
+ + str(random.randint(0, 100))
+ )
for existing_name in cls.existing_alphas:
if existing_name == alpha_mil_name:
new_name_generated = False
diff --git a/gen/radios.py b/gen/radios.py
index e6d413cc..ae72922b 100644
--- a/gen/radios.py
+++ b/gen/radios.py
@@ -68,9 +68,10 @@ class Radio:
def range(self) -> Iterator[RadioFrequency]:
"""Returns an iterator over the usable frequencies of this radio."""
- return (RadioFrequency(x) for x in range(
- self.minimum.hertz, self.maximum.hertz, self.step.hertz
- ))
+ return (
+ RadioFrequency(x)
+ for x in range(self.minimum.hertz, self.maximum.hertz, self.step.hertz)
+ )
@property
def last_channel(self) -> RadioFrequency:
@@ -99,14 +100,12 @@ RADIOS: List[Radio] = [
Radio("SCR-522", MHz(100), MHz(156), step=MHz(1)),
Radio("A.R.I. 1063", MHz(100), MHz(156), step=MHz(1)),
Radio("BC-1206", kHz(200), kHz(400), step=kHz(10)),
-
# Note: The M2000C V/UHF can operate in both ranges, but has a gap between
# 150 MHz and 225 MHz. We can't allocate in that gap, and the current
# system doesn't model gaps, so just pretend it ends at 150 MHz for now. We
# can model gaps later if needed.
Radio("TRT ERA 7000 V/UHF", MHz(118), MHz(150), step=MHz(1)),
Radio("TRT ERA 7200 UHF", MHz(225), MHz(400), step=MHz(1)),
-
# Tomcat radios
# # https://www.heatblur.se/F-14Manual/general.html#an-arc-159-uhf-1-radio
Radio("AN/ARC-159", MHz(225), MHz(400), step=MHz(1)),
@@ -114,31 +113,23 @@ RADIOS: List[Radio] = [
# to 400 MHz range, but we can't model gaps with the current implementation.
# https://www.heatblur.se/F-14Manual/general.html#an-arc-182-v-uhf-2-radio
Radio("AN/ARC-182", MHz(108), MHz(174), step=MHz(1)),
-
# Also capable of [103, 156) at 25 kHz intervals, but we can't do gaps.
Radio("FR 22", MHz(225), MHz(400), step=kHz(50)),
-
# P-51 / P-47 Radio
# 4 preset channels (A/B/C/D)
Radio("SCR522", MHz(100), MHz(156), step=kHz(25)),
-
Radio("R&S M3AR VHF", MHz(120), MHz(174), step=MHz(1)),
Radio("R&S M3AR UHF", MHz(225), MHz(400), step=MHz(1)),
-
# MiG-15bis
Radio("RSI-6K HF", MHz(3, 750), MHz(5), step=kHz(25)),
-
# MiG-19P
Radio("RSIU-4V", MHz(100), MHz(150), step=MHz(1)),
-
# MiG-21bis
Radio("RSIU-5V", MHz(118), MHz(140), step=MHz(1)),
-
# Ka-50
# Note: Also capable of 100MHz-150MHz, but we can't model gaps.
Radio("R-800L1", MHz(220), MHz(400), step=kHz(25)),
Radio("R-828", MHz(20), MHz(60), step=kHz(25)),
-
# UH-1H
Radio("AN/ARC-51BX", MHz(225), MHz(400), step=kHz(50)),
Radio("AN/ARC-131", MHz(30), MHz(76), step=kHz(50)),
@@ -218,7 +209,8 @@ class RadioRegistry:
# https://github.com/Khopa/dcs_liberation/issues/598
channel = radio.last_channel
logging.warning(
- f"No more free channels for {radio.name}. Reusing {channel}.")
+ f"No more free channels for {radio.name}. Reusing {channel}."
+ )
return channel
def alloc_uhf(self) -> RadioFrequency:
diff --git a/gen/runways.py b/gen/runways.py
index ab150720..dfb0cebe 100644
--- a/gen/runways.py
+++ b/gen/runways.py
@@ -25,8 +25,9 @@ class RunwayData:
icls: Optional[int] = None
@classmethod
- def for_airfield(cls, airport: Airport, runway_heading: int,
- runway_name: str) -> RunwayData:
+ def for_airfield(
+ cls, airport: Airport, runway_heading: int, runway_name: str
+ ) -> RunwayData:
"""Creates RunwayData for the given runway of an airfield.
Args:
@@ -56,7 +57,7 @@ class RunwayData:
atc=atc,
tacan=tacan,
tacan_callsign=tacan_callsign,
- ils=ils
+ ils=ils,
)
@classmethod
diff --git a/gen/sam/aaa_bofors.py b/gen/sam/aaa_bofors.py
index 1d7d18c4..919ec249 100644
--- a/gen/sam/aaa_bofors.py
+++ b/gen/sam/aaa_bofors.py
@@ -20,15 +20,19 @@ class BoforsGenerator(AirDefenseGroupGenerator):
grid_x = random.randint(2, 3)
grid_y = random.randint(2, 3)
- spacing = random.randint(10,40)
+ spacing = random.randint(10, 40)
index = 0
for i in range(grid_x):
for j in range(grid_y):
- index = index+1
- self.add_unit(AirDefence.AAA_Bofors_40mm, "AAA#" + str(index),
- self.position.x + spacing*i,
- self.position.y + spacing*j, self.heading)
+ index = index + 1
+ self.add_unit(
+ AirDefence.AAA_Bofors_40mm,
+ "AAA#" + str(index),
+ self.position.x + spacing * i,
+ self.position.y + spacing * j,
+ self.heading,
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/aaa_flak.py b/gen/sam/aaa_flak.py
index a6acc45a..d3386700 100644
--- a/gen/sam/aaa_flak.py
+++ b/gen/sam/aaa_flak.py
@@ -37,34 +37,64 @@ class FlakGenerator(AirDefenseGroupGenerator):
for i in range(grid_x):
for j in range(grid_y):
- index = index+1
- self.add_unit(unit_type, "AAA#" + str(index),
- self.position.x + spacing*i + random.randint(1,5),
- self.position.y + spacing*j + random.randint(1,5), self.heading)
+ index = index + 1
+ self.add_unit(
+ unit_type,
+ "AAA#" + str(index),
+ self.position.x + spacing * i + random.randint(1, 5),
+ self.position.y + spacing * j + random.randint(1, 5),
+ self.heading,
+ )
- if(mixed):
+ if mixed:
unit_type = random.choice(GFLAK)
# Search lights
- search_pos = self.get_circular_position(random.randint(2,3), 80)
+ search_pos = self.get_circular_position(random.randint(2, 3), 80)
for index, pos in enumerate(search_pos):
- self.add_unit(AirDefence.Flak_Searchlight_37, "SearchLight#" + str(index), pos[0], pos[1], self.heading)
+ self.add_unit(
+ AirDefence.Flak_Searchlight_37,
+ "SearchLight#" + str(index),
+ pos[0],
+ pos[1],
+ self.heading,
+ )
# Support
- self.add_unit(AirDefence.Maschinensatz_33, "MC33#", self.position.x-20, self.position.y-20, self.heading)
- self.add_unit(AirDefence.AAA_Kdo_G_40, "KDO#", self.position.x - 25, self.position.y - 20,
- self.heading)
+ self.add_unit(
+ AirDefence.Maschinensatz_33,
+ "MC33#",
+ self.position.x - 20,
+ self.position.y - 20,
+ self.heading,
+ )
+ self.add_unit(
+ AirDefence.AAA_Kdo_G_40,
+ "KDO#",
+ self.position.x - 25,
+ self.position.y - 20,
+ self.heading,
+ )
# Commander
- self.add_unit(Unarmed.Kübelwagen_82, "Kubel#", self.position.x - 35, self.position.y - 20,
- self.heading)
+ self.add_unit(
+ Unarmed.Kübelwagen_82,
+ "Kubel#",
+ self.position.x - 35,
+ self.position.y - 20,
+ self.heading,
+ )
# Some Opel Blitz trucks
- for i in range(int(max(1,grid_x/2))):
- for j in range(int(max(1,grid_x/2))):
- self.add_unit(Unarmed.Blitz_3_6_6700A, "BLITZ#" + str(index),
- self.position.x + 125 + 15*i + random.randint(1,5),
- self.position.y + 15*j + random.randint(1,5), 75)
+ for i in range(int(max(1, grid_x / 2))):
+ for j in range(int(max(1, grid_x / 2))):
+ self.add_unit(
+ Unarmed.Blitz_3_6_6700A,
+ "BLITZ#" + str(index),
+ self.position.x + 125 + 15 * i + random.randint(1, 5),
+ self.position.y + 15 * j + random.randint(1, 5),
+ 75,
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/aaa_flak18.py b/gen/sam/aaa_flak18.py
index 0716f05a..8dfda229 100644
--- a/gen/sam/aaa_flak18.py
+++ b/gen/sam/aaa_flak18.py
@@ -24,12 +24,22 @@ class Flak18Generator(AirDefenseGroupGenerator):
for i in range(3):
for j in range(2):
index = index + 1
- self.add_unit(AirDefence.AAA_8_8cm_Flak_18, "AAA#" + str(index),
- self.position.x + spacing * i + random.randint(1, 5),
- self.position.y + spacing * j + random.randint(1, 5), self.heading)
+ self.add_unit(
+ AirDefence.AAA_8_8cm_Flak_18,
+ "AAA#" + str(index),
+ self.position.x + spacing * i + random.randint(1, 5),
+ self.position.y + spacing * j + random.randint(1, 5),
+ self.heading,
+ )
# Add a commander truck
- self.add_unit(Unarmed.Blitz_3_6_6700A, "Blitz#", self.position.x - 35, self.position.y - 20, self.heading)
+ self.add_unit(
+ Unarmed.Blitz_3_6_6700A,
+ "Blitz#",
+ self.position.x - 35,
+ self.position.y - 20,
+ self.heading,
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/aaa_ks19.py b/gen/sam/aaa_ks19.py
index c0eb50ab..c733b468 100644
--- a/gen/sam/aaa_ks19.py
+++ b/gen/sam/aaa_ks19.py
@@ -19,15 +19,25 @@ class KS19Generator(AirDefenseGroupGenerator):
spacing = random.randint(10, 40)
- self.add_unit(highdigitsams.AAA_SON_9_Fire_Can, "TR", self.position.x - 20, self.position.y - 20, self.heading)
+ self.add_unit(
+ highdigitsams.AAA_SON_9_Fire_Can,
+ "TR",
+ self.position.x - 20,
+ self.position.y - 20,
+ self.heading,
+ )
index = 0
for i in range(3):
for j in range(3):
index = index + 1
- self.add_unit(highdigitsams.AAA_100mm_KS_19, "AAA#" + str(index),
- self.position.x + spacing * i,
- self.position.y + spacing * j, self.heading)
+ self.add_unit(
+ highdigitsams.AAA_100mm_KS_19,
+ "AAA#" + str(index),
+ self.position.x + spacing * i,
+ self.position.y + spacing * j,
+ self.heading,
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/aaa_ww2_ally_flak.py b/gen/sam/aaa_ww2_ally_flak.py
index 6c2fed26..1d1d06f4 100644
--- a/gen/sam/aaa_ww2_ally_flak.py
+++ b/gen/sam/aaa_ww2_ally_flak.py
@@ -20,21 +20,63 @@ class AllyWW2FlakGenerator(AirDefenseGroupGenerator):
positions = self.get_circular_position(4, launcher_distance=30, coverage=360)
for i, position in enumerate(positions):
- self.add_unit(AirDefence.AA_gun_QF_3_7, "AA#" + str(i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.AA_gun_QF_3_7,
+ "AA#" + str(i),
+ position[0],
+ position[1],
+ position[2],
+ )
positions = self.get_circular_position(8, launcher_distance=60, coverage=360)
for i, position in enumerate(positions):
- self.add_unit(AirDefence.AAA_M1_37mm, "AA#" + str(4 + i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.AAA_M1_37mm,
+ "AA#" + str(4 + i),
+ position[0],
+ position[1],
+ position[2],
+ )
positions = self.get_circular_position(8, launcher_distance=90, coverage=360)
for i, position in enumerate(positions):
- self.add_unit(AirDefence.AAA_M45_Quadmount, "AA#" + str(12 + i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.AAA_M45_Quadmount,
+ "AA#" + str(12 + i),
+ position[0],
+ position[1],
+ position[2],
+ )
# Add a commander truck
- self.add_unit(Unarmed.Willys_MB, "CMD#1", self.position.x, self.position.y - 20, random.randint(0, 360))
- self.add_unit(Armor.M30_Cargo_Carrier, "LOG#1", self.position.x, self.position.y + 20, random.randint(0, 360))
- self.add_unit(Armor.M4_Tractor, "LOG#2", self.position.x + 20, self.position.y, random.randint(0, 360))
- self.add_unit(Unarmed.Bedford_MWD, "LOG#3", self.position.x - 20, self.position.y, random.randint(0, 360))
+ self.add_unit(
+ Unarmed.Willys_MB,
+ "CMD#1",
+ self.position.x,
+ self.position.y - 20,
+ random.randint(0, 360),
+ )
+ self.add_unit(
+ Armor.M30_Cargo_Carrier,
+ "LOG#1",
+ self.position.x,
+ self.position.y + 20,
+ random.randint(0, 360),
+ )
+ self.add_unit(
+ Armor.M4_Tractor,
+ "LOG#2",
+ self.position.x + 20,
+ self.position.y,
+ random.randint(0, 360),
+ )
+ self.add_unit(
+ Unarmed.Bedford_MWD,
+ "LOG#3",
+ self.position.x - 20,
+ self.position.y,
+ random.randint(0, 360),
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/aaa_zsu57.py b/gen/sam/aaa_zsu57.py
index 45847018..3c877ee0 100644
--- a/gen/sam/aaa_zsu57.py
+++ b/gen/sam/aaa_zsu57.py
@@ -16,9 +16,17 @@ class ZSU57Generator(AirDefenseGroupGenerator):
def generate(self):
num_launchers = 5
- positions = self.get_circular_position(num_launchers, launcher_distance=110, coverage=360)
+ positions = self.get_circular_position(
+ num_launchers, launcher_distance=110, coverage=360
+ )
for i, position in enumerate(positions):
- self.add_unit(AirDefence.AAA_ZSU_57_2, "SPAA#" + str(i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.AAA_ZSU_57_2,
+ "SPAA#" + str(i),
+ position[0],
+ position[1],
+ position[2],
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/aaa_zu23_insurgent.py b/gen/sam/aaa_zu23_insurgent.py
index 85d65290..78ac4218 100644
--- a/gen/sam/aaa_zu23_insurgent.py
+++ b/gen/sam/aaa_zu23_insurgent.py
@@ -20,15 +20,19 @@ class ZU23InsurgentGenerator(AirDefenseGroupGenerator):
grid_x = random.randint(2, 3)
grid_y = random.randint(2, 3)
- spacing = random.randint(10,40)
+ spacing = random.randint(10, 40)
index = 0
for i in range(grid_x):
for j in range(grid_y):
- index = index+1
- self.add_unit(AirDefence.AAA_ZU_23_Insurgent_Closed, "AAA#" + str(index),
- self.position.x + spacing*i,
- self.position.y + spacing*j, self.heading)
+ index = index + 1
+ self.add_unit(
+ AirDefence.AAA_ZU_23_Insurgent_Closed,
+ "AAA#" + str(index),
+ self.position.x + spacing * i,
+ self.position.y + spacing * j,
+ self.heading,
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/airdefensegroupgenerator.py b/gen/sam/airdefensegroupgenerator.py
index 20096046..39d61e8f 100644
--- a/gen/sam/airdefensegroupgenerator.py
+++ b/gen/sam/airdefensegroupgenerator.py
@@ -28,8 +28,9 @@ class AirDefenseGroupGenerator(GroupGenerator, ABC):
self.auxiliary_groups: List[VehicleGroup] = []
def add_auxiliary_group(self, name_suffix: str) -> VehicleGroup:
- group = VehicleGroup(self.game.next_group_id(),
- "|".join([self.go.group_name, name_suffix]))
+ group = VehicleGroup(
+ self.game.next_group_id(), "|".join([self.go.group_name, name_suffix])
+ )
self.auxiliary_groups.append(group)
return group
@@ -37,7 +38,8 @@ class AirDefenseGroupGenerator(GroupGenerator, ABC):
raise RuntimeError(
"Deprecated call to AirDefenseGroupGenerator.get_generated_group "
"misses auxiliary groups. Use AirDefenseGroupGenerator.groups "
- "instead.")
+ "instead."
+ )
@property
def groups(self) -> Iterator[VehicleGroup]:
diff --git a/gen/sam/cold_war_flak.py b/gen/sam/cold_war_flak.py
index ce1b71d9..81a184f7 100644
--- a/gen/sam/cold_war_flak.py
+++ b/gen/sam/cold_war_flak.py
@@ -29,18 +29,38 @@ class EarlyColdWarFlakGenerator(AirDefenseGroupGenerator):
for i in range(3):
for j in range(2):
index = index + 1
- self.add_unit(AirDefence.AAA_8_8cm_Flak_18, "AAA#" + str(index),
- self.position.x + spacing * i + random.randint(1, 5),
- self.position.y + spacing * j + random.randint(1, 5), self.heading)
+ self.add_unit(
+ AirDefence.AAA_8_8cm_Flak_18,
+ "AAA#" + str(index),
+ self.position.x + spacing * i + random.randint(1, 5),
+ self.position.y + spacing * j + random.randint(1, 5),
+ self.heading,
+ )
# Short range guns
- self.add_unit(AirDefence.AAA_Bofors_40mm, "SHO#1",
- self.position.x - 40, self.position.y - 40, self.heading + 180),
- self.add_unit(AirDefence.AAA_Bofors_40mm, "SHO#2",
- self.position.x + spacing * 2 + 40, self.position.y + spacing + 40, self.heading),
+ self.add_unit(
+ AirDefence.AAA_Bofors_40mm,
+ "SHO#1",
+ self.position.x - 40,
+ self.position.y - 40,
+ self.heading + 180,
+ ),
+ self.add_unit(
+ AirDefence.AAA_Bofors_40mm,
+ "SHO#2",
+ self.position.x + spacing * 2 + 40,
+ self.position.y + spacing + 40,
+ self.heading,
+ ),
# Add a truck
- self.add_unit(Unarmed.Transport_KAMAZ_43101, "Truck#", self.position.x - 60, self.position.y - 20, self.heading)
+ self.add_unit(
+ Unarmed.Transport_KAMAZ_43101,
+ "Truck#",
+ self.position.x - 60,
+ self.position.y - 20,
+ self.heading,
+ )
@classmethod
def range(cls) -> AirDefenseRange:
@@ -66,18 +86,38 @@ class ColdWarFlakGenerator(AirDefenseGroupGenerator):
for i in range(3):
for j in range(2):
index = index + 1
- self.add_unit(AirDefence.AAA_8_8cm_Flak_18, "AAA#" + str(index),
- self.position.x + spacing * i + random.randint(1, 5),
- self.position.y + spacing * j + random.randint(1, 5), self.heading)
+ self.add_unit(
+ AirDefence.AAA_8_8cm_Flak_18,
+ "AAA#" + str(index),
+ self.position.x + spacing * i + random.randint(1, 5),
+ self.position.y + spacing * j + random.randint(1, 5),
+ self.heading,
+ )
# Short range guns
- self.add_unit(AirDefence.AAA_ZU_23_Closed, "SHO#1",
- self.position.x - 40, self.position.y - 40, self.heading + 180),
- self.add_unit(AirDefence.AAA_ZU_23_Closed, "SHO#2",
- self.position.x + spacing * 2 + 40, self.position.y + spacing + 40, self.heading),
+ self.add_unit(
+ AirDefence.AAA_ZU_23_Closed,
+ "SHO#1",
+ self.position.x - 40,
+ self.position.y - 40,
+ self.heading + 180,
+ ),
+ self.add_unit(
+ AirDefence.AAA_ZU_23_Closed,
+ "SHO#2",
+ self.position.x + spacing * 2 + 40,
+ self.position.y + spacing + 40,
+ self.heading,
+ ),
# Add a P19 Radar for EWR
- self.add_unit(AirDefence.SAM_SR_P_19, "SR#0", self.position.x - 60, self.position.y - 20, self.heading)
+ self.add_unit(
+ AirDefence.SAM_SR_P_19,
+ "SR#0",
+ self.position.x - 60,
+ self.position.y - 20,
+ self.heading,
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/ewrs.py b/gen/sam/ewrs.py
index 2c60af22..ef94f8b2 100644
--- a/gen/sam/ewrs.py
+++ b/gen/sam/ewrs.py
@@ -10,8 +10,9 @@ class EwrGenerator(GroupGenerator):
raise NotImplementedError
def generate(self) -> None:
- self.add_unit(self.unit_type, "EWR", self.position.x, self.position.y,
- self.heading)
+ self.add_unit(
+ self.unit_type, "EWR", self.position.x, self.position.y, self.heading
+ )
class BoxSpringGenerator(EwrGenerator):
diff --git a/gen/sam/freya_ewr.py b/gen/sam/freya_ewr.py
index f244482b..af637b91 100644
--- a/gen/sam/freya_ewr.py
+++ b/gen/sam/freya_ewr.py
@@ -17,27 +17,93 @@ class FreyaGenerator(AirDefenseGroupGenerator):
def generate(self):
# TODO : would be better with the Concrete structure that is supposed to protect it
- self.add_unit(AirDefence.EWR_FuMG_401_Freya_LZ, "EWR#1", self.position.x, self.position.y, self.heading)
+ self.add_unit(
+ AirDefence.EWR_FuMG_401_Freya_LZ,
+ "EWR#1",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
positions = self.get_circular_position(4, launcher_distance=50, coverage=360)
for i, position in enumerate(positions):
- self.add_unit(AirDefence.AAA_Flak_Vierling_38, "AA#" + str(i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.AAA_Flak_Vierling_38,
+ "AA#" + str(i),
+ position[0],
+ position[1],
+ position[2],
+ )
positions = self.get_circular_position(4, launcher_distance=100, coverage=360)
for i, position in enumerate(positions):
- self.add_unit(AirDefence.AAA_8_8cm_Flak_18, "AA#" + str(4+i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.AAA_8_8cm_Flak_18,
+ "AA#" + str(4 + i),
+ position[0],
+ position[1],
+ position[2],
+ )
# Command/Logi
- self.add_unit(Unarmed.Kübelwagen_82, "Kubel#1", self.position.x - 20, self.position.y - 20, self.heading)
- self.add_unit(Unarmed.Sd_Kfz_7, "Sdkfz#1", self.position.x + 20, self.position.y + 22, self.heading)
- self.add_unit(Unarmed.Sd_Kfz_2, "Sdkfz#2", self.position.x - 22, self.position.y + 20, self.heading)
+ self.add_unit(
+ Unarmed.Kübelwagen_82,
+ "Kubel#1",
+ self.position.x - 20,
+ self.position.y - 20,
+ self.heading,
+ )
+ self.add_unit(
+ Unarmed.Sd_Kfz_7,
+ "Sdkfz#1",
+ self.position.x + 20,
+ self.position.y + 22,
+ self.heading,
+ )
+ self.add_unit(
+ Unarmed.Sd_Kfz_2,
+ "Sdkfz#2",
+ self.position.x - 22,
+ self.position.y + 20,
+ self.heading,
+ )
# Maschinensatz_33 and Kdo.g 40 Telemeter
- self.add_unit(AirDefence.Maschinensatz_33, "Energy#1", self.position.x + 20, self.position.y - 20, self.heading)
- self.add_unit(AirDefence.AAA_Kdo_G_40, "Telemeter#1", self.position.x + 20, self.position.y - 10, self.heading)
- self.add_unit(Infantry.Infantry_Mauser_98, "Inf#1", self.position.x + 20, self.position.y - 14, self.heading)
- self.add_unit(Infantry.Infantry_Mauser_98, "Inf#2", self.position.x + 20, self.position.y - 22, self.heading)
- self.add_unit(Infantry.Infantry_Mauser_98, "Inf#3", self.position.x + 20, self.position.y - 24, self.heading + 45)
+ self.add_unit(
+ AirDefence.Maschinensatz_33,
+ "Energy#1",
+ self.position.x + 20,
+ self.position.y - 20,
+ self.heading,
+ )
+ self.add_unit(
+ AirDefence.AAA_Kdo_G_40,
+ "Telemeter#1",
+ self.position.x + 20,
+ self.position.y - 10,
+ self.heading,
+ )
+ self.add_unit(
+ Infantry.Infantry_Mauser_98,
+ "Inf#1",
+ self.position.x + 20,
+ self.position.y - 14,
+ self.heading,
+ )
+ self.add_unit(
+ Infantry.Infantry_Mauser_98,
+ "Inf#2",
+ self.position.x + 20,
+ self.position.y - 22,
+ self.heading,
+ )
+ self.add_unit(
+ Infantry.Infantry_Mauser_98,
+ "Inf#3",
+ self.position.x + 20,
+ self.position.y - 24,
+ self.heading + 45,
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/group_generator.py b/gen/sam/group_generator.py
index be63b777..65eb0b50 100644
--- a/gen/sam/group_generator.py
+++ b/gen/sam/group_generator.py
@@ -23,14 +23,12 @@ if TYPE_CHECKING:
# care about in the format we want if we just generate our own group description
# types rather than pydcs groups.
class GroupGenerator:
-
def __init__(self, game: Game, ground_object: TheaterGroundObject) -> None:
self.game = game
self.go = ground_object
self.position = ground_object.position
self.heading = random.randint(0, 359)
- self.vg = unitgroup.VehicleGroup(self.game.next_group_id(),
- self.go.group_name)
+ self.vg = unitgroup.VehicleGroup(self.game.next_group_id(), self.go.group_name)
wp = self.vg.add_waypoint(self.position, PointAction.OffRoad, 0)
wp.ETA_locked = True
@@ -40,16 +38,27 @@ class GroupGenerator:
def get_generated_group(self) -> unitgroup.VehicleGroup:
return self.vg
- def add_unit(self, unit_type: Type[VehicleType], name: str, pos_x: float,
- pos_y: float, heading: int) -> Vehicle:
- return self.add_unit_to_group(self.vg, unit_type, name,
- Point(pos_x, pos_y), heading)
+ def add_unit(
+ self,
+ unit_type: Type[VehicleType],
+ name: str,
+ pos_x: float,
+ pos_y: float,
+ heading: int,
+ ) -> Vehicle:
+ return self.add_unit_to_group(
+ self.vg, unit_type, name, Point(pos_x, pos_y), heading
+ )
- def add_unit_to_group(self, group: unitgroup.VehicleGroup,
- unit_type: Type[VehicleType], name: str,
- position: Point, heading: int) -> Vehicle:
- unit = Vehicle(self.game.next_unit_id(),
- f"{group.name}|{name}", unit_type.id)
+ def add_unit_to_group(
+ self,
+ group: unitgroup.VehicleGroup,
+ unit_type: Type[VehicleType],
+ name: str,
+ position: Point,
+ heading: int,
+ ) -> Vehicle:
+ unit = Vehicle(self.game.next_unit_id(), f"{group.name}|{name}", unit_type.id)
unit.position = position
unit.heading = heading
group.add_unit(unit)
@@ -82,31 +91,36 @@ class GroupGenerator:
current_offset = self.heading
current_offset -= outer_offset * (math.ceil(num_units / 2) - 1)
for x in range(1, num_units + 1):
- positions.append((
- self.position.x + launcher_distance * math.cos(math.radians(current_offset)),
- self.position.y + launcher_distance * math.sin(math.radians(current_offset)),
- current_offset,
- ))
+ positions.append(
+ (
+ self.position.x
+ + launcher_distance * math.cos(math.radians(current_offset)),
+ self.position.y
+ + launcher_distance * math.sin(math.radians(current_offset)),
+ current_offset,
+ )
+ )
current_offset += outer_offset
return positions
class ShipGroupGenerator(GroupGenerator):
"""Abstract class for other ship generator classes"""
- def __init__(self, game: Game, ground_object: TheaterGroundObject, faction: Faction):
+
+ def __init__(
+ self, game: Game, ground_object: TheaterGroundObject, faction: Faction
+ ):
self.game = game
self.go = ground_object
self.position = ground_object.position
self.heading = random.randint(0, 359)
self.faction = faction
- self.vg = unitgroup.ShipGroup(self.game.next_group_id(),
- self.go.group_name)
+ self.vg = unitgroup.ShipGroup(self.game.next_group_id(), self.go.group_name)
wp = self.vg.add_waypoint(self.position, 0)
wp.ETA_locked = True
-
+
def add_unit(self, unit_type, name, pos_x, pos_y, heading) -> Ship:
- unit = Ship(self.game.next_unit_id(),
- f"{self.go.group_name}|{name}", unit_type)
+ unit = Ship(self.game.next_unit_id(), f"{self.go.group_name}|{name}", unit_type)
unit.position.x = pos_x
unit.position.y = pos_y
unit.heading = heading
diff --git a/gen/sam/sam_avenger.py b/gen/sam/sam_avenger.py
index 32d1c228..982b9471 100644
--- a/gen/sam/sam_avenger.py
+++ b/gen/sam/sam_avenger.py
@@ -19,10 +19,24 @@ class AvengerGenerator(AirDefenseGroupGenerator):
def generate(self):
num_launchers = random.randint(2, 3)
- self.add_unit(Unarmed.Transport_M818, "TRUCK", self.position.x, self.position.y, self.heading)
- positions = self.get_circular_position(num_launchers, launcher_distance=110, coverage=180)
+ self.add_unit(
+ Unarmed.Transport_M818,
+ "TRUCK",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
+ positions = self.get_circular_position(
+ num_launchers, launcher_distance=110, coverage=180
+ )
for i, position in enumerate(positions):
- self.add_unit(AirDefence.SAM_Avenger_M1097, "SPAA#" + str(i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.SAM_Avenger_M1097,
+ "SPAA#" + str(i),
+ position[0],
+ position[1],
+ position[2],
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/sam_chaparral.py b/gen/sam/sam_chaparral.py
index 1e768bf4..a0b1ece2 100644
--- a/gen/sam/sam_chaparral.py
+++ b/gen/sam/sam_chaparral.py
@@ -19,10 +19,24 @@ class ChaparralGenerator(AirDefenseGroupGenerator):
def generate(self):
num_launchers = random.randint(2, 4)
- self.add_unit(Unarmed.Transport_M818, "TRUCK", self.position.x, self.position.y, self.heading)
- positions = self.get_circular_position(num_launchers, launcher_distance=110, coverage=180)
+ self.add_unit(
+ Unarmed.Transport_M818,
+ "TRUCK",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
+ positions = self.get_circular_position(
+ num_launchers, launcher_distance=110, coverage=180
+ )
for i, position in enumerate(positions):
- self.add_unit(AirDefence.SAM_Chaparral_M48, "SPAA#" + str(i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.SAM_Chaparral_M48,
+ "SPAA#" + str(i),
+ position[0],
+ position[1],
+ position[2],
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/sam_gepard.py b/gen/sam/sam_gepard.py
index 7e8ef223..df16df31 100644
--- a/gen/sam/sam_gepard.py
+++ b/gen/sam/sam_gepard.py
@@ -17,10 +17,28 @@ class GepardGenerator(AirDefenseGroupGenerator):
price = 50
def generate(self):
- self.add_unit(AirDefence.SPAAA_Gepard, "SPAAA", self.position.x, self.position.y, self.heading)
+ self.add_unit(
+ AirDefence.SPAAA_Gepard,
+ "SPAAA",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
if random.randint(0, 1) == 1:
- self.add_unit(AirDefence.SPAAA_Gepard, "SPAAA2", self.position.x, self.position.y, self.heading)
- self.add_unit(Unarmed.Transport_M818, "TRUCK", self.position.x + 80, self.position.y, self.heading)
+ self.add_unit(
+ AirDefence.SPAAA_Gepard,
+ "SPAAA2",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
+ self.add_unit(
+ Unarmed.Transport_M818,
+ "TRUCK",
+ self.position.x + 80,
+ self.position.y,
+ self.heading,
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/sam_group_generator.py b/gen/sam/sam_group_generator.py
index dfda4048..9d8545fb 100644
--- a/gen/sam/sam_group_generator.py
+++ b/gen/sam/sam_group_generator.py
@@ -49,7 +49,12 @@ from gen.sam.sam_roland import RolandGenerator
from gen.sam.sam_sa10 import (
SA10Generator,
Tier2SA10Generator,
- Tier3SA10Generator, SA10BGenerator, SA12Generator, SA20Generator, SA20BGenerator, SA23Generator,
+ Tier3SA10Generator,
+ SA10BGenerator,
+ SA12Generator,
+ SA20Generator,
+ SA20BGenerator,
+ SA23Generator,
)
from gen.sam.sam_sa11 import SA11Generator
from gen.sam.sam_sa13 import SA13Generator
@@ -103,7 +108,6 @@ SAM_MAP: Dict[str, Type[AirDefenseGroupGenerator]] = {
"FreyaGenerator": FreyaGenerator,
"AllyWW2FlakGenerator": AllyWW2FlakGenerator,
"ZSU57Generator": ZSU57Generator,
-
"KS19Generator": KS19Generator,
"SA10BGenerator": SA10BGenerator,
"SA12Generator": SA12Generator,
@@ -145,7 +149,7 @@ SAM_PRICES = {
AirDefence.SAM_SA_13_Strela_10M3_9A35M3: 30,
AirDefence.SAM_SA_15_Tor_9A331: 40,
AirDefence.SAM_SA_19_Tunguska_2S6: 35,
- AirDefence.HQ_7_Self_Propelled_LN: 35
+ AirDefence.HQ_7_Self_Propelled_LN: 35,
}
EWR_MAP = {
@@ -163,7 +167,8 @@ EWR_MAP = {
def get_faction_possible_sams_generator(
- faction: Faction) -> List[Type[AirDefenseGroupGenerator]]:
+ faction: Faction,
+) -> List[Type[AirDefenseGroupGenerator]]:
"""
Return the list of possible SAM generator for the given faction
:param faction: Faction name to search units for
@@ -180,8 +185,10 @@ def get_faction_possible_ewrs_generator(faction: Faction) -> List[Type[GroupGene
def _generate_anti_air_from(
- generators: Sequence[Type[AirDefenseGroupGenerator]], game: Game,
- ground_object: SamGroundObject) -> List[VehicleGroup]:
+ generators: Sequence[Type[AirDefenseGroupGenerator]],
+ game: Game,
+ ground_object: SamGroundObject,
+) -> List[VehicleGroup]:
if not generators:
return []
sam_generator_class = random.choice(generators)
@@ -191,8 +198,10 @@ def _generate_anti_air_from(
def generate_anti_air_group(
- game: Game, ground_object: SamGroundObject, faction: Faction,
- ranges: Optional[Iterable[Set[AirDefenseRange]]] = None
+ game: Game,
+ ground_object: SamGroundObject,
+ faction: Faction,
+ ranges: Optional[Iterable[Set[AirDefenseRange]]] = None,
) -> List[VehicleGroup]:
"""
This generate a SAM group
@@ -213,24 +222,25 @@ def generate_anti_air_group(
"""
generators = get_faction_possible_sams_generator(faction)
if ranges is None:
- ranges = [{
- AirDefenseRange.Long,
- AirDefenseRange.Medium,
- AirDefenseRange.Short,
- }]
+ ranges = [
+ {
+ AirDefenseRange.Long,
+ AirDefenseRange.Medium,
+ AirDefenseRange.Short,
+ }
+ ]
for range_options in ranges:
- generators_for_range = [g for g in generators if
- g.range() in range_options]
- groups = _generate_anti_air_from(generators_for_range, game,
- ground_object)
+ generators_for_range = [g for g in generators if g.range() in range_options]
+ groups = _generate_anti_air_from(generators_for_range, game, ground_object)
if groups:
return groups
return []
-def generate_ewr_group(game: Game, ground_object: TheaterGroundObject,
- faction: Faction) -> Optional[VehicleGroup]:
+def generate_ewr_group(
+ game: Game, ground_object: TheaterGroundObject, faction: Faction
+) -> Optional[VehicleGroup]:
"""Generates an early warning radar group.
:param game: The Game.
diff --git a/gen/sam/sam_hawk.py b/gen/sam/sam_hawk.py
index 0d526301..651531c0 100644
--- a/gen/sam/sam_hawk.py
+++ b/gen/sam/sam_hawk.py
@@ -18,20 +18,51 @@ class HawkGenerator(AirDefenseGroupGenerator):
price = 115
def generate(self):
- self.add_unit(AirDefence.SAM_Hawk_SR_AN_MPQ_50, "SR", self.position.x + 20, self.position.y, self.heading)
- self.add_unit(AirDefence.SAM_Hawk_PCP, "PCP", self.position.x, self.position.y, self.heading)
- self.add_unit(AirDefence.SAM_Hawk_TR_AN_MPQ_46, "TR", self.position.x + 40, self.position.y, self.heading)
+ self.add_unit(
+ AirDefence.SAM_Hawk_SR_AN_MPQ_50,
+ "SR",
+ self.position.x + 20,
+ self.position.y,
+ self.heading,
+ )
+ self.add_unit(
+ AirDefence.SAM_Hawk_PCP,
+ "PCP",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
+ self.add_unit(
+ AirDefence.SAM_Hawk_TR_AN_MPQ_46,
+ "TR",
+ self.position.x + 40,
+ self.position.y,
+ self.heading,
+ )
# Triple A for close range defense
aa_group = self.add_auxiliary_group("AA")
- self.add_unit_to_group(aa_group, AirDefence.AAA_Vulcan_M163, "AAA",
- self.position + Point(20, 30), self.heading)
+ self.add_unit_to_group(
+ aa_group,
+ AirDefence.AAA_Vulcan_M163,
+ "AAA",
+ self.position + Point(20, 30),
+ self.heading,
+ )
num_launchers = random.randint(3, 6)
- positions = self.get_circular_position(num_launchers, launcher_distance=120, coverage=180)
+ positions = self.get_circular_position(
+ num_launchers, launcher_distance=120, coverage=180
+ )
for i, position in enumerate(positions):
- self.add_unit(AirDefence.SAM_Hawk_LN_M192, "LN#" + str(i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.SAM_Hawk_LN_M192,
+ "LN#" + str(i),
+ position[0],
+ position[1],
+ position[2],
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/sam_hq7.py b/gen/sam/sam_hq7.py
index a9f6eb59..06bba42f 100644
--- a/gen/sam/sam_hq7.py
+++ b/gen/sam/sam_hq7.py
@@ -18,23 +18,51 @@ class HQ7Generator(AirDefenseGroupGenerator):
price = 120
def generate(self):
- self.add_unit(AirDefence.HQ_7_Self_Propelled_STR, "STR", self.position.x, self.position.y, self.heading)
- self.add_unit(AirDefence.HQ_7_Self_Propelled_LN, "LN", self.position.x + 20, self.position.y, self.heading)
+ self.add_unit(
+ AirDefence.HQ_7_Self_Propelled_STR,
+ "STR",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
+ self.add_unit(
+ AirDefence.HQ_7_Self_Propelled_LN,
+ "LN",
+ self.position.x + 20,
+ self.position.y,
+ self.heading,
+ )
# Triple A for close range defense
aa_group = self.add_auxiliary_group("AA")
- self.add_unit_to_group(aa_group, AirDefence.AAA_ZU_23_on_Ural_375,
- "AAA1", self.position + Point(20, 30),
- self.heading)
- self.add_unit_to_group(aa_group, AirDefence.AAA_ZU_23_on_Ural_375,
- "AAA2", self.position - Point(20, 30),
- self.heading)
+ self.add_unit_to_group(
+ aa_group,
+ AirDefence.AAA_ZU_23_on_Ural_375,
+ "AAA1",
+ self.position + Point(20, 30),
+ self.heading,
+ )
+ self.add_unit_to_group(
+ aa_group,
+ AirDefence.AAA_ZU_23_on_Ural_375,
+ "AAA2",
+ self.position - Point(20, 30),
+ self.heading,
+ )
num_launchers = random.randint(0, 3)
if num_launchers > 0:
- positions = self.get_circular_position(num_launchers, launcher_distance=120, coverage=360)
+ positions = self.get_circular_position(
+ num_launchers, launcher_distance=120, coverage=360
+ )
for i, position in enumerate(positions):
- self.add_unit(AirDefence.HQ_7_Self_Propelled_LN, "LN#" + str(i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.HQ_7_Self_Propelled_LN,
+ "LN#" + str(i),
+ position[0],
+ position[1],
+ position[2],
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/sam_linebacker.py b/gen/sam/sam_linebacker.py
index e2dae5a1..1fa89ca2 100644
--- a/gen/sam/sam_linebacker.py
+++ b/gen/sam/sam_linebacker.py
@@ -19,10 +19,24 @@ class LinebackerGenerator(AirDefenseGroupGenerator):
def generate(self):
num_launchers = random.randint(2, 4)
- self.add_unit(Unarmed.Transport_M818, "TRUCK", self.position.x, self.position.y, self.heading)
- positions = self.get_circular_position(num_launchers, launcher_distance=110, coverage=180)
+ self.add_unit(
+ Unarmed.Transport_M818,
+ "TRUCK",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
+ positions = self.get_circular_position(
+ num_launchers, launcher_distance=110, coverage=180
+ )
for i, position in enumerate(positions):
- self.add_unit(AirDefence.SAM_Linebacker_M6, "M6#" + str(i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.SAM_Linebacker_M6,
+ "M6#" + str(i),
+ position[0],
+ position[1],
+ position[2],
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/sam_patriot.py b/gen/sam/sam_patriot.py
index 45fcce1a..21f78b36 100644
--- a/gen/sam/sam_patriot.py
+++ b/gen/sam/sam_patriot.py
@@ -19,24 +19,65 @@ class PatriotGenerator(AirDefenseGroupGenerator):
def generate(self):
# Command Post
- self.add_unit(AirDefence.SAM_Patriot_STR_AN_MPQ_53, "STR", self.position.x + 30, self.position.y + 30, self.heading)
- self.add_unit(AirDefence.SAM_Patriot_AMG_AN_MRC_137, "MRC", self.position.x, self.position.y, self.heading)
- self.add_unit(AirDefence.SAM_Patriot_ECS_AN_MSQ_104, "MSQ", self.position.x + 30, self.position.y, self.heading)
- self.add_unit(AirDefence.SAM_Patriot_ICC, "ICC", self.position.x + 60, self.position.y, self.heading)
- self.add_unit(AirDefence.SAM_Patriot_EPP_III, "EPP", self.position.x, self.position.y + 30, self.heading)
+ self.add_unit(
+ AirDefence.SAM_Patriot_STR_AN_MPQ_53,
+ "STR",
+ self.position.x + 30,
+ self.position.y + 30,
+ self.heading,
+ )
+ self.add_unit(
+ AirDefence.SAM_Patriot_AMG_AN_MRC_137,
+ "MRC",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
+ self.add_unit(
+ AirDefence.SAM_Patriot_ECS_AN_MSQ_104,
+ "MSQ",
+ self.position.x + 30,
+ self.position.y,
+ self.heading,
+ )
+ self.add_unit(
+ AirDefence.SAM_Patriot_ICC,
+ "ICC",
+ self.position.x + 60,
+ self.position.y,
+ self.heading,
+ )
+ self.add_unit(
+ AirDefence.SAM_Patriot_EPP_III,
+ "EPP",
+ self.position.x,
+ self.position.y + 30,
+ self.heading,
+ )
num_launchers = random.randint(3, 4)
- positions = self.get_circular_position(num_launchers, launcher_distance=120, coverage=360)
+ positions = self.get_circular_position(
+ num_launchers, launcher_distance=120, coverage=360
+ )
for i, position in enumerate(positions):
- self.add_unit(AirDefence.SAM_Patriot_LN_M901, "LN#" + str(i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.SAM_Patriot_LN_M901,
+ "LN#" + str(i),
+ position[0],
+ position[1],
+ position[2],
+ )
# Short range protection for high value site
aa_group = self.add_auxiliary_group("AA")
num_launchers = random.randint(3, 4)
- positions = self.get_circular_position(num_launchers, launcher_distance=200, coverage=360)
+ positions = self.get_circular_position(
+ num_launchers, launcher_distance=200, coverage=360
+ )
for i, (x, y, heading) in enumerate(positions):
- self.add_unit_to_group(aa_group, AirDefence.AAA_Vulcan_M163,
- f"SPAAA#{i}", Point(x, y), heading)
+ self.add_unit_to_group(
+ aa_group, AirDefence.AAA_Vulcan_M163, f"SPAAA#{i}", Point(x, y), heading
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/sam_rapier.py b/gen/sam/sam_rapier.py
index 5b4dbaa9..1ff8f9ce 100644
--- a/gen/sam/sam_rapier.py
+++ b/gen/sam/sam_rapier.py
@@ -17,14 +17,34 @@ class RapierGenerator(AirDefenseGroupGenerator):
price = 50
def generate(self):
- self.add_unit(AirDefence.Rapier_FSA_Blindfire_Tracker, "BT", self.position.x, self.position.y, self.heading)
- self.add_unit(AirDefence.Rapier_FSA_Optical_Tracker, "OT", self.position.x + 20, self.position.y, self.heading)
+ self.add_unit(
+ AirDefence.Rapier_FSA_Blindfire_Tracker,
+ "BT",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
+ self.add_unit(
+ AirDefence.Rapier_FSA_Optical_Tracker,
+ "OT",
+ self.position.x + 20,
+ self.position.y,
+ self.heading,
+ )
num_launchers = random.randint(3, 6)
- positions = self.get_circular_position(num_launchers, launcher_distance=80, coverage=240)
+ positions = self.get_circular_position(
+ num_launchers, launcher_distance=80, coverage=240
+ )
for i, position in enumerate(positions):
- self.add_unit(AirDefence.Rapier_FSA_Launcher, "LN#" + str(i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.Rapier_FSA_Launcher,
+ "LN#" + str(i),
+ position[0],
+ position[1],
+ position[2],
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/sam_roland.py b/gen/sam/sam_roland.py
index 3c2685c7..26c1bcdf 100644
--- a/gen/sam/sam_roland.py
+++ b/gen/sam/sam_roland.py
@@ -15,9 +15,27 @@ class RolandGenerator(AirDefenseGroupGenerator):
price = 40
def generate(self):
- self.add_unit(AirDefence.SAM_Roland_EWR, "EWR", self.position.x + 40, self.position.y, self.heading)
- self.add_unit(AirDefence.SAM_Roland_ADS, "ADS", self.position.x, self.position.y, self.heading)
- self.add_unit(Unarmed.Transport_M818, "TRUCK", self.position.x + 80, self.position.y, self.heading)
+ self.add_unit(
+ AirDefence.SAM_Roland_EWR,
+ "EWR",
+ self.position.x + 40,
+ self.position.y,
+ self.heading,
+ )
+ self.add_unit(
+ AirDefence.SAM_Roland_ADS,
+ "ADS",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
+ self.add_unit(
+ Unarmed.Transport_M818,
+ "TRUCK",
+ self.position.x + 80,
+ self.position.y,
+ self.heading,
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/sam_sa10.py b/gen/sam/sam_sa10.py
index b1923785..b8731590 100644
--- a/gen/sam/sam_sa10.py
+++ b/gen/sam/sam_sa10.py
@@ -33,28 +33,41 @@ class SA10Generator(AirDefenseGroupGenerator):
def generate(self):
# Search Radar
- self.add_unit(self.sr1, "SR1", self.position.x, self.position.y + 40, self.heading)
+ self.add_unit(
+ self.sr1, "SR1", self.position.x, self.position.y + 40, self.heading
+ )
# Search radar for missiles (optionnal)
- self.add_unit(self.sr2, "SR2", self.position.x - 40, self.position.y, self.heading)
+ self.add_unit(
+ self.sr2, "SR2", self.position.x - 40, self.position.y, self.heading
+ )
# Command Post
self.add_unit(self.cp, "CP", self.position.x, self.position.y, self.heading)
# 2 Tracking radars
- self.add_unit(self.tr1, "TR1", self.position.x - 40, self.position.y - 40, self.heading)
+ self.add_unit(
+ self.tr1, "TR1", self.position.x - 40, self.position.y - 40, self.heading
+ )
- self.add_unit(self.tr2, "TR2", self.position.x + 40, self.position.y - 40,
- self.heading)
+ self.add_unit(
+ self.tr2, "TR2", self.position.x + 40, self.position.y - 40, self.heading
+ )
# 2 different launcher type (C & D)
num_launchers = random.randint(6, 8)
- positions = self.get_circular_position(num_launchers, launcher_distance=100, coverage=360)
+ positions = self.get_circular_position(
+ num_launchers, launcher_distance=100, coverage=360
+ )
for i, position in enumerate(positions):
- if i%2 == 0:
- self.add_unit(self.ln1, "LN#" + str(i), position[0], position[1], position[2])
+ if i % 2 == 0:
+ self.add_unit(
+ self.ln1, "LN#" + str(i), position[0], position[1], position[2]
+ )
else:
- self.add_unit(self.ln2, "LN#" + str(i), position[0], position[1], position[2])
+ self.add_unit(
+ self.ln2, "LN#" + str(i), position[0], position[1], position[2]
+ )
self.generate_defensive_groups()
@@ -67,10 +80,16 @@ class SA10Generator(AirDefenseGroupGenerator):
aa_group = self.add_auxiliary_group("AA")
num_launchers = random.randint(6, 8)
positions = self.get_circular_position(
- num_launchers, launcher_distance=210, coverage=360)
+ num_launchers, launcher_distance=210, coverage=360
+ )
for i, (x, y, heading) in enumerate(positions):
- self.add_unit_to_group(aa_group, AirDefence.SPAAA_ZSU_23_4_Shilka,
- f"AA#{i}", Point(x, y), heading)
+ self.add_unit_to_group(
+ aa_group,
+ AirDefence.SPAAA_ZSU_23_4_Shilka,
+ f"AA#{i}",
+ Point(x, y),
+ heading,
+ )
class Tier2SA10Generator(SA10Generator):
@@ -82,10 +101,16 @@ class Tier2SA10Generator(SA10Generator):
pd_group = self.add_auxiliary_group("PD")
num_launchers = random.randint(2, 4)
positions = self.get_circular_position(
- num_launchers, launcher_distance=140, coverage=360)
+ num_launchers, launcher_distance=140, coverage=360
+ )
for i, (x, y, heading) in enumerate(positions):
- self.add_unit_to_group(pd_group, AirDefence.SAM_SA_15_Tor_9A331,
- f"PD#{i}", Point(x, y), heading)
+ self.add_unit_to_group(
+ pd_group,
+ AirDefence.SAM_SA_15_Tor_9A331,
+ f"PD#{i}",
+ Point(x, y),
+ heading,
+ )
class Tier3SA10Generator(SA10Generator):
@@ -94,19 +119,31 @@ class Tier3SA10Generator(SA10Generator):
aa_group = self.add_auxiliary_group("AA")
num_launchers = random.randint(6, 8)
positions = self.get_circular_position(
- num_launchers, launcher_distance=210, coverage=360)
+ num_launchers, launcher_distance=210, coverage=360
+ )
for i, (x, y, heading) in enumerate(positions):
- self.add_unit_to_group(aa_group, AirDefence.SAM_SA_19_Tunguska_2S6,
- f"AA#{i}", Point(x, y), heading)
+ self.add_unit_to_group(
+ aa_group,
+ AirDefence.SAM_SA_19_Tunguska_2S6,
+ f"AA#{i}",
+ Point(x, y),
+ heading,
+ )
# SA-15 for both shorter range targets and point defense.
pd_group = self.add_auxiliary_group("PD")
num_launchers = random.randint(2, 4)
positions = self.get_circular_position(
- num_launchers, launcher_distance=140, coverage=360)
+ num_launchers, launcher_distance=140, coverage=360
+ )
for i, (x, y, heading) in enumerate(positions):
- self.add_unit_to_group(pd_group, AirDefence.SAM_SA_15_Tor_9A331,
- f"PD#{i}", Point(x, y), heading)
+ self.add_unit_to_group(
+ pd_group,
+ AirDefence.SAM_SA_15_Tor_9A331,
+ f"PD#{i}",
+ Point(x, y),
+ heading,
+ )
class SA10BGenerator(Tier3SA10Generator):
@@ -186,4 +223,4 @@ class SA23Generator(Tier3SA10Generator):
self.tr1 = highdigitsams.SAM_SA_23_S_300VM_9S32ME_TR
self.tr2 = highdigitsams.SAM_SA_23_S_300VM_9S32ME_TR
self.ln1 = highdigitsams.SAM_SA_23_S_300VM_9A82ME_LN
- self.ln2 = highdigitsams.SAM_SA_23_S_300VM_9A83ME_LN
\ No newline at end of file
+ self.ln2 = highdigitsams.SAM_SA_23_S_300VM_9A83ME_LN
diff --git a/gen/sam/sam_sa11.py b/gen/sam/sam_sa11.py
index 2fd5a08f..adf0362e 100644
--- a/gen/sam/sam_sa11.py
+++ b/gen/sam/sam_sa11.py
@@ -17,14 +17,34 @@ class SA11Generator(AirDefenseGroupGenerator):
price = 180
def generate(self):
- self.add_unit(AirDefence.SAM_SA_11_Buk_SR_9S18M1, "SR", self.position.x+20, self.position.y, self.heading)
- self.add_unit(AirDefence.SAM_SA_11_Buk_CC_9S470M1, "CC", self.position.x, self.position.y, self.heading)
+ self.add_unit(
+ AirDefence.SAM_SA_11_Buk_SR_9S18M1,
+ "SR",
+ self.position.x + 20,
+ self.position.y,
+ self.heading,
+ )
+ self.add_unit(
+ AirDefence.SAM_SA_11_Buk_CC_9S470M1,
+ "CC",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
num_launchers = random.randint(2, 4)
- positions = self.get_circular_position(num_launchers, launcher_distance=140, coverage=180)
+ positions = self.get_circular_position(
+ num_launchers, launcher_distance=140, coverage=180
+ )
for i, position in enumerate(positions):
- self.add_unit(AirDefence.SAM_SA_11_Buk_LN_9A310M1, "LN#" + str(i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.SAM_SA_11_Buk_LN_9A310M1,
+ "LN#" + str(i),
+ position[0],
+ position[1],
+ position[2],
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/sam_sa13.py b/gen/sam/sam_sa13.py
index ec7b3693..dec20085 100644
--- a/gen/sam/sam_sa13.py
+++ b/gen/sam/sam_sa13.py
@@ -17,13 +17,33 @@ class SA13Generator(AirDefenseGroupGenerator):
price = 50
def generate(self):
- self.add_unit(Unarmed.Transport_UAZ_469, "UAZ", self.position.x, self.position.y, self.heading)
- self.add_unit(Unarmed.Transport_KAMAZ_43101, "TRUCK", self.position.x+40, self.position.y, self.heading)
+ self.add_unit(
+ Unarmed.Transport_UAZ_469,
+ "UAZ",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
+ self.add_unit(
+ Unarmed.Transport_KAMAZ_43101,
+ "TRUCK",
+ self.position.x + 40,
+ self.position.y,
+ self.heading,
+ )
num_launchers = random.randint(2, 3)
- positions = self.get_circular_position(num_launchers, launcher_distance=120, coverage=360)
+ positions = self.get_circular_position(
+ num_launchers, launcher_distance=120, coverage=360
+ )
for i, position in enumerate(positions):
- self.add_unit(AirDefence.SAM_SA_13_Strela_10M3_9A35M3, "LN#" + str(i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.SAM_SA_13_Strela_10M3_9A35M3,
+ "LN#" + str(i),
+ position[0],
+ position[1],
+ position[2],
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/sam_sa15.py b/gen/sam/sam_sa15.py
index 30eaabfe..ffd45752 100644
--- a/gen/sam/sam_sa15.py
+++ b/gen/sam/sam_sa15.py
@@ -15,10 +15,28 @@ class SA15Generator(AirDefenseGroupGenerator):
price = 55
def generate(self):
- self.add_unit(AirDefence.SAM_SA_15_Tor_9A331, "ADS", self.position.x, self.position.y, self.heading)
- self.add_unit(Unarmed.Transport_UAZ_469, "EWR", self.position.x + 40, self.position.y, self.heading)
- self.add_unit(Unarmed.Transport_KAMAZ_43101, "TRUCK", self.position.x + 80, self.position.y, self.heading)
+ self.add_unit(
+ AirDefence.SAM_SA_15_Tor_9A331,
+ "ADS",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
+ self.add_unit(
+ Unarmed.Transport_UAZ_469,
+ "EWR",
+ self.position.x + 40,
+ self.position.y,
+ self.heading,
+ )
+ self.add_unit(
+ Unarmed.Transport_KAMAZ_43101,
+ "TRUCK",
+ self.position.x + 80,
+ self.position.y,
+ self.heading,
+ )
@classmethod
def range(cls) -> AirDefenseRange:
- return AirDefenseRange.Medium
\ No newline at end of file
+ return AirDefenseRange.Medium
diff --git a/gen/sam/sam_sa17.py b/gen/sam/sam_sa17.py
index eced94bf..52922646 100644
--- a/gen/sam/sam_sa17.py
+++ b/gen/sam/sam_sa17.py
@@ -16,14 +16,31 @@ class SA17Generator(AirDefenseGroupGenerator):
price = 180
def generate(self):
- self.add_unit(AirDefence.SAM_SA_11_Buk_SR_9S18M1, "SR", self.position.x + 20, self.position.y, self.heading)
- self.add_unit(AirDefence.SAM_SA_11_Buk_CC_9S470M1, "CC", self.position.x, self.position.y, self.heading)
+ self.add_unit(
+ AirDefence.SAM_SA_11_Buk_SR_9S18M1,
+ "SR",
+ self.position.x + 20,
+ self.position.y,
+ self.heading,
+ )
+ self.add_unit(
+ AirDefence.SAM_SA_11_Buk_CC_9S470M1,
+ "CC",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
positions = self.get_circular_position(3, launcher_distance=140, coverage=180)
for i, position in enumerate(positions):
- self.add_unit(highdigitsams.SAM_SA_17_Buk_M1_2_LN_9A310M1_2, "LN#" + str(i), position[0], position[1],
- position[2])
+ self.add_unit(
+ highdigitsams.SAM_SA_17_Buk_M1_2_LN_9A310M1_2,
+ "LN#" + str(i),
+ position[0],
+ position[1],
+ position[2],
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/sam_sa19.py b/gen/sam/sam_sa19.py
index 298ae91c..02a3ff24 100644
--- a/gen/sam/sam_sa19.py
+++ b/gen/sam/sam_sa19.py
@@ -20,11 +20,25 @@ class SA19Generator(AirDefenseGroupGenerator):
num_launchers = random.randint(1, 3)
if num_launchers == 1:
- self.add_unit(AirDefence.SAM_SA_19_Tunguska_2S6, "LN#0", self.position.x, self.position.y, self.heading)
+ self.add_unit(
+ AirDefence.SAM_SA_19_Tunguska_2S6,
+ "LN#0",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
else:
- positions = self.get_circular_position(num_launchers, launcher_distance=120, coverage=180)
+ positions = self.get_circular_position(
+ num_launchers, launcher_distance=120, coverage=180
+ )
for i, position in enumerate(positions):
- self.add_unit(AirDefence.SAM_SA_19_Tunguska_2S6, "LN#" + str(i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.SAM_SA_19_Tunguska_2S6,
+ "LN#" + str(i),
+ position[0],
+ position[1],
+ position[2],
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/sam_sa2.py b/gen/sam/sam_sa2.py
index c95da151..4307371e 100644
--- a/gen/sam/sam_sa2.py
+++ b/gen/sam/sam_sa2.py
@@ -17,14 +17,30 @@ class SA2Generator(AirDefenseGroupGenerator):
price = 74
def generate(self):
- self.add_unit(AirDefence.SAM_SR_P_19, "SR", self.position.x, self.position.y, self.heading)
- self.add_unit(AirDefence.SAM_SA_2_TR_SNR_75_Fan_Song, "TR", self.position.x + 20, self.position.y, self.heading)
+ self.add_unit(
+ AirDefence.SAM_SR_P_19, "SR", self.position.x, self.position.y, self.heading
+ )
+ self.add_unit(
+ AirDefence.SAM_SA_2_TR_SNR_75_Fan_Song,
+ "TR",
+ self.position.x + 20,
+ self.position.y,
+ self.heading,
+ )
num_launchers = random.randint(3, 6)
- positions = self.get_circular_position(num_launchers, launcher_distance=120, coverage=180)
+ positions = self.get_circular_position(
+ num_launchers, launcher_distance=120, coverage=180
+ )
for i, position in enumerate(positions):
- self.add_unit(AirDefence.SAM_SA_2_LN_SM_90, "LN#" + str(i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.SAM_SA_2_LN_SM_90,
+ "LN#" + str(i),
+ position[0],
+ position[1],
+ position[2],
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/sam_sa3.py b/gen/sam/sam_sa3.py
index 8ab5cad3..eb689de5 100644
--- a/gen/sam/sam_sa3.py
+++ b/gen/sam/sam_sa3.py
@@ -17,14 +17,30 @@ class SA3Generator(AirDefenseGroupGenerator):
price = 80
def generate(self):
- self.add_unit(AirDefence.SAM_SR_P_19, "SR", self.position.x, self.position.y, self.heading)
- self.add_unit(AirDefence.SAM_SA_3_S_125_TR_SNR, "TR", self.position.x + 20, self.position.y, self.heading)
+ self.add_unit(
+ AirDefence.SAM_SR_P_19, "SR", self.position.x, self.position.y, self.heading
+ )
+ self.add_unit(
+ AirDefence.SAM_SA_3_S_125_TR_SNR,
+ "TR",
+ self.position.x + 20,
+ self.position.y,
+ self.heading,
+ )
num_launchers = random.randint(3, 6)
- positions = self.get_circular_position(num_launchers, launcher_distance=120, coverage=180)
+ positions = self.get_circular_position(
+ num_launchers, launcher_distance=120, coverage=180
+ )
for i, position in enumerate(positions):
- self.add_unit(AirDefence.SAM_SA_3_S_125_LN_5P73, "LN#" + str(i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.SAM_SA_3_S_125_LN_5P73,
+ "LN#" + str(i),
+ position[0],
+ position[1],
+ position[2],
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/sam_sa6.py b/gen/sam/sam_sa6.py
index fab5f01b..eb084aa1 100644
--- a/gen/sam/sam_sa6.py
+++ b/gen/sam/sam_sa6.py
@@ -17,13 +17,27 @@ class SA6Generator(AirDefenseGroupGenerator):
price = 102
def generate(self):
- self.add_unit(AirDefence.SAM_SA_6_Kub_STR_9S91, "STR", self.position.x, self.position.y, self.heading)
+ self.add_unit(
+ AirDefence.SAM_SA_6_Kub_STR_9S91,
+ "STR",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
num_launchers = random.randint(2, 4)
- positions = self.get_circular_position(num_launchers, launcher_distance=120, coverage=360)
+ positions = self.get_circular_position(
+ num_launchers, launcher_distance=120, coverage=360
+ )
for i, position in enumerate(positions):
- self.add_unit(AirDefence.SAM_SA_6_Kub_LN_2P25, "LN#" + str(i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.SAM_SA_6_Kub_LN_2P25,
+ "LN#" + str(i),
+ position[0],
+ position[1],
+ position[2],
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/sam_sa8.py b/gen/sam/sam_sa8.py
index 2dd104ee..3bf14f2e 100644
--- a/gen/sam/sam_sa8.py
+++ b/gen/sam/sam_sa8.py
@@ -15,8 +15,20 @@ class SA8Generator(AirDefenseGroupGenerator):
price = 55
def generate(self):
- self.add_unit(AirDefence.SAM_SA_8_Osa_9A33, "OSA", self.position.x, self.position.y, self.heading)
- self.add_unit(AirDefence.SAM_SA_8_Osa_LD_9T217, "LD", self.position.x + 20, self.position.y, self.heading)
+ self.add_unit(
+ AirDefence.SAM_SA_8_Osa_9A33,
+ "OSA",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
+ self.add_unit(
+ AirDefence.SAM_SA_8_Osa_LD_9T217,
+ "LD",
+ self.position.x + 20,
+ self.position.y,
+ self.heading,
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/sam_sa9.py b/gen/sam/sam_sa9.py
index f1cfaff7..0051a03a 100644
--- a/gen/sam/sam_sa9.py
+++ b/gen/sam/sam_sa9.py
@@ -17,13 +17,33 @@ class SA9Generator(AirDefenseGroupGenerator):
price = 40
def generate(self):
- self.add_unit(Unarmed.Transport_UAZ_469, "UAZ", self.position.x, self.position.y, self.heading)
- self.add_unit(Unarmed.Transport_KAMAZ_43101, "TRUCK", self.position.x+40, self.position.y, self.heading)
+ self.add_unit(
+ Unarmed.Transport_UAZ_469,
+ "UAZ",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
+ self.add_unit(
+ Unarmed.Transport_KAMAZ_43101,
+ "TRUCK",
+ self.position.x + 40,
+ self.position.y,
+ self.heading,
+ )
num_launchers = random.randint(2, 3)
- positions = self.get_circular_position(num_launchers, launcher_distance=120, coverage=360)
+ positions = self.get_circular_position(
+ num_launchers, launcher_distance=120, coverage=360
+ )
for i, position in enumerate(positions):
- self.add_unit(AirDefence.SAM_SA_9_Strela_1_9P31, "LN#" + str(i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.SAM_SA_9_Strela_1_9P31,
+ "LN#" + str(i),
+ position[0],
+ position[1],
+ position[2],
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/sam_vulcan.py b/gen/sam/sam_vulcan.py
index 5b67d878..44364189 100644
--- a/gen/sam/sam_vulcan.py
+++ b/gen/sam/sam_vulcan.py
@@ -17,12 +17,29 @@ class VulcanGenerator(AirDefenseGroupGenerator):
price = 25
def generate(self):
- self.add_unit(AirDefence.AAA_Vulcan_M163, "SPAAA", self.position.x, self.position.y, self.heading)
+ self.add_unit(
+ AirDefence.AAA_Vulcan_M163,
+ "SPAAA",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
if random.randint(0, 1) == 1:
- self.add_unit(AirDefence.AAA_Vulcan_M163, "SPAAA2", self.position.x, self.position.y, self.heading)
- self.add_unit(Unarmed.Transport_M818, "TRUCK", self.position.x + 80, self.position.y, self.heading)
+ self.add_unit(
+ AirDefence.AAA_Vulcan_M163,
+ "SPAAA2",
+ self.position.x,
+ self.position.y,
+ self.heading,
+ )
+ self.add_unit(
+ Unarmed.Transport_M818,
+ "TRUCK",
+ self.position.x + 80,
+ self.position.y,
+ self.heading,
+ )
@classmethod
def range(cls) -> AirDefenseRange:
return AirDefenseRange.Short
-
diff --git a/gen/sam/sam_zsu23.py b/gen/sam/sam_zsu23.py
index c25a9295..aa70e54b 100644
--- a/gen/sam/sam_zsu23.py
+++ b/gen/sam/sam_zsu23.py
@@ -19,9 +19,17 @@ class ZSU23Generator(AirDefenseGroupGenerator):
def generate(self):
num_launchers = random.randint(4, 5)
- positions = self.get_circular_position(num_launchers, launcher_distance=120, coverage=180)
+ positions = self.get_circular_position(
+ num_launchers, launcher_distance=120, coverage=180
+ )
for i, position in enumerate(positions):
- self.add_unit(AirDefence.SPAAA_ZSU_23_4_Shilka, "SPAA#" + str(i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.SPAAA_ZSU_23_4_Shilka,
+ "SPAA#" + str(i),
+ position[0],
+ position[1],
+ position[2],
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/sam_zu23.py b/gen/sam/sam_zu23.py
index 494c436d..b17367f4 100644
--- a/gen/sam/sam_zu23.py
+++ b/gen/sam/sam_zu23.py
@@ -20,15 +20,19 @@ class ZU23Generator(AirDefenseGroupGenerator):
grid_x = random.randint(2, 3)
grid_y = random.randint(2, 3)
- spacing = random.randint(10,40)
+ spacing = random.randint(10, 40)
index = 0
for i in range(grid_x):
for j in range(grid_y):
- index = index+1
- self.add_unit(AirDefence.AAA_ZU_23_Closed, "AAA#" + str(index),
- self.position.x + spacing*i,
- self.position.y + spacing*j, self.heading)
+ index = index + 1
+ self.add_unit(
+ AirDefence.AAA_ZU_23_Closed,
+ "AAA#" + str(index),
+ self.position.x + spacing * i,
+ self.position.y + spacing * j,
+ self.heading,
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/sam_zu23_ural.py b/gen/sam/sam_zu23_ural.py
index 2f26436b..5f075f49 100644
--- a/gen/sam/sam_zu23_ural.py
+++ b/gen/sam/sam_zu23_ural.py
@@ -19,9 +19,17 @@ class ZU23UralGenerator(AirDefenseGroupGenerator):
def generate(self):
num_launchers = random.randint(2, 8)
- positions = self.get_circular_position(num_launchers, launcher_distance=80, coverage=360)
+ positions = self.get_circular_position(
+ num_launchers, launcher_distance=80, coverage=360
+ )
for i, position in enumerate(positions):
- self.add_unit(AirDefence.AAA_ZU_23_on_Ural_375, "SPAA#" + str(i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.AAA_ZU_23_on_Ural_375,
+ "SPAA#" + str(i),
+ position[0],
+ position[1],
+ position[2],
+ )
@classmethod
def range(cls) -> AirDefenseRange:
diff --git a/gen/sam/sam_zu23_ural_insurgent.py b/gen/sam/sam_zu23_ural_insurgent.py
index d8c26995..3e8282e0 100644
--- a/gen/sam/sam_zu23_ural_insurgent.py
+++ b/gen/sam/sam_zu23_ural_insurgent.py
@@ -19,11 +19,18 @@ class ZU23UralInsurgentGenerator(AirDefenseGroupGenerator):
def generate(self):
num_launchers = random.randint(2, 8)
- positions = self.get_circular_position(num_launchers, launcher_distance=80, coverage=360)
+ positions = self.get_circular_position(
+ num_launchers, launcher_distance=80, coverage=360
+ )
for i, position in enumerate(positions):
- self.add_unit(AirDefence.AAA_ZU_23_Insurgent_on_Ural_375, "SPAA#" + str(i), position[0], position[1], position[2])
+ self.add_unit(
+ AirDefence.AAA_ZU_23_Insurgent_on_Ural_375,
+ "SPAA#" + str(i),
+ position[0],
+ position[1],
+ position[2],
+ )
@classmethod
def range(cls) -> AirDefenseRange:
return AirDefenseRange.Short
-
diff --git a/gen/triggergen.py b/gen/triggergen.py
index 6a24d703..7df4838f 100644
--- a/gen/triggergen.py
+++ b/gen/triggergen.py
@@ -2,18 +2,13 @@ from __future__ import annotations
from typing import TYPE_CHECKING
-from dcs.action import (
- MarkToAll,
- SetFlag,
- DoScript,
- ClearFlag
-)
+from dcs.action import MarkToAll, SetFlag, DoScript, ClearFlag
from dcs.condition import (
TimeAfter,
AllOfCoalitionOutsideZone,
PartOfCoalitionInZone,
FlagIsFalse,
- FlagIsTrue
+ FlagIsTrue,
)
from dcs.unitgroup import FlyingGroup
from dcs.mission import Mission
@@ -56,7 +51,7 @@ class Silence(Option):
class TriggersGenerator:
- capture_zone_types = (Fob, )
+ capture_zone_types = (Fob,)
capture_zone_flag = 600
def __init__(self, mission: Mission, game: Game):
@@ -82,16 +77,18 @@ class TriggersGenerator:
airport.operating_level_air = 0
airport.operating_level_equipment = 0
airport.operating_level_fuel = 0
-
+
for airport in self.mission.terrain.airport_list():
if airport.id not in cp_ids:
airport.unlimited_fuel = True
airport.unlimited_munitions = True
airport.unlimited_aircrafts = True
-
+
for cp in self.game.theater.controlpoints:
if isinstance(cp, Airfield):
- self.mission.terrain.airport_by_id(cp.at.id).set_coalition(cp.captured and player_coalition or enemy_coalition)
+ self.mission.terrain.airport_by_id(cp.at.id).set_coalition(
+ cp.captured and player_coalition or enemy_coalition
+ )
def _set_skill(self, player_coalition: str, enemy_coalition: str):
"""
@@ -99,17 +96,28 @@ class TriggersGenerator:
"""
for coalition_name, coalition in self.mission.coalition.items():
if coalition_name == player_coalition:
- skill_level = self.game.settings.player_skill, self.game.settings.player_skill
+ skill_level = (
+ self.game.settings.player_skill,
+ self.game.settings.player_skill,
+ )
elif coalition_name == enemy_coalition:
- skill_level = self.game.settings.enemy_skill, self.game.settings.enemy_vehicle_skill
+ skill_level = (
+ self.game.settings.enemy_skill,
+ self.game.settings.enemy_vehicle_skill,
+ )
else:
continue
for country in coalition.countries.values():
- flying_groups = country.plane_group + country.helicopter_group # type: FlyingGroup
+ flying_groups = (
+ country.plane_group + country.helicopter_group
+ ) # type: FlyingGroup
for flying_group in flying_groups:
for plane_unit in flying_group.units:
- if plane_unit.skill != Skill.Client and plane_unit.skill != Skill.Player:
+ if (
+ plane_unit.skill != Skill.Client
+ and plane_unit.skill != Skill.Player
+ ):
plane_unit.skill = Skill(skill_level[0])
for vehicle_group in country.vehicle_group:
@@ -127,7 +135,9 @@ class TriggersGenerator:
added = []
for ground_object in cp.ground_objects:
if ground_object.obj_name not in added:
- zone = self.mission.triggers.add_triggerzone(ground_object.position, radius=10, hidden=True, name="MARK")
+ zone = self.mission.triggers.add_triggerzone(
+ ground_object.position, radius=10, hidden=True, name="MARK"
+ )
if cp.captured:
name = ground_object.obj_name + " [ALLY]"
else:
@@ -137,7 +147,9 @@ class TriggersGenerator:
added.append(ground_object.obj_name)
self.mission.triggerrules.triggers.append(mark_trigger)
- def _generate_capture_triggers(self, player_coalition: str, enemy_coalition: str) -> None:
+ def _generate_capture_triggers(
+ self, player_coalition: str, enemy_coalition: str
+ ) -> None:
"""Creates a pair of triggers for each control point of `cls.capture_zone_types`.
One for the initial capture of a control point, and one if it is recaptured.
Directly appends to the global `base_capture_events` var declared by `dcs_libaration.lua`
@@ -155,33 +167,41 @@ class TriggersGenerator:
defending_coalition = enemy_coalition
defend_coalition_int = 1
- trigger_zone = self.mission.triggers.add_triggerzone(cp.position, radius=3000, hidden=False, name="CAPTURE")
+ trigger_zone = self.mission.triggers.add_triggerzone(
+ cp.position, radius=3000, hidden=False, name="CAPTURE"
+ )
flag = self.get_capture_zone_flag()
capture_trigger = TriggerCondition(Event.NoEvent, "Capture Trigger")
- capture_trigger.add_condition(AllOfCoalitionOutsideZone(defending_coalition, trigger_zone.id))
- capture_trigger.add_condition(PartOfCoalitionInZone(attacking_coalition, trigger_zone.id, unit_type="GROUND"))
+ capture_trigger.add_condition(
+ AllOfCoalitionOutsideZone(defending_coalition, trigger_zone.id)
+ )
+ capture_trigger.add_condition(
+ PartOfCoalitionInZone(
+ attacking_coalition, trigger_zone.id, unit_type="GROUND"
+ )
+ )
capture_trigger.add_condition(FlagIsFalse(flag=flag))
script_string = String(
f'base_capture_events[#base_capture_events + 1] = "{cp.id}||{attack_coalition_int}||{cp.full_name}"'
)
- capture_trigger.add_action(DoScript(
- script_string
- )
- )
+ capture_trigger.add_action(DoScript(script_string))
capture_trigger.add_action(SetFlag(flag=flag))
self.mission.triggerrules.triggers.append(capture_trigger)
recapture_trigger = TriggerCondition(Event.NoEvent, "Capture Trigger")
- recapture_trigger.add_condition(AllOfCoalitionOutsideZone(attacking_coalition, trigger_zone.id))
- recapture_trigger.add_condition(PartOfCoalitionInZone(defending_coalition, trigger_zone.id, unit_type="GROUND"))
+ recapture_trigger.add_condition(
+ AllOfCoalitionOutsideZone(attacking_coalition, trigger_zone.id)
+ )
+ recapture_trigger.add_condition(
+ PartOfCoalitionInZone(
+ defending_coalition, trigger_zone.id, unit_type="GROUND"
+ )
+ )
recapture_trigger.add_condition(FlagIsTrue(flag=flag))
script_string = String(
f'base_capture_events[#base_capture_events + 1] = "{cp.id}||{defend_coalition_int}||{cp.full_name}"'
)
- recapture_trigger.add_action(DoScript(
- script_string
- )
- )
+ recapture_trigger.add_action(DoScript(script_string))
recapture_trigger.add_action(ClearFlag(flag=flag))
self.mission.triggerrules.triggers.append(recapture_trigger)
@@ -190,10 +210,14 @@ class TriggersGenerator:
enemy_coalition = "red"
player_cp, enemy_cp = self.game.theater.closest_opposing_control_points()
- self.mission.coalition["blue"].bullseye = {"x": enemy_cp.position.x,
- "y": enemy_cp.position.y}
- self.mission.coalition["red"].bullseye = {"x": player_cp.position.x,
- "y": player_cp.position.y}
+ self.mission.coalition["blue"].bullseye = {
+ "x": enemy_cp.position.x,
+ "y": enemy_cp.position.y,
+ }
+ self.mission.coalition["red"].bullseye = {
+ "x": player_cp.position.x,
+ "y": player_cp.position.y,
+ }
self._set_skill(player_coalition, enemy_coalition)
self._set_allegiances(player_coalition, enemy_coalition)
diff --git a/gen/units.py b/gen/units.py
index 005e1576..cfd16ab8 100644
--- a/gen/units.py
+++ b/gen/units.py
@@ -3,4 +3,4 @@
def meters_to_feet(meters: float) -> float:
"""Convers meters to feet."""
- return meters * 3.28084
\ No newline at end of file
+ return meters * 3.28084
diff --git a/gen/visualgen.py b/gen/visualgen.py
index e03da467..8c1982fa 100644
--- a/gen/visualgen.py
+++ b/gen/visualgen.py
@@ -103,7 +103,9 @@ class VisualGenerator:
if from_cp.is_global or to_cp.is_global:
continue
- plane_start, heading, distance = Conflict.frontline_vector(from_cp, to_cp, self.game.theater)
+ plane_start, heading, distance = Conflict.frontline_vector(
+ from_cp, to_cp, self.game.theater
+ )
if not plane_start:
continue
@@ -112,7 +114,9 @@ class VisualGenerator:
for k, v in FRONT_SMOKE_TYPE_CHANCES.items():
if random.randint(0, 100) <= k:
- pos = position.random_point_within(FRONT_SMOKE_RANDOM_SPREAD, FRONT_SMOKE_RANDOM_SPREAD)
+ pos = position.random_point_within(
+ FRONT_SMOKE_RANDOM_SPREAD, FRONT_SMOKE_RANDOM_SPREAD
+ )
if not self.game.theater.is_on_land(pos):
break
@@ -120,7 +124,8 @@ class VisualGenerator:
self.mission.country(self.game.enemy_country),
"",
_type=v,
- position=pos)
+ position=pos,
+ )
break
def _generate_stub_planes(self):
@@ -138,7 +143,14 @@ class VisualGenerator:
def generate_target_smokes(self, target):
spread = target.size * DESTINATION_SMOKE_DISTANCE_FACTOR
- for _ in range(0, int(target.size * DESTINATION_SMOKE_AMOUNT_FACTOR * (1.1 - target.base.strength))):
+ for _ in range(
+ 0,
+ int(
+ target.size
+ * DESTINATION_SMOKE_AMOUNT_FACTOR
+ * (1.1 - target.base.strength)
+ ),
+ ):
for k, v in DESTINATION_SMOKE_TYPE_CHANCES.items():
if random.randint(0, 100) <= k:
position = target.position.random_point_within(0, spread)
@@ -149,7 +161,8 @@ class VisualGenerator:
self.mission.country(self.game.enemy_country),
"",
_type=v,
- position=position)
+ position=position,
+ )
break
def generate_transportation_marker(self, at: Point):
@@ -157,7 +170,7 @@ class VisualGenerator:
self.mission.country(self.game.player_country),
"",
_type=MarkerSmoke,
- position=at
+ position=at,
)
def generate_transportation_destination(self, at: Point):
@@ -166,7 +179,7 @@ class VisualGenerator:
self.mission.country(self.game.player_country),
"",
_type=Outpost,
- position=at
+ position=at,
)
def generate(self):
diff --git a/pydcs b/pydcs
index 84f116c3..42de2ec3 160000
--- a/pydcs
+++ b/pydcs
@@ -1 +1 @@
-Subproject commit 84f116c35879b05470ad7f30b0c5b0bca26088a5
+Subproject commit 42de2ec352903d592ca123950b4b12a15ffa6544
diff --git a/qt_ui/dialogs.py b/qt_ui/dialogs.py
index 09fd2b93..bf9166e1 100644
--- a/qt_ui/dialogs.py
+++ b/qt_ui/dialogs.py
@@ -37,10 +37,7 @@ class Dialog:
def open_new_package_dialog(cls, mission_target: MissionTarget, parent=None):
"""Opens the dialog to create a new package with the given target."""
cls.new_package_dialog = QNewPackageDialog(
- cls.game_model,
- cls.game_model.ato_model,
- mission_target,
- parent=parent
+ cls.game_model, cls.game_model.ato_model, mission_target, parent=parent
)
cls.new_package_dialog.show()
@@ -48,20 +45,16 @@ class Dialog:
def open_edit_package_dialog(cls, package_model: PackageModel):
"""Opens the dialog to edit the given package."""
cls.edit_package_dialog = QEditPackageDialog(
- cls.game_model,
- cls.game_model.ato_model,
- package_model
+ cls.game_model, cls.game_model.ato_model, package_model
)
cls.edit_package_dialog.show()
@classmethod
- def open_edit_flight_dialog(cls, package_model: PackageModel,
- flight: Flight, parent=None) -> None:
+ def open_edit_flight_dialog(
+ cls, package_model: PackageModel, flight: Flight, parent=None
+ ) -> None:
"""Opens the dialog to edit the given flight."""
cls.edit_flight_dialog = QEditFlightDialog(
- cls.game_model,
- package_model,
- flight,
- parent=parent
+ cls.game_model, package_model, flight, parent=parent
)
cls.edit_flight_dialog.show()
diff --git a/qt_ui/displayoptions.py b/qt_ui/displayoptions.py
index 7b894b1d..423fe77f 100644
--- a/qt_ui/displayoptions.py
+++ b/qt_ui/displayoptions.py
@@ -20,6 +20,7 @@ class DisplayRule:
@value.setter
def value(self, value: bool) -> None:
from qt_ui.widgets.map.QLiberationMap import QLiberationMap
+
self._value = value
if QLiberationMap.instance is not None:
QLiberationMap.instance.reload_scene()
@@ -52,14 +53,16 @@ class FlightPathOptions(DisplayGroup):
class ThreatZoneOptions(DisplayGroup):
def __init__(self, coalition_name: str) -> None:
super().__init__(f"{coalition_name} Threat Zones")
- self.none = DisplayRule(
- f"Hide {coalition_name.lower()} threat zones", True)
+ self.none = DisplayRule(f"Hide {coalition_name.lower()} threat zones", True)
self.all = DisplayRule(
- f"Show full {coalition_name.lower()} threat zones", False)
+ f"Show full {coalition_name.lower()} threat zones", False
+ )
self.aircraft = DisplayRule(
- f"Show {coalition_name.lower()} aircraft threat tones", False)
+ f"Show {coalition_name.lower()} aircraft threat tones", False
+ )
self.air_defenses = DisplayRule(
- f"Show {coalition_name.lower()} air defenses threat zones", False)
+ f"Show {coalition_name.lower()} air defenses threat zones", False
+ )
class NavMeshOptions(DisplayGroup):
@@ -99,10 +102,8 @@ class DisplayOptions:
map_poly = DisplayRule("Map Polygon Debug Mode", False)
waypoint_info = DisplayRule("Waypoint Information", True)
culling = DisplayRule("Display Culling Zones", False)
- actual_frontline_pos = DisplayRule("Display Actual Frontline Location",
- False)
- barcap_commit_range = DisplayRule("Display selected BARCAP commit range",
- False)
+ actual_frontline_pos = DisplayRule("Display Actual Frontline Location", False)
+ barcap_commit_range = DisplayRule("Display selected BARCAP commit range", False)
flight_paths = FlightPathOptions()
blue_threat_zones = ThreatZoneOptions("Blue")
red_threat_zones = ThreatZoneOptions("Red")
diff --git a/qt_ui/liberation_install.py b/qt_ui/liberation_install.py
index a8044363..164c9323 100644
--- a/qt_ui/liberation_install.py
+++ b/qt_ui/liberation_install.py
@@ -20,7 +20,7 @@ def init():
if os.path.isfile(PREFERENCES_FILE_PATH):
try:
- with(open(PREFERENCES_FILE_PATH)) as prefs:
+ with (open(PREFERENCES_FILE_PATH)) as prefs:
pref_data = json.loads(prefs.read())
__dcs_saved_game_directory = pref_data["saved_game_dir"]
__dcs_installation_directory = pref_data["dcs_install_dir"]
@@ -37,9 +37,13 @@ def init():
else:
__last_save_file = ""
try:
- __dcs_saved_game_directory = dcs.installation.get_dcs_saved_games_directory()
+ __dcs_saved_game_directory = (
+ dcs.installation.get_dcs_saved_games_directory()
+ )
if os.path.exists(__dcs_saved_game_directory + ".openbeta"):
- __dcs_saved_game_directory = dcs.installation.get_dcs_saved_games_directory() + ".openbeta"
+ __dcs_saved_game_directory = (
+ dcs.installation.get_dcs_saved_games_directory() + ".openbeta"
+ )
except:
__dcs_saved_game_directory = ""
try:
@@ -69,10 +73,12 @@ def save_config():
global __dcs_saved_game_directory
global __dcs_installation_directory
global __last_save_file
- pref_data = {"saved_game_dir": __dcs_saved_game_directory,
- "dcs_install_dir": __dcs_installation_directory,
- "last_save_file": __last_save_file}
- with(open(PREFERENCES_FILE_PATH, "w")) as prefs:
+ pref_data = {
+ "saved_game_dir": __dcs_saved_game_directory,
+ "dcs_install_dir": __dcs_installation_directory,
+ "last_save_file": __last_save_file,
+ }
+ with (open(PREFERENCES_FILE_PATH, "w")) as prefs:
prefs.write(json.dumps(pref_data))
@@ -97,7 +103,9 @@ def get_last_save_file():
def replace_mission_scripting_file():
install_dir = get_dcs_install_directory()
- mission_scripting_path = os.path.join(install_dir, "Scripts", "MissionScripting.lua")
+ mission_scripting_path = os.path.join(
+ install_dir, "Scripts", "MissionScripting.lua"
+ )
liberation_scripting_path = "./resources/scripts/MissionScripting.lua"
backup_scripting_path = "./resources/scripts/MissionScripting.original.lua"
if os.path.isfile(mission_scripting_path):
@@ -116,9 +124,10 @@ def replace_mission_scripting_file():
def restore_original_mission_scripting():
install_dir = get_dcs_install_directory()
- mission_scripting_path = os.path.join(install_dir, "Scripts", "MissionScripting.lua")
+ mission_scripting_path = os.path.join(
+ install_dir, "Scripts", "MissionScripting.lua"
+ )
backup_scripting_path = "./resources/scripts/MissionScripting.original.lua"
if os.path.isfile(backup_scripting_path) and os.path.isfile(mission_scripting_path):
copyfile(backup_scripting_path, mission_scripting_path)
-
diff --git a/qt_ui/liberation_theme.py b/qt_ui/liberation_theme.py
index 79714209..0bc7dbb3 100644
--- a/qt_ui/liberation_theme.py
+++ b/qt_ui/liberation_theme.py
@@ -12,16 +12,16 @@ DEFAULT_THEME_INDEX = 1
# new themes can be added here
THEMES: Dict[int, Dict[str, str]] = {
- 0: {'themeName': 'Vanilla',
- 'themeFile': 'windows-style.css',
- 'themeIcons': 'medium',
- },
-
- 1: {'themeName': 'DCS World',
- 'themeFile': 'style-dcs.css',
- 'themeIcons': 'light',
- },
-
+ 0: {
+ "themeName": "Vanilla",
+ "themeFile": "windows-style.css",
+ "themeIcons": "medium",
+ },
+ 1: {
+ "themeName": "DCS World",
+ "themeFile": "style-dcs.css",
+ "themeIcons": "light",
+ },
}
@@ -32,7 +32,7 @@ def init():
if os.path.isfile(THEME_PREFERENCES_FILE_PATH):
try:
- with(open(THEME_PREFERENCES_FILE_PATH)) as prefs:
+ with (open(THEME_PREFERENCES_FILE_PATH)) as prefs:
pref_data = json.loads(prefs.read())
__theme_index = pref_data["theme_index"]
set_theme_index(__theme_index)
@@ -64,26 +64,24 @@ def get_theme_index():
# get theme name based on current index
def get_theme_name():
- theme_name = THEMES[get_theme_index()]['themeName']
+ theme_name = THEMES[get_theme_index()]["themeName"]
return theme_name
# get theme icon sub-folder name based on current index
def get_theme_icons():
- theme_icons = THEMES[get_theme_index()]['themeIcons']
+ theme_icons = THEMES[get_theme_index()]["themeIcons"]
return str(theme_icons)
# get theme stylesheet css based on current index
def get_theme_css_file():
- theme_file = THEMES[get_theme_index()]['themeFile']
+ theme_file = THEMES[get_theme_index()]["themeFile"]
return str(theme_file)
# save current theme index to json file
def save_theme_config():
- pref_data = {
- "theme_index": get_theme_index()
- }
- with(open(THEME_PREFERENCES_FILE_PATH, "w")) as prefs:
+ pref_data = {"theme_index": get_theme_index()}
+ with (open(THEME_PREFERENCES_FILE_PATH, "w")) as prefs:
prefs.write(json.dumps(pref_data))
diff --git a/qt_ui/main.py b/qt_ui/main.py
index b8984a2a..95b07f3d 100644
--- a/qt_ui/main.py
+++ b/qt_ui/main.py
@@ -31,28 +31,36 @@ from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
from qt_ui.windows.QLiberationWindow import QLiberationWindow
from qt_ui.windows.newgame.QCampaignList import Campaign
from qt_ui.windows.newgame.QNewGameWizard import DEFAULT_BUDGET
-from qt_ui.windows.preferences.QLiberationFirstStartWindow import \
- QLiberationFirstStartWindow
+from qt_ui.windows.preferences.QLiberationFirstStartWindow import (
+ QLiberationFirstStartWindow,
+)
def run_ui(game: Optional[Game] = None) -> None:
- os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1" # Potential fix for 4K screens
+ os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1" # Potential fix for 4K screens
app = QApplication(sys.argv)
# init the theme and load the stylesheet based on the theme index
liberation_theme.init()
- with open("./resources/stylesheets/"+liberation_theme.get_theme_css_file()) as stylesheet:
- logging.info('Loading stylesheet: %s', liberation_theme.get_theme_css_file())
+ with open(
+ "./resources/stylesheets/" + liberation_theme.get_theme_css_file()
+ ) as stylesheet:
+ logging.info("Loading stylesheet: %s", liberation_theme.get_theme_css_file())
app.setStyleSheet(stylesheet.read())
# Inject custom payload in pydcs framework
- custom_payloads = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..\\resources\\customized_payloads")
+ custom_payloads = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)),
+ "..\\resources\\customized_payloads",
+ )
if os.path.exists(custom_payloads):
dcs.unittype.FlyingType.payload_dirs.append(custom_payloads)
else:
# For release version the path is different.
- custom_payloads = os.path.join(os.path.dirname(os.path.realpath(__file__)),
- "resources\\customized_payloads")
+ custom_payloads = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)),
+ "resources\\customized_payloads",
+ )
if os.path.exists(custom_payloads):
dcs.unittype.FlyingType.payload_dirs.append(custom_payloads)
@@ -62,7 +70,11 @@ def run_ui(game: Optional[Game] = None) -> None:
window.exec_()
logging.info("Using {} as 'Saved Game Folder'".format(persistency.base_path()))
- logging.info("Using {} as 'DCS installation folder'".format(liberation_install.get_dcs_install_directory()))
+ logging.info(
+ "Using {} as 'DCS installation folder'".format(
+ liberation_install.get_dcs_install_directory()
+ )
+ )
# Splash screen setup
pixmap = QPixmap("./resources/ui/splash_screen.png")
@@ -83,7 +95,9 @@ def run_ui(game: Optional[Game] = None) -> None:
except:
error_dialog = QtWidgets.QErrorMessage()
error_dialog.setWindowTitle("Wrong DCS installation directory.")
- error_dialog.showMessage("Unable to modify Mission Scripting file. Possible issues with rights. Try running as admin, or please perform the modification of the MissionScripting file manually.")
+ error_dialog.showMessage(
+ "Unable to modify Mission Scripting file. Possible issues with rights. Try running as admin, or please perform the modification of the MissionScripting file manually."
+ )
error_dialog.exec_()
# Apply CSS (need works)
@@ -113,15 +127,15 @@ def parse_args() -> argparse.Namespace:
return path
parser.add_argument(
- "--warn-missing-weapon-data", action="store_true",
- help="Emits a warning for weapons without date or fallback information."
+ "--warn-missing-weapon-data",
+ action="store_true",
+ help="Emits a warning for weapons without date or fallback information.",
)
new_game = subparsers.add_parser("new-game")
new_game.add_argument(
- "campaign", type=path_arg,
- help="Path to the campaign to start."
+ "campaign", type=path_arg, help="Path to the campaign to start."
)
new_game.add_argument(
@@ -133,34 +147,38 @@ def parse_args() -> argparse.Namespace:
)
new_game.add_argument(
- "--supercarrier", action="store_true",
- help="Use the supercarrier module."
+ "--supercarrier", action="store_true", help="Use the supercarrier module."
)
new_game.add_argument(
- "--auto-procurement", action="store_true",
- help="Automate bluefor procurement."
+ "--auto-procurement", action="store_true", help="Automate bluefor procurement."
)
new_game.add_argument(
- "--inverted", action="store_true",
- help="Invert the campaign."
+ "--inverted", action="store_true", help="Invert the campaign."
)
return parser.parse_args()
-def create_game(campaign_path: Path, blue: str, red: str,
- supercarrier: bool, auto_procurement: bool,
- inverted: bool) -> Game:
+def create_game(
+ campaign_path: Path,
+ blue: str,
+ red: str,
+ supercarrier: bool,
+ auto_procurement: bool,
+ inverted: bool,
+) -> Game:
campaign = Campaign.from_json(campaign_path)
generator = GameGenerator(
- blue, red, campaign.load_theater(),
+ blue,
+ red,
+ campaign.load_theater(),
Settings(
supercarrier=supercarrier,
automate_runway_repair=auto_procurement,
automate_front_line_reinforcements=auto_procurement,
- automate_aircraft_reinforcements=auto_procurement
+ automate_aircraft_reinforcements=auto_procurement,
),
GeneratorSettings(
start_date=datetime.today(),
@@ -171,8 +189,8 @@ def create_game(campaign_path: Path, blue: str, red: str,
no_carrier=False,
no_lha=False,
no_player_navy=False,
- no_enemy_navy=False
- )
+ no_enemy_navy=False,
+ ),
)
return generator.generate()
@@ -201,9 +219,14 @@ def main():
lint_weapon_data()
if args.subcommand == "new-game":
- game = create_game(args.campaign, args.blue, args.red,
- args.supercarrier, args.auto_procurement,
- args.inverted)
+ game = create_game(
+ args.campaign,
+ args.blue,
+ args.red,
+ args.supercarrier,
+ args.auto_procurement,
+ args.inverted,
+ )
run_ui(game)
diff --git a/qt_ui/models.py b/qt_ui/models.py
index 670c52ad..cdc594d6 100644
--- a/qt_ui/models.py
+++ b/qt_ui/models.py
@@ -125,7 +125,8 @@ class PackageModel(QAbstractListModel):
"""Returns the text that should be displayed for the flight."""
estimator = TotEstimator(self.package)
delay = datetime.timedelta(
- seconds=int(estimator.mission_start_time(flight).total_seconds()))
+ seconds=int(estimator.mission_start_time(flight).total_seconds())
+ )
origin = flight.from_cp.name
return f"{flight} from {origin} in {delay}"
@@ -290,6 +291,7 @@ class GameModel:
This isn't a real Qt data model, but simplifies management of the game and
its ATO objects.
"""
+
def __init__(self, game: Optional[Game]) -> None:
self.game: Optional[Game] = game
if self.game is None:
diff --git a/qt_ui/uiconstants.py b/qt_ui/uiconstants.py
index 1ac196f6..7c7170fa 100644
--- a/qt_ui/uiconstants.py
+++ b/qt_ui/uiconstants.py
@@ -7,11 +7,11 @@ from game.theater.theatergroundobject import CATEGORY_MAP
from .liberation_theme import get_theme_icons
-URLS : Dict[str, str] = {
+URLS: Dict[str, str] = {
"Manual": "https://github.com/khopa/dcs_liberation/wiki",
"Repository": "https://github.com/khopa/dcs_liberation",
"ForumThread": "https://forums.eagle.ru/showthread.php?t=214834",
- "Issues": "https://github.com/khopa/dcs_liberation/issues"
+ "Issues": "https://github.com/khopa/dcs_liberation/issues",
}
LABELS_OPTIONS = ["Full", "Abbreviated", "Dot Only", "Off"]
@@ -28,46 +28,36 @@ FONT_MAP = QFont(FONT_NAME, 10, weight=75, italic=False)
COLORS: Dict[str, QColor] = {
"white": QColor(255, 255, 255),
"white_transparent": QColor(255, 255, 255, 35),
-
"light_red": QColor(231, 92, 83, 90),
"red": QColor(200, 80, 80),
"dark_red": QColor(140, 20, 20),
"red_transparent": QColor(227, 32, 0, 20),
"transparent": QColor(255, 255, 255, 0),
-
"light_blue": QColor(105, 182, 240, 90),
"blue": QColor(0, 132, 255),
"dark_blue": QColor(45, 62, 80),
"sea_blue": QColor(52, 68, 85),
"sea_blue_transparent": QColor(52, 68, 85, 150),
"blue_transparent": QColor(0, 132, 255, 20),
-
"purple": QColor(187, 137, 255),
"yellow": QColor(238, 225, 123),
-
"bright_red": QColor(150, 80, 80),
"super_red": QColor(227, 32, 0),
-
"green": QColor(128, 186, 128),
"light_green": QColor(223, 255, 173),
"light_green_transparent": QColor(180, 255, 140, 50),
"bright_green": QColor(64, 200, 64),
-
"black": QColor(0, 0, 0),
"black_transparent": QColor(0, 0, 0, 5),
-
"orange": QColor(254, 125, 10),
-
"night_overlay": QColor(12, 20, 69),
"dawn_dust_overlay": QColor(46, 38, 85),
-
"grey": QColor(150, 150, 150),
"grey_transparent": QColor(150, 150, 150, 150),
"dark_grey": QColor(75, 75, 75),
"dark_grey_transparent": QColor(75, 75, 75, 150),
"dark_dark_grey": QColor(48, 48, 48),
"dark_dark_grey_transparent": QColor(48, 48, 48, 150),
-
}
CP_SIZE = 12
@@ -78,29 +68,44 @@ VEHICLE_BANNERS: Dict[str, QPixmap] = {}
VEHICLES_ICONS: Dict[str, QPixmap] = {}
ICONS: Dict[str, QPixmap] = {}
+
def load_icons():
- ICONS["New"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/new.png")
- ICONS["Open"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/open.png")
- ICONS["Save"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/save.png")
- ICONS["Discord"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/discord.png")
- ICONS["Github"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/github.png")
+ ICONS["New"] = QPixmap("./resources/ui/misc/" + get_theme_icons() + "/new.png")
+ ICONS["Open"] = QPixmap("./resources/ui/misc/" + get_theme_icons() + "/open.png")
+ ICONS["Save"] = QPixmap("./resources/ui/misc/" + get_theme_icons() + "/save.png")
+ ICONS["Discord"] = QPixmap(
+ "./resources/ui/misc/" + get_theme_icons() + "/discord.png"
+ )
+ ICONS["Github"] = QPixmap(
+ "./resources/ui/misc/" + get_theme_icons() + "/github.png"
+ )
-
- ICONS["Control Points"] = QPixmap("./resources/ui/misc/" + get_theme_icons() + "/circle.png")
- ICONS["Ground Objects"] = QPixmap("./resources/ui/misc/" + get_theme_icons() + "/industry.png")
- ICONS["Lines"] = QPixmap("./resources/ui/misc/" + get_theme_icons() + "/arrows-h.png")
- ICONS["Waypoint Information"] = QPixmap("./resources/ui/misc/" + get_theme_icons() + "/info.png")
- ICONS["Map Polygon Debug Mode"] = QPixmap("./resources/ui/misc/" + get_theme_icons() + "/map.png")
+ ICONS["Control Points"] = QPixmap(
+ "./resources/ui/misc/" + get_theme_icons() + "/circle.png"
+ )
+ ICONS["Ground Objects"] = QPixmap(
+ "./resources/ui/misc/" + get_theme_icons() + "/industry.png"
+ )
+ ICONS["Lines"] = QPixmap(
+ "./resources/ui/misc/" + get_theme_icons() + "/arrows-h.png"
+ )
+ ICONS["Waypoint Information"] = QPixmap(
+ "./resources/ui/misc/" + get_theme_icons() + "/info.png"
+ )
+ ICONS["Map Polygon Debug Mode"] = QPixmap(
+ "./resources/ui/misc/" + get_theme_icons() + "/map.png"
+ )
ICONS["Ally SAM Threat Range"] = QPixmap("./resources/ui/misc/blue-sam.png")
ICONS["Enemy SAM Threat Range"] = QPixmap("./resources/ui/misc/red-sam.png")
ICONS["SAM Detection Range"] = QPixmap("./resources/ui/misc/detection-sam.png")
- ICONS["Display Culling Zones"] = QPixmap("./resources/ui/misc/" + get_theme_icons() + "/eraser.png")
+ ICONS["Display Culling Zones"] = QPixmap(
+ "./resources/ui/misc/" + get_theme_icons() + "/eraser.png"
+ )
ICONS["Hide Flight Paths"] = QPixmap("./resources/ui/misc/hide-flight-path.png")
ICONS["Show Selected Flight Path"] = QPixmap("./resources/ui/misc/flight-path.png")
ICONS["Show All Flight Paths"] = QPixmap("./resources/ui/misc/all-flight-paths.png")
-
ICONS["Hangar"] = QPixmap("./resources/ui/misc/hangar.png")
ICONS["Terrain_Caucasus"] = QPixmap("./resources/ui/terrain_caucasus.gif")
@@ -115,18 +120,32 @@ def load_icons():
ICONS["Dusk"] = QPixmap("./resources/ui/conditions/timeofday/dusk.png")
ICONS["Night"] = QPixmap("./resources/ui/conditions/timeofday/night.png")
- ICONS["Money"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/money_icon.png")
- ICONS["PassTurn"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/hourglass.png")
- ICONS["Proceed"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/proceed.png")
- ICONS["Settings"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/settings.png")
- ICONS["Statistics"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/statistics.png")
- ICONS["Ordnance"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/ordnance_icon.png")
+ ICONS["Money"] = QPixmap(
+ "./resources/ui/misc/" + get_theme_icons() + "/money_icon.png"
+ )
+ ICONS["PassTurn"] = QPixmap(
+ "./resources/ui/misc/" + get_theme_icons() + "/hourglass.png"
+ )
+ ICONS["Proceed"] = QPixmap(
+ "./resources/ui/misc/" + get_theme_icons() + "/proceed.png"
+ )
+ ICONS["Settings"] = QPixmap(
+ "./resources/ui/misc/" + get_theme_icons() + "/settings.png"
+ )
+ ICONS["Statistics"] = QPixmap(
+ "./resources/ui/misc/" + get_theme_icons() + "/statistics.png"
+ )
+ ICONS["Ordnance"] = QPixmap(
+ "./resources/ui/misc/" + get_theme_icons() + "/ordnance_icon.png"
+ )
ICONS["target"] = QPixmap("./resources/ui/ground_assets/target.png")
ICONS["cleared"] = QPixmap("./resources/ui/ground_assets/cleared.png")
for category in CATEGORY_MAP.keys():
ICONS[category] = QPixmap("./resources/ui/ground_assets/" + category + ".png")
- ICONS[category + "_blue"] = QPixmap("./resources/ui/ground_assets/" + category + "_blue.png")
+ ICONS[category + "_blue"] = QPixmap(
+ "./resources/ui/ground_assets/" + category + "_blue.png"
+ )
ICONS["destroyed"] = QPixmap("./resources/ui/ground_assets/destroyed.png")
ICONS["ship"] = QPixmap("./resources/ui/ground_assets/ship.png")
ICONS["ship_blue"] = QPixmap("./resources/ui/ground_assets/ship_blue.png")
@@ -135,11 +154,19 @@ def load_icons():
ICONS["nothreat"] = QPixmap("./resources/ui/ground_assets/nothreat.png")
ICONS["nothreat_blue"] = QPixmap("./resources/ui/ground_assets/nothreat_blue.png")
- ICONS["Generator"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/generator.png")
- ICONS["Missile"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/missile.png")
- ICONS["Cheat"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/cheat.png")
- ICONS["Plugins"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/plugins.png")
- ICONS["PluginsOptions"] = QPixmap("./resources/ui/misc/"+get_theme_icons()+"/pluginsoptions.png")
+ ICONS["Generator"] = QPixmap(
+ "./resources/ui/misc/" + get_theme_icons() + "/generator.png"
+ )
+ ICONS["Missile"] = QPixmap(
+ "./resources/ui/misc/" + get_theme_icons() + "/missile.png"
+ )
+ ICONS["Cheat"] = QPixmap("./resources/ui/misc/" + get_theme_icons() + "/cheat.png")
+ ICONS["Plugins"] = QPixmap(
+ "./resources/ui/misc/" + get_theme_icons() + "/plugins.png"
+ )
+ ICONS["PluginsOptions"] = QPixmap(
+ "./resources/ui/misc/" + get_theme_icons() + "/pluginsoptions.png"
+ )
ICONS["TaskCAS"] = QPixmap("./resources/ui/tasks/cas.png")
ICONS["TaskCAP"] = QPixmap("./resources/ui/tasks/cap.png")
@@ -150,20 +177,46 @@ def load_icons():
Weather Icons
"""
ICONS["Weather_winds"] = QPixmap("./resources/ui/conditions/weather/winds.png")
- ICONS["Weather_day-clear"] = QPixmap("./resources/ui/conditions/weather/day-clear.png")
- ICONS["Weather_day-cloudy-fog"] = QPixmap("./resources/ui/conditions/weather/day-cloudy-fog.png")
+ ICONS["Weather_day-clear"] = QPixmap(
+ "./resources/ui/conditions/weather/day-clear.png"
+ )
+ ICONS["Weather_day-cloudy-fog"] = QPixmap(
+ "./resources/ui/conditions/weather/day-cloudy-fog.png"
+ )
ICONS["Weather_day-fog"] = QPixmap("./resources/ui/conditions/weather/day-fog.png")
- ICONS["Weather_day-partly-cloudy"] = QPixmap("./resources/ui/conditions/weather/day-partly-cloudy.png")
- ICONS["Weather_day-rain"] = QPixmap("./resources/ui/conditions/weather/day-rain.png")
- ICONS["Weather_day-thunderstorm"] = QPixmap("./resources/ui/conditions/weather/day-thunderstorm.png")
- ICONS["Weather_day-totally-cloud"] = QPixmap("./resources/ui/conditions/weather/day-totally-cloud.png")
- ICONS["Weather_night-clear"] = QPixmap("./resources/ui/conditions/weather/night-clear.png")
- ICONS["Weather_night-cloudy-fog"] = QPixmap("./resources/ui/conditions/weather/night-cloudy-fog.png")
- ICONS["Weather_night-fog"] = QPixmap("./resources/ui/conditions/weather/night-fog.png")
- ICONS["Weather_night-partly-cloudy"] = QPixmap("./resources/ui/conditions/weather/night-partly-cloudy.png")
- ICONS["Weather_night-rain"] = QPixmap("./resources/ui/conditions/weather/night-rain.png")
- ICONS["Weather_night-thunderstorm"] = QPixmap("./resources/ui/conditions/weather/night-thunderstorm.png")
- ICONS["Weather_night-totally-cloud"] = QPixmap("./resources/ui/conditions/weather/night-totally-cloud.png")
+ ICONS["Weather_day-partly-cloudy"] = QPixmap(
+ "./resources/ui/conditions/weather/day-partly-cloudy.png"
+ )
+ ICONS["Weather_day-rain"] = QPixmap(
+ "./resources/ui/conditions/weather/day-rain.png"
+ )
+ ICONS["Weather_day-thunderstorm"] = QPixmap(
+ "./resources/ui/conditions/weather/day-thunderstorm.png"
+ )
+ ICONS["Weather_day-totally-cloud"] = QPixmap(
+ "./resources/ui/conditions/weather/day-totally-cloud.png"
+ )
+ ICONS["Weather_night-clear"] = QPixmap(
+ "./resources/ui/conditions/weather/night-clear.png"
+ )
+ ICONS["Weather_night-cloudy-fog"] = QPixmap(
+ "./resources/ui/conditions/weather/night-cloudy-fog.png"
+ )
+ ICONS["Weather_night-fog"] = QPixmap(
+ "./resources/ui/conditions/weather/night-fog.png"
+ )
+ ICONS["Weather_night-partly-cloudy"] = QPixmap(
+ "./resources/ui/conditions/weather/night-partly-cloudy.png"
+ )
+ ICONS["Weather_night-rain"] = QPixmap(
+ "./resources/ui/conditions/weather/night-rain.png"
+ )
+ ICONS["Weather_night-thunderstorm"] = QPixmap(
+ "./resources/ui/conditions/weather/night-thunderstorm.png"
+ )
+ ICONS["Weather_night-totally-cloud"] = QPixmap(
+ "./resources/ui/conditions/weather/night-totally-cloud.png"
+ )
EVENT_ICONS: Dict[str, QPixmap] = {}
@@ -172,12 +225,17 @@ EVENT_ICONS: Dict[str, QPixmap] = {}
def load_event_icons():
for image in os.listdir("./resources/ui/events/"):
if image.endswith(".PNG"):
- EVENT_ICONS[image[:-4]] = QPixmap(os.path.join("./resources/ui/events/", image))
+ EVENT_ICONS[image[:-4]] = QPixmap(
+ os.path.join("./resources/ui/events/", image)
+ )
+
def load_aircraft_icons():
for aircraft in os.listdir("./resources/ui/units/aircrafts/icons/"):
if aircraft.endswith(".jpg"):
- AIRCRAFT_ICONS[aircraft[:-7]] = QPixmap(os.path.join("./resources/ui/units/aircrafts/icons/", aircraft))
+ AIRCRAFT_ICONS[aircraft[:-7]] = QPixmap(
+ os.path.join("./resources/ui/units/aircrafts/icons/", aircraft)
+ )
AIRCRAFT_ICONS["F-16C_50"] = AIRCRAFT_ICONS["F-16C"]
AIRCRAFT_ICONS["FA-18C_hornet"] = AIRCRAFT_ICONS["FA-18C"]
AIRCRAFT_ICONS["A-10C_2"] = AIRCRAFT_ICONS["A-10C"]
@@ -186,14 +244,22 @@ def load_aircraft_icons():
def load_vehicle_icons():
for vehicle in os.listdir("./resources/ui/units/vehicles/icons/"):
if vehicle.endswith(".jpg"):
- VEHICLES_ICONS[vehicle[:-7]] = QPixmap(os.path.join("./resources/ui/units/vehicles/icons/", vehicle))
+ VEHICLES_ICONS[vehicle[:-7]] = QPixmap(
+ os.path.join("./resources/ui/units/vehicles/icons/", vehicle)
+ )
+
def load_aircraft_banners():
for aircraft in os.listdir("./resources/ui/units/aircrafts/banners/"):
if aircraft.endswith(".jpg"):
- AIRCRAFT_BANNERS[aircraft[:-7]] = QPixmap(os.path.join("./resources/ui/units/aircrafts/banners/", aircraft))
+ AIRCRAFT_BANNERS[aircraft[:-7]] = QPixmap(
+ os.path.join("./resources/ui/units/aircrafts/banners/", aircraft)
+ )
+
def load_vehicle_banners():
for aircraft in os.listdir("./resources/ui/units/vehicles/banners/"):
if aircraft.endswith(".jpg"):
- VEHICLE_BANNERS[aircraft[:-7]] = QPixmap(os.path.join("./resources/ui/units/vehicles/banners/", aircraft))
\ No newline at end of file
+ VEHICLE_BANNERS[aircraft[:-7]] = QPixmap(
+ os.path.join("./resources/ui/units/vehicles/banners/", aircraft)
+ )
diff --git a/qt_ui/widgets/QBudgetBox.py b/qt_ui/widgets/QBudgetBox.py
index c8ba24dd..fe20ab44 100644
--- a/qt_ui/widgets/QBudgetBox.py
+++ b/qt_ui/widgets/QBudgetBox.py
@@ -35,7 +35,9 @@ class QBudgetBox(QGroupBox):
:param budget: Current money available
:param reward: Planned reward for next turn
"""
- self.money_amount.setText(str(round(budget,2)) + "M (+" + str(round(reward,2)) + "M)")
+ self.money_amount.setText(
+ str(round(budget, 2)) + "M (+" + str(round(reward, 2)) + "M)"
+ )
def setGame(self, game):
if game is None:
@@ -47,4 +49,4 @@ class QBudgetBox(QGroupBox):
def openFinances(self):
self.subwindow = QFinancesMenu(self.game)
- self.subwindow.show()
\ No newline at end of file
+ self.subwindow.show()
diff --git a/qt_ui/widgets/QConditionsWidget.py b/qt_ui/widgets/QConditionsWidget.py
index 89cf2cdb..661905f4 100644
--- a/qt_ui/widgets/QConditionsWidget.py
+++ b/qt_ui/widgets/QConditionsWidget.py
@@ -18,10 +18,12 @@ class QTimeTurnWidget(QGroupBox):
"""
UI Component to display current turn and time info
"""
-
+
def __init__(self):
super(QTimeTurnWidget, self).__init__("Turn")
- self.setStyleSheet('padding: 0px; margin-left: 5px; margin-right: 0px; margin-top: 1ex; margin-bottom: 5px; border-right: 0px')
+ self.setStyleSheet(
+ "padding: 0px; margin-left: 5px; margin-right: 0px; margin-top: 1ex; margin-bottom: 5px; border-right: 0px"
+ )
self.icons = {
TimeOfDay.Dawn: CONST.ICONS["Dawn"],
@@ -55,20 +57,21 @@ class QTimeTurnWidget(QGroupBox):
"""
self.daytime_icon.setPixmap(self.icons[conditions.time_of_day])
self.date_display.setText(conditions.start_time.strftime("%d %b %Y"))
- self.time_display.setText(
- conditions.start_time.strftime("%H:%M:%S Local"))
+ self.time_display.setText(conditions.start_time.strftime("%H:%M:%S Local"))
self.setTitle(f"Turn {turn}")
+
class QWeatherWidget(QGroupBox):
"""
UI Component to display current weather forecast
"""
+
turn = None
conditions = None
def __init__(self):
super(QWeatherWidget, self).__init__("")
- self.setProperty('style', 'QWeatherWidget')
+ self.setProperty("style", "QWeatherWidget")
self.icons = {
TimeOfDay.Dawn: CONST.ICONS["Dawn"],
@@ -83,17 +86,15 @@ class QWeatherWidget(QGroupBox):
self.makeWeatherIcon()
self.makeCloudRainFogWidget()
self.makeWindsWidget()
-
+
def makeWeatherIcon(self):
- """Makes the Weather Icon Widget
- """
+ """Makes the Weather Icon Widget"""
self.weather_icon = QLabel()
self.weather_icon.setPixmap(self.icons[TimeOfDay.Dawn])
self.layout.addWidget(self.weather_icon)
def makeCloudRainFogWidget(self):
- """Makes the Cloud, Rain, Fog Widget
- """
+ """Makes the Cloud, Rain, Fog Widget"""
self.textLayout = QVBoxLayout()
self.layout.addLayout(self.textLayout)
@@ -107,43 +108,41 @@ class QWeatherWidget(QGroupBox):
self.textLayout.addWidget(self.forecastFog)
def makeWindsWidget(self):
- """Factory for the winds widget.
- """
+ """Factory for the winds widget."""
windsLayout = QGridLayout()
self.layout.addLayout(windsLayout)
- windsLayout.addWidget(self.makeIcon(CONST.ICONS['Weather_winds']), 0, 0, 3, 1)
+ windsLayout.addWidget(self.makeIcon(CONST.ICONS["Weather_winds"]), 0, 0, 3, 1)
- windsLayout.addWidget(self.makeLabel('At GL'), 0, 1)
- windsLayout.addWidget(self.makeLabel('At FL08'), 1, 1)
- windsLayout.addWidget(self.makeLabel('At FL26'), 2, 1)
+ windsLayout.addWidget(self.makeLabel("At GL"), 0, 1)
+ windsLayout.addWidget(self.makeLabel("At FL08"), 1, 1)
+ windsLayout.addWidget(self.makeLabel("At FL26"), 2, 1)
- self.windGLSpeedLabel = self.makeLabel('0kts')
- self.windGLDirLabel = self.makeLabel('0º')
+ self.windGLSpeedLabel = self.makeLabel("0kts")
+ self.windGLDirLabel = self.makeLabel("0º")
windsLayout.addWidget(self.windGLSpeedLabel, 0, 2)
windsLayout.addWidget(self.windGLDirLabel, 0, 3)
-
- self.windFL08SpeedLabel = self.makeLabel('0kts')
- self.windFL08DirLabel = self.makeLabel('0º')
+ self.windFL08SpeedLabel = self.makeLabel("0kts")
+ self.windFL08DirLabel = self.makeLabel("0º")
windsLayout.addWidget(self.windFL08SpeedLabel, 1, 2)
windsLayout.addWidget(self.windFL08DirLabel, 1, 3)
- self.windFL26SpeedLabel = self.makeLabel('0kts')
- self.windFL26DirLabel = self.makeLabel('0º')
+ self.windFL26SpeedLabel = self.makeLabel("0kts")
+ self.windFL26DirLabel = self.makeLabel("0º")
windsLayout.addWidget(self.windFL26SpeedLabel, 2, 2)
windsLayout.addWidget(self.windFL26DirLabel, 2, 3)
- def makeLabel(self, text: str = '') -> QLabel:
+ def makeLabel(self, text: str = "") -> QLabel:
"""Shorthand to generate a QLabel with widget standard style
:arg pixmap QPixmap for the icon.
"""
label = QLabel(text)
- label.setProperty('style', 'text-sm')
+ label.setProperty("style", "text-sm")
return label
-
+
def makeIcon(self, pixmap: QPixmap) -> QLabel:
"""Shorthand to generate a QIcon with pixmap.
@@ -167,26 +166,28 @@ class QWeatherWidget(QGroupBox):
self.updateWinds()
def updateWinds(self):
- """Updates the UI with the current conditions wind info.
- """
+ """Updates the UI with the current conditions wind info."""
windGlSpeed = mps(self.conditions.weather.wind.at_0m.speed or 0)
- windGlDir = str(self.conditions.weather.wind.at_0m.direction or 0).rjust(3, '0')
- self.windGLSpeedLabel.setText(f'{int(windGlSpeed.knots)}kts')
- self.windGLDirLabel.setText(f'{windGlDir}º')
+ windGlDir = str(self.conditions.weather.wind.at_0m.direction or 0).rjust(3, "0")
+ self.windGLSpeedLabel.setText(f"{int(windGlSpeed.knots)}kts")
+ self.windGLDirLabel.setText(f"{windGlDir}º")
windFL08Speed = mps(self.conditions.weather.wind.at_2000m.speed or 0)
- windFL08Dir = str(self.conditions.weather.wind.at_2000m.direction or 0).rjust(3, '0')
- self.windFL08SpeedLabel.setText(f'{int(windFL08Speed.knots)}kts')
- self.windFL08DirLabel.setText(f'{windFL08Dir}º')
+ windFL08Dir = str(self.conditions.weather.wind.at_2000m.direction or 0).rjust(
+ 3, "0"
+ )
+ self.windFL08SpeedLabel.setText(f"{int(windFL08Speed.knots)}kts")
+ self.windFL08DirLabel.setText(f"{windFL08Dir}º")
windFL26Speed = mps(self.conditions.weather.wind.at_8000m.speed or 0)
- windFL26Dir = str(self.conditions.weather.wind.at_8000m.direction or 0).rjust(3, '0')
- self.windFL26SpeedLabel.setText(f'{int(windFL26Speed.knots)}kts')
- self.windFL26DirLabel.setText(f'{windFL26Dir}º')
+ windFL26Dir = str(self.conditions.weather.wind.at_8000m.direction or 0).rjust(
+ 3, "0"
+ )
+ self.windFL26SpeedLabel.setText(f"{int(windFL26Speed.knots)}kts")
+ self.windFL26DirLabel.setText(f"{windFL26Dir}º")
def updateForecast(self):
- """Updates the Forecast Text and icon with the current conditions wind info.
- """
+ """Updates the Forecast Text and icon with the current conditions wind info."""
icon = []
if self.conditions.weather.clouds is None:
cloudDensity = 0
@@ -197,44 +198,44 @@ class QWeatherWidget(QGroupBox):
fog = self.conditions.weather.fog or None
is_night = self.conditions.time_of_day == TimeOfDay.Night
- time = 'night' if is_night else 'day'
+ time = "night" if is_night else "day"
if cloudDensity <= 0:
- self.forecastClouds.setText('Sunny')
- icon = [time, 'clear']
-
+ self.forecastClouds.setText("Sunny")
+ icon = [time, "clear"]
+
if cloudDensity > 0 and cloudDensity < 3:
- self.forecastClouds.setText('Partly Cloudy')
- icon = [time, 'partly-cloudy']
+ self.forecastClouds.setText("Partly Cloudy")
+ icon = [time, "partly-cloudy"]
if cloudDensity >= 3 and cloudDensity < 5:
- self.forecastClouds.setText('Mostly Cloudy')
- icon = [time, 'partly-cloudy']
+ self.forecastClouds.setText("Mostly Cloudy")
+ icon = [time, "partly-cloudy"]
if cloudDensity >= 5:
- self.forecastClouds.setText('Totally Cloudy')
- icon = [time, 'partly-cloudy']
+ self.forecastClouds.setText("Totally Cloudy")
+ icon = [time, "partly-cloudy"]
if precipitation == PydcsWeather.Preceptions.Rain:
- self.forecastRain.setText('Rain')
- icon = [time, 'rain']
+ self.forecastRain.setText("Rain")
+ icon = [time, "rain"]
elif precipitation == PydcsWeather.Preceptions.Thunderstorm:
- self.forecastRain.setText('Thunderstorm')
- icon = [time, 'thunderstorm']
-
+ self.forecastRain.setText("Thunderstorm")
+ icon = [time, "thunderstorm"]
+
else:
- self.forecastRain.setText('No Rain')
+ self.forecastRain.setText("No Rain")
if not fog:
- self.forecastFog.setText('No fog')
- else:
+ self.forecastFog.setText("No fog")
+ else:
visibility = round(fog.visibility.nautical_miles, 1)
- self.forecastFog.setText(f'Fog vis: {visibility}nm')
- icon = [time, ('cloudy' if cloudDensity > 1 else None), 'fog']
+ self.forecastFog.setText(f"Fog vis: {visibility}nm")
+ icon = [time, ("cloudy" if cloudDensity > 1 else None), "fog"]
- icon_key = "Weather_{}".format('-'.join(filter(None.__ne__, icon)))
- icon = CONST.ICONS.get(icon_key) or CONST.ICONS['Weather_night-partly-cloudy']
+ icon_key = "Weather_{}".format("-".join(filter(None.__ne__, icon)))
+ icon = CONST.ICONS.get(icon_key) or CONST.ICONS["Weather_night-partly-cloudy"]
self.weather_icon.setPixmap(icon)
@@ -245,7 +246,7 @@ class QConditionsWidget(QFrame):
def __init__(self):
super(QConditionsWidget, self).__init__()
- self.setProperty('style', 'QConditionsWidget')
+ self.setProperty("style", "QConditionsWidget")
self.layout = QGridLayout()
self.layout.setContentsMargins(0, 0, 0, 0)
@@ -254,11 +255,13 @@ class QConditionsWidget(QFrame):
self.setLayout(self.layout)
self.time_turn_widget = QTimeTurnWidget()
- self.time_turn_widget.setStyleSheet('QGroupBox { margin-right: 0px; }')
+ self.time_turn_widget.setStyleSheet("QGroupBox { margin-right: 0px; }")
self.layout.addWidget(self.time_turn_widget, 0, 0)
self.weather_widget = QWeatherWidget()
- self.weather_widget.setStyleSheet('QGroupBox { margin-top: 5px; margin-left: 0px; border-left: 0px; }')
+ self.weather_widget.setStyleSheet(
+ "QGroupBox { margin-top: 5px; margin-left: 0px; border-left: 0px; }"
+ )
self.weather_widget.hide()
self.layout.addWidget(self.weather_widget, 0, 1)
@@ -271,4 +274,3 @@ class QConditionsWidget(QFrame):
self.time_turn_widget.setCurrentTurn(turn, conditions)
self.weather_widget.setCurrentTurn(turn, conditions)
self.weather_widget.show()
-
diff --git a/qt_ui/widgets/QDebriefingInformation.py b/qt_ui/widgets/QDebriefingInformation.py
index abf6caea..9c7ddcef 100644
--- a/qt_ui/widgets/QDebriefingInformation.py
+++ b/qt_ui/widgets/QDebriefingInformation.py
@@ -8,4 +8,4 @@ class QDebriefingInformation(QFrame):
def __init__(self):
super(QDebriefingInformation, self).__init__()
- self.init_ui()
\ No newline at end of file
+ self.init_ui()
diff --git a/qt_ui/widgets/QFactionsInfos.py b/qt_ui/widgets/QFactionsInfos.py
index 79b5848d..40369356 100644
--- a/qt_ui/widgets/QFactionsInfos.py
+++ b/qt_ui/widgets/QFactionsInfos.py
@@ -16,10 +16,10 @@ class QFactionsInfos(QGroupBox):
self.layout = QGridLayout()
self.layout.setSpacing(0)
- self.layout.addWidget(QLabel("Player : "),0,0)
- self.layout.addWidget(self.player_name,0,1)
- self.layout.addWidget(QLabel("Enemy : "),1,0)
- self.layout.addWidget(self.enemy_name,1,1)
+ self.layout.addWidget(QLabel("Player : "), 0, 0)
+ self.layout.addWidget(self.player_name, 0, 1)
+ self.layout.addWidget(QLabel("Enemy : "), 1, 0)
+ self.layout.addWidget(self.enemy_name, 1, 1)
self.setLayout(self.layout)
def setGame(self, game: Game):
@@ -29,4 +29,3 @@ class QFactionsInfos(QGroupBox):
else:
self.player_name.setText("")
self.enemy_name.setText("")
-
diff --git a/qt_ui/widgets/QFlightSizeSpinner.py b/qt_ui/widgets/QFlightSizeSpinner.py
index a2619507..30cb8002 100644
--- a/qt_ui/widgets/QFlightSizeSpinner.py
+++ b/qt_ui/widgets/QFlightSizeSpinner.py
@@ -5,8 +5,9 @@ from PySide2.QtWidgets import QSpinBox
class QFlightSizeSpinner(QSpinBox):
"""Spin box for selecting the number of aircraft in a flight."""
- def __init__(self, min_size: int = 1, max_size: int = 4,
- default_size: int = 2) -> None:
+ def __init__(
+ self, min_size: int = 1, max_size: int = 4, default_size: int = 2
+ ) -> None:
super().__init__()
self.setMinimum(min_size)
self.setMaximum(max_size)
diff --git a/qt_ui/widgets/QIntelBox.py b/qt_ui/widgets/QIntelBox.py
index 3925baf3..2e3eb7e8 100644
--- a/qt_ui/widgets/QIntelBox.py
+++ b/qt_ui/widgets/QIntelBox.py
@@ -94,12 +94,16 @@ class QIntelBox(QGroupBox):
data = self.game.game_stats.data_per_turn[-1]
- self.air_strength.setText(self.forces_strength_text(
- data.allied_units.aircraft_count,
- data.enemy_units.aircraft_count))
- self.ground_strength.setText(self.forces_strength_text(
- data.allied_units.vehicles_count,
- data.enemy_units.vehicles_count))
+ self.air_strength.setText(
+ self.forces_strength_text(
+ data.allied_units.aircraft_count, data.enemy_units.aircraft_count
+ )
+ )
+ self.ground_strength.setText(
+ self.forces_strength_text(
+ data.allied_units.vehicles_count, data.enemy_units.vehicles_count
+ )
+ )
self.economic_strength.setText(self.economic_strength_text())
def open_details_window(self) -> None:
diff --git a/qt_ui/widgets/QLabeledWidget.py b/qt_ui/widgets/QLabeledWidget.py
index 91bb52bb..547f8b7b 100644
--- a/qt_ui/widgets/QLabeledWidget.py
+++ b/qt_ui/widgets/QLabeledWidget.py
@@ -12,8 +12,9 @@ class QLabeledWidget(QHBoxLayout):
label is used to name the input.
"""
- def __init__(self, text: str, widget: QWidget,
- tooltip: Optional[str] = None) -> None:
+ def __init__(
+ self, text: str, widget: QWidget, tooltip: Optional[str] = None
+ ) -> None:
super().__init__()
label = QLabel(text)
self.addWidget(label)
diff --git a/qt_ui/widgets/QTopPanel.py b/qt_ui/widgets/QTopPanel.py
index a01b2953..68834d28 100644
--- a/qt_ui/widgets/QTopPanel.py
+++ b/qt_ui/widgets/QTopPanel.py
@@ -22,15 +22,13 @@ from qt_ui.widgets.QFactionsInfos import QFactionsInfos
from qt_ui.widgets.QIntelBox import QIntelBox
from qt_ui.widgets.clientslots import MaxPlayerCount
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
-from qt_ui.windows.QWaitingForMissionResultWindow import \
- QWaitingForMissionResultWindow
+from qt_ui.windows.QWaitingForMissionResultWindow import QWaitingForMissionResultWindow
from qt_ui.windows.settings.QSettingsWindow import QSettingsWindow
from qt_ui.windows.stats.QStatsWindow import QStatsWindow
from qt_ui.widgets.QConditionsWidget import QConditionsWidget
class QTopPanel(QFrame):
-
def __init__(self, game_model: GameModel):
super(QTopPanel, self).__init__()
self.game_model = game_model
@@ -43,7 +41,7 @@ class QTopPanel(QFrame):
def game(self) -> Optional[Game]:
return self.game_model.game
- def init_ui(self):
+ def init_ui(self):
self.conditionsWidget = QConditionsWidget()
self.budgetBox = QBudgetBox(self.game)
@@ -85,14 +83,13 @@ class QTopPanel(QFrame):
self.proceedBox = QGroupBox("Proceed")
self.proceedBoxLayout = QHBoxLayout()
- self.proceedBoxLayout.addLayout(
- MaxPlayerCount(self.game_model.ato_model))
+ self.proceedBoxLayout.addLayout(MaxPlayerCount(self.game_model.ato_model))
self.proceedBoxLayout.addWidget(self.passTurnButton)
self.proceedBoxLayout.addWidget(self.proceedButton)
self.proceedBox.setLayout(self.proceedBoxLayout)
self.layout = QHBoxLayout()
-
+
self.layout.addWidget(self.factionsInfos)
self.layout.addWidget(self.conditionsWidget)
self.layout.addWidget(self.budgetBox)
@@ -101,8 +98,8 @@ class QTopPanel(QFrame):
self.layout.addStretch(1)
self.layout.addWidget(self.proceedBox)
- self.layout.setContentsMargins(0,0,0,0)
-
+ self.layout.setContentsMargins(0, 0, 0, 0)
+
self.setLayout(self.layout)
def setGame(self, game: Optional[Game]):
@@ -169,48 +166,50 @@ class QTopPanel(QFrame):
result = QMessageBox.question(
self,
"Continue without client slots?",
- ("No client slots have been created for players. Continuing will "
- "allow the AI to perform the mission, but players will be unable "
- "to participate.
"
- "
"
- "To add client slots for players, select a package from the "
- "Packages panel on the left of the main window, and then a flight "
- "from the Flights panel below the Packages panel. The edit button "
- "below the Flights panel will allow you to edit the number of "
- "client slots in the flight. Each client slot allows one player.
"
- "
Click 'Yes' to continue with an AI only mission"
- "
Click 'No' if you'd like to make more changes."),
+ (
+ "No client slots have been created for players. Continuing will "
+ "allow the AI to perform the mission, but players will be unable "
+ "to participate.
"
+ "
"
+ "To add client slots for players, select a package from the "
+ "Packages panel on the left of the main window, and then a flight "
+ "from the Flights panel below the Packages panel. The edit button "
+ "below the Flights panel will allow you to edit the number of "
+ "client slots in the flight. Each client slot allows one player.
"
+ "
Click 'Yes' to continue with an AI only mission"
+ "
Click 'No' if you'd like to make more changes."
+ ),
QMessageBox.No,
- QMessageBox.Yes
+ QMessageBox.Yes,
)
return result == QMessageBox.Yes
- def confirm_negative_start_time(self,
- negative_starts: List[Package]) -> bool:
- formatted = '
'.join(
+ def confirm_negative_start_time(self, negative_starts: List[Package]) -> bool:
+ formatted = "
".join(
[f"{p.primary_task} {p.target.name}" for p in negative_starts]
)
mbox = QMessageBox(
QMessageBox.Question,
"Continue with past start times?",
- ("Some flights in the following packages have start times set "
- "earlier than mission start time:
"
- "
"
- f"{formatted}
"
- "
"
- "Flight start times are estimated based on the package TOT, so it "
- "is possible that not all flights will be able to reach the "
- "target area at their assigned times.
"
- "
"
- "You can either continue with the mission as planned, with the "
- "misplanned flights potentially flying too fast and/or missing "
- "their rendezvous; automatically fix negative TOTs; or cancel "
- "mission start and fix the packages manually."),
- parent=self
+ (
+ "Some flights in the following packages have start times set "
+ "earlier than mission start time:
"
+ "
"
+ f"{formatted}
"
+ "
"
+ "Flight start times are estimated based on the package TOT, so it "
+ "is possible that not all flights will be able to reach the "
+ "target area at their assigned times.
"
+ "
"
+ "You can either continue with the mission as planned, with the "
+ "misplanned flights potentially flying too fast and/or missing "
+ "their rendezvous; automatically fix negative TOTs; or cancel "
+ "mission start and fix the packages manually."
+ ),
+ parent=self,
)
auto = mbox.addButton("Fix TOTs automatically", QMessageBox.ActionRole)
- ignore = mbox.addButton("Continue without fixing",
- QMessageBox.DestructiveRole)
+ ignore = mbox.addButton("Continue without fixing", QMessageBox.DestructiveRole)
cancel = mbox.addButton(QMessageBox.Cancel)
mbox.setEscapeButton(cancel)
mbox.exec_()
@@ -238,12 +237,12 @@ class QTopPanel(QFrame):
closest_cps[1],
self.game.theater.controlpoints[0].position,
self.game.player_name,
- self.game.enemy_name)
+ self.game.enemy_name,
+ )
unit_map = self.game.initiate_event(game_event)
- waiting = QWaitingForMissionResultWindow(game_event, self.game,
- unit_map)
+ waiting = QWaitingForMissionResultWindow(game_event, self.game, unit_map)
waiting.show()
- def budget_update(self, game:Game):
+ def budget_update(self, game: Game):
self.budgetBox.setGame(game)
diff --git a/qt_ui/widgets/ato.py b/qt_ui/widgets/ato.py
index aece9ee1..fa5e7072 100644
--- a/qt_ui/widgets/ato.py
+++ b/qt_ui/widgets/ato.py
@@ -71,34 +71,38 @@ class FlightDelegate(QStyledItemDelegate):
return f"From {origin} to {flight.arrival.name}"
return f"From {origin}"
- def paint(self, painter: QPainter, option: QStyleOptionViewItem,
- index: QModelIndex) -> None:
+ def paint(
+ self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex
+ ) -> None:
# Draw the list item with all the default selection styling, but with an
# invalid index so text formatting is left to us.
super().paint(painter, option, QModelIndex())
- rect = option.rect.adjusted(self.HMARGIN, self.VMARGIN, -self.HMARGIN,
- -self.VMARGIN)
+ rect = option.rect.adjusted(
+ self.HMARGIN, self.VMARGIN, -self.HMARGIN, -self.VMARGIN
+ )
with painter_context(painter):
painter.setFont(self.get_font(option))
icon: Optional[QIcon] = index.data(Qt.DecorationRole)
if icon is not None:
- icon.paint(painter, rect, Qt.AlignLeft | Qt.AlignVCenter,
- self.icon_mode(option),
- self.icon_state(option))
+ icon.paint(
+ painter,
+ rect,
+ Qt.AlignLeft | Qt.AlignVCenter,
+ self.icon_mode(option),
+ self.icon_state(option),
+ )
- rect = rect.adjusted(self.icon_size(option).width() + self.HMARGIN,
- 0, 0, 0)
+ rect = rect.adjusted(self.icon_size(option).width() + self.HMARGIN, 0, 0, 0)
painter.drawText(rect, Qt.AlignLeft, self.first_row_text(index))
line2 = rect.adjusted(0, rect.height() / 2, 0, rect.height() / 2)
painter.drawText(line2, Qt.AlignLeft, self.second_row_text(index))
clients = self.num_clients(index)
if clients:
- painter.drawText(rect, Qt.AlignRight,
- f"Player Slots: {clients}")
+ painter.drawText(rect, Qt.AlignRight, f"Player Slots: {clients}")
def num_clients(self, index: QModelIndex) -> int:
flight = self.flight(index)
@@ -126,22 +130,24 @@ class FlightDelegate(QStyledItemDelegate):
else:
return icon_size
- def sizeHint(self, option: QStyleOptionViewItem,
- index: QModelIndex) -> QSize:
+ def sizeHint(self, option: QStyleOptionViewItem, index: QModelIndex) -> QSize:
left = self.icon_size(option).width() + self.HMARGIN
metrics = QFontMetrics(self.get_font(option))
first = metrics.size(0, self.first_row_text(index))
second = metrics.size(0, self.second_row_text(index))
text_width = max(first.width(), second.width())
- return QSize(left + text_width + 2 * self.HMARGIN,
- first.height() + second.height() + 2 * self.VMARGIN)
+ return QSize(
+ left + text_width + 2 * self.HMARGIN,
+ first.height() + second.height() + 2 * self.VMARGIN,
+ )
class QFlightList(QListView):
"""List view for displaying the flights of a package."""
- def __init__(self, game_model: GameModel,
- package_model: Optional[PackageModel]) -> None:
+ def __init__(
+ self, game_model: GameModel, package_model: Optional[PackageModel]
+ ) -> None:
super().__init__()
self.game_model = game_model
self.package_model = package_model
@@ -163,8 +169,7 @@ class QFlightList(QListView):
# noinspection PyUnresolvedReferences
model.deleted.connect(self.disconnect_model)
self.selectionModel().setCurrentIndex(
- model.index(0, 0, QModelIndex()),
- QItemSelectionModel.Select
+ model.index(0, 0, QModelIndex()), QItemSelectionModel.Select
)
def disconnect_model(self) -> None:
@@ -192,14 +197,15 @@ class QFlightList(QListView):
def edit_flight(self, index: QModelIndex) -> None:
from qt_ui.dialogs import Dialog
+
Dialog.open_edit_flight_dialog(
- self.package_model, self.package_model.flight_at_index(index),
- parent=self.window()
+ self.package_model,
+ self.package_model.flight_at_index(index),
+ parent=self.window(),
)
def delete_flight(self, index: QModelIndex) -> None:
- self.game_model.game.aircraft_inventory.return_from_flight(
- self.selected_item)
+ self.game_model.game.aircraft_inventory.return_from_flight(self.selected_item)
self.package_model.delete_flight_at_index(index)
GameUpdateSignal.get_instance().redraw_flight_paths()
@@ -226,8 +232,9 @@ class QFlightPanel(QGroupBox):
delete buttons for flight management.
"""
- def __init__(self, game_model: GameModel,
- package_model: Optional[PackageModel] = None) -> None:
+ def __init__(
+ self, game_model: GameModel, package_model: Optional[PackageModel] = None
+ ) -> None:
super().__init__("Flights")
self.game_model = game_model
self.package_model = package_model
@@ -336,14 +343,16 @@ class PackageDelegate(QStyledItemDelegate):
package = self.package(index)
return f"TOT T+{package.time_over_target}"
- def paint(self, painter: QPainter, option: QStyleOptionViewItem,
- index: QModelIndex) -> None:
+ def paint(
+ self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex
+ ) -> None:
# Draw the list item with all the default selection styling, but with an
# invalid index so text formatting is left to us.
super().paint(painter, option, QModelIndex())
- rect = option.rect.adjusted(self.HMARGIN, self.VMARGIN, -self.HMARGIN,
- -self.VMARGIN)
+ rect = option.rect.adjusted(
+ self.HMARGIN, self.VMARGIN, -self.HMARGIN, -self.VMARGIN
+ )
with painter_context(painter):
painter.setFont(self.get_font(option))
@@ -354,20 +363,20 @@ class PackageDelegate(QStyledItemDelegate):
clients = self.num_clients(index)
if clients:
- painter.drawText(rect, Qt.AlignRight,
- f"Player Slots: {clients}")
+ painter.drawText(rect, Qt.AlignRight, f"Player Slots: {clients}")
def num_clients(self, index: QModelIndex) -> int:
package = self.package(index)
return sum(f.client_count for f in package.flights)
- def sizeHint(self, option: QStyleOptionViewItem,
- index: QModelIndex) -> QSize:
+ def sizeHint(self, option: QStyleOptionViewItem, index: QModelIndex) -> QSize:
metrics = QFontMetrics(self.get_font(option))
left = metrics.size(0, self.left_text(index))
right = metrics.size(0, self.right_text(index))
- return QSize(max(left.width(), right.width()) + 2 * self.HMARGIN,
- left.height() + right.height() + 2 * self.VMARGIN)
+ return QSize(
+ max(left.width(), right.width()) + 2 * self.HMARGIN,
+ left.height() + right.height() + 2 * self.VMARGIN,
+ )
class QPackageList(QListView):
@@ -393,19 +402,20 @@ class QPackageList(QListView):
def edit_package(self, index: QModelIndex) -> None:
from qt_ui.dialogs import Dialog
+
Dialog.open_edit_package_dialog(self.ato_model.get_package_model(index))
def delete_package(self, index: QModelIndex) -> None:
self.ato_model.delete_package_at_index(index)
GameUpdateSignal.get_instance().redraw_flight_paths()
- def on_new_packages(self, _parent: QModelIndex, first: int,
- _last: int) -> None:
+ def on_new_packages(self, _parent: QModelIndex, first: int, _last: int) -> None:
# Select the newly created pacakges. This should only ever happen due to
# the player saving a new package, so selecting it helps them view/edit
# it faster.
- self.selectionModel().setCurrentIndex(self.model().index(first, 0),
- QItemSelectionModel.Select)
+ self.selectionModel().setCurrentIndex(
+ self.model().index(first, 0), QItemSelectionModel.Select
+ )
def on_double_click(self, index: QModelIndex) -> None:
if not index.isValid():
@@ -533,8 +543,6 @@ class QAirTaskingOrderPanel(QSplitter):
"""Sets the newly selected flight for display in the bottom panel."""
index = self.package_panel.package_list.currentIndex()
if index.isValid():
- self.flight_panel.set_package(
- self.ato_model.get_package_model(index)
- )
+ self.flight_panel.set_package(self.ato_model.get_package_model(index))
else:
self.flight_panel.set_package(None)
diff --git a/qt_ui/widgets/clientslots.py b/qt_ui/widgets/clientslots.py
index 1c9fff9b..231ed61a 100644
--- a/qt_ui/widgets/clientslots.py
+++ b/qt_ui/widgets/clientslots.py
@@ -11,9 +11,12 @@ class MaxPlayerCount(QLabeledWidget):
self.slots_label = QLabel(str(self.count_client_slots))
self.ato_model.client_slots_changed.connect(self.update_count)
super().__init__(
- "Max Players:", self.slots_label,
- ("Total number of client slots. To add client slots, edit a flight "
- "using the panel on the left.")
+ "Max Players:",
+ self.slots_label,
+ (
+ "Total number of client slots. To add client slots, edit a flight "
+ "using the panel on the left."
+ ),
)
@property
diff --git a/qt_ui/widgets/combos/QAircraftTypeSelector.py b/qt_ui/widgets/combos/QAircraftTypeSelector.py
index 64e3ab07..5946fdcb 100644
--- a/qt_ui/widgets/combos/QAircraftTypeSelector.py
+++ b/qt_ui/widgets/combos/QAircraftTypeSelector.py
@@ -11,10 +11,16 @@ import gen.flights.ai_flight_planner_db
from game import Game, db
+
class QAircraftTypeSelector(QComboBox):
"""Combo box for selecting among the given aircraft types."""
- def __init__(self, aircraft_types: Iterable[Type[FlyingType]], country: str, mission_type: str) -> None:
+ def __init__(
+ self,
+ aircraft_types: Iterable[Type[FlyingType]],
+ country: str,
+ mission_type: str,
+ ) -> None:
super().__init__()
self.model().sort(0)
@@ -26,29 +32,66 @@ class QAircraftTypeSelector(QComboBox):
current_aircraft = self.currentData()
self.clear()
for aircraft in aircraft_types:
- if mission_type in [FlightType.BARCAP, FlightType.ESCORT, FlightType.INTERCEPTION, FlightType.SWEEP, FlightType.TARCAP]:
+ if mission_type in [
+ FlightType.BARCAP,
+ FlightType.ESCORT,
+ FlightType.INTERCEPTION,
+ FlightType.SWEEP,
+ FlightType.TARCAP,
+ ]:
if aircraft in gen.flights.ai_flight_planner_db.CAP_CAPABLE:
- self.addItem(f"{db.unit_get_expanded_info(self.country, aircraft, 'name')}", userData=aircraft)
- elif mission_type in [FlightType.CAS, FlightType.BAI, FlightType.OCA_AIRCRAFT]:
- if aircraft in gen.flights.ai_flight_planner_db.CAS_CAPABLE or aircraft in gen.flights.ai_flight_planner_db.TRANSPORT_CAPABLE:
- self.addItem(f"{db.unit_get_expanded_info(self.country, aircraft, 'name')}", userData=aircraft)
+ self.addItem(
+ f"{db.unit_get_expanded_info(self.country, aircraft, 'name')}",
+ userData=aircraft,
+ )
+ elif mission_type in [
+ FlightType.CAS,
+ FlightType.BAI,
+ FlightType.OCA_AIRCRAFT,
+ ]:
+ if (
+ aircraft in gen.flights.ai_flight_planner_db.CAS_CAPABLE
+ or aircraft in gen.flights.ai_flight_planner_db.TRANSPORT_CAPABLE
+ ):
+ self.addItem(
+ f"{db.unit_get_expanded_info(self.country, aircraft, 'name')}",
+ userData=aircraft,
+ )
elif mission_type in [FlightType.SEAD]:
if aircraft in gen.flights.ai_flight_planner_db.SEAD_CAPABLE:
- self.addItem(f"{db.unit_get_expanded_info(self.country, aircraft, 'name')}", userData=aircraft)
+ self.addItem(
+ f"{db.unit_get_expanded_info(self.country, aircraft, 'name')}",
+ userData=aircraft,
+ )
elif mission_type in [FlightType.DEAD]:
if aircraft in gen.flights.ai_flight_planner_db.DEAD_CAPABLE:
- self.addItem(f"{db.unit_get_expanded_info(self.country, aircraft, 'name')}", userData=aircraft)
+ self.addItem(
+ f"{db.unit_get_expanded_info(self.country, aircraft, 'name')}",
+ userData=aircraft,
+ )
elif mission_type in [FlightType.STRIKE]:
- if aircraft in gen.flights.ai_flight_planner_db.STRIKE_CAPABLE or aircraft in gen.flights.ai_flight_planner_db.TRANSPORT_CAPABLE:
- self.addItem(f"{db.unit_get_expanded_info(self.country, aircraft, 'name')}", userData=aircraft)
+ if (
+ aircraft in gen.flights.ai_flight_planner_db.STRIKE_CAPABLE
+ or aircraft in gen.flights.ai_flight_planner_db.TRANSPORT_CAPABLE
+ ):
+ self.addItem(
+ f"{db.unit_get_expanded_info(self.country, aircraft, 'name')}",
+ userData=aircraft,
+ )
elif mission_type in [FlightType.ANTISHIP]:
if aircraft in gen.flights.ai_flight_planner_db.ANTISHIP_CAPABLE:
- self.addItem(f"{db.unit_get_expanded_info(self.country, aircraft, 'name')}", userData=aircraft)
+ self.addItem(
+ f"{db.unit_get_expanded_info(self.country, aircraft, 'name')}",
+ userData=aircraft,
+ )
elif mission_type in [FlightType.OCA_RUNWAY]:
if aircraft in gen.flights.ai_flight_planner_db.RUNWAY_ATTACK_CAPABLE:
- self.addItem(f"{db.unit_get_expanded_info(self.country, aircraft, 'name')}", userData=aircraft)
+ self.addItem(
+ f"{db.unit_get_expanded_info(self.country, aircraft, 'name')}",
+ userData=aircraft,
+ )
current_aircraft_index = self.findData(current_aircraft)
if current_aircraft_index != -1:
self.setCurrentIndex(current_aircraft_index)
if self.count() == 0:
- self.addItem("No capable aircraft available", userData=None)
\ No newline at end of file
+ self.addItem("No capable aircraft available", userData=None)
diff --git a/qt_ui/widgets/combos/QArrivalAirfieldSelector.py b/qt_ui/widgets/combos/QArrivalAirfieldSelector.py
index 22097b34..e4075f57 100644
--- a/qt_ui/widgets/combos/QArrivalAirfieldSelector.py
+++ b/qt_ui/widgets/combos/QArrivalAirfieldSelector.py
@@ -14,8 +14,12 @@ class QArrivalAirfieldSelector(QComboBox):
aircraft type is able to land at.
"""
- def __init__(self, destinations: Iterable[ControlPoint],
- aircraft: Type[FlyingType], optional_text: str) -> None:
+ def __init__(
+ self,
+ destinations: Iterable[ControlPoint],
+ aircraft: Type[FlyingType],
+ optional_text: str,
+ ) -> None:
super().__init__()
self.destinations = list(destinations)
self.aircraft = aircraft
diff --git a/qt_ui/widgets/combos/QFilteredComboBox.py b/qt_ui/widgets/combos/QFilteredComboBox.py
index 7d152b2e..1fae0cf8 100644
--- a/qt_ui/widgets/combos/QFilteredComboBox.py
+++ b/qt_ui/widgets/combos/QFilteredComboBox.py
@@ -3,9 +3,16 @@ from PySide2.QtWidgets import QComboBox, QCompleter
class QFilteredComboBox(QComboBox):
-
- def __init__(self, parent=None, include_targets=True, include_airbases=True,
- include_frontlines=True, include_units=True, include_enemy=True, include_friendly=True):
+ def __init__(
+ self,
+ parent=None,
+ include_targets=True,
+ include_airbases=True,
+ include_frontlines=True,
+ include_units=True,
+ include_enemy=True,
+ include_friendly=True,
+ ):
super(QFilteredComboBox, self).__init__(parent)
self.setFocusPolicy(Qt.StrongFocus)
diff --git a/qt_ui/widgets/combos/QOriginAirfieldSelector.py b/qt_ui/widgets/combos/QOriginAirfieldSelector.py
index 364f8b04..75342fd1 100644
--- a/qt_ui/widgets/combos/QOriginAirfieldSelector.py
+++ b/qt_ui/widgets/combos/QOriginAirfieldSelector.py
@@ -18,9 +18,12 @@ class QOriginAirfieldSelector(QComboBox):
availability_changed = Signal(int)
- def __init__(self, global_inventory: GlobalAircraftInventory,
- origins: Iterable[ControlPoint],
- aircraft: Type[FlyingType]) -> None:
+ def __init__(
+ self,
+ global_inventory: GlobalAircraftInventory,
+ origins: Iterable[ControlPoint],
+ aircraft: Type[FlyingType],
+ ) -> None:
super().__init__()
self.global_inventory = global_inventory
self.origins = list(origins)
diff --git a/qt_ui/widgets/combos/QPredefinedWaypointSelectionComboBox.py b/qt_ui/widgets/combos/QPredefinedWaypointSelectionComboBox.py
index 8bb72d81..5de3527e 100644
--- a/qt_ui/widgets/combos/QPredefinedWaypointSelectionComboBox.py
+++ b/qt_ui/widgets/combos/QPredefinedWaypointSelectionComboBox.py
@@ -9,9 +9,17 @@ from qt_ui.widgets.combos.QFilteredComboBox import QFilteredComboBox
class QPredefinedWaypointSelectionComboBox(QFilteredComboBox):
-
- def __init__(self, game: Game, parent=None, include_targets=True, include_airbases=True,
- include_frontlines=True, include_units=True, include_enemy=True, include_friendly=True):
+ def __init__(
+ self,
+ game: Game,
+ parent=None,
+ include_targets=True,
+ include_airbases=True,
+ include_frontlines=True,
+ include_units=True,
+ include_enemy=True,
+ include_friendly=True,
+ ):
super(QPredefinedWaypointSelectionComboBox, self).__init__(parent)
self.game = game
self.include_targets = include_targets
@@ -34,7 +42,11 @@ class QPredefinedWaypointSelectionComboBox(QFilteredComboBox):
waypoints = [first_waypoint]
if include_all_from_same_location:
for w in self.wpts:
- if w is not first_waypoint and w.obj_name and w.obj_name == first_waypoint.obj_name:
+ if (
+ w is not first_waypoint
+ and w.obj_name
+ and w.obj_name == first_waypoint.obj_name
+ ):
waypoints.append(w)
return waypoints
@@ -53,14 +65,19 @@ class QPredefinedWaypointSelectionComboBox(QFilteredComboBox):
if self.include_frontlines:
for cp in self.game.theater.controlpoints:
if cp.captured:
- enemy_cp = [ecp for ecp in cp.connected_points if ecp.captured != cp.captured]
+ enemy_cp = [
+ ecp
+ for ecp in cp.connected_points
+ if ecp.captured != cp.captured
+ ]
for ecp in enemy_cp:
pos = Conflict.frontline_position(cp, ecp, self.game.theater)[0]
wpt = FlightWaypoint(
FlightWaypointType.CUSTOM,
pos.x,
pos.y,
- Distance.from_meters(800))
+ Distance.from_meters(800),
+ )
wpt.name = "Frontline " + cp.name + "/" + ecp.name + " [CAS]"
wpt.alt_type = "RADIO"
wpt.pretty_name = wpt.name
@@ -69,14 +86,18 @@ class QPredefinedWaypointSelectionComboBox(QFilteredComboBox):
if self.include_targets:
for cp in self.game.theater.controlpoints:
- if (self.include_enemy and not cp.captured) or (self.include_friendly and cp.captured):
+ if (self.include_enemy and not cp.captured) or (
+ self.include_friendly and cp.captured
+ ):
for ground_object in cp.ground_objects:
- if not ground_object.is_dead and isinstance(ground_object, BuildingGroundObject):
+ if not ground_object.is_dead and isinstance(
+ ground_object, BuildingGroundObject
+ ):
wpt = FlightWaypoint(
FlightWaypointType.CUSTOM,
ground_object.position.x,
ground_object.position.y,
- Distance.from_meters(0)
+ Distance.from_meters(0),
)
wpt.alt_type = "RADIO"
wpt.name = ground_object.waypoint_name
@@ -91,19 +112,31 @@ class QPredefinedWaypointSelectionComboBox(QFilteredComboBox):
if self.include_units:
for cp in self.game.theater.controlpoints:
- if (self.include_enemy and not cp.captured) or (self.include_friendly and cp.captured):
+ if (self.include_enemy and not cp.captured) or (
+ self.include_friendly and cp.captured
+ ):
for ground_object in cp.ground_objects:
- if not ground_object.is_dead and ground_object.dcs_identifier == "AA":
+ if (
+ not ground_object.is_dead
+ and ground_object.dcs_identifier == "AA"
+ ):
for g in ground_object.groups:
for j, u in enumerate(g.units):
wpt = FlightWaypoint(
FlightWaypointType.CUSTOM,
u.position.x,
u.position.y,
- Distance.from_meters(0)
+ Distance.from_meters(0),
)
wpt.alt_type = "RADIO"
- wpt.name = wpt.name = "[" + str(ground_object.obj_name) + "] : " + u.type + " #" + str(j)
+ wpt.name = wpt.name = (
+ "["
+ + str(ground_object.obj_name)
+ + "] : "
+ + u.type
+ + " #"
+ + str(j)
+ )
wpt.pretty_name = wpt.name
wpt.targets.append(u)
wpt.obj_name = ground_object.obj_name
@@ -116,17 +149,21 @@ class QPredefinedWaypointSelectionComboBox(QFilteredComboBox):
if self.include_airbases:
for cp in self.game.theater.controlpoints:
- if (self.include_enemy and not cp.captured) or (self.include_friendly and cp.captured):
+ if (self.include_enemy and not cp.captured) or (
+ self.include_friendly and cp.captured
+ ):
wpt = FlightWaypoint(
FlightWaypointType.CUSTOM,
cp.position.x,
cp.position.y,
- Distance.from_meters(0)
+ Distance.from_meters(0),
)
wpt.alt_type = "RADIO"
wpt.name = cp.name
if cp.captured:
- wpt.description = "Position of " + cp.name + " [Friendly Airbase]"
+ wpt.description = (
+ "Position of " + cp.name + " [Friendly Airbase]"
+ )
else:
wpt.description = "Position of " + cp.name + " [Enemy Airbase]"
diff --git a/qt_ui/widgets/combos/QSEADTargetSelectionComboBox.py b/qt_ui/widgets/combos/QSEADTargetSelectionComboBox.py
index a037d1b4..3cd46bf9 100644
--- a/qt_ui/widgets/combos/QSEADTargetSelectionComboBox.py
+++ b/qt_ui/widgets/combos/QSEADTargetSelectionComboBox.py
@@ -7,7 +7,6 @@ from qt_ui.widgets.combos.QFilteredComboBox import QFilteredComboBox
class SEADTargetInfo:
-
def __init__(self):
self.name = ""
self.location = None
@@ -15,8 +14,8 @@ class SEADTargetInfo:
self.threat_range = 0
self.detection_range = 0
-class QSEADTargetSelectionComboBox(QFilteredComboBox):
+class QSEADTargetSelectionComboBox(QFilteredComboBox):
def __init__(self, game: Game, parent=None):
super(QSEADTargetSelectionComboBox, self).__init__(parent)
self.game = game
@@ -41,7 +40,8 @@ class QSEADTargetSelectionComboBox(QFilteredComboBox):
return i + 1
for cp in self.game.theater.controlpoints:
- if cp.captured: continue
+ if cp.captured:
+ continue
for g in cp.ground_objects:
radars = []
@@ -53,7 +53,10 @@ class QSEADTargetSelectionComboBox(QFilteredComboBox):
utype = db.unit_type_from_name(u.type)
if utype in UNITS_WITH_RADAR:
- if hasattr(utype, "detection_range") and utype.detection_range > 1000:
+ if (
+ hasattr(utype, "detection_range")
+ and utype.detection_range > 1000
+ ):
if utype.detection_range > detection_range:
detection_range = utype.detection_range
radars.append(u)
@@ -63,9 +66,18 @@ class QSEADTargetSelectionComboBox(QFilteredComboBox):
threat_range = utype.threat_range
if len(radars) > 0:
tgt_info = SEADTargetInfo()
- tgt_info.name = g.obj_name + " [" + ",".join([db.unit_type_from_name(u.type).id for u in radars]) + " ]"
+ tgt_info.name = (
+ g.obj_name
+ + " ["
+ + ",".join(
+ [db.unit_type_from_name(u.type).id for u in radars]
+ )
+ + " ]"
+ )
if len(tgt_info.name) > 25:
- tgt_info.name = g.obj_name + " [" + str(len(radars)) + " units]"
+ tgt_info.name = (
+ g.obj_name + " [" + str(len(radars)) + " units]"
+ )
tgt_info.radars = radars
tgt_info.location = g
tgt_info.threat_range = threat_range
@@ -73,5 +85,3 @@ class QSEADTargetSelectionComboBox(QFilteredComboBox):
i = add_model_item(i, model, tgt_info)
self.setModel(model)
-
-
diff --git a/qt_ui/widgets/combos/QStrikeTargetSelectionComboBox.py b/qt_ui/widgets/combos/QStrikeTargetSelectionComboBox.py
index b5fcc57d..d31c501c 100644
--- a/qt_ui/widgets/combos/QStrikeTargetSelectionComboBox.py
+++ b/qt_ui/widgets/combos/QStrikeTargetSelectionComboBox.py
@@ -5,7 +5,6 @@ from qt_ui.widgets.combos.QFilteredComboBox import QFilteredComboBox
class StrikeTargetInfo:
-
def __init__(self):
self.name = ""
self.location = None
@@ -14,17 +13,14 @@ class StrikeTargetInfo:
class QStrikeTargetSelectionComboBox(QFilteredComboBox):
-
def __init__(self, game: Game, parent=None):
super(QStrikeTargetSelectionComboBox, self).__init__(parent)
self.game = game
self.find_possible_strike_targets()
-
for t in self.targets:
print(t.name + " - " + str(len(t.units)) + " " + str(len(t.buildings)))
-
def get_selected_target(self) -> StrikeTargetInfo:
n = self.currentText()
for target in self.targets:
@@ -44,12 +40,14 @@ class QStrikeTargetSelectionComboBox(QFilteredComboBox):
return i + 1
for cp in self.game.theater.controlpoints:
- if cp.captured: continue
+ if cp.captured:
+ continue
added_obj_names = []
for g in cp.ground_objects:
- if g.obj_name in added_obj_names: continue
+ if g.obj_name in added_obj_names:
+ continue
target = StrikeTargetInfo()
target.location = g
@@ -70,5 +68,3 @@ class QStrikeTargetSelectionComboBox(QFilteredComboBox):
added_obj_names.append(g.obj_name)
self.setModel(model)
-
-
diff --git a/qt_ui/widgets/floatspinners.py b/qt_ui/widgets/floatspinners.py
index 058b3516..54f4dccd 100644
--- a/qt_ui/widgets/floatspinners.py
+++ b/qt_ui/widgets/floatspinners.py
@@ -4,9 +4,12 @@ from PySide2.QtWidgets import QSpinBox
class TenthsSpinner(QSpinBox):
- def __init__(self, minimum: Optional[int] = None,
- maximum: Optional[int] = None,
- initial: Optional[int] = None) -> None:
+ def __init__(
+ self,
+ minimum: Optional[int] = None,
+ maximum: Optional[int] = None,
+ initial: Optional[int] = None,
+ ) -> None:
super().__init__()
if minimum is not None:
diff --git a/qt_ui/widgets/map/QFrontLine.py b/qt_ui/widgets/map/QFrontLine.py
index 9f99ab13..41edcaea 100644
--- a/qt_ui/widgets/map/QFrontLine.py
+++ b/qt_ui/widgets/map/QFrontLine.py
@@ -27,8 +27,15 @@ class QFrontLine(QGraphicsLineItem):
change the mouse cursor on hover.
"""
- def __init__(self, x1: float, y1: float, x2: float, y2: float,
- mission_target: FrontLine, game_model: GameModel) -> None:
+ def __init__(
+ self,
+ x1: float,
+ y1: float,
+ x2: float,
+ y2: float,
+ mission_target: FrontLine,
+ game_model: GameModel,
+ ) -> None:
super().__init__(x1, y1, x2, y2)
self.mission_target = mission_target
self.game_model = game_model
@@ -98,10 +105,9 @@ class QFrontLine(QGraphicsLineItem):
self.mission_target.control_point_b.base.affect_strength(-0.1)
self.game_model.game.initialize_turn()
GameUpdateSignal.get_instance().updateGame(self.game_model.game)
-
+
def cheat_backward(self) -> None:
self.mission_target.control_point_a.base.affect_strength(-0.1)
self.mission_target.control_point_b.base.affect_strength(0.1)
self.game_model.game.initialize_turn()
GameUpdateSignal.get_instance().updateGame(self.game_model.game)
-
\ No newline at end of file
diff --git a/qt_ui/widgets/map/QLiberationMap.py b/qt_ui/widgets/map/QLiberationMap.py
index 1f171843..2be5e520 100644
--- a/qt_ui/widgets/map/QLiberationMap.py
+++ b/qt_ui/widgets/map/QLiberationMap.py
@@ -70,10 +70,10 @@ from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
MAX_SHIP_DISTANCE = nautical_miles(80)
+
def binomial(i: int, n: int) -> float:
"""Binomial coefficient"""
- return math.factorial(n) / float(
- math.factorial(i) * math.factorial(n - i))
+ return math.factorial(n) / float(math.factorial(i) * math.factorial(n - i))
def bernstein(t: float, i: int, n: int) -> float:
@@ -92,7 +92,9 @@ def bezier(t: float, points: Iterable[Tuple[float, float]]) -> Tuple[float, floa
return x, y
-def bezier_curve_range(n: int, points: Iterable[Tuple[float, float]]) -> Iterator[Tuple[float, float]]:
+def bezier_curve_range(
+ n: int, points: Iterable[Tuple[float, float]]
+) -> Iterator[Tuple[float, float]]:
"""Range of points in a curve bezier"""
for i in range(n):
t = i / float(n - 1)
@@ -133,7 +135,9 @@ class QLiberationMap(QGraphicsView):
self.setGame(game_model.game)
# Object displayed when unit is selected
- self.movement_line = QtWidgets.QGraphicsLineItem(QtCore.QLineF(QPointF(0,0),QPointF(0,0)))
+ self.movement_line = QtWidgets.QGraphicsLineItem(
+ QtCore.QLineF(QPointF(0, 0), QPointF(0, 0))
+ )
self.movement_line.setPen(QPen(CONST.COLORS["orange"], width=10.0))
self.selected_cp: QMapControlPoint = None
@@ -162,8 +166,7 @@ class QLiberationMap(QGraphicsView):
# update_flight_selection will be called in when the last
# package is removed. If no flight is selected, it's not a
# problem to also have no package selected.
- logging.error(
- "Flight was selected with no package selected")
+ logging.error("Flight was selected with no package selected")
return
# Optional[int] isn't a valid type for a Qt signal. None will be
@@ -183,7 +186,6 @@ class QLiberationMap(QGraphicsView):
self.navmesh_highlight: Optional[QPolygonF] = None
self.shortest_path_segments: List[QLineF] = []
-
def init_scene(self):
scene = QLiberationScene(self)
self.setScene(scene)
@@ -203,6 +205,7 @@ class QLiberationMap(QGraphicsView):
"""
Uncomment to set up theather reference points"""
+
def keyPressEvent(self, event):
modifiers = QtWidgets.QApplication.keyboardModifiers()
if not self.reference_point_setup_mode:
@@ -225,40 +228,39 @@ class QLiberationMap(QGraphicsView):
if event.key() == QtCore.Qt.Key_Down:
self.update_reference_point(
- self.game.theater.reference_points[0],
- Point(0, distance))
+ self.game.theater.reference_points[0], Point(0, distance)
+ )
if event.key() == QtCore.Qt.Key_Up:
self.update_reference_point(
- self.game.theater.reference_points[0],
- Point(0, -distance))
+ self.game.theater.reference_points[0], Point(0, -distance)
+ )
if event.key() == QtCore.Qt.Key_Left:
self.update_reference_point(
- self.game.theater.reference_points[0],
- Point(-distance, 0))
+ self.game.theater.reference_points[0], Point(-distance, 0)
+ )
if event.key() == QtCore.Qt.Key_Right:
self.update_reference_point(
- self.game.theater.reference_points[0],
- Point(distance, 0))
+ self.game.theater.reference_points[0], Point(distance, 0)
+ )
if event.key() == QtCore.Qt.Key_S:
self.update_reference_point(
- self.game.theater.reference_points[1],
- Point(0, distance))
+ self.game.theater.reference_points[1], Point(0, distance)
+ )
if event.key() == QtCore.Qt.Key_W:
self.update_reference_point(
- self.game.theater.reference_points[1],
- Point(0, -distance))
+ self.game.theater.reference_points[1], Point(0, -distance)
+ )
if event.key() == QtCore.Qt.Key_A:
self.update_reference_point(
- self.game.theater.reference_points[1],
- Point(-distance, 0))
+ self.game.theater.reference_points[1], Point(-distance, 0)
+ )
if event.key() == QtCore.Qt.Key_D:
self.update_reference_point(
- self.game.theater.reference_points[1],
- Point(distance, 0))
+ self.game.theater.reference_points[1], Point(distance, 0)
+ )
- logging.debug(
- f"Reference points: {self.game.theater.reference_points}")
+ logging.debug(f"Reference points: {self.game.theater.reference_points}")
self.reload_scene()
@staticmethod
@@ -275,16 +277,33 @@ class QLiberationMap(QGraphicsView):
distance_point = self._transform_point(culling_distance_point)
transformed = self._transform_point(point)
radius = distance_point[0] - transformed[0]
- scene.addEllipse(transformed[0]-radius, transformed[1]-radius, 2*radius, 2*radius, CONST.COLORS["transparent"], CONST.COLORS["light_green_transparent"])
+ scene.addEllipse(
+ transformed[0] - radius,
+ transformed[1] - radius,
+ 2 * radius,
+ 2 * radius,
+ CONST.COLORS["transparent"],
+ CONST.COLORS["light_green_transparent"],
+ )
for zone in culling_zones:
- culling_distance_zone = Point(zone.x + culling_distance*1000, zone.y + culling_distance*1000)
+ culling_distance_zone = Point(
+ zone.x + culling_distance * 1000, zone.y + culling_distance * 1000
+ )
distance_zone = self._transform_point(culling_distance_zone)
transformed = self._transform_point(zone)
radius = distance_zone[0] - transformed[0]
- scene.addEllipse(transformed[0]-radius, transformed[1]-radius, 2*radius, 2*radius, CONST.COLORS["transparent"], CONST.COLORS["light_green_transparent"])
+ scene.addEllipse(
+ transformed[0] - radius,
+ transformed[1] - radius,
+ 2 * radius,
+ 2 * radius,
+ CONST.COLORS["transparent"],
+ CONST.COLORS["light_green_transparent"],
+ )
- def draw_shapely_poly(self, scene: QGraphicsScene, poly: Polygon, pen: QPen,
- brush: QBrush) -> Optional[QPolygonF]:
+ def draw_shapely_poly(
+ self, scene: QGraphicsScene, poly: Polygon, pen: QPen, brush: QBrush
+ ) -> Optional[QPolygonF]:
if poly.is_empty:
return None
points = []
@@ -293,16 +312,18 @@ class QLiberationMap(QGraphicsView):
points.append(QPointF(x, y))
return scene.addPolygon(QPolygonF(points), pen, brush)
- def draw_threat_zone(self, scene: QGraphicsScene, poly: Polygon,
- player: bool) -> None:
+ def draw_threat_zone(
+ self, scene: QGraphicsScene, poly: Polygon, player: bool
+ ) -> None:
if player:
brush = QColor(0, 132, 255, 100)
else:
brush = QColor(227, 32, 0, 100)
self.draw_shapely_poly(scene, poly, CONST.COLORS["transparent"], brush)
- def display_threat_zones(self, scene: QGraphicsScene,
- options: ThreatZoneOptions, player: bool) -> None:
+ def display_threat_zones(
+ self, scene: QGraphicsScene, options: ThreatZoneOptions, player: bool
+ ) -> None:
"""Draws the threat zones on the map."""
threat_zones = self.game.threat_zone_for(player)
if options.all:
@@ -321,33 +342,44 @@ class QLiberationMap(QGraphicsView):
for poly in polys:
self.draw_threat_zone(scene, poly, player)
- def draw_navmesh_neighbor_line(self, scene: QGraphicsScene, poly: Polygon,
- begin: ShapelyPoint) -> None:
+ def draw_navmesh_neighbor_line(
+ self, scene: QGraphicsScene, poly: Polygon, begin: ShapelyPoint
+ ) -> None:
vertex = Point(begin.x, begin.y)
centroid = poly.centroid
direction = Point(centroid.x, centroid.y)
- end = vertex.point_from_heading(vertex.heading_between_point(direction),
- nautical_miles(2).meters)
+ end = vertex.point_from_heading(
+ vertex.heading_between_point(direction), nautical_miles(2).meters
+ )
- scene.addLine(QLineF(QPointF(*self._transform_point(vertex)),
- QPointF(*self._transform_point(end))),
- CONST.COLORS["yellow"])
+ scene.addLine(
+ QLineF(
+ QPointF(*self._transform_point(vertex)),
+ QPointF(*self._transform_point(end)),
+ ),
+ CONST.COLORS["yellow"],
+ )
@singledispatchmethod
- def draw_navmesh_border(self, intersection, scene: QGraphicsScene,
- poly: Polygon) -> None:
- raise NotImplementedError("draw_navmesh_border not implemented for %s",
- intersection.__class__.__name__)
+ def draw_navmesh_border(
+ self, intersection, scene: QGraphicsScene, poly: Polygon
+ ) -> None:
+ raise NotImplementedError(
+ "draw_navmesh_border not implemented for %s",
+ intersection.__class__.__name__,
+ )
@draw_navmesh_border.register
- def draw_navmesh_point_border(self, intersection: ShapelyPoint,
- scene: QGraphicsScene, poly: Polygon) -> None:
+ def draw_navmesh_point_border(
+ self, intersection: ShapelyPoint, scene: QGraphicsScene, poly: Polygon
+ ) -> None:
# Draw a line from the vertex toward the center of the polygon.
self.draw_navmesh_neighbor_line(scene, poly, intersection)
@draw_navmesh_border.register
- def draw_navmesh_edge_border(self, intersection: LineString,
- scene: QGraphicsScene, poly: Polygon) -> None:
+ def draw_navmesh_edge_border(
+ self, intersection: LineString, scene: QGraphicsScene, poly: Polygon
+ ) -> None:
# Draw a line from the center of the edge toward the center of the
# polygon.
edge_center = intersection.interpolate(0.5, normalized=True)
@@ -355,13 +387,16 @@ class QLiberationMap(QGraphicsView):
def display_navmesh(self, scene: QGraphicsScene, player: bool) -> None:
for navpoly in self.game.navmesh_for(player).polys:
- self.draw_shapely_poly(scene, navpoly.poly, CONST.COLORS["black"],
- CONST.COLORS["transparent"])
+ self.draw_shapely_poly(
+ scene, navpoly.poly, CONST.COLORS["black"], CONST.COLORS["transparent"]
+ )
position = self._transform_point(
- Point(navpoly.poly.centroid.x, navpoly.poly.centroid.y))
- text = scene.addSimpleText(f"Navmesh {navpoly.ident}",
- self.waypoint_info_font)
+ Point(navpoly.poly.centroid.x, navpoly.poly.centroid.y)
+ )
+ text = scene.addSimpleText(
+ f"Navmesh {navpoly.ident}", self.waypoint_info_font
+ )
text.setBrush(QColor(255, 255, 255))
text.setPen(QColor(255, 255, 255))
text.moveBy(position[0] + 8, position[1])
@@ -370,8 +405,9 @@ class QLiberationMap(QGraphicsView):
for border in navpoly.neighbors.values():
self.draw_navmesh_border(border, scene, navpoly.poly)
- def highlight_mouse_navmesh(self, scene: QGraphicsScene, navmesh: NavMesh,
- mouse_position: Point) -> None:
+ def highlight_mouse_navmesh(
+ self, scene: QGraphicsScene, navmesh: NavMesh, mouse_position: Point
+ ) -> None:
if self.navmesh_highlight is not None:
try:
scene.removeItem(self.navmesh_highlight)
@@ -381,11 +417,15 @@ class QLiberationMap(QGraphicsView):
if navpoly is None:
return
self.navmesh_highlight = self.draw_shapely_poly(
- scene, navpoly.poly, CONST.COLORS["transparent"],
- CONST.COLORS["light_green_transparent"])
+ scene,
+ navpoly.poly,
+ CONST.COLORS["transparent"],
+ CONST.COLORS["light_green_transparent"],
+ )
- def draw_shortest_path(self, scene: QGraphicsScene, navmesh: NavMesh,
- destination: Point, player: bool) -> None:
+ def draw_shortest_path(
+ self, scene: QGraphicsScene, navmesh: NavMesh, destination: Point, player: bool
+ ) -> None:
for line in self.shortest_path_segments:
try:
scene.removeItem(line)
@@ -407,21 +447,36 @@ class QLiberationMap(QGraphicsView):
flight_path_pen = self.flight_path_pen(player, selected=True)
# Draw the line to the *middle* of the waypoint.
offset = self.WAYPOINT_SIZE // 2
- self.shortest_path_segments.append(scene.addLine(
- prev_pos[0] + offset, prev_pos[1] + offset,
- new_pos[0] + offset, new_pos[1] + offset,
- flight_path_pen
- ))
+ self.shortest_path_segments.append(
+ scene.addLine(
+ prev_pos[0] + offset,
+ prev_pos[1] + offset,
+ new_pos[0] + offset,
+ new_pos[1] + offset,
+ flight_path_pen,
+ )
+ )
- self.shortest_path_segments.append(scene.addEllipse(
- new_pos[0], new_pos[1], self.WAYPOINT_SIZE,
- self.WAYPOINT_SIZE, flight_path_pen, flight_path_pen
- ))
+ self.shortest_path_segments.append(
+ scene.addEllipse(
+ new_pos[0],
+ new_pos[1],
+ self.WAYPOINT_SIZE,
+ self.WAYPOINT_SIZE,
+ flight_path_pen,
+ flight_path_pen,
+ )
+ )
prev_pos = new_pos
- def draw_test_flight_plan(self, scene: QGraphicsScene, task: FlightType,
- point_near_target: Point, player: bool) -> None:
+ def draw_test_flight_plan(
+ self,
+ scene: QGraphicsScene,
+ task: FlightType,
+ point_near_target: Point,
+ player: bool,
+ ) -> None:
for line in self.shortest_path_segments:
try:
scene.removeItem(line)
@@ -438,8 +493,16 @@ class QLiberationMap(QGraphicsView):
origin = self.game.theater.enemy_points()[0]
package = Package(target)
- flight = Flight(package, F_16C_50, 2, task, start_type="Warm",
- departure=origin, arrival=origin, divert=None)
+ flight = Flight(
+ package,
+ F_16C_50,
+ 2,
+ task,
+ start_type="Warm",
+ departure=origin,
+ arrival=origin,
+ divert=None,
+ )
package.add_flight(flight)
planner = FlightPlanBuilder(self.game, package, is_player=player)
try:
@@ -452,31 +515,49 @@ class QLiberationMap(QGraphicsView):
@staticmethod
def should_display_ground_objects_at(cp: ControlPoint) -> bool:
- return ((DisplayOptions.sam_ranges and cp.captured) or
- (DisplayOptions.enemy_sam_ranges and not cp.captured))
+ return (DisplayOptions.sam_ranges and cp.captured) or (
+ DisplayOptions.enemy_sam_ranges and not cp.captured
+ )
- def draw_threat_range(self, scene: QGraphicsScene, group: Group, ground_object: TheaterGroundObject, cp: ControlPoint) -> None:
+ def draw_threat_range(
+ self,
+ scene: QGraphicsScene,
+ group: Group,
+ ground_object: TheaterGroundObject,
+ cp: ControlPoint,
+ ) -> None:
go_pos = self._transform_point(ground_object.position)
detection_range = ground_object.detection_range(group)
threat_range = ground_object.threat_range(group)
if threat_range:
threat_pos = self._transform_point(
- ground_object.position + Point(threat_range.meters,
- threat_range.meters))
+ ground_object.position + Point(threat_range.meters, threat_range.meters)
+ )
threat_radius = Point(*go_pos).distance_to_point(Point(*threat_pos))
# Add threat range circle
- scene.addEllipse(go_pos[0] - threat_radius / 2 + 7, go_pos[1] - threat_radius / 2 + 6,
- threat_radius, threat_radius, self.threat_pen(cp.captured))
+ scene.addEllipse(
+ go_pos[0] - threat_radius / 2 + 7,
+ go_pos[1] - threat_radius / 2 + 6,
+ threat_radius,
+ threat_radius,
+ self.threat_pen(cp.captured),
+ )
if detection_range and DisplayOptions.detection_range:
# Add detection range circle
detection_pos = self._transform_point(
- ground_object.position + Point(detection_range.meters,
- detection_range.meters))
+ ground_object.position
+ + Point(detection_range.meters, detection_range.meters)
+ )
detection_radius = Point(*go_pos).distance_to_point(Point(*detection_pos))
- scene.addEllipse(go_pos[0] - detection_radius/2 + 7, go_pos[1] - detection_radius/2 + 6,
- detection_radius, detection_radius, self.detection_pen(cp.captured))
+ scene.addEllipse(
+ go_pos[0] - detection_radius / 2 + 7,
+ go_pos[1] - detection_radius / 2 + 6,
+ detection_radius,
+ detection_radius,
+ self.detection_pen(cp.captured),
+ )
def draw_ground_objects(self, scene: QGraphicsScene, cp: ControlPoint) -> None:
added_objects = []
@@ -486,8 +567,22 @@ class QLiberationMap(QGraphicsView):
go_pos = self._transform_point(ground_object.position)
if not ground_object.airbase_group:
- buildings = self.game.theater.find_ground_objects_by_obj_name(ground_object.obj_name)
- scene.addItem(QMapGroundObject(self, go_pos[0], go_pos[1], 14, 12, cp, ground_object, self.game, buildings))
+ buildings = self.game.theater.find_ground_objects_by_obj_name(
+ ground_object.obj_name
+ )
+ scene.addItem(
+ QMapGroundObject(
+ self,
+ go_pos[0],
+ go_pos[1],
+ 14,
+ 12,
+ cp,
+ ground_object,
+ self.game,
+ buildings,
+ )
+ )
should_display = self.should_display_ground_objects_at(cp)
if ground_object.might_have_aa and should_display:
@@ -508,10 +603,8 @@ class QLiberationMap(QGraphicsView):
if DisplayOptions.culling and self.game.settings.perf_culling:
self.display_culling(scene)
- self.display_threat_zones(scene, DisplayOptions.blue_threat_zones,
- player=True)
- self.display_threat_zones(scene, DisplayOptions.red_threat_zones,
- player=False)
+ self.display_threat_zones(scene, DisplayOptions.blue_threat_zones, player=True)
+ self.display_threat_zones(scene, DisplayOptions.red_threat_zones, player=False)
if DisplayOptions.navmeshes.blue_navmesh:
self.display_navmesh(scene, player=True)
@@ -522,24 +615,33 @@ class QLiberationMap(QGraphicsView):
pos = self._transform_point(cp.position)
- scene.addItem(QMapControlPoint(self, pos[0] - CONST.CP_SIZE / 2,
- pos[1] - CONST.CP_SIZE / 2,
- CONST.CP_SIZE,
- CONST.CP_SIZE, cp, self.game_model))
+ scene.addItem(
+ QMapControlPoint(
+ self,
+ pos[0] - CONST.CP_SIZE / 2,
+ pos[1] - CONST.CP_SIZE / 2,
+ CONST.CP_SIZE,
+ CONST.CP_SIZE,
+ cp,
+ self.game_model,
+ )
+ )
if cp.captured:
pen = QPen(brush=CONST.COLORS[playerColor])
- brush = CONST.COLORS[playerColor+"_transparent"]
+ brush = CONST.COLORS[playerColor + "_transparent"]
else:
pen = QPen(brush=CONST.COLORS[enemyColor])
- brush = CONST.COLORS[enemyColor+"_transparent"]
+ brush = CONST.COLORS[enemyColor + "_transparent"]
self.draw_ground_objects(scene, cp)
if cp.target_position is not None:
proj = self._transform_point(cp.target_position)
- scene.addLine(QLineF(QPointF(pos[0], pos[1]), QPointF(proj[0], proj[1])),
- QPen(CONST.COLORS["green"], width=10, s=Qt.DashDotLine))
+ scene.addLine(
+ QLineF(QPointF(pos[0], pos[1]), QPointF(proj[0], proj[1])),
+ QPen(CONST.COLORS["green"], width=10, s=Qt.DashDotLine),
+ )
for cp in self.game.theater.enemy_points():
if DisplayOptions.lines:
@@ -585,8 +687,9 @@ class QLiberationMap(QGraphicsView):
continue
self.draw_flight_plan(scene, flight, selected)
- def draw_flight_plan(self, scene: QGraphicsScene, flight: Flight,
- selected: bool) -> None:
+ def draw_flight_plan(
+ self, scene: QGraphicsScene, flight: Flight, selected: bool
+ ) -> None:
is_player = flight.from_cp.captured
pos = self._transform_point(flight.from_cp.position)
@@ -604,8 +707,7 @@ class QLiberationMap(QGraphicsView):
continue
new_pos = self._transform_point(Point(point.x, point.y))
- self.draw_flight_path(scene, prev_pos, new_pos, is_player,
- selected)
+ self.draw_flight_path(scene, prev_pos, new_pos, is_player, selected)
self.draw_waypoint(scene, new_pos, is_player, selected)
if selected and DisplayOptions.waypoint_info:
if point.waypoint_type in target_types:
@@ -613,44 +715,63 @@ class QLiberationMap(QGraphicsView):
# Don't draw dozens of targets over each other.
continue
drew_target = True
- self.draw_waypoint_info(scene, idx + 1, point, new_pos,
- flight.flight_plan)
+ self.draw_waypoint_info(
+ scene, idx + 1, point, new_pos, flight.flight_plan
+ )
prev_pos = tuple(new_pos)
if selected and DisplayOptions.barcap_commit_range:
self.draw_barcap_commit_range(scene, flight)
- def draw_barcap_commit_range(self, scene: QGraphicsScene,
- flight: Flight) -> None:
+ def draw_barcap_commit_range(self, scene: QGraphicsScene, flight: Flight) -> None:
if flight.flight_type is not FlightType.BARCAP:
return
if not isinstance(flight.flight_plan, BarCapFlightPlan):
return
start = flight.flight_plan.patrol_start
end = flight.flight_plan.patrol_end
- line = LineString([
- ShapelyPoint(start.x, start.y),
- ShapelyPoint(end.x, end.y),
- ])
+ line = LineString(
+ [
+ ShapelyPoint(start.x, start.y),
+ ShapelyPoint(end.x, end.y),
+ ]
+ )
doctrine = self.game.faction_for(flight.departure.captured).doctrine
bubble = line.buffer(doctrine.cap_engagement_range.meters)
- self.flight_path_items.append(self.draw_shapely_poly(
- scene, bubble, CONST.COLORS["yellow"], CONST.COLORS["transparent"]
- ))
+ self.flight_path_items.append(
+ self.draw_shapely_poly(
+ scene, bubble, CONST.COLORS["yellow"], CONST.COLORS["transparent"]
+ )
+ )
- def draw_waypoint(self, scene: QGraphicsScene,
- position: Tuple[float, float], player: bool,
- selected: bool) -> None:
+ def draw_waypoint(
+ self,
+ scene: QGraphicsScene,
+ position: Tuple[float, float],
+ player: bool,
+ selected: bool,
+ ) -> None:
waypoint_pen = self.waypoint_pen(player, selected)
waypoint_brush = self.waypoint_brush(player, selected)
- self.flight_path_items.append(scene.addEllipse(
- position[0], position[1], self.WAYPOINT_SIZE,
- self.WAYPOINT_SIZE, waypoint_pen, waypoint_brush
- ))
+ self.flight_path_items.append(
+ scene.addEllipse(
+ position[0],
+ position[1],
+ self.WAYPOINT_SIZE,
+ self.WAYPOINT_SIZE,
+ waypoint_pen,
+ waypoint_brush,
+ )
+ )
- def draw_waypoint_info(self, scene: QGraphicsScene, number: int,
- waypoint: FlightWaypoint, position: Tuple[int, int],
- flight_plan: FlightPlan) -> None:
+ def draw_waypoint_info(
+ self,
+ scene: QGraphicsScene,
+ number: int,
+ waypoint: FlightWaypoint,
+ position: Tuple[int, int],
+ flight_plan: FlightPlan,
+ ) -> None:
altitude = int(waypoint.alt.feet)
altitude_type = "AGL" if waypoint.alt_type == "RADIO" else "MSL"
@@ -669,11 +790,13 @@ class QLiberationMap(QGraphicsView):
pen = QPen(QColor("black"), 0.3)
brush = QColor("white")
- text = "\n".join([
- f"{number} {waypoint.name}",
- f"{altitude} ft {altitude_type}",
- tot,
- ])
+ text = "\n".join(
+ [
+ f"{number} {waypoint.name}",
+ f"{altitude} ft {altitude_type}",
+ tot,
+ ]
+ )
item = scene.addSimpleText(text, self.waypoint_info_font)
item.setFlag(QGraphicsItem.ItemIgnoresTransformations)
@@ -683,19 +806,30 @@ class QLiberationMap(QGraphicsView):
item.setZValue(2)
self.flight_path_items.append(item)
- def draw_flight_path(self, scene: QGraphicsScene, pos0: Tuple[float, float],
- pos1: Tuple[float, float], player: bool,
- selected: bool) -> None:
+ def draw_flight_path(
+ self,
+ scene: QGraphicsScene,
+ pos0: Tuple[float, float],
+ pos1: Tuple[float, float],
+ player: bool,
+ selected: bool,
+ ) -> None:
flight_path_pen = self.flight_path_pen(player, selected)
# Draw the line to the *middle* of the waypoint.
offset = self.WAYPOINT_SIZE // 2
- self.flight_path_items.append(scene.addLine(
- pos0[0] + offset, pos0[1] + offset,
- pos1[0] + offset, pos1[1] + offset,
- flight_path_pen
- ))
+ self.flight_path_items.append(
+ scene.addLine(
+ pos0[0] + offset,
+ pos0[1] + offset,
+ pos1[0] + offset,
+ pos1[1] + offset,
+ flight_path_pen,
+ )
+ )
- def draw_bezier_frontline(self, scene: QGraphicsScene, pen:QPen, frontline: FrontLine) -> None:
+ def draw_bezier_frontline(
+ self, scene: QGraphicsScene, pen: QPen, frontline: FrontLine
+ ) -> None:
"""
Thanks to Alquimista for sharing a python implementation of the bezier algorithm this is adapted from.
https://gist.github.com/Alquimista/1274149#file-bezdraw-py
@@ -706,7 +840,9 @@ class QLiberationMap(QGraphicsView):
bezier_fixed_points.append(self._transform_point(segment.point_b))
old_point = bezier_fixed_points[0]
- for point in bezier_curve_range(int(len(bezier_fixed_points) * 2), bezier_fixed_points):
+ for point in bezier_curve_range(
+ int(len(bezier_fixed_points) * 2), bezier_fixed_points
+ ):
scene.addLine(old_point[0], old_point[1], point[0], point[1], pen=pen)
old_point = point
@@ -715,14 +851,18 @@ class QLiberationMap(QGraphicsView):
for connected_cp in cp.connected_points:
pos2 = self._transform_point(connected_cp.position)
if not cp.captured:
- color = CONST.COLORS["dark_"+enemyColor]
+ color = CONST.COLORS["dark_" + enemyColor]
else:
- color = CONST.COLORS["dark_"+playerColor]
+ color = CONST.COLORS["dark_" + playerColor]
pen = QPen(brush=color)
pen.setColor(color)
pen.setWidth(6)
frontline = FrontLine(cp, connected_cp, self.game.theater)
- if cp.captured and not connected_cp.captured and Conflict.has_frontline_between(cp, connected_cp):
+ if (
+ cp.captured
+ and not connected_cp.captured
+ and Conflict.has_frontline_between(cp, connected_cp)
+ ):
if DisplayOptions.actual_frontline_pos:
self.draw_actual_frontline(frontline, scene, pen)
else:
@@ -730,35 +870,30 @@ class QLiberationMap(QGraphicsView):
else:
self.draw_bezier_frontline(scene, pen, frontline)
- def draw_frontline_approximation(self, frontline: FrontLine, scene: QGraphicsScene, pen: QPen) -> None:
+ def draw_frontline_approximation(
+ self, frontline: FrontLine, scene: QGraphicsScene, pen: QPen
+ ) -> None:
posx = frontline.position
h = frontline.attack_heading
pos2 = self._transform_point(posx)
self.draw_bezier_frontline(scene, pen, frontline)
- p1 = point_from_heading(pos2[0], pos2[1], h+180, 25)
+ p1 = point_from_heading(pos2[0], pos2[1], h + 180, 25)
p2 = point_from_heading(pos2[0], pos2[1], h, 25)
scene.addItem(
- QFrontLine(
- p1[0],
- p1[1],
- p2[0],
- p2[1],
- frontline,
- self.game_model
- )
+ QFrontLine(p1[0], p1[1], p2[0], p2[1], frontline, self.game_model)
)
- def draw_actual_frontline(self, frontline: FrontLine, scene: QGraphicsScene, pen: QPen) -> None:
+ def draw_actual_frontline(
+ self, frontline: FrontLine, scene: QGraphicsScene, pen: QPen
+ ) -> None:
self.draw_bezier_frontline(scene, pen, frontline)
vector = Conflict.frontline_vector(
- frontline.control_point_a,
- frontline.control_point_b,
- self.game.theater
+ frontline.control_point_a, frontline.control_point_b, self.game.theater
)
left_pos = self._transform_point(vector[0])
right_pos = self._transform_point(
- vector[0].point_from_heading(vector[1], vector[2])
- )
+ vector[0].point_from_heading(vector[1], vector[2])
+ )
scene.addItem(
QFrontLine(
left_pos[0],
@@ -766,7 +901,7 @@ class QLiberationMap(QGraphicsView):
right_pos[0],
right_pos[1],
frontline,
- self.game_model
+ self.game_model,
)
)
@@ -779,26 +914,48 @@ class QLiberationMap(QGraphicsView):
SMALL_LINE = 2
dist = self.distance_to_pixels(nautical_miles(scale_distance_nm))
- self.scene().addRect(POS_X, POS_Y-PADDING, PADDING*2 + dist, BIG_LINE*2+3*PADDING, pen=CONST.COLORS["black"], brush=CONST.COLORS["black"])
- l = self.scene().addLine(POS_X + PADDING, POS_Y + BIG_LINE*2, POS_X + PADDING + dist, POS_Y + BIG_LINE*2)
+ self.scene().addRect(
+ POS_X,
+ POS_Y - PADDING,
+ PADDING * 2 + dist,
+ BIG_LINE * 2 + 3 * PADDING,
+ pen=CONST.COLORS["black"],
+ brush=CONST.COLORS["black"],
+ )
+ l = self.scene().addLine(
+ POS_X + PADDING,
+ POS_Y + BIG_LINE * 2,
+ POS_X + PADDING + dist,
+ POS_Y + BIG_LINE * 2,
+ )
- text = self.scene().addText("0nm", font=QFont("Trebuchet MS", 6, weight=5, italic=False))
- text.setPos(POS_X, POS_Y + BIG_LINE*2)
+ text = self.scene().addText(
+ "0nm", font=QFont("Trebuchet MS", 6, weight=5, italic=False)
+ )
+ text.setPos(POS_X, POS_Y + BIG_LINE * 2)
text.setDefaultTextColor(Qt.white)
- text2 = self.scene().addText(str(scale_distance_nm) + "nm", font=QFont("Trebuchet MS", 6, weight=5, italic=False))
+ text2 = self.scene().addText(
+ str(scale_distance_nm) + "nm",
+ font=QFont("Trebuchet MS", 6, weight=5, italic=False),
+ )
text2.setPos(POS_X + dist, POS_Y + BIG_LINE * 2)
text2.setDefaultTextColor(Qt.white)
l.setPen(CONST.COLORS["white"])
- for i in range(number_of_points+1):
- d = float(i)/float(number_of_points)
+ for i in range(number_of_points + 1):
+ d = float(i) / float(number_of_points)
if i == 0 or i == number_of_points:
h = BIG_LINE
else:
h = SMALL_LINE
- l = self.scene().addLine(POS_X + PADDING + d * dist, POS_Y + BIG_LINE*2, POS_X + PADDING + d * dist, POS_Y + BIG_LINE - h)
+ l = self.scene().addLine(
+ POS_X + PADDING + d * dist,
+ POS_Y + BIG_LINE * 2,
+ POS_X + PADDING + d * dist,
+ POS_Y + BIG_LINE - h,
+ )
l.setPen(CONST.COLORS["white"])
def wheelEvent(self, event: QWheelEvent):
@@ -828,7 +985,8 @@ class QLiberationMap(QGraphicsView):
point_b = self.game.theater.reference_points[1]
world_distance = self._transpose_point(
- point_b.world_coordinates - point_a.world_coordinates)
+ point_b.world_coordinates - point_a.world_coordinates
+ )
image_distance = point_b.image_coordinates - point_a.image_coordinates
x_scale = image_distance.x / world_distance.x
@@ -870,8 +1028,7 @@ class QLiberationMap(QGraphicsView):
scale = self._scaling_factor()
offset = point_a.image_coordinates - scene_point
- scaled = self._transpose_point(
- Point(offset.x / scale.x, offset.y / scale.y))
+ scaled = self._transpose_point(Point(offset.x / scale.x, offset.y / scale.y))
return point_a.world_coordinates - scaled
def distance_to_pixels(self, distance: Distance) -> int:
@@ -955,7 +1112,12 @@ class QLiberationMap(QGraphicsView):
for sea_zone in self.game.theater.landmap.sea_zones:
print(sea_zone)
- poly = QPolygonF([QPointF(*self._transform_point(Point(point[0], point[1]))) for point in sea_zone.exterior.coords])
+ poly = QPolygonF(
+ [
+ QPointF(*self._transform_point(Point(point[0], point[1])))
+ for point in sea_zone.exterior.coords
+ ]
+ )
if self.reference_point_setup_mode:
color = "sea_blue_transparent"
else:
@@ -963,18 +1125,40 @@ class QLiberationMap(QGraphicsView):
scene.addPolygon(poly, CONST.COLORS[color], CONST.COLORS[color])
for inclusion_zone in self.game.theater.landmap.inclusion_zones:
- poly = QPolygonF([QPointF(*self._transform_point(Point(point[0], point[1]))) for point in inclusion_zone.exterior.coords])
+ poly = QPolygonF(
+ [
+ QPointF(*self._transform_point(Point(point[0], point[1])))
+ for point in inclusion_zone.exterior.coords
+ ]
+ )
if self.reference_point_setup_mode:
- scene.addPolygon(poly, CONST.COLORS["grey_transparent"], CONST.COLORS["dark_grey_transparent"])
+ scene.addPolygon(
+ poly,
+ CONST.COLORS["grey_transparent"],
+ CONST.COLORS["dark_grey_transparent"],
+ )
else:
- scene.addPolygon(poly, CONST.COLORS["grey"], CONST.COLORS["dark_grey"])
+ scene.addPolygon(
+ poly, CONST.COLORS["grey"], CONST.COLORS["dark_grey"]
+ )
for exclusion_zone in self.game.theater.landmap.exclusion_zones:
- poly = QPolygonF([QPointF(*self._transform_point(Point(point[0], point[1]))) for point in exclusion_zone.exterior.coords])
+ poly = QPolygonF(
+ [
+ QPointF(*self._transform_point(Point(point[0], point[1])))
+ for point in exclusion_zone.exterior.coords
+ ]
+ )
if self.reference_point_setup_mode:
- scene.addPolygon(poly, CONST.COLORS["grey_transparent"], CONST.COLORS["dark_dark_grey_transparent"])
+ scene.addPolygon(
+ poly,
+ CONST.COLORS["grey_transparent"],
+ CONST.COLORS["dark_dark_grey_transparent"],
+ )
else:
- scene.addPolygon(poly, CONST.COLORS["grey"], CONST.COLORS["dark_dark_grey"])
+ scene.addPolygon(
+ poly, CONST.COLORS["grey"], CONST.COLORS["dark_dark_grey"]
+ )
# Uncomment to display plan projection test
# self.projection_test()
@@ -983,15 +1167,18 @@ class QLiberationMap(QGraphicsView):
if self.reference_point_setup_mode:
for i, point in enumerate(self.game.theater.reference_points):
self.scene().addRect(
- QRectF(point.image_coordinates.x, point.image_coordinates.y,
- 25, 25), pen=CONST.COLORS["red"],
- brush=CONST.COLORS["red"])
+ QRectF(
+ point.image_coordinates.x, point.image_coordinates.y, 25, 25
+ ),
+ pen=CONST.COLORS["red"],
+ brush=CONST.COLORS["red"],
+ )
text = self.scene().addText(
f"P{i} = {point.image_coordinates}",
- font=QFont("Trebuchet MS", 14, weight=8, italic=False))
+ font=QFont("Trebuchet MS", 14, weight=8, italic=False),
+ )
text.setDefaultTextColor(CONST.COLORS["red"])
- text.setPos(point.image_coordinates.x + 26,
- point.image_coordinates.y)
+ text.setPos(point.image_coordinates.x + 26, point.image_coordinates.y)
# Set to True to visually debug _transform_point.
draw_transformed = False
@@ -1000,10 +1187,12 @@ class QLiberationMap(QGraphicsView):
self.scene().addRect(
QRectF(x, y, 25, 25),
pen=CONST.COLORS["red"],
- brush=CONST.COLORS["red"])
+ brush=CONST.COLORS["red"],
+ )
text = self.scene().addText(
f"P{i}' = {x}, {y}",
- font=QFont("Trebuchet MS", 14, weight=8, italic=False))
+ font=QFont("Trebuchet MS", 14, weight=8, italic=False),
+ )
text.setDefaultTextColor(CONST.COLORS["red"])
text.setPos(x + 26, y)
@@ -1023,7 +1212,9 @@ class QLiberationMap(QGraphicsView):
self.state = QLiberationMapState.MOVING_UNIT
self.selected_cp = selected_cp
position = self._transform_point(selected_cp.control_point.position)
- self.movement_line = QtWidgets.QGraphicsLineItem(QLineF(QPointF(*position), QPointF(*position)))
+ self.movement_line = QtWidgets.QGraphicsLineItem(
+ QLineF(QPointF(*position), QPointF(*position))
+ )
self.scene().addItem(self.movement_line)
def is_valid_ship_pos(self, scene_position: Point) -> bool:
@@ -1043,7 +1234,8 @@ class QLiberationMap(QGraphicsView):
if self.state == QLiberationMapState.MOVING_UNIT:
self.setCursor(Qt.PointingHandCursor)
self.movement_line.setLine(
- QLineF(self.movement_line.line().p1(), event.scenePos()))
+ QLineF(self.movement_line.line().p1(), event.scenePos())
+ )
if self.is_valid_ship_pos(mouse_position):
self.movement_line.setPen(CONST.COLORS["green"])
@@ -1053,21 +1245,28 @@ class QLiberationMap(QGraphicsView):
mouse_world_pos = self._scene_to_dcs_coords(mouse_position)
if DisplayOptions.navmeshes.blue_navmesh:
self.highlight_mouse_navmesh(
- self.scene(), self.game.blue_navmesh,
- self._scene_to_dcs_coords(mouse_position))
+ self.scene(),
+ self.game.blue_navmesh,
+ self._scene_to_dcs_coords(mouse_position),
+ )
if DisplayOptions.path_debug.shortest_path:
- self.draw_shortest_path(self.scene(), self.game.blue_navmesh,
- mouse_world_pos, player=True)
+ self.draw_shortest_path(
+ self.scene(), self.game.blue_navmesh, mouse_world_pos, player=True
+ )
if DisplayOptions.navmeshes.red_navmesh:
self.highlight_mouse_navmesh(
- self.scene(), self.game.red_navmesh, mouse_world_pos)
+ self.scene(), self.game.red_navmesh, mouse_world_pos
+ )
debug_blue = DisplayOptions.path_debug_faction.blue
if DisplayOptions.path_debug.shortest_path:
self.draw_shortest_path(
- self.scene(), self.game.navmesh_for(player=debug_blue),
- mouse_world_pos, player=False)
+ self.scene(),
+ self.game.navmesh_for(player=debug_blue),
+ mouse_world_pos,
+ player=False,
+ )
elif not DisplayOptions.path_debug.hide:
if DisplayOptions.path_debug.barcap:
task = FlightType.BARCAP
@@ -1080,10 +1279,10 @@ class QLiberationMap(QGraphicsView):
elif DisplayOptions.path_debug.tarcap:
task = FlightType.TARCAP
else:
- raise ValueError(
- "Unexpected value for DisplayOptions.path_debug")
- self.draw_test_flight_plan(self.scene(), task, mouse_world_pos,
- player=debug_blue)
+ raise ValueError("Unexpected value for DisplayOptions.path_debug")
+ self.draw_test_flight_plan(
+ self.scene(), task, mouse_world_pos, player=debug_blue
+ )
def sceneMousePressEvent(self, event: QGraphicsSceneMouseEvent):
if self.state == QLiberationMapState.MOVING_UNIT:
@@ -1109,4 +1308,4 @@ class QLiberationMap(QGraphicsView):
self.scene().removeItem(self.movement_line)
except:
pass
- self.selected_cp = None
\ No newline at end of file
+ self.selected_cp = None
diff --git a/qt_ui/widgets/map/QLiberationScene.py b/qt_ui/widgets/map/QLiberationScene.py
index 5ad08d5e..fff8c379 100644
--- a/qt_ui/widgets/map/QLiberationScene.py
+++ b/qt_ui/widgets/map/QLiberationScene.py
@@ -4,17 +4,18 @@ import qt_ui.uiconstants as CONST
class QLiberationScene(QGraphicsScene):
-
def __init__(self, parent):
super().__init__(parent)
- item = self.addText("Go to \"File/New Game\" to setup a new campaign or go to \"File/Open\" to load an existing save game.",
- CONST.FONT_PRIMARY)
+ item = self.addText(
+ 'Go to "File/New Game" to setup a new campaign or go to "File/Open" to load an existing save game.',
+ CONST.FONT_PRIMARY,
+ )
item.setDefaultTextColor(CONST.COLORS["white"])
def mouseMoveEvent(self, event: QGraphicsSceneMouseEvent):
super(QLiberationScene, self).mouseMoveEvent(event)
self.parent().sceneMouseMovedEvent(event)
- def mousePressEvent(self, event:QGraphicsSceneMouseEvent):
+ def mousePressEvent(self, event: QGraphicsSceneMouseEvent):
super(QLiberationScene, self).mousePressEvent(event)
self.parent().sceneMousePressEvent(event)
diff --git a/qt_ui/widgets/map/QMapControlPoint.py b/qt_ui/widgets/map/QMapControlPoint.py
index 035db95e..12bfce6a 100644
--- a/qt_ui/widgets/map/QMapControlPoint.py
+++ b/qt_ui/widgets/map/QMapControlPoint.py
@@ -13,8 +13,16 @@ from ...windows.GameUpdateSignal import GameUpdateSignal
class QMapControlPoint(QMapObject):
- def __init__(self, parent, x: float, y: float, w: float, h: float,
- control_point: ControlPoint, game_model: GameModel) -> None:
+ def __init__(
+ self,
+ parent,
+ x: float,
+ y: float,
+ w: float,
+ h: float,
+ control_point: ControlPoint,
+ game_model: GameModel,
+ ) -> None:
super().__init__(x, y, w, h, mission_target=control_point)
self.game_model = game_model
self.control_point = control_point
@@ -22,8 +30,7 @@ class QMapControlPoint(QMapObject):
self.setZValue(1)
self.setToolTip(self.control_point.name)
self.base_details_dialog: Optional[QBaseMenu2] = None
- self.capture_action = QAction(
- f"CHEAT: Capture {self.control_point.name}")
+ self.capture_action = QAction(f"CHEAT: Capture {self.control_point.name}")
self.capture_action.triggered.connect(self.cheat_capture)
self.move_action = QAction("Move")
@@ -69,9 +76,7 @@ class QMapControlPoint(QMapObject):
def on_click(self) -> None:
self.base_details_dialog = QBaseMenu2(
- self.window(),
- self.control_point,
- self.game_model
+ self.window(), self.control_point, self.game_model
)
self.base_details_dialog.show()
@@ -89,7 +94,10 @@ class QMapControlPoint(QMapObject):
return
for connected in self.control_point.connected_points:
- if connected.captured and self.game_model.game.settings.enable_base_capture_cheat:
+ if (
+ connected.captured
+ and self.game_model.game.settings.enable_base_capture_cheat
+ ):
menu.addAction(self.capture_action)
break
@@ -105,7 +113,7 @@ class QMapControlPoint(QMapObject):
def cancel_move(self):
self.control_point.target_position = None
GameUpdateSignal.get_instance().updateGame(self.game_model.game)
-
+
def open_new_package_dialog(self) -> None:
"""Extends the default packagedialog to redirect to base menu for red air base."""
is_navy = isinstance(self.control_point, NavalControlPoint)
diff --git a/qt_ui/widgets/map/QMapGroundObject.py b/qt_ui/widgets/map/QMapGroundObject.py
index da69a9fc..4d8b5a3a 100644
--- a/qt_ui/widgets/map/QMapGroundObject.py
+++ b/qt_ui/widgets/map/QMapGroundObject.py
@@ -16,10 +16,18 @@ from ...displayoptions import DisplayOptions
class QMapGroundObject(QMapObject):
- def __init__(self, parent, x: float, y: float, w: float, h: float,
- control_point: ControlPoint,
- ground_object: TheaterGroundObject, game: Game,
- buildings: Optional[List[TheaterGroundObject]] = None) -> None:
+ def __init__(
+ self,
+ parent,
+ x: float,
+ y: float,
+ w: float,
+ h: float,
+ control_point: ControlPoint,
+ ground_object: TheaterGroundObject,
+ game: Game,
+ buildings: Optional[List[TheaterGroundObject]] = None,
+ ) -> None:
super().__init__(x, y, w, h, mission_target=ground_object)
self.ground_object = ground_object
self.control_point = control_point
@@ -42,7 +50,7 @@ class QMapGroundObject(QMapObject):
for g in self.ground_object.groups:
for u in g.units:
if u.type in units:
- units[u.type] = units[u.type]+1
+ units[u.type] = units[u.type] + 1
else:
units[u.type] = 1
@@ -78,8 +86,12 @@ class QMapGroundObject(QMapObject):
if isinstance(self.ground_object, MissileSiteGroundObject):
cat = "missile"
- rect = QRect(option.rect.x() + 2, option.rect.y(),
- option.rect.width() - 2, option.rect.height())
+ rect = QRect(
+ option.rect.x() + 2,
+ option.rect.y(),
+ option.rect.width() - 2,
+ option.rect.height(),
+ )
is_dead = self.ground_object.is_dead
for building in self.buildings:
@@ -96,7 +108,7 @@ class QMapGroundObject(QMapObject):
if not is_dead and not self.control_point.captured:
if cat == "aa" and not has_threat:
painter.drawPixmap(rect, const.ICONS["nothreat" + enemy_icons])
- else:
+ else:
painter.drawPixmap(rect, const.ICONS[cat + enemy_icons])
elif not is_dead:
if cat == "aa" and not has_threat:
@@ -128,13 +140,22 @@ class QMapGroundObject(QMapObject):
units_dead += len(g.units_losts)
if units_dead + units_alive > 0:
- ratio = float(units_alive)/(float(units_dead) + float(units_alive))
+ ratio = float(units_alive) / (float(units_dead) + float(units_alive))
bar_height = ratio * option.rect.height()
- painter.fillRect(option.rect.x(), option.rect.y(), 2,
- option.rect.height(),
- QBrush(const.COLORS["dark_red"]))
- painter.fillRect(option.rect.x(), option.rect.y(), 2, bar_height,
- QBrush(const.COLORS["green"]))
+ painter.fillRect(
+ option.rect.x(),
+ option.rect.y(),
+ 2,
+ option.rect.height(),
+ QBrush(const.COLORS["dark_red"]),
+ )
+ painter.fillRect(
+ option.rect.x(),
+ option.rect.y(),
+ 2,
+ bar_height,
+ QBrush(const.COLORS["green"]),
+ )
def on_click(self) -> None:
self.ground_object_dialog = QGroundObjectMenu(
@@ -142,6 +163,6 @@ class QMapGroundObject(QMapObject):
self.ground_object,
self.buildings,
self.control_point,
- self.game
+ self.game,
)
self.ground_object_dialog.show()
diff --git a/qt_ui/widgets/map/QMapObject.py b/qt_ui/widgets/map/QMapObject.py
index a12feb33..f4b0bfb6 100644
--- a/qt_ui/widgets/map/QMapObject.py
+++ b/qt_ui/widgets/map/QMapObject.py
@@ -23,8 +23,9 @@ class QMapObject(QGraphicsRectItem):
change the mouse cursor on hover.
"""
- def __init__(self, x: float, y: float, w: float, h: float,
- mission_target: MissionTarget) -> None:
+ def __init__(
+ self, x: float, y: float, w: float, h: float, mission_target: MissionTarget
+ ) -> None:
super().__init__(x, y, w, h)
self.mission_target = mission_target
self.new_package_dialog: Optional[QNewPackageDialog] = None
diff --git a/qt_ui/widgets/spinsliders.py b/qt_ui/widgets/spinsliders.py
index 1b63862b..90623a6d 100644
--- a/qt_ui/widgets/spinsliders.py
+++ b/qt_ui/widgets/spinsliders.py
@@ -5,8 +5,7 @@ from qt_ui.widgets.floatspinners import TenthsSpinner
class TenthsSpinSlider(QGridLayout):
- def __init__(self, label: str, minimum: int, maximum: int,
- initial: int) -> None:
+ def __init__(self, label: str, minimum: int, maximum: int, initial: int) -> None:
super().__init__()
self.addWidget(QLabel(label), 0, 0)
diff --git a/qt_ui/widgets/views/QSeadTargetInfoView.py b/qt_ui/widgets/views/QSeadTargetInfoView.py
index 06dcdfc3..0fc40b22 100644
--- a/qt_ui/widgets/views/QSeadTargetInfoView.py
+++ b/qt_ui/widgets/views/QSeadTargetInfoView.py
@@ -31,12 +31,3 @@ class QSeadTargetInfoView(QGroupBox):
for r in self.sead_target_infos.radars:
radar_list_model.appendRow(QStandardItem(r.type))
self.radar_list.setModel(radar_list_model)
-
-
-
-
-
-
-
-
-
diff --git a/qt_ui/widgets/views/QStrikeTargetInfoView.py b/qt_ui/widgets/views/QStrikeTargetInfoView.py
index efa707f9..cb24f0a5 100644
--- a/qt_ui/widgets/views/QStrikeTargetInfoView.py
+++ b/qt_ui/widgets/views/QStrikeTargetInfoView.py
@@ -1,7 +1,14 @@
import random
from PySide2.QtGui import QStandardItemModel, QStandardItem
-from PySide2.QtWidgets import QGroupBox, QLabel, QWidget, QVBoxLayout, QListView, QAbstractItemView
+from PySide2.QtWidgets import (
+ QGroupBox,
+ QLabel,
+ QWidget,
+ QVBoxLayout,
+ QListView,
+ QAbstractItemView,
+)
from qt_ui.widgets.combos.QStrikeTargetSelectionComboBox import StrikeTargetInfo
@@ -16,7 +23,9 @@ class QStrikeTargetInfoView(QGroupBox):
if strike_target_infos is None:
strike_target_infos = StrikeTargetInfo()
- super(QStrikeTargetInfoView, self).__init__("Target : " + strike_target_infos.name)
+ super(QStrikeTargetInfoView, self).__init__(
+ "Target : " + strike_target_infos.name
+ )
self.strike_target_infos = strike_target_infos
@@ -24,14 +33,12 @@ class QStrikeTargetInfoView(QGroupBox):
self.init_ui()
-
def init_ui(self):
layout = QVBoxLayout(self)
layout.setSpacing(0)
layout.addWidget(self.listView)
self.setLayout(layout)
-
def setTarget(self, target):
self.setTitle(target.name)
@@ -40,36 +47,27 @@ class QStrikeTargetInfoView(QGroupBox):
self.listView.setSelectionMode(QAbstractItemView.NoSelection)
if len(self.strike_target_infos.units) > 0:
- dic = {}
- for u in self.strike_target_infos.units:
- if u.type in dic.keys():
- dic[u.type] = dic[u.type] + 1
- else:
- dic[u.type] = 1
- for k,v in dic.items():
- model.appendRow(QStandardItem(k + " x " + str(v)))
- print(k + " x " + str(v))
+ dic = {}
+ for u in self.strike_target_infos.units:
+ if u.type in dic.keys():
+ dic[u.type] = dic[u.type] + 1
+ else:
+ dic[u.type] = 1
+ for k, v in dic.items():
+ model.appendRow(QStandardItem(k + " x " + str(v)))
+ print(k + " x " + str(v))
else:
- dic = {}
- for b in self.strike_target_infos.buildings:
- id = b.dcs_identifier
- if b.is_dead:
- id = id + "[Destroyed]"
- if id in dic.keys():
- dic[id] = dic[id] + 1
- else:
- dic[id] = 1
- for k, v in dic.items():
- model.appendRow(QStandardItem(k + " x " + str(v)))
- print(k + " x " + str(v))
+ dic = {}
+ for b in self.strike_target_infos.buildings:
+ id = b.dcs_identifier
+ if b.is_dead:
+ id = id + "[Destroyed]"
+ if id in dic.keys():
+ dic[id] = dic[id] + 1
+ else:
+ dic[id] = 1
+ for k, v in dic.items():
+ model.appendRow(QStandardItem(k + " x " + str(v)))
+ print(k + " x " + str(v))
self.listView.setModel(model)
-
-
-
-
-
-
-
-
-
diff --git a/qt_ui/windows/QDebriefingWindow.py b/qt_ui/windows/QDebriefingWindow.py
index f54530a0..d4fa312b 100644
--- a/qt_ui/windows/QDebriefingWindow.py
+++ b/qt_ui/windows/QDebriefingWindow.py
@@ -15,7 +15,6 @@ from game.debriefing import Debriefing
class QDebriefingWindow(QDialog):
-
def __init__(self, debriefing: Debriefing):
super(QDebriefingWindow, self).__init__()
self.debriefing = debriefing
@@ -42,8 +41,7 @@ class QDebriefingWindow(QDialog):
self.layout.addWidget(title)
# Player lost units
- lostUnits = QGroupBox(
- f"{self.debriefing.player_country}'s lost units:")
+ lostUnits = QGroupBox(f"{self.debriefing.player_country}'s lost units:")
lostUnitsLayout = QGridLayout()
lostUnits.setLayout(lostUnitsLayout)
@@ -52,25 +50,27 @@ class QDebriefingWindow(QDialog):
for unit_type, count in player_air_losses.items():
try:
lostUnitsLayout.addWidget(
- QLabel(db.unit_get_expanded_info(self.debriefing.player_country, unit_type, 'name')), row, 0)
+ QLabel(
+ db.unit_get_expanded_info(
+ self.debriefing.player_country, unit_type, "name"
+ )
+ ),
+ row,
+ 0,
+ )
lostUnitsLayout.addWidget(QLabel(str(count)), row, 1)
row += 1
except AttributeError:
- logging.exception(
- f"Issue adding {unit_type} to debriefing information")
+ logging.exception(f"Issue adding {unit_type} to debriefing information")
- front_line_losses = self.debriefing.front_line_losses_by_type(
- player=True
- )
+ front_line_losses = self.debriefing.front_line_losses_by_type(player=True)
for unit_type, count in front_line_losses.items():
try:
- lostUnitsLayout.addWidget(
- QLabel(db.unit_type_name(unit_type)), row, 0)
+ lostUnitsLayout.addWidget(QLabel(db.unit_type_name(unit_type)), row, 0)
lostUnitsLayout.addWidget(QLabel(str(count)), row, 1)
row += 1
except AttributeError:
- logging.exception(
- f"Issue adding {unit_type} to debriefing information")
+ logging.exception(f"Issue adding {unit_type} to debriefing information")
building_losses = self.debriefing.building_losses_by_type(player=True)
for building, count in building_losses.items():
@@ -79,14 +79,12 @@ class QDebriefingWindow(QDialog):
lostUnitsLayout.addWidget(QLabel(str(count)), row, 1)
row += 1
except AttributeError:
- logging.exception(
- f"Issue adding {building} to debriefing information")
+ logging.exception(f"Issue adding {building} to debriefing information")
self.layout.addWidget(lostUnits)
# Enemy lost units
- enemylostUnits = QGroupBox(
- f"{self.debriefing.enemy_country}'s lost units:")
+ enemylostUnits = QGroupBox(f"{self.debriefing.enemy_country}'s lost units:")
enemylostUnitsLayout = QGridLayout()
enemylostUnits.setLayout(enemylostUnitsLayout)
@@ -94,16 +92,20 @@ class QDebriefingWindow(QDialog):
for unit_type, count in enemy_air_losses.items():
try:
enemylostUnitsLayout.addWidget(
- QLabel(db.unit_get_expanded_info(self.debriefing.enemy_country, unit_type, 'name')), row, 0)
+ QLabel(
+ db.unit_get_expanded_info(
+ self.debriefing.enemy_country, unit_type, "name"
+ )
+ ),
+ row,
+ 0,
+ )
enemylostUnitsLayout.addWidget(QLabel(str(count)), row, 1)
row += 1
except AttributeError:
- logging.exception(
- f"Issue adding {unit_type} to debriefing information")
+ logging.exception(f"Issue adding {unit_type} to debriefing information")
- front_line_losses = self.debriefing.front_line_losses_by_type(
- player=False
- )
+ front_line_losses = self.debriefing.front_line_losses_by_type(player=False)
for unit_type, count in front_line_losses.items():
if count == 0:
continue
@@ -118,8 +120,7 @@ class QDebriefingWindow(QDialog):
enemylostUnitsLayout.addWidget(QLabel("{}".format(count)), row, 1)
row += 1
except AttributeError:
- logging.exception(
- f"Issue adding {building} to debriefing information")
+ logging.exception(f"Issue adding {building} to debriefing information")
self.layout.addWidget(enemylostUnits)
diff --git a/qt_ui/windows/QUnitInfoWindow.py b/qt_ui/windows/QUnitInfoWindow.py
index 71735496..541f208b 100644
--- a/qt_ui/windows/QUnitInfoWindow.py
+++ b/qt_ui/windows/QUnitInfoWindow.py
@@ -28,13 +28,14 @@ from gen.flights.flight import FlightType
class QUnitInfoWindow(QDialog):
-
def __init__(self, game: Game, unit_type: Type[UnitType]) -> None:
super(QUnitInfoWindow, self).__init__()
self.setModal(True)
self.game = game
self.unit_type = unit_type
- self.setWindowTitle(f"Unit Info: {db.unit_get_expanded_info(self.game.player_country, self.unit_type, 'name')}")
+ self.setWindowTitle(
+ f"Unit Info: {db.unit_get_expanded_info(self.game.player_country, self.unit_type, 'name')}"
+ )
self.setWindowIcon(QIcon("./resources/icon.png"))
self.setMinimumHeight(570)
self.setMaximumWidth(640)
@@ -47,7 +48,10 @@ class QUnitInfoWindow(QDialog):
header = QLabel(self)
header.setGeometry(0, 0, 720, 360)
- if dcs.planes.plane_map.get(self.unit_type.id) is not None or dcs.helicopters.helicopter_map.get(self.unit_type.id) is not None:
+ if (
+ dcs.planes.plane_map.get(self.unit_type.id) is not None
+ or dcs.helicopters.helicopter_map.get(self.unit_type.id) is not None
+ ):
pixmap = AIRCRAFT_BANNERS.get(self.unit_type.id)
elif dcs.vehicles.vehicle_map.get(self.unit_type.id) is not None:
pixmap = VEHICLE_BANNERS.get(self.unit_type.id)
@@ -57,24 +61,32 @@ class QUnitInfoWindow(QDialog):
self.layout.addWidget(header, 0, 0)
self.gridLayout = QGridLayout()
-
+
# Build the topmost details grid.
self.details_grid = QFrame()
self.details_grid_layout = QGridLayout()
self.details_grid_layout.setMargin(0)
- self.name_box = QLabel(f"Name: {db.unit_get_expanded_info(self.game.player_country, self.unit_type, 'manufacturer')} {db.unit_get_expanded_info(self.game.player_country, self.unit_type, 'name')}")
+ self.name_box = QLabel(
+ f"Name: {db.unit_get_expanded_info(self.game.player_country, self.unit_type, 'manufacturer')} {db.unit_get_expanded_info(self.game.player_country, self.unit_type, 'name')}"
+ )
self.name_box.setProperty("style", "info-element")
-
- self.country_box = QLabel(f"Country of Origin: {db.unit_get_expanded_info(self.game.player_country, self.unit_type, 'country-of-origin')}")
+
+ self.country_box = QLabel(
+ f"Country of Origin: {db.unit_get_expanded_info(self.game.player_country, self.unit_type, 'country-of-origin')}"
+ )
self.country_box.setProperty("style", "info-element")
-
- self.role_box = QLabel(f"Role: {db.unit_get_expanded_info(self.game.player_country, self.unit_type, 'role')}")
+
+ self.role_box = QLabel(
+ f"Role: {db.unit_get_expanded_info(self.game.player_country, self.unit_type, 'role')}"
+ )
self.role_box.setProperty("style", "info-element")
-
- self.year_box = QLabel(f"Variant Introduction: {db.unit_get_expanded_info(self.game.player_country, self.unit_type, 'year-of-variant-introduction')}")
+
+ self.year_box = QLabel(
+ f"Variant Introduction: {db.unit_get_expanded_info(self.game.player_country, self.unit_type, 'year-of-variant-introduction')}"
+ )
self.year_box.setProperty("style", "info-element")
-
+
self.details_grid_layout.addWidget(self.name_box, 0, 0)
self.details_grid_layout.addWidget(self.country_box, 0, 1)
self.details_grid_layout.addWidget(self.role_box, 1, 0)
@@ -83,17 +95,24 @@ class QUnitInfoWindow(QDialog):
self.details_grid.setLayout(self.details_grid_layout)
self.gridLayout.addWidget(self.details_grid, 1, 0)
-
+
# If it's an aircraft, include the task list.
- if dcs.planes.plane_map.get(self.unit_type.id) is not None or dcs.helicopters.helicopter_map.get(self.unit_type.id) is not None:
- self.tasks_box = QLabel(f"In-Game Tasks: {self.generateAircraftTasks()}")
+ if (
+ dcs.planes.plane_map.get(self.unit_type.id) is not None
+ or dcs.helicopters.helicopter_map.get(self.unit_type.id) is not None
+ ):
+ self.tasks_box = QLabel(
+ f"In-Game Tasks: {self.generateAircraftTasks()}"
+ )
self.tasks_box.setProperty("style", "info-element")
self.gridLayout.addWidget(self.tasks_box, 2, 0)
# Finally, add the description box.
self.details_text = QTextBrowser()
self.details_text.setProperty("style", "info-desc")
- self.details_text.setText(db.unit_get_expanded_info(self.game.player_country, self.unit_type, "text"))
+ self.details_text.setText(
+ db.unit_get_expanded_info(self.game.player_country, self.unit_type, "text")
+ )
self.gridLayout.addWidget(self.details_text, 3, 0)
self.layout.addLayout(self.gridLayout, 1, 0)
@@ -102,9 +121,18 @@ class QUnitInfoWindow(QDialog):
def generateAircraftTasks(self) -> str:
aircraft_tasks = ""
if self.unit_type in gen.flights.ai_flight_planner_db.CAP_CAPABLE:
- aircraft_tasks = aircraft_tasks + f"{FlightType.BARCAP}, {FlightType.ESCORT}, {FlightType.INTERCEPTION}, {FlightType.SWEEP}, {FlightType.TARCAP}, "
- if self.unit_type in gen.flights.ai_flight_planner_db.CAS_CAPABLE or self.unit_type in gen.flights.ai_flight_planner_db.TRANSPORT_CAPABLE:
- aircraft_tasks = aircraft_tasks + f"{FlightType.CAS}, {FlightType.BAI}, {FlightType.OCA_AIRCRAFT}, "
+ aircraft_tasks = (
+ aircraft_tasks
+ + f"{FlightType.BARCAP}, {FlightType.ESCORT}, {FlightType.INTERCEPTION}, {FlightType.SWEEP}, {FlightType.TARCAP}, "
+ )
+ if (
+ self.unit_type in gen.flights.ai_flight_planner_db.CAS_CAPABLE
+ or self.unit_type in gen.flights.ai_flight_planner_db.TRANSPORT_CAPABLE
+ ):
+ aircraft_tasks = (
+ aircraft_tasks
+ + f"{FlightType.CAS}, {FlightType.BAI}, {FlightType.OCA_AIRCRAFT}, "
+ )
if self.unit_type in gen.flights.ai_flight_planner_db.SEAD_CAPABLE:
aircraft_tasks = aircraft_tasks + f"{FlightType.SEAD}, "
if self.unit_type in gen.flights.ai_flight_planner_db.DEAD_CAPABLE:
@@ -113,6 +141,9 @@ class QUnitInfoWindow(QDialog):
aircraft_tasks = aircraft_tasks + f"{FlightType.ANTISHIP}, "
if self.unit_type in gen.flights.ai_flight_planner_db.RUNWAY_ATTACK_CAPABLE:
aircraft_tasks = aircraft_tasks + f"{FlightType.OCA_RUNWAY}, "
- if self.unit_type in gen.flights.ai_flight_planner_db.STRIKE_CAPABLE or self.unit_type in gen.flights.ai_flight_planner_db.TRANSPORT_CAPABLE:
+ if (
+ self.unit_type in gen.flights.ai_flight_planner_db.STRIKE_CAPABLE
+ or self.unit_type in gen.flights.ai_flight_planner_db.TRANSPORT_CAPABLE
+ ):
aircraft_tasks = aircraft_tasks + f"{FlightType.STRIKE}, "
- return aircraft_tasks[:-2]
\ No newline at end of file
+ return aircraft_tasks[:-2]
diff --git a/qt_ui/windows/QWaitingForMissionResultWindow.py b/qt_ui/windows/QWaitingForMissionResultWindow.py
index db8e9f54..2efa730b 100644
--- a/qt_ui/windows/QWaitingForMissionResultWindow.py
+++ b/qt_ui/windows/QWaitingForMissionResultWindow.py
@@ -49,7 +49,6 @@ DebriefingFileWrittenSignal()
class QWaitingForMissionResultWindow(QDialog):
-
def __init__(self, gameEvent: Event, game: Game, unit_map: UnitMap) -> None:
super(QWaitingForMissionResultWindow, self).__init__()
self.setModal(True)
@@ -61,10 +60,14 @@ class QWaitingForMissionResultWindow(QDialog):
self.setMinimumHeight(570)
self.initUi()
- DebriefingFileWrittenSignal.get_instance().debriefingReceived.connect(self.updateLayout)
+ DebriefingFileWrittenSignal.get_instance().debriefingReceived.connect(
+ self.updateLayout
+ )
self.wait_thread = wait_for_debriefing(
- lambda debriefing: self.on_debriefing_update(debriefing), self.game,
- self.unit_map)
+ lambda debriefing: self.on_debriefing_update(debriefing),
+ self.game,
+ self.unit_map,
+ )
def initUi(self):
self.layout = QGridLayout()
@@ -89,7 +92,8 @@ class QWaitingForMissionResultWindow(QDialog):
)
self.instructions_text = QTextBrowser()
self.instructions_text.setHtml(
- jinja.get_template("mission_start_EN.j2").render())
+ jinja.get_template("mission_start_EN.j2").render()
+ )
self.instructions_text.setOpenExternalLinks(True)
self.gridLayout.addWidget(self.instructions_text, 1, 0)
@@ -110,7 +114,6 @@ class QWaitingForMissionResultWindow(QDialog):
self.actions_layout.addWidget(self.cancel)
self.gridLayout.addWidget(self.actions, 2, 0)
-
self.actions2 = QGroupBox("Actions :")
self.actions2_layout = QHBoxLayout()
self.actions2.setLayout(self.actions2_layout)
@@ -137,26 +140,24 @@ class QWaitingForMissionResultWindow(QDialog):
updateLayout.addWidget(QLabel("Aircraft destroyed"), 0, 0)
updateLayout.addWidget(
- QLabel(str(len(list(debriefing.air_losses.losses)))), 0, 1)
+ QLabel(str(len(list(debriefing.air_losses.losses)))), 0, 1
+ )
+ updateLayout.addWidget(QLabel("Front line units destroyed"), 1, 0)
updateLayout.addWidget(
- QLabel("Front line units destroyed"), 1, 0)
- updateLayout.addWidget(
- QLabel(str(len(list(debriefing.front_line_losses)))), 1, 1)
+ QLabel(str(len(list(debriefing.front_line_losses)))), 1, 1
+ )
+ updateLayout.addWidget(QLabel("Other ground units destroyed"), 2, 0)
updateLayout.addWidget(
- QLabel("Other ground units destroyed"), 2, 0)
- updateLayout.addWidget(
- QLabel(str(len(list(debriefing.ground_object_losses)))), 2, 1)
+ QLabel(str(len(list(debriefing.ground_object_losses)))), 2, 1
+ )
- updateLayout.addWidget(
- QLabel("Buildings destroyed"), 3, 0)
- updateLayout.addWidget(
- QLabel(str(len(list(debriefing.building_losses)))), 3, 1)
+ updateLayout.addWidget(QLabel("Buildings destroyed"), 3, 0)
+ updateLayout.addWidget(QLabel(str(len(list(debriefing.building_losses)))), 3, 1)
updateLayout.addWidget(QLabel("Base Capture Events"), 4, 0)
- updateLayout.addWidget(
- QLabel(str(len(debriefing.base_capture_events))), 4, 1)
+ updateLayout.addWidget(QLabel(str(len(debriefing.base_capture_events))), 4, 1)
# Clear previous content of the window
for i in reversed(range(self.gridLayout.count())):
@@ -183,7 +184,8 @@ class QWaitingForMissionResultWindow(QDialog):
except Exception:
logging.exception("Got an error while sending debriefing")
self.wait_thread = wait_for_debriefing(
- lambda d: self.on_debriefing_update(d), self.game, self.unit_map)
+ lambda d: self.on_debriefing_update(d), self.game, self.unit_map
+ )
def process_debriefing(self):
start = timeit.default_timer()
@@ -205,7 +207,9 @@ class QWaitingForMissionResultWindow(QDialog):
self.wait_thread.stop()
def submit_manually(self):
- file = QFileDialog.getOpenFileName(self, "Select game file to open", filter="json(*.json)", dir=".")
+ file = QFileDialog.getOpenFileName(
+ self, "Select game file to open", filter="json(*.json)", dir="."
+ )
print(file)
try:
with open(file[0], "r") as json_file:
@@ -223,4 +227,3 @@ class QWaitingForMissionResultWindow(QDialog):
msg.setWindowFlags(Qt.WindowStaysOnTopHint)
msg.exec_()
return
-
diff --git a/qt_ui/windows/basemenu/QBaseMenu2.py b/qt_ui/windows/basemenu/QBaseMenu2.py
index 5b399c82..65b49710 100644
--- a/qt_ui/windows/basemenu/QBaseMenu2.py
+++ b/qt_ui/windows/basemenu/QBaseMenu2.py
@@ -22,7 +22,6 @@ from qt_ui.windows.basemenu.QRecruitBehaviour import QRecruitBehaviour
class QBaseMenu2(QDialog):
-
def __init__(self, parent, cp: ControlPoint, game_model: GameModel):
super(QBaseMenu2, self).__init__(parent)
@@ -95,8 +94,7 @@ class QBaseMenu2(QDialog):
self.budget_display.setAlignment(Qt.AlignRight | Qt.AlignBottom)
self.budget_display.setProperty("style", "budget-label")
bottom_row.addWidget(self.budget_display)
- GameUpdateSignal.get_instance().budgetupdated.connect(
- self.update_budget)
+ GameUpdateSignal.get_instance().budgetupdated.connect(self.update_budget)
self.setLayout(main_layout)
@property
@@ -114,13 +112,16 @@ class QBaseMenu2(QDialog):
"Cannot repair runway",
f"Runway repair costs ${db.RUNWAY_REPAIR_COST}M but you have "
f"only ${self.game_model.game.budget}M available.",
- QMessageBox.Ok)
+ QMessageBox.Ok,
+ )
return
if not self.can_repair_runway:
QMessageBox.critical(
self,
"Cannot repair runway",
- f"Cannot repair this runway.", QMessageBox.Ok)
+ f"Cannot repair this runway.",
+ QMessageBox.Ok,
+ )
return
self.cp.begin_runway_repair()
@@ -144,7 +145,8 @@ class QBaseMenu2(QDialog):
return
else:
self.repair_button.setText(
- f"Cannot afford repair ${db.RUNWAY_REPAIR_COST}M")
+ f"Cannot afford repair ${db.RUNWAY_REPAIR_COST}M"
+ )
self.repair_button.setDisabled(True)
return
@@ -152,11 +154,15 @@ class QBaseMenu2(QDialog):
self.repair_button.setDisabled(True)
def update_intel_summary(self) -> None:
- self.intel_summary.setText("\n".join([
- f"{self.cp.base.total_aircraft} aircraft",
- f"{self.cp.base.total_armor} ground units",
- str(self.cp.runway_status)
- ]))
+ self.intel_summary.setText(
+ "\n".join(
+ [
+ f"{self.cp.base.total_aircraft} aircraft",
+ f"{self.cp.base.total_armor} ground units",
+ str(self.cp.runway_status),
+ ]
+ )
+ )
def closeEvent(self, close_event: QCloseEvent):
GameUpdateSignal.get_instance().updateGame(self.game_model.game)
@@ -173,5 +179,4 @@ class QBaseMenu2(QDialog):
Dialog.open_new_package_dialog(self.cp, parent=self.window())
def update_budget(self, game: Game) -> None:
- self.budget_display.setText(
- QRecruitBehaviour.BUDGET_FORMAT.format(game.budget))
+ self.budget_display.setText(QRecruitBehaviour.BUDGET_FORMAT.format(game.budget))
diff --git a/qt_ui/windows/basemenu/QBaseMenuTabs.py b/qt_ui/windows/basemenu/QBaseMenuTabs.py
index b7bb551a..b33cc733 100644
--- a/qt_ui/windows/basemenu/QBaseMenuTabs.py
+++ b/qt_ui/windows/basemenu/QBaseMenuTabs.py
@@ -9,7 +9,6 @@ from qt_ui.windows.basemenu.intel.QIntelInfo import QIntelInfo
class QBaseMenuTabs(QTabWidget):
-
def __init__(self, cp: ControlPoint, game_model: GameModel):
super(QBaseMenuTabs, self).__init__()
@@ -30,4 +29,4 @@ class QBaseMenuTabs(QTabWidget):
self.ground_forces_hq = QGroundForcesHQ(cp, game_model)
self.addTab(self.ground_forces_hq, "Ground Forces HQ")
self.base_defenses_hq = QBaseDefensesHQ(cp, game_model.game)
- self.addTab(self.base_defenses_hq, "Base Defenses")
\ No newline at end of file
+ self.addTab(self.base_defenses_hq, "Base Defenses")
diff --git a/qt_ui/windows/basemenu/QRecruitBehaviour.py b/qt_ui/windows/basemenu/QRecruitBehaviour.py
index 799c526b..97ef9b2a 100644
--- a/qt_ui/windows/basemenu/QRecruitBehaviour.py
+++ b/qt_ui/windows/basemenu/QRecruitBehaviour.py
@@ -48,8 +48,13 @@ class QRecruitBehaviour:
def budget(self, value: int) -> None:
self.game_model.game.budget = value
- def add_purchase_row(self, unit_type: Type[UnitType], layout: QLayout,
- row: int, disabled: bool = False) -> int:
+ def add_purchase_row(
+ self,
+ unit_type: Type[UnitType],
+ layout: QLayout,
+ row: int,
+ disabled: bool = False,
+ ) -> int:
exist = QGroupBox()
exist.setProperty("style", "buy-box")
exist.setMaximumHeight(36)
@@ -60,8 +65,16 @@ class QRecruitBehaviour:
existing_units = self.cp.base.total_units_of_type(unit_type)
scheduled_units = self.pending_deliveries.units.get(unit_type, 0)
- unitName = QLabel("" + db.unit_get_expanded_info(self.game_model.game.player_country, unit_type, 'name') + "")
- unitName.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
+ unitName = QLabel(
+ ""
+ + db.unit_get_expanded_info(
+ self.game_model.game.player_country, unit_type, "name"
+ )
+ + ""
+ )
+ unitName.setSizePolicy(
+ QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+ )
existing_units = QLabel(str(existing_units))
existing_units.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
@@ -104,7 +117,7 @@ class QRecruitBehaviour:
info.setMinimumHeight(36)
infolayout = QHBoxLayout()
info.setLayout(infolayout)
-
+
unitInfo = QPushButton("i")
unitInfo.setProperty("style", "btn-info")
unitInfo.setDisabled(disabled)
@@ -114,9 +127,13 @@ class QRecruitBehaviour:
unitInfo.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
existLayout.addWidget(unitName)
- existLayout.addItem(QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum))
+ existLayout.addItem(
+ QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum)
+ )
existLayout.addWidget(existing_units)
- existLayout.addItem(QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum))
+ existLayout.addItem(
+ QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum)
+ )
existLayout.addWidget(price)
buysellayout.addWidget(sell)
@@ -133,13 +150,17 @@ class QRecruitBehaviour:
def _update_count_label(self, unit_type: Type[UnitType]):
- self.bought_amount_labels[unit_type].setText("{}".format(
- unit_type in self.pending_deliveries.units and "{}".format(self.pending_deliveries.units[unit_type]) or "0"
- ))
+ self.bought_amount_labels[unit_type].setText(
+ "{}".format(
+ unit_type in self.pending_deliveries.units
+ and "{}".format(self.pending_deliveries.units[unit_type])
+ or "0"
+ )
+ )
- self.existing_units_labels[unit_type].setText("{}".format(
- self.cp.base.total_units_of_type(unit_type)
- ))
+ self.existing_units_labels[unit_type].setText(
+ "{}".format(self.cp.base.total_units_of_type(unit_type))
+ )
def update_available_budget(self) -> None:
GameUpdateSignal.get_instance().updateBudget(self.game_model.game)
diff --git a/qt_ui/windows/basemenu/airfield/QAircraftRecruitmentMenu.py b/qt_ui/windows/basemenu/airfield/QAircraftRecruitmentMenu.py
index c1016b40..a9551694 100644
--- a/qt_ui/windows/basemenu/airfield/QAircraftRecruitmentMenu.py
+++ b/qt_ui/windows/basemenu/airfield/QAircraftRecruitmentMenu.py
@@ -65,11 +65,19 @@ class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
continue
unit_types.add(unit)
- sorted_units = sorted(unit_types, key=lambda u: db.unit_get_expanded_info(self.game_model.game.player_country, u, 'name'))
+ sorted_units = sorted(
+ unit_types,
+ key=lambda u: db.unit_get_expanded_info(
+ self.game_model.game.player_country, u, "name"
+ ),
+ )
for unit_type in sorted_units:
row = self.add_purchase_row(
- unit_type, task_box_layout, row,
- disabled=not self.cp.can_operate(unit_type))
+ unit_type,
+ task_box_layout,
+ row,
+ disabled=not self.cp.can_operate(unit_type),
+ )
stretch = QVBoxLayout()
stretch.addStretch()
task_box_layout.addLayout(stretch, row, 0)
@@ -89,8 +97,11 @@ class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
if self.cp.unclaimed_parking(self.game_model.game) <= 0:
logging.debug(f"No space for additional aircraft at {self.cp}.")
QMessageBox.warning(
- self, "No space for additional aircraft",
- f"There is no parking space left at {self.cp.name} to accommodate another plane.", QMessageBox.Ok)
+ self,
+ "No space for additional aircraft",
+ f"There is no parking space left at {self.cp.name} to accommodate another plane.",
+ QMessageBox.Ok,
+ )
return
# If we change our mind about selling, we want the aircraft to be put
# back in the inventory immediately.
@@ -98,7 +109,7 @@ class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
global_inventory = self.game_model.game.aircraft_inventory
inventory = global_inventory.for_control_point(self.cp)
inventory.add_aircraft(unit_type, 1)
-
+
super().buy(unit_type)
self.hangar_status.update_label()
@@ -112,19 +123,20 @@ class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
inventory.remove_aircraft(unit_type, 1)
except ValueError:
QMessageBox.critical(
- self, "Could not sell aircraft",
+ self,
+ "Could not sell aircraft",
f"Attempted to sell one {unit_type.id} at {self.cp.name} "
"but none are available. Are all aircraft currently "
- "assigned to a mission?", QMessageBox.Ok)
+ "assigned to a mission?",
+ QMessageBox.Ok,
+ )
return
super().sell(unit_type)
self.hangar_status.update_label()
class QHangarStatus(QHBoxLayout):
-
- def __init__(self, game_model: GameModel,
- control_point: ControlPoint) -> None:
+ def __init__(self, game_model: GameModel, control_point: ControlPoint) -> None:
super().__init__()
self.game_model = game_model
self.control_point = control_point
@@ -140,8 +152,7 @@ class QHangarStatus(QHBoxLayout):
self.setAlignment(Qt.AlignLeft)
def update_label(self) -> None:
- next_turn = self.control_point.expected_aircraft_next_turn(
- self.game_model.game)
+ next_turn = self.control_point.expected_aircraft_next_turn(self.game_model.game)
max_amount = self.control_point.total_aircraft_parking
components = [f"{next_turn.present} present"]
@@ -158,4 +169,5 @@ class QHangarStatus(QHBoxLayout):
details = ", ".join(components)
self.text.setText(
- f"{next_turn.total}/{max_amount} ({details})")
+ f"{next_turn.total}/{max_amount} ({details})"
+ )
diff --git a/qt_ui/windows/basemenu/airfield/QAirfieldCommand.py b/qt_ui/windows/basemenu/airfield/QAirfieldCommand.py
index cac85b83..289fd8f8 100644
--- a/qt_ui/windows/basemenu/airfield/QAirfieldCommand.py
+++ b/qt_ui/windows/basemenu/airfield/QAirfieldCommand.py
@@ -2,14 +2,14 @@ from PySide2.QtWidgets import QFrame, QGridLayout, QGroupBox, QVBoxLayout
from game.theater import ControlPoint
from qt_ui.models import GameModel
-from qt_ui.windows.basemenu.airfield.QAircraftRecruitmentMenu import \
- QAircraftRecruitmentMenu
+from qt_ui.windows.basemenu.airfield.QAircraftRecruitmentMenu import (
+ QAircraftRecruitmentMenu,
+)
from qt_ui.windows.mission.QPlannedFlightsView import QPlannedFlightsView
class QAirfieldCommand(QFrame):
-
- def __init__(self, cp:ControlPoint, game_model: GameModel):
+ def __init__(self, cp: ControlPoint, game_model: GameModel):
super(QAirfieldCommand, self).__init__()
self.cp = cp
self.game_model = game_model
@@ -22,9 +22,7 @@ class QAirfieldCommand(QFrame):
planned = QGroupBox("Planned Flights")
planned_layout = QVBoxLayout()
- planned_layout.addWidget(
- QPlannedFlightsView(self.game_model, self.cp)
- )
+ planned_layout.addWidget(QPlannedFlightsView(self.game_model, self.cp))
planned.setLayout(planned_layout)
layout.addWidget(planned, 0, 1)
diff --git a/qt_ui/windows/basemenu/base_defenses/QBaseDefenseGroupInfo.py b/qt_ui/windows/basemenu/base_defenses/QBaseDefenseGroupInfo.py
index 16aa2a90..618e62dd 100644
--- a/qt_ui/windows/basemenu/base_defenses/QBaseDefenseGroupInfo.py
+++ b/qt_ui/windows/basemenu/base_defenses/QBaseDefenseGroupInfo.py
@@ -16,13 +16,14 @@ from dcs import vehicles
class QBaseDefenseGroupInfo(QGroupBox):
-
def __init__(self, cp: ControlPoint, ground_object: TheaterGroundObject, game):
super(QBaseDefenseGroupInfo, self).__init__("Group : " + ground_object.obj_name)
self.ground_object = ground_object
self.cp = cp
self.game = game
- self.buildings = game.theater.find_ground_objects_by_obj_name(self.ground_object.obj_name)
+ self.buildings = game.theater.find_ground_objects_by_obj_name(
+ self.ground_object.obj_name
+ )
self.main_layout = QVBoxLayout()
self.unit_layout = QGridLayout()
@@ -76,24 +77,30 @@ class QBaseDefenseGroupInfo(QGroupBox):
unit_display_name = k
unit_type = vehicles.vehicle_map.get(k)
if unit_type is not None:
- unit_display_name = db.unit_get_expanded_info(self.game.enemy_country, unit_type, 'name')
- self.unit_layout.addWidget(QLabel(str(v) + " x " + "" + unit_display_name + ""), i, 1)
+ unit_display_name = db.unit_get_expanded_info(
+ self.game.enemy_country, unit_type, "name"
+ )
+ self.unit_layout.addWidget(
+ QLabel(str(v) + " x " + "" + unit_display_name + ""),
+ i,
+ 1,
+ )
i = i + 1
if len(unit_dict.items()) == 0:
self.unit_layout.addWidget(QLabel("/"), 0, 0)
-
-
self.setLayout(self.main_layout)
-
+
def onAttack(self):
Dialog.open_new_package_dialog(self.ground_object, parent=self.window())
def onManage(self):
- self.edition_menu = QGroundObjectMenu(self.window(), self.ground_object, self.buildings, self.cp, self.game)
+ self.edition_menu = QGroundObjectMenu(
+ self.window(), self.ground_object, self.buildings, self.cp, self.game
+ )
self.edition_menu.show()
self.edition_menu.changed.connect(self.onEdition)
def onEdition(self):
- self.buildLayout()
\ No newline at end of file
+ self.buildLayout()
diff --git a/qt_ui/windows/basemenu/base_defenses/QBaseDefensesHQ.py b/qt_ui/windows/basemenu/base_defenses/QBaseDefensesHQ.py
index 75a45eb0..f1d99d67 100644
--- a/qt_ui/windows/basemenu/base_defenses/QBaseDefensesHQ.py
+++ b/qt_ui/windows/basemenu/base_defenses/QBaseDefensesHQ.py
@@ -2,13 +2,11 @@ from PySide2.QtWidgets import QFrame, QGridLayout
from game import Game
from game.theater import ControlPoint
-from qt_ui.windows.basemenu.base_defenses.QBaseInformation import \
- QBaseInformation
+from qt_ui.windows.basemenu.base_defenses.QBaseInformation import QBaseInformation
class QBaseDefensesHQ(QFrame):
-
- def __init__(self, cp:ControlPoint, game:Game):
+ def __init__(self, cp: ControlPoint, game: Game):
super(QBaseDefensesHQ, self).__init__()
self.cp = cp
self.game = game
@@ -19,4 +17,3 @@ class QBaseDefensesHQ(QFrame):
layout = QGridLayout()
layout.addWidget(QBaseInformation(self.cp, airport, self.game))
self.setLayout(layout)
-
diff --git a/qt_ui/windows/basemenu/base_defenses/QBaseInformation.py b/qt_ui/windows/basemenu/base_defenses/QBaseInformation.py
index 7db68d8c..f2b874dd 100644
--- a/qt_ui/windows/basemenu/base_defenses/QBaseInformation.py
+++ b/qt_ui/windows/basemenu/base_defenses/QBaseInformation.py
@@ -9,13 +9,13 @@ from PySide2.QtWidgets import (
from game.theater import Airport, ControlPoint, Fob
from game.theater.theatergroundobject import BuildingGroundObject
-from qt_ui.windows.basemenu.base_defenses.QBaseDefenseGroupInfo import \
- QBaseDefenseGroupInfo
+from qt_ui.windows.basemenu.base_defenses.QBaseDefenseGroupInfo import (
+ QBaseDefenseGroupInfo,
+)
class QBaseInformation(QFrame):
-
- def __init__(self, cp:ControlPoint, airport:Airport, game):
+ def __init__(self, cp: ControlPoint, airport: Airport, game):
super(QBaseInformation, self).__init__()
self.cp = cp
self.airport = airport
@@ -53,4 +53,4 @@ class QBaseInformation(QFrame):
self.mainLayout.addWidget(scroll)
- self.setLayout(self.mainLayout)
\ No newline at end of file
+ self.setLayout(self.mainLayout)
diff --git a/qt_ui/windows/basemenu/ground_forces/QArmorRecruitmentMenu.py b/qt_ui/windows/basemenu/ground_forces/QArmorRecruitmentMenu.py
index 3f089036..46536204 100644
--- a/qt_ui/windows/basemenu/ground_forces/QArmorRecruitmentMenu.py
+++ b/qt_ui/windows/basemenu/ground_forces/QArmorRecruitmentMenu.py
@@ -17,7 +17,6 @@ from qt_ui.windows.basemenu.QRecruitBehaviour import QRecruitBehaviour
class QArmorRecruitmentMenu(QFrame, QRecruitBehaviour):
-
def __init__(self, cp: ControlPoint, game_model: GameModel):
QFrame.__init__(self)
self.cp = cp
@@ -32,8 +31,9 @@ class QArmorRecruitmentMenu(QFrame, QRecruitBehaviour):
main_layout = QVBoxLayout()
units = {
- PinpointStrike: db.find_unittype(PinpointStrike,
- self.game_model.game.player_name),
+ PinpointStrike: db.find_unittype(
+ PinpointStrike, self.game_model.game.player_name
+ ),
}
scroll_content = QWidget()
@@ -43,8 +43,13 @@ class QArmorRecruitmentMenu(QFrame, QRecruitBehaviour):
for task_type in units.keys():
units_column = list(set(units[task_type]))
- if len(units_column) == 0: continue
- units_column.sort(key=lambda u: db.unit_get_expanded_info(self.game_model.game.player_country, u, 'name'))
+ if len(units_column) == 0:
+ continue
+ units_column.sort(
+ key=lambda u: db.unit_get_expanded_info(
+ self.game_model.game.player_country, u, "name"
+ )
+ )
for unit_type in units_column:
row = self.add_purchase_row(unit_type, task_box_layout, row)
stretch = QVBoxLayout()
@@ -63,8 +68,11 @@ class QArmorRecruitmentMenu(QFrame, QRecruitBehaviour):
def sell(self, unit_type: UnitType):
if self.pending_deliveries.available_next_turn(unit_type) <= 0:
QMessageBox.critical(
- self, "Could not sell ground unit",
+ self,
+ "Could not sell ground unit",
f"Attempted to sell one {unit_type.id} at {self.cp.name} "
- "but none are available.", QMessageBox.Ok)
+ "but none are available.",
+ QMessageBox.Ok,
+ )
return
- super().sell(unit_type)
\ No newline at end of file
+ super().sell(unit_type)
diff --git a/qt_ui/windows/basemenu/ground_forces/QGroundForcesHQ.py b/qt_ui/windows/basemenu/ground_forces/QGroundForcesHQ.py
index 39cba843..f6304fcd 100644
--- a/qt_ui/windows/basemenu/ground_forces/QGroundForcesHQ.py
+++ b/qt_ui/windows/basemenu/ground_forces/QGroundForcesHQ.py
@@ -2,14 +2,15 @@ from PySide2.QtWidgets import QFrame, QGridLayout
from game.theater import ControlPoint
from qt_ui.models import GameModel
-from qt_ui.windows.basemenu.ground_forces.QArmorRecruitmentMenu import \
- QArmorRecruitmentMenu
-from qt_ui.windows.basemenu.ground_forces.QGroundForcesStrategy import \
- QGroundForcesStrategy
+from qt_ui.windows.basemenu.ground_forces.QArmorRecruitmentMenu import (
+ QArmorRecruitmentMenu,
+)
+from qt_ui.windows.basemenu.ground_forces.QGroundForcesStrategy import (
+ QGroundForcesStrategy,
+)
class QGroundForcesHQ(QFrame):
-
def __init__(self, cp: ControlPoint, game_model: GameModel) -> None:
super(QGroundForcesHQ, self).__init__()
self.cp = cp
@@ -19,6 +20,5 @@ class QGroundForcesHQ(QFrame):
def init_ui(self):
layout = QGridLayout()
layout.addWidget(QArmorRecruitmentMenu(self.cp, self.game_model), 0, 0)
- layout.addWidget(QGroundForcesStrategy(self.cp, self.game_model.game),
- 0, 1)
+ layout.addWidget(QGroundForcesStrategy(self.cp, self.game_model.game), 0, 1)
self.setLayout(layout)
diff --git a/qt_ui/windows/basemenu/ground_forces/QGroundForcesStrategy.py b/qt_ui/windows/basemenu/ground_forces/QGroundForcesStrategy.py
index 3aee8c50..c903413b 100644
--- a/qt_ui/windows/basemenu/ground_forces/QGroundForcesStrategy.py
+++ b/qt_ui/windows/basemenu/ground_forces/QGroundForcesStrategy.py
@@ -2,13 +2,13 @@ from PySide2.QtWidgets import QGroupBox, QLabel, QVBoxLayout
from game import Game
from game.theater import ControlPoint
-from qt_ui.windows.basemenu.ground_forces.QGroundForcesStrategySelector import \
- QGroundForcesStrategySelector
+from qt_ui.windows.basemenu.ground_forces.QGroundForcesStrategySelector import (
+ QGroundForcesStrategySelector,
+)
class QGroundForcesStrategy(QGroupBox):
-
- def __init__(self, cp:ControlPoint, game:Game):
+ def __init__(self, cp: ControlPoint, game: Game):
super(QGroundForcesStrategy, self).__init__("Frontline operations :")
self.cp = cp
self.game = game
diff --git a/qt_ui/windows/basemenu/ground_forces/QGroundForcesStrategySelector.py b/qt_ui/windows/basemenu/ground_forces/QGroundForcesStrategySelector.py
index 4acd8731..9cd23eaa 100644
--- a/qt_ui/windows/basemenu/ground_forces/QGroundForcesStrategySelector.py
+++ b/qt_ui/windows/basemenu/ground_forces/QGroundForcesStrategySelector.py
@@ -4,8 +4,7 @@ from game.theater import CombatStance, ControlPoint
class QGroundForcesStrategySelector(QComboBox):
-
- def __init__(self, cp:ControlPoint, enemy_cp:ControlPoint):
+ def __init__(self, cp: ControlPoint, enemy_cp: ControlPoint):
super(QGroundForcesStrategySelector, self).__init__()
self.cp = cp
self.enemy_cp = enemy_cp
diff --git a/qt_ui/windows/basemenu/intel/QIntelInfo.py b/qt_ui/windows/basemenu/intel/QIntelInfo.py
index 6c40d5f9..ea5dfa4c 100644
--- a/qt_ui/windows/basemenu/intel/QIntelInfo.py
+++ b/qt_ui/windows/basemenu/intel/QIntelInfo.py
@@ -15,8 +15,7 @@ from game.theater import ControlPoint
class QIntelInfo(QFrame):
-
- def __init__(self, cp:ControlPoint, game:Game):
+ def __init__(self, cp: ControlPoint, game: Game):
super(QIntelInfo, self).__init__()
self.cp = cp
self.game = game
@@ -27,8 +26,6 @@ class QIntelInfo(QFrame):
scroll_content = QWidget()
intelLayout = QVBoxLayout()
-
-
units = {
CAP: db.find_unittype(CAP, self.game.enemy_name),
Embarking: db.find_unittype(Embarking, self.game.enemy_name),
@@ -50,7 +47,17 @@ class QIntelInfo(QFrame):
existing_units = self.cp.base.total_units_of_type(unit_type)
if existing_units == 0:
continue
- groupLayout.addWidget(QLabel("" + db.unit_get_expanded_info(self.game.enemy_country, unit_type, 'name') + ""), row, 0)
+ groupLayout.addWidget(
+ QLabel(
+ ""
+ + db.unit_get_expanded_info(
+ self.game.enemy_country, unit_type, "name"
+ )
+ + ""
+ ),
+ row,
+ 0,
+ )
groupLayout.addWidget(QLabel(str(existing_units)), row, 1)
row += 1
@@ -64,5 +71,5 @@ class QIntelInfo(QFrame):
scroll.setWidget(scroll_content)
layout.addWidget(scroll)
-
- self.setLayout(layout)
\ No newline at end of file
+
+ self.setLayout(layout)
diff --git a/qt_ui/windows/finances/QFinancesMenu.py b/qt_ui/windows/finances/QFinancesMenu.py
index e1151b64..ea008c10 100644
--- a/qt_ui/windows/finances/QFinancesMenu.py
+++ b/qt_ui/windows/finances/QFinancesMenu.py
@@ -16,7 +16,6 @@ from game.theater import ControlPoint
class QHorizontalSeparationLine(QFrame):
-
def __init__(self):
super().__init__()
self.setMinimumWidth(1)
@@ -34,7 +33,8 @@ class FinancesLayout(QGridLayout):
income = Income(game, player)
control_points = reversed(
- sorted(income.control_points, key=lambda c: c.income_per_turn))
+ sorted(income.control_points, key=lambda c: c.income_per_turn)
+ )
for control_point in control_points:
self.add_control_point(control_point)
@@ -46,8 +46,10 @@ class FinancesLayout(QGridLayout):
self.add_line()
- self.add_row(middle=f"Income multiplier: {income.multiplier:.1f}",
- right=f"{income.total}M")
+ self.add_row(
+ middle=f"Income multiplier: {income.multiplier:.1f}",
+ right=f"{income.total}M",
+ )
if player:
budget = game.budget
@@ -57,8 +59,12 @@ class FinancesLayout(QGridLayout):
self.add_row(middle="Balance", right=f"{budget}M")
self.setRowStretch(next(self.row), 1)
- def add_row(self, left: Optional[str] = None, middle: Optional[str] = None,
- right: Optional[str] = None) -> None:
+ def add_row(
+ self,
+ left: Optional[str] = None,
+ middle: Optional[str] = None,
+ right: Optional[str] = None,
+ ) -> None:
if not any([left, middle, right]):
raise ValueError
@@ -71,17 +77,21 @@ class FinancesLayout(QGridLayout):
self.addWidget(QLabel(right), row, 2)
def add_control_point(self, control_point: ControlPoint) -> None:
- self.add_row(left=f"{control_point.name}",
- right=f"{control_point.income_per_turn}M")
+ self.add_row(
+ left=f"{control_point.name}",
+ right=f"{control_point.income_per_turn}M",
+ )
def add_building(self, building: BuildingIncome) -> None:
row = next(self.row)
self.addWidget(
- QLabel(f"{building.category.upper()} [{building.name}]"),
- row, 0)
- self.addWidget(QLabel(
- f"{building.number} buildings x {building.income_per_building}M"),
- row, 1)
+ QLabel(f"{building.category.upper()} [{building.name}]"), row, 0
+ )
+ self.addWidget(
+ QLabel(f"{building.number} buildings x {building.income_per_building}M"),
+ row,
+ 1,
+ )
rlabel = QLabel(f"{building.income}M")
rlabel.setProperty("style", "green")
self.addWidget(rlabel, row, 2)
@@ -91,7 +101,6 @@ class FinancesLayout(QGridLayout):
class QFinancesMenu(QDialog):
-
def __init__(self, game: Game):
super(QFinancesMenu, self).__init__()
diff --git a/qt_ui/windows/groundobject/QBuildingInfo.py b/qt_ui/windows/groundobject/QBuildingInfo.py
index fcf6366b..3f484f15 100644
--- a/qt_ui/windows/groundobject/QBuildingInfo.py
+++ b/qt_ui/windows/groundobject/QBuildingInfo.py
@@ -4,8 +4,8 @@ from PySide2.QtGui import QPixmap
from PySide2.QtWidgets import QGroupBox, QHBoxLayout, QVBoxLayout, QLabel
from game.db import REWARDS
-class QBuildingInfo(QGroupBox):
+class QBuildingInfo(QGroupBox):
def __init__(self, building, ground_object):
super(QBuildingInfo, self).__init__()
self.building = building
@@ -14,7 +14,9 @@ class QBuildingInfo(QGroupBox):
def init_ui(self):
self.header = QLabel()
- path = os.path.join("./resources/ui/units/buildings/" + self.building.dcs_identifier + ".png")
+ path = os.path.join(
+ "./resources/ui/units/buildings/" + self.building.dcs_identifier + ".png"
+ )
if self.building.is_dead:
pixmap = QPixmap("./resources/ui/units/buildings/dead.png")
elif os.path.isfile(path):
@@ -22,7 +24,10 @@ class QBuildingInfo(QGroupBox):
else:
pixmap = QPixmap("./resources/ui/units/buildings/missing.png")
self.header.setPixmap(pixmap)
- name = "{} {}".format(self.building.dcs_identifier[0:18], "[DEAD]" if self.building.is_dead else "")
+ name = "{} {}".format(
+ self.building.dcs_identifier[0:18],
+ "[DEAD]" if self.building.is_dead else "",
+ )
self.name = QLabel(name)
self.name.setProperty("style", "small")
layout = QVBoxLayout()
@@ -30,9 +35,9 @@ class QBuildingInfo(QGroupBox):
layout.addWidget(self.name)
if self.building.category in REWARDS.keys():
- income_label_text = 'Value: ' + str(REWARDS[self.building.category]) + "M"
+ income_label_text = "Value: " + str(REWARDS[self.building.category]) + "M"
if self.building.is_dead:
- income_label_text = '' + income_label_text + ''
+ income_label_text = "" + income_label_text + ""
self.reward = QLabel(income_label_text)
layout.addWidget(self.reward)
diff --git a/qt_ui/windows/groundobject/QGroundObjectMenu.py b/qt_ui/windows/groundobject/QGroundObjectMenu.py
index d979c657..13abb5b3 100644
--- a/qt_ui/windows/groundobject/QGroundObjectMenu.py
+++ b/qt_ui/windows/groundobject/QGroundObjectMenu.py
@@ -22,8 +22,7 @@ from game.data.building_data import FORTIFICATION_BUILDINGS
from game.db import PRICES, PinpointStrike, REWARDS, unit_type_of
from game.theater import ControlPoint, TheaterGroundObject
from game.theater.theatergroundobject import NavalGroundObject
-from gen.defenses.armor_group_generator import \
- generate_armor_group_of_type_and_size
+from gen.defenses.armor_group_generator import generate_armor_group_of_type_and_size
from gen.sam.sam_group_generator import get_faction_possible_sams_generator
from qt_ui.uiconstants import EVENT_ICONS
from qt_ui.widgets.QBudgetBox import QBudgetBox
@@ -36,9 +35,14 @@ class QGroundObjectMenu(QDialog):
changed = QtCore.Signal()
- def __init__(self, parent, ground_object: TheaterGroundObject,
- buildings: Optional[List[TheaterGroundObject]],
- cp: ControlPoint, game: Game):
+ def __init__(
+ self,
+ parent,
+ ground_object: TheaterGroundObject,
+ buildings: Optional[List[TheaterGroundObject]],
+ cp: ControlPoint,
+ game: Game,
+ ):
super().__init__(parent)
self.setMinimumWidth(350)
self.ground_object = ground_object
@@ -105,8 +109,20 @@ class QGroundObjectMenu(QDialog):
unit_display_name = u.type
unit_type = vehicles.vehicle_map.get(u.type)
if unit_type is not None:
- unit_display_name = db.unit_get_expanded_info(self.game.enemy_country, unit_type, 'name')
- self.intelLayout.addWidget(QLabel("Unit #" + str(u.id) + " - " + str(unit_display_name) + ""), i, 0)
+ unit_display_name = db.unit_get_expanded_info(
+ self.game.enemy_country, unit_type, "name"
+ )
+ self.intelLayout.addWidget(
+ QLabel(
+ "Unit #"
+ + str(u.id)
+ + " - "
+ + str(unit_display_name)
+ + ""
+ ),
+ i,
+ 0,
+ )
i = i + 1
for u in g.units_losts:
@@ -117,11 +133,19 @@ class QGroundObjectMenu(QDialog):
else:
price = 6
- self.intelLayout.addWidget(QLabel("Unit #" + str(u.id) + " - " + str(u.type) + " [DEAD]"), i, 0)
+ self.intelLayout.addWidget(
+ QLabel(
+ "Unit #" + str(u.id) + " - " + str(u.type) + " [DEAD]"
+ ),
+ i,
+ 0,
+ )
if self.cp.captured:
repair = QPushButton("Repair [" + str(price) + "M]")
repair.setProperty("style", "btn-success")
- repair.clicked.connect(lambda u=u, g=g, p=price: self.repair_unit(g, u, p))
+ repair.clicked.connect(
+ lambda u=u, g=g, p=price: self.repair_unit(g, u, p)
+ )
self.intelLayout.addWidget(repair, i, 1)
i = i + 1
stretch = QVBoxLayout()
@@ -136,7 +160,9 @@ class QGroundObjectMenu(QDialog):
received_income = 0
for i, building in enumerate(self.buildings):
if building.dcs_identifier not in FORTIFICATION_BUILDINGS:
- self.buildingsLayout.addWidget(QBuildingInfo(building, self.ground_object), j/3, j%3)
+ self.buildingsLayout.addWidget(
+ QBuildingInfo(building, self.ground_object), j / 3, j % 3
+ )
j = j + 1
if building.category in REWARDS.keys():
@@ -148,8 +174,12 @@ class QGroundObjectMenu(QDialog):
self.financesBox = QGroupBox("Finances: ")
self.financesBoxLayout = QGridLayout()
- self.financesBoxLayout.addWidget(QLabel("Available: " + str(total_income) + "M"), 2, 1)
- self.financesBoxLayout.addWidget(QLabel("Receiving: " + str(received_income) + "M"), 2, 2)
+ self.financesBoxLayout.addWidget(
+ QLabel("Available: " + str(total_income) + "M"), 2, 1
+ )
+ self.financesBoxLayout.addWidget(
+ QLabel("Receiving: " + str(received_income) + "M"), 2, 2
+ )
self.financesBox.setLayout(self.financesBoxLayout)
self.buildingBox.setLayout(self.buildingsLayout)
@@ -224,17 +254,25 @@ class QGroundObjectMenu(QDialog):
GameUpdateSignal.get_instance().updateBudget(self.game)
def buy_group(self):
- self.subwindow = QBuyGroupForGroundObjectDialog(self, self.ground_object, self.cp, self.game, self.total_value)
+ self.subwindow = QBuyGroupForGroundObjectDialog(
+ self, self.ground_object, self.cp, self.game, self.total_value
+ )
self.subwindow.changed.connect(self.do_refresh_layout)
self.subwindow.show()
-
class QBuyGroupForGroundObjectDialog(QDialog):
changed = QtCore.Signal()
- def __init__(self, parent, ground_object: TheaterGroundObject, cp: ControlPoint, game: Game, current_group_value: int):
+ def __init__(
+ self,
+ parent,
+ ground_object: TheaterGroundObject,
+ cp: ControlPoint,
+ game: Game,
+ current_group_value: int,
+ ):
super(QBuyGroupForGroundObjectDialog, self).__init__(parent)
self.setMinimumWidth(350)
@@ -256,8 +294,6 @@ class QBuyGroupForGroundObjectDialog(QDialog):
self.buySamBox = QGroupBox("Buy SAM site :")
self.buyArmorBox = QGroupBox("Buy defensive position :")
-
-
self.init_ui()
def init_ui(self):
@@ -267,7 +303,9 @@ class QBuyGroupForGroundObjectDialog(QDialog):
possible_sams = get_faction_possible_sams_generator(faction)
for sam in possible_sams:
- self.samCombo.addItem(sam.name + " [$" + str(sam.price) + "M]", userData=sam)
+ self.samCombo.addItem(
+ sam.name + " [$" + str(sam.price) + "M]", userData=sam
+ )
self.samCombo.currentIndexChanged.connect(self.samComboChanged)
self.buySamLayout.addWidget(QLabel("Site Type :"), 0, 0, Qt.AlignLeft)
@@ -281,9 +319,14 @@ class QBuyGroupForGroundObjectDialog(QDialog):
# Armored units
- armored_units = db.find_unittype(PinpointStrike, faction.name) # Todo : refactor this legacy nonsense
+ armored_units = db.find_unittype(
+ PinpointStrike, faction.name
+ ) # Todo : refactor this legacy nonsense
for unit in set(armored_units):
- self.buyArmorCombo.addItem(db.unit_type_name_2(unit) + " [$" + str(db.PRICES[unit]) + "M]", userData=unit)
+ self.buyArmorCombo.addItem(
+ db.unit_type_name_2(unit) + " [$" + str(db.PRICES[unit]) + "M]",
+ userData=unit,
+ )
self.buyArmorCombo.currentIndexChanged.connect(self.armorComboChanged)
self.amount.setMinimum(2)
@@ -293,9 +336,13 @@ class QBuyGroupForGroundObjectDialog(QDialog):
self.buyArmorLayout.addWidget(QLabel("Unit type :"), 0, 0, Qt.AlignLeft)
self.buyArmorLayout.addWidget(self.buyArmorCombo, 0, 1, alignment=Qt.AlignRight)
- self.buyArmorLayout.addWidget(QLabel("Group size :"), 1, 0, alignment=Qt.AlignLeft)
+ self.buyArmorLayout.addWidget(
+ QLabel("Group size :"), 1, 0, alignment=Qt.AlignLeft
+ )
self.buyArmorLayout.addWidget(self.amount, 1, 1, alignment=Qt.AlignRight)
- self.buyArmorLayout.addWidget(self.buyArmorButton, 2, 1, alignment=Qt.AlignRight)
+ self.buyArmorLayout.addWidget(
+ self.buyArmorButton, 2, 1, alignment=Qt.AlignRight
+ )
stretch2 = QVBoxLayout()
stretch2.addStretch()
self.buyArmorLayout.addLayout(stretch2, 3, 0)
@@ -321,13 +368,36 @@ class QBuyGroupForGroundObjectDialog(QDialog):
pass
def samComboChanged(self, index):
- self.buySamButton.setText("Buy [$" + str(self.samCombo.itemData(index).price) + "M] [-$" + str(self.current_group_value) + "M]")
+ self.buySamButton.setText(
+ "Buy [$"
+ + str(self.samCombo.itemData(index).price)
+ + "M] [-$"
+ + str(self.current_group_value)
+ + "M]"
+ )
def armorComboChanged(self, index):
- self.buyArmorButton.setText("Buy [$" + str(db.PRICES[self.buyArmorCombo.itemData(index)] * self.amount.value()) + "M][-$" + str(self.current_group_value) + "M]")
+ self.buyArmorButton.setText(
+ "Buy [$"
+ + str(db.PRICES[self.buyArmorCombo.itemData(index)] * self.amount.value())
+ + "M][-$"
+ + str(self.current_group_value)
+ + "M]"
+ )
def amountComboChanged(self):
- self.buyArmorButton.setText("Buy [$" + str(db.PRICES[self.buyArmorCombo.itemData(self.buyArmorCombo.currentIndex())] * self.amount.value()) + "M][-$" + str(self.current_group_value) + "M]")
+ self.buyArmorButton.setText(
+ "Buy [$"
+ + str(
+ db.PRICES[
+ self.buyArmorCombo.itemData(self.buyArmorCombo.currentIndex())
+ ]
+ * self.amount.value()
+ )
+ + "M][-$"
+ + str(self.current_group_value)
+ + "M]"
+ )
def buyArmor(self):
logging.info("Buying Armor ")
@@ -342,7 +412,9 @@ class QBuyGroupForGroundObjectDialog(QDialog):
self.game.budget -= price
# Generate Armor
- group = generate_armor_group_of_type_and_size(self.game, self.ground_object, utype, int(self.amount.value()))
+ group = generate_armor_group_of_type_and_size(
+ self.game, self.ground_object, utype, int(self.amount.value())
+ )
self.ground_object.groups = [group]
GameUpdateSignal.get_instance().updateBudget(self.game)
@@ -377,4 +449,4 @@ class QBuyGroupForGroundObjectDialog(QDialog):
msg.setStandardButtons(QMessageBox.Ok)
msg.setWindowFlags(Qt.WindowStaysOnTopHint)
msg.exec_()
- self.close()
\ No newline at end of file
+ self.close()
diff --git a/qt_ui/windows/infos/QInfoItem.py b/qt_ui/windows/infos/QInfoItem.py
index f8d63bf2..b15c5f1c 100644
--- a/qt_ui/windows/infos/QInfoItem.py
+++ b/qt_ui/windows/infos/QInfoItem.py
@@ -4,7 +4,6 @@ from game.infos.information import Information
class QInfoItem(QStandardItem):
-
def __init__(self, info: Information):
super(QInfoItem, self).__init__()
self.info = info
diff --git a/qt_ui/windows/infos/QInfoList.py b/qt_ui/windows/infos/QInfoList.py
index e2f934c0..7614d21f 100644
--- a/qt_ui/windows/infos/QInfoList.py
+++ b/qt_ui/windows/infos/QInfoList.py
@@ -7,15 +7,16 @@ from qt_ui.windows.infos.QInfoItem import QInfoItem
class QInfoList(QListView):
-
- def __init__(self, game:Game):
+ def __init__(self, game: Game):
super(QInfoList, self).__init__()
self.model = QStandardItemModel(self)
self.setModel(self.model)
self.game = game
self.update_list()
- self.selectionModel().setCurrentIndex(self.indexAt(QPoint(1, 1)), QItemSelectionModel.Select)
+ self.selectionModel().setCurrentIndex(
+ self.indexAt(QPoint(1, 1)), QItemSelectionModel.Select
+ )
self.selectionModel().selectionChanged.connect(self.on_selected_info_changed)
def on_selected_info_changed(self):
@@ -26,8 +27,10 @@ class QInfoList(QListView):
if self.game is not None:
for i, info in enumerate(reversed(self.game.informations)):
self.model.appendRow(QInfoItem(info))
- self.selectionModel().setCurrentIndex(self.indexAt(QPoint(1, 1)), QItemSelectionModel.Select)
+ self.selectionModel().setCurrentIndex(
+ self.indexAt(QPoint(1, 1)), QItemSelectionModel.Select
+ )
def setGame(self, game):
self.game = game
- self.update_list()
\ No newline at end of file
+ self.update_list()
diff --git a/qt_ui/windows/infos/QInfoPanel.py b/qt_ui/windows/infos/QInfoPanel.py
index 6b31afa3..2bb021ab 100644
--- a/qt_ui/windows/infos/QInfoPanel.py
+++ b/qt_ui/windows/infos/QInfoPanel.py
@@ -5,7 +5,6 @@ from qt_ui.windows.infos.QInfoList import QInfoList
class QInfoPanel(QGroupBox):
-
def __init__(self, game: Game):
super(QInfoPanel, self).__init__("Info Panel")
self.informations_list = QInfoList(game)
@@ -24,5 +23,3 @@ class QInfoPanel(QGroupBox):
layout.setSpacing(0)
layout.setContentsMargins(0, 20, 0, 0)
self.setLayout(layout)
-
-
diff --git a/qt_ui/windows/infos/QInfoWidget.py b/qt_ui/windows/infos/QInfoWidget.py
index dfa8336a..5f76b422 100644
--- a/qt_ui/windows/infos/QInfoWidget.py
+++ b/qt_ui/windows/infos/QInfoWidget.py
@@ -4,7 +4,6 @@ from game.infos.information import Information
class QInfoWidget(QFrame):
-
def __init__(self, info: Information):
super(QInfoWidget, self).__init__()
self.info = info
@@ -14,8 +13,6 @@ class QInfoWidget(QFrame):
def init_ui(self):
layout = QGridLayout()
- layout.addWidget(self.titleLabel,0,0)
- layout.addWidget(self.textLabel,1,0)
+ layout.addWidget(self.titleLabel, 0, 0)
+ layout.addWidget(self.textLabel, 1, 0)
self.setLayout(layout)
-
-
diff --git a/qt_ui/windows/intel.py b/qt_ui/windows/intel.py
index b2db5421..5e8784cd 100644
--- a/qt_ui/windows/intel.py
+++ b/qt_ui/windows/intel.py
@@ -58,7 +58,9 @@ class IntelTableLayout(QGridLayout):
def add_spacer(self) -> None:
self.addItem(
QSpacerItem(0, 0, QSizePolicy.Preferred, QSizePolicy.Expanding),
- next(self.row), 0)
+ next(self.row),
+ 0,
+ )
def add_row(self, text: str, count: int) -> None:
row = next(self.row)
@@ -81,7 +83,10 @@ class AircraftIntelLayout(IntelTableLayout):
for airframe, count in base.aircraft.items():
if not count:
continue
- self.add_row(db.unit_get_expanded_info(game.enemy_country, airframe, 'name'), count)
+ self.add_row(
+ db.unit_get_expanded_info(game.enemy_country, airframe, "name"),
+ count,
+ )
self.add_spacer()
self.add_row("Total", total)
@@ -121,7 +126,6 @@ class ArmyIntelTab(ScrollingFrame):
class IntelTabs(QTabWidget):
-
def __init__(self, game: Game):
super().__init__()
@@ -131,7 +135,6 @@ class IntelTabs(QTabWidget):
class IntelWindow(QDialog):
-
def __init__(self, game: Game):
super().__init__()
diff --git a/qt_ui/windows/mission/QEditFlightDialog.py b/qt_ui/windows/mission/QEditFlightDialog.py
index a6893a47..028b088d 100644
--- a/qt_ui/windows/mission/QEditFlightDialog.py
+++ b/qt_ui/windows/mission/QEditFlightDialog.py
@@ -14,8 +14,13 @@ from qt_ui.windows.mission.flight.QFlightPlanner import QFlightPlanner
class QEditFlightDialog(QDialog):
"""Dialog window for editing flight plans and loadouts."""
- def __init__(self, game_model: GameModel, package_model: PackageModel,
- flight: Flight, parent=None) -> None:
+ def __init__(
+ self,
+ game_model: GameModel,
+ package_model: PackageModel,
+ flight: Flight,
+ parent=None,
+ ) -> None:
super().__init__(parent=parent)
self.game_model = game_model
@@ -25,8 +30,7 @@ class QEditFlightDialog(QDialog):
layout = QVBoxLayout()
- self.flight_planner = QFlightPlanner(package_model, flight,
- game_model.game)
+ self.flight_planner = QFlightPlanner(package_model, flight, game_model.game)
layout.addWidget(self.flight_planner)
self.setLayout(layout)
diff --git a/qt_ui/windows/mission/QFlightItem.py b/qt_ui/windows/mission/QFlightItem.py
index 3ba73a64..d8d9cb44 100644
--- a/qt_ui/windows/mission/QFlightItem.py
+++ b/qt_ui/windows/mission/QFlightItem.py
@@ -9,13 +9,15 @@ from qt_ui.uiconstants import AIRCRAFT_ICONS
# TODO: Replace with QFlightList.
class QFlightItem(QStandardItem):
-
def __init__(self, package: Package, flight: Flight):
super(QFlightItem, self).__init__()
self.package = package
self.flight = flight
- if db.unit_type_name(self.flight.unit_type).replace("/", " ") in AIRCRAFT_ICONS.keys():
+ if (
+ db.unit_type_name(self.flight.unit_type).replace("/", " ")
+ in AIRCRAFT_ICONS.keys()
+ ):
icon = QIcon((AIRCRAFT_ICONS[db.unit_type_name(self.flight.unit_type)]))
self.setIcon(icon)
self.setEditable(False)
diff --git a/qt_ui/windows/mission/QPackageDialog.py b/qt_ui/windows/mission/QPackageDialog.py
index 10acc4fe..3497140f 100644
--- a/qt_ui/windows/mission/QPackageDialog.py
+++ b/qt_ui/windows/mission/QPackageDialog.py
@@ -60,9 +60,9 @@ class QPackageDialog(QDialog):
self.package_type_label = QLabel("Package Type:")
self.package_type_text = QLabel(self.package_model.description)
# noinspection PyUnresolvedReferences
- self.package_changed.connect(lambda: self.package_type_text.setText(
- self.package_model.description
- ))
+ self.package_changed.connect(
+ lambda: self.package_type_text.setText(self.package_model.description)
+ )
self.package_type_column.addWidget(self.package_type_label)
self.package_type_column.addWidget(self.package_type_text)
@@ -91,7 +91,9 @@ class QPackageDialog(QDialog):
self.auto_asap.toggled.connect(self.set_asap)
self.tot_column.addWidget(self.auto_asap)
- self.tot_help_label = QLabel("Help")
+ self.tot_help_label = QLabel(
+ 'Help'
+ )
self.tot_help_label.setAlignment(Qt.AlignCenter)
self.tot_help_label.setOpenExternalLinks(True)
self.tot_column.addWidget(self.tot_help_label)
@@ -159,16 +161,17 @@ class QPackageDialog(QDialog):
def update_tot(self) -> None:
self.tot_spinner.setTime(self.tot_qtime())
- def on_selection_changed(self, selected: QItemSelection,
- _deselected: QItemSelection) -> None:
+ def on_selection_changed(
+ self, selected: QItemSelection, _deselected: QItemSelection
+ ) -> None:
"""Updates the state of the delete button."""
self.delete_flight_button.setEnabled(not selected.empty())
def on_add_flight(self) -> None:
"""Opens the new flight dialog."""
- self.add_flight_dialog = QFlightCreator(self.game,
- self.package_model.package,
- parent=self.window())
+ self.add_flight_dialog = QFlightCreator(
+ self.game, self.package_model.package, parent=self.window()
+ )
self.add_flight_dialog.created.connect(self.add_flight)
self.add_flight_dialog.show()
@@ -176,8 +179,9 @@ class QPackageDialog(QDialog):
"""Adds the new flight to the package."""
self.game.aircraft_inventory.claim_for_flight(flight)
self.package_model.add_flight(flight)
- planner = FlightPlanBuilder(self.game, self.package_model.package,
- is_player=True)
+ planner = FlightPlanBuilder(
+ self.game, self.package_model.package, is_player=True
+ )
try:
planner.populate_flight_plan(flight)
except PlanningError as ex:
@@ -209,8 +213,9 @@ class QNewPackageDialog(QPackageDialog):
New packages do not affect the ATO model until they are saved.
"""
- def __init__(self, game_model: GameModel, model: AtoModel,
- target: MissionTarget, parent=None) -> None:
+ def __init__(
+ self, game_model: GameModel, model: AtoModel, target: MissionTarget, parent=None
+ ) -> None:
super().__init__(game_model, PackageModel(Package(target)), parent=parent)
self.ato_model = model
@@ -240,8 +245,9 @@ class QEditPackageDialog(QPackageDialog):
Changes to existing packages occur immediately.
"""
- def __init__(self, game_model: GameModel, model: AtoModel,
- package: PackageModel) -> None:
+ def __init__(
+ self, game_model: GameModel, model: AtoModel, package: PackageModel
+ ) -> None:
super().__init__(game_model, package)
self.ato_model = model
diff --git a/qt_ui/windows/mission/QPlannedFlightsView.py b/qt_ui/windows/mission/QPlannedFlightsView.py
index 1ca6e845..302003ad 100644
--- a/qt_ui/windows/mission/QPlannedFlightsView.py
+++ b/qt_ui/windows/mission/QPlannedFlightsView.py
@@ -8,7 +8,6 @@ from game.theater.controlpoint import ControlPoint
class QPlannedFlightsView(QListView):
-
def __init__(self, game_model: GameModel, cp: ControlPoint) -> None:
super(QPlannedFlightsView, self).__init__()
self.game_model = game_model
diff --git a/qt_ui/windows/mission/flight/QFlightCreator.py b/qt_ui/windows/mission/flight/QFlightCreator.py
index eafd3c90..f4aa743c 100644
--- a/qt_ui/windows/mission/flight/QFlightCreator.py
+++ b/qt_ui/windows/mission/flight/QFlightCreator.py
@@ -20,8 +20,7 @@ from qt_ui.uiconstants import EVENT_ICONS
from qt_ui.widgets.QFlightSizeSpinner import QFlightSizeSpinner
from qt_ui.widgets.QLabeledWidget import QLabeledWidget
from qt_ui.widgets.combos.QAircraftTypeSelector import QAircraftTypeSelector
-from qt_ui.widgets.combos.QArrivalAirfieldSelector import \
- QArrivalAirfieldSelector
+from qt_ui.widgets.combos.QArrivalAirfieldSelector import QArrivalAirfieldSelector
from qt_ui.widgets.combos.QFlightTypeComboBox import QFlightTypeComboBox
from qt_ui.widgets.combos.QOriginAirfieldSelector import QOriginAirfieldSelector
@@ -42,26 +41,24 @@ class QFlightCreator(QDialog):
layout = QVBoxLayout()
- self.task_selector = QFlightTypeComboBox(
- self.game.theater, package.target
- )
+ self.task_selector = QFlightTypeComboBox(self.game.theater, package.target)
self.task_selector.setCurrentIndex(0)
- self.task_selector.currentTextChanged.connect(
- self.on_task_changed)
+ self.task_selector.currentTextChanged.connect(self.on_task_changed)
layout.addLayout(QLabeledWidget("Task:", self.task_selector))
self.aircraft_selector = QAircraftTypeSelector(
- self.game.aircraft_inventory.available_types_for_player, self.game.player_country, self.task_selector.currentData()
+ self.game.aircraft_inventory.available_types_for_player,
+ self.game.player_country,
+ self.task_selector.currentData(),
)
self.aircraft_selector.setCurrentIndex(0)
- self.aircraft_selector.currentIndexChanged.connect(
- self.on_aircraft_changed)
+ self.aircraft_selector.currentIndexChanged.connect(self.on_aircraft_changed)
layout.addLayout(QLabeledWidget("Aircraft:", self.aircraft_selector))
self.departure = QOriginAirfieldSelector(
self.game.aircraft_inventory,
[cp for cp in game.theater.controlpoints if cp.captured],
- self.aircraft_selector.currentData()
+ self.aircraft_selector.currentData(),
)
self.departure.availability_changed.connect(self.update_max_size)
self.departure.currentIndexChanged.connect(self.on_departure_changed)
@@ -70,14 +67,14 @@ class QFlightCreator(QDialog):
self.arrival = QArrivalAirfieldSelector(
[cp for cp in game.theater.controlpoints if cp.captured],
self.aircraft_selector.currentData(),
- "Same as departure"
+ "Same as departure",
)
layout.addLayout(QLabeledWidget("Arrival:", self.arrival))
self.divert = QArrivalAirfieldSelector(
[cp for cp in game.theater.controlpoints if cp.captured],
self.aircraft_selector.currentData(),
- "None"
+ "None",
)
layout.addLayout(QLabeledWidget("Divert:", self.divert))
@@ -86,15 +83,12 @@ class QFlightCreator(QDialog):
layout.addLayout(QLabeledWidget("Size:", self.flight_size_spinner))
self.client_slots_spinner = QFlightSizeSpinner(
- min_size=0,
- max_size=self.flight_size_spinner.value(),
- default_size=0
+ min_size=0, max_size=self.flight_size_spinner.value(), default_size=0
)
self.flight_size_spinner.valueChanged.connect(
lambda v: self.client_slots_spinner.setMaximum(v)
)
- layout.addLayout(
- QLabeledWidget("Client Slots:", self.client_slots_spinner))
+ layout.addLayout(QLabeledWidget("Client Slots:", self.client_slots_spinner))
# When an off-map spawn overrides the start type to in-flight, we save
# the selected type into this value. If a non-off-map spawn is selected
@@ -103,14 +97,20 @@ class QFlightCreator(QDialog):
self.start_type = QComboBox()
self.start_type.addItems(["Cold", "Warm", "Runway", "In Flight"])
self.start_type.setCurrentText(self.game.settings.default_start_type)
- layout.addLayout(QLabeledWidget(
- "Start type:", self.start_type,
- tooltip="Selects the start type for this flight."))
- layout.addWidget(QLabel(
- "Any option other than Cold will make this flight " +
- "non-targetable
by OCA/Aircraft missions. This will affect " +
- "game balance."
- ))
+ layout.addLayout(
+ QLabeledWidget(
+ "Start type:",
+ self.start_type,
+ tooltip="Selects the start type for this flight.",
+ )
+ )
+ layout.addWidget(
+ QLabel(
+ "Any option other than Cold will make this flight "
+ + "non-targetable
by OCA/Aircraft missions. This will affect "
+ + "game balance."
+ )
+ )
self.custom_name = QLineEdit()
self.custom_name.textChanged.connect(self.set_custom_name_text)
@@ -159,8 +159,7 @@ class QFlightCreator(QDialog):
def create_flight(self) -> None:
error = self.verify_form()
if error is not None:
- QMessageBox.critical(self, "Could not create flight", error,
- QMessageBox.Ok)
+ QMessageBox.critical(self, "Could not create flight", error, QMessageBox.Ok)
return
task = self.task_selector.currentData()
@@ -173,9 +172,18 @@ class QFlightCreator(QDialog):
if arrival is None:
arrival = origin
- flight = Flight(self.package, self.country, aircraft, size, task,
- self.start_type.currentText(), origin, arrival, divert,
- custom_name=self.custom_name_text)
+ flight = Flight(
+ self.package,
+ self.country,
+ aircraft,
+ size,
+ task,
+ self.start_type.currentText(),
+ origin,
+ arrival,
+ divert,
+ custom_name=self.custom_name_text,
+ )
flight.client_count = self.client_slots_spinner.value()
# noinspection PyUnresolvedReferences
@@ -203,7 +211,10 @@ class QFlightCreator(QDialog):
self.restore_start_type = None
def on_task_changed(self) -> None:
- self.aircraft_selector.updateItems(self.task_selector.currentData(), self.game.aircraft_inventory.available_types_for_player)
+ self.aircraft_selector.updateItems(
+ self.task_selector.currentData(),
+ self.game.aircraft_inventory.available_types_for_player,
+ )
def update_max_size(self, available: int) -> None:
self.flight_size_spinner.setMaximum(min(available, 4))
diff --git a/qt_ui/windows/mission/flight/QFlightPlanner.py b/qt_ui/windows/mission/flight/QFlightPlanner.py
index 71904b48..0c1b9e03 100644
--- a/qt_ui/windows/mission/flight/QFlightPlanner.py
+++ b/qt_ui/windows/mission/flight/QFlightPlanner.py
@@ -3,16 +3,14 @@ from PySide2.QtWidgets import QTabWidget
from game import Game
from gen.flights.flight import Flight
from qt_ui.models import PackageModel
-from qt_ui.windows.mission.flight.payload.QFlightPayloadTab import \
- QFlightPayloadTab
-from qt_ui.windows.mission.flight.settings.QGeneralFlightSettingsTab import \
- QGeneralFlightSettingsTab
-from qt_ui.windows.mission.flight.waypoints.QFlightWaypointTab import \
- QFlightWaypointTab
+from qt_ui.windows.mission.flight.payload.QFlightPayloadTab import QFlightPayloadTab
+from qt_ui.windows.mission.flight.settings.QGeneralFlightSettingsTab import (
+ QGeneralFlightSettingsTab,
+)
+from qt_ui.windows.mission.flight.waypoints.QFlightWaypointTab import QFlightWaypointTab
class QFlightPlanner(QTabWidget):
-
def __init__(self, package_model: PackageModel, flight: Flight, game: Game):
super().__init__()
@@ -20,8 +18,7 @@ class QFlightPlanner(QTabWidget):
game, package_model, flight
)
self.payload_tab = QFlightPayloadTab(flight, game)
- self.waypoint_tab = QFlightWaypointTab(game, package_model.package,
- flight)
+ self.waypoint_tab = QFlightWaypointTab(game, package_model.package, flight)
self.addTab(self.general_settings_tab, "General Flight settings")
self.addTab(self.payload_tab, "Payload")
self.addTab(self.waypoint_tab, "Waypoints")
diff --git a/qt_ui/windows/mission/flight/payload/QFlightPayloadTab.py b/qt_ui/windows/mission/flight/payload/QFlightPayloadTab.py
index 9ad63330..b61fe432 100644
--- a/qt_ui/windows/mission/flight/payload/QFlightPayloadTab.py
+++ b/qt_ui/windows/mission/flight/payload/QFlightPayloadTab.py
@@ -7,7 +7,6 @@ from qt_ui.windows.mission.flight.payload.QLoadoutEditor import QLoadoutEditor
class QFlightPayloadTab(QFrame):
-
def __init__(self, flight: Flight, game: Game):
super(QFlightPayloadTab, self).__init__()
self.flight = flight
@@ -18,7 +17,9 @@ class QFlightPayloadTab(QFrame):
layout = QGridLayout()
# Docs Link
- docsText = QLabel("How to create your own default loadout")
+ docsText = QLabel(
+ 'How to create your own default loadout'
+ )
docsText.setAlignment(Qt.AlignCenter)
docsText.setOpenExternalLinks(True)
diff --git a/qt_ui/windows/mission/flight/payload/QLoadoutEditor.py b/qt_ui/windows/mission/flight/payload/QLoadoutEditor.py
index 75c0f7ec..4d675e42 100644
--- a/qt_ui/windows/mission/flight/payload/QLoadoutEditor.py
+++ b/qt_ui/windows/mission/flight/payload/QLoadoutEditor.py
@@ -13,7 +13,6 @@ from qt_ui.windows.mission.flight.payload.QPylonEditor import QPylonEditor
class QLoadoutEditor(QGroupBox):
-
def __init__(self, flight: Flight, game: Game) -> None:
super().__init__("Use custom loadout")
self.flight = flight
@@ -28,8 +27,7 @@ class QLoadoutEditor(QGroupBox):
for i, pylon in enumerate(Pylon.iter_pylons(self.flight.unit_type)):
label = QLabel(f"{pylon.number}")
- label.setSizePolicy(
- QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
+ label.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
layout.addWidget(label, i, 0)
layout.addWidget(QPylonEditor(game, flight, pylon), i, 1)
diff --git a/qt_ui/windows/mission/flight/payload/QPylonEditor.py b/qt_ui/windows/mission/flight/payload/QPylonEditor.py
index 9d95bc8c..eb0314cb 100644
--- a/qt_ui/windows/mission/flight/payload/QPylonEditor.py
+++ b/qt_ui/windows/mission/flight/payload/QPylonEditor.py
@@ -11,7 +11,6 @@ from dcs import weapons_data
class QPylonEditor(QComboBox):
-
def __init__(self, game: Game, flight: Flight, pylon: Pylon) -> None:
super().__init__()
self.flight = flight
@@ -30,7 +29,7 @@ class QPylonEditor(QComboBox):
self.addItem(weapon.name, weapon)
if current == weapon:
self.setCurrentIndex(i + 1)
-
+
self.currentIndexChanged.connect(self.on_pylon_change)
def on_pylon_change(self):
@@ -40,8 +39,7 @@ class QPylonEditor(QComboBox):
if selected is None:
logging.debug(f"Pylon {self.pylon.number} emptied")
else:
- logging.debug(
- f"Pylon {self.pylon.number} changed to {selected.name}")
+ logging.debug(f"Pylon {self.pylon.number} changed to {selected.name}")
def default_loadout(self) -> None:
self.flight.unit_type.load_payloads()
@@ -51,7 +49,9 @@ class QPylonEditor(QComboBox):
loadout = None
# Iterate through each possible payload type for a given aircraft.
# Some aircraft have custom loadouts that in aren't the standard set.
- for payload_override in db.EXPANDED_TASK_PAYLOAD_OVERRIDE.get(self.flight.flight_type.name):
+ for payload_override in db.EXPANDED_TASK_PAYLOAD_OVERRIDE.get(
+ self.flight.flight_type.name
+ ):
if loadout is None:
loadout = self.flight.unit_type.loadout_by_name(payload_override)
if loadout is not None:
@@ -75,6 +75,12 @@ class QPylonEditor(QComboBox):
else:
historical_weapon = orig_weapon
if historical_weapon is not None:
- self.setCurrentText(weapons_data.weapon_ids.get(historical_weapon.cls_id).get("name"))
+ self.setCurrentText(
+ weapons_data.weapon_ids.get(historical_weapon.cls_id).get(
+ "name"
+ )
+ )
else:
- self.setCurrentText(weapons_data.weapon_ids.get(pylon_default_weapon).get("name"))
\ No newline at end of file
+ self.setCurrentText(
+ weapons_data.weapon_ids.get(pylon_default_weapon).get("name")
+ )
diff --git a/qt_ui/windows/mission/flight/settings/FlightAirfieldDisplay.py b/qt_ui/windows/mission/flight/settings/FlightAirfieldDisplay.py
index 4b56cf1b..282df1ce 100644
--- a/qt_ui/windows/mission/flight/settings/FlightAirfieldDisplay.py
+++ b/qt_ui/windows/mission/flight/settings/FlightAirfieldDisplay.py
@@ -1,6 +1,6 @@
import logging
-from PySide2.QtWidgets import (QGroupBox, QLabel, QMessageBox, QVBoxLayout)
+from PySide2.QtWidgets import QGroupBox, QLabel, QMessageBox, QVBoxLayout
from game import Game
from gen.flights.flight import Flight
@@ -8,14 +8,11 @@ from gen.flights.flightplan import FlightPlanBuilder, PlanningError
from gen.flights.traveltime import TotEstimator
from qt_ui.models import PackageModel
from qt_ui.widgets.QLabeledWidget import QLabeledWidget
-from qt_ui.widgets.combos.QArrivalAirfieldSelector import \
- QArrivalAirfieldSelector
+from qt_ui.widgets.combos.QArrivalAirfieldSelector import QArrivalAirfieldSelector
class FlightAirfieldDisplay(QGroupBox):
-
- def __init__(self, game: Game, package_model: PackageModel,
- flight: Flight) -> None:
+ def __init__(self, game: Game, package_model: PackageModel, flight: Flight) -> None:
super().__init__("Departure/Arrival")
self.game = game
self.package_model = package_model
@@ -24,18 +21,25 @@ class FlightAirfieldDisplay(QGroupBox):
layout = QVBoxLayout()
self.departure_time = QLabel()
- layout.addLayout(QLabeledWidget(
- f"Departing from {flight.from_cp.name}",
- self.departure_time))
+ layout.addLayout(
+ QLabeledWidget(
+ f"Departing from {flight.from_cp.name}", self.departure_time
+ )
+ )
self.package_model.tot_changed.connect(self.update_departure_time)
self.update_departure_time()
- layout.addWidget(QLabel("Determined based on the package TOT. Edit the "
- "package to adjust the TOT."))
+ layout.addWidget(
+ QLabel(
+ "Determined based on the package TOT. Edit the "
+ "package to adjust the TOT."
+ )
+ )
self.arrival = QArrivalAirfieldSelector(
[cp for cp in game.theater.controlpoints if cp.captured],
- flight.unit_type, "Same as departure"
+ flight.unit_type,
+ "Same as departure",
)
self.arrival.currentIndexChanged.connect(self.set_arrival)
if flight.arrival != flight.departure:
@@ -44,7 +48,8 @@ class FlightAirfieldDisplay(QGroupBox):
self.divert = QArrivalAirfieldSelector(
[cp for cp in game.theater.controlpoints if cp.captured],
- flight.unit_type, "None"
+ flight.unit_type,
+ "None",
)
self.divert.currentIndexChanged.connect(self.set_divert)
if flight.divert is not None:
@@ -94,6 +99,7 @@ class FlightAirfieldDisplay(QGroupBox):
)
def update_flight_plan(self) -> None:
- planner = FlightPlanBuilder(self.game, self.package_model.package,
- is_player=True)
+ planner = FlightPlanBuilder(
+ self.game, self.package_model.package, is_player=True
+ )
planner.populate_flight_plan(self.flight)
diff --git a/qt_ui/windows/mission/flight/settings/QCustomName.py b/qt_ui/windows/mission/flight/settings/QCustomName.py
index 7a22e48d..f0e04130 100644
--- a/qt_ui/windows/mission/flight/settings/QCustomName.py
+++ b/qt_ui/windows/mission/flight/settings/QCustomName.py
@@ -4,7 +4,6 @@ from gen.flights.flight import Flight
class QFlightCustomName(QGroupBox):
-
def __init__(self, flight: Flight):
super(QFlightCustomName, self).__init__()
diff --git a/qt_ui/windows/mission/flight/settings/QFlightSlotEditor.py b/qt_ui/windows/mission/flight/settings/QFlightSlotEditor.py
index f21b07b0..bf078bfe 100644
--- a/qt_ui/windows/mission/flight/settings/QFlightSlotEditor.py
+++ b/qt_ui/windows/mission/flight/settings/QFlightSlotEditor.py
@@ -17,9 +17,7 @@ class QFlightSlotEditor(QGroupBox):
self.package_model = package_model
self.flight = flight
self.game = game
- self.inventory = self.game.aircraft_inventory.for_control_point(
- flight.from_cp
- )
+ self.inventory = self.game.aircraft_inventory.for_control_point(flight.from_cp)
available = self.inventory.available(self.flight.unit_type)
max_count = self.flight.count + available
if max_count > 4:
@@ -67,7 +65,8 @@ class QFlightSlotEditor(QGroupBox):
logging.error(
f"Could not add {difference} additional aircraft to "
f"{self.flight} because {self.flight.from_cp} has only "
- f"{available} {self.flight.unit_type} remaining")
+ f"{available} {self.flight.unit_type} remaining"
+ )
self.flight.count = old_count
self.game.aircraft_inventory.claim_for_flight(self.flight)
self.changed.emit()
@@ -81,4 +80,4 @@ class QFlightSlotEditor(QGroupBox):
def _cap_client_count(self):
if self.flight.client_count > self.flight.count:
self.flight.client_count = self.flight.count
- self.client_count_spinner.setValue(self.flight.client_count)
\ No newline at end of file
+ self.client_count_spinner.setValue(self.flight.client_count)
diff --git a/qt_ui/windows/mission/flight/settings/QFlightStartType.py b/qt_ui/windows/mission/flight/settings/QFlightStartType.py
index 17fbe042..ccab3deb 100644
--- a/qt_ui/windows/mission/flight/settings/QFlightStartType.py
+++ b/qt_ui/windows/mission/flight/settings/QFlightStartType.py
@@ -11,7 +11,6 @@ from qt_ui.models import PackageModel
class QFlightStartType(QGroupBox):
-
def __init__(self, package_model: PackageModel, flight: Flight):
super().__init__()
self.package_model = package_model
@@ -32,10 +31,12 @@ class QFlightStartType(QGroupBox):
self.main_row.addWidget(self.start_type)
self.layout.addLayout(self.main_row)
- self.layout.addWidget(QLabel(
- "Any option other than Cold will make this flight non-targetable " +
- "by OCA/Aircraft missions. This will affect game balance."
- ))
+ self.layout.addWidget(
+ QLabel(
+ "Any option other than Cold will make this flight non-targetable "
+ + "by OCA/Aircraft missions. This will affect game balance."
+ )
+ )
self.setLayout(self.layout)
def _on_start_type_selected(self):
diff --git a/qt_ui/windows/mission/flight/settings/QFlightTypeTaskInfo.py b/qt_ui/windows/mission/flight/settings/QFlightTypeTaskInfo.py
index 76e7f815..c05a0fa6 100644
--- a/qt_ui/windows/mission/flight/settings/QFlightTypeTaskInfo.py
+++ b/qt_ui/windows/mission/flight/settings/QFlightTypeTaskInfo.py
@@ -5,7 +5,6 @@ from qt_ui.uiconstants import AIRCRAFT_ICONS
class QFlightTypeTaskInfo(QGroupBox):
-
def __init__(self, flight):
super(QFlightTypeTaskInfo, self).__init__("Flight")
self.flight = flight
@@ -14,7 +13,9 @@ class QFlightTypeTaskInfo(QGroupBox):
self.aircraft_icon = QLabel()
if db.unit_type_name(self.flight.unit_type) in AIRCRAFT_ICONS:
- self.aircraft_icon.setPixmap(AIRCRAFT_ICONS[db.unit_type_name(self.flight.unit_type)])
+ self.aircraft_icon.setPixmap(
+ AIRCRAFT_ICONS[db.unit_type_name(self.flight.unit_type)]
+ )
self.task = QLabel("Task:")
self.task_type = QLabel(str(flight.flight_type))
diff --git a/qt_ui/windows/mission/flight/settings/QGeneralFlightSettingsTab.py b/qt_ui/windows/mission/flight/settings/QGeneralFlightSettingsTab.py
index 804fe8dc..0b207356 100644
--- a/qt_ui/windows/mission/flight/settings/QGeneralFlightSettingsTab.py
+++ b/qt_ui/windows/mission/flight/settings/QGeneralFlightSettingsTab.py
@@ -4,16 +4,15 @@ from PySide2.QtWidgets import QFrame, QGridLayout, QVBoxLayout
from game import Game
from gen.flights.flight import Flight
from qt_ui.models import PackageModel
-from qt_ui.windows.mission.flight.settings.FlightAirfieldDisplay import \
- FlightAirfieldDisplay
-from qt_ui.windows.mission.flight.settings.QFlightSlotEditor import \
- QFlightSlotEditor
-from qt_ui.windows.mission.flight.settings.QFlightStartType import \
- QFlightStartType
-from qt_ui.windows.mission.flight.settings.QFlightTypeTaskInfo import \
- QFlightTypeTaskInfo
-from qt_ui.windows.mission.flight.settings.QCustomName import \
- QFlightCustomName
+from qt_ui.windows.mission.flight.settings.FlightAirfieldDisplay import (
+ FlightAirfieldDisplay,
+)
+from qt_ui.windows.mission.flight.settings.QFlightSlotEditor import QFlightSlotEditor
+from qt_ui.windows.mission.flight.settings.QFlightStartType import QFlightStartType
+from qt_ui.windows.mission.flight.settings.QFlightTypeTaskInfo import (
+ QFlightTypeTaskInfo,
+)
+from qt_ui.windows.mission.flight.settings.QCustomName import QFlightCustomName
class QGeneralFlightSettingsTab(QFrame):
@@ -24,8 +23,7 @@ class QGeneralFlightSettingsTab(QFrame):
layout = QGridLayout()
layout.addWidget(QFlightTypeTaskInfo(flight), 0, 0)
- layout.addWidget(FlightAirfieldDisplay(game, package_model, flight), 1,
- 0)
+ layout.addWidget(FlightAirfieldDisplay(game, package_model, flight), 1, 0)
layout.addWidget(QFlightSlotEditor(package_model, flight, game), 2, 0)
layout.addWidget(QFlightStartType(package_model, flight), 3, 0)
layout.addWidget(QFlightCustomName(flight), 4, 0)
diff --git a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointInfoBox.py b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointInfoBox.py
index 137b70b7..29834c01 100644
--- a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointInfoBox.py
+++ b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointInfoBox.py
@@ -4,12 +4,11 @@ from gen.flights.flight import FlightWaypoint
class QFlightWaypointInfoBox(QGroupBox):
-
- def __init__(self, flight_wpt:FlightWaypoint = None):
+ def __init__(self, flight_wpt: FlightWaypoint = None):
super(QFlightWaypointInfoBox, self).__init__("Waypoint")
self.flight_wpt = flight_wpt
if flight_wpt is None:
- self.flight_wpt = FlightWaypoint(0,0,0)
+ self.flight_wpt = FlightWaypoint(0, 0, 0)
self.x_position_label = QLabel(str(self.flight_wpt.x))
self.y_position_label = QLabel(str(self.flight_wpt.y))
self.alt_label = QLabel(str(int(self.flight_wpt.alt.feet)))
@@ -46,7 +45,7 @@ class QFlightWaypointInfoBox(QGroupBox):
desc_layout.addWidget(self.desc_label)
desc_layout.addStretch()
- #layout.addLayout(name_layout)
+ # layout.addLayout(name_layout)
layout.addLayout(x_pos_layout)
layout.addLayout(y_pos_layout)
layout.addLayout(alt_layout)
@@ -54,10 +53,10 @@ class QFlightWaypointInfoBox(QGroupBox):
self.setLayout(layout)
- def set_flight_waypoint(self, flight_wpt:FlightWaypoint):
+ def set_flight_waypoint(self, flight_wpt: FlightWaypoint):
self.flight_wpt = flight_wpt
if flight_wpt is None:
- self.flight_wpt = FlightWaypoint(0,0,0)
+ self.flight_wpt = FlightWaypoint(0, 0, 0)
self.x_position_label.setText(str(self.flight_wpt.x))
self.y_position_label.setText(str(self.flight_wpt.y))
self.alt_label.setText(str(int(self.flight_wpt.alt.feet)))
diff --git a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointItem.py b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointItem.py
index d3c596b1..c970bb94 100644
--- a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointItem.py
+++ b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointItem.py
@@ -6,10 +6,8 @@ from gen.flights.flight import FlightWaypoint
class QWaypointItem(QStandardItem):
-
def __init__(self, point: FlightWaypoint, number):
super(QWaypointItem, self).__init__()
self.number = number
- self.setText('{:<16}'.format(point.pretty_name))
+ self.setText("{:<16}".format(point.pretty_name))
self.setEditable(False)
-
diff --git a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointList.py b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointList.py
index 28c63d59..b9ba7444 100644
--- a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointList.py
+++ b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointList.py
@@ -6,12 +6,10 @@ from PySide2.QtWidgets import QHeaderView, QTableView
from gen.ato import Package
from gen.flights.flight import Flight, FlightWaypoint, FlightWaypointType
-from qt_ui.windows.mission.flight.waypoints.QFlightWaypointItem import \
- QWaypointItem
+from qt_ui.windows.mission.flight.waypoints.QFlightWaypointItem import QWaypointItem
class QFlightWaypointList(QTableView):
-
def __init__(self, package: Package, flight: Flight):
super().__init__()
self.package = package
@@ -28,7 +26,9 @@ class QFlightWaypointList(QTableView):
self.selectedPoint = self.flight.points[0]
self.update_list()
- self.selectionModel().setCurrentIndex(self.indexAt(QPoint(1, 1)), QItemSelectionModel.Select)
+ self.selectionModel().setCurrentIndex(
+ self.indexAt(QPoint(1, 1)), QItemSelectionModel.Select
+ )
def update_list(self):
self.model.clear()
@@ -38,16 +38,18 @@ class QFlightWaypointList(QTableView):
waypoints = self.flight.flight_plan.waypoints
for row, waypoint in enumerate(waypoints):
self.add_waypoint_row(row, self.flight, waypoint)
- self.selectionModel().setCurrentIndex(self.indexAt(QPoint(1, 1)),
- QItemSelectionModel.Select)
+ self.selectionModel().setCurrentIndex(
+ self.indexAt(QPoint(1, 1)), QItemSelectionModel.Select
+ )
self.resizeColumnsToContents()
total_column_width = self.verticalHeader().width() + self.lineWidth()
for i in range(0, self.model.columnCount()):
total_column_width += self.columnWidth(i) + self.lineWidth()
self.setFixedWidth(total_column_width)
- def add_waypoint_row(self, row: int, flight: Flight,
- waypoint: FlightWaypoint) -> None:
+ def add_waypoint_row(
+ self, row: int, flight: Flight, waypoint: FlightWaypoint
+ ) -> None:
self.model.insertRow(self.model.rowCount())
self.model.setItem(row, 0, QWaypointItem(waypoint, row))
diff --git a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointTab.py b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointTab.py
index abd1733d..95ede450 100644
--- a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointTab.py
+++ b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointTab.py
@@ -20,15 +20,15 @@ from gen.flights.flightplan import (
PlanningError,
StrikeFlightPlan,
)
-from qt_ui.windows.mission.flight.waypoints.QFlightWaypointList import \
- QFlightWaypointList
-from qt_ui.windows.mission.flight.waypoints \
- .QPredefinedWaypointSelectionWindow import \
- QPredefinedWaypointSelectionWindow
+from qt_ui.windows.mission.flight.waypoints.QFlightWaypointList import (
+ QFlightWaypointList,
+)
+from qt_ui.windows.mission.flight.waypoints.QPredefinedWaypointSelectionWindow import (
+ QPredefinedWaypointSelectionWindow,
+)
class QFlightWaypointTab(QFrame):
-
def __init__(self, game: Game, package: Package, flight: Flight):
super(QFlightWaypointTab, self).__init__()
self.game = game
@@ -46,8 +46,7 @@ class QFlightWaypointTab(QFrame):
def init_ui(self):
layout = QGridLayout()
- self.flight_waypoint_list = QFlightWaypointList(self.package,
- self.flight)
+ self.flight_waypoint_list = QFlightWaypointList(self.package, self.flight)
layout.addWidget(self.flight_waypoint_list, 0, 0)
rlayout = QVBoxLayout()
@@ -58,10 +57,13 @@ class QFlightWaypointTab(QFrame):
self.recreate_buttons.clear()
for task in self.package.target.mission_types(for_player=True):
+
def make_closure(arg):
def closure():
return self.confirm_recreate(arg)
+
return closure
+
button = QPushButton(f"Recreate as {task}")
button.clicked.connect(make_closure(task))
rlayout.addWidget(button)
@@ -106,7 +108,9 @@ class QFlightWaypointTab(QFrame):
self.flight.flight_plan.custom_waypoints.remove(waypoint)
def on_fast_waypoint(self):
- self.subwindow = QPredefinedWaypointSelectionWindow(self.game, self.flight, self.flight_waypoint_list)
+ self.subwindow = QPredefinedWaypointSelectionWindow(
+ self.game, self.flight, self.flight_waypoint_list
+ )
self.subwindow.waypoints_added.connect(self.on_waypoints_added)
self.subwindow.show()
@@ -120,8 +124,7 @@ class QFlightWaypointTab(QFrame):
self.on_change()
def on_rtb_waypoint(self):
- rtb = self.planner.generate_rtb_waypoint(self.flight,
- self.flight.from_cp)
+ rtb = self.planner.generate_rtb_waypoint(self.flight, self.flight.from_cp)
self.degrade_to_custom_flight_plan()
assert isinstance(self.flight.flight_plan, CustomFlightPlan)
self.flight.flight_plan.custom_waypoints.append(rtb)
@@ -133,17 +136,19 @@ class QFlightWaypointTab(QFrame):
self.flight.flight_plan = CustomFlightPlan(
package=self.flight.package,
flight=self.flight,
- custom_waypoints=self.flight.flight_plan.waypoints
+ custom_waypoints=self.flight.flight_plan.waypoints,
)
def confirm_recreate(self, task: FlightType) -> None:
result = QMessageBox.question(
self,
"Regenerate flight?",
- ("Changing the flight type will reset its flight plan. Do you want "
- "to continue?"),
+ (
+ "Changing the flight type will reset its flight plan. Do you want "
+ "to continue?"
+ ),
QMessageBox.No,
- QMessageBox.Yes
+ QMessageBox.Yes,
)
original_task = self.flight.flight_type
if result == QMessageBox.Yes:
diff --git a/qt_ui/windows/mission/flight/waypoints/QPredefinedWaypointSelectionWindow.py b/qt_ui/windows/mission/flight/waypoints/QPredefinedWaypointSelectionWindow.py
index ccec5034..5bc71271 100644
--- a/qt_ui/windows/mission/flight/waypoints/QPredefinedWaypointSelectionWindow.py
+++ b/qt_ui/windows/mission/flight/waypoints/QPredefinedWaypointSelectionWindow.py
@@ -11,16 +11,18 @@ from PySide2.QtWidgets import (
from game import Game
from gen.flights.flight import Flight
from qt_ui.uiconstants import EVENT_ICONS
-from qt_ui.widgets.combos.QPredefinedWaypointSelectionComboBox import \
- QPredefinedWaypointSelectionComboBox
-from qt_ui.windows.mission.flight.waypoints.QFlightWaypointInfoBox import \
- QFlightWaypointInfoBox
+from qt_ui.widgets.combos.QPredefinedWaypointSelectionComboBox import (
+ QPredefinedWaypointSelectionComboBox,
+)
+from qt_ui.windows.mission.flight.waypoints.QFlightWaypointInfoBox import (
+ QFlightWaypointInfoBox,
+)
PREDEFINED_WAYPOINT_CATEGORIES = [
"Frontline (CAS AREA)",
"Building",
"Units",
- "Airbase"
+ "Airbase",
]
@@ -56,7 +58,6 @@ class QPredefinedWaypointSelectionWindow(QDialog):
self.init_ui()
self.on_select_wpt_changed()
-
def init_ui(self):
layout = QVBoxLayout()
@@ -79,7 +80,9 @@ class QPredefinedWaypointSelectionWindow(QDialog):
self.setLayout(layout)
def on_select_wpt_changed(self):
- self.selected_waypoints = self.wpt_selection_box.get_selected_waypoints(self.include_all.isChecked())
+ self.selected_waypoints = self.wpt_selection_box.get_selected_waypoints(
+ self.include_all.isChecked()
+ )
if self.selected_waypoints is None or len(self.selected_waypoints) <= 0:
self.add_button.setDisabled(True)
else:
diff --git a/qt_ui/windows/newgame/QCampaignList.py b/qt_ui/windows/newgame/QCampaignList.py
index 7c9e7cec..b97f2ef0 100644
--- a/qt_ui/windows/newgame/QCampaignList.py
+++ b/qt_ui/windows/newgame/QCampaignList.py
@@ -19,6 +19,7 @@ PERF_MEDIUM = 1
PERF_HARD = 2
PERF_NASA = 3
+
@dataclass(frozen=True)
class Campaign:
name: str
@@ -46,7 +47,7 @@ class Campaign:
data.get("recommended_enemy_faction", "Russia 1990"),
data.get("performance", 0),
data,
- path
+ path,
)
def load_theater(self) -> ConflictTheater:
@@ -68,7 +69,6 @@ def load_campaigns() -> List[Campaign]:
class QCampaignItem(QStandardItem):
-
def __init__(self, campaign: Campaign) -> None:
super(QCampaignItem, self).__init__()
self.setIcon(QtGui.QIcon(CONST.ICONS[campaign.icon_name]))
@@ -77,7 +77,6 @@ class QCampaignItem(QStandardItem):
class QCampaignList(QListView):
-
def __init__(self, campaigns: List[Campaign]) -> None:
super(QCampaignList, self).__init__()
self.model = QStandardItemModel(self)
@@ -105,4 +104,4 @@ class QCampaignList(QListView):
self.repaint()
def clear_layout(self):
- self.model.removeRows(0, self.model.rowCount())
\ No newline at end of file
+ self.model.removeRows(0, self.model.rowCount())
diff --git a/qt_ui/windows/newgame/QNewGameWizard.py b/qt_ui/windows/newgame/QNewGameWizard.py
index 4d7bb5cb..866db587 100644
--- a/qt_ui/windows/newgame/QNewGameWizard.py
+++ b/qt_ui/windows/newgame/QNewGameWizard.py
@@ -47,8 +47,10 @@ class NewGameWizard(QtWidgets.QWizard):
self.addPage(DifficultyAndAutomationOptions())
self.addPage(ConclusionPage())
- self.setPixmap(QtWidgets.QWizard.WatermarkPixmap,
- QtGui.QPixmap('./resources/ui/wizard/watermark1.png'))
+ self.setPixmap(
+ QtWidgets.QWizard.WatermarkPixmap,
+ QtGui.QPixmap("./resources/ui/wizard/watermark1.png"),
+ )
self.setWizardStyle(QtWidgets.QWizard.ModernStyle)
self.setWindowTitle("New Game")
@@ -63,21 +65,19 @@ class NewGameWizard(QtWidgets.QWizard):
campaign = self.campaigns[0]
settings = Settings(
- player_income_multiplier=self.field(
- "player_income_multiplier") / 10,
+ player_income_multiplier=self.field("player_income_multiplier") / 10,
enemy_income_multiplier=self.field("enemy_income_multiplier") / 10,
automate_runway_repair=self.field("automate_runway_repairs"),
automate_front_line_reinforcements=self.field(
"automate_front_line_purchases"
),
- automate_aircraft_reinforcements=self.field(
- "automate_aircraft_purchases"
- ),
- supercarrier=self.field("supercarrier")
+ automate_aircraft_reinforcements=self.field("automate_aircraft_purchases"),
+ supercarrier=self.field("supercarrier"),
)
generator_settings = GeneratorSettings(
start_date=db.TIME_PERIODS[
- list(db.TIME_PERIODS.keys())[self.field("timePeriod")]],
+ list(db.TIME_PERIODS.keys())[self.field("timePeriod")]
+ ],
player_budget=int(self.field("starting_money")),
enemy_budget=int(self.field("enemy_starting_money")),
# QSlider forces integers, so we use 1 to 50 and divide by 10 to
@@ -87,7 +87,7 @@ class NewGameWizard(QtWidgets.QWizard):
no_carrier=self.field("no_carrier"),
no_lha=self.field("no_lha"),
no_player_navy=self.field("no_player_navy"),
- no_enemy_navy=self.field("no_enemy_navy")
+ no_enemy_navy=self.field("no_enemy_navy"),
)
blue_faction = [c for c in db.FACTIONS][self.field("blueFaction")]
@@ -97,7 +97,7 @@ class NewGameWizard(QtWidgets.QWizard):
red_faction,
campaign.load_theater(),
settings,
- generator_settings
+ generator_settings,
)
self.generatedGame = generator.generate()
@@ -109,11 +109,15 @@ class IntroPage(QtWidgets.QWizardPage):
super(IntroPage, self).__init__(parent)
self.setTitle("Introduction")
- self.setPixmap(QtWidgets.QWizard.WatermarkPixmap,
- QtGui.QPixmap('./resources/ui/wizard/watermark1.png'))
+ self.setPixmap(
+ QtWidgets.QWizard.WatermarkPixmap,
+ QtGui.QPixmap("./resources/ui/wizard/watermark1.png"),
+ )
- label = QtWidgets.QLabel("This wizard will help you setup a new game.\n\n"
- "Please make sure you saved and backed up your previous game before going through.")
+ label = QtWidgets.QLabel(
+ "This wizard will help you setup a new game.\n\n"
+ "Please make sure you saved and backed up your previous game before going through."
+ )
label.setWordWrap(True)
layout = QtWidgets.QVBoxLayout()
@@ -126,9 +130,13 @@ class FactionSelection(QtWidgets.QWizardPage):
super(FactionSelection, self).__init__(parent)
self.setTitle("Faction selection")
- self.setSubTitle("\nChoose the two opposing factions and select the player side.")
- self.setPixmap(QtWidgets.QWizard.LogoPixmap,
- QtGui.QPixmap('./resources/ui/misc/generator.png'))
+ self.setSubTitle(
+ "\nChoose the two opposing factions and select the player side."
+ )
+ self.setPixmap(
+ QtWidgets.QWizard.LogoPixmap,
+ QtGui.QPixmap("./resources/ui/misc/generator.png"),
+ )
self.setMinimumHeight(250)
@@ -178,19 +186,21 @@ class FactionSelection(QtWidgets.QWizardPage):
# Create required mod layout
self.requiredModsGroup = QtWidgets.QGroupBox("Required Mods")
self.requiredModsGroupLayout = QtWidgets.QHBoxLayout()
- self.requiredMods = QtWidgets.QLabel("