mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Initial implementation of AEW&C missions.
Still a work in progress (the missions don't actually perform their task, just orbit). Currently: * AEW&C aircraft can be bought. * AEW&C missions can be planned at any control point and at front lines. * AEW&C will return after 4H or Bingo.
This commit is contained in:
parent
4a0ccc4c2f
commit
e0501e46e3
@ -4,6 +4,8 @@ Saves from 2.4 are not compatible with 2.5.
|
||||
|
||||
## Features/Improvements
|
||||
|
||||
* **[Flight Planner]** (WIP) Added AEW&C missions.
|
||||
|
||||
## Fixes
|
||||
|
||||
# 2.4.1
|
||||
|
||||
@ -1117,7 +1117,8 @@ COMMON_OVERRIDE = {
|
||||
GroundAttack: "STRIKE",
|
||||
Escort: "CAP",
|
||||
RunwayAttack: "RUNWAY_ATTACK",
|
||||
FighterSweep: "CAP"
|
||||
FighterSweep: "CAP",
|
||||
AWACS: "AEW&C",
|
||||
}
|
||||
|
||||
"""
|
||||
@ -1328,6 +1329,7 @@ CARRIER_CAPABLE = [
|
||||
A_4E_C,
|
||||
Rafale_M,
|
||||
S_3B,
|
||||
E_2C,
|
||||
|
||||
UH_1H,
|
||||
Mi_8MT,
|
||||
|
||||
@ -4,7 +4,7 @@ import math
|
||||
import typing
|
||||
from typing import Dict, Type
|
||||
|
||||
from dcs.task import CAP, CAS, Embarking, PinpointStrike, Task
|
||||
from dcs.task import AWACS, CAP, CAS, Embarking, PinpointStrike, Task
|
||||
from dcs.unittype import FlyingType, UnitType, VehicleType
|
||||
from dcs.vehicles import AirDefence, Armor
|
||||
|
||||
@ -122,7 +122,7 @@ class Base:
|
||||
for_task = db.unit_task(unit_type)
|
||||
|
||||
target_dict = None
|
||||
if for_task == CAS or for_task == CAP or for_task == Embarking:
|
||||
if for_task == AWACS or for_task == CAS or for_task == CAP or for_task == Embarking:
|
||||
target_dict = self.aircraft
|
||||
elif for_task == PinpointStrike:
|
||||
target_dict = self.armor
|
||||
|
||||
@ -812,6 +812,7 @@ class FrontLine(MissionTarget):
|
||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||
yield from [
|
||||
FlightType.CAS,
|
||||
FlightType.AEWC,
|
||||
# TODO: FlightType.TROOP_TRANSPORT
|
||||
# TODO: FlightType.EVAC
|
||||
]
|
||||
|
||||
@ -603,6 +603,14 @@ class ControlPoint(MissionTarget, ABC):
|
||||
def income_per_turn(self) -> int:
|
||||
return 0
|
||||
|
||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||
from gen.flights.flight import FlightType
|
||||
if self.is_friendly(for_player):
|
||||
yield from [
|
||||
FlightType.AEWC,
|
||||
]
|
||||
yield from super().mission_types(for_player)
|
||||
|
||||
|
||||
class Airfield(ControlPoint):
|
||||
|
||||
|
||||
@ -41,6 +41,7 @@ from dcs.planes import (
|
||||
)
|
||||
from dcs.point import MovingPoint, PointAction
|
||||
from dcs.task import (
|
||||
AWACS,
|
||||
AntishipStrike,
|
||||
AttackGroup,
|
||||
Bombing,
|
||||
@ -90,7 +91,6 @@ from game.utils import Distance, meters, nautical_miles
|
||||
from gen.airsupportgen import AirSupport
|
||||
from gen.ato import AirTaskingOrder, Package
|
||||
from gen.callsigns import create_group_callsign_from_unit
|
||||
from gen.conflictgen import FRONTLINE_LENGTH
|
||||
from gen.flights.flight import (
|
||||
Flight,
|
||||
FlightType,
|
||||
@ -129,10 +129,11 @@ HELICOPTER_CHANNEL = MHz(127)
|
||||
UHF_FALLBACK_CHANNEL = MHz(251)
|
||||
|
||||
TARGET_WAYPOINTS = (
|
||||
FlightWaypointType.TARGET_GROUP_LOC,
|
||||
FlightWaypointType.TARGET_POINT,
|
||||
FlightWaypointType.TARGET_SHIP,
|
||||
)
|
||||
FlightWaypointType.TARGET_GROUP_LOC,
|
||||
FlightWaypointType.TARGET_POINT,
|
||||
FlightWaypointType.TARGET_SHIP,
|
||||
)
|
||||
|
||||
|
||||
# TODO: Get radio information for all the special cases.
|
||||
def get_fallback_channel(unit_type: UnitType) -> RadioFrequency:
|
||||
@ -731,11 +732,14 @@ class AircraftConflictGenerator:
|
||||
group.load_loadout(payload_name)
|
||||
if not group.units[0].pylons and for_task == RunwayAttack:
|
||||
if PinpointStrike in db.PLANE_PAYLOAD_OVERRIDES[unit_type]:
|
||||
logging.warning("No loadout for \"Runway Attack\" for the {}, defaulting to Strike loadout".format(str(unit_type)))
|
||||
logging.warning(
|
||||
"No loadout for \"Runway Attack\" for the {}, defaulting to Strike loadout".format(
|
||||
str(unit_type)))
|
||||
payload_name = db.PLANE_PAYLOAD_OVERRIDES[unit_type][PinpointStrike]
|
||||
group.load_loadout(payload_name)
|
||||
did_load_loadout = True
|
||||
logging.info("Loaded overridden payload for {} - {} for task {}".format(unit_type, payload_name, for_task))
|
||||
logging.info(
|
||||
"Loaded overridden payload for {} - {} for task {}".format(unit_type, payload_name, for_task))
|
||||
|
||||
if not did_load_loadout:
|
||||
group.load_task_default_loadout(for_task)
|
||||
@ -995,7 +999,7 @@ class AircraftConflictGenerator:
|
||||
|
||||
group = self._generate_at_airport(
|
||||
name=namegen.next_aircraft_name(country, control_point.id,
|
||||
flight),
|
||||
flight),
|
||||
side=country,
|
||||
unit_type=aircraft,
|
||||
count=1,
|
||||
@ -1058,7 +1062,7 @@ class AircraftConflictGenerator:
|
||||
trigger.add_condition(
|
||||
CoalitionHasAirdrome(coalition, flight.from_cp.id))
|
||||
|
||||
def generate_planned_flight(self, cp, country, flight:Flight):
|
||||
def generate_planned_flight(self, cp, country, flight: Flight):
|
||||
name = namegen.next_aircraft_name(country, cp.id, flight)
|
||||
try:
|
||||
if flight.start_type == "In Flight":
|
||||
@ -1249,6 +1253,17 @@ class AircraftConflictGenerator:
|
||||
roe=OptROE.Values.OpenFire,
|
||||
restrict_jettison=True)
|
||||
|
||||
def configure_awacs(
|
||||
self, group: FlyingGroup, package: Package, flight: Flight,
|
||||
dynamic_runways: Dict[str, RunwayData]) -> None:
|
||||
group.task = AWACS.name
|
||||
self._setup_group(group, AWACS, package, flight, dynamic_runways)
|
||||
self.configure_behavior(
|
||||
group,
|
||||
react_on_threat=OptReactOnThreat.Values.EvadeFire,
|
||||
roe=OptROE.Values.WeaponHold,
|
||||
restrict_jettison=True)
|
||||
|
||||
def configure_escort(self, group: FlyingGroup, package: Package,
|
||||
flight: Flight,
|
||||
dynamic_runways: Dict[str, RunwayData]) -> None:
|
||||
@ -1274,6 +1289,8 @@ class AircraftConflictGenerator:
|
||||
self.configure_cap(group, package, flight, dynamic_runways)
|
||||
elif flight_type == FlightType.SWEEP:
|
||||
self.configure_sweep(group, package, flight, dynamic_runways)
|
||||
elif flight_type == FlightType.AEWC:
|
||||
self.configure_awacs(group, package, flight, dynamic_runways)
|
||||
elif flight_type in [FlightType.CAS, FlightType.BAI]:
|
||||
self.configure_cas(group, package, flight, dynamic_runways)
|
||||
elif flight_type == FlightType.DEAD:
|
||||
@ -1326,8 +1343,8 @@ class AircraftConflictGenerator:
|
||||
filtered_points = [
|
||||
point for idx, point in enumerate(filtered_points) if (
|
||||
point.waypoint_type not in TARGET_WAYPOINTS or idx == keep_target[0]
|
||||
)
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
for idx, point in enumerate(filtered_points):
|
||||
PydcsWaypointBuilder.for_waypoint(
|
||||
@ -1458,8 +1475,8 @@ class PydcsWaypointBuilder:
|
||||
If the flight is a player controlled Viggen flight, no TOT should be set on any waypoint except actual target waypoints.
|
||||
"""
|
||||
if (
|
||||
(self.flight.client_count > 0 and self.flight.unit_type == AJS37) and
|
||||
(self.waypoint.waypoint_type not in TARGET_WAYPOINTS)
|
||||
(self.flight.client_count > 0 and self.flight.unit_type == AJS37) and
|
||||
(self.waypoint.waypoint_type not in TARGET_WAYPOINTS)
|
||||
):
|
||||
return True
|
||||
else:
|
||||
@ -1622,12 +1639,12 @@ class SeadIngressBuilder(PydcsWaypointBuilder):
|
||||
tgroup = self.mission.find_group(target_group.group_name)
|
||||
if tgroup is not None:
|
||||
waypoint.add_task(EngageTargetsInZone(
|
||||
position=tgroup.position,
|
||||
radius=int(nautical_miles(30).meters),
|
||||
targets=[
|
||||
Targets.All.GroundUnits.AirDefence,
|
||||
])
|
||||
)
|
||||
position=tgroup.position,
|
||||
radius=int(nautical_miles(30).meters),
|
||||
targets=[
|
||||
Targets.All.GroundUnits.AirDefence,
|
||||
])
|
||||
)
|
||||
else:
|
||||
logging.error(f"Could not find group for DEAD mission {target_group.group_name}")
|
||||
self.register_special_waypoints(self.waypoint.targets)
|
||||
|
||||
@ -174,6 +174,7 @@ class Package:
|
||||
FlightType.TARCAP,
|
||||
FlightType.BARCAP,
|
||||
FlightType.SWEEP,
|
||||
FlightType.AEWC,
|
||||
FlightType.ESCORT,
|
||||
]
|
||||
for task in task_priorities:
|
||||
|
||||
@ -12,8 +12,8 @@ from dcs.helicopters import (
|
||||
OH_58D,
|
||||
SA342L,
|
||||
SA342M,
|
||||
SH_60B,
|
||||
UH_1H,
|
||||
SH_60B
|
||||
)
|
||||
from dcs.planes import (
|
||||
AJS37,
|
||||
@ -22,11 +22,14 @@ from dcs.planes import (
|
||||
A_10C,
|
||||
A_10C_2,
|
||||
A_20G,
|
||||
A_50,
|
||||
B_17G,
|
||||
B_1B,
|
||||
B_52H,
|
||||
Bf_109K_4,
|
||||
C_101CC,
|
||||
E_2C,
|
||||
E_3A,
|
||||
FA_18C_hornet,
|
||||
FW_190A8,
|
||||
FW_190D9,
|
||||
@ -40,9 +43,11 @@ from dcs.planes import (
|
||||
F_4E,
|
||||
F_5E_3,
|
||||
F_86F_Sabre,
|
||||
I_16,
|
||||
JF_17,
|
||||
J_11A,
|
||||
Ju_88A4,
|
||||
KJ_2000,
|
||||
L_39ZA,
|
||||
MQ_9_Reaper,
|
||||
M_2000C,
|
||||
@ -83,18 +88,16 @@ from dcs.planes import (
|
||||
Tu_22M3,
|
||||
Tu_95MS,
|
||||
WingLoong_I,
|
||||
I_16
|
||||
)
|
||||
from dcs.unittype import FlyingType
|
||||
|
||||
from gen.flights.flight import FlightType
|
||||
|
||||
from pydcs_extensions.a4ec.a4ec import A_4E_C
|
||||
from pydcs_extensions.f22a.f22a import F_22A
|
||||
from pydcs_extensions.mb339.mb339 import MB_339PAN
|
||||
from pydcs_extensions.rafale.rafale import Rafale_A_S, Rafale_M, Rafale_B
|
||||
from pydcs_extensions.su57.su57 import Su_57
|
||||
from pydcs_extensions.hercules.hercules import Hercules
|
||||
from pydcs_extensions.mb339.mb339 import MB_339PAN
|
||||
from pydcs_extensions.rafale.rafale import Rafale_A_S, Rafale_B, Rafale_M
|
||||
from pydcs_extensions.su57.su57 import Su_57
|
||||
|
||||
# All aircraft lists are in priority order. Aircraft higher in the list will be
|
||||
# preferred over those lower in the list.
|
||||
@ -155,8 +158,8 @@ CAP_CAPABLE = [
|
||||
# Used for CAS (Close air support) and BAI (Battlefield Interdiction)
|
||||
CAS_CAPABLE = [
|
||||
A_10C_2,
|
||||
A_10C,
|
||||
B_1B,
|
||||
A_10C,
|
||||
F_14B,
|
||||
F_14A_135_GR,
|
||||
Su_25TM,
|
||||
@ -373,6 +376,13 @@ DRONES = [
|
||||
WingLoong_I
|
||||
]
|
||||
|
||||
AEWC_CAPABLE = [
|
||||
E_3A,
|
||||
E_2C,
|
||||
A_50,
|
||||
KJ_2000,
|
||||
]
|
||||
|
||||
|
||||
def aircraft_for_task(task: FlightType) -> List[Type[FlyingType]]:
|
||||
cap_missions = (FlightType.BARCAP, FlightType.TARCAP)
|
||||
@ -396,6 +406,8 @@ def aircraft_for_task(task: FlightType) -> List[Type[FlyingType]]:
|
||||
return STRIKE_CAPABLE
|
||||
elif task == FlightType.ESCORT:
|
||||
return CAP_CAPABLE
|
||||
elif task == FlightType.AEWC:
|
||||
return AEWC_CAPABLE
|
||||
else:
|
||||
logging.error(f"Unplannable flight type: {task}")
|
||||
return []
|
||||
|
||||
@ -20,6 +20,14 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
class FlightType(Enum):
|
||||
"""Enumeration of mission types.
|
||||
|
||||
The value of each enumeration is the name that will be shown in the UI.
|
||||
|
||||
These values are persisted to the save game as well since they are a part of
|
||||
each flight and thus a part of the ATO, so changing these values will break
|
||||
save compat.
|
||||
"""
|
||||
TARCAP = "TARCAP"
|
||||
BARCAP = "BARCAP"
|
||||
CAS = "CAS"
|
||||
@ -33,6 +41,7 @@ class FlightType(Enum):
|
||||
SWEEP = "Fighter sweep"
|
||||
OCA_RUNWAY = "OCA/Runway"
|
||||
OCA_AIRCRAFT = "OCA/Aircraft"
|
||||
AEWC = "AEW&C"
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.value
|
||||
|
||||
@ -15,6 +15,13 @@ from datetime import timedelta
|
||||
from functools import cached_property
|
||||
from typing import Iterator, List, Optional, Set, TYPE_CHECKING, Tuple
|
||||
|
||||
from dcs.planes import (
|
||||
E_3A,
|
||||
E_2C,
|
||||
A_50,
|
||||
KJ_2000
|
||||
)
|
||||
|
||||
from dcs.mapping import Point
|
||||
from dcs.unit import Unit
|
||||
from shapely.geometry import Point as ShapelyPoint
|
||||
@ -29,7 +36,7 @@ from game.theater import (
|
||||
TheaterGroundObject,
|
||||
)
|
||||
from game.theater.theatergroundobject import EwrGroundObject
|
||||
from game.utils import Distance, Speed, meters, nautical_miles
|
||||
from game.utils import Distance, Speed, feet, meters, nautical_miles
|
||||
from .closestairfields import ObjectiveDistanceCache
|
||||
from .flight import Flight, FlightType, FlightWaypoint, FlightWaypointType
|
||||
from .traveltime import GroundSpeed, TravelTime
|
||||
@ -121,7 +128,7 @@ class FlightPlan:
|
||||
failed to generate. Nevertheless, we have to defend against it.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
@cached_property
|
||||
def bingo_fuel(self) -> int:
|
||||
"""Bingo fuel value for the FlightPlan
|
||||
@ -145,7 +152,7 @@ class FlightPlan:
|
||||
"""Joker fuel value for the FlightPlan
|
||||
"""
|
||||
return self.bingo_fuel + 1000
|
||||
|
||||
|
||||
def max_distance_from(self, cp: ControlPoint) -> Distance:
|
||||
"""Returns the farthest waypoint of the flight plan from a ControlPoint.
|
||||
:arg cp The ControlPoint to measure distance from.
|
||||
@ -280,11 +287,11 @@ class LoiterFlightPlan(FlightPlan):
|
||||
travel_time = super().travel_time_between_waypoints(a, b)
|
||||
if a != self.hold:
|
||||
return travel_time
|
||||
try:
|
||||
return travel_time + self.hold_duration
|
||||
except AttributeError:
|
||||
# Save compat for 2.3.
|
||||
return travel_time + timedelta(minutes=5)
|
||||
return travel_time + self.hold_duration
|
||||
|
||||
@property
|
||||
def mission_departure_time(self) -> timedelta:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@ -542,10 +549,10 @@ class StrikeFlightPlan(FormationFlightPlan):
|
||||
@property
|
||||
def package_speed_waypoints(self) -> Set[FlightWaypoint]:
|
||||
return {
|
||||
self.ingress,
|
||||
self.egress,
|
||||
self.split,
|
||||
} | set(self.targets)
|
||||
self.ingress,
|
||||
self.egress,
|
||||
self.split,
|
||||
} | set(self.targets)
|
||||
|
||||
def speed_between_waypoints(self, a: FlightWaypoint,
|
||||
b: FlightWaypoint) -> Speed:
|
||||
@ -696,6 +703,41 @@ class SweepFlightPlan(LoiterFlightPlan):
|
||||
return self.sweep_end_time
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AwacsFlightPlan(LoiterFlightPlan):
|
||||
takeoff: FlightWaypoint
|
||||
nav_to: List[FlightWaypoint]
|
||||
nav_from: List[FlightWaypoint]
|
||||
land: FlightWaypoint
|
||||
divert: Optional[FlightWaypoint]
|
||||
|
||||
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
|
||||
yield self.takeoff
|
||||
yield from self.nav_to
|
||||
yield self.hold
|
||||
yield from self.nav_from
|
||||
yield self.land
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
|
||||
def tot_for_waypoint(self, waypoint: FlightWaypoint) -> Optional[timedelta]:
|
||||
if waypoint == self.hold:
|
||||
return self.package.time_over_target
|
||||
return None
|
||||
|
||||
@property
|
||||
def tot_waypoint(self) -> Optional[FlightWaypoint]:
|
||||
return self.hold
|
||||
|
||||
@property
|
||||
def push_time(self) -> timedelta:
|
||||
return self.package.time_over_target + self.hold_duration
|
||||
|
||||
@property
|
||||
def mission_departure_time(self) -> timedelta:
|
||||
return self.push_time
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CustomFlightPlan(FlightPlan):
|
||||
custom_waypoints: List[FlightWaypoint]
|
||||
@ -791,6 +833,8 @@ class FlightPlanBuilder:
|
||||
return self.generate_sweep(flight)
|
||||
elif task == FlightType.TARCAP:
|
||||
return self.generate_tarcap(flight)
|
||||
elif task == FlightType.AEWC:
|
||||
return self.generate_aewc(flight)
|
||||
raise PlanningError(
|
||||
f"{task} flight plan generation not implemented")
|
||||
|
||||
@ -921,6 +965,45 @@ class FlightPlanBuilder:
|
||||
FlightWaypointType.INGRESS_STRIKE,
|
||||
targets)
|
||||
|
||||
def generate_aewc(self, flight: Flight) -> AwacsFlightPlan:
|
||||
"""Generate a AWACS flight at a given location.
|
||||
|
||||
Args:
|
||||
flight: The flight to generate the flight plan for.
|
||||
"""
|
||||
location = self.package.target
|
||||
|
||||
start = self.aewc_orbit(location)
|
||||
|
||||
# As high as possible to maximize detection and on-station time.
|
||||
if flight.unit_type == E_2C:
|
||||
patrol_alt = feet(30000)
|
||||
elif flight.unit_type == E_3A:
|
||||
patrol_alt = feet(35000)
|
||||
elif flight.unit_type == A_50:
|
||||
patrol_alt = feet(33000)
|
||||
elif flight.unit_type == KJ_2000:
|
||||
patrol_alt = feet(40000)
|
||||
else:
|
||||
patrol_alt = feet(25000)
|
||||
|
||||
builder = WaypointBuilder(flight, self.game, self.is_player)
|
||||
start = builder.orbit(start, patrol_alt)
|
||||
|
||||
return AwacsFlightPlan(
|
||||
package=self.package,
|
||||
flight=flight,
|
||||
takeoff=builder.takeoff(flight.departure),
|
||||
nav_to=builder.nav_path(flight.departure.position, start.position,
|
||||
patrol_alt),
|
||||
nav_from=builder.nav_path(start.position, flight.arrival.position,
|
||||
patrol_alt),
|
||||
land=builder.land(flight.arrival),
|
||||
divert=builder.divert(flight.divert),
|
||||
hold=start,
|
||||
hold_duration=timedelta(hours=4),
|
||||
)
|
||||
|
||||
def generate_bai(self, flight: Flight) -> StrikeFlightPlan:
|
||||
"""Generates a BAI flight plan.
|
||||
|
||||
@ -1095,6 +1178,18 @@ class FlightPlanBuilder:
|
||||
start = end.point_from_heading(heading - 180, diameter)
|
||||
return start, end
|
||||
|
||||
@staticmethod
|
||||
def aewc_orbit(location: MissionTarget) -> Point:
|
||||
closest_airfield = location
|
||||
# TODO: This is a heading to itself.
|
||||
# Place this either over the target or as close as possible outside the
|
||||
# threat zone: https://github.com/Khopa/dcs_liberation/issues/842.
|
||||
heading = location.position.heading_between_point(closest_airfield.position)
|
||||
return location.position.point_from_heading(
|
||||
heading,
|
||||
5000
|
||||
)
|
||||
|
||||
def racetrack_for_frontline(self, origin: Point,
|
||||
front_line: FrontLine) -> Tuple[Point, Point]:
|
||||
ally_cp, enemy_cp = front_line.control_points
|
||||
|
||||
@ -366,6 +366,26 @@ class WaypointBuilder:
|
||||
return (self.race_track_start(start, altitude),
|
||||
self.race_track_end(end, altitude))
|
||||
|
||||
@staticmethod
|
||||
def orbit(start: Point, altitude: Distance) -> FlightWaypoint:
|
||||
"""Creates an circular orbit point.
|
||||
|
||||
Args:
|
||||
start: Position of the waypoint.
|
||||
altitude: Altitude of the racetrack.
|
||||
"""
|
||||
|
||||
waypoint = FlightWaypoint(
|
||||
FlightWaypointType.LOITER,
|
||||
start.x,
|
||||
start.y,
|
||||
altitude
|
||||
)
|
||||
waypoint.name = "ORBIT"
|
||||
waypoint.description = "Anchor and hold at this point"
|
||||
waypoint.pretty_name = "Orbit"
|
||||
return waypoint
|
||||
|
||||
@staticmethod
|
||||
def sweep_start(position: Point, altitude: Distance) -> FlightWaypoint:
|
||||
"""Creates a sweep start waypoint.
|
||||
|
||||
@ -47,6 +47,9 @@ class QAircraftTypeSelector(QComboBox):
|
||||
elif mission_type in [FlightType.OCA_RUNWAY]:
|
||||
if aircraft in gen.flights.ai_flight_planner_db.RUNWAY_ATTACK_CAPABLE:
|
||||
self.addItem(f"{db.unit_get_expanded_info(self.country, aircraft, 'name')}", userData=aircraft)
|
||||
elif mission_type in [FlightType.AEWC]:
|
||||
if aircraft in gen.flights.ai_flight_planner_db.AEWC_CAPABLE:
|
||||
self.addItem(f"{db.unit_get_expanded_info(self.country, aircraft, 'name')}", userData=aircraft)
|
||||
current_aircraft_index = self.findData(current_aircraft)
|
||||
if current_aircraft_index != -1:
|
||||
self.setCurrentIndex(current_aircraft_index)
|
||||
|
||||
@ -12,7 +12,7 @@ from PySide2.QtWidgets import (
|
||||
QVBoxLayout,
|
||||
QWidget,
|
||||
)
|
||||
from dcs.task import CAP, CAS
|
||||
from dcs.task import CAP, CAS, AWACS
|
||||
from dcs.unittype import FlyingType, UnitType
|
||||
|
||||
from game import db
|
||||
@ -45,7 +45,7 @@ class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
|
||||
def init_ui(self):
|
||||
main_layout = QVBoxLayout()
|
||||
|
||||
tasks = [CAP, CAS]
|
||||
tasks = [CAP, CAS, AWACS]
|
||||
|
||||
scroll_content = QWidget()
|
||||
task_box_layout = QGridLayout()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user