mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Add SEAD Sweep flight plan
Reintroduce legacy SEAD Escort flight plan, but under a separate type because it didn't really escort the primary flight...
This commit is contained in:
parent
e2d9a794b8
commit
db038ecdea
@ -47,6 +47,7 @@
|
||||
* **[Options]** Renamed Maximum frontline length -> Maximum frontline width.
|
||||
* **[Squadrons]** Add livery selector in Squadron Dialog, allowing you to change the livery during the campaign.
|
||||
* **[New Game Wizard]** Automatically invert factions when 'Invert Map' is selected.
|
||||
* **[Flight Plans]** Added "SEAD Sweep" flight plan, which basically reintroduces the legacy "SEAD Escort" flight plan where the flight will engage whatever it can find without actually escorting the primary flight.
|
||||
|
||||
|
||||
## Fixes
|
||||
|
||||
@ -19,6 +19,7 @@ from .ocarunway import OcaRunwayFlightPlan
|
||||
from .packagerefueling import PackageRefuelingFlightPlan
|
||||
from .planningerror import PlanningError
|
||||
from .sead import SeadFlightPlan
|
||||
from .seadsweep import SeadSweepFlightPlan
|
||||
from .strike import StrikeFlightPlan
|
||||
from .sweep import SweepFlightPlan
|
||||
from .tarcap import TarCapFlightPlan
|
||||
@ -51,6 +52,7 @@ class FlightPlanBuilderTypes:
|
||||
FlightType.OCA_RUNWAY: OcaRunwayFlightPlan.builder_type(),
|
||||
FlightType.SEAD: SeadFlightPlan.builder_type(),
|
||||
FlightType.SEAD_ESCORT: EscortFlightPlan.builder_type(),
|
||||
FlightType.SEAD_SWEEP: SeadSweepFlightPlan.builder_type(),
|
||||
FlightType.STRIKE: StrikeFlightPlan.builder_type(),
|
||||
FlightType.SWEEP: SweepFlightPlan.builder_type(),
|
||||
FlightType.TARCAP: TarCapFlightPlan.builder_type(),
|
||||
|
||||
@ -182,6 +182,8 @@ class FormationAttackBuilder(IBuilder[FlightPlanT, LayoutT], ABC):
|
||||
initial = None
|
||||
if ingress_type == FlightWaypointType.INGRESS_SEAD:
|
||||
initial = builder.sead_search(self.package.target)
|
||||
elif ingress_type == FlightWaypointType.INGRESS_SEAD_SWEEP:
|
||||
initial = builder.sead_sweep(self.package.target)
|
||||
|
||||
return FormationAttackLayout(
|
||||
departure=builder.takeoff(self.flight.departure),
|
||||
@ -213,7 +215,7 @@ class FormationAttackBuilder(IBuilder[FlightPlanT, LayoutT], ABC):
|
||||
return builder.bai_group(target)
|
||||
elif flight.flight_type == FlightType.DEAD:
|
||||
return builder.dead_point(target)
|
||||
elif flight.flight_type == FlightType.SEAD:
|
||||
elif flight.flight_type in {FlightType.SEAD, FlightType.SEAD_SWEEP}:
|
||||
return builder.sead_point(target)
|
||||
else:
|
||||
return builder.strike_point(target)
|
||||
|
||||
28
game/ato/flightplans/seadsweep.py
Normal file
28
game/ato/flightplans/seadsweep.py
Normal file
@ -0,0 +1,28 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import timedelta
|
||||
from typing import Type
|
||||
|
||||
from .formationattack import (
|
||||
FormationAttackBuilder,
|
||||
FormationAttackFlightPlan,
|
||||
FormationAttackLayout,
|
||||
)
|
||||
from ..flightwaypointtype import FlightWaypointType
|
||||
|
||||
|
||||
class SeadSweepFlightPlan(FormationAttackFlightPlan):
|
||||
@staticmethod
|
||||
def builder_type() -> Type[Builder]:
|
||||
return Builder
|
||||
|
||||
def default_tot_offset(self) -> timedelta:
|
||||
return -timedelta(minutes=2)
|
||||
|
||||
|
||||
class Builder(FormationAttackBuilder[SeadSweepFlightPlan, FormationAttackLayout]):
|
||||
def layout(self) -> FormationAttackLayout:
|
||||
return self._build(FlightWaypointType.INGRESS_SEAD_SWEEP)
|
||||
|
||||
def build(self) -> SeadSweepFlightPlan:
|
||||
return SeadSweepFlightPlan(self.flight, self.layout())
|
||||
@ -423,6 +423,32 @@ class WaypointBuilder:
|
||||
)
|
||||
|
||||
def sead_search(self, target: MissionTarget) -> FlightWaypoint:
|
||||
hold = self._sead_search_point(target)
|
||||
|
||||
return FlightWaypoint(
|
||||
"SEAD Search",
|
||||
FlightWaypointType.NAV,
|
||||
hold,
|
||||
self.doctrine.ingress_altitude,
|
||||
alt_type="BARO",
|
||||
description="Anchor and search from this point",
|
||||
pretty_name="SEAD Search",
|
||||
)
|
||||
|
||||
def sead_sweep(self, target: MissionTarget) -> FlightWaypoint:
|
||||
hold = self._sead_search_point(target)
|
||||
|
||||
return FlightWaypoint(
|
||||
"SEAD Sweep",
|
||||
FlightWaypointType.NAV,
|
||||
hold,
|
||||
self.doctrine.ingress_altitude,
|
||||
alt_type="BARO",
|
||||
description="Anchor and search from this point",
|
||||
pretty_name="SEAD Sweep",
|
||||
)
|
||||
|
||||
def _sead_search_point(self, target: MissionTarget) -> Point:
|
||||
"""Creates custom waypoint for AI SEAD flights
|
||||
to avoid having them fly all the way to the SAM site.
|
||||
Args:
|
||||
@ -437,16 +463,7 @@ class WaypointBuilder:
|
||||
hold = target.position.point_from_heading(
|
||||
hdg, min(threat_range, ingress2tgt_dist * 0.95)
|
||||
)
|
||||
|
||||
return FlightWaypoint(
|
||||
"SEAD Search",
|
||||
FlightWaypointType.INGRESS_SEAD,
|
||||
hold,
|
||||
self.doctrine.ingress_altitude,
|
||||
alt_type="BARO",
|
||||
description="Anchor and search from this point",
|
||||
pretty_name="SEAD Search",
|
||||
)
|
||||
return hold
|
||||
|
||||
@staticmethod
|
||||
def escort_hold(start: Point, altitude: Distance) -> FlightWaypoint:
|
||||
|
||||
@ -57,6 +57,7 @@ class FlightType(Enum):
|
||||
REFUELING = "Refueling"
|
||||
FERRY = "Ferry"
|
||||
AIR_ASSAULT = "Air Assault"
|
||||
SEAD_SWEEP = "SEAD Sweep" # Reintroduce legacy "engage-whatever-you-can-find" SEAD
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.value
|
||||
@ -91,6 +92,7 @@ class FlightType(Enum):
|
||||
FlightType.OCA_AIRCRAFT,
|
||||
FlightType.SEAD_ESCORT,
|
||||
FlightType.AIR_ASSAULT,
|
||||
FlightType.SEAD_SWEEP,
|
||||
}
|
||||
|
||||
@property
|
||||
@ -110,6 +112,7 @@ class FlightType(Enum):
|
||||
FlightType.REFUELING: AirEntity.TANKER,
|
||||
FlightType.SEAD: AirEntity.SUPPRESSION_OF_ENEMY_AIR_DEFENCE,
|
||||
FlightType.SEAD_ESCORT: AirEntity.SUPPRESSION_OF_ENEMY_AIR_DEFENCE,
|
||||
FlightType.SEAD_SWEEP: AirEntity.SUPPRESSION_OF_ENEMY_AIR_DEFENCE,
|
||||
FlightType.STRIKE: AirEntity.ATTACK_STRIKE,
|
||||
FlightType.SWEEP: AirEntity.FIGHTER,
|
||||
FlightType.TARCAP: AirEntity.FIGHTER,
|
||||
|
||||
@ -50,3 +50,4 @@ class FlightWaypointType(IntEnum):
|
||||
CARGO_STOP = 30 # Stopover landing point using the LandingReFuAr waypoint type
|
||||
INGRESS_AIR_ASSAULT = 31
|
||||
INGRESS_ANTI_SHIP = 32
|
||||
INGRESS_SEAD_SWEEP = 33
|
||||
|
||||
@ -184,6 +184,9 @@ class Loadout:
|
||||
# A SEAD escort typically does not need a different loadout than a regular
|
||||
# SEAD flight, so fall back to SEAD if needed.
|
||||
loadout_names[FlightType.SEAD_ESCORT].extend(loadout_names[FlightType.SEAD])
|
||||
loadout_names[FlightType.SEAD_SWEEP].extend(
|
||||
loadout_names[FlightType.SEAD_ESCORT]
|
||||
)
|
||||
# Sweep and escort can fall back to TARCAP.
|
||||
loadout_names[FlightType.ESCORT].extend(loadout_names[FlightType.TARCAP])
|
||||
loadout_names[FlightType.SWEEP].extend(loadout_names[FlightType.TARCAP])
|
||||
|
||||
@ -459,6 +459,9 @@ class AircraftType(UnitType[Type[FlyingType]]):
|
||||
for task_name, priority in data.get("tasks", {}).items():
|
||||
task_priorities[FlightType(task_name)] = priority
|
||||
|
||||
if FlightType.SEAD in task_priorities:
|
||||
task_priorities[FlightType.SEAD_SWEEP] = task_priorities[FlightType.SEAD]
|
||||
|
||||
for variant in data.get("variants", [aircraft.id]):
|
||||
yield AircraftType(
|
||||
dcs_unit_type=aircraft,
|
||||
|
||||
@ -56,7 +56,7 @@ class AircraftBehavior:
|
||||
self.configure_cas(group, flight)
|
||||
elif self.task == FlightType.DEAD:
|
||||
self.configure_dead(group, flight)
|
||||
elif self.task == FlightType.SEAD:
|
||||
elif self.task in [FlightType.SEAD, FlightType.SEAD_SWEEP]:
|
||||
self.configure_sead(group, flight)
|
||||
elif self.task == FlightType.SEAD_ESCORT:
|
||||
self.configure_sead_escort(group, flight)
|
||||
|
||||
27
game/missiongenerator/aircraft/waypoints/seadsweepingress.py
Normal file
27
game/missiongenerator/aircraft/waypoints/seadsweepingress.py
Normal file
@ -0,0 +1,27 @@
|
||||
from dcs.point import MovingPoint
|
||||
from dcs.task import (
|
||||
OptECMUsing,
|
||||
ControlledTask,
|
||||
EngageTargets,
|
||||
Targets,
|
||||
)
|
||||
|
||||
from game.utils import nautical_miles
|
||||
from .pydcswaypointbuilder import PydcsWaypointBuilder
|
||||
|
||||
|
||||
class SeadSweepIngressBuilder(PydcsWaypointBuilder):
|
||||
def add_tasks(self, waypoint: MovingPoint) -> None:
|
||||
# Preemptively use ECM to better avoid getting swatted.
|
||||
ecm_option = OptECMUsing(value=OptECMUsing.Values.UseIfDetectedLockByRadar)
|
||||
waypoint.tasks.append(ecm_option)
|
||||
|
||||
waypoint.add_task(
|
||||
ControlledTask(
|
||||
EngageTargets(
|
||||
# TODO: From doctrine.
|
||||
max_distance=int(nautical_miles(30).meters),
|
||||
targets=[Targets.All.GroundUnits.AirDefence.AAA.SAMRelated],
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -37,6 +37,7 @@ from .racetrack import RaceTrackBuilder
|
||||
from .racetrackend import RaceTrackEndBuilder
|
||||
from .refuel import RefuelPointBuilder
|
||||
from .seadingress import SeadIngressBuilder
|
||||
from .seadsweepingress import SeadSweepIngressBuilder
|
||||
from .splitpoint import SplitPointBuilder
|
||||
from .strikeingress import StrikeIngressBuilder
|
||||
from .sweepingress import SweepIngressBuilder
|
||||
@ -126,6 +127,7 @@ class WaypointGenerator:
|
||||
FlightWaypointType.INGRESS_OCA_AIRCRAFT: OcaAircraftIngressBuilder,
|
||||
FlightWaypointType.INGRESS_OCA_RUNWAY: OcaRunwayIngressBuilder,
|
||||
FlightWaypointType.INGRESS_SEAD: SeadIngressBuilder,
|
||||
FlightWaypointType.INGRESS_SEAD_SWEEP: SeadSweepIngressBuilder,
|
||||
FlightWaypointType.INGRESS_STRIKE: StrikeIngressBuilder,
|
||||
FlightWaypointType.INGRESS_SWEEP: SweepIngressBuilder,
|
||||
FlightWaypointType.JOIN: JoinPointBuilder,
|
||||
|
||||
@ -38,6 +38,7 @@ class MissionTarget:
|
||||
FlightType.ESCORT,
|
||||
FlightType.TARCAP,
|
||||
FlightType.SEAD_ESCORT,
|
||||
FlightType.SEAD_SWEEP,
|
||||
FlightType.SWEEP,
|
||||
# TODO: FlightType.ELINT,
|
||||
# TODO: FlightType.EWAR,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user