From fd473f0a46d140f54b9610485d0ebbdad8e13f7c Mon Sep 17 00:00:00 2001 From: Dan Albert Date: Thu, 19 Nov 2020 00:29:05 -0800 Subject: [PATCH] Fix custom waypoints. Like with deleting waypoints, these will degrade the flight plan to the 2.1 behavior. Ascend/descend points aren't in use any more, so I removed those. --- gen/flights/flightplan.py | 39 ++---------- gen/flights/traveltime.py | 7 ++- gen/flights/waypointbuilder.py | 57 ------------------ .../QPredefinedWaypointSelectionComboBox.py | 3 +- .../flight/waypoints/QFlightWaypointTab.py | 60 +++++++------------ .../QPredefinedWaypointSelectionWindow.py | 29 +++++---- theater/theatergroundobject.py | 8 +++ 7 files changed, 59 insertions(+), 144 deletions(-) diff --git a/gen/flights/flightplan.py b/gen/flights/flightplan.py index 7919ae9f..430a8c11 100644 --- a/gen/flights/flightplan.py +++ b/gen/flights/flightplan.py @@ -659,7 +659,6 @@ class FlightPlanBuilder: builder = WaypointBuilder(self.game.conditions, flight, self.doctrine) start, end = builder.race_track(start, end, patrol_alt) - descent, land = builder.rtb(flight.from_cp) return BarCapFlightPlan( package=self.package, @@ -668,7 +667,7 @@ class FlightPlanBuilder: takeoff=builder.takeoff(flight.from_cp), patrol_start=start, patrol_end=end, - land=land + land=builder.land(flight.from_cp) ) def generate_frontline_cap(self, flight: Flight) -> FrontLineCapFlightPlan: @@ -707,9 +706,8 @@ class FlightPlanBuilder: # Create points builder = WaypointBuilder(self.game.conditions, flight, self.doctrine) - start, end = builder.race_track(orbit0p, orbit1p, patrol_alt) - descent, land = builder.rtb(flight.from_cp) + return FrontLineCapFlightPlan( package=self.package, flight=flight, @@ -721,7 +719,7 @@ class FlightPlanBuilder: takeoff=builder.takeoff(flight.from_cp), patrol_start=start, patrol_end=end, - land=land + land=builder.land(flight.from_cp) ) def generate_dead(self, flight: Flight, @@ -780,7 +778,6 @@ class FlightPlanBuilder: ingress, target, egress = builder.escort( self.package.waypoints.ingress, self.package.target, self.package.waypoints.egress) - descent, land = builder.rtb(flight.from_cp) return StrikeFlightPlan( package=self.package, @@ -792,7 +789,7 @@ class FlightPlanBuilder: targets=[target], egress=egress, split=builder.split(self.package.waypoints.split), - land=land + land=builder.land(flight.from_cp) ) def generate_cas(self, flight: Flight) -> CasFlightPlan: @@ -814,7 +811,6 @@ class FlightPlanBuilder: egress = ingress.point_from_heading(heading, distance) builder = WaypointBuilder(self.game.conditions, flight, self.doctrine) - descent, land = builder.rtb(flight.from_cp) return CasFlightPlan( package=self.package, @@ -824,7 +820,7 @@ class FlightPlanBuilder: patrol_start=builder.ingress_cas(ingress, location), target=builder.cas(center), patrol_end=builder.egress(egress, location), - land=land + land=builder.land(flight.from_cp) ) @staticmethod @@ -894,28 +890,6 @@ class FlightPlanBuilder: self.doctrine.hold_distance) # TODO: Make a model for the waypoint builder and use that in the UI. - def generate_ascend_point(self, flight: Flight, - departure: ControlPoint) -> FlightWaypoint: - """Generate ascend point. - - Args: - flight: The flight to generate the descend point for. - departure: Departure airfield or carrier. - """ - builder = WaypointBuilder(self.game.conditions, flight, self.doctrine) - return builder.ascent(departure) - - def generate_descend_point(self, flight: Flight, - arrival: ControlPoint) -> FlightWaypoint: - """Generate approach/descend point. - - Args: - flight: The flight to generate the descend point for. - arrival: Arrival airfield or carrier. - """ - builder = WaypointBuilder(self.game.conditions, flight, self.doctrine) - return builder.descent(arrival) - def generate_rtb_waypoint(self, flight: Flight, arrival: ControlPoint) -> FlightWaypoint: """Generate RTB landing point. @@ -954,7 +928,6 @@ class FlightPlanBuilder: target_waypoints.append( self.target_area_waypoint(flight, location, builder)) - descent, land = builder.rtb(flight.from_cp) return StrikeFlightPlan( package=self.package, flight=flight, @@ -965,7 +938,7 @@ class FlightPlanBuilder: targets=target_waypoints, egress=builder.egress(self.package.waypoints.egress, location), split=builder.split(self.package.waypoints.split), - land=land + land=builder.land(flight.from_cp) ) def _retreating_rendezvous_point(self, attack_transition: Point) -> Point: diff --git a/gen/flights/traveltime.py b/gen/flights/traveltime.py index 17f8ec36..0bddfcaf 100644 --- a/gen/flights/traveltime.py +++ b/gen/flights/traveltime.py @@ -118,8 +118,11 @@ class TotEstimator: def takeoff_time_for_flight(self, flight: Flight) -> Optional[timedelta]: travel_time = self.travel_time_to_rendezvous_or_target(flight) if travel_time is None: - logging.warning("Found no rendezvous or target point. Cannot " - f"estimate takeoff time takeoff time for {flight}") + from gen.flights.flightplan import CustomFlightPlan + if not isinstance(flight.flight_plan, CustomFlightPlan): + logging.warning( + "Found no rendezvous or target point. Cannot estimate " + f"takeoff time takeoff time for {flight}.") return None from gen.flights.flightplan import FormationFlightPlan diff --git a/gen/flights/waypointbuilder.py b/gen/flights/waypointbuilder.py index ddc76b5f..3b67e8e0 100644 --- a/gen/flights/waypointbuilder.py +++ b/gen/flights/waypointbuilder.py @@ -7,11 +7,9 @@ from dcs.mapping import Point from dcs.unit import Unit from game.data.doctrine import Doctrine -from game.utils import nm_to_meter from game.weather import Conditions from theater import ControlPoint, MissionTarget, TheaterGroundObject from .flight import Flight, FlightWaypoint, FlightWaypointType -from ..runways import RunwayAssigner @dataclass(frozen=True) @@ -57,52 +55,6 @@ class WaypointBuilder: waypoint.pretty_name = "Takeoff" return waypoint - def ascent(self, departure: ControlPoint) -> FlightWaypoint: - """Create ascent waypoint for the given departure airfield or carrier. - - Args: - departure: Departure airfield or carrier. - """ - heading = RunwayAssigner(self.conditions).takeoff_heading(departure) - position = departure.position.point_from_heading( - heading, nm_to_meter(5) - ) - waypoint = FlightWaypoint( - FlightWaypointType.ASCEND_POINT, - position.x, - position.y, - 500 if self.is_helo else self.doctrine.pattern_altitude - ) - waypoint.name = "ASCEND" - waypoint.alt_type = "RADIO" - waypoint.description = "Ascend" - waypoint.pretty_name = "Ascend" - return waypoint - - def descent(self, arrival: ControlPoint) -> FlightWaypoint: - """Create descent waypoint for the given arrival airfield or carrier. - - Args: - arrival: Arrival airfield or carrier. - """ - landing_heading = RunwayAssigner(self.conditions).landing_heading( - arrival) - heading = (landing_heading + 180) % 360 - position = arrival.position.point_from_heading( - heading, nm_to_meter(5) - ) - waypoint = FlightWaypoint( - FlightWaypointType.DESCENT_POINT, - position.x, - position.y, - 300 if self.is_helo else self.doctrine.pattern_altitude - ) - waypoint.name = "DESCEND" - waypoint.alt_type = "RADIO" - waypoint.description = "Descend to pattern altitude" - waypoint.pretty_name = "Descend" - return waypoint - @staticmethod def land(arrival: ControlPoint) -> FlightWaypoint: """Create descent waypoint for the given arrival airfield or carrier. @@ -326,15 +278,6 @@ class WaypointBuilder: return (self.race_track_start(start, altitude), self.race_track_end(end, altitude)) - def rtb(self, - arrival: ControlPoint) -> Tuple[FlightWaypoint, FlightWaypoint]: - """Creates descent ant landing waypoints for the given control point. - - Args: - arrival: Arrival airfield or carrier. - """ - return self.descent(arrival), self.land(arrival) - def escort(self, ingress: Point, target: MissionTarget, egress: Point) -> \ Tuple[FlightWaypoint, FlightWaypoint, FlightWaypoint]: """Creates the waypoints needed to escort the package. diff --git a/qt_ui/widgets/combos/QPredefinedWaypointSelectionComboBox.py b/qt_ui/widgets/combos/QPredefinedWaypointSelectionComboBox.py index 72ece41e..2a9f8bc9 100644 --- a/qt_ui/widgets/combos/QPredefinedWaypointSelectionComboBox.py +++ b/qt_ui/widgets/combos/QPredefinedWaypointSelectionComboBox.py @@ -44,7 +44,6 @@ class QPredefinedWaypointSelectionComboBox(QFilteredComboBox): i = 0 def add_model_item(i, model, name, wpt): - print(name) item = QStandardItem(name) model.setItem(i, 0, item) self.wpts.append(wpt) @@ -79,7 +78,7 @@ class QPredefinedWaypointSelectionComboBox(QFilteredComboBox): 0 ) wpt.alt_type = "RADIO" - wpt.name = wpt.name = "[" + str(ground_object.obj_name) + "] : " + ground_object.category + " #" + str(ground_object.object_id) + wpt.name = ground_object.waypoint_name wpt.pretty_name = wpt.name wpt.obj_name = ground_object.obj_name wpt.targets.append(ground_object) diff --git a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointTab.py b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointTab.py index 4352ac47..c480da2a 100644 --- a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointTab.py +++ b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointTab.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import Iterable, List, Optional from PySide2.QtCore import Signal from PySide2.QtWidgets import ( @@ -20,7 +20,7 @@ from gen.flights.flightplan import ( ) from qt_ui.windows.mission.flight.waypoints.QFlightWaypointList import \ QFlightWaypointList -from qt_ui.windows.mission.flight.waypoints\ +from qt_ui.windows.mission.flight.waypoints \ .QPredefinedWaypointSelectionWindow import \ QPredefinedWaypointSelectionWindow from theater import FrontLine @@ -38,8 +38,6 @@ class QFlightWaypointTab(QFrame): self.planner = FlightPlanBuilder(self.game, package, is_player=True) self.flight_waypoint_list: Optional[QFlightWaypointList] = None - self.ascend_waypoint: Optional[QPushButton] = None - self.descend_waypoint: Optional[QPushButton] = None self.rtb_waypoint: Optional[QPushButton] = None self.delete_selected: Optional[QPushButton] = None self.open_fast_waypoint_button: Optional[QPushButton] = None @@ -82,14 +80,6 @@ class QFlightWaypointTab(QFrame): rlayout.addWidget(QLabel("Advanced : ")) rlayout.addWidget(QLabel("Do not use for AI flights")) - self.ascend_waypoint = QPushButton("Add Ascend Waypoint") - self.ascend_waypoint.clicked.connect(self.on_ascend_waypoint) - rlayout.addWidget(self.ascend_waypoint) - - self.descend_waypoint = QPushButton("Add Descend Waypoint") - self.descend_waypoint.clicked.connect(self.on_descend_waypoint) - rlayout.addWidget(self.descend_waypoint) - self.rtb_waypoint = QPushButton("Add RTB Waypoint") self.rtb_waypoint.clicked.connect(self.on_rtb_waypoint) rlayout.addWidget(self.rtb_waypoint) @@ -115,47 +105,43 @@ class QFlightWaypointTab(QFrame): # Need to degrade to a custom flight plan and remove the waypoint. # If the waypoint is a target waypoint and is not the last target # waypoint, we don't need to degrade. - flight_plan = self.flight.flight_plan - if isinstance(flight_plan, StrikeFlightPlan): - if waypoint in flight_plan.targets and len(flight_plan.targets) > 1: - flight_plan.targets.remove(waypoint) + if isinstance(self.flight.flight_plan, StrikeFlightPlan): + is_target = waypoint in self.flight.flight_plan.targets + if is_target and len(self.flight.flight_plan.targets) > 1: + self.flight.flight_plan.targets.remove(waypoint) return - if not isinstance(flight_plan, CustomFlightPlan): - flight_plan = CustomFlightPlan( - package=self.flight.package, - flight=self.flight, - custom_waypoints=flight_plan.waypoints - ) - - flight_plan.waypoints.remove(waypoint) - self.flight.flight_plan = flight_plan + self.degrade_to_custom_flight_plan() + self.flight.flight_plan.waypoints.remove(waypoint) def on_fast_waypoint(self): self.subwindow = QPredefinedWaypointSelectionWindow(self.game, self.flight, self.flight_waypoint_list) - self.subwindow.finished.connect(self.on_change) + self.subwindow.waypoints_added.connect(self.on_waypoints_added) self.subwindow.show() - def on_ascend_waypoint(self): - ascend = self.planner.generate_ascend_point(self.flight, - self.flight.from_cp) - self.flight.points.append(ascend) + def on_waypoints_added(self, waypoints: Iterable[FlightWaypoint]) -> None: + if not waypoints: + return + self.degrade_to_custom_flight_plan() + self.flight.flight_plan.waypoints.extend(waypoints) self.flight_waypoint_list.update_list() self.on_change() def on_rtb_waypoint(self): rtb = self.planner.generate_rtb_waypoint(self.flight, self.flight.from_cp) - self.flight.points.append(rtb) + self.degrade_to_custom_flight_plan() + self.flight.flight_plan.waypoints.append(rtb) self.flight_waypoint_list.update_list() self.on_change() - def on_descend_waypoint(self): - descend = self.planner.generate_descend_point(self.flight, - self.flight.from_cp) - self.flight.points.append(descend) - self.flight_waypoint_list.update_list() - self.on_change() + def degrade_to_custom_flight_plan(self) -> None: + if not isinstance(self.flight.flight_plan, CustomFlightPlan): + self.flight.flight_plan = CustomFlightPlan( + package=self.flight.package, + flight=self.flight, + custom_waypoints=self.flight.flight_plan.waypoints + ) def confirm_recreate(self, task: FlightType) -> None: result = QMessageBox.question( diff --git a/qt_ui/windows/mission/flight/waypoints/QPredefinedWaypointSelectionWindow.py b/qt_ui/windows/mission/flight/waypoints/QPredefinedWaypointSelectionWindow.py index e7e2a90c..ccec5034 100644 --- a/qt_ui/windows/mission/flight/waypoints/QPredefinedWaypointSelectionWindow.py +++ b/qt_ui/windows/mission/flight/waypoints/QPredefinedWaypointSelectionWindow.py @@ -1,11 +1,20 @@ -from PySide2.QtCore import Qt -from PySide2.QtWidgets import QDialog, QLabel, QHBoxLayout, QVBoxLayout, QPushButton, QCheckBox +from PySide2.QtCore import Qt, Signal +from PySide2.QtWidgets import ( + QCheckBox, + QDialog, + QHBoxLayout, + QLabel, + QPushButton, + QVBoxLayout, +) from game import Game from gen.flights.flight import Flight from qt_ui.uiconstants import EVENT_ICONS -from qt_ui.widgets.combos.QPredefinedWaypointSelectionComboBox import QPredefinedWaypointSelectionComboBox -from qt_ui.windows.mission.flight.waypoints.QFlightWaypointInfoBox import QFlightWaypointInfoBox +from qt_ui.widgets.combos.QPredefinedWaypointSelectionComboBox import \ + QPredefinedWaypointSelectionComboBox +from qt_ui.windows.mission.flight.waypoints.QFlightWaypointInfoBox import \ + QFlightWaypointInfoBox PREDEFINED_WAYPOINT_CATEGORIES = [ "Frontline (CAS AREA)", @@ -17,6 +26,8 @@ PREDEFINED_WAYPOINT_CATEGORIES = [ class QPredefinedWaypointSelectionWindow(QDialog): + # List of FlightWaypoint + waypoints_added = Signal(list) def __init__(self, game: Game, flight: Flight, flight_waypoint_list): super(QPredefinedWaypointSelectionWindow, self).__init__() @@ -44,7 +55,6 @@ class QPredefinedWaypointSelectionWindow(QDialog): self.init_ui() self.on_select_wpt_changed() - print("DONE") def init_ui(self): @@ -77,12 +87,5 @@ class QPredefinedWaypointSelectionWindow(QDialog): self.add_button.setDisabled(False) def add_waypoint(self): - - for wpt in self.selected_waypoints: - self.flight.points.append(wpt) - - self.flight_waypoint_list.update_list() + self.waypoints_added.emit(self.selected_waypoints) self.close() - - - diff --git a/theater/theatergroundobject.py b/theater/theatergroundobject.py index 0e8b3c87..a0694974 100644 --- a/theater/theatergroundobject.py +++ b/theater/theatergroundobject.py @@ -99,6 +99,10 @@ class TheaterGroundObject(MissionTarget): """The name of the unit group.""" return f"{self.category}|{self.group_id}" + @property + def waypoint_name(self) -> str: + return f"[{self.name}] {self.category}" + def __str__(self) -> str: return NAME_BY_CATEGORY[self.category] @@ -136,6 +140,10 @@ class BuildingGroundObject(TheaterGroundObject): """The name of the unit group.""" return f"{self.category}|{self.group_id}|{self.object_id}" + @property + def waypoint_name(self) -> str: + return f"{super().waypoint_name} #{self.object_id}" + class GenericCarrierGroundObject(TheaterGroundObject): pass