mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Mission planning has been completely redone. Missions are now planned by right clicking the target area and choosing "New package". A package can include multiple flights for the same objective. Right now the automatic flight planner is only fragging single-flight packages in the same manner that it used to, but that can be improved now. The air tasking order (ATO) is now the left bar of the main UI. This shows every fragged package, and the flights in the selected package. The info bar that was previously on the left is now a smaller bar at the bottom of the screen. The old "Mission Planning" button is now just the "Take Off" button. The flight plan display no longer shows enemy flight plans. That could be re-added if needed, probably with a difficulty/cheat option. Aircraft inventories have been disassociated from the Planner class. Aircraft inventories are now stored globally in the Game object. Save games made prior to this update will not be compatible do to the changes in how aircraft inventories and planned flights are stored.
118 lines
4.0 KiB
Python
118 lines
4.0 KiB
Python
"""Air Tasking Orders.
|
|
|
|
The classes of the Air Tasking Order (ATO) define all of the missions that have
|
|
been planned, and which aircraft have been assigned to them. Each planned
|
|
mission, or "package" is composed of individual flights. The package may contain
|
|
dissimilar aircraft performing different roles, but all for the same goal. For
|
|
example, the package to strike an enemy airfield may contain an escort flight,
|
|
a SEAD flight, and the strike aircraft themselves. CAP packages may contain only
|
|
the single CAP flight.
|
|
"""
|
|
from collections import defaultdict
|
|
from dataclasses import dataclass, field
|
|
import logging
|
|
from typing import Dict, List
|
|
|
|
from .flights.flight import Flight, FlightType
|
|
from theater.missiontarget import MissionTarget
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Task:
|
|
"""The main task of a flight or package."""
|
|
|
|
#: The type of task.
|
|
task_type: FlightType
|
|
|
|
#: The location of the objective.
|
|
location: str
|
|
|
|
|
|
@dataclass
|
|
class Package:
|
|
"""A mission package."""
|
|
|
|
#: The mission target. Currently can be either a ControlPoint or a
|
|
#: TheaterGroundObject (non-ControlPoint map objectives).
|
|
target: MissionTarget
|
|
|
|
#: The set of flights in the package.
|
|
flights: List[Flight] = field(default_factory=list)
|
|
|
|
def add_flight(self, flight: Flight) -> None:
|
|
"""Adds a flight to the package."""
|
|
self.flights.append(flight)
|
|
|
|
def remove_flight(self, flight: Flight) -> None:
|
|
"""Removes a flight from the package."""
|
|
self.flights.remove(flight)
|
|
|
|
@property
|
|
def package_description(self) -> str:
|
|
"""Generates a package description based on flight composition."""
|
|
if not self.flights:
|
|
return "No mission"
|
|
|
|
flight_counts: Dict[FlightType, int] = defaultdict(lambda: 0)
|
|
for flight in self.flights:
|
|
flight_counts[flight.flight_type] += 1
|
|
|
|
# The package will contain a mix of mission types, but in general we can
|
|
# determine the goal of the mission because some mission types are more
|
|
# likely to be the main task than others. For example, a package with
|
|
# only CAP flights is a CAP package, a flight with CAP and strike is a
|
|
# strike package, a flight with CAP and DEAD is a DEAD package, and a
|
|
# flight with strike and SEAD is an OCA/Strike package. The type of
|
|
# package is determined by the highest priority flight in the package.
|
|
task_priorities = [
|
|
FlightType.CAS,
|
|
FlightType.STRIKE,
|
|
FlightType.ANTISHIP,
|
|
FlightType.BAI,
|
|
FlightType.EVAC,
|
|
FlightType.TROOP_TRANSPORT,
|
|
FlightType.RECON,
|
|
FlightType.ELINT,
|
|
FlightType.DEAD,
|
|
FlightType.SEAD,
|
|
FlightType.LOGISTICS,
|
|
FlightType.INTERCEPTION,
|
|
FlightType.TARCAP,
|
|
FlightType.CAP,
|
|
FlightType.BARCAP,
|
|
FlightType.EWAR,
|
|
]
|
|
for task in task_priorities:
|
|
if flight_counts[task]:
|
|
return task.name
|
|
|
|
# If we get here, our task_priorities list above is incomplete. Log the
|
|
# issue and return the type of *any* flight in the package.
|
|
some_mission = next(iter(self.flights)).flight_type
|
|
logging.warning(f"Unhandled mission type: {some_mission}")
|
|
return some_mission.name
|
|
|
|
def __hash__(self) -> int:
|
|
# TODO: Far from perfect. Number packages?
|
|
return hash(self.target.name)
|
|
|
|
|
|
@dataclass
|
|
class AirTaskingOrder:
|
|
"""The entire ATO for one coalition."""
|
|
|
|
#: The set of all planned packages in the ATO.
|
|
packages: List[Package] = field(default_factory=list)
|
|
|
|
def add_package(self, package: Package) -> None:
|
|
"""Adds a package to the ATO."""
|
|
self.packages.append(package)
|
|
|
|
def remove_package(self, package: Package) -> None:
|
|
"""Removes a package from the ATO."""
|
|
self.packages.remove(package)
|
|
|
|
def clear(self) -> None:
|
|
"""Removes all packages from the ATO."""
|
|
self.packages.clear()
|