mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Doctrine cleanup (#3318)
This PR: - Refactors the doctrine class to have a bit more structure, in anticipation of adding more elements to Doctrine. - Moves previously hard coded helo-specific altitudes into the Doctrine class, aligning a bunch of altitudes ~200ft in the process. - Refactors ingress_altitude to combat_altitude to clarify that the altitude is applied to multiple waypoint types, not just the ingress altitude.
This commit is contained in:
parent
c695e7724a
commit
5b858886c0
@ -88,7 +88,7 @@ class Builder(IBuilder[AirAssaultFlightPlan, AirAssaultLayout]):
|
||||
raise PlanningError("Air assault is only usable by helicopters")
|
||||
assert self.package.waypoints is not None
|
||||
|
||||
altitude = feet(1500) if self.flight.is_helo else self.doctrine.ingress_altitude
|
||||
altitude = self.doctrine.helicopter.air_assault_nav_altitude
|
||||
altitude_is_agl = self.flight.is_helo
|
||||
|
||||
builder = WaypointBuilder(self.flight, self.coalition)
|
||||
|
||||
@ -19,7 +19,7 @@ class BarCapFlightPlan(PatrollingFlightPlan[PatrollingLayout]):
|
||||
|
||||
@property
|
||||
def patrol_duration(self) -> timedelta:
|
||||
return self.flight.coalition.doctrine.cap_duration
|
||||
return self.flight.coalition.doctrine.cap.duration
|
||||
|
||||
@property
|
||||
def patrol_speed(self) -> Speed:
|
||||
@ -29,7 +29,7 @@ class BarCapFlightPlan(PatrollingFlightPlan[PatrollingLayout]):
|
||||
|
||||
@property
|
||||
def engagement_distance(self) -> Distance:
|
||||
return self.flight.coalition.doctrine.cap_engagement_range
|
||||
return self.flight.coalition.doctrine.cap.engagement_range
|
||||
|
||||
|
||||
class Builder(CapBuilder[BarCapFlightPlan, PatrollingLayout]):
|
||||
@ -44,8 +44,8 @@ class Builder(CapBuilder[BarCapFlightPlan, PatrollingLayout]):
|
||||
preferred_alt = self.flight.unit_type.preferred_patrol_altitude
|
||||
randomized_alt = preferred_alt + feet(random.randint(-2, 1) * 1000)
|
||||
patrol_alt = max(
|
||||
self.doctrine.min_patrol_altitude,
|
||||
min(self.doctrine.max_patrol_altitude, randomized_alt),
|
||||
self.doctrine.cap.min_patrol_altitude,
|
||||
min(self.doctrine.cap.max_patrol_altitude, randomized_alt),
|
||||
)
|
||||
|
||||
builder = WaypointBuilder(self.flight, self.coalition)
|
||||
|
||||
@ -90,10 +90,10 @@ class CapBuilder(IBuilder[FlightPlanT, LayoutT], ABC):
|
||||
# buffer.
|
||||
distance_to_no_fly = (
|
||||
meters(position.distance(self.threat_zones.all))
|
||||
- self.doctrine.cap_engagement_range
|
||||
- self.doctrine.cap.engagement_range
|
||||
- nautical_miles(5)
|
||||
)
|
||||
max_track_length = self.doctrine.cap_max_track_length
|
||||
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
|
||||
@ -108,15 +108,15 @@ class CapBuilder(IBuilder[FlightPlanT, LayoutT], ABC):
|
||||
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
|
||||
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
|
||||
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
|
||||
self.doctrine.cap.max_distance_from_cp, distance_to_no_fly
|
||||
)
|
||||
|
||||
end = location.position.point_from_heading(
|
||||
@ -125,7 +125,7 @@ class CapBuilder(IBuilder[FlightPlanT, LayoutT], ABC):
|
||||
)
|
||||
|
||||
track_length = random.randint(
|
||||
int(self.doctrine.cap_min_track_length.meters),
|
||||
int(self.doctrine.cap.min_track_length.meters),
|
||||
int(max_track_length.meters),
|
||||
)
|
||||
start = end.point_from_heading(heading.opposite.degrees, track_length)
|
||||
|
||||
@ -44,7 +44,7 @@ class CasFlightPlan(PatrollingFlightPlan[CasLayout], UiZoneDisplay):
|
||||
|
||||
@property
|
||||
def patrol_duration(self) -> timedelta:
|
||||
return self.flight.coalition.doctrine.cas_duration
|
||||
return self.flight.coalition.doctrine.cas.duration
|
||||
|
||||
@property
|
||||
def patrol_speed(self) -> Speed:
|
||||
@ -96,7 +96,7 @@ class Builder(IBuilder[CasFlightPlan, CasLayout]):
|
||||
builder = WaypointBuilder(self.flight, self.coalition)
|
||||
|
||||
is_helo = self.flight.unit_type.dcs_unit_type.helicopter
|
||||
patrol_altitude = self.doctrine.ingress_altitude if not is_helo else meters(50)
|
||||
patrol_altitude = self.doctrine.resolve_combat_altitude(is_helo)
|
||||
use_agl_patrol_altitude = is_helo
|
||||
|
||||
ip_solver = IpSolver(
|
||||
|
||||
@ -33,7 +33,7 @@ class Builder(FormationAttackBuilder[EscortFlightPlan, FormationAttackLayout]):
|
||||
departure=builder.takeoff(self.flight.departure),
|
||||
hold=hold,
|
||||
nav_to=builder.nav_path(
|
||||
hold.position, join.position, self.doctrine.ingress_altitude
|
||||
hold.position, join.position, self.doctrine.combat_altitude
|
||||
),
|
||||
join=join,
|
||||
ingress=ingress,
|
||||
@ -43,7 +43,7 @@ class Builder(FormationAttackBuilder[EscortFlightPlan, FormationAttackLayout]):
|
||||
nav_from=builder.nav_path(
|
||||
refuel.position,
|
||||
self.flight.arrival.position,
|
||||
self.doctrine.ingress_altitude,
|
||||
self.doctrine.combat_altitude,
|
||||
),
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
|
||||
@ -163,7 +163,7 @@ class FormationAttackBuilder(IBuilder[FlightPlanT, LayoutT], ABC):
|
||||
departure=builder.takeoff(self.flight.departure),
|
||||
hold=hold,
|
||||
nav_to=builder.nav_path(
|
||||
hold.position, join.position, self.doctrine.ingress_altitude
|
||||
hold.position, join.position, self.doctrine.combat_altitude
|
||||
),
|
||||
join=join,
|
||||
ingress=ingress,
|
||||
@ -173,7 +173,7 @@ class FormationAttackBuilder(IBuilder[FlightPlanT, LayoutT], ABC):
|
||||
nav_from=builder.nav_path(
|
||||
refuel.position,
|
||||
self.flight.arrival.position,
|
||||
self.doctrine.ingress_altitude,
|
||||
self.doctrine.combat_altitude,
|
||||
),
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
|
||||
@ -114,11 +114,11 @@ class Builder(IBuilder[SweepFlightPlan, SweepLayout]):
|
||||
self.package.waypoints.join.heading_between_point(target)
|
||||
)
|
||||
start_pos = target.point_from_heading(
|
||||
heading.degrees, -self.doctrine.sweep_distance.meters
|
||||
heading.degrees, -self.doctrine.sweep.distance.meters
|
||||
)
|
||||
|
||||
builder = WaypointBuilder(self.flight, self.coalition)
|
||||
start, end = builder.sweep(start_pos, target, self.doctrine.ingress_altitude)
|
||||
start, end = builder.sweep(start_pos, target, self.doctrine.combat_altitude)
|
||||
|
||||
hold = builder.hold(self._hold_point())
|
||||
|
||||
@ -126,12 +126,12 @@ class Builder(IBuilder[SweepFlightPlan, SweepLayout]):
|
||||
departure=builder.takeoff(self.flight.departure),
|
||||
hold=hold,
|
||||
nav_to=builder.nav_path(
|
||||
hold.position, start.position, self.doctrine.ingress_altitude
|
||||
hold.position, start.position, self.doctrine.combat_altitude
|
||||
),
|
||||
nav_from=builder.nav_path(
|
||||
end.position,
|
||||
self.flight.arrival.position,
|
||||
self.doctrine.ingress_altitude,
|
||||
self.doctrine.combat_altitude,
|
||||
),
|
||||
sweep_start=start,
|
||||
sweep_end=end,
|
||||
|
||||
@ -40,7 +40,7 @@ class TarCapFlightPlan(PatrollingFlightPlan[TarCapLayout]):
|
||||
# flights in the package that have requested escort. If the package
|
||||
# requests an escort the CAP self.flight will remain on station for the
|
||||
# duration of the escorted mission, or until it is winchester/bingo.
|
||||
return self.flight.coalition.doctrine.cap_duration
|
||||
return self.flight.coalition.doctrine.cap.duration
|
||||
|
||||
@property
|
||||
def patrol_speed(self) -> Speed:
|
||||
@ -50,7 +50,7 @@ class TarCapFlightPlan(PatrollingFlightPlan[TarCapLayout]):
|
||||
|
||||
@property
|
||||
def engagement_distance(self) -> Distance:
|
||||
return self.flight.coalition.doctrine.cap_engagement_range
|
||||
return self.flight.coalition.doctrine.cap.engagement_range
|
||||
|
||||
@staticmethod
|
||||
def builder_type() -> Type[Builder]:
|
||||
@ -90,8 +90,8 @@ class Builder(CapBuilder[TarCapFlightPlan, TarCapLayout]):
|
||||
preferred_alt = self.flight.unit_type.preferred_patrol_altitude
|
||||
randomized_alt = preferred_alt + feet(random.randint(-2, 1) * 1000)
|
||||
patrol_alt = max(
|
||||
self.doctrine.min_patrol_altitude,
|
||||
min(self.doctrine.max_patrol_altitude, randomized_alt),
|
||||
self.doctrine.cap.min_patrol_altitude,
|
||||
min(self.doctrine.cap.max_patrol_altitude, randomized_alt),
|
||||
)
|
||||
|
||||
builder = WaypointBuilder(self.flight, self.coalition)
|
||||
|
||||
@ -72,7 +72,7 @@ class WaypointBuilder:
|
||||
"NAV",
|
||||
FlightWaypointType.NAV,
|
||||
position,
|
||||
meters(500) if self.is_helo else self.doctrine.rendezvous_altitude,
|
||||
self.doctrine.resolve_rendezvous_altitude(self.is_helo),
|
||||
description="Enter theater",
|
||||
pretty_name="Enter theater",
|
||||
)
|
||||
@ -99,7 +99,7 @@ class WaypointBuilder:
|
||||
"NAV",
|
||||
FlightWaypointType.NAV,
|
||||
position,
|
||||
meters(500) if self.is_helo else self.doctrine.rendezvous_altitude,
|
||||
self.doctrine.resolve_rendezvous_altitude(self.is_helo),
|
||||
description="Exit theater",
|
||||
pretty_name="Exit theater",
|
||||
)
|
||||
@ -127,10 +127,7 @@ class WaypointBuilder:
|
||||
position = divert.position
|
||||
altitude_type: AltitudeReference
|
||||
if isinstance(divert, OffMapSpawn):
|
||||
if self.is_helo:
|
||||
altitude = meters(500)
|
||||
else:
|
||||
altitude = self.doctrine.rendezvous_altitude
|
||||
altitude = self.doctrine.resolve_rendezvous_altitude(self.is_helo)
|
||||
altitude_type = "BARO"
|
||||
else:
|
||||
altitude = meters(0)
|
||||
@ -168,10 +165,7 @@ class WaypointBuilder:
|
||||
"HOLD",
|
||||
FlightWaypointType.LOITER,
|
||||
position,
|
||||
# Bug: DCS only accepts MSL altitudes for the orbit task and 500 meters is
|
||||
# below the ground for most if not all of NTTR (and lots of places in other
|
||||
# maps).
|
||||
meters(500) if self.is_helo else self.doctrine.rendezvous_altitude,
|
||||
self.doctrine.resolve_rendezvous_altitude(self.is_helo),
|
||||
alt_type,
|
||||
description="Wait until push time",
|
||||
pretty_name="Hold",
|
||||
@ -186,7 +180,7 @@ class WaypointBuilder:
|
||||
"JOIN",
|
||||
FlightWaypointType.JOIN,
|
||||
position,
|
||||
meters(80) if self.is_helo else self.doctrine.ingress_altitude,
|
||||
self.doctrine.resolve_combat_altitude(self.is_helo),
|
||||
alt_type,
|
||||
description="Rendezvous with package",
|
||||
pretty_name="Join",
|
||||
@ -201,7 +195,7 @@ class WaypointBuilder:
|
||||
"REFUEL",
|
||||
FlightWaypointType.REFUEL,
|
||||
position,
|
||||
meters(80) if self.is_helo else self.doctrine.ingress_altitude,
|
||||
self.doctrine.resolve_combat_altitude(self.is_helo),
|
||||
alt_type,
|
||||
description="Refuel from tanker",
|
||||
pretty_name="Refuel",
|
||||
@ -229,7 +223,7 @@ class WaypointBuilder:
|
||||
"SPLIT",
|
||||
FlightWaypointType.SPLIT,
|
||||
position,
|
||||
meters(80) if self.is_helo else self.doctrine.ingress_altitude,
|
||||
self.doctrine.resolve_combat_altitude(self.is_helo),
|
||||
alt_type,
|
||||
description="Depart from package",
|
||||
pretty_name="Split",
|
||||
@ -249,7 +243,7 @@ class WaypointBuilder:
|
||||
"INGRESS",
|
||||
ingress_type,
|
||||
position,
|
||||
meters(60) if self.is_helo else self.doctrine.ingress_altitude,
|
||||
self.doctrine.resolve_combat_altitude(self.is_helo),
|
||||
alt_type,
|
||||
description=f"INGRESS on {objective.name}",
|
||||
pretty_name=f"INGRESS on {objective.name}",
|
||||
@ -294,7 +288,7 @@ class WaypointBuilder:
|
||||
f"SEAD on {target.name}",
|
||||
target,
|
||||
flyover=True,
|
||||
altitude=self.doctrine.ingress_altitude,
|
||||
altitude=self.doctrine.combat_altitude,
|
||||
alt_type="BARO",
|
||||
)
|
||||
|
||||
@ -484,7 +478,7 @@ class WaypointBuilder:
|
||||
"TARGET",
|
||||
FlightWaypointType.TARGET_GROUP_LOC,
|
||||
target.position,
|
||||
meters(60) if self.is_helo else self.doctrine.ingress_altitude,
|
||||
self.doctrine.resolve_combat_altitude(self.is_helo),
|
||||
alt_type,
|
||||
description="Escort the package",
|
||||
pretty_name="Target area",
|
||||
|
||||
@ -158,7 +158,7 @@ class TheaterState(WorldState["TheaterState"]):
|
||||
# Plan enough rounds of CAP that the target has coverage over the expected
|
||||
# mission duration.
|
||||
mission_duration = game.settings.desired_player_mission_duration.total_seconds()
|
||||
barcap_duration = coalition.doctrine.cap_duration.total_seconds()
|
||||
barcap_duration = coalition.doctrine.cap.duration.total_seconds()
|
||||
barcap_rounds = math.ceil(mission_duration / barcap_duration)
|
||||
|
||||
refueling_targets: list[MissionTarget] = []
|
||||
|
||||
@ -2,7 +2,7 @@ from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import yaml
|
||||
from typing import ClassVar
|
||||
from typing import Any, ClassVar
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import timedelta
|
||||
@ -32,18 +32,94 @@ class GroundUnitProcurementRatios:
|
||||
return GroundUnitProcurementRatios(r)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Helicopter:
|
||||
#: The altitude used for combat section of a flight, overrides the base combat_altitude parameter for helos
|
||||
combat_altitude: Distance
|
||||
|
||||
#: The altitude used for forming up a pacakge. Overrides the base rendezvous_altitude parameter for helos
|
||||
rendezvous_altitude: Distance
|
||||
|
||||
#: Altitude of the nav points (cruise section) of air assault missions.
|
||||
air_assault_nav_altitude: Distance
|
||||
|
||||
@staticmethod
|
||||
def from_dict(data: dict[str, Any]) -> Helicopter:
|
||||
return Helicopter(
|
||||
combat_altitude=feet(data["combat_altitude_ft_agl"]),
|
||||
rendezvous_altitude=feet(data["rendezvous_altitude_ft_agl"]),
|
||||
air_assault_nav_altitude=feet(data["air_assault_nav_altitude_ft_agl"]),
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Cas:
|
||||
#: The duration that CAP flights will remain on-station.
|
||||
duration: timedelta
|
||||
|
||||
@staticmethod
|
||||
def from_dict(data: dict[str, Any]) -> Cas:
|
||||
return Cas(duration=timedelta(minutes=data["duration_minutes"]))
|
||||
|
||||
|
||||
@dataclass
|
||||
class Sweep:
|
||||
#: Length of the sweep / patrol leg
|
||||
distance: Distance
|
||||
|
||||
@staticmethod
|
||||
def from_dict(data: dict[str, Any]) -> Sweep:
|
||||
return Sweep(
|
||||
distance=nautical_miles(data["distance_nm"]),
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Cap:
|
||||
#: The duration that CAP flights will remain on-station.
|
||||
duration: timedelta
|
||||
|
||||
#: The minimum length of the CAP race track.
|
||||
min_track_length: Distance
|
||||
|
||||
#: The maximum length of the CAP race track.
|
||||
max_track_length: Distance
|
||||
|
||||
#: The minimum distance between the defended position and the *end* of the
|
||||
#: CAP race track.
|
||||
min_distance_from_cp: Distance
|
||||
|
||||
#: The maximum distance between the defended position and the *end* of the
|
||||
#: CAP race track.
|
||||
max_distance_from_cp: Distance
|
||||
|
||||
#: The engagement range of CAP flights. Any enemy aircraft within this range
|
||||
#: of the CAP's current position will be engaged by the CAP.
|
||||
engagement_range: Distance
|
||||
|
||||
#: Defines the range of altitudes CAP racetracks are planned at.
|
||||
min_patrol_altitude: Distance
|
||||
max_patrol_altitude: Distance
|
||||
|
||||
@staticmethod
|
||||
def from_dict(data: dict[str, Any]) -> Cap:
|
||||
return Cap(
|
||||
duration=timedelta(minutes=data["duration_minutes"]),
|
||||
min_track_length=nautical_miles(data["min_track_length_nm"]),
|
||||
max_track_length=nautical_miles(data["max_track_length_nm"]),
|
||||
min_distance_from_cp=nautical_miles(data["min_distance_from_cp_nm"]),
|
||||
max_distance_from_cp=nautical_miles(data["max_distance_from_cp_nm"]),
|
||||
engagement_range=nautical_miles(data["engagement_range_nm"]),
|
||||
min_patrol_altitude=feet(data["min_patrol_altitude_ft_msl"]),
|
||||
max_patrol_altitude=feet(data["max_patrol_altitude_ft_msl"]),
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Doctrine:
|
||||
#: Name of the doctrine, used to assign a doctrine in a faction.
|
||||
name: str
|
||||
|
||||
cas: bool
|
||||
cap: bool
|
||||
sead: bool
|
||||
strike: bool
|
||||
antiship: bool
|
||||
|
||||
rendezvous_altitude: Distance
|
||||
|
||||
#: The minimum distance between the departure airfield and the hold point.
|
||||
hold_distance: Distance
|
||||
|
||||
@ -62,42 +138,40 @@ class Doctrine:
|
||||
#: target.
|
||||
min_ingress_distance: Distance
|
||||
|
||||
ingress_altitude: Distance
|
||||
#: The altitude used for combat section of a flight.
|
||||
combat_altitude: Distance
|
||||
|
||||
min_patrol_altitude: Distance
|
||||
max_patrol_altitude: Distance
|
||||
pattern_altitude: Distance
|
||||
|
||||
#: The duration that CAP flights will remain on-station.
|
||||
cap_duration: timedelta
|
||||
|
||||
#: The minimum length of the CAP race track.
|
||||
cap_min_track_length: Distance
|
||||
|
||||
#: The maximum length of the CAP race track.
|
||||
cap_max_track_length: Distance
|
||||
|
||||
#: The minimum distance between the defended position and the *end* of the
|
||||
#: CAP race track.
|
||||
cap_min_distance_from_cp: Distance
|
||||
|
||||
#: The maximum distance between the defended position and the *end* of the
|
||||
#: CAP race track.
|
||||
cap_max_distance_from_cp: Distance
|
||||
|
||||
#: The engagement range of CAP flights. Any enemy aircraft within this range
|
||||
#: of the CAP's current position will be engaged by the CAP.
|
||||
cap_engagement_range: Distance
|
||||
|
||||
cas_duration: timedelta
|
||||
|
||||
sweep_distance: Distance
|
||||
#: The altitude used for forming up a pacakge.
|
||||
rendezvous_altitude: Distance
|
||||
|
||||
#: Defines prioritization of ground unit purchases.
|
||||
ground_unit_procurement_ratios: GroundUnitProcurementRatios
|
||||
|
||||
#: Helicopter specific doctrines.
|
||||
helicopter: Helicopter
|
||||
|
||||
#: Doctrine for CAS missions.
|
||||
cas: Cas
|
||||
|
||||
#: Doctrine for CAP missions.
|
||||
cap: Cap
|
||||
|
||||
#: Doctrine for Fighter Sweep missions.
|
||||
sweep: Sweep
|
||||
|
||||
_by_name: ClassVar[dict[str, Doctrine]] = {}
|
||||
_loaded: ClassVar[bool] = False
|
||||
|
||||
def resolve_combat_altitude(self, is_helo: bool = False) -> Distance:
|
||||
if is_helo:
|
||||
return self.helicopter.combat_altitude
|
||||
return self.combat_altitude
|
||||
|
||||
def resolve_rendezvous_altitude(self, is_helo: bool = False) -> Distance:
|
||||
if is_helo:
|
||||
return self.helicopter.rendezvous_altitude
|
||||
return self.rendezvous_altitude
|
||||
|
||||
@classmethod
|
||||
def register(cls, doctrine: Doctrine) -> None:
|
||||
if doctrine.name in cls._by_name:
|
||||
@ -127,11 +201,6 @@ class Doctrine:
|
||||
cls.register(
|
||||
Doctrine(
|
||||
name=data["name"],
|
||||
cap=data["cap"],
|
||||
cas=data["cas"],
|
||||
sead=data["sead"],
|
||||
strike=data["strike"],
|
||||
antiship=data["antiship"],
|
||||
rendezvous_altitude=feet(data["rendezvous_altitude_ft_msl"]),
|
||||
hold_distance=nautical_miles(data["hold_distance_nm"]),
|
||||
push_distance=nautical_miles(data["push_distance_nm"]),
|
||||
@ -142,31 +211,14 @@ class Doctrine:
|
||||
min_ingress_distance=nautical_miles(
|
||||
data["min_ingress_distance_nm"]
|
||||
),
|
||||
ingress_altitude=feet(data["ingress_altitude_ft_msl"]),
|
||||
min_patrol_altitude=feet(data["min_patrol_altitude_ft_msl"]),
|
||||
max_patrol_altitude=feet(data["max_patrol_altitude_ft_msl"]),
|
||||
pattern_altitude=feet(data["pattern_altitude_ft_msl"]),
|
||||
cap_duration=timedelta(minutes=data["cap_duration_minutes"]),
|
||||
cap_min_track_length=nautical_miles(
|
||||
data["cap_min_track_length_nm"]
|
||||
),
|
||||
cap_max_track_length=nautical_miles(
|
||||
data["cap_max_track_length_nm"]
|
||||
),
|
||||
cap_min_distance_from_cp=nautical_miles(
|
||||
data["cap_min_distance_from_cp_nm"]
|
||||
),
|
||||
cap_max_distance_from_cp=nautical_miles(
|
||||
data["cap_max_distance_from_cp_nm"]
|
||||
),
|
||||
cap_engagement_range=nautical_miles(
|
||||
data["cap_engagement_range_nm"]
|
||||
),
|
||||
cas_duration=timedelta(minutes=data["cas_duration_minutes"]),
|
||||
sweep_distance=nautical_miles(data["sweep_distance_nm"]),
|
||||
combat_altitude=feet(data["combat_altitude_ft_msl"]),
|
||||
ground_unit_procurement_ratios=GroundUnitProcurementRatios.from_dict(
|
||||
data["ground_unit_procurement_ratios"]
|
||||
),
|
||||
helicopter=Helicopter.from_dict(data["helicopter"]),
|
||||
cas=Cas.from_dict(data["cas"]),
|
||||
cap=Cap.from_dict(data["cap"]),
|
||||
sweep=Sweep.from_dict(data["sweep"]),
|
||||
)
|
||||
)
|
||||
cls._loaded = True
|
||||
|
||||
@ -165,7 +165,7 @@ class ThreatZones:
|
||||
cls, doctrine: Doctrine, control_point: ControlPoint
|
||||
) -> Distance:
|
||||
cap_threat_range = (
|
||||
doctrine.cap_max_distance_from_cp + doctrine.cap_engagement_range
|
||||
doctrine.cap.max_distance_from_cp + doctrine.cap.engagement_range
|
||||
)
|
||||
opposing_airfield = cls.closest_enemy_airbase(
|
||||
control_point, cap_threat_range * 2
|
||||
|
||||
@ -1,27 +1,24 @@
|
||||
name: coldwar
|
||||
cap: true
|
||||
cas: true
|
||||
sead: true
|
||||
strike: true
|
||||
antiship: true
|
||||
rendezvous_altitude_ft_msl: 22000
|
||||
hold_distance_nm: 15
|
||||
push_distance_nm: 10
|
||||
join_distance_nm: 10
|
||||
max_ingress_distance_nm: 30
|
||||
min_ingress_distance_nm: 10
|
||||
ingress_altitude_ft_msl: 18000
|
||||
min_patrol_altitude_ft_msl: 10000
|
||||
max_patrol_altitude_ft_msl: 24000
|
||||
pattern_altitude_ft_msl: 5000
|
||||
cap_duration_minutes: 30
|
||||
cap_min_track_length_nm: 12
|
||||
cap_max_track_length_nm: 24
|
||||
cap_min_distance_from_cp_nm: 8
|
||||
cap_max_distance_from_cp_nm: 25
|
||||
cap_engagement_range_nm: 35
|
||||
cas_duration_minutes: 30
|
||||
sweep_distance_nm: 40
|
||||
rendezvous_altitude_ft_msl: 22000
|
||||
combat_altitude_ft_msl: 18000
|
||||
cap:
|
||||
duration_minutes: 30
|
||||
min_track_length_nm: 12
|
||||
max_track_length_nm: 24
|
||||
min_distance_from_cp_nm: 8
|
||||
max_distance_from_cp_nm: 25
|
||||
engagement_range_nm: 35
|
||||
min_patrol_altitude_ft_msl: 10000
|
||||
max_patrol_altitude_ft_msl: 24000
|
||||
cas:
|
||||
duration_minutes: 30
|
||||
sweep:
|
||||
distance_nm: 40
|
||||
ground_unit_procurement_ratios:
|
||||
Tank: 4
|
||||
ATGM: 2
|
||||
@ -30,3 +27,8 @@ ground_unit_procurement_ratios:
|
||||
Artillery: 1
|
||||
SHORAD: 2
|
||||
Recon: 1
|
||||
helicopter:
|
||||
combat_altitude_ft_agl: 200
|
||||
rendezvous_altitude_ft_agl: 1500
|
||||
air_assault_nav_altitude_ft_agl: 1500
|
||||
|
||||
|
||||
@ -1,27 +1,24 @@
|
||||
name: modern
|
||||
cap: true
|
||||
cas: true
|
||||
sead: true
|
||||
strike: true
|
||||
antiship: true
|
||||
rendezvous_altitude_ft_msl: 25000
|
||||
hold_distance_nm: 25
|
||||
push_distance_nm: 20
|
||||
join_distance_nm: 20
|
||||
max_ingress_distance_nm: 45
|
||||
min_ingress_distance_nm: 10
|
||||
ingress_altitude_ft_msl: 20000
|
||||
min_patrol_altitude_ft_msl: 15000
|
||||
max_patrol_altitude_ft_msl: 33000
|
||||
pattern_altitude_ft_msl: 5000
|
||||
cap_duration_minutes: 30
|
||||
cap_min_track_length_nm: 15
|
||||
cap_max_track_length_nm: 40
|
||||
cap_min_distance_from_cp_nm: 10
|
||||
cap_max_distance_from_cp_nm: 40
|
||||
cap_engagement_range_nm: 50
|
||||
cas_duration_minutes: 30
|
||||
sweep_distance_nm: 60
|
||||
rendezvous_altitude_ft_msl: 25000
|
||||
combat_altitude_ft_msl: 20000
|
||||
cap:
|
||||
duration_minutes: 30
|
||||
min_track_length_nm: 15
|
||||
max_track_length_nm: 40
|
||||
min_distance_from_cp_nm: 10
|
||||
max_distance_from_cp_nm: 40
|
||||
engagement_range_nm: 50
|
||||
min_patrol_altitude_ft_msl: 15000
|
||||
max_patrol_altitude_ft_msl: 33000
|
||||
cas:
|
||||
duration_minutes: 30
|
||||
sweep:
|
||||
distance_nm: 60
|
||||
ground_unit_procurement_ratios:
|
||||
Tank: 3
|
||||
ATGM: 2
|
||||
@ -30,3 +27,7 @@ ground_unit_procurement_ratios:
|
||||
Artillery: 1
|
||||
SHORAD: 2
|
||||
Recon: 1
|
||||
helicopter:
|
||||
combat_altitude_ft_agl: 200
|
||||
rendezvous_altitude_ft_agl: 1500
|
||||
air_assault_nav_altitude_ft_agl: 1500
|
||||
|
||||
@ -1,27 +1,24 @@
|
||||
name: ww2
|
||||
cap: true
|
||||
cas: true
|
||||
sead: false
|
||||
strike: true
|
||||
antiship: true
|
||||
hold_distance_nm: 10
|
||||
push_distance_nm: 5
|
||||
join_distance_nm: 5
|
||||
rendezvous_altitude_ft_msl: 10000
|
||||
max_ingress_distance_nm: 7
|
||||
min_ingress_distance_nm: 5
|
||||
ingress_altitude_ft_msl: 8000
|
||||
min_patrol_altitude_ft_msl: 4000
|
||||
max_patrol_altitude_ft_msl: 15000
|
||||
pattern_altitude_ft_msl: 5000
|
||||
cap_duration_minutes: 30
|
||||
cap_min_track_length_nm: 8
|
||||
cap_max_track_length_nm: 18
|
||||
cap_min_distance_from_cp_nm: 0
|
||||
cap_max_distance_from_cp_nm: 5
|
||||
cap_engagement_range_nm: 20
|
||||
cas_duration_minutes: 30
|
||||
sweep_distance_nm: 10
|
||||
rendezvous_altitude_ft_msl: 10000
|
||||
combat_altitude_ft_msl: 8000
|
||||
cap:
|
||||
duration_minutes: 30
|
||||
min_track_length_nm: 8
|
||||
max_track_length_nm: 18
|
||||
min_distance_from_cp_nm: 0
|
||||
max_distance_from_cp_nm: 5
|
||||
engagement_range_nm: 20
|
||||
min_patrol_altitude_ft_msl: 4000
|
||||
max_patrol_altitude_ft_msl: 15000
|
||||
cas:
|
||||
duration_minutes: 30
|
||||
sweep:
|
||||
distance_nm: 10
|
||||
ground_unit_procurement_ratios:
|
||||
Tank: 3
|
||||
ATGM: 3
|
||||
@ -29,3 +26,7 @@ ground_unit_procurement_ratios:
|
||||
Artillery: 1
|
||||
SHORAD: 3
|
||||
Recon: 1
|
||||
helicopter:
|
||||
combat_altitude_ft_agl: 200
|
||||
rendezvous_altitude_ft_agl: 1500
|
||||
air_assault_nav_altitude_ft_agl: 1500
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user