diff --git a/game/ato/flightplans/escort.py b/game/ato/flightplans/escort.py index 1ecfaba6..794f5cf1 100644 --- a/game/ato/flightplans/escort.py +++ b/game/ato/flightplans/escort.py @@ -1,6 +1,5 @@ from __future__ import annotations -from datetime import timedelta, datetime from typing import Type from .airassault import AirAssaultLayout @@ -16,18 +15,6 @@ from ...utils import feet class EscortFlightPlan(FormationAttackFlightPlan): - @property - def push_time(self) -> datetime: - hold2join_time = ( - self.travel_time_between_waypoints( - self.layout.hold, - self.layout.join, - ) - if self.layout.hold is not None - else timedelta(0) - ) - return self.join_time - hold2join_time - @staticmethod def builder_type() -> Type[Builder]: return Builder @@ -74,10 +61,10 @@ class Builder(FormationAttackBuilder[EscortFlightPlan, FormationAttackLayout]): ascent = layout.pickup_ascent or layout.drop_off_ascent assert ascent is not None join = builder.join(ascent.position) - else: - join = builder.join(layout.ingress.position) - if layout.pickup and layout.drop_off_ascent: - join = builder.join(layout.drop_off_ascent.position) + if layout.pickup and layout.drop_off_ascent: + join = builder.join(layout.drop_off_ascent.position) + elif layout.pickup: + join = builder.join(layout.pickup.position) split = builder.split(layout.arrival.position) if layout.drop_off: initial = builder.escort_hold( diff --git a/game/ato/flightplans/flightplan.py b/game/ato/flightplans/flightplan.py index 91ac8af9..196ab3f1 100644 --- a/game/ato/flightplans/flightplan.py +++ b/game/ato/flightplans/flightplan.py @@ -104,6 +104,19 @@ class FlightPlan(ABC, Generic[LayoutT]): # # Plus, it's a loiter point so there's no reason to hurry. factor = 0.75 + elif ( + self.flight.is_helo + and ( + a.waypoint_type == FlightWaypointType.JOIN + or "INGRESS" in a.waypoint_type.name + or a.waypoint_type == FlightWaypointType.CUSTOM + ) + and self.package.primary_flight + and not self.package.primary_flight.flight_plan.is_airassault + ): + # Helicopter flights should be slowed down between JOIN & INGRESS + # to allow the escort to keep up while engaging targets along the way. + factor = 0.50 # TODO: Adjust if AGL. # We don't have an exact heightmap, but we should probably be performing # *some* adjustment for NTTR since the minimum altitude of the map is diff --git a/game/ato/flightplans/formation.py b/game/ato/flightplans/formation.py index 9be8c287..92d4aba8 100644 --- a/game/ato/flightplans/formation.py +++ b/game/ato/flightplans/formation.py @@ -92,10 +92,15 @@ class FormationFlightPlan(LoiterFlightPlan, ABC): @property def push_time(self) -> datetime: - return self.join_time - self.travel_time_between_waypoints( - self.layout.hold, - self.layout.join, + hold2join_time = ( + self.travel_time_between_waypoints( + self.layout.hold, + self.layout.join, + ) + if self.layout.hold + else timedelta(0) ) + return self.join_time - hold2join_time @property def mission_begin_on_station_time(self) -> datetime | None: diff --git a/game/ato/flightplans/waypointbuilder.py b/game/ato/flightplans/waypointbuilder.py index ba63601b..3ed23cb3 100644 --- a/game/ato/flightplans/waypointbuilder.py +++ b/game/ato/flightplans/waypointbuilder.py @@ -248,10 +248,14 @@ class WaypointBuilder: else feet(1000) ) + heading = objective.position.heading_between_point(position) + return FlightWaypoint( "INGRESS", ingress_type, - position, + objective.position.point_from_heading(heading, nautical_miles(5).meters) + if self.is_helo + else position, alt, alt_type, description=f"INGRESS on {objective.name}", diff --git a/game/missiongenerator/aircraft/waypoints/joinpoint.py b/game/missiongenerator/aircraft/waypoints/joinpoint.py index 36724470..19056df9 100644 --- a/game/missiongenerator/aircraft/waypoints/joinpoint.py +++ b/game/missiongenerator/aircraft/waypoints/joinpoint.py @@ -94,7 +94,11 @@ class JoinPointBuilder(PydcsWaypointBuilder): max_dist: float = 30.0, vertical_spacing: float = 2000.0, ) -> None: - waypoint.tasks.append(OptROE(value=OptROE.Values.OpenFire)) + if self.flight.is_helo: + # Make helicopters a bit more aggressive + waypoint.tasks.append(OptROE(value=OptROE.Values.OpenFireWeaponFree)) + else: + waypoint.tasks.append(OptROE(value=OptROE.Values.OpenFire)) rx = (random.random() + 0.1) * 333 ry = feet(vertical_spacing).meters diff --git a/game/missiongenerator/aircraft/waypoints/splitpoint.py b/game/missiongenerator/aircraft/waypoints/splitpoint.py index b9394ba1..f3fe891e 100644 --- a/game/missiongenerator/aircraft/waypoints/splitpoint.py +++ b/game/missiongenerator/aircraft/waypoints/splitpoint.py @@ -7,6 +7,7 @@ from dcs.task import ( SwitchWaypoint, ) +from game.utils import knots from .pydcswaypointbuilder import PydcsWaypointBuilder @@ -29,10 +30,12 @@ class SplitPointBuilder(PydcsWaypointBuilder): waypoint.tasks.append(OptFormation.rotary_wedge()) else: waypoint.tasks.append(OptFormation.finger_four_close()) - if not self.flight.is_helo: - waypoint.speed_locked = True + waypoint.speed_locked = True + waypoint.ETA_locked = False + if self.flight.is_helo: + waypoint.speed = knots(100).meters_per_second + else: waypoint.speed = self.flight.coalition.doctrine.rtb_speed.meters_per_second - waypoint.ETA_locked = False if self.flight is self.package.primary_flight: script = RunScript( f'trigger.action.setUserFlag("split-{id(self.package)}", true)'