Use task priorities from aircraft yamls.

Preferred aircraft per task are now determined by a ranking of weights
stored in the aircraft yaml files. To aid in visualizing the priorities
across aircraft, Liberation can be run with the argument
dump-task-priorities to dump a yaml file in Saved
Games/DCS/Liberation/Debug/priorities.yaml, which will show each task
along with priority sorted aircraft and their weights.

The current weights in the data were exported from the existing lists,
where each position from the bottom of the list was worth 10 (to allow
some games for less shuffling later).

Fixes https://github.com/dcs-liberation/dcs_liberation/issues/2809.
This commit is contained in:
Dan Albert 2023-04-26 21:31:33 -07:00 committed by Raffson
parent 9ebbe11d83
commit 0b6575ca97
No known key found for this signature in database
GPG Key ID: B0402B2C9B764D99
10 changed files with 28 additions and 854 deletions

View File

@ -135,6 +135,7 @@ Saves from 6.x are not compatible with 7.0.
* **[Mission Generation]** Both A-10C modules now use separate radios for inter- and intra-flight comms (similar to other modern aircraft).
* **[Modding]** Updated Community A-4E-C mod version support to 2.1.0 release.
* **[Modding]** Add support for VSN F-4B and F-4C mod.
* **[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.
## Fixes

View File

@ -1,805 +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,
F_14A_135_GR,
F_14B,
F_15C,
F_15E,
F_16A,
F_16A_MLU,
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,
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_F1EE,
Mirage_F1EQ,
Mirage_F1M_CE,
Mirage_F1M_EE,
Mirage_F1C_200,
Mirage_F1CT,
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,
MB_339A,
)
from dcs.unittype import FlyingType
from game.dcs.aircrafttype import AircraftType
from pydcs_extensions.a4ec.a4ec import A_4E_C
from pydcs_extensions.a6a.a6a import VSN_A6A
from pydcs_extensions.a7e.a7e import A_7E
from pydcs_extensions.SWPack.SWPack import (
TIE,
HUNTER,
TIE_INTER,
AWING,
XWING,
YWING,
CORVETTE,
tie_bomber_2,
naboo_starfighter,
)
from pydcs_extensions.f100.f100 import VSN_F100
from pydcs_extensions.f104.f104 import VSN_F104C, VSN_F104G, VSN_F104S, VSN_F104S_AG
from pydcs_extensions.f105.f105 import VSN_F105D, VSN_F105G
from pydcs_extensions.f15d.f15d import F_15D
from pydcs_extensions.f16i_idf.f16i_idf import (
F_16D_50,
F_16D_52,
F_16D_50_NS,
F_16D_52_NS,
F_16D_Barak_30,
F_16D_Barak_40,
F_16I,
)
from pydcs_extensions.f22a.f22a import F_22A
from pydcs_extensions.f4b.f4b import VSN_F4B, VSN_F4C
from pydcs_extensions.f84g.f84g import VSN_F84G
from pydcs_extensions.fa18efg.fa18efg import FA_18E, FA_18F, EA_18G
from pydcs_extensions.hercules.hercules import Hercules
from pydcs_extensions.jas39.jas39 import JAS39Gripen, JAS39Gripen_BVR, JAS39Gripen_AG
from pydcs_extensions.su30.su30 import Su_30MKA, Su_30MKI, Su_30MKM, Su_30SM
from pydcs_extensions.su57.su57 import Su_57
from pydcs_extensions.ov10a.ov10a import Bronco_OV_10A
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
ESCORT_CAPABLE = [
TIE,
HUNTER,
XWING,
AWING,
CORVETTE,
TIE_INTER,
naboo_starfighter,
Su_57,
F_22A,
F_15C,
F_15D,
F_14B,
F_14A_135_GR,
F_14A,
Su_33,
J_11A,
Su_30,
Su_30MKA,
Su_30MKI,
Su_30MKM,
Su_30SM,
Su_27,
MiG_29S,
F_16C_50,
F_16I,
F_16D_Barak_40,
F_16D_Barak_30,
F_16D_50,
F_16D_50_NS,
F_16D_52,
F_16D_52_NS,
FA_18E,
FA_18F,
FA_18C_hornet,
JF_17,
JAS39Gripen_BVR,
JAS39Gripen,
F_16A_MLU,
F_16A,
F_4E,
VSN_F4C,
VSN_F4B,
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,
F_5E_3,
VSN_F104S,
VSN_F104G,
VSN_F104C,
MiG_19P,
VSN_F100,
A_4E_C,
F_86F_Sabre,
MiG_15bis,
C_101CC,
VSN_F84G,
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,
]
# Types to be skipped for escorts
CAP_CAPABLE = ESCORT_CAPABLE + [
L_39ZA,
]
# Used for CAS (Close air support) and BAI (Battlefield Interdiction)
CAS_CAPABLE = [
tie_bomber_2,
YWING,
A_10C_2,
A_10C,
Hercules,
Su_34,
Su_25TM,
Su_25T,
Su_25,
F_15D,
F_15E,
F_16C_50,
F_16I,
F_16D_Barak_40,
F_16D_Barak_30,
F_16D_50,
F_16D_50_NS,
F_16D_52,
F_16D_52_NS,
FA_18E,
FA_18F,
FA_18C_hornet,
Tornado_GR4,
Tornado_IDS,
JAS39Gripen_AG,
JF_17,
AV8BNA,
A_10A,
F_16A_MLU,
F_16A,
B_1B,
A_7E,
A_4E_C,
F_14B,
F_14A_135_GR,
AJS37,
Su_24M,
Su_17M4,
Su_33,
F_4E,
S_3B,
Su_30,
Su_30MKA,
Su_30MKI,
Su_30MKM,
Su_30SM,
MiG_29S,
MiG_27K,
MiG_29A,
MiG_21Bis,
AH_64D_BLK_II,
AH_64D,
AH_64A,
AH_1W,
OH_58D,
SA342M,
SA342L,
Ka_50,
Ka_50_3,
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,
C_101CC,
L_39ZA,
MB_339A,
Bronco_OV_10A,
UH_1H,
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,
VSN_A6A,
VSN_F4C,
VSN_F4B,
VSN_F100,
VSN_F105G,
VSN_F105D,
VSN_F104S_AG,
VSN_F104G,
VSN_F104C,
VSN_F84G,
]
# Aircraft used for SEAD and SEAD Escort tasks. Must be capable of the CAS DCS task.
SEAD_ESCORT_CAPABLE = [
JF_17,
F_16C_50,
F_16I,
F_16D_Barak_40,
F_16D_Barak_30,
F_16D_50,
F_16D_50_NS,
F_16D_52,
F_16D_52_NS,
EA_18G,
FA_18E,
FA_18F,
FA_18C_hornet,
Tornado_IDS,
Su_25T,
Su_25TM,
F_4E,
A_7E,
A_4E_C,
JAS39Gripen_AG,
AV8BNA,
Su_24M,
Su_17M4,
Su_34,
Su_30,
Su_30MKA,
Su_30MKI,
Su_30MKM,
Su_30SM,
MiG_27K,
Tornado_GR4,
VSN_F105G,
VSN_F100,
]
SEAD_CAPABLE = SEAD_ESCORT_CAPABLE + [
F_14B,
F_14A_135_GR,
]
# Aircraft used for DEAD tasks. Must be capable of the CAS DCS task.
DEAD_CAPABLE = SEAD_CAPABLE + [
YWING,
tie_bomber_2,
AJS37,
F_16A_MLU,
F_16A,
F_15E,
JAS39Gripen_AG,
B_1B,
B_52H,
Tu_160,
Tu_95MS,
H_6J,
A_20G,
Ju_88A4,
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,
VSN_A6A,
VSN_F105D,
VSN_F104S_AG,
VSN_F104G,
VSN_F104C,
VSN_F100,
VSN_F84G,
]
# Aircraft used for Strike mission
STRIKE_CAPABLE = [
YWING,
tie_bomber_2,
F_117A,
B_1B,
B_52H,
Tu_160,
Tu_95MS,
Tu_22M3,
H_6J,
F_15D,
F_15E,
AJS37,
Tornado_GR4,
F_16C_50,
F_16I,
F_16D_Barak_40,
F_16D_Barak_30,
F_16D_50,
F_16D_50_NS,
F_16D_52,
F_16D_52_NS,
FA_18E,
FA_18F,
FA_18C_hornet,
AV8BNA,
JF_17,
F_16A_MLU,
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_30MKA,
Su_30MKI,
Su_30MKM,
Su_30SM,
Su_27,
MiG_29S,
MiG_29G,
MiG_29A,
F_4E,
A_7E,
A_10C_2,
A_10C,
VSN_F4C,
VSN_F4B,
S_3B,
A_4E_C,
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,
C_101CC,
L_39ZA,
MB_339A,
B_17G,
A_20G,
Ju_88A4,
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,
VSN_A6A,
VSN_F100,
VSN_F104S_AG,
VSN_F104G,
VSN_F104C,
VSN_F105G,
VSN_F105D,
VSN_F84G,
]
ANTISHIP_CAPABLE = [
AJS37,
Tu_142,
Tu_22M3,
H_6J,
FA_18E,
FA_18F,
FA_18C_hornet,
JAS39Gripen_AG,
F_16A_MLU,
F_16A,
Su_24M,
Su_17M4,
JF_17,
Su_34,
Su_30,
Su_30MKA,
Su_30MKI,
Su_30MKM,
Su_30SM,
Tornado_IDS,
Tornado_GR4,
AV8BNA,
S_3B,
A_7E,
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,
Tornado_IDS,
M_2000C,
Mirage_F1B,
Mirage_F1BE,
Mirage_F1CE,
Mirage_F1EE,
Mirage_F1EQ,
Mirage_F1M_CE,
Mirage_F1M_EE,
Mirage_F1CT,
H_6J,
B_1B,
B_52H,
Tu_22M3,
H_6J,
F_15E,
AJS37,
F_16C_50,
F_16I,
F_16D_Barak_40,
F_16D_Barak_30,
F_16D_50,
F_16D_50_NS,
F_16D_52,
F_16D_52_NS,
FA_18E,
FA_18F,
FA_18C_hornet,
AV8BNA,
JF_17,
F_16A_MLU,
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_30MKA,
Su_30MKI,
Su_30MKM,
Su_30SM,
Su_27,
MiG_29S,
MiG_29G,
MiG_29A,
F_4E,
A_10C_2,
A_10C,
VSN_F4C,
VSN_F4B,
S_3B,
A_7E,
A_4E_C,
Bronco_OV_10A,
M_2000C,
MiG_27K,
MiG_21Bis,
MiG_15bis,
F_5E_3,
F_86F_Sabre,
C_101CC,
L_39ZA,
MB_339A,
B_17G,
A_20G,
Ju_88A4,
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,
VSN_A6A,
VSN_F105G,
VSN_F105D,
VSN_F104S_AG,
VSN_F104G,
VSN_F104C,
VSN_F100,
]
# 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,
C_47,
IL_76MD,
An_26B,
Yak_40,
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_ESCORT_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 ESCORT_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

View File

@ -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:

View File

@ -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,
mission_types=tuple(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=[],

View File

@ -364,6 +364,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()

View File

@ -4,7 +4,6 @@ import itertools
from collections import defaultdict
from typing import Sequence, Iterator, TYPE_CHECKING, Optional
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 task in squadron.mission_types:

View File

@ -256,6 +256,14 @@ class Squadron:
def has_unfilled_pilot_slots(self) -> bool:
return not self.pilot_limits_enabled or self._number_of_unfilled_pilot_slots > 0
def capable_of(self, task: FlightType) -> bool:
"""Returns True if the squadron is capable of performing the given task.
A squadron may be capable of performing a task even if it will not be
automatically assigned to it.
"""
return self.aircraft.capable_of(task)
def can_auto_assign(self, task: FlightType) -> bool:
return task in self.auto_assignable_mission_types

View File

@ -25,16 +25,12 @@ class SquadronDef:
role: str
aircraft: AircraftType
livery: Optional[str]
mission_types: tuple[FlightType, ...]
auto_assignable_mission_types: set[FlightType]
operating_bases: OperatingBases
female_pilot_percentage: int
pilot_pool: list[Pilot]
claimed: bool = False
auto_assignable_mission_types: set[FlightType] = field(
init=False, hash=False, compare=False
)
def __post_init__(self) -> None:
self.auto_assignable_mission_types = set(self.mission_types)
@ -48,7 +44,11 @@ class SquadronDef:
self.auto_assignable_mission_types.intersection_update(self.mission_types)
def can_auto_assign(self, task: FlightType) -> bool:
return task in self.auto_assignable_mission_types
"""
A squadron may be capable of performing a task even if it will not be
automatically assigned to it.
"""
return self.aircraft.capable_of(task)
def operates_from(self, control_point: ControlPoint) -> bool:
if not control_point.can_operate(self.aircraft):
@ -95,7 +95,7 @@ class SquadronDef:
role=data["role"],
aircraft=unit_type,
livery=data.get("livery"),
mission_types=tuple(mission_types),
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,

View File

@ -40,7 +40,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
@ -270,7 +269,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

View File

@ -10,8 +10,6 @@ from PySide2.QtWidgets import (
QFrame,
)
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
@ -84,9 +82,8 @@ class QUnitInfoWindow(QDialog):
# If it's an aircraft, include the task list.
if isinstance(unit_type, AircraftType):
self.tasks_box = QLabel(
f"<b>In-Game Tasks:</b> {self.generateAircraftTasks()}"
)
tasks = ", ".join(str(t) for t in unit_type.iter_task_capabilities())
self.tasks_box = QLabel(f"<b>In-Game Tasks:</b> {tasks}")
self.tasks_box.setProperty("style", "info-element")
self.gridLayout.addWidget(self.tasks_box, 2, 0)
@ -101,30 +98,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]