Build a proper type for StartType.

This commit is contained in:
Dan Albert 2021-10-22 11:29:40 -07:00
parent be69d17345
commit b0787d9a3f
8 changed files with 65 additions and 40 deletions

View File

@ -1,6 +1,7 @@
from __future__ import annotations from __future__ import annotations
from typing import Optional, List, TYPE_CHECKING from datetime import datetime, timedelta
from typing import Any, Optional, List, TYPE_CHECKING
from gen.flights.loadouts import Loadout from gen.flights.loadouts import Loadout
@ -14,6 +15,7 @@ if TYPE_CHECKING:
from .flighttype import FlightType from .flighttype import FlightType
from .flightwaypoint import FlightWaypoint from .flightwaypoint import FlightWaypoint
from .package import Package from .package import Package
from .starttype import StartType
class Flight: class Flight:
@ -24,7 +26,7 @@ class Flight:
squadron: Squadron, squadron: Squadron,
count: int, count: int,
flight_type: FlightType, flight_type: FlightType,
start_type: str, start_type: StartType,
divert: Optional[ControlPoint], divert: Optional[ControlPoint],
custom_name: Optional[str] = None, custom_name: Optional[str] = None,
cargo: Optional[TransferOrder] = None, cargo: Optional[TransferOrder] = None,

15
game/ato/starttype.py Normal file
View File

@ -0,0 +1,15 @@
from enum import Enum, unique
@unique
class StartType(Enum):
"""The start type for a Flight.
This is distinct from dcs.mission.StartType because we need a fourth state:
IN_FLIGHT.
"""
IN_FLIGHT = "In Flight"
RUNWAY = "Runway"
COLD = "Cold"
WARM = "Warm"

View File

@ -6,6 +6,7 @@ from game.utils import nautical_miles
from ..ato.package import Package from ..ato.package import Package
from game.theater import MissionTarget, OffMapSpawn, ControlPoint from game.theater import MissionTarget, OffMapSpawn, ControlPoint
from ..ato.flight import Flight from ..ato.flight import Flight
from ..ato.starttype import StartType
if TYPE_CHECKING: if TYPE_CHECKING:
from game.dcs.aircrafttype import AircraftType from game.dcs.aircrafttype import AircraftType
@ -24,7 +25,7 @@ class PackageBuilder:
air_wing: AirWing, air_wing: AirWing,
is_player: bool, is_player: bool,
package_country: str, package_country: str,
start_type: str, start_type: StartType,
asap: bool, asap: bool,
) -> None: ) -> None:
self.closest_airfields = closest_airfields self.closest_airfields = closest_airfields

View File

@ -13,6 +13,7 @@ from .choicesoption import choices_option
from .minutesoption import minutes_option from .minutesoption import minutes_option
from .optiondescription import OptionDescription, SETTING_DESCRIPTION_KEY from .optiondescription import OptionDescription, SETTING_DESCRIPTION_KEY
from .skilloption import skill_option from .skilloption import skill_option
from ..ato.starttype import StartType
@unique @unique
@ -323,12 +324,12 @@ class Settings:
"option only allows the player to wait on the ground.</strong>" "option only allows the player to wait on the ground.</strong>"
), ),
) )
default_start_type: str = choices_option( default_start_type: StartType = choices_option(
"Default start type for AI aircraft", "Default start type for AI aircraft",
page=MISSION_GENERATOR_PAGE, page=MISSION_GENERATOR_PAGE,
section=GAMEPLAY_SECTION, section=GAMEPLAY_SECTION,
choices=["Cold", "Warm", "Runway", "In Flight"], choices={v.value: v for v in StartType},
default="Cold", default=StartType.COLD,
detail=( detail=(
"Warning: Options other than Cold will significantly reduce the number of " "Warning: Options other than Cold will significantly reduce the number of "
"targets available for OCA/Aircraft missions, and OCA/Aircraft flights " "targets available for OCA/Aircraft missions, and OCA/Aircraft flights "

View File

@ -49,6 +49,7 @@ from .theatergroundobject import (
TheaterGroundObject, TheaterGroundObject,
BuildingGroundObject, BuildingGroundObject,
) )
from ..ato.starttype import StartType
from ..dcs.aircrafttype import AircraftType from ..dcs.aircrafttype import AircraftType
from ..dcs.groundunittype import GroundUnitType from ..dcs.groundunittype import GroundUnitType
from ..utils import nautical_miles from ..utils import nautical_miles
@ -681,7 +682,7 @@ class ControlPoint(MissionTarget, ABC):
self.base.set_strength_to_minimum() self.base.set_strength_to_minimum()
@property @property
def required_aircraft_start_type(self) -> Optional[str]: def required_aircraft_start_type(self) -> Optional[StartType]:
return None return None
@abstractmethod @abstractmethod
@ -1151,8 +1152,8 @@ class OffMapSpawn(ControlPoint):
return True return True
@property @property
def required_aircraft_start_type(self) -> Optional[str]: def required_aircraft_start_type(self) -> Optional[StartType]:
return "In Flight" return StartType.IN_FLIGHT
@property @property
def heading(self) -> Heading: def heading(self) -> Heading:

View File

@ -5,17 +5,16 @@ import logging
import random import random
from dataclasses import dataclass, field from dataclasses import dataclass, field
from enum import Enum from enum import Enum
from typing import Optional, TYPE_CHECKING, Any from typing import Optional, TYPE_CHECKING
from dcs.cloud_presets import Clouds as PydcsClouds from dcs.cloud_presets import Clouds as PydcsClouds
from dcs.weather import CloudPreset, Weather as PydcsWeather, Wind from dcs.weather import CloudPreset, Weather as PydcsWeather, Wind
from game.settings import Settings
from game.utils import Distance, Heading, meters, interpolate, Pressure, inches_hg from game.utils import Distance, Heading, meters, interpolate, Pressure, inches_hg
from game.theater.seasonalconditions import determine_season from game.theater.seasonalconditions import determine_season
if TYPE_CHECKING: if TYPE_CHECKING:
from game.settings import Settings
from game.theater import ConflictTheater from game.theater import ConflictTheater
from game.theater.seasonalconditions import SeasonalConditions from game.theater.seasonalconditions import SeasonalConditions

View File

@ -14,7 +14,7 @@ from dcs.condition import CoalitionHasAirdrome, TimeAfter
from dcs.country import Country from dcs.country import Country
from dcs.flyingunit import FlyingUnit from dcs.flyingunit import FlyingUnit
from dcs.mapping import Point from dcs.mapping import Point
from dcs.mission import Mission, StartType from dcs.mission import Mission, StartType as DcsStartType
from dcs.planes import ( from dcs.planes import (
AJS37, AJS37,
B_17G, B_17G,
@ -67,6 +67,7 @@ from dcs.unitgroup import FlyingGroup, ShipGroup, StaticGroup
from dcs.unittype import FlyingType from dcs.unittype import FlyingType
from game import db from game import db
from game.ato.starttype import StartType
from game.data.weapons import Pylon, WeaponType as WeaponTypeEnum from game.data.weapons import Pylon, WeaponType as WeaponTypeEnum
from game.dcs.aircrafttype import AircraftType from game.dcs.aircrafttype import AircraftType
from game.factions.faction import Faction from game.factions.faction import Faction
@ -258,19 +259,19 @@ class AircraftConflictGenerator:
return total return total
@staticmethod @staticmethod
def _start_type(start_type: str) -> StartType: def _start_type(start_type: str) -> DcsStartType:
if start_type == "Runway": if start_type == "Runway":
return StartType.Runway return DcsStartType.Runway
elif start_type == "Cold": elif start_type == "Cold":
return StartType.Cold return DcsStartType.Cold
return StartType.Warm return DcsStartType.Warm
@staticmethod @staticmethod
def _start_type_at_group( def _start_type_at_group(
start_type: str, start_type: str,
unit_type: Type[FlyingType], unit_type: Type[FlyingType],
at: Union[ShipGroup, StaticGroup], at: Union[ShipGroup, StaticGroup],
) -> StartType: ) -> DcsStartType:
group_units = at.units group_units = at.units
# Setting Su-33s starting from the non-supercarrier Kuznetsov to take off from runway # Setting Su-33s starting from the non-supercarrier Kuznetsov to take off from runway
# to work around a DCS AI issue preventing Su-33s from taking off when set to "Takeoff from ramp" (#1352) # to work around a DCS AI issue preventing Su-33s from taking off when set to "Takeoff from ramp" (#1352)
@ -279,7 +280,7 @@ class AircraftConflictGenerator:
and group_units[0] is not None and group_units[0] is not None
and group_units[0].type == KUZNECOW.id and group_units[0].type == KUZNECOW.id
): ):
return StartType.Runway return DcsStartType.Runway
else: else:
return AircraftConflictGenerator._start_type(start_type) return AircraftConflictGenerator._start_type(start_type)
@ -490,7 +491,7 @@ class AircraftConflictGenerator:
parking_slots=None, parking_slots=None,
) )
def _generate_inflight( def _generate_over_departure(
self, name: str, side: Country, flight: Flight, origin: ControlPoint self, name: str, side: Country, flight: Flight, origin: ControlPoint
) -> FlyingGroup[Any]: ) -> FlyingGroup[Any]:
assert flight.count > 0 assert flight.count > 0
@ -652,7 +653,7 @@ class AircraftConflictGenerator:
continue continue
for flight in package.flights: for flight in package.flights:
logging.info(f"Generating flight: {flight.unit_type}") logging.info(f"Generating flight: {flight.unit_type}")
group = self.generate_planned_flight(flight.from_cp, country, flight) group = self.generate_planned_flight(country, flight)
self.unit_map.add_aircraft(group, flight) self.unit_map.add_aircraft(group, flight)
self.setup_flight_group(group, package, flight, dynamic_runways) self.setup_flight_group(group, package, flight, dynamic_runways)
self.create_waypoints(group, package, flight) self.create_waypoints(group, package, flight)
@ -691,7 +692,7 @@ class AircraftConflictGenerator:
squadron, squadron,
1, 1,
FlightType.BARCAP, FlightType.BARCAP,
"Cold", StartType.COLD,
divert=None, divert=None,
) )
@ -753,14 +754,14 @@ class AircraftConflictGenerator:
coalition = self.game.coalition_for(flight.departure.captured).coalition_id coalition = self.game.coalition_for(flight.departure.captured).coalition_id
trigger.add_condition(CoalitionHasAirdrome(coalition, flight.from_cp.id)) trigger.add_condition(CoalitionHasAirdrome(coalition, flight.from_cp.id))
def generate_planned_flight( def generate_flight_at_departure(
self, cp: ControlPoint, country: Country, flight: Flight self, country: Country, flight: Flight, start_type: StartType
) -> FlyingGroup[Any]: ) -> FlyingGroup[Any]:
name = namegen.next_aircraft_name(country, cp.id, flight) name = namegen.next_aircraft_name(country, flight.departure.id, flight)
group: FlyingGroup[Any] cp = flight.departure
try: try:
if flight.start_type == "In Flight": if start_type is StartType.IN_FLIGHT:
group = self._generate_inflight( group = self._generate_over_departure(
name=name, side=country, flight=flight, origin=cp name=name, side=country, flight=flight, origin=cp
) )
return group return group
@ -777,7 +778,7 @@ class AircraftConflictGenerator:
side=country, side=country,
unit_type=flight.unit_type.dcs_unit_type, unit_type=flight.unit_type.dcs_unit_type,
count=flight.count, count=flight.count,
start_type=flight.start_type, start_type=start_type.value,
at=carrier_group, at=carrier_group,
) )
else: else:
@ -788,7 +789,7 @@ class AircraftConflictGenerator:
side=country, side=country,
unit_type=flight.unit_type.dcs_unit_type, unit_type=flight.unit_type.dcs_unit_type,
count=flight.count, count=flight.count,
start_type=flight.start_type, start_type=start_type.value,
cp=cp, cp=cp,
) )
@ -801,22 +802,26 @@ class AircraftConflictGenerator:
side=country, side=country,
unit_type=flight.unit_type.dcs_unit_type, unit_type=flight.unit_type.dcs_unit_type,
count=flight.count, count=flight.count,
start_type=flight.start_type, start_type=start_type.value,
airport=cp.airport, airport=cp.airport,
) )
except Exception as e: except NoParkingSlotError:
# Generated when there is no place on Runway or on Parking Slots # Generated when there is no place on Runway or on Parking Slots
logging.error(e) logging.exception(
logging.warning(
"No room on runway or parking slots. Starting from the air." "No room on runway or parking slots. Starting from the air."
) )
flight.start_type = "In Flight" flight.start_type = StartType.IN_FLIGHT
group = self._generate_inflight( group = self._generate_over_departure(
name=name, side=country, flight=flight, origin=cp name=name, side=country, flight=flight, origin=cp
) )
group.points[0].alt = 1500 group.points[0].alt = 1500
return group return group
def generate_planned_flight(
self, country: Country, flight: Flight
) -> FlyingGroup[Any]:
return self.generate_flight_at_departure(country, flight, flight.start_type)
@staticmethod @staticmethod
def set_reduced_fuel( def set_reduced_fuel(
flight: Flight, group: FlyingGroup[Any], unit_type: Type[FlyingType] flight: Flight, group: FlyingGroup[Any], unit_type: Type[FlyingType]
@ -1360,7 +1365,7 @@ class AircraftConflictGenerator:
# Late activation causes the aircraft to not be spawned # Late activation causes the aircraft to not be spawned
# until triggered. # until triggered.
self.set_activation_time(flight, group, start_time) self.set_activation_time(flight, group, start_time)
elif flight.start_type == "Cold": elif flight.start_type is StartType.COLD:
# Setting the start time causes the AI to wait until the # Setting the start time causes the AI to wait until the
# specified time to begin their startup sequence. # specified time to begin their startup sequence.
self.set_startup_time(flight, group, start_time) self.set_startup_time(flight, group, start_time)
@ -1374,7 +1379,7 @@ class AircraftConflictGenerator:
@staticmethod @staticmethod
def should_activate_late(flight: Flight) -> bool: def should_activate_late(flight: Flight) -> bool:
if flight.start_type != "Cold": if flight.start_type is StartType.COLD:
# Avoid spawning aircraft in the air or on the runway until it's # Avoid spawning aircraft in the air or on the runway until it's
# time for their mission. Also avoid burning through gas spawning # time for their mission. Also avoid burning through gas spawning
# hot aircraft hours before their takeoff time. # hot aircraft hours before their takeoff time.

View File

@ -19,6 +19,7 @@ from dcs.mapping import Point
from dcs.unit import Unit from dcs.unit import Unit
from shapely.geometry import Point as ShapelyPoint from shapely.geometry import Point as ShapelyPoint
from game.ato.starttype import StartType
from game.data.doctrine import Doctrine from game.data.doctrine import Doctrine
from game.dcs.aircrafttype import FuelConsumption from game.dcs.aircrafttype import FuelConsumption
from game.flightplan import IpZoneGeometry, JoinZoneGeometry, HoldZoneGeometry from game.flightplan import IpZoneGeometry, JoinZoneGeometry, HoldZoneGeometry
@ -275,7 +276,7 @@ class FlightPlan:
return start_time return start_time
def estimate_startup(self) -> timedelta: def estimate_startup(self) -> timedelta:
if self.flight.start_type == "Cold": if self.flight.start_type is StartType.COLD:
if self.flight.client_count: if self.flight.client_count:
return timedelta(minutes=10) return timedelta(minutes=10)
else: else:
@ -284,7 +285,7 @@ class FlightPlan:
return timedelta() return timedelta()
def estimate_ground_ops(self) -> timedelta: def estimate_ground_ops(self) -> timedelta:
if self.flight.start_type in ("Runway", "In Flight"): if self.flight.start_type in {StartType.RUNWAY, StartType.IN_FLIGHT}:
return timedelta() return timedelta()
if self.flight.from_cp.is_fleet: if self.flight.from_cp.is_fleet:
return timedelta(minutes=2) return timedelta(minutes=2)