diff --git a/game/ato/flightplans/airassault.py b/game/ato/flightplans/airassault.py index ac37640b..e74b4102 100644 --- a/game/ato/flightplans/airassault.py +++ b/game/ato/flightplans/airassault.py @@ -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) diff --git a/game/ato/flightplans/barcap.py b/game/ato/flightplans/barcap.py index 43c5535e..401a6e8b 100644 --- a/game/ato/flightplans/barcap.py +++ b/game/ato/flightplans/barcap.py @@ -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) diff --git a/game/ato/flightplans/capbuilder.py b/game/ato/flightplans/capbuilder.py index 260c6d44..40fce198 100644 --- a/game/ato/flightplans/capbuilder.py +++ b/game/ato/flightplans/capbuilder.py @@ -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) diff --git a/game/ato/flightplans/cas.py b/game/ato/flightplans/cas.py index ef8472e2..b27d762b 100644 --- a/game/ato/flightplans/cas.py +++ b/game/ato/flightplans/cas.py @@ -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( diff --git a/game/ato/flightplans/escort.py b/game/ato/flightplans/escort.py index 5e1ca54d..3d52466d 100644 --- a/game/ato/flightplans/escort.py +++ b/game/ato/flightplans/escort.py @@ -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), diff --git a/game/ato/flightplans/formationattack.py b/game/ato/flightplans/formationattack.py index 0e9e0f2a..bd19b1c0 100644 --- a/game/ato/flightplans/formationattack.py +++ b/game/ato/flightplans/formationattack.py @@ -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), diff --git a/game/ato/flightplans/sweep.py b/game/ato/flightplans/sweep.py index a81eb0b2..7dddca7d 100644 --- a/game/ato/flightplans/sweep.py +++ b/game/ato/flightplans/sweep.py @@ -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, diff --git a/game/ato/flightplans/tarcap.py b/game/ato/flightplans/tarcap.py index 3f6d4ac4..53fb546c 100644 --- a/game/ato/flightplans/tarcap.py +++ b/game/ato/flightplans/tarcap.py @@ -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) diff --git a/game/ato/flightplans/waypointbuilder.py b/game/ato/flightplans/waypointbuilder.py index 499cfd95..37be083c 100644 --- a/game/ato/flightplans/waypointbuilder.py +++ b/game/ato/flightplans/waypointbuilder.py @@ -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", diff --git a/game/commander/theaterstate.py b/game/commander/theaterstate.py index fa283e0c..bc8d7166 100644 --- a/game/commander/theaterstate.py +++ b/game/commander/theaterstate.py @@ -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] = [] diff --git a/game/data/doctrine.py b/game/data/doctrine.py index 8a260984..91f5b81a 100644 --- a/game/data/doctrine.py +++ b/game/data/doctrine.py @@ -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 diff --git a/game/threatzones.py b/game/threatzones.py index 07fec2bd..48c955da 100644 --- a/game/threatzones.py +++ b/game/threatzones.py @@ -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 diff --git a/resources/doctrines/coldwar.yaml b/resources/doctrines/coldwar.yaml index be1a9fce..192d38fe 100644 --- a/resources/doctrines/coldwar.yaml +++ b/resources/doctrines/coldwar.yaml @@ -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 + diff --git a/resources/doctrines/modern.yaml b/resources/doctrines/modern.yaml index c2b4a314..2e913742 100644 --- a/resources/doctrines/modern.yaml +++ b/resources/doctrines/modern.yaml @@ -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 diff --git a/resources/doctrines/ww2.yaml b/resources/doctrines/ww2.yaml index 20549444..da041591 100644 --- a/resources/doctrines/ww2.yaml +++ b/resources/doctrines/ww2.yaml @@ -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