diff --git a/changelog.md b/changelog.md
index b1bbe612..10b92049 100644
--- a/changelog.md
+++ b/changelog.md
@@ -15,6 +15,7 @@ Saves from 6.x are not compatible with 7.0.
* **[Modding]** Custom factions can now be defined in YAML as well as JSON. JSON support may be removed in the future if having both formats causes confusion.
* **[Modding]** Campaigns which require custom factions can now define those factions directly in the campaign YAML. See Operation Aliied Sword for an example.
* **[Modding]** The `mission_types` field in squadron files has been removed. Squadron task capability is now determined by airframe, and the auto-assignable list has always been overridden by the campaign settings.
+* **[Modding]** Aircraft task capabilities and preferred aircraft for each task are now moddable in the aircraft unit yaml files. Each aircraft has a weight per task. Higher weights are given higher preference.
* **[New Game Wizard]** Choices for some options will be remembered for the next new game. Not all settings will be preserved, as many are campaign dependent.
* **[New Game Wizard]** Lua plugins can now be set while creating a new game.
* **[Squadrons]** Squadron-specific mission capability lists no longer restrict players from assigning missions outside the squadron's preferences.
diff --git a/game/ato/ai_flight_planner_db.py b/game/ato/ai_flight_planner_db.py
deleted file mode 100644
index 7d09c405..00000000
--- a/game/ato/ai_flight_planner_db.py
+++ /dev/null
@@ -1,644 +0,0 @@
-import logging
-from collections.abc import Sequence
-from typing import Type
-
-from dcs.helicopters import (
- AH_1W,
- AH_64A,
- AH_64D,
- AH_64D_BLK_II,
- CH_47D,
- CH_53E,
- Ka_50,
- Ka_50_3,
- Mi_24P,
- Mi_24V,
- Mi_26,
- Mi_28N,
- Mi_8MT,
- OH_58D,
- SA342L,
- SA342M,
- SH_60B,
- UH_1H,
- UH_60A,
-)
-from dcs.planes import (
- AJS37,
- AV8BNA,
- A_10A,
- A_10C,
- A_10C_2,
- A_20G,
- A_50,
- An_26B,
- B_17G,
- B_1B,
- B_52H,
- Bf_109K_4,
- C_101CC,
- C_130,
- C_17A,
- C_47,
- E_2C,
- E_3A,
- FA_18C_hornet,
- FW_190A8,
- FW_190D9,
- F_117A,
- F_14A_135_GR,
- F_14B,
- F_15C,
- F_15E,
- F_16A,
- F_16C_50,
- F_4E,
- F_5E_3,
- F_86F_Sabre,
- H_6J,
- IL_76MD,
- IL_78M,
- I_16,
- JF_17,
- J_11A,
- Ju_88A4,
- KC130,
- KC135MPRS,
- KC_135,
- KJ_2000,
- L_39ZA,
- MB_339A,
- MQ_9_Reaper,
- M_2000C,
- MiG_15bis,
- MiG_19P,
- MiG_21Bis,
- MiG_23MLD,
- MiG_25PD,
- MiG_27K,
- MiG_29A,
- MiG_29G,
- MiG_29S,
- MiG_31,
- Mirage_2000_5,
- Mirage_F1B,
- Mirage_F1BE,
- Mirage_F1CE,
- Mirage_F1CT,
- Mirage_F1C_200,
- Mirage_F1EE,
- Mirage_F1EQ,
- Mirage_F1M_CE,
- Mirage_F1M_EE,
- MosquitoFBMkVI,
- P_47D_30,
- P_47D_30bl1,
- P_47D_40,
- P_51D,
- P_51D_30_NA,
- RQ_1A_Predator,
- S_3B,
- S_3B_Tanker,
- SpitfireLFMkIX,
- SpitfireLFMkIXCW,
- Su_17M4,
- Su_24M,
- Su_25,
- Su_25T,
- Su_25TM,
- Su_27,
- Su_30,
- Su_33,
- Su_34,
- Tornado_GR4,
- Tornado_IDS,
- Tu_142,
- Tu_160,
- Tu_22M3,
- Tu_95MS,
- WingLoong_I,
- Yak_40,
-)
-from dcs.unittype import FlyingType
-
-from game.dcs.aircrafttype import AircraftType
-from pydcs_extensions.a4ec.a4ec import A_4E_C
-from pydcs_extensions.f104.f104 import VSN_F104G, VSN_F104S, VSN_F104S_AG
-from pydcs_extensions.f4.f4 import VSN_F4B, VSN_F4C
-from pydcs_extensions.f22a.f22a import F_22A
-from pydcs_extensions.hercules.hercules import Hercules
-from pydcs_extensions.jas39.jas39 import JAS39Gripen, JAS39Gripen_AG
-from pydcs_extensions.ov10a.ov10a import Bronco_OV_10A
-from pydcs_extensions.su57.su57 import Su_57
-from pydcs_extensions.uh60l.uh60l import KC130J, UH_60L
-from .flighttype import FlightType
-
-# All aircraft lists are in priority order. Aircraft higher in the list will be
-# preferred over those lower in the list.
-# TODO: These lists really ought to be era (faction) dependent.
-# Factions which have F-5s, F-86s, and A-4s will should prefer F-5s for CAP, but
-# factions that also have F-4s should not.
-
-# Used for CAP, Escort, and intercept if there is not a specialised aircraft available
-CAP_CAPABLE = [
- Su_57,
- F_22A,
- F_15C,
- F_14B,
- F_14A_135_GR,
- Su_33,
- J_11A,
- Su_30,
- Su_27,
- MiG_29S,
- F_16C_50,
- FA_18C_hornet,
- JF_17,
- JAS39Gripen,
- F_16A,
- F_4E,
- MiG_31,
- MiG_25PD,
- MiG_29G,
- MiG_29A,
- MiG_23MLD,
- MiG_21Bis,
- Mirage_2000_5,
- Mirage_F1B,
- Mirage_F1BE,
- Mirage_F1CE,
- Mirage_F1EE,
- Mirage_F1EQ,
- Mirage_F1M_CE,
- Mirage_F1M_EE,
- Mirage_F1C_200,
- Mirage_F1CT,
- F_15E,
- M_2000C,
- VSN_F4B,
- VSN_F4C,
- F_5E_3,
- VSN_F104S,
- VSN_F104G,
- MiG_19P,
- A_4E_C,
- F_86F_Sabre,
- MiG_15bis,
- C_101CC,
- L_39ZA,
- P_51D_30_NA,
- P_51D,
- SpitfireLFMkIXCW,
- SpitfireLFMkIX,
- MosquitoFBMkVI,
- Bf_109K_4,
- FW_190D9,
- FW_190A8,
- P_47D_30,
- P_47D_30bl1,
- P_47D_40,
- I_16,
-]
-
-
-# Used for CAS (Close air support) and BAI (Battlefield Interdiction)
-CAS_CAPABLE = [
- A_10C_2,
- A_10C,
- Hercules,
- Su_34,
- Su_25TM,
- Su_25T,
- Su_25,
- F_15E,
- F_16C_50,
- FA_18C_hornet,
- Tornado_GR4,
- Tornado_IDS,
- JAS39Gripen_AG,
- JF_17,
- AV8BNA,
- A_10A,
- B_1B,
- A_4E_C,
- Bronco_OV_10A,
- F_14B,
- F_14A_135_GR,
- AJS37,
- Su_24M,
- Su_17M4,
- Su_33,
- F_4E,
- S_3B,
- Su_30,
- MiG_29S,
- MiG_27K,
- MiG_29A,
- MiG_21Bis,
- AH_64D_BLK_II,
- AH_64D,
- AH_64A,
- AH_1W,
- OH_58D,
- SA342M,
- SA342L,
- Ka_50_3,
- Ka_50,
- Mi_28N,
- Mi_24P,
- Mi_24V,
- Mi_8MT,
- H_6J,
- MiG_19P,
- MiG_15bis,
- M_2000C,
- Mirage_F1B,
- Mirage_F1BE,
- Mirage_F1CE,
- Mirage_F1EE,
- Mirage_F1EQ,
- Mirage_F1M_CE,
- Mirage_F1M_EE,
- Mirage_F1CT,
- F_5E_3,
- F_86F_Sabre,
- MB_339A,
- C_101CC,
- L_39ZA,
- UH_1H,
- VSN_F104S_AG,
- VSN_F104G,
- VSN_F4B,
- VSN_F4C,
- A_20G,
- Ju_88A4,
- P_47D_40,
- P_47D_30bl1,
- P_47D_30,
- P_51D_30_NA,
- P_51D,
- SpitfireLFMkIXCW,
- SpitfireLFMkIX,
- MosquitoFBMkVI,
- I_16,
- Bf_109K_4,
- FW_190D9,
- FW_190A8,
- WingLoong_I,
- MQ_9_Reaper,
- RQ_1A_Predator,
-]
-
-
-# Aircraft used for SEAD and SEAD Escort tasks. Must be capable of the CAS DCS task.
-SEAD_CAPABLE = [
- JF_17,
- F_16C_50,
- FA_18C_hornet,
- Tornado_IDS,
- Su_25T,
- Su_25TM,
- F_4E,
- A_4E_C,
- F_14B,
- F_14A_135_GR,
- JAS39Gripen_AG,
- AV8BNA,
- VSN_F4C,
- Su_24M,
- Su_17M4,
- Su_34,
- Su_30,
- MiG_27K,
- Tornado_GR4,
-]
-
-
-# Aircraft used for DEAD tasks. Must be capable of the CAS DCS task.
-DEAD_CAPABLE = SEAD_CAPABLE + [
- AJS37,
- F_15E,
- F_14B,
- F_14A_135_GR,
- JAS39Gripen_AG,
- B_1B,
- B_52H,
- Tu_160,
- Tu_95MS,
- H_6J,
- A_20G,
- Ju_88A4,
- VSN_F4B,
- VSN_F4C,
- VSN_F104S_AG,
- VSN_F104G,
- P_47D_40,
- P_47D_30bl1,
- P_47D_30,
- P_51D_30_NA,
- P_51D,
- Bronco_OV_10A,
- SpitfireLFMkIXCW,
- SpitfireLFMkIX,
- MosquitoFBMkVI,
- Bf_109K_4,
- FW_190D9,
- FW_190A8,
-]
-
-
-# Aircraft used for Strike mission
-STRIKE_CAPABLE = [
- F_117A,
- B_1B,
- B_52H,
- Tu_160,
- Tu_95MS,
- Tu_22M3,
- H_6J,
- F_15E,
- AJS37,
- Tornado_GR4,
- F_16C_50,
- FA_18C_hornet,
- AV8BNA,
- JF_17,
- F_16A,
- F_14B,
- F_14A_135_GR,
- JAS39Gripen_AG,
- Tornado_IDS,
- Su_17M4,
- Su_24M,
- Su_25TM,
- Su_25T,
- Su_25,
- Su_34,
- Su_33,
- Su_30,
- Su_27,
- MiG_29S,
- MiG_29G,
- MiG_29A,
- F_4E,
- A_10C_2,
- A_10C,
- S_3B,
- A_4E_C,
- VSN_F4B,
- VSN_F4C,
- Bronco_OV_10A,
- M_2000C,
- Mirage_F1B,
- Mirage_F1BE,
- Mirage_F1CE,
- Mirage_F1EE,
- Mirage_F1EQ,
- Mirage_F1M_CE,
- Mirage_F1M_EE,
- Mirage_F1CT,
- MiG_27K,
- MiG_21Bis,
- MiG_15bis,
- F_5E_3,
- F_86F_Sabre,
- MB_339A,
- C_101CC,
- L_39ZA,
- B_17G,
- A_20G,
- Ju_88A4,
- VSN_F104S_AG,
- VSN_F104G,
- P_47D_40,
- P_47D_30bl1,
- P_47D_30,
- P_51D_30_NA,
- P_51D,
- SpitfireLFMkIXCW,
- SpitfireLFMkIX,
- MosquitoFBMkVI,
- Bf_109K_4,
- FW_190D9,
- FW_190A8,
-]
-
-
-ANTISHIP_CAPABLE = [
- AJS37,
- Tu_142,
- Tu_22M3,
- H_6J,
- FA_18C_hornet,
- JAS39Gripen_AG,
- Su_24M,
- Su_17M4,
- JF_17,
- Su_34,
- Su_30,
- Tornado_IDS,
- Tornado_GR4,
- AV8BNA,
- S_3B,
- A_20G,
- Ju_88A4,
- MosquitoFBMkVI,
- C_101CC,
- SH_60B,
-]
-
-
-# This list does not "inherit" from the strike list because some strike aircraft can
-# only carry guided weapons, and the AI cannot do runway attack with dguided weapons.
-# https://github.com/dcs-liberation/dcs_liberation/issues/1703
-RUNWAY_ATTACK_CAPABLE = [
- JF_17,
- Su_34,
- Su_30,
- Tornado_IDS,
- M_2000C,
- H_6J,
- B_1B,
- B_52H,
- Tu_22M3,
- H_6J,
- F_15E,
- AJS37,
- F_16C_50,
- FA_18C_hornet,
- AV8BNA,
- JF_17,
- F_16A,
- F_14B,
- F_14A_135_GR,
- JAS39Gripen_AG,
- Tornado_IDS,
- Su_17M4,
- Su_24M,
- Su_25TM,
- Su_25T,
- Su_25,
- Su_34,
- Su_33,
- Su_30,
- Su_27,
- MiG_29S,
- MiG_29G,
- MiG_29A,
- F_4E,
- A_10C_2,
- A_10C,
- S_3B,
- A_4E_C,
- VSN_F4B,
- VSN_F4C,
- Bronco_OV_10A,
- M_2000C,
- Mirage_F1B,
- Mirage_F1BE,
- Mirage_F1CE,
- Mirage_F1EE,
- Mirage_F1EQ,
- Mirage_F1M_CE,
- Mirage_F1M_EE,
- Mirage_F1CT,
- MiG_27K,
- MiG_21Bis,
- MiG_15bis,
- MB_339A,
- F_5E_3,
- F_86F_Sabre,
- C_101CC,
- L_39ZA,
- B_17G,
- A_20G,
- Ju_88A4,
- VSN_F104S_AG,
- VSN_F104G,
- P_47D_40,
- P_47D_30bl1,
- P_47D_30,
- P_51D_30_NA,
- P_51D,
- SpitfireLFMkIXCW,
- SpitfireLFMkIX,
- MosquitoFBMkVI,
- Bf_109K_4,
- FW_190D9,
- FW_190A8,
-]
-
-# For any aircraft that isn't necessarily directly involved in strike
-# missions in a direct combat sense, but can transport objects and infantry.
-TRANSPORT_CAPABLE = [
- C_17A,
- Hercules,
- C_130,
- IL_76MD,
- An_26B,
- Yak_40,
- C_47,
- CH_53E,
- CH_47D,
- UH_60L,
- SH_60B,
- UH_60A,
- UH_1H,
- Mi_8MT,
- Mi_8MT,
- Mi_26,
-]
-
-AIR_ASSAULT_CAPABLE = [
- CH_53E,
- CH_47D,
- UH_60L,
- SH_60B,
- UH_60A,
- UH_1H,
- Mi_8MT,
- Mi_26,
- Mi_24P,
- Mi_24V,
- Hercules,
-]
-
-DRONES = [MQ_9_Reaper, RQ_1A_Predator, WingLoong_I]
-
-AEWC_CAPABLE = [
- E_3A,
- E_2C,
- A_50,
- KJ_2000,
-]
-
-# Priority is given to the tankers that can carry the most fuel.
-REFUELING_CAPABALE = [
- KC_135,
- KC135MPRS,
- IL_78M,
- KC130J,
- KC130,
- S_3B_Tanker,
-]
-
-
-def dcs_types_for_task(task: FlightType) -> Sequence[Type[FlyingType]]:
- cap_missions = (
- FlightType.BARCAP,
- FlightType.INTERCEPTION,
- FlightType.SWEEP,
- FlightType.TARCAP,
- )
- if task in cap_missions:
- return CAP_CAPABLE
- elif task == FlightType.ANTISHIP:
- return ANTISHIP_CAPABLE
- elif task == FlightType.BAI:
- return CAS_CAPABLE
- elif task == FlightType.CAS:
- return CAS_CAPABLE
- elif task == FlightType.SEAD:
- return SEAD_CAPABLE
- elif task == FlightType.SEAD_ESCORT:
- return SEAD_CAPABLE
- elif task == FlightType.DEAD:
- return DEAD_CAPABLE
- elif task == FlightType.OCA_AIRCRAFT:
- return CAS_CAPABLE
- elif task == FlightType.OCA_RUNWAY:
- return RUNWAY_ATTACK_CAPABLE
- elif task == FlightType.STRIKE:
- return STRIKE_CAPABLE
- elif task == FlightType.ESCORT:
- return CAP_CAPABLE
- elif task == FlightType.AEWC:
- return AEWC_CAPABLE
- elif task == FlightType.REFUELING:
- return REFUELING_CAPABALE
- elif task == FlightType.TRANSPORT:
- return TRANSPORT_CAPABLE
- elif task == FlightType.AIR_ASSAULT:
- return AIR_ASSAULT_CAPABLE
- else:
- logging.error(f"Unplannable flight type: {task}")
- return []
-
-
-def aircraft_for_task(task: FlightType) -> list[AircraftType]:
- dcs_types = dcs_types_for_task(task)
- types: list[AircraftType] = []
- for dcs_type in dcs_types:
- types.extend(AircraftType.for_dcs_type(dcs_type))
- return types
-
-
-def tasks_for_aircraft(aircraft: AircraftType) -> list[FlightType]:
- tasks: list[FlightType] = []
- for task in FlightType:
- if task is FlightType.FERRY:
- # Not a plannable task, so skip it.
- continue
- if aircraft in aircraft_for_task(task):
- tasks.append(task)
- return tasks
diff --git a/game/ato/flighttype.py b/game/ato/flighttype.py
index 9660f3f2..18216ea3 100644
--- a/game/ato/flighttype.py
+++ b/game/ato/flighttype.py
@@ -24,8 +24,8 @@ class FlightType(Enum):
* Implementations of MissionTarget.mission_types: A mission type can only be planned
against compatible targets. The mission_types method of each target class defines
which missions may target it.
- * ai_flight_planner_db.py: Add the new mission type to aircraft_for_task that
- returns the list of compatible aircraft in order of preference.
+ * resources/units/aircraft/*.yaml: Assign aircraft weight for the new task type in
+ the `tasks` dict for all capable aircraft.
You may also need to update:
diff --git a/game/campaignloader/squadrondefgenerator.py b/game/campaignloader/squadrondefgenerator.py
index f5ff6d70..52eb6726 100644
--- a/game/campaignloader/squadrondefgenerator.py
+++ b/game/campaignloader/squadrondefgenerator.py
@@ -4,7 +4,6 @@ import itertools
import random
from typing import Optional, TYPE_CHECKING
-from game.ato.ai_flight_planner_db import aircraft_for_task, tasks_for_aircraft
from game.ato.flighttype import FlightType
from game.dcs.aircrafttype import AircraftType
from game.squadrons.operatingbases import OperatingBases
@@ -25,7 +24,7 @@ class SquadronDefGenerator:
self, task: FlightType, control_point: ControlPoint
) -> Optional[SquadronDef]:
aircraft_choice: Optional[AircraftType] = None
- for aircraft in aircraft_for_task(task):
+ for aircraft in AircraftType.priority_list_for_task(task):
if aircraft not in self.faction.aircrafts:
continue
if not control_point.can_operate(aircraft):
@@ -48,7 +47,7 @@ class SquadronDefGenerator:
role="Flying Squadron",
aircraft=aircraft,
livery=None,
- auto_assignable_mission_types=set(tasks_for_aircraft(aircraft)),
+ auto_assignable_mission_types=set(aircraft.iter_task_capabilities()),
operating_bases=OperatingBases.default_for_aircraft(aircraft),
female_pilot_percentage=6,
pilot_pool=[],
diff --git a/game/dcs/aircrafttype.py b/game/dcs/aircrafttype.py
index c34a2225..bfc19c6d 100644
--- a/game/dcs/aircrafttype.py
+++ b/game/dcs/aircrafttype.py
@@ -359,6 +359,9 @@ class AircraftType(UnitType[Type[FlyingType]]):
capable.append(aircraft)
return list(reversed(sorted(capable, key=lambda a: a.task_priority(task))))
+ def iter_task_capabilities(self) -> Iterator[FlightType]:
+ yield from self.task_priorities
+
@staticmethod
def each_dcs_type() -> Iterator[Type[FlyingType]]:
yield from helicopter_map.values()
diff --git a/game/missiongenerator/airsupportgenerator.py b/game/missiongenerator/airsupportgenerator.py
index 8aa8c209..1dbc7c09 100644
--- a/game/missiongenerator/airsupportgenerator.py
+++ b/game/missiongenerator/airsupportgenerator.py
@@ -15,7 +15,7 @@ from dcs.task import (
)
from dcs.unittype import UnitType
-from game.ato.ai_flight_planner_db import AEWC_CAPABLE
+from game.ato import FlightType
from game.callsigns import callsign_for_support_unit
from game.naming import namegen
from game.radio.radios import RadioRegistry
@@ -165,7 +165,7 @@ class AirSupportGenerator:
possible_awacs = [
a
for a in self.game.faction_for(player=True).aircrafts
- if a in AEWC_CAPABLE
+ if a.capable_of(FlightType.AEWC)
]
if not possible_awacs:
diff --git a/game/squadrons/airwing.py b/game/squadrons/airwing.py
index 19e4a91c..c8948a66 100644
--- a/game/squadrons/airwing.py
+++ b/game/squadrons/airwing.py
@@ -4,7 +4,6 @@ import itertools
from collections import defaultdict
from typing import Iterator, Optional, Sequence, TYPE_CHECKING
-from game.ato.ai_flight_planner_db import aircraft_for_task
from game.ato.closestairfields import ObjectiveDistanceCache
from game.dcs.aircrafttype import AircraftType
from .squadrondefloader import SquadronDefLoader
@@ -48,7 +47,7 @@ class AirWing:
self, location: MissionTarget, task: FlightType, size: int, this_turn: bool
) -> list[Squadron]:
airfield_cache = ObjectiveDistanceCache.get_closest_airfields(location)
- best_aircraft = aircraft_for_task(task)
+ best_aircraft = AircraftType.priority_list_for_task(task)
ordered: list[Squadron] = []
for control_point in airfield_cache.operational_airfields:
if control_point.captured != self.player:
@@ -79,7 +78,7 @@ class AirWing:
def best_available_aircrafts_for(self, task: FlightType) -> list[AircraftType]:
"""Returns an ordered list of available aircrafts for the given task"""
aircrafts = []
- best_aircraft_for_task = aircraft_for_task(task)
+ best_aircraft_for_task = AircraftType.priority_list_for_task(task)
for aircraft, squadrons in self.squadrons.items():
for squadron in squadrons:
if squadron.untasked_aircraft and squadron.capable_of(task):
diff --git a/game/squadrons/squadron.py b/game/squadrons/squadron.py
index c7eebf5e..9618fa81 100644
--- a/game/squadrons/squadron.py
+++ b/game/squadrons/squadron.py
@@ -12,7 +12,6 @@ from faker import Faker
from game.ato import Flight, FlightType, Package
from game.settings import AutoAtoBehavior, Settings
from .pilot import Pilot, PilotStatus
-from ..ato.ai_flight_planner_db import aircraft_for_task
from ..db.database import Database
from ..utils import meters
@@ -253,7 +252,7 @@ class Squadron:
A squadron may be capable of performing a task even if it will not be
automatically assigned to it.
"""
- return self.aircraft in aircraft_for_task(task)
+ return self.aircraft.capable_of(task)
def can_auto_assign(self, task: FlightType) -> bool:
"""Returns True if the squadron may be automatically assigned the given task.
diff --git a/game/squadrons/squadrondef.py b/game/squadrons/squadrondef.py
index ff535a31..1c009dab 100644
--- a/game/squadrons/squadrondef.py
+++ b/game/squadrons/squadrondef.py
@@ -6,7 +6,6 @@ from typing import Optional, TYPE_CHECKING
import yaml
-from game.ato.ai_flight_planner_db import aircraft_for_task, tasks_for_aircraft
from game.dcs.aircrafttype import AircraftType
from game.squadrons.operatingbases import OperatingBases
from game.squadrons.pilot import Pilot
@@ -41,7 +40,7 @@ class SquadronDef:
A squadron may be capable of performing a task even if it will not be
automatically assigned to it.
"""
- return self.aircraft in aircraft_for_task(task)
+ return self.aircraft.capable_of(task)
def operates_from(self, control_point: ControlPoint) -> bool:
if not control_point.can_operate(self.aircraft):
@@ -76,7 +75,7 @@ class SquadronDef:
role=data["role"],
aircraft=unit_type,
livery=data.get("livery"),
- auto_assignable_mission_types=set(tasks_for_aircraft(unit_type)),
+ auto_assignable_mission_types=set(unit_type.iter_task_capabilities()),
operating_bases=OperatingBases.from_yaml(unit_type, data.get("bases", {})),
female_pilot_percentage=female_pilot_percentage,
pilot_pool=pilots,
diff --git a/game/transfers.py b/game/transfers.py
index ca913272..86f946d4 100644
--- a/game/transfers.py
+++ b/game/transfers.py
@@ -41,7 +41,6 @@ from typing import Generic, Iterator, List, Optional, Sequence, TYPE_CHECKING, T
from dcs.mapping import Point
-from game.ato.ai_flight_planner_db import aircraft_for_task
from game.ato.closestairfields import ObjectiveDistanceCache
from game.ato.flight import Flight
from game.ato.flighttype import FlightType
@@ -277,7 +276,7 @@ class AirliftPlanner:
def compatible_with_mission(
self, unit_type: AircraftType, airfield: ControlPoint
) -> bool:
- if unit_type not in aircraft_for_task(FlightType.TRANSPORT):
+ if not unit_type.capable_of(FlightType.TRANSPORT):
return False
if not self.transfer.origin.can_operate(unit_type):
return False
diff --git a/qt_ui/windows/QUnitInfoWindow.py b/qt_ui/windows/QUnitInfoWindow.py
index 92cacce0..85712b4c 100644
--- a/qt_ui/windows/QUnitInfoWindow.py
+++ b/qt_ui/windows/QUnitInfoWindow.py
@@ -4,8 +4,6 @@ from PySide6.QtCore import Qt
from PySide6.QtGui import QIcon
from PySide6.QtWidgets import QDialog, QFrame, QGridLayout, QLabel, QTextBrowser
-import game.ato.ai_flight_planner_db
-from game.ato.flighttype import FlightType
from game.dcs.aircrafttype import AircraftType
from game.dcs.groundunittype import GroundUnitType
from game.dcs.unittype import UnitType
@@ -78,9 +76,8 @@ class QUnitInfoWindow(QDialog):
# If it's an aircraft, include the task list.
if isinstance(unit_type, AircraftType):
- self.tasks_box = QLabel(
- f"In-Game Tasks: {self.generateAircraftTasks()}"
- )
+ tasks = ", ".join(str(t) for t in unit_type.iter_task_capabilities())
+ self.tasks_box = QLabel(f"In-Game Tasks: {tasks}")
self.tasks_box.setProperty("style", "info-element")
self.gridLayout.addWidget(self.tasks_box, 2, 0)
@@ -95,30 +92,3 @@ class QUnitInfoWindow(QDialog):
self.layout.addLayout(self.gridLayout, 1, 0)
self.setLayout(self.layout)
-
- def generateAircraftTasks(self) -> str:
- aircraft_tasks = ""
- unit_type = self.unit_type.dcs_unit_type
- if unit_type in game.ato.ai_flight_planner_db.CAP_CAPABLE:
- aircraft_tasks = (
- aircraft_tasks
- + f"{FlightType.BARCAP}, {FlightType.ESCORT}, {FlightType.INTERCEPTION}, {FlightType.SWEEP}, {FlightType.TARCAP}, "
- )
- if unit_type in game.ato.ai_flight_planner_db.CAS_CAPABLE:
- aircraft_tasks = (
- aircraft_tasks
- + f"{FlightType.CAS}, {FlightType.BAI}, {FlightType.OCA_AIRCRAFT}, "
- )
- if unit_type in game.ato.ai_flight_planner_db.SEAD_CAPABLE:
- aircraft_tasks = aircraft_tasks + f"{FlightType.SEAD}, "
- if unit_type in game.ato.ai_flight_planner_db.DEAD_CAPABLE:
- aircraft_tasks = aircraft_tasks + f"{FlightType.DEAD}, "
- if unit_type in game.ato.ai_flight_planner_db.ANTISHIP_CAPABLE:
- aircraft_tasks = aircraft_tasks + f"{FlightType.ANTISHIP}, "
- if unit_type in game.ato.ai_flight_planner_db.RUNWAY_ATTACK_CAPABLE:
- aircraft_tasks = aircraft_tasks + f"{FlightType.OCA_RUNWAY}, "
- if unit_type in game.ato.ai_flight_planner_db.STRIKE_CAPABLE:
- aircraft_tasks = aircraft_tasks + f"{FlightType.STRIKE}, "
- if unit_type in game.ato.ai_flight_planner_db.REFUELING_CAPABALE:
- aircraft_tasks = aircraft_tasks + f"{FlightType.REFUELING}, "
- return aircraft_tasks[:-2]