MetalStormGhost 6e37cadb84
Settings doctrine page + streamlining (#156)
* Added a separate Doctrine page in settings with the following new options:
- Minimum number of aircraft for autoplanner to plan OCA packages against
- Airbase threat range (nmi)
- TARCAP threat buffer distance (nmi)
- AEW&C threat buffer distance (nmi)
- Theater tanker threat buffer distance (nmi)

Implemented handling for the OPFOR autoplanner aggressiveness in objectivefinder.py vulnerable_control_points().

* * Added three new options in Settings:
- Autoplanner plans refueling flights for Strike packages
- Autoplanner plans refueling flights for OCA packages
- Autoplanner plans refueling flights for DEAD packages

Fixed a bug in faction.py where F-16Ds were not correctly removed from the faction when the F-16I/F-16D mod was not selected.

* Renamed Maximum frontline length -> Maximum frontline width.
2023-07-01 23:54:27 +02:00

133 lines
4.3 KiB
Python

from __future__ import annotations
from collections.abc import Iterator
from dataclasses import dataclass
from datetime import timedelta
from typing import TYPE_CHECKING, Type
from game.theater import FrontLine
from game.utils import Distance, Speed, kph, meters
from .ibuilder import IBuilder
from .invalidobjectivelocation import InvalidObjectiveLocation
from .patrolling import PatrollingFlightPlan, PatrollingLayout
from .uizonedisplay import UiZone, UiZoneDisplay
from .waypointbuilder import WaypointBuilder
from ..flightwaypointtype import FlightWaypointType
if TYPE_CHECKING:
from ..flightwaypoint import FlightWaypoint
@dataclass
class CasLayout(PatrollingLayout):
target: FlightWaypoint
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
yield self.departure
yield from self.nav_to
yield self.patrol_start
yield self.target
yield self.patrol_end
yield from self.nav_from
yield self.arrival
if self.divert is not None:
yield self.divert
yield self.bullseye
class CasFlightPlan(PatrollingFlightPlan[CasLayout], UiZoneDisplay):
@staticmethod
def builder_type() -> Type[Builder]:
return Builder
@property
def patrol_duration(self) -> timedelta:
return self.flight.coalition.doctrine.cas_duration
@property
def patrol_speed(self) -> Speed:
# 2021-08-02: patrol_speed will currently have no effect because
# CAS doesn't use OrbitAction. But all PatrollingFlightPlan are expected
# to have patrol_speed
return kph(0)
@property
def engagement_distance(self) -> Distance:
max_length = self.flight.coalition.game.settings.max_frontline_width * 1000
return meters(max_length) / 2
@property
def combat_speed_waypoints(self) -> set[FlightWaypoint]:
return {self.layout.patrol_start, self.layout.target, self.layout.patrol_end}
def request_escort_at(self) -> FlightWaypoint | None:
return self.layout.patrol_start
def dismiss_escort_at(self) -> FlightWaypoint | None:
return self.layout.patrol_end
def ui_zone(self) -> UiZone:
return UiZone(
[self.layout.target.position],
self.engagement_distance,
)
class Builder(IBuilder[CasFlightPlan, CasLayout]):
def layout(self) -> CasLayout:
location = self.package.target
if not isinstance(location, FrontLine):
raise InvalidObjectiveLocation(self.flight.flight_type, location)
from game.missiongenerator.frontlineconflictdescription import (
FrontLineConflictDescription,
)
bounds = FrontLineConflictDescription.frontline_bounds(
location, self.theater, self.coalition.game.settings
)
ingress = bounds.left_position
center = bounds.center
egress = bounds.right_position
ingress_distance = ingress.distance_to_point(self.flight.departure.position)
egress_distance = egress.distance_to_point(self.flight.departure.position)
if egress_distance < ingress_distance:
ingress, egress = egress, ingress
builder = WaypointBuilder(self.flight, self.coalition)
is_helo = self.flight.unit_type.dcs_unit_type.helicopter
ingress_egress_altitude = (
self.doctrine.ingress_altitude if not is_helo else meters(50)
)
use_agl_ingress_egress = is_helo
return CasLayout(
departure=builder.takeoff(self.flight.departure),
nav_to=builder.nav_path(
self.flight.departure.position,
ingress,
ingress_egress_altitude,
use_agl_ingress_egress,
),
nav_from=builder.nav_path(
egress,
self.flight.arrival.position,
ingress_egress_altitude,
use_agl_ingress_egress,
),
patrol_start=builder.ingress(
FlightWaypointType.INGRESS_CAS, ingress, location
),
target=builder.cas(center),
patrol_end=builder.egress(egress, location),
arrival=builder.land(self.flight.arrival),
divert=builder.divert(self.flight.divert),
bullseye=builder.bullseye(),
)
def build(self) -> CasFlightPlan:
return CasFlightPlan(self.flight, self.layout())