mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Use more sensible patrol speeds for CAP, and fix is_helo (#1492)
* Use more sensible patrol speeds for CAP, and fix is_helo
This commit is contained in:
parent
9121cf7ecb
commit
30801dff9f
@ -29,7 +29,15 @@ from game.radio.channels import (
|
||||
ViggenRadioChannelAllocator,
|
||||
NoOpChannelAllocator,
|
||||
)
|
||||
from game.utils import Distance, Speed, feet, kph, knots, nautical_miles
|
||||
from game.utils import (
|
||||
Distance,
|
||||
SPEED_OF_SOUND_AT_SEA_LEVEL,
|
||||
Speed,
|
||||
feet,
|
||||
kph,
|
||||
knots,
|
||||
nautical_miles,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from gen.aircraft import FlightData
|
||||
@ -182,7 +190,7 @@ class AircraftType(UnitType[Type[FlyingType]]):
|
||||
|
||||
@property
|
||||
def preferred_patrol_altitude(self) -> Distance:
|
||||
if self.patrol_altitude:
|
||||
if self.patrol_altitude is not None:
|
||||
return self.patrol_altitude
|
||||
else:
|
||||
# Estimate based on max speed.
|
||||
@ -208,6 +216,40 @@ class AircraftType(UnitType[Type[FlyingType]]):
|
||||
min(altitude_for_highest_speed, rounded_altitude),
|
||||
)
|
||||
|
||||
def preferred_patrol_speed(self, altitude: Distance) -> Speed:
|
||||
"""Preferred true airspeed when patrolling"""
|
||||
if self.patrol_speed is not None:
|
||||
return self.patrol_speed
|
||||
else:
|
||||
# Estimate based on max speed.
|
||||
max_speed = self.max_speed
|
||||
if max_speed > SPEED_OF_SOUND_AT_SEA_LEVEL * 1.6:
|
||||
# Fast airplanes, should manage pretty high patrol speed
|
||||
return (
|
||||
Speed.from_mach(0.85, altitude)
|
||||
if altitude.feet > 20000
|
||||
else Speed.from_mach(0.7, altitude)
|
||||
)
|
||||
elif max_speed > SPEED_OF_SOUND_AT_SEA_LEVEL * 1.2:
|
||||
# Medium-fast like F/A-18C
|
||||
return (
|
||||
Speed.from_mach(0.8, altitude)
|
||||
if altitude.feet > 20000
|
||||
else Speed.from_mach(0.65, altitude)
|
||||
)
|
||||
elif max_speed > SPEED_OF_SOUND_AT_SEA_LEVEL * 0.7:
|
||||
# Semi-fast like airliners or similar
|
||||
return (
|
||||
Speed.from_mach(0.5, altitude)
|
||||
if altitude.feet > 20000
|
||||
else Speed.from_mach(0.4, altitude)
|
||||
)
|
||||
else:
|
||||
# Slow like warbirds or helicopters
|
||||
# Use whichever is slowest - mach 0.35 or 70% of max speed
|
||||
logging.debug(f"{self.name} max_speed * 0.7 is {max_speed * 0.7}")
|
||||
return min(Speed.from_mach(0.35, altitude), max_speed * 0.7)
|
||||
|
||||
def alloc_flight_radio(self, radio_registry: RadioRegistry) -> RadioFrequency:
|
||||
from gen.radios import ChannelInUseError, kHz
|
||||
|
||||
|
||||
@ -1775,17 +1775,11 @@ class RaceTrackBuilder(PydcsWaypointBuilder):
|
||||
)
|
||||
)
|
||||
|
||||
# TODO: Set orbit speeds for all race tracks and remove this special case.
|
||||
if isinstance(flight_plan, RefuelingFlightPlan):
|
||||
orbit = OrbitAction(
|
||||
altitude=waypoint.alt,
|
||||
pattern=OrbitAction.OrbitPattern.RaceTrack,
|
||||
speed=int(flight_plan.patrol_speed.kph),
|
||||
)
|
||||
else:
|
||||
orbit = OrbitAction(
|
||||
altitude=waypoint.alt, pattern=OrbitAction.OrbitPattern.RaceTrack
|
||||
)
|
||||
orbit = OrbitAction(
|
||||
altitude=waypoint.alt,
|
||||
pattern=OrbitAction.OrbitPattern.RaceTrack,
|
||||
speed=int(flight_plan.patrol_speed.kph),
|
||||
)
|
||||
|
||||
racetrack = ControlledTask(orbit)
|
||||
self.set_waypoint_tot(waypoint, flight_plan.patrol_start_time)
|
||||
|
||||
@ -141,8 +141,8 @@ class FlightWaypoint:
|
||||
waypoint_type: The waypoint type.
|
||||
x: X coordinate of the waypoint.
|
||||
y: Y coordinate of the waypoint.
|
||||
alt: Altitude of the waypoint. By default this is AGL, but it can be
|
||||
changed to MSL by setting alt_type to "RADIO".
|
||||
alt: Altitude of the waypoint. By default this is MSL, but it can be
|
||||
changed to AGL by setting alt_type to "RADIO"
|
||||
"""
|
||||
self.waypoint_type = waypoint_type
|
||||
self.x = x
|
||||
|
||||
@ -411,6 +411,9 @@ class PatrollingFlightPlan(FlightPlan):
|
||||
#: Maximum time to remain on station.
|
||||
patrol_duration: timedelta
|
||||
|
||||
#: Racetrack speed TAS.
|
||||
patrol_speed: Speed
|
||||
|
||||
#: The engagement range of any Search Then Engage task, or the radius of a
|
||||
#: Search Then Engage in Zone task. Any enemies of the appropriate type for
|
||||
#: this mission within this range of the flight's current position (or the
|
||||
@ -779,9 +782,6 @@ class RefuelingFlightPlan(PatrollingFlightPlan):
|
||||
divert: Optional[FlightWaypoint]
|
||||
bullseye: FlightWaypoint
|
||||
|
||||
#: Racetrack speed.
|
||||
patrol_speed: Speed
|
||||
|
||||
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
|
||||
yield self.takeoff
|
||||
yield from self.nav_to
|
||||
@ -1124,6 +1124,11 @@ class FlightPlanBuilder:
|
||||
min(self.doctrine.max_patrol_altitude, randomized_alt),
|
||||
)
|
||||
|
||||
patrol_speed = flight.unit_type.preferred_patrol_speed(patrol_alt)
|
||||
logging.debug(
|
||||
f"BARCAP patrol speed for {flight.unit_type.name} at {patrol_alt.feet}ft: {patrol_speed.knots} KTAS"
|
||||
)
|
||||
|
||||
builder = WaypointBuilder(flight, self.coalition)
|
||||
start, end = builder.race_track(start_pos, end_pos, patrol_alt)
|
||||
|
||||
@ -1131,6 +1136,7 @@ class FlightPlanBuilder:
|
||||
package=self.package,
|
||||
flight=flight,
|
||||
patrol_duration=self.doctrine.cap_duration,
|
||||
patrol_speed=patrol_speed,
|
||||
engagement_distance=self.doctrine.cap_engagement_range,
|
||||
takeoff=builder.takeoff(flight.departure),
|
||||
nav_to=builder.nav_path(
|
||||
@ -1362,6 +1368,10 @@ class FlightPlanBuilder:
|
||||
self.doctrine.min_patrol_altitude,
|
||||
min(self.doctrine.max_patrol_altitude, randomized_alt),
|
||||
)
|
||||
patrol_speed = flight.unit_type.preferred_patrol_speed(patrol_alt)
|
||||
logging.debug(
|
||||
f"TARCAP patrol speed for {flight.unit_type.name} at {patrol_alt.feet}ft: {patrol_speed.knots} KTAS"
|
||||
)
|
||||
|
||||
# Create points
|
||||
builder = WaypointBuilder(flight, self.coalition)
|
||||
@ -1383,6 +1393,7 @@ class FlightPlanBuilder:
|
||||
# requests an escort the CAP flight will remain on station for the
|
||||
# duration of the escorted mission, or until it is winchester/bingo.
|
||||
patrol_duration=self.doctrine.cap_duration,
|
||||
patrol_speed=patrol_speed,
|
||||
engagement_distance=self.doctrine.cap_engagement_range,
|
||||
takeoff=builder.takeoff(flight.departure),
|
||||
nav_to=builder.nav_path(flight.departure.position, orbit0p, patrol_alt),
|
||||
@ -1546,16 +1557,33 @@ class FlightPlanBuilder:
|
||||
|
||||
builder = WaypointBuilder(flight, self.coalition)
|
||||
|
||||
# 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
|
||||
is_helo = flight.unit_type.dcs_unit_type.helicopter
|
||||
ingress_egress_altitude = (
|
||||
self.doctrine.ingress_altitude if not is_helo else meters(50)
|
||||
)
|
||||
patrol_speed = flight.unit_type.preferred_patrol_speed(ingress_egress_altitude)
|
||||
use_agl_ingress_egress = is_helo
|
||||
|
||||
return CasFlightPlan(
|
||||
package=self.package,
|
||||
flight=flight,
|
||||
patrol_duration=self.doctrine.cas_duration,
|
||||
patrol_speed=patrol_speed,
|
||||
takeoff=builder.takeoff(flight.departure),
|
||||
nav_to=builder.nav_path(
|
||||
flight.departure.position, ingress, self.doctrine.ingress_altitude
|
||||
flight.departure.position,
|
||||
ingress,
|
||||
ingress_egress_altitude,
|
||||
use_agl_ingress_egress,
|
||||
),
|
||||
nav_from=builder.nav_path(
|
||||
egress, flight.arrival.position, self.doctrine.ingress_altitude
|
||||
egress,
|
||||
flight.arrival.position,
|
||||
ingress_egress_altitude,
|
||||
use_agl_ingress_egress,
|
||||
),
|
||||
patrol_start=builder.ingress(
|
||||
FlightWaypointType.INGRESS_CAS, ingress, location
|
||||
@ -1608,6 +1636,7 @@ class FlightPlanBuilder:
|
||||
else:
|
||||
altitude = feet(21000)
|
||||
|
||||
# TODO: Could use flight.unit_type.preferred_patrol_speed(altitude) instead.
|
||||
if tanker_type.patrol_speed is not None:
|
||||
speed = tanker_type.patrol_speed
|
||||
else:
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
|
||||
import random
|
||||
from dataclasses import dataclass
|
||||
@ -55,7 +56,7 @@ class WaypointBuilder:
|
||||
|
||||
@property
|
||||
def is_helo(self) -> bool:
|
||||
return getattr(self.flight.unit_type, "helicopter", False)
|
||||
return self.flight.unit_type.dcs_unit_type.helicopter
|
||||
|
||||
def takeoff(self, departure: ControlPoint) -> FlightWaypoint:
|
||||
"""Create takeoff waypoint for the given arrival airfield or carrier.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user