mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Add a wrapper type for ground unit info.
This commit is contained in:
@@ -1,239 +1,17 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import unique, Enum
|
||||
from typing import Type
|
||||
|
||||
from dcs.vehicles import AirDefence, Infantry, Unarmed, Artillery, Armor
|
||||
from dcs.unittype import VehicleType
|
||||
|
||||
from pydcs_extensions.frenchpack import frenchpack
|
||||
|
||||
|
||||
@unique
|
||||
class GroundUnitClass(Enum):
|
||||
Tank = (
|
||||
"Tank",
|
||||
(
|
||||
Armor.MBT_T_55,
|
||||
Armor.MBT_T_72B,
|
||||
Armor.MBT_T_72B3,
|
||||
Armor.MBT_T_80U,
|
||||
Armor.MBT_T_90,
|
||||
Armor.MBT_Leopard_2A4,
|
||||
Armor.MBT_Leopard_2A4_Trs,
|
||||
Armor.MBT_Leopard_2A5,
|
||||
Armor.MBT_Leopard_2A6M,
|
||||
Armor.MBT_Leopard_1A3,
|
||||
Armor.MBT_Leclerc,
|
||||
Armor.MBT_Challenger_II,
|
||||
Armor.MBT_Chieftain_Mk_3,
|
||||
Armor.MBT_M1A2_Abrams,
|
||||
Armor.MBT_M60A3_Patton,
|
||||
Armor.MBT_Merkava_IV,
|
||||
Armor.ZTZ_96B,
|
||||
# WW2
|
||||
# Axis
|
||||
Armor.Tk_PzIV_H,
|
||||
Armor.SPG_Sturmpanzer_IV_Brummbar,
|
||||
Armor.MT_Pz_Kpfw_V_Panther_Ausf_G,
|
||||
Armor.HT_Pz_Kpfw_VI_Tiger_I,
|
||||
Armor.HT_Pz_Kpfw_VI_Ausf__B_Tiger_II,
|
||||
# Allies
|
||||
Armor.Tk_M4_Sherman,
|
||||
Armor.CT_Centaur_IV,
|
||||
Armor.CT_Cromwell_IV,
|
||||
Armor.HIT_Churchill_VII,
|
||||
# Mods
|
||||
frenchpack.DIM__TOYOTA_BLUE,
|
||||
frenchpack.DIM__TOYOTA_GREEN,
|
||||
frenchpack.DIM__TOYOTA_DESERT,
|
||||
frenchpack.DIM__KAMIKAZE,
|
||||
frenchpack.AMX_30B2,
|
||||
frenchpack.Leclerc_Serie_XXI,
|
||||
),
|
||||
)
|
||||
|
||||
Atgm = (
|
||||
"ATGM",
|
||||
(
|
||||
Armor.ATGM_HMMWV,
|
||||
Armor.ATGM_VAB_Mephisto,
|
||||
Armor.ATGM_Stryker,
|
||||
Armor.IFV_BMP_2,
|
||||
# WW2 (Tank Destroyers)
|
||||
# Axxis
|
||||
Armor.SPG_StuG_III_Ausf__G,
|
||||
Armor.SPG_StuG_IV,
|
||||
Armor.SPG_Jagdpanzer_IV,
|
||||
Armor.SPG_Jagdpanther_G1,
|
||||
Armor.SPG_Sd_Kfz_184_Elefant,
|
||||
# Allies
|
||||
Armor.SPG_M10_GMC,
|
||||
Armor.MT_M4A4_Sherman_Firefly,
|
||||
# Mods
|
||||
frenchpack.VBAE_CRAB_MMP,
|
||||
frenchpack.VAB_MEPHISTO,
|
||||
frenchpack.TRM_2000_PAMELA,
|
||||
),
|
||||
)
|
||||
|
||||
Ifv = (
|
||||
"IFV",
|
||||
(
|
||||
Armor.IFV_BMP_3,
|
||||
Armor.IFV_BMP_2,
|
||||
Armor.IFV_BMP_1,
|
||||
Armor.IFV_Marder,
|
||||
Armor.IFV_Warrior,
|
||||
Armor.SPG_Stryker_MGS,
|
||||
Armor.IFV_M2A2_Bradley,
|
||||
Armor.IFV_BMD_1,
|
||||
Armor.ZBD_04A,
|
||||
# Mods
|
||||
frenchpack.VBAE_CRAB,
|
||||
frenchpack.VAB_T20_13,
|
||||
),
|
||||
)
|
||||
|
||||
Apc = (
|
||||
"APC",
|
||||
(
|
||||
Armor.IFV_M1126_Stryker_ICV,
|
||||
Armor.APC_M113,
|
||||
Armor.APC_BTR_80,
|
||||
Armor.IFV_BTR_82A,
|
||||
Armor.APC_MTLB,
|
||||
Armor.APC_AAV_7_Amphibious,
|
||||
Armor.APC_TPz_Fuchs,
|
||||
Armor.APC_BTR_RD,
|
||||
# WW2
|
||||
Armor.APC_M2A1_Halftrack,
|
||||
Armor.APC_Sd_Kfz_251_Halftrack,
|
||||
# Mods
|
||||
frenchpack.VAB__50,
|
||||
frenchpack.VBL__50,
|
||||
frenchpack.VBL_AANF1,
|
||||
),
|
||||
)
|
||||
|
||||
Artillery = (
|
||||
"Artillery",
|
||||
(
|
||||
Artillery.Grad_MRL_FDDM__FC,
|
||||
Artillery.MLRS_9A52_Smerch_HE_300mm,
|
||||
Artillery.SPH_2S1_Gvozdika_122mm,
|
||||
Artillery.SPH_2S3_Akatsia_152mm,
|
||||
Artillery.MLRS_BM_21_Grad_122mm,
|
||||
Artillery.MLRS_9K57_Uragan_BM_27_220mm,
|
||||
Artillery.SPH_M109_Paladin_155mm,
|
||||
Artillery.MLRS_M270_227mm,
|
||||
Artillery.SPM_2S9_Nona_120mm_M,
|
||||
Artillery.SPH_Dana_vz77_152mm,
|
||||
Artillery.SPH_T155_Firtina_155mm,
|
||||
Artillery.PLZ_05,
|
||||
Artillery.SPH_2S19_Msta_152mm,
|
||||
Artillery.MLRS_9A52_Smerch_CM_300mm,
|
||||
# WW2
|
||||
Artillery.SPG_M12_GMC_155mm,
|
||||
),
|
||||
)
|
||||
|
||||
Logistics = (
|
||||
"Logistics",
|
||||
(
|
||||
Unarmed.Carrier_M30_Cargo,
|
||||
Unarmed.Truck_M818_6x6,
|
||||
Unarmed.Truck_KAMAZ_43101,
|
||||
Unarmed.Truck_Ural_375,
|
||||
Unarmed.Truck_GAZ_66,
|
||||
Unarmed.Truck_GAZ_3307,
|
||||
Unarmed.Truck_GAZ_3308,
|
||||
Unarmed.Truck_Ural_4320_31_Arm_d,
|
||||
Unarmed.Truck_Ural_4320T,
|
||||
Unarmed.Truck_Opel_Blitz,
|
||||
Unarmed.LUV_Kubelwagen_82,
|
||||
Unarmed.Carrier_Sd_Kfz_7_Tractor,
|
||||
Unarmed.LUV_Kettenrad,
|
||||
Unarmed.Car_Willys_Jeep,
|
||||
Unarmed.LUV_Land_Rover_109,
|
||||
Unarmed.Truck_Land_Rover_101_FC,
|
||||
# Mods
|
||||
frenchpack.VBL,
|
||||
frenchpack.VAB,
|
||||
),
|
||||
)
|
||||
|
||||
Recon = (
|
||||
"Recon",
|
||||
(
|
||||
Armor.Scout_HMMWV,
|
||||
Armor.Scout_Cobra,
|
||||
Armor.LT_PT_76,
|
||||
Armor.IFV_LAV_25,
|
||||
Armor.Scout_BRDM_2,
|
||||
# WW2
|
||||
Armor.LT_Mk_VII_Tetrarch,
|
||||
Armor.IFV_Sd_Kfz_234_2_Puma,
|
||||
Armor.Car_M8_Greyhound_Armored,
|
||||
Armor.Car_Daimler_Armored,
|
||||
# Mods
|
||||
frenchpack.ERC_90,
|
||||
frenchpack.AMX_10RCR,
|
||||
frenchpack.AMX_10RCR_SEPAR,
|
||||
),
|
||||
)
|
||||
|
||||
Infantry = (
|
||||
"Infantry",
|
||||
(
|
||||
Infantry.Insurgent_AK_74,
|
||||
Infantry.Infantry_AK_74,
|
||||
Infantry.Infantry_M1_Garand,
|
||||
Infantry.Infantry_Mauser_98,
|
||||
Infantry.Infantry_SMLE_No_4_Mk_1,
|
||||
Infantry.Infantry_M4_Georgia,
|
||||
Infantry.Infantry_AK_74_Rus,
|
||||
Infantry.Paratrooper_AKS,
|
||||
Infantry.Paratrooper_RPG_16,
|
||||
Infantry.Infantry_M249,
|
||||
Infantry.Infantry_M4,
|
||||
Infantry.Infantry_RPG,
|
||||
),
|
||||
)
|
||||
|
||||
Shorads = (
|
||||
"SHORADS",
|
||||
(
|
||||
AirDefence.SPAAA_ZU_23_2_Mounted_Ural_375,
|
||||
AirDefence.SPAAA_ZU_23_2_Insurgent_Mounted_Ural_375,
|
||||
AirDefence.SPAAA_ZSU_57_2,
|
||||
AirDefence.SPAAA_ZSU_23_4_Shilka_Gun_Dish,
|
||||
AirDefence.SAM_SA_8_Osa_Gecko_TEL,
|
||||
AirDefence.SAM_SA_9_Strela_1_Gaskin_TEL,
|
||||
AirDefence.SAM_SA_13_Strela_10M3_Gopher_TEL,
|
||||
AirDefence.SAM_SA_15_Tor_Gauntlet,
|
||||
AirDefence.SAM_SA_19_Tunguska_Grison,
|
||||
AirDefence.SPAAA_Gepard,
|
||||
AirDefence.SPAAA_Vulcan_M163,
|
||||
AirDefence.SAM_Linebacker___Bradley_M6,
|
||||
AirDefence.SAM_Chaparral_M48,
|
||||
AirDefence.SAM_Avenger__Stinger,
|
||||
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,
|
||||
AirDefence.AAA_8_8cm_Flak_41,
|
||||
AirDefence.AAA_Bofors_40mm,
|
||||
AirDefence.AAA_S_60_57mm,
|
||||
AirDefence.AAA_M1_37mm,
|
||||
AirDefence.AAA_QF_3_7,
|
||||
),
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self, class_name: str, unit_list: tuple[Type[VehicleType], ...]
|
||||
) -> None:
|
||||
self.class_name = class_name
|
||||
self.unit_list = unit_list
|
||||
|
||||
def __contains__(self, unit_type: Type[VehicleType]) -> bool:
|
||||
return unit_type in self.unit_list
|
||||
Tank = "Tank"
|
||||
Atgm = "ATGM"
|
||||
Ifv = "IFV"
|
||||
Apc = "APC"
|
||||
Artillery = "Artillery"
|
||||
Logistics = "Logistics"
|
||||
Recon = "Recon"
|
||||
Infantry = "Infantry"
|
||||
Shorads = "SHORADS"
|
||||
Manpads = "MANPADS"
|
||||
|
||||
391
game/db.py
391
game/db.py
@@ -1,8 +1,7 @@
|
||||
import json
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
from typing import List, Optional, Type, Union
|
||||
from typing import Optional, Type, Union
|
||||
|
||||
from dcs.countries import country_dict
|
||||
from dcs.helicopters import (
|
||||
@@ -21,8 +20,6 @@ from dcs.planes import (
|
||||
plane_map,
|
||||
)
|
||||
from dcs.ships import (
|
||||
Boat_Armed_Hi_speed,
|
||||
Bulker_Yakushev,
|
||||
CVN_71_Theodore_Roosevelt,
|
||||
CVN_72_Abraham_Lincoln,
|
||||
CVN_73_George_Washington,
|
||||
@@ -30,21 +27,12 @@ from dcs.ships import (
|
||||
CVN_75_Harry_S__Truman,
|
||||
CV_1143_5_Admiral_Kuznetsov,
|
||||
CV_1143_5_Admiral_Kuznetsov_2017,
|
||||
Cargo_Ivanov,
|
||||
LHA_1_Tarawa,
|
||||
Tanker_Elnya_160,
|
||||
ship_map,
|
||||
)
|
||||
from dcs.terrain.terrain import Airport
|
||||
from dcs.unit import Ship, Unit, Vehicle
|
||||
from dcs.unitgroup import ShipGroup, StaticGroup
|
||||
from dcs.unittype import UnitType, VehicleType
|
||||
from dcs.unittype import UnitType
|
||||
from dcs.vehicles import (
|
||||
AirDefence,
|
||||
Armor,
|
||||
Artillery,
|
||||
Infantry,
|
||||
Unarmed,
|
||||
vehicle_map,
|
||||
)
|
||||
|
||||
@@ -250,271 +238,6 @@ For example, player accessible Hornet is called `FA_18C_hornet`, and MANPAD Igla
|
||||
# to be cheap enough to repair with a single turn's income.
|
||||
RUNWAY_REPAIR_COST = 100
|
||||
|
||||
"""
|
||||
Prices for the aircraft.
|
||||
This defines both price for the player (although only aircraft listed in CAP/CAS/Transport/Armor/AirDefense roles will be purchasable)
|
||||
and prioritization for the enemy (i.e. less important bases will receive units with lower price)
|
||||
"""
|
||||
PRICES = {
|
||||
# armor
|
||||
Armor.APC_MTLB: 4,
|
||||
Artillery.Grad_MRL_FDDM__FC: 4,
|
||||
Armor.Scout_BRDM_2: 6,
|
||||
Armor.APC_BTR_RD: 6,
|
||||
Armor.APC_BTR_80: 8,
|
||||
Armor.IFV_BTR_82A: 10,
|
||||
Armor.MBT_T_55: 18,
|
||||
Armor.MBT_T_72B: 20,
|
||||
Armor.MBT_T_72B3: 25,
|
||||
Armor.MBT_T_80U: 25,
|
||||
Armor.MBT_T_90: 30,
|
||||
Armor.IFV_BMD_1: 8,
|
||||
Armor.IFV_BMP_1: 14,
|
||||
Armor.IFV_BMP_2: 16,
|
||||
Armor.IFV_BMP_3: 18,
|
||||
Armor.LT_PT_76: 9,
|
||||
Armor.ZBD_04A: 12,
|
||||
Armor.ZTZ_96B: 30,
|
||||
Armor.Scout_Cobra: 4,
|
||||
Armor.APC_M113: 6,
|
||||
Armor.Scout_HMMWV: 2,
|
||||
Armor.ATGM_HMMWV: 8,
|
||||
Armor.ATGM_VAB_Mephisto: 12,
|
||||
Armor.IFV_M2A2_Bradley: 12,
|
||||
Armor.IFV_M1126_Stryker_ICV: 10,
|
||||
Armor.SPG_Stryker_MGS: 14,
|
||||
Armor.ATGM_Stryker: 12,
|
||||
Armor.MBT_M60A3_Patton: 16,
|
||||
Armor.MBT_M1A2_Abrams: 25,
|
||||
Armor.MBT_Leclerc: 25,
|
||||
Armor.MBT_Leopard_1A3: 18,
|
||||
Armor.MBT_Leopard_2A4: 20,
|
||||
Armor.MBT_Leopard_2A4_Trs: 20,
|
||||
Armor.MBT_Leopard_2A5: 22,
|
||||
Armor.MBT_Leopard_2A6M: 25,
|
||||
Armor.MBT_Merkava_IV: 25,
|
||||
Armor.APC_TPz_Fuchs: 5,
|
||||
Armor.MBT_Challenger_II: 25,
|
||||
Armor.MBT_Chieftain_Mk_3: 20,
|
||||
Armor.IFV_Marder: 10,
|
||||
Armor.IFV_Warrior: 10,
|
||||
Armor.IFV_LAV_25: 7,
|
||||
Armor.APC_AAV_7_Amphibious: 10,
|
||||
Artillery.MLRS_M270_227mm: 55,
|
||||
Artillery.SPH_M109_Paladin_155mm: 25,
|
||||
Artillery.SPM_2S9_Nona_120mm_M: 12,
|
||||
Artillery.SPH_2S1_Gvozdika_122mm: 18,
|
||||
Artillery.SPH_2S3_Akatsia_152mm: 24,
|
||||
Artillery.SPH_2S19_Msta_152mm: 30,
|
||||
Artillery.MLRS_BM_21_Grad_122mm: 15,
|
||||
Artillery.MLRS_9K57_Uragan_BM_27_220mm: 50,
|
||||
Artillery.MLRS_9A52_Smerch_HE_300mm: 40,
|
||||
Artillery.Mortar_2B11_120mm: 4,
|
||||
Artillery.SPH_Dana_vz77_152mm: 26,
|
||||
Artillery.PLZ_05: 25,
|
||||
Artillery.SPH_T155_Firtina_155mm: 28,
|
||||
Artillery.MLRS_9A52_Smerch_CM_300mm: 60,
|
||||
Unarmed.LUV_UAZ_469_Jeep: 3,
|
||||
Unarmed.Truck_Ural_375: 3,
|
||||
Unarmed.Truck_GAZ_3307: 2,
|
||||
Infantry.Infantry_M4: 1,
|
||||
Infantry.Infantry_AK_74: 1,
|
||||
Unarmed.Truck_M818_6x6: 3,
|
||||
Unarmed.LUV_Land_Rover_109: 1,
|
||||
Unarmed.Truck_GAZ_3308: 1,
|
||||
Unarmed.Truck_GAZ_66: 1,
|
||||
Unarmed.Truck_KAMAZ_43101: 1,
|
||||
Unarmed.Truck_Land_Rover_101_FC: 1,
|
||||
Unarmed.Truck_Ural_4320_31_Arm_d: 1,
|
||||
Unarmed.Truck_Ural_4320T: 1,
|
||||
# WW2
|
||||
Armor.MT_Pz_Kpfw_V_Panther_Ausf_G: 24,
|
||||
Armor.Tk_PzIV_H: 16,
|
||||
Armor.HT_Pz_Kpfw_VI_Tiger_I: 24,
|
||||
Armor.HT_Pz_Kpfw_VI_Ausf__B_Tiger_II: 26,
|
||||
Armor.SPG_Jagdpanther_G1: 18,
|
||||
Armor.SPG_Jagdpanzer_IV: 11,
|
||||
Armor.SPG_Sd_Kfz_184_Elefant: 18,
|
||||
Armor.APC_Sd_Kfz_251_Halftrack: 4,
|
||||
Armor.IFV_Sd_Kfz_234_2_Puma: 8,
|
||||
Armor.Tk_M4_Sherman: 12,
|
||||
Armor.MT_M4A4_Sherman_Firefly: 16,
|
||||
Armor.CT_Cromwell_IV: 12,
|
||||
Unarmed.Carrier_M30_Cargo: 2,
|
||||
Armor.APC_M2A1_Halftrack: 4,
|
||||
Armor.CT_Centaur_IV: 10,
|
||||
Armor.HIT_Churchill_VII: 16,
|
||||
Armor.Car_M8_Greyhound_Armored: 8,
|
||||
Armor.SPG_M10_GMC: 14,
|
||||
Armor.SPG_StuG_III_Ausf__G: 12,
|
||||
Armor.SPG_StuG_IV: 14,
|
||||
Artillery.SPG_M12_GMC_155mm: 10,
|
||||
Armor.SPG_Sturmpanzer_IV_Brummbar: 10,
|
||||
Armor.Car_Daimler_Armored: 8,
|
||||
Armor.LT_Mk_VII_Tetrarch: 8,
|
||||
Unarmed.Tractor_M4_Hi_Speed: 2,
|
||||
Unarmed.Carrier_Sd_Kfz_7_Tractor: 1,
|
||||
Unarmed.LUV_Kettenrad: 1,
|
||||
Unarmed.LUV_Kubelwagen_82: 1,
|
||||
Unarmed.Truck_Opel_Blitz: 1,
|
||||
Unarmed.Truck_Bedford: 1,
|
||||
Unarmed.Truck_GMC_Jimmy_6x6_Truck: 1,
|
||||
Unarmed.Car_Willys_Jeep: 1,
|
||||
# ship
|
||||
CV_1143_5_Admiral_Kuznetsov: 100,
|
||||
CVN_74_John_C__Stennis: 100,
|
||||
LHA_1_Tarawa: 50,
|
||||
Bulker_Yakushev: 10,
|
||||
Boat_Armed_Hi_speed: 10,
|
||||
Cargo_Ivanov: 10,
|
||||
Tanker_Elnya_160: 10,
|
||||
# Air Defence units
|
||||
AirDefence.SAM_SA_19_Tunguska_Grison: 30,
|
||||
AirDefence.SAM_SA_6_Kub_Gainful_TEL: 20,
|
||||
AirDefence.SAM_SA_3_S_125_Goa_LN: 6,
|
||||
AirDefence.SAM_SA_11_Buk_Gadfly_Fire_Dome_TEL: 30,
|
||||
AirDefence.SAM_SA_11_Buk_Gadfly_C2: 25,
|
||||
AirDefence.SAM_SA_11_Buk_Gadfly_Snow_Drift_SR: 28,
|
||||
AirDefence.SAM_SA_8_Osa_Gecko_TEL: 28,
|
||||
AirDefence.SAM_SA_15_Tor_Gauntlet: 40,
|
||||
AirDefence.SAM_SA_13_Strela_10M3_Gopher_TEL: 16,
|
||||
AirDefence.SAM_SA_9_Strela_1_Gaskin_TEL: 12,
|
||||
AirDefence.SAM_SA_8_Osa_LD_9T217: 22,
|
||||
AirDefence.SAM_Patriot_CR__AMG_AN_MRC_137: 35,
|
||||
AirDefence.SAM_Patriot_ECS: 30,
|
||||
AirDefence.SPAAA_Gepard: 24,
|
||||
AirDefence.SAM_Hawk_Platoon_Command_Post__PCP: 14,
|
||||
AirDefence.SPAAA_Vulcan_M163: 10,
|
||||
AirDefence.SAM_Hawk_LN_M192: 8,
|
||||
AirDefence.SAM_Chaparral_M48: 16,
|
||||
AirDefence.SAM_Linebacker___Bradley_M6: 18,
|
||||
AirDefence.SAM_Patriot_LN: 15,
|
||||
AirDefence.SAM_Avenger__Stinger: 20,
|
||||
AirDefence.SAM_Patriot_EPP_III: 15,
|
||||
AirDefence.SAM_Patriot_C2_ICC: 18,
|
||||
AirDefence.SAM_Roland_ADS: 12,
|
||||
AirDefence.MANPADS_Stinger: 6,
|
||||
AirDefence.MANPADS_Stinger_C2_Desert: 4,
|
||||
AirDefence.MANPADS_Stinger_C2: 4,
|
||||
AirDefence.SPAAA_ZSU_23_4_Shilka_Gun_Dish: 10,
|
||||
AirDefence.SPAAA_ZSU_57_2: 12,
|
||||
AirDefence.AAA_ZU_23_Closed_Emplacement: 6,
|
||||
AirDefence.AAA_ZU_23_Emplacement: 6,
|
||||
AirDefence.SPAAA_ZU_23_2_Mounted_Ural_375: 7,
|
||||
AirDefence.AAA_ZU_23_Insurgent_Closed_Emplacement: 6,
|
||||
AirDefence.SPAAA_ZU_23_2_Insurgent_Mounted_Ural_375: 7,
|
||||
AirDefence.AAA_ZU_23_Insurgent_Emplacement: 6,
|
||||
AirDefence.MANPADS_SA_18_Igla_Grouse: 10,
|
||||
AirDefence.MANPADS_SA_18_Igla_Grouse_C2: 8,
|
||||
AirDefence.MANPADS_SA_18_Igla_S_Grouse: 12,
|
||||
AirDefence.MANPADS_SA_18_Igla_S_Grouse_C2: 8,
|
||||
AirDefence.EWR_1L13: 30,
|
||||
AirDefence.SAM_SA_6_Kub_Straight_Flush_STR: 22,
|
||||
AirDefence.EWR_55G6: 30,
|
||||
AirDefence.MCC_SR_Sborka_Dog_Ear_SR: 10,
|
||||
AirDefence.SAM_Hawk_TR__AN_MPQ_46: 14,
|
||||
AirDefence.SAM_Hawk_SR__AN_MPQ_50: 18,
|
||||
AirDefence.SAM_Patriot_STR: 22,
|
||||
AirDefence.SAM_Hawk_CWAR_AN_MPQ_55: 20,
|
||||
AirDefence.SAM_P19_Flat_Face_SR__SA_2_3: 14,
|
||||
AirDefence.SAM_Roland_EWR: 16,
|
||||
AirDefence.SAM_SA_3_S_125_Low_Blow_TR: 14,
|
||||
AirDefence.SAM_SA_2_S_75_Guideline_LN: 8,
|
||||
AirDefence.SAM_SA_2_S_75_Fan_Song_TR: 12,
|
||||
AirDefence.SAM_Rapier_LN: 6,
|
||||
AirDefence.SAM_Rapier_Tracker: 6,
|
||||
AirDefence.SAM_Rapier_Blindfire_TR: 8,
|
||||
AirDefence.HQ_7_Self_Propelled_LN: 20,
|
||||
AirDefence.HQ_7_Self_Propelled_STR: 24,
|
||||
AirDefence.AAA_8_8cm_Flak_18: 6,
|
||||
AirDefence.AAA_Flak_38_20mm: 6,
|
||||
AirDefence.AAA_8_8cm_Flak_36: 8,
|
||||
AirDefence.AAA_8_8cm_Flak_37: 9,
|
||||
AirDefence.AAA_Flak_Vierling_38_Quad_20mm: 5,
|
||||
AirDefence.AAA_SP_Kdo_G_40: 8,
|
||||
AirDefence.SL_Flakscheinwerfer_37: 4,
|
||||
AirDefence.PU_Maschinensatz_33: 10,
|
||||
AirDefence.AAA_8_8cm_Flak_41: 10,
|
||||
AirDefence.EWR_FuMG_401_Freya_LZ: 25,
|
||||
AirDefence.AAA_Bofors_40mm: 8,
|
||||
AirDefence.AAA_S_60_57mm: 8,
|
||||
AirDefence.AAA_M1_37mm: 7,
|
||||
AirDefence.AAA_M45_Quadmount_HB_12_7mm: 4,
|
||||
AirDefence.AAA_QF_3_7: 10,
|
||||
# FRENCH PACK MOD
|
||||
frenchpack.AMX_10RCR: 10,
|
||||
frenchpack.AMX_10RCR_SEPAR: 12,
|
||||
frenchpack.ERC_90: 12,
|
||||
frenchpack.MO_120_RT: 10,
|
||||
frenchpack._53T2: 4,
|
||||
frenchpack.TRM_2000: 4,
|
||||
frenchpack.TRM_2000_Fuel: 4,
|
||||
frenchpack.TRM_2000_53T2: 8,
|
||||
frenchpack.TRM_2000_PAMELA: 14,
|
||||
frenchpack.VAB_MEDICAL: 8,
|
||||
frenchpack.VAB: 6,
|
||||
frenchpack.VAB__50: 4,
|
||||
frenchpack.VAB_T20_13: 6,
|
||||
frenchpack.VAB_MEPHISTO: 8,
|
||||
frenchpack.VAB_MORTIER: 10,
|
||||
frenchpack.VBL__50: 4,
|
||||
frenchpack.VBL_AANF1: 2,
|
||||
frenchpack.VBL: 1,
|
||||
frenchpack.VBAE_CRAB: 8,
|
||||
frenchpack.VBAE_CRAB_MMP: 12,
|
||||
frenchpack.AMX_30B2: 18,
|
||||
frenchpack.Tracma_TD_1500: 2,
|
||||
frenchpack.Infantry_Soldier_JTAC: 1,
|
||||
frenchpack.Leclerc_Serie_XXI: 35,
|
||||
frenchpack.DIM__TOYOTA_BLUE: 2,
|
||||
frenchpack.DIM__TOYOTA_GREEN: 2,
|
||||
frenchpack.DIM__TOYOTA_DESERT: 2,
|
||||
frenchpack.DIM__KAMIKAZE: 6,
|
||||
# SA-10
|
||||
AirDefence.SAM_SA_10_S_300_Grumble_C2: 18,
|
||||
AirDefence.SAM_SA_10_S_300_Grumble_Flap_Lid_TR: 24,
|
||||
AirDefence.SAM_SA_10_S_300_Grumble_Clam_Shell_SR: 30,
|
||||
AirDefence.SAM_SA_10_S_300_Grumble_Big_Bird_SR: 30,
|
||||
AirDefence.SAM_SA_10_S_300_Grumble_TEL_C: 22,
|
||||
AirDefence.SAM_SA_10_S_300_Grumble_TEL_D: 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,
|
||||
highdigitsams.SAM_SA_10__5V55RUD__S_300PS_LN_5P85CE: 24,
|
||||
highdigitsams.SAM_SA_10__5V55RUD__S_300PS_LN_5P85DE: 24,
|
||||
highdigitsams.SAM_SA_10B_S_300PS_30N6_TR: 26,
|
||||
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,
|
||||
highdigitsams.SAM_SA_20_S_300PMU1_SR_5N66E: 38,
|
||||
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,
|
||||
}
|
||||
|
||||
"""
|
||||
Units separated by country.
|
||||
country : DCS Country name
|
||||
@@ -620,107 +343,6 @@ def upgrade_to_supercarrier(unit, name: str):
|
||||
return unit
|
||||
|
||||
|
||||
MANPADS: List[Type[VehicleType]] = [
|
||||
AirDefence.MANPADS_SA_18_Igla_Grouse,
|
||||
AirDefence.MANPADS_SA_18_Igla_S_Grouse,
|
||||
AirDefence.MANPADS_Stinger,
|
||||
]
|
||||
|
||||
INFANTRY: List[VehicleType] = [
|
||||
Infantry.Paratrooper_AKS,
|
||||
Infantry.Paratrooper_AKS,
|
||||
Infantry.Paratrooper_AKS,
|
||||
Infantry.Paratrooper_AKS,
|
||||
Infantry.Paratrooper_AKS,
|
||||
Infantry.Infantry_RPG,
|
||||
Infantry.Infantry_M4,
|
||||
Infantry.Infantry_M4,
|
||||
Infantry.Infantry_M4,
|
||||
Infantry.Infantry_M4,
|
||||
Infantry.Infantry_M4,
|
||||
Infantry.Infantry_M249,
|
||||
Artillery.Mortar_2B11_120mm,
|
||||
Infantry.Infantry_AK_74,
|
||||
Infantry.Infantry_AK_74,
|
||||
Infantry.Infantry_AK_74,
|
||||
Infantry.Infantry_AK_74,
|
||||
Infantry.Infantry_AK_74,
|
||||
Infantry.Paratrooper_RPG_16,
|
||||
Infantry.Infantry_M4_Georgia,
|
||||
Infantry.Infantry_M4_Georgia,
|
||||
Infantry.Infantry_M4_Georgia,
|
||||
Infantry.Infantry_M4_Georgia,
|
||||
Infantry.Infantry_AK_74_Rus,
|
||||
Infantry.Infantry_AK_74_Rus,
|
||||
Infantry.Infantry_AK_74_Rus,
|
||||
Infantry.Infantry_AK_74_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_Mauser_98,
|
||||
Infantry.Infantry_M1_Garand,
|
||||
Infantry.Infantry_M1_Garand,
|
||||
Infantry.Infantry_M1_Garand,
|
||||
Infantry.Insurgent_AK_74,
|
||||
Infantry.Insurgent_AK_74,
|
||||
Infantry.Insurgent_AK_74,
|
||||
]
|
||||
|
||||
|
||||
def find_manpad(country_name: str) -> List[VehicleType]:
|
||||
return [x for x in MANPADS if x in FACTIONS[country_name].infantry_units]
|
||||
|
||||
|
||||
def find_infantry(country_name: str, allow_manpad: bool = False) -> List[VehicleType]:
|
||||
if allow_manpad:
|
||||
inf = INFANTRY + MANPADS
|
||||
else:
|
||||
inf = INFANTRY
|
||||
return [x for x in inf if x in FACTIONS[country_name].infantry_units]
|
||||
|
||||
|
||||
def unit_type_name(unit_type) -> str:
|
||||
return unit_type.id and unit_type.id or unit_type.name
|
||||
|
||||
|
||||
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: Type[UnitType], request_type: str
|
||||
) -> str:
|
||||
original_name = unit_type.name and unit_type.name or unit_type.id
|
||||
default_value = None
|
||||
faction_value = None
|
||||
with UNITINFOTEXT_PATH.open("r", encoding="utf-8") as fdata:
|
||||
data = json.load(fdata)
|
||||
type_exists = data.get(unit_type.id)
|
||||
if type_exists is not None:
|
||||
for faction in type_exists:
|
||||
if default_value is None:
|
||||
default_exists = faction.get("default")
|
||||
if default_exists is not None:
|
||||
default_value = default_exists.get(request_type)
|
||||
if faction_value is None:
|
||||
faction_exists = faction.get(country_name)
|
||||
if faction_exists is not None:
|
||||
faction_value = faction_exists.get(request_type)
|
||||
if default_value is None:
|
||||
if request_type == "text":
|
||||
return "WIP - This unit doesn't have any description text yet."
|
||||
if request_type == "name":
|
||||
return original_name
|
||||
else:
|
||||
return "Unknown"
|
||||
if faction_value is None:
|
||||
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]
|
||||
@@ -734,15 +356,6 @@ def unit_type_from_name(name: str) -> Optional[Type[UnitType]]:
|
||||
return None
|
||||
|
||||
|
||||
def unit_type_of(unit: Unit) -> UnitType:
|
||||
if isinstance(unit, Vehicle):
|
||||
return vehicle_map[unit.type]
|
||||
elif isinstance(unit, Ship):
|
||||
return ship_map[unit.type]
|
||||
else:
|
||||
return unit.type
|
||||
|
||||
|
||||
def country_id_from_name(name):
|
||||
for k, v in country_dict.items():
|
||||
if v.name == name:
|
||||
|
||||
@@ -12,6 +12,7 @@ from dcs.helicopters import helicopter_map
|
||||
from dcs.planes import plane_map
|
||||
from dcs.unittype import FlyingType
|
||||
|
||||
from game.dcs.unittype import UnitType
|
||||
from game.radio.channels import (
|
||||
ChannelNamer,
|
||||
RadioChannelAllocator,
|
||||
@@ -90,15 +91,7 @@ class RadioConfig:
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AircraftType:
|
||||
dcs_unit_type: Type[FlyingType]
|
||||
name: str
|
||||
description: str
|
||||
year_introduced: str
|
||||
country_of_origin: str
|
||||
manufacturer: str
|
||||
role: str
|
||||
price: int
|
||||
class AircraftType(UnitType[FlyingType]):
|
||||
carrier_capable: bool
|
||||
lha_capable: bool
|
||||
always_keeps_gun: bool
|
||||
|
||||
95
game/dcs/groundunittype.py
Normal file
95
game/dcs/groundunittype.py
Normal file
@@ -0,0 +1,95 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Type, Optional, ClassVar, Iterator
|
||||
|
||||
import yaml
|
||||
from dcs.unittype import VehicleType
|
||||
from dcs.vehicles import vehicle_map
|
||||
|
||||
from game.data.groundunitclass import GroundUnitClass
|
||||
from game.dcs.unittype import UnitType
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class GroundUnitType(UnitType[VehicleType]):
|
||||
unit_class: Optional[GroundUnitClass]
|
||||
spawn_weight: int
|
||||
|
||||
_by_name: ClassVar[dict[str, GroundUnitType]] = {}
|
||||
_by_unit_type: ClassVar[
|
||||
dict[Type[VehicleType], list[GroundUnitType]]
|
||||
] = defaultdict(list)
|
||||
_loaded: ClassVar[bool] = False
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.name
|
||||
|
||||
@property
|
||||
def dcs_id(self) -> str:
|
||||
return self.dcs_unit_type.id
|
||||
|
||||
@classmethod
|
||||
def register(cls, aircraft_type: GroundUnitType) -> None:
|
||||
cls._by_name[aircraft_type.name] = aircraft_type
|
||||
cls._by_unit_type[aircraft_type.dcs_unit_type].append(aircraft_type)
|
||||
|
||||
@classmethod
|
||||
def named(cls, name: str) -> GroundUnitType:
|
||||
if not cls._loaded:
|
||||
cls._load_all()
|
||||
return cls._by_name[name]
|
||||
|
||||
@classmethod
|
||||
def for_dcs_type(cls, dcs_unit_type: Type[VehicleType]) -> Iterator[GroundUnitType]:
|
||||
yield from cls._by_unit_type[dcs_unit_type]
|
||||
|
||||
@staticmethod
|
||||
def _each_unit_type() -> Iterator[Type[VehicleType]]:
|
||||
yield from vehicle_map.values()
|
||||
|
||||
@classmethod
|
||||
def _load_all(cls) -> None:
|
||||
for unit_type in cls._each_unit_type():
|
||||
for data in cls._each_variant_of(unit_type):
|
||||
cls.register(data)
|
||||
cls._loaded = True
|
||||
|
||||
@classmethod
|
||||
def _each_variant_of(cls, vehicle: Type[VehicleType]) -> Iterator[GroundUnitType]:
|
||||
data_path = Path("resources/units/ground_units") / f"{vehicle.id}.yaml"
|
||||
if not data_path.exists():
|
||||
logging.warning(f"No data for {vehicle.id}; it will not be available")
|
||||
return
|
||||
|
||||
with data_path.open() as data_file:
|
||||
data = yaml.safe_load(data_file)
|
||||
|
||||
try:
|
||||
introduction = data["introduced"]
|
||||
if introduction is None:
|
||||
introduction = "N/A"
|
||||
except KeyError:
|
||||
introduction = "No data."
|
||||
|
||||
class_name = data.get("class")
|
||||
unit_class: Optional[GroundUnitClass] = None
|
||||
if class_name is not None:
|
||||
unit_class = GroundUnitClass(class_name)
|
||||
|
||||
for variant in data.get("variants", [vehicle.id]):
|
||||
yield GroundUnitType(
|
||||
dcs_unit_type=vehicle,
|
||||
unit_class=unit_class,
|
||||
spawn_weight=data.get("spawn_weight", 0),
|
||||
name=variant,
|
||||
description=data.get("description", "No data."),
|
||||
year_introduced=introduction,
|
||||
country_of_origin=data.get("origin", "No data."),
|
||||
manufacturer=data.get("manufacturer", "No data."),
|
||||
role=data.get("role", "No data."),
|
||||
price=data.get("price", 1),
|
||||
)
|
||||
21
game/dcs/unittype.py
Normal file
21
game/dcs/unittype.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import TypeVar, Generic, Type
|
||||
|
||||
from dcs.unittype import UnitType as DcsUnitType
|
||||
|
||||
DcsUnitTypeT = TypeVar("DcsUnitTypeT", bound=DcsUnitType)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UnitType(Generic[DcsUnitTypeT]):
|
||||
dcs_unit_type: Type[DcsUnitTypeT]
|
||||
name: str
|
||||
description: str
|
||||
year_introduced: str
|
||||
country_of_origin: str
|
||||
manufacturer: str
|
||||
role: str
|
||||
price: int
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.name
|
||||
@@ -14,14 +14,12 @@ from typing import (
|
||||
Dict,
|
||||
Iterator,
|
||||
List,
|
||||
Type,
|
||||
TYPE_CHECKING,
|
||||
)
|
||||
|
||||
from dcs.unittype import UnitType
|
||||
|
||||
from game import db
|
||||
from game.dcs.aircrafttype import AircraftType
|
||||
from game.dcs.groundunittype import GroundUnitType
|
||||
from game.theater import Airfield, ControlPoint
|
||||
from game.transfers import CargoShip
|
||||
from game.unitmap import (
|
||||
@@ -183,8 +181,8 @@ class Debriefing:
|
||||
def casualty_count(self, control_point: ControlPoint) -> int:
|
||||
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]:
|
||||
losses_by_type: Dict[Type[UnitType], int] = defaultdict(int)
|
||||
def front_line_losses_by_type(self, player: bool) -> dict[GroundUnitType, int]:
|
||||
losses_by_type: dict[GroundUnitType, int] = defaultdict(int)
|
||||
if player:
|
||||
losses = self.ground_losses.player_front_line
|
||||
else:
|
||||
@@ -193,8 +191,8 @@ class Debriefing:
|
||||
losses_by_type[loss.unit_type] += 1
|
||||
return losses_by_type
|
||||
|
||||
def convoy_losses_by_type(self, player: bool) -> Dict[Type[UnitType], int]:
|
||||
losses_by_type: Dict[Type[UnitType], int] = defaultdict(int)
|
||||
def convoy_losses_by_type(self, player: bool) -> dict[GroundUnitType, int]:
|
||||
losses_by_type: dict[GroundUnitType, int] = defaultdict(int)
|
||||
if player:
|
||||
losses = self.ground_losses.player_convoy
|
||||
else:
|
||||
@@ -203,8 +201,8 @@ class Debriefing:
|
||||
losses_by_type[loss.unit_type] += 1
|
||||
return losses_by_type
|
||||
|
||||
def cargo_ship_losses_by_type(self, player: bool) -> Dict[Type[UnitType], int]:
|
||||
losses_by_type: Dict[Type[UnitType], int] = defaultdict(int)
|
||||
def cargo_ship_losses_by_type(self, player: bool) -> dict[GroundUnitType, int]:
|
||||
losses_by_type: dict[GroundUnitType, int] = defaultdict(int)
|
||||
if player:
|
||||
ships = self.ground_losses.player_cargo_ships
|
||||
else:
|
||||
@@ -214,8 +212,8 @@ class Debriefing:
|
||||
losses_by_type[unit_type] += count
|
||||
return losses_by_type
|
||||
|
||||
def airlift_losses_by_type(self, player: bool) -> Dict[Type[UnitType], int]:
|
||||
losses_by_type: Dict[Type[UnitType], int] = defaultdict(int)
|
||||
def airlift_losses_by_type(self, player: bool) -> dict[GroundUnitType, int]:
|
||||
losses_by_type: dict[GroundUnitType, int] = defaultdict(int)
|
||||
if player:
|
||||
losses = self.ground_losses.player_airlifts
|
||||
else:
|
||||
|
||||
@@ -14,6 +14,7 @@ from game.operation.operation import Operation
|
||||
from game.theater import ControlPoint
|
||||
from gen import AirTaskingOrder
|
||||
from gen.ground_forces.combat_stance import CombatStance
|
||||
from ..dcs.groundunittype import GroundUnitType
|
||||
from ..unitmap import UnitMap
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -439,7 +440,7 @@ class Event:
|
||||
|
||||
# Also transfer pending deliveries.
|
||||
for unit_type, count in source.pending_unit_deliveries.units.items():
|
||||
if not issubclass(unit_type, VehicleType):
|
||||
if not isinstance(unit_type, GroundUnitType):
|
||||
continue
|
||||
if count <= 0:
|
||||
# Don't transfer *sales*...
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import itertools
|
||||
import logging
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Optional, Dict, Type, List, Any, cast, Iterator
|
||||
from typing import Optional, Dict, Type, List, Any, Iterator
|
||||
|
||||
import dcs
|
||||
from dcs.countries import country_dict
|
||||
from dcs.planes import plane_map
|
||||
from dcs.unittype import FlyingType, ShipType, VehicleType, UnitType
|
||||
from dcs.vehicles import Armor, Unarmed, Infantry, Artillery, AirDefence
|
||||
from dcs.unittype import ShipType, UnitType
|
||||
|
||||
from game.data.building_data import (
|
||||
WW2_ALLIES_BUILDINGS,
|
||||
@@ -24,7 +23,7 @@ from game.data.doctrine import (
|
||||
)
|
||||
from game.data.groundunitclass import GroundUnitClass
|
||||
from game.dcs.aircrafttype import AircraftType
|
||||
from pydcs_extensions.mod_units import MODDED_VEHICLES
|
||||
from game.dcs.groundunittype import GroundUnitType
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -55,16 +54,16 @@ class Faction:
|
||||
tankers: List[AircraftType] = field(default_factory=list)
|
||||
|
||||
# Available frontline units
|
||||
frontline_units: List[Type[VehicleType]] = field(default_factory=list)
|
||||
frontline_units: List[GroundUnitType] = field(default_factory=list)
|
||||
|
||||
# Available artillery units
|
||||
artillery_units: List[Type[VehicleType]] = field(default_factory=list)
|
||||
artillery_units: List[GroundUnitType] = field(default_factory=list)
|
||||
|
||||
# Infantry units used
|
||||
infantry_units: List[Type[VehicleType]] = field(default_factory=list)
|
||||
infantry_units: List[GroundUnitType] = field(default_factory=list)
|
||||
|
||||
# Logistics units used
|
||||
logistics_units: List[Type[VehicleType]] = field(default_factory=list)
|
||||
logistics_units: List[GroundUnitType] = field(default_factory=list)
|
||||
|
||||
# Possible SAMS site generators for this faction
|
||||
air_defenses: List[str] = field(default_factory=list)
|
||||
@@ -135,15 +134,11 @@ class Faction:
|
||||
#: both will use it.
|
||||
unrestricted_satnav: bool = False
|
||||
|
||||
def has_access_to_unittype(self, unitclass: GroundUnitClass) -> bool:
|
||||
has_access = False
|
||||
for vehicle in unitclass.unit_list:
|
||||
if vehicle in self.frontline_units:
|
||||
def has_access_to_unittype(self, unit_class: GroundUnitClass) -> bool:
|
||||
for vehicle in itertools.chain(self.frontline_units, self.artillery_units):
|
||||
if vehicle.unit_class is unit_class:
|
||||
return True
|
||||
if vehicle in self.artillery_units:
|
||||
return True
|
||||
|
||||
return has_access
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def from_json(cls: Type[Faction], json: Dict[str, Any]) -> Faction:
|
||||
@@ -172,10 +167,18 @@ class Faction:
|
||||
set(faction.aircrafts + faction.awacs + faction.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 = [
|
||||
GroundUnitType.named(n) for n in json.get("frontline_units", [])
|
||||
]
|
||||
faction.artillery_units = [
|
||||
GroundUnitType.named(n) for n in json.get("artillery_units", [])
|
||||
]
|
||||
faction.infantry_units = [
|
||||
GroundUnitType.named(n) for n in json.get("infantry_units", [])
|
||||
]
|
||||
faction.logistics_units = [
|
||||
GroundUnitType.named(n) for n in json.get("logistics_units", [])
|
||||
]
|
||||
|
||||
faction.ewrs = json.get("ewrs", [])
|
||||
|
||||
@@ -242,55 +245,24 @@ class Faction:
|
||||
return faction
|
||||
|
||||
@property
|
||||
def ground_units(self) -> Iterator[Type[VehicleType]]:
|
||||
def ground_units(self) -> Iterator[GroundUnitType]:
|
||||
yield from self.artillery_units
|
||||
yield from self.frontline_units
|
||||
yield from self.logistics_units
|
||||
|
||||
|
||||
def unit_loader(unit: str, class_repository: List[Any]) -> Optional[Type[UnitType]]:
|
||||
"""
|
||||
Find unit by name
|
||||
:param unit: Unit name as string
|
||||
:param class_repository: Repository of classes (Either a module, a class, or a list of classes)
|
||||
:return: The unit as a PyDCS type
|
||||
"""
|
||||
if unit is None:
|
||||
return None
|
||||
elif unit in plane_map.keys():
|
||||
return plane_map[unit]
|
||||
else:
|
||||
for mother_class in class_repository:
|
||||
if getattr(mother_class, unit, None) is not None:
|
||||
return getattr(mother_class, unit)
|
||||
if type(mother_class) is list:
|
||||
for m in mother_class:
|
||||
if m.__name__ == unit:
|
||||
return m
|
||||
logging.error(f"FACTION ERROR : Unable to find {unit} in pydcs")
|
||||
return None
|
||||
|
||||
|
||||
def load_vehicle(name: str) -> Optional[Type[VehicleType]]:
|
||||
return cast(
|
||||
Optional[FlyingType],
|
||||
unit_loader(
|
||||
name, [Infantry, Unarmed, Armor, AirDefence, Artillery, MODDED_VEHICLES]
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def load_all_vehicles(data) -> List[Type[VehicleType]]:
|
||||
items = []
|
||||
for name in data:
|
||||
item = load_vehicle(name)
|
||||
if item is not None:
|
||||
items.append(item)
|
||||
return items
|
||||
def infantry_with_class(
|
||||
self, unit_class: GroundUnitClass
|
||||
) -> Iterator[GroundUnitType]:
|
||||
for unit in self.infantry_units:
|
||||
if unit.unit_class is unit_class:
|
||||
yield unit
|
||||
|
||||
|
||||
def load_ship(name: str) -> Optional[Type[ShipType]]:
|
||||
return cast(Optional[FlyingType], unit_loader(name, [dcs.ships]))
|
||||
if (ship := getattr(dcs.ships, name, None)) is not None:
|
||||
return ship
|
||||
logging.error(f"FACTION ERROR : Unable to find {name} in dcs.ships")
|
||||
return None
|
||||
|
||||
|
||||
def load_all_ships(data) -> List[Type[ShipType]]:
|
||||
|
||||
@@ -3,13 +3,12 @@ from __future__ import annotations
|
||||
import math
|
||||
import random
|
||||
from dataclasses import dataclass
|
||||
from typing import Iterator, List, Optional, TYPE_CHECKING, Tuple, Type
|
||||
|
||||
from dcs.unittype import FlyingType, VehicleType
|
||||
from typing import Iterator, List, Optional, TYPE_CHECKING, Tuple
|
||||
|
||||
from game import db
|
||||
from game.data.groundunitclass import GroundUnitClass
|
||||
from game.dcs.aircrafttype import AircraftType
|
||||
from game.dcs.groundunittype import GroundUnitType
|
||||
from game.factions.faction import Faction
|
||||
from game.theater import ControlPoint, MissionTarget
|
||||
from game.utils import Distance
|
||||
@@ -148,17 +147,17 @@ class ProcurementAi:
|
||||
|
||||
def affordable_ground_unit_of_class(
|
||||
self, budget: float, unit_class: GroundUnitClass
|
||||
) -> Optional[Type[VehicleType]]:
|
||||
) -> Optional[GroundUnitType]:
|
||||
faction_units = set(self.faction.frontline_units) | set(
|
||||
self.faction.artillery_units
|
||||
)
|
||||
of_class = set(unit_class.unit_list) & faction_units
|
||||
of_class = {u for u in faction_units if u.unit_class is unit_class}
|
||||
|
||||
# faction has no access to needed unit type, take a random unit
|
||||
if not of_class:
|
||||
of_class = faction_units
|
||||
|
||||
affordable_units = [u for u in of_class if db.PRICES[u] <= budget]
|
||||
affordable_units = [u for u in of_class if u.price <= budget]
|
||||
if not affordable_units:
|
||||
return None
|
||||
return random.choice(affordable_units)
|
||||
@@ -180,7 +179,7 @@ class ProcurementAi:
|
||||
# Can't afford any more units.
|
||||
break
|
||||
|
||||
budget -= db.PRICES[unit]
|
||||
budget -= unit.price
|
||||
cp.pending_unit_deliveries.order({unit: 1})
|
||||
|
||||
return budget
|
||||
@@ -361,9 +360,9 @@ class ProcurementAi:
|
||||
class_cost = 0
|
||||
total_cost = 0
|
||||
for unit_type, count in allocations.all.items():
|
||||
cost = db.PRICES[unit_type] * count
|
||||
cost = unit_type.price * count
|
||||
total_cost += cost
|
||||
if unit_type in unit_class:
|
||||
if unit_type.unit_class is unit_class:
|
||||
class_cost += cost
|
||||
if not total_cost:
|
||||
return 0
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import itertools
|
||||
import logging
|
||||
import typing
|
||||
from typing import Dict, Type
|
||||
from typing import Any
|
||||
|
||||
from dcs.unittype import VehicleType
|
||||
|
||||
from game.db import PRICES
|
||||
from game.dcs.aircrafttype import AircraftType
|
||||
from game.dcs.groundunittype import GroundUnitType
|
||||
from game.dcs.unittype import UnitType
|
||||
|
||||
BASE_MAX_STRENGTH = 1
|
||||
BASE_MIN_STRENGTH = 0
|
||||
@@ -14,8 +12,8 @@ BASE_MIN_STRENGTH = 0
|
||||
|
||||
class Base:
|
||||
def __init__(self):
|
||||
self.aircraft: Dict[AircraftType, int] = {}
|
||||
self.armor: Dict[Type[VehicleType], int] = {}
|
||||
self.aircraft: dict[AircraftType, int] = {}
|
||||
self.armor: dict[GroundUnitType, int] = {}
|
||||
self.strength = 1
|
||||
|
||||
@property
|
||||
@@ -30,13 +28,10 @@ class Base:
|
||||
def total_armor_value(self) -> int:
|
||||
total = 0
|
||||
for unit_type, count in self.armor.items():
|
||||
try:
|
||||
total += PRICES[unit_type] * count
|
||||
except KeyError:
|
||||
logging.exception(f"No price found for {unit_type.id}")
|
||||
total += unit_type.price * count
|
||||
return total
|
||||
|
||||
def total_units_of_type(self, unit_type: typing.Any) -> int:
|
||||
def total_units_of_type(self, unit_type: UnitType) -> int:
|
||||
return sum(
|
||||
[
|
||||
c
|
||||
@@ -45,30 +40,25 @@ class Base:
|
||||
]
|
||||
)
|
||||
|
||||
def commission_units(self, units: typing.Dict[typing.Any, int]):
|
||||
def commission_units(self, units: dict[Any, int]):
|
||||
for unit_type, unit_count in units.items():
|
||||
if unit_count <= 0:
|
||||
continue
|
||||
|
||||
target_dict: dict[typing.Any, int]
|
||||
target_dict: dict[Any, int]
|
||||
if isinstance(unit_type, AircraftType):
|
||||
target_dict = self.aircraft
|
||||
elif issubclass(unit_type, VehicleType):
|
||||
elif isinstance(unit_type, GroundUnitType):
|
||||
target_dict = self.armor
|
||||
else:
|
||||
logging.error(
|
||||
f"Unexpected unit type of {unit_type}: "
|
||||
f"{unit_type.__module__}.{unit_type.__name__}"
|
||||
)
|
||||
logging.error(f"Unexpected unit type of {unit_type}")
|
||||
return
|
||||
|
||||
target_dict[unit_type] = target_dict.get(unit_type, 0) + unit_count
|
||||
|
||||
def commit_losses(self, units_lost: typing.Dict[typing.Any, int]):
|
||||
|
||||
def commit_losses(self, units_lost: dict[Any, int]):
|
||||
for unit_type, count in units_lost.items():
|
||||
|
||||
target_dict: dict[typing.Any, int]
|
||||
target_dict: dict[Any, int]
|
||||
if unit_type in self.aircraft:
|
||||
target_dict = self.aircraft
|
||||
elif unit_type in self.armor:
|
||||
|
||||
@@ -16,7 +16,6 @@ from typing import (
|
||||
Optional,
|
||||
Set,
|
||||
TYPE_CHECKING,
|
||||
Type,
|
||||
Union,
|
||||
Sequence,
|
||||
Iterable,
|
||||
@@ -32,7 +31,6 @@ from dcs.ships import (
|
||||
)
|
||||
from dcs.terrain.terrain import Airport, ParkingSlot
|
||||
from dcs.unit import Unit
|
||||
from dcs.unittype import VehicleType
|
||||
|
||||
from game import db
|
||||
from game.point_with_heading import PointWithHeading
|
||||
@@ -46,8 +44,8 @@ from .theatergroundobject import (
|
||||
GenericCarrierGroundObject,
|
||||
TheaterGroundObject,
|
||||
)
|
||||
from ..db import PRICES
|
||||
from ..dcs.aircrafttype import AircraftType
|
||||
from ..dcs.groundunittype import GroundUnitType
|
||||
from ..utils import nautical_miles
|
||||
from ..weather import Conditions
|
||||
|
||||
@@ -161,13 +159,13 @@ class AircraftAllocations:
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class GroundUnitAllocations:
|
||||
present: dict[Type[VehicleType], int]
|
||||
ordered: dict[Type[VehicleType], int]
|
||||
transferring: dict[Type[VehicleType], int]
|
||||
present: dict[GroundUnitType, int]
|
||||
ordered: dict[GroundUnitType, int]
|
||||
transferring: dict[GroundUnitType, int]
|
||||
|
||||
@property
|
||||
def all(self) -> dict[Type[VehicleType], int]:
|
||||
combined: dict[Type[VehicleType], int] = defaultdict(int)
|
||||
def all(self) -> dict[GroundUnitType, int]:
|
||||
combined: dict[GroundUnitType, int] = defaultdict(int)
|
||||
for unit_type, count in itertools.chain(
|
||||
self.present.items(), self.ordered.items(), self.transferring.items()
|
||||
):
|
||||
@@ -178,11 +176,11 @@ class GroundUnitAllocations:
|
||||
def total_value(self) -> int:
|
||||
total: int = 0
|
||||
for unit_type, count in self.present.items():
|
||||
total += PRICES[unit_type] * count
|
||||
total += unit_type.price * count
|
||||
for unit_type, count in self.ordered.items():
|
||||
total += PRICES[unit_type] * count
|
||||
total += unit_type.price * count
|
||||
for unit_type, count in self.transferring.items():
|
||||
total += PRICES[unit_type] * count
|
||||
total += unit_type.price * count
|
||||
|
||||
return total
|
||||
|
||||
@@ -697,10 +695,10 @@ class ControlPoint(MissionTarget, ABC):
|
||||
) -> GroundUnitAllocations:
|
||||
on_order = {}
|
||||
for unit_bought, count in self.pending_unit_deliveries.units.items():
|
||||
if type(unit_bought) == type and issubclass(unit_bought, VehicleType):
|
||||
if isinstance(unit_bought, GroundUnitType):
|
||||
on_order[unit_bought] = count
|
||||
|
||||
transferring: dict[Type[VehicleType], int] = defaultdict(int)
|
||||
transferring: dict[GroundUnitType, int] = defaultdict(int)
|
||||
for transfer in transfers:
|
||||
if transfer.destination == self:
|
||||
for unit_type, count in transfer.units.items():
|
||||
|
||||
@@ -12,15 +12,14 @@ from typing import (
|
||||
List,
|
||||
Optional,
|
||||
TYPE_CHECKING,
|
||||
Type,
|
||||
TypeVar,
|
||||
Sequence,
|
||||
)
|
||||
|
||||
from dcs.mapping import Point
|
||||
from dcs.unittype import VehicleType
|
||||
|
||||
from game.dcs.aircrafttype import AircraftType
|
||||
from game.dcs.groundunittype import GroundUnitType
|
||||
from game.procurement import AircraftProcurementRequest
|
||||
from game.squadrons import Squadron
|
||||
from game.theater import ControlPoint, MissionTarget
|
||||
@@ -73,7 +72,7 @@ class TransferOrder:
|
||||
player: bool = field(init=False)
|
||||
|
||||
#: The units being transferred.
|
||||
units: Dict[Type[VehicleType], int]
|
||||
units: Dict[GroundUnitType, int]
|
||||
|
||||
transport: Optional[Transport] = field(default=None)
|
||||
|
||||
@@ -90,7 +89,7 @@ class TransferOrder:
|
||||
def kill_all(self) -> None:
|
||||
self.units.clear()
|
||||
|
||||
def kill_unit(self, unit_type: Type[VehicleType]) -> None:
|
||||
def kill_unit(self, unit_type: GroundUnitType) -> None:
|
||||
if unit_type not in self.units or not self.units[unit_type]:
|
||||
raise KeyError(f"{self.destination} has no {unit_type} remaining")
|
||||
self.units[unit_type] -= 1
|
||||
@@ -99,7 +98,7 @@ class TransferOrder:
|
||||
def size(self) -> int:
|
||||
return sum(c for c in self.units.values())
|
||||
|
||||
def iter_units(self) -> Iterator[Type[VehicleType]]:
|
||||
def iter_units(self) -> Iterator[GroundUnitType]:
|
||||
for unit_type, count in self.units.items():
|
||||
for _ in range(count):
|
||||
yield unit_type
|
||||
@@ -157,7 +156,7 @@ class Airlift(Transport):
|
||||
self.flight = flight
|
||||
|
||||
@property
|
||||
def units(self) -> Dict[Type[VehicleType], int]:
|
||||
def units(self) -> Dict[GroundUnitType, int]:
|
||||
return self.transfer.units
|
||||
|
||||
@property
|
||||
@@ -315,7 +314,7 @@ class MultiGroupTransport(MissionTarget, Transport):
|
||||
transfer.transport = None
|
||||
self.transfers.remove(transfer)
|
||||
|
||||
def kill_unit(self, unit_type: Type[VehicleType]) -> None:
|
||||
def kill_unit(self, unit_type: GroundUnitType) -> None:
|
||||
for transfer in self.transfers:
|
||||
try:
|
||||
transfer.kill_unit(unit_type)
|
||||
@@ -338,13 +337,18 @@ class MultiGroupTransport(MissionTarget, Transport):
|
||||
return sum(sum(t.units.values()) for t in self.transfers)
|
||||
|
||||
@property
|
||||
def units(self) -> Dict[Type[VehicleType], int]:
|
||||
units: Dict[Type[VehicleType], int] = defaultdict(int)
|
||||
def units(self) -> dict[GroundUnitType, int]:
|
||||
units: Dict[GroundUnitType, int] = defaultdict(int)
|
||||
for transfer in self.transfers:
|
||||
for unit_type, count in transfer.units.items():
|
||||
units[unit_type] += count
|
||||
return units
|
||||
|
||||
def iter_units(self) -> Iterator[GroundUnitType]:
|
||||
for unit_type, count in self.units.items():
|
||||
for _ in range(count):
|
||||
yield unit_type
|
||||
|
||||
@property
|
||||
def player_owned(self) -> bool:
|
||||
return self.origin.captured
|
||||
|
||||
@@ -3,13 +3,11 @@ from __future__ import annotations
|
||||
import logging
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
from typing import Dict, Optional, TYPE_CHECKING, Type, Any
|
||||
|
||||
from dcs.unittype import UnitType, VehicleType
|
||||
from typing import Dict, Optional, TYPE_CHECKING, Any
|
||||
|
||||
from game.theater import ControlPoint
|
||||
from .db import PRICES
|
||||
from .dcs.aircrafttype import AircraftType
|
||||
from .dcs.groundunittype import GroundUnitType
|
||||
from .dcs.unittype import UnitType
|
||||
from .theater.transitnetwork import (
|
||||
NoPathError,
|
||||
TransitNetwork,
|
||||
@@ -25,24 +23,21 @@ class GroundUnitSource:
|
||||
control_point: ControlPoint
|
||||
|
||||
|
||||
AircraftOrVehicleType = Any
|
||||
|
||||
|
||||
class PendingUnitDeliveries:
|
||||
def __init__(self, destination: ControlPoint) -> None:
|
||||
self.destination = destination
|
||||
|
||||
# Maps unit type to order quantity.
|
||||
self.units: Dict[AircraftOrVehicleType, int] = defaultdict(int)
|
||||
self.units: Dict[UnitType, int] = defaultdict(int)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"Pending delivery to {self.destination}"
|
||||
|
||||
def order(self, units: Dict[AircraftOrVehicleType, int]) -> None:
|
||||
def order(self, units: Dict[UnitType, int]) -> None:
|
||||
for k, v in units.items():
|
||||
self.units[k] += v
|
||||
|
||||
def sell(self, units: Dict[AircraftOrVehicleType, int]) -> None:
|
||||
def sell(self, units: Dict[UnitType, int]) -> None:
|
||||
for k, v in units.items():
|
||||
self.units[k] -= v
|
||||
|
||||
@@ -50,24 +45,20 @@ class PendingUnitDeliveries:
|
||||
self.refund(game, self.units)
|
||||
self.units = defaultdict(int)
|
||||
|
||||
def refund(self, game: Game, units: Dict[Type[UnitType], int]) -> None:
|
||||
def refund(self, game: Game, units: Dict[UnitType, int]) -> None:
|
||||
for unit_type, count in units.items():
|
||||
try:
|
||||
price = PRICES[unit_type]
|
||||
except KeyError:
|
||||
logging.error(f"Could not refund {unit_type.id}, price unknown")
|
||||
continue
|
||||
logging.info(f"Refunding {count} {unit_type} at {self.destination.name}")
|
||||
game.adjust_budget(
|
||||
unit_type.price * count, player=self.destination.captured
|
||||
)
|
||||
|
||||
logging.info(f"Refunding {count} {unit_type.id} at {self.destination.name}")
|
||||
game.adjust_budget(price * count, player=self.destination.captured)
|
||||
|
||||
def pending_orders(self, unit_type: AircraftOrVehicleType) -> int:
|
||||
def pending_orders(self, unit_type: UnitType) -> int:
|
||||
pending_units = self.units.get(unit_type)
|
||||
if pending_units is None:
|
||||
pending_units = 0
|
||||
return pending_units
|
||||
|
||||
def available_next_turn(self, unit_type: AircraftOrVehicleType) -> int:
|
||||
def available_next_turn(self, unit_type: UnitType) -> int:
|
||||
current_units = self.destination.base.total_units_of_type(unit_type)
|
||||
return self.pending_orders(unit_type) + current_units
|
||||
|
||||
@@ -81,20 +72,14 @@ class PendingUnitDeliveries:
|
||||
self.refund_all(game)
|
||||
return
|
||||
|
||||
bought_units: Dict[AircraftOrVehicleType, int] = {}
|
||||
units_needing_transfer: Dict[Type[VehicleType], int] = {}
|
||||
sold_units: Dict[AircraftOrVehicleType, int] = {}
|
||||
bought_units: Dict[UnitType, int] = {}
|
||||
units_needing_transfer: Dict[GroundUnitType, int] = {}
|
||||
sold_units: Dict[UnitType, int] = {}
|
||||
for unit_type, count in self.units.items():
|
||||
coalition = "Ally" if self.destination.captured else "Enemy"
|
||||
|
||||
if isinstance(unit_type, AircraftType):
|
||||
name = unit_type.name
|
||||
else:
|
||||
name = unit_type.id
|
||||
|
||||
d: dict[Any, int]
|
||||
if (
|
||||
type(unit_type) == type
|
||||
and issubclass(unit_type, VehicleType)
|
||||
isinstance(unit_type, GroundUnitType)
|
||||
and self.destination != ground_unit_source
|
||||
):
|
||||
source = ground_unit_source
|
||||
@@ -106,11 +91,11 @@ class PendingUnitDeliveries:
|
||||
if count >= 0:
|
||||
d[unit_type] = count
|
||||
game.message(
|
||||
f"{coalition} reinforcements: {name} x {count} at {source}"
|
||||
f"{coalition} reinforcements: {unit_type} x {count} at {source}"
|
||||
)
|
||||
else:
|
||||
sold_units[unit_type] = -count
|
||||
game.message(f"{coalition} sold: {name} x {-count} at {source}")
|
||||
game.message(f"{coalition} sold: {unit_type} x {-count} at {source}")
|
||||
|
||||
self.units = defaultdict(int)
|
||||
self.destination.base.commission_units(bought_units)
|
||||
@@ -121,7 +106,7 @@ class PendingUnitDeliveries:
|
||||
self.create_transfer(game, ground_unit_source, units_needing_transfer)
|
||||
|
||||
def create_transfer(
|
||||
self, game: Game, source: ControlPoint, units: Dict[Type[VehicleType], int]
|
||||
self, game: Game, source: ControlPoint, units: Dict[GroundUnitType, int]
|
||||
) -> None:
|
||||
game.transfers.new_transfer(TransferOrder(source, self.destination, units))
|
||||
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
import itertools
|
||||
import math
|
||||
from dataclasses import dataclass
|
||||
from typing import Dict, Optional, Type
|
||||
from typing import Dict, Optional
|
||||
|
||||
from dcs.unit import Unit
|
||||
from dcs.unitgroup import FlyingGroup, Group, VehicleGroup
|
||||
from dcs.unittype import VehicleType
|
||||
|
||||
from game import db
|
||||
from game.dcs.groundunittype import GroundUnitType
|
||||
from game.squadrons import Pilot
|
||||
from game.theater import Airfield, ControlPoint, TheaterGroundObject
|
||||
from game.theater.theatergroundobject import BuildingGroundObject, SceneryGroundObject
|
||||
@@ -24,7 +23,7 @@ class FlyingUnit:
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class FrontLineUnit:
|
||||
unit_type: Type[VehicleType]
|
||||
unit_type: GroundUnitType
|
||||
origin: ControlPoint
|
||||
|
||||
|
||||
@@ -37,13 +36,13 @@ class GroundObjectUnit:
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ConvoyUnit:
|
||||
unit_type: Type[VehicleType]
|
||||
unit_type: GroundUnitType
|
||||
convoy: Convoy
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AirliftUnits:
|
||||
cargo: tuple[Type[VehicleType], ...]
|
||||
cargo: tuple[GroundUnitType, ...]
|
||||
transfer: TransferOrder
|
||||
|
||||
|
||||
@@ -85,20 +84,15 @@ class UnitMap:
|
||||
def airfield(self, name: str) -> Optional[Airfield]:
|
||||
return self.airfields.get(name, None)
|
||||
|
||||
def add_front_line_units(self, group: Group, origin: ControlPoint) -> None:
|
||||
def add_front_line_units(
|
||||
self, group: Group, origin: ControlPoint, unit_type: GroundUnitType
|
||||
) -> None:
|
||||
for unit in group.units:
|
||||
# The actual name is a String (the pydcs translatable string), which
|
||||
# doesn't define __eq__.
|
||||
name = str(unit.name)
|
||||
if name in self.front_line_units:
|
||||
raise RuntimeError(f"Duplicate front line unit: {name}")
|
||||
unit_type = db.unit_type_from_name(unit.type)
|
||||
if unit_type is None:
|
||||
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"
|
||||
)
|
||||
self.front_line_units[name] = FrontLineUnit(unit_type, origin)
|
||||
|
||||
def front_line_unit(self, name: str) -> Optional[FrontLineUnit]:
|
||||
@@ -141,19 +135,12 @@ class UnitMap:
|
||||
return self.ground_object_units.get(name, None)
|
||||
|
||||
def add_convoy_units(self, group: Group, convoy: Convoy) -> None:
|
||||
for unit in group.units:
|
||||
for unit, unit_type in zip(group.units, convoy.iter_units()):
|
||||
# The actual name is a String (the pydcs translatable string), which
|
||||
# doesn't define __eq__.
|
||||
name = str(unit.name)
|
||||
if name in self.convoys:
|
||||
raise RuntimeError(f"Duplicate convoy unit: {name}")
|
||||
unit_type = db.unit_type_from_name(unit.type)
|
||||
if unit_type is None:
|
||||
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"
|
||||
)
|
||||
self.convoys[name] = ConvoyUnit(unit_type, convoy)
|
||||
|
||||
def convoy_unit(self, name: str) -> Optional[ConvoyUnit]:
|
||||
|
||||
Reference in New Issue
Block a user