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

96 lines
3.6 KiB
Python

from __future__ import annotations
import random
from abc import ABC
from typing import Any, TYPE_CHECKING, TypeVar
from dcs import Point
from shapely.geometry import Point as ShapelyPoint
from game.utils import Heading, meters, nautical_miles
from .flightplan import FlightPlan
from .patrolling import PatrollingLayout
from ..closestairfields import ObjectiveDistanceCache
from ..flightplans.ibuilder import IBuilder
from ..flightplans.planningerror import PlanningError
if TYPE_CHECKING:
from game.theater import MissionTarget
FlightPlanT = TypeVar("FlightPlanT", bound=FlightPlan[Any])
LayoutT = TypeVar("LayoutT", bound=PatrollingLayout)
class CapBuilder(IBuilder[FlightPlanT, LayoutT], ABC):
def cap_racetrack_for_objective(
self, location: MissionTarget, barcap: bool
) -> tuple[Point, Point]:
closest_cache = ObjectiveDistanceCache.get_closest_airfields(location)
for airfield in closest_cache.operational_airfields:
# If the mission is a BARCAP of an enemy airfield, find the *next*
# closest enemy airfield.
if airfield == self.package.target:
continue
if airfield.captured != self.is_player:
closest_airfield = airfield
break
else:
raise PlanningError("Could not find any enemy airfields")
heading = Heading.from_degrees(
location.position.heading_between_point(closest_airfield.position)
)
position = ShapelyPoint(
self.package.target.position.x, self.package.target.position.y
)
if barcap:
# BARCAPs should remain far enough back from the enemy that their
# commit range does not enter the enemy's threat zone. Include a 5nm
# buffer.
distance_to_no_fly = (
meters(position.distance(self.threat_zones.all))
- self.doctrine.cap_engagement_range
- nautical_miles(5)
)
max_track_length = self.doctrine.cap_max_track_length
else:
# Other race tracks (TARCAPs, currently) just try to keep some
# distance from the nearest enemy airbase, but since they are by
# definition in enemy territory they can't avoid the threat zone
# without being useless.
min_distance_from_enemy = nautical_miles(
self.coalition.game.settings.tarcap_threat_buffer_min_distance
)
distance_to_airfield = meters(
closest_airfield.position.distance_to_point(
self.package.target.position
)
)
distance_to_no_fly = distance_to_airfield - min_distance_from_enemy
# TARCAPs fly short racetracks because they need to react faster.
max_track_length = self.doctrine.cap_min_track_length + 0.3 * (
self.doctrine.cap_max_track_length - self.doctrine.cap_min_track_length
)
min_cap_distance = min(
self.doctrine.cap_min_distance_from_cp, distance_to_no_fly
)
max_cap_distance = min(
self.doctrine.cap_max_distance_from_cp, distance_to_no_fly
)
end = location.position.point_from_heading(
heading.degrees,
random.randint(int(min_cap_distance.meters), int(max_cap_distance.meters)),
)
track_length = random.randint(
int(self.doctrine.cap_min_track_length.meters),
int(max_track_length.meters),
)
start = end.point_from_heading(heading.opposite.degrees, track_length)
return start, end