Move Flight and its related components out of gen.

This commit is contained in:
Dan Albert
2021-09-13 23:23:59 -07:00
parent 52b9656a1a
commit be69d17345
87 changed files with 587 additions and 551 deletions

4
game/ato/__init__.py Normal file
View File

@@ -0,0 +1,4 @@
from .flight import Flight
from .flighttype import FlightType
from .flightwaypoint import FlightWaypoint
from .package import Package

View File

@@ -0,0 +1,24 @@
from dataclasses import dataclass, field
from typing import List
from game.ato.package import Package
@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()

107
game/ato/flight.py Normal file
View File

@@ -0,0 +1,107 @@
from __future__ import annotations
from typing import Optional, List, TYPE_CHECKING
from gen.flights.loadouts import Loadout
from .flightroster import FlightRoster
if TYPE_CHECKING:
from game.dcs.aircrafttype import AircraftType
from game.squadrons import Squadron, Pilot
from game.theater import ControlPoint, MissionTarget
from game.transfers import TransferOrder
from .flighttype import FlightType
from .flightwaypoint import FlightWaypoint
from .package import Package
class Flight:
def __init__(
self,
package: Package,
country: str,
squadron: Squadron,
count: int,
flight_type: FlightType,
start_type: str,
divert: Optional[ControlPoint],
custom_name: Optional[str] = None,
cargo: Optional[TransferOrder] = None,
roster: Optional[FlightRoster] = None,
) -> None:
self.package = package
self.country = country
self.squadron = squadron
self.squadron.claim_inventory(count)
if roster is None:
self.roster = FlightRoster(self.squadron, initial_size=count)
else:
self.roster = roster
self.departure = self.squadron.location
self.arrival = self.squadron.arrival
self.divert = divert
self.flight_type = flight_type
# TODO: Replace with FlightPlan.
self.targets: List[MissionTarget] = []
self.loadout = Loadout.default_for(self)
self.start_type = start_type
self.use_custom_loadout = False
self.custom_name = custom_name
# Only used by transport missions.
self.cargo = cargo
# Will be replaced with a more appropriate FlightPlan by
# FlightPlanBuilder, but an empty flight plan the flight begins with an
# empty flight plan.
from gen.flights.flightplan import FlightPlan, CustomFlightPlan
self.flight_plan: FlightPlan = CustomFlightPlan(
package=package, flight=self, custom_waypoints=[]
)
@property
def count(self) -> int:
return self.roster.max_size
@property
def client_count(self) -> int:
return self.roster.player_count
@property
def unit_type(self) -> AircraftType:
return self.squadron.aircraft
@property
def from_cp(self) -> ControlPoint:
return self.departure
@property
def points(self) -> List[FlightWaypoint]:
return self.flight_plan.waypoints[1:]
def resize(self, new_size: int) -> None:
self.squadron.claim_inventory(new_size - self.count)
self.roster.resize(new_size)
def set_pilot(self, index: int, pilot: Optional[Pilot]) -> None:
self.roster.set_pilot(index, pilot)
@property
def missing_pilots(self) -> int:
return self.roster.missing_pilots
def return_pilots_and_aircraft(self) -> None:
self.roster.clear()
self.squadron.claim_inventory(-self.count)
def __repr__(self) -> str:
if self.custom_name:
return f"{self.custom_name} {self.count} x {self.unit_type}"
return f"[{self.flight_type}] {self.count} x {self.unit_type}"
def __str__(self) -> str:
if self.custom_name:
return f"{self.custom_name} {self.count} x {self.unit_type}"
return f"[{self.flight_type}] {self.count} x {self.unit_type}"

49
game/ato/flightroster.py Normal file
View File

@@ -0,0 +1,49 @@
from __future__ import annotations
from typing import Optional, TYPE_CHECKING
if TYPE_CHECKING:
from game.squadrons import Squadron, Pilot
class FlightRoster:
def __init__(self, squadron: Squadron, initial_size: int = 0) -> None:
self.squadron = squadron
self.pilots: list[Optional[Pilot]] = []
self.resize(initial_size)
@property
def max_size(self) -> int:
return len(self.pilots)
@property
def player_count(self) -> int:
return len([p for p in self.pilots if p is not None and p.player])
@property
def missing_pilots(self) -> int:
return len([p for p in self.pilots if p is None])
def resize(self, new_size: int) -> None:
if self.max_size > new_size:
self.squadron.return_pilots(
[p for p in self.pilots[new_size:] if p is not None]
)
self.pilots = self.pilots[:new_size]
return
self.pilots.extend(
[
self.squadron.claim_available_pilot()
for _ in range(new_size - self.max_size)
]
)
def set_pilot(self, index: int, pilot: Optional[Pilot]) -> None:
if pilot is not None:
self.squadron.claim_pilot(pilot)
if (current_pilot := self.pilots[index]) is not None:
self.squadron.return_pilot(current_pilot)
self.pilots[index] = pilot
def clear(self) -> None:
self.squadron.return_pilots([p for p in self.pilots if p is not None])

90
game/ato/flighttype.py Normal file
View File

@@ -0,0 +1,90 @@
from __future__ import annotations
from enum import Enum
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.
When adding new mission types to this list, you will also need to update:
* flightplan.py: Add waypoint population in generate_flight_plan. Add a new flight
plan type if necessary, though most are a subclass of StrikeFlightPlan.
* aircraft.py: Add a configuration method and call it in setup_flight_group. This is
responsible for configuring waypoint 0 actions like setting ROE, threat reaction,
and mission abort parameters (winchester, bingo, etc).
* 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.
You may also need to update:
* flightwaypointtype.py: Add a new waypoint type if necessary. Most mission types
will need these, as aircraft.py uses the ingress point type to specialize AI
tasks, and non-strike-like missions will need more specialized control.
* ai_flight_planner.py: Use the new mission type in propose_missions so the AI will
plan the new mission type.
* FlightType.is_air_to_air and FlightType.is_air_to_ground: If the new mission type
fits either of these categories, update those methods accordingly.
"""
TARCAP = "TARCAP"
BARCAP = "BARCAP"
CAS = "CAS"
INTERCEPTION = "Intercept"
STRIKE = "Strike"
ANTISHIP = "Anti-ship"
SEAD = "SEAD"
DEAD = "DEAD"
ESCORT = "Escort"
BAI = "BAI"
SWEEP = "Fighter sweep"
OCA_RUNWAY = "OCA/Runway"
OCA_AIRCRAFT = "OCA/Aircraft"
AEWC = "AEW&C"
TRANSPORT = "Transport"
SEAD_ESCORT = "SEAD Escort"
REFUELING = "Refueling"
FERRY = "Ferry"
def __str__(self) -> str:
return self.value
@classmethod
def from_name(cls, name: str) -> FlightType:
for entry in cls:
if name == entry.value:
return entry
raise KeyError(f"No FlightType with name {name}")
@property
def is_air_to_air(self) -> bool:
return self in {
FlightType.TARCAP,
FlightType.BARCAP,
FlightType.INTERCEPTION,
FlightType.ESCORT,
FlightType.SWEEP,
}
@property
def is_air_to_ground(self) -> bool:
return self in {
FlightType.CAS,
FlightType.STRIKE,
FlightType.ANTISHIP,
FlightType.SEAD,
FlightType.DEAD,
FlightType.BAI,
FlightType.OCA_RUNWAY,
FlightType.OCA_AIRCRAFT,
FlightType.SEAD_ESCORT,
}

View File

@@ -0,0 +1,92 @@
from datetime import timedelta
from typing import Optional, Sequence, Union
from dcs import Point
from dcs.point import MovingPoint, PointAction
from dcs.unit import Unit
from game.theater import ControlPoint, MissionTarget
from game.utils import Distance, meters
from game.ato.flightwaypointtype import FlightWaypointType
class FlightWaypoint:
def __init__(
self,
waypoint_type: FlightWaypointType,
x: float,
y: float,
alt: Distance = meters(0),
control_point: Optional[ControlPoint] = None,
) -> None:
"""Creates a flight waypoint.
Args:
waypoint_type: The waypoint type.
x: X coordinate of the waypoint.
y: Y coordinate of the waypoint.
alt: Altitude of the waypoint. By default this is MSL, but it can be
changed to AGL by setting alt_type to "RADIO"
control_point: The control point to associate with this waypoint. Needed for
landing points.
"""
self.waypoint_type = waypoint_type
self.x = x
self.y = y
self.alt = alt
self.control_point = control_point
self.alt_type = "BARO"
self.name = ""
# TODO: Merge with pretty_name.
# Only used in the waypoint list in the flight edit page. No sense
# having three names. A short and long form is enough.
self.description = ""
self.targets: Sequence[Union[MissionTarget, Unit]] = []
self.obj_name = ""
self.pretty_name = ""
self.only_for_player = False
self.flyover = False
# The minimum amount of fuel remaining at this waypoint in pounds.
self.min_fuel: Optional[float] = None
# These are set very late by the air conflict generator (part of mission
# generation). We do it late so that we don't need to propagate changes
# to waypoint times whenever the player alters the package TOT or the
# flight's offset in the UI.
self.tot: Optional[timedelta] = None
self.departure_time: Optional[timedelta] = None
@property
def position(self) -> Point:
return Point(self.x, self.y)
@classmethod
def from_pydcs(cls, point: MovingPoint, from_cp: ControlPoint) -> "FlightWaypoint":
waypoint = FlightWaypoint(
FlightWaypointType.NAV,
point.position.x,
point.position.y,
meters(point.alt),
)
waypoint.alt_type = point.alt_type
# Other actions exist... but none of them *should* be the first
# waypoint for a flight.
waypoint.waypoint_type = {
PointAction.TurningPoint: FlightWaypointType.NAV,
PointAction.FlyOverPoint: FlightWaypointType.NAV,
PointAction.FromParkingArea: FlightWaypointType.TAKEOFF,
PointAction.FromParkingAreaHot: FlightWaypointType.TAKEOFF,
PointAction.FromRunway: FlightWaypointType.TAKEOFF,
PointAction.FromGroundArea: FlightWaypointType.TAKEOFF,
PointAction.FromGroundAreaHot: FlightWaypointType.TAKEOFF,
}[point.action]
if waypoint.waypoint_type == FlightWaypointType.NAV:
waypoint.name = "NAV"
waypoint.pretty_name = "Nav"
waypoint.description = "Nav"
else:
waypoint.name = "TAKEOFF"
waypoint.pretty_name = "Takeoff"
waypoint.description = "Takeoff"
waypoint.description = f"Takeoff from {from_cp.name}"
return waypoint

View File

@@ -0,0 +1,47 @@
from enum import Enum
class FlightWaypointType(Enum):
"""Enumeration of waypoint types.
The value of the enum has no meaning but should remain stable to prevent breaking
save game compatibility.
When adding a new waypoint type, you will also need to update:
* waypointbuilder.py: Add a builder to simplify construction of the new waypoint
type unless the new waypoint type will be a parameter to an existing builder
method (such as how escort ingress waypoints work).
* aircraft.py: Associate AI actions with the new waypoint type by subclassing
PydcsWaypointBuilder and using it in PydcsWaypointBuilder.for_waypoint.
"""
TAKEOFF = 0 # Take off point
ASCEND_POINT = 1 # Ascension point after take off
PATROL = 2 # Patrol point
PATROL_TRACK = 3 # Patrol race track
NAV = 4 # Nav point
INGRESS_STRIKE = 5 # Ingress strike (For generator, means that this should have bombing on next TARGET_POINT points)
INGRESS_SEAD = 6 # Ingress sead (For generator, means that this should attack groups on TARGET_GROUP_LOC points)
INGRESS_CAS = 7 # Ingress cas (should start CAS task)
CAS = 8 # Should do CAS there
EGRESS = 9 # Should stop attack
DESCENT_POINT = 10 # Should start descending to pattern alt
LANDING_POINT = 11 # Should land there
TARGET_POINT = 12 # A target building or static object, position
TARGET_GROUP_LOC = 13 # A target group approximate location
TARGET_SHIP = 14 # Unused.
CUSTOM = 15 # User waypoint (no specific behaviour)
JOIN = 16
SPLIT = 17
LOITER = 18
INGRESS_ESCORT = 19
INGRESS_DEAD = 20
INGRESS_SWEEP = 21
INGRESS_BAI = 22
DIVERT = 23
INGRESS_OCA_RUNWAY = 24
INGRESS_OCA_AIRCRAFT = 25
PICKUP = 26
DROP_OFF = 27
BULLSEYE = 28

183
game/ato/package.py Normal file
View File

@@ -0,0 +1,183 @@
import logging
from collections import defaultdict
from dataclasses import dataclass, field
from datetime import timedelta
from typing import List, Optional, Dict
from game.ato import Flight, FlightType
from game.ato.packagewaypoints import PackageWaypoints
from game.theater import MissionTarget
from game.utils import Speed
from gen.flights.flightplan import FormationFlightPlan
from gen.flights.traveltime import TotEstimator
@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)
delay: int = field(default=0)
#: True if the package ToT should be reset to ASAP whenever the player makes
#: a change. This is really a UI property rather than a game property, but
#: we want it to persist in the save.
auto_asap: bool = field(default=False)
#: Desired TOT as an offset from mission start.
time_over_target: timedelta = field(default=timedelta())
waypoints: Optional[PackageWaypoints] = field(default=None)
@property
def has_players(self) -> bool:
return any(flight.client_count for flight in self.flights)
@property
def formation_speed(self) -> Optional[Speed]:
"""The speed of the package when in formation.
If none of the flights in the package will join a formation, this
returns None. This is nto uncommon, since only strike-like (strike,
DEAD, anti-ship, BAI, etc.) flights and their escorts fly in formation.
Others (CAP and CAS, currently) will coordinate in target timing but
fly their own path to the target.
"""
speeds = []
for flight in self.flights:
if isinstance(flight.flight_plan, FormationFlightPlan):
speeds.append(flight.flight_plan.best_flight_formation_speed)
if not speeds:
return None
return min(speeds)
# TODO: Should depend on the type of escort.
# SEAD might be able to leave before CAP.
@property
def escort_start_time(self) -> Optional[timedelta]:
times = []
for flight in self.flights:
waypoint = flight.flight_plan.request_escort_at()
if waypoint is None:
continue
tot = flight.flight_plan.tot_for_waypoint(waypoint)
if tot is None:
logging.error(
f"{flight} requested escort at {waypoint} but that "
"waypoint has no TOT. It may not be escorted."
)
continue
times.append(tot)
if times:
return min(times)
return None
@property
def escort_end_time(self) -> Optional[timedelta]:
times = []
for flight in self.flights:
waypoint = flight.flight_plan.dismiss_escort_at()
if waypoint is None:
continue
tot = flight.flight_plan.tot_for_waypoint(waypoint)
if tot is None:
tot = flight.flight_plan.depart_time_for_waypoint(waypoint)
if tot is None:
logging.error(
f"{flight} dismissed escort at {waypoint} but that "
"waypoint has no TOT or departure time. It may not be "
"escorted."
)
continue
times.append(tot)
if times:
return max(times)
return None
@property
def mission_departure_time(self) -> Optional[timedelta]:
times = []
for flight in self.flights:
times.append(flight.flight_plan.mission_departure_time)
if times:
return max(times)
return None
def set_tot_asap(self) -> None:
self.time_over_target = TotEstimator(self).earliest_tot()
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)
if not self.flights:
self.waypoints = None
@property
def primary_task(self) -> Optional[FlightType]:
if not self.flights:
return None
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. This list defines the
# priority order for package task names. The package's primary task will be the
# first task in this list that matches a flight in the package.
tasks_by_priority = [
FlightType.CAS,
FlightType.STRIKE,
FlightType.ANTISHIP,
FlightType.OCA_AIRCRAFT,
FlightType.OCA_RUNWAY,
FlightType.BAI,
FlightType.DEAD,
FlightType.TRANSPORT,
FlightType.SEAD,
FlightType.TARCAP,
FlightType.BARCAP,
FlightType.AEWC,
FlightType.FERRY,
FlightType.REFUELING,
FlightType.SWEEP,
FlightType.ESCORT,
]
for task in tasks_by_priority:
if flight_counts[task]:
return task
# 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
@property
def package_description(self) -> str:
"""Generates a package description based on flight composition."""
task = self.primary_task
if task is None:
return "No mission"
oca_strike_types = {FlightType.OCA_AIRCRAFT, FlightType.OCA_RUNWAY}
if task in oca_strike_types:
return "OCA Strike"
return str(task)
def __hash__(self) -> int:
# TODO: Far from perfect. Number packages?
return hash(self.target.name)

View File

@@ -0,0 +1,10 @@
from dataclasses import dataclass
from dcs import Point
@dataclass(frozen=True)
class PackageWaypoints:
join: Point
ingress: Point
split: Point

14
game/ato/task.py Normal file
View File

@@ -0,0 +1,14 @@
from dataclasses import dataclass
from game.ato import FlightType
@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

View File

@@ -5,7 +5,7 @@ from collections import defaultdict
from dataclasses import dataclass
from typing import Any, TYPE_CHECKING, Union
from gen.flights.flight import FlightType
from game.ato.flighttype import FlightType
from game.theater.controlpoint import ControlPoint
if TYPE_CHECKING:

View File

@@ -6,7 +6,7 @@ from typing import Optional, TYPE_CHECKING
from game.squadrons import Squadron
from game.squadrons.squadrondef import SquadronDef
from game.squadrons.squadrondefloader import SquadronDefLoader
from gen.flights.flight import FlightType
from ..ato.flighttype import FlightType
from .campaignairwingconfig import CampaignAirWingConfig, SquadronConfig
from .squadrondefgenerator import SquadronDefGenerator
from ..dcs.aircrafttype import AircraftType

View File

@@ -9,7 +9,7 @@ from game.squadrons.operatingbases import OperatingBases
from game.squadrons.squadrondef import SquadronDef
from game.theater import ControlPoint
from gen.flights.ai_flight_planner_db import aircraft_for_task, tasks_for_aircraft
from gen.flights.flight import FlightType
from game.ato.flighttype import FlightType
if TYPE_CHECKING:
from game.coalition import Coalition

View File

@@ -24,7 +24,7 @@ from game.factions.faction import Faction
from game.procurement import AircraftProcurementRequest, ProcurementAi
from game.theater.bullseye import Bullseye
from game.theater.transitnetwork import TransitNetwork, TransitNetworkBuilder
from gen.ato import AirTaskingOrder
from game.ato.airtaaskingorder import AirTaskingOrder
class Coalition:

View File

@@ -3,7 +3,7 @@ from enum import Enum, auto
from typing import Optional
from game.theater import MissionTarget
from gen.flights.flight import FlightType
from game.ato.flighttype import FlightType
class EscortType(Enum):

View File

@@ -7,7 +7,7 @@ from datetime import timedelta
from typing import Iterator, Dict, TYPE_CHECKING
from game.theater import MissionTarget
from gen.flights.flight import FlightType
from game.ato.flighttype import FlightType
from gen.flights.traveltime import TotEstimator
if TYPE_CHECKING:

View File

@@ -3,10 +3,9 @@ from __future__ import annotations
from typing import Optional, TYPE_CHECKING
from game.utils import nautical_miles
from gen.ato import Package
from ..ato.package import Package
from game.theater import MissionTarget, OffMapSpawn, ControlPoint
from gen.flights.flight import Flight
from ..ato.flight import Flight
if TYPE_CHECKING:
from game.dcs.aircrafttype import AircraftType

View File

@@ -13,9 +13,10 @@ from game.settings import Settings
from game.squadrons import AirWing
from game.theater import ConflictTheater
from game.threatzones import ThreatZones
from gen.ato import AirTaskingOrder, Package
from game.ato.airtaaskingorder import AirTaskingOrder
from game.ato.package import Package
from gen.flights.closestairfields import ObjectiveDistanceCache
from gen.flights.flight import FlightType
from game.ato.flighttype import FlightType
from gen.flights.flightplan import FlightPlanBuilder
if TYPE_CHECKING:

View File

@@ -15,8 +15,8 @@ from game.settings import AutoAtoBehavior
from game.theater import MissionTarget
from game.theater.theatergroundobject import IadsGroundObject, NavalGroundObject
from game.utils import Distance, meters
from gen.ato import Package
from gen.flights.flight import FlightType
from game.ato.package import Package
from game.ato.flighttype import FlightType
if TYPE_CHECKING:
from game.coalition import Coalition

View File

@@ -5,7 +5,7 @@ from dataclasses import dataclass
from game.commander.tasks.packageplanningtask import PackagePlanningTask
from game.commander.theaterstate import TheaterState
from game.theater import MissionTarget
from gen.flights.flight import FlightType
from game.ato.flighttype import FlightType
@dataclass

View File

@@ -6,7 +6,7 @@ from game.commander.missionproposals import EscortType
from game.commander.tasks.packageplanningtask import PackagePlanningTask
from game.commander.theaterstate import TheaterState
from game.theater.theatergroundobject import NavalGroundObject
from gen.flights.flight import FlightType
from game.ato.flighttype import FlightType
@dataclass

View File

@@ -5,7 +5,7 @@ from dataclasses import dataclass
from game.commander.tasks.packageplanningtask import PackagePlanningTask
from game.commander.theaterstate import TheaterState
from game.transfers import CargoShip
from gen.flights.flight import FlightType
from game.ato.flighttype import FlightType
@dataclass

View File

@@ -5,7 +5,7 @@ from dataclasses import dataclass
from game.commander.tasks.packageplanningtask import PackagePlanningTask
from game.commander.theaterstate import TheaterState
from game.theater.theatergroundobject import VehicleGroupGroundObject
from gen.flights.flight import FlightType
from game.ato.flighttype import FlightType
@dataclass

View File

@@ -5,7 +5,7 @@ from dataclasses import dataclass
from game.commander.tasks.packageplanningtask import PackagePlanningTask
from game.commander.theaterstate import TheaterState
from game.theater import ControlPoint
from gen.flights.flight import FlightType
from game.ato.flighttype import FlightType
@dataclass

View File

@@ -5,7 +5,7 @@ from dataclasses import dataclass
from game.commander.tasks.packageplanningtask import PackagePlanningTask
from game.commander.theaterstate import TheaterState
from game.theater import FrontLine
from gen.flights.flight import FlightType
from game.ato.flighttype import FlightType
@dataclass

View File

@@ -6,7 +6,7 @@ from game.commander.tasks.packageplanningtask import PackagePlanningTask
from game.commander.theaterstate import TheaterState
from game.data.doctrine import Doctrine
from game.transfers import Convoy
from gen.flights.flight import FlightType
from game.ato.flighttype import FlightType
@dataclass

View File

@@ -6,7 +6,7 @@ from game.commander.missionproposals import EscortType
from game.commander.tasks.packageplanningtask import PackagePlanningTask
from game.commander.theaterstate import TheaterState
from game.theater.theatergroundobject import IadsGroundObject
from gen.flights.flight import FlightType
from game.ato.flighttype import FlightType
@dataclass

View File

@@ -5,7 +5,7 @@ from dataclasses import dataclass
from game.commander.tasks.packageplanningtask import PackagePlanningTask
from game.commander.theaterstate import TheaterState
from game.theater import ControlPoint
from gen.flights.flight import FlightType
from game.ato.flighttype import FlightType
@dataclass

View File

@@ -5,7 +5,7 @@ from dataclasses import dataclass
from game.commander.tasks.packageplanningtask import PackagePlanningTask
from game.commander.theaterstate import TheaterState
from game.theater import MissionTarget
from gen.flights.flight import FlightType
from game.ato.flighttype import FlightType
@dataclass

View File

@@ -6,7 +6,7 @@ from typing import Any
from game.commander.tasks.packageplanningtask import PackagePlanningTask
from game.commander.theaterstate import TheaterState
from game.theater.theatergroundobject import TheaterGroundObject
from gen.flights.flight import FlightType
from game.ato.flighttype import FlightType
@dataclass

View File

@@ -31,7 +31,7 @@ from game.unitmap import (
UnitMap,
FlyingUnit,
)
from gen.flights.flight import Flight
from game.ato.flight import Flight
if TYPE_CHECKING:
from game import Game

View File

@@ -10,7 +10,7 @@ from game import persistency
from game.debriefing import Debriefing
from game.operation.operation import Operation
from game.theater import ControlPoint
from gen.ato import AirTaskingOrder
from ..ato.airtaaskingorder import AirTaskingOrder
from gen.ground_forces.combat_stance import CombatStance
from ..unitmap import UnitMap

View File

@@ -6,11 +6,11 @@ import shapely.ops
from dcs import Point
from shapely.geometry import Point as ShapelyPoint, Polygon, MultiPolygon
from game.theater import ConflictTheater
from game.utils import nautical_miles
if TYPE_CHECKING:
from game.coalition import Coalition
from game.theater import ConflictTheater
class HoldZoneGeometry:

View File

@@ -18,10 +18,8 @@ from faker import Faker
from game.models.game_stats import GameStats
from game.plugins import LuaPluginManager
from gen import naming
from gen.ato import AirTaskingOrder
from gen.conflictgen import Conflict
from gen.flights.closestairfields import ObjectiveDistanceCache
from gen.flights.flight import FlightType
from .ato.flighttype import FlightType
from gen.ground_forces.ai_ground_planner import GroundPlanner
from . import persistency
from .campaignloader import CampaignAirWingConfig
@@ -31,18 +29,20 @@ from .event.event import Event
from .event.frontlineattack import FrontlineAttackEvent
from .factions.faction import Faction
from .infos.information import Information
from .navmesh import NavMesh
from .profiling import logged_duration
from .settings import Settings
from .theater import ConflictTheater, ControlPoint
from .theater.bullseye import Bullseye
from .theater.transitnetwork import TransitNetwork, TransitNetworkBuilder
from .threatzones import ThreatZones
from .unitmap import UnitMap
from .weather import Conditions, TimeOfDay
if TYPE_CHECKING:
from gen.conflictgen import Conflict
from .ato.airtaaskingorder import AirTaskingOrder
from .navmesh import NavMesh
from .squadrons import AirWing
from .threatzones import ThreatZones
from .unitmap import UnitMap
COMMISION_UNIT_VARIETY = 4
COMMISION_LIMITS_SCALE = 1.5
@@ -453,6 +453,8 @@ class Game:
Compute the current conflict center position(s), mainly used for culling calculation
:return: List of points of interests
"""
from gen.conflictgen import Conflict
zones = []
# By default, use the existing frontline conflict position

View File

@@ -27,7 +27,7 @@ from gen.cargoshipgen import CargoShipGenerator
from gen.conflictgen import Conflict
from gen.convoygen import ConvoyGenerator
from gen.environmentgen import EnvironmentGenerator
from gen.flights.flight import FlightType
from ..ato.flighttype import FlightType
from gen.forcedoptionsgen import ForcedOptionsGenerator
from gen.groundobjectsgen import GroundObjectsGenerator
from gen.kneeboard import KneeboardGenerator

View File

@@ -11,13 +11,10 @@ from game.dcs.groundunittype import GroundUnitType
from game.factions.faction import Faction
from game.squadrons import Squadron
from game.theater import ControlPoint, MissionTarget
from game.utils import meters
from gen.flights.ai_flight_planner_db import aircraft_for_task
from gen.flights.closestairfields import ObjectiveDistanceCache
from gen.flights.flight import FlightType
if TYPE_CHECKING:
from game import Game
from game.ato import FlightType
FRONTLINE_RESERVES_FACTOR = 1.3

View File

@@ -7,11 +7,11 @@ from typing import Sequence, Iterator, TYPE_CHECKING, Optional
from game.dcs.aircrafttype import AircraftType
from gen.flights.ai_flight_planner_db import aircraft_for_task
from gen.flights.closestairfields import ObjectiveDistanceCache
from .squadron import Squadron
from ..theater import ControlPoint, MissionTarget
if TYPE_CHECKING:
from gen.flights.flight import FlightType
from ..ato.flighttype import FlightType
from .squadron import Squadron
class AirWing:

View File

@@ -12,14 +12,14 @@ from typing import (
from faker import Faker
from game.settings import AutoAtoBehavior, Settings
from gen.ato import Package
from gen.flights.flight import FlightType, Flight
from game.ato import Flight, FlightType
from gen.flights.flightplan import FlightPlanBuilder
from .pilot import Pilot, PilotStatus
from ..utils import meters
if TYPE_CHECKING:
from game import Game
from game.ato import Package
from game.coalition import Coalition
from game.dcs.aircrafttype import AircraftType
from game.theater import ControlPoint, ConflictTheater, MissionTarget

View File

@@ -16,7 +16,7 @@ from game.squadrons.operatingbases import OperatingBases
from game.squadrons.pilot import Pilot
if TYPE_CHECKING:
from gen.flights.flight import FlightType
from game.ato.flighttype import FlightType
from game.theater import ControlPoint
@@ -62,7 +62,7 @@ class SquadronDef:
@classmethod
def from_yaml(cls, path: Path) -> SquadronDef:
from gen.flights.ai_flight_planner_db import tasks_for_aircraft
from gen.flights.flight import FlightType
from game.ato import FlightType
with path.open(encoding="utf8") as squadron_file:
data = yaml.safe_load(squadron_file)

View File

@@ -56,7 +56,7 @@ from ..weather import Conditions
if TYPE_CHECKING:
from game import Game
from gen.flights.flight import FlightType
from ..ato.flighttype import FlightType
from game.squadrons.squadron import Squadron
from ..coalition import Coalition
from ..transfers import PendingTransfers
@@ -892,7 +892,7 @@ class Airfield(ControlPoint):
return self.runway_is_operational()
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
from gen.flights.flight import FlightType
from game.ato import FlightType
if not self.is_friendly(for_player):
yield from [
@@ -975,7 +975,7 @@ class NavalControlPoint(ControlPoint, ABC):
return True
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
from gen.flights.flight import FlightType
from game.ato import FlightType
if self.is_friendly(for_player):
yield from [
@@ -1063,7 +1063,7 @@ class Carrier(NavalControlPoint):
)
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
from gen.flights.flight import FlightType
from game.ato import FlightType
yield from super().mission_types(for_player)
if self.is_friendly(for_player):
@@ -1212,7 +1212,7 @@ class Fob(ControlPoint):
return RunwayStatus()
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
from gen.flights.flight import FlightType
from game.ato import FlightType
if not self.is_friendly(for_player):
yield FlightType.STRIKE

View File

@@ -2,17 +2,16 @@ from __future__ import annotations
import logging
from dataclasses import dataclass
from typing import Iterator, List, Tuple, Any
from typing import Iterator, List, Tuple, Any, TYPE_CHECKING
from dcs.mapping import Point
from gen.flights.flight import FlightType
from .controlpoint import (
ControlPoint,
MissionTarget,
)
from .controlpoint import ControlPoint, MissionTarget
from ..utils import Heading, pairwise
if TYPE_CHECKING:
from game.ato import FlightType
FRONTLINE_MIN_CP_DISTANCE = 5000
@@ -97,6 +96,8 @@ class FrontLine(MissionTarget):
return False
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
from game.ato import FlightType
yield from [
FlightType.CAS,
FlightType.AEWC,

View File

@@ -7,7 +7,7 @@ from dcs.mapping import Point
from dcs.unit import Unit
if TYPE_CHECKING:
from gen.flights.flight import FlightType
from game.ato.flighttype import FlightType
class MissionTarget:
@@ -30,7 +30,7 @@ class MissionTarget:
raise NotImplementedError
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
from gen.flights.flight import FlightType
from game.ato import FlightType
if self.is_friendly(for_player):
yield FlightType.BARCAP

View File

@@ -21,7 +21,7 @@ from ..utils import Distance, Heading, meters
if TYPE_CHECKING:
from .controlpoint import ControlPoint
from gen.flights.flight import FlightType
from ..ato.flighttype import FlightType
from .missiontarget import MissionTarget
@@ -121,7 +121,7 @@ class TheaterGroundObject(MissionTarget, Generic[GroupT]):
return self.control_point.is_friendly(to_player)
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
from gen.flights.flight import FlightType
from game.ato import FlightType
if self.is_friendly(for_player):
yield from [
@@ -352,7 +352,7 @@ class FactoryGroundObject(BuildingGroundObject):
class NavalGroundObject(TheaterGroundObject[ShipGroup]):
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
from gen.flights.flight import FlightType
from game.ato import FlightType
if not self.is_friendly(for_player):
yield FlightType.ANTISHIP
@@ -474,7 +474,7 @@ class CoastalSiteGroundObject(TheaterGroundObject[VehicleGroup]):
class IadsGroundObject(TheaterGroundObject[VehicleGroup], ABC):
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
from gen.flights.flight import FlightType
from game.ato import FlightType
if not self.is_friendly(for_player):
yield FlightType.DEAD
@@ -504,7 +504,7 @@ class SamGroundObject(IadsGroundObject):
)
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
from gen.flights.flight import FlightType
from game.ato import FlightType
if not self.is_friendly(for_player):
yield FlightType.DEAD

View File

@@ -17,7 +17,7 @@ from game.data.doctrine import Doctrine
from game.theater import ControlPoint, MissionTarget, TheaterGroundObject
from game.utils import Distance, meters, nautical_miles
from gen.flights.closestairfields import ObjectiveDistanceCache
from gen.flights.flight import Flight, FlightWaypoint
from game.ato import Flight, FlightWaypoint
if TYPE_CHECKING:
from game import Game

View File

@@ -57,10 +57,11 @@ from game.theater.transitnetwork import (
TransitNetwork,
)
from game.utils import meters, nautical_miles
from gen.ato import Package
from game.ato.package import Package
from gen.flights.ai_flight_planner_db import aircraft_for_task
from gen.flights.closestairfields import ObjectiveDistanceCache
from gen.flights.flight import Flight, FlightType
from game.ato.flighttype import FlightType
from game.ato.flight import Flight
from gen.flights.flightplan import FlightPlanBuilder
from gen.naming import namegen

View File

@@ -12,7 +12,7 @@ from game.squadrons import Pilot
from game.theater import Airfield, ControlPoint, TheaterGroundObject
from game.theater.theatergroundobject import BuildingGroundObject, SceneryGroundObject
from game.transfers import CargoShip, Convoy, TransferOrder
from gen.flights.flight import Flight
from game.ato.flight import Flight
@dataclass(frozen=True)