mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Plan anti-ship missions automatically.
This commit is contained in:
parent
2ac92a75a4
commit
69dbe62b70
@ -5,7 +5,16 @@ import operator
|
|||||||
import random
|
import random
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from typing import Iterator, List, Optional, Set, TYPE_CHECKING, Tuple, Type
|
from typing import (
|
||||||
|
Iterable,
|
||||||
|
Iterator,
|
||||||
|
List,
|
||||||
|
Optional,
|
||||||
|
Set,
|
||||||
|
TYPE_CHECKING,
|
||||||
|
Tuple,
|
||||||
|
Type,
|
||||||
|
)
|
||||||
|
|
||||||
from dcs.unittype import FlyingType, UnitType
|
from dcs.unittype import FlyingType, UnitType
|
||||||
|
|
||||||
@ -16,6 +25,8 @@ from game.utils import nm_to_meter
|
|||||||
from gen import Conflict
|
from gen import Conflict
|
||||||
from gen.ato import Package
|
from gen.ato import Package
|
||||||
from gen.flights.ai_flight_planner_db import (
|
from gen.flights.ai_flight_planner_db import (
|
||||||
|
ANTISHIP_CAPABLE,
|
||||||
|
ANTISHIP_PREFERRED,
|
||||||
CAP_CAPABLE,
|
CAP_CAPABLE,
|
||||||
CAP_PREFERRED,
|
CAP_PREFERRED,
|
||||||
CAS_CAPABLE,
|
CAS_CAPABLE,
|
||||||
@ -46,7 +57,7 @@ from theater import (
|
|||||||
# Avoid importing some types that cause circular imports unless type checking.
|
# Avoid importing some types that cause circular imports unless type checking.
|
||||||
from theater.theatergroundobject import (
|
from theater.theatergroundobject import (
|
||||||
EwrGroundObject,
|
EwrGroundObject,
|
||||||
VehicleGroupGroundObject,
|
NavalGroundObject, VehicleGroupGroundObject,
|
||||||
)
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -141,6 +152,8 @@ class AircraftAllocator:
|
|||||||
cap_missions = (FlightType.BARCAP, FlightType.TARCAP)
|
cap_missions = (FlightType.BARCAP, FlightType.TARCAP)
|
||||||
if task in cap_missions:
|
if task in cap_missions:
|
||||||
return CAP_PREFERRED
|
return CAP_PREFERRED
|
||||||
|
elif task == FlightType.ANTISHIP:
|
||||||
|
return ANTISHIP_PREFERRED
|
||||||
elif task == FlightType.BAI:
|
elif task == FlightType.BAI:
|
||||||
return CAS_CAPABLE
|
return CAS_CAPABLE
|
||||||
elif task == FlightType.CAS:
|
elif task == FlightType.CAS:
|
||||||
@ -159,6 +172,8 @@ class AircraftAllocator:
|
|||||||
cap_missions = (FlightType.BARCAP, FlightType.TARCAP)
|
cap_missions = (FlightType.BARCAP, FlightType.TARCAP)
|
||||||
if task in cap_missions:
|
if task in cap_missions:
|
||||||
return CAP_CAPABLE
|
return CAP_CAPABLE
|
||||||
|
elif task == FlightType.ANTISHIP:
|
||||||
|
return ANTISHIP_CAPABLE
|
||||||
elif task == FlightType.BAI:
|
elif task == FlightType.BAI:
|
||||||
return CAS_CAPABLE
|
return CAS_CAPABLE
|
||||||
elif task == FlightType.CAS:
|
elif task == FlightType.CAS:
|
||||||
@ -279,22 +294,10 @@ class ObjectiveFinder:
|
|||||||
SAM sites are sorted by their closest proximity to any friendly control
|
SAM sites are sorted by their closest proximity to any friendly control
|
||||||
point (airfield or fleet).
|
point (airfield or fleet).
|
||||||
"""
|
"""
|
||||||
sams: List[Tuple[TheaterGroundObject, int]] = []
|
return self._targets_by_range(self.enemy_sams())
|
||||||
for sam in self.enemy_sams():
|
|
||||||
ranges: List[int] = []
|
|
||||||
for cp in self.friendly_control_points():
|
|
||||||
ranges.append(sam.distance_to(cp))
|
|
||||||
sams.append((sam, min(ranges)))
|
|
||||||
|
|
||||||
sams = sorted(sams, key=operator.itemgetter(1))
|
|
||||||
for sam, _range in sams:
|
|
||||||
yield sam
|
|
||||||
|
|
||||||
def enemy_vehicle_groups(self) -> Iterator[VehicleGroupGroundObject]:
|
def enemy_vehicle_groups(self) -> Iterator[VehicleGroupGroundObject]:
|
||||||
"""Iterates over all enemy vehicle groups."""
|
"""Iterates over all enemy vehicle groups."""
|
||||||
# Control points might have the same ground object several times, for
|
|
||||||
# some reason.
|
|
||||||
found_targets: Set[str] = set()
|
|
||||||
for cp in self.enemy_control_points():
|
for cp in self.enemy_control_points():
|
||||||
for ground_object in cp.ground_objects:
|
for ground_object in cp.ground_objects:
|
||||||
if not isinstance(ground_object, VehicleGroupGroundObject):
|
if not isinstance(ground_object, VehicleGroupGroundObject):
|
||||||
@ -303,11 +306,7 @@ class ObjectiveFinder:
|
|||||||
if ground_object.is_dead:
|
if ground_object.is_dead:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if ground_object.name in found_targets:
|
|
||||||
continue
|
|
||||||
|
|
||||||
yield ground_object
|
yield ground_object
|
||||||
found_targets.add(ground_object.name)
|
|
||||||
|
|
||||||
def threatening_vehicle_groups(self) -> Iterator[TheaterGroundObject]:
|
def threatening_vehicle_groups(self) -> Iterator[TheaterGroundObject]:
|
||||||
"""Iterates over enemy vehicle groups near friendly control points.
|
"""Iterates over enemy vehicle groups near friendly control points.
|
||||||
@ -315,16 +314,40 @@ class ObjectiveFinder:
|
|||||||
Groups are sorted by their closest proximity to any friendly control
|
Groups are sorted by their closest proximity to any friendly control
|
||||||
point (airfield or fleet).
|
point (airfield or fleet).
|
||||||
"""
|
"""
|
||||||
groups: List[Tuple[VehicleGroupGroundObject, int]] = []
|
return self._targets_by_range(self.enemy_vehicle_groups())
|
||||||
for group in self.enemy_vehicle_groups():
|
|
||||||
|
def enemy_ships(self) -> Iterator[NavalGroundObject]:
|
||||||
|
for cp in self.enemy_control_points():
|
||||||
|
for ground_object in cp.ground_objects:
|
||||||
|
if not isinstance(ground_object, NavalGroundObject):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if ground_object.is_dead:
|
||||||
|
continue
|
||||||
|
|
||||||
|
yield ground_object
|
||||||
|
|
||||||
|
def threatening_ships(self) -> Iterator[TheaterGroundObject]:
|
||||||
|
"""Iterates over enemy ships near friendly control points.
|
||||||
|
|
||||||
|
Groups are sorted by their closest proximity to any friendly control
|
||||||
|
point (airfield or fleet).
|
||||||
|
"""
|
||||||
|
return self._targets_by_range(self.enemy_ships())
|
||||||
|
|
||||||
|
def _targets_by_range(
|
||||||
|
self,
|
||||||
|
targets: Iterable[MissionTarget]) -> Iterator[TheaterGroundObject]:
|
||||||
|
target_ranges: List[Tuple[MissionTarget, int]] = []
|
||||||
|
for target in targets:
|
||||||
ranges: List[int] = []
|
ranges: List[int] = []
|
||||||
for cp in self.friendly_control_points():
|
for cp in self.friendly_control_points():
|
||||||
ranges.append(group.distance_to(cp))
|
ranges.append(target.distance_to(cp))
|
||||||
groups.append((group, min(ranges)))
|
target_ranges.append((target, min(ranges)))
|
||||||
|
|
||||||
groups = sorted(groups, key=operator.itemgetter(1))
|
target_ranges = sorted(target_ranges, key=operator.itemgetter(1))
|
||||||
for group, _range in groups:
|
for target, _range in target_ranges:
|
||||||
yield group
|
yield target
|
||||||
|
|
||||||
def strike_targets(self) -> Iterator[TheaterGroundObject]:
|
def strike_targets(self) -> Iterator[TheaterGroundObject]:
|
||||||
"""Iterates over enemy strike targets.
|
"""Iterates over enemy strike targets.
|
||||||
@ -333,11 +356,17 @@ class ObjectiveFinder:
|
|||||||
point (airfield or fleet).
|
point (airfield or fleet).
|
||||||
"""
|
"""
|
||||||
targets: List[Tuple[TheaterGroundObject, int]] = []
|
targets: List[Tuple[TheaterGroundObject, int]] = []
|
||||||
# Control points might have the same ground object several times, for
|
# Building objectives are made of several individual TGOs (one per
|
||||||
# some reason.
|
# building).
|
||||||
found_targets: Set[str] = set()
|
found_targets: Set[str] = set()
|
||||||
for enemy_cp in self.enemy_control_points():
|
for enemy_cp in self.enemy_control_points():
|
||||||
for ground_object in enemy_cp.ground_objects:
|
for ground_object in enemy_cp.ground_objects:
|
||||||
|
if isinstance(ground_object, VehicleGroupGroundObject):
|
||||||
|
# BAI target, not strike target.
|
||||||
|
continue
|
||||||
|
if isinstance(ground_object, NavalGroundObject):
|
||||||
|
# Anti-ship target, not strike target.
|
||||||
|
continue
|
||||||
if ground_object.is_dead:
|
if ground_object.is_dead:
|
||||||
continue
|
continue
|
||||||
if ground_object.name in found_targets:
|
if ground_object.name in found_targets:
|
||||||
@ -440,6 +469,7 @@ class CoalitionMissionPlanner:
|
|||||||
# TODO: Merge into doctrine, also limit by aircraft.
|
# TODO: Merge into doctrine, also limit by aircraft.
|
||||||
MAX_CAP_RANGE = nm_to_meter(100)
|
MAX_CAP_RANGE = nm_to_meter(100)
|
||||||
MAX_CAS_RANGE = nm_to_meter(50)
|
MAX_CAS_RANGE = nm_to_meter(50)
|
||||||
|
MAX_ANTISHIP_RANGE = nm_to_meter(150)
|
||||||
MAX_BAI_RANGE = nm_to_meter(150)
|
MAX_BAI_RANGE = nm_to_meter(150)
|
||||||
MAX_SEAD_RANGE = nm_to_meter(150)
|
MAX_SEAD_RANGE = nm_to_meter(150)
|
||||||
MAX_STRIKE_RANGE = nm_to_meter(150)
|
MAX_STRIKE_RANGE = nm_to_meter(150)
|
||||||
@ -476,6 +506,13 @@ class CoalitionMissionPlanner:
|
|||||||
ProposedFlight(FlightType.ESCORT, 2, self.MAX_SEAD_RANGE),
|
ProposedFlight(FlightType.ESCORT, 2, self.MAX_SEAD_RANGE),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
for group in self.objective_finder.threatening_ships():
|
||||||
|
yield ProposedMission(group, [
|
||||||
|
ProposedFlight(FlightType.ANTISHIP, 2, self.MAX_ANTISHIP_RANGE),
|
||||||
|
# TODO: Max escort range.
|
||||||
|
ProposedFlight(FlightType.ESCORT, 2, self.MAX_ANTISHIP_RANGE),
|
||||||
|
])
|
||||||
|
|
||||||
for group in self.objective_finder.threatening_vehicle_groups():
|
for group in self.objective_finder.threatening_vehicle_groups():
|
||||||
yield ProposedMission(group, [
|
yield ProposedMission(group, [
|
||||||
ProposedFlight(FlightType.BAI, 2, self.MAX_BAI_RANGE),
|
ProposedFlight(FlightType.BAI, 2, self.MAX_BAI_RANGE),
|
||||||
|
|||||||
@ -444,6 +444,7 @@ STRIKE_PREFERRED = [
|
|||||||
ANTISHIP_CAPABLE = [
|
ANTISHIP_CAPABLE = [
|
||||||
Su_24M,
|
Su_24M,
|
||||||
Su_17M4,
|
Su_17M4,
|
||||||
|
FA_18C_hornet,
|
||||||
F_A_18C,
|
F_A_18C,
|
||||||
F_15E,
|
F_15E,
|
||||||
AV8BNA,
|
AV8BNA,
|
||||||
@ -458,7 +459,15 @@ ANTISHIP_CAPABLE = [
|
|||||||
Tornado_GR4,
|
Tornado_GR4,
|
||||||
|
|
||||||
Ju_88A4,
|
Ju_88A4,
|
||||||
Rafale_A_S
|
Rafale_A_S,
|
||||||
|
]
|
||||||
|
|
||||||
|
ANTISHIP_PREFERRED = [
|
||||||
|
FA_18C_hornet,
|
||||||
|
F_A_18C,
|
||||||
|
JF_17,
|
||||||
|
Rafale_A_S,
|
||||||
|
Su_24M,
|
||||||
]
|
]
|
||||||
|
|
||||||
DRONES = [
|
DRONES = [
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user