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.
This commit is contained in:
Dan Albert 2020-11-19 00:29:05 -08:00
parent a816877d08
commit fd473f0a46
7 changed files with 59 additions and 144 deletions

View File

@ -659,7 +659,6 @@ class FlightPlanBuilder:
builder = WaypointBuilder(self.game.conditions, flight, self.doctrine) builder = WaypointBuilder(self.game.conditions, flight, self.doctrine)
start, end = builder.race_track(start, end, patrol_alt) start, end = builder.race_track(start, end, patrol_alt)
descent, land = builder.rtb(flight.from_cp)
return BarCapFlightPlan( return BarCapFlightPlan(
package=self.package, package=self.package,
@ -668,7 +667,7 @@ class FlightPlanBuilder:
takeoff=builder.takeoff(flight.from_cp), takeoff=builder.takeoff(flight.from_cp),
patrol_start=start, patrol_start=start,
patrol_end=end, patrol_end=end,
land=land land=builder.land(flight.from_cp)
) )
def generate_frontline_cap(self, flight: Flight) -> FrontLineCapFlightPlan: def generate_frontline_cap(self, flight: Flight) -> FrontLineCapFlightPlan:
@ -707,9 +706,8 @@ class FlightPlanBuilder:
# Create points # Create points
builder = WaypointBuilder(self.game.conditions, flight, self.doctrine) builder = WaypointBuilder(self.game.conditions, flight, self.doctrine)
start, end = builder.race_track(orbit0p, orbit1p, patrol_alt) start, end = builder.race_track(orbit0p, orbit1p, patrol_alt)
descent, land = builder.rtb(flight.from_cp)
return FrontLineCapFlightPlan( return FrontLineCapFlightPlan(
package=self.package, package=self.package,
flight=flight, flight=flight,
@ -721,7 +719,7 @@ class FlightPlanBuilder:
takeoff=builder.takeoff(flight.from_cp), takeoff=builder.takeoff(flight.from_cp),
patrol_start=start, patrol_start=start,
patrol_end=end, patrol_end=end,
land=land land=builder.land(flight.from_cp)
) )
def generate_dead(self, flight: Flight, def generate_dead(self, flight: Flight,
@ -780,7 +778,6 @@ class FlightPlanBuilder:
ingress, target, egress = builder.escort( ingress, target, egress = builder.escort(
self.package.waypoints.ingress, self.package.target, self.package.waypoints.ingress, self.package.target,
self.package.waypoints.egress) self.package.waypoints.egress)
descent, land = builder.rtb(flight.from_cp)
return StrikeFlightPlan( return StrikeFlightPlan(
package=self.package, package=self.package,
@ -792,7 +789,7 @@ class FlightPlanBuilder:
targets=[target], targets=[target],
egress=egress, egress=egress,
split=builder.split(self.package.waypoints.split), split=builder.split(self.package.waypoints.split),
land=land land=builder.land(flight.from_cp)
) )
def generate_cas(self, flight: Flight) -> CasFlightPlan: def generate_cas(self, flight: Flight) -> CasFlightPlan:
@ -814,7 +811,6 @@ class FlightPlanBuilder:
egress = ingress.point_from_heading(heading, distance) egress = ingress.point_from_heading(heading, distance)
builder = WaypointBuilder(self.game.conditions, flight, self.doctrine) builder = WaypointBuilder(self.game.conditions, flight, self.doctrine)
descent, land = builder.rtb(flight.from_cp)
return CasFlightPlan( return CasFlightPlan(
package=self.package, package=self.package,
@ -824,7 +820,7 @@ class FlightPlanBuilder:
patrol_start=builder.ingress_cas(ingress, location), patrol_start=builder.ingress_cas(ingress, location),
target=builder.cas(center), target=builder.cas(center),
patrol_end=builder.egress(egress, location), patrol_end=builder.egress(egress, location),
land=land land=builder.land(flight.from_cp)
) )
@staticmethod @staticmethod
@ -894,28 +890,6 @@ class FlightPlanBuilder:
self.doctrine.hold_distance) self.doctrine.hold_distance)
# TODO: Make a model for the waypoint builder and use that in the UI. # 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, def generate_rtb_waypoint(self, flight: Flight,
arrival: ControlPoint) -> FlightWaypoint: arrival: ControlPoint) -> FlightWaypoint:
"""Generate RTB landing point. """Generate RTB landing point.
@ -954,7 +928,6 @@ class FlightPlanBuilder:
target_waypoints.append( target_waypoints.append(
self.target_area_waypoint(flight, location, builder)) self.target_area_waypoint(flight, location, builder))
descent, land = builder.rtb(flight.from_cp)
return StrikeFlightPlan( return StrikeFlightPlan(
package=self.package, package=self.package,
flight=flight, flight=flight,
@ -965,7 +938,7 @@ class FlightPlanBuilder:
targets=target_waypoints, targets=target_waypoints,
egress=builder.egress(self.package.waypoints.egress, location), egress=builder.egress(self.package.waypoints.egress, location),
split=builder.split(self.package.waypoints.split), split=builder.split(self.package.waypoints.split),
land=land land=builder.land(flight.from_cp)
) )
def _retreating_rendezvous_point(self, attack_transition: Point) -> Point: def _retreating_rendezvous_point(self, attack_transition: Point) -> Point:

View File

@ -118,8 +118,11 @@ class TotEstimator:
def takeoff_time_for_flight(self, flight: Flight) -> Optional[timedelta]: def takeoff_time_for_flight(self, flight: Flight) -> Optional[timedelta]:
travel_time = self.travel_time_to_rendezvous_or_target(flight) travel_time = self.travel_time_to_rendezvous_or_target(flight)
if travel_time is None: if travel_time is None:
logging.warning("Found no rendezvous or target point. Cannot " from gen.flights.flightplan import CustomFlightPlan
f"estimate takeoff time takeoff time for {flight}") 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 return None
from gen.flights.flightplan import FormationFlightPlan from gen.flights.flightplan import FormationFlightPlan

View File

@ -7,11 +7,9 @@ from dcs.mapping import Point
from dcs.unit import Unit from dcs.unit import Unit
from game.data.doctrine import Doctrine from game.data.doctrine import Doctrine
from game.utils import nm_to_meter
from game.weather import Conditions from game.weather import Conditions
from theater import ControlPoint, MissionTarget, TheaterGroundObject from theater import ControlPoint, MissionTarget, TheaterGroundObject
from .flight import Flight, FlightWaypoint, FlightWaypointType from .flight import Flight, FlightWaypoint, FlightWaypointType
from ..runways import RunwayAssigner
@dataclass(frozen=True) @dataclass(frozen=True)
@ -57,52 +55,6 @@ class WaypointBuilder:
waypoint.pretty_name = "Takeoff" waypoint.pretty_name = "Takeoff"
return waypoint 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 @staticmethod
def land(arrival: ControlPoint) -> FlightWaypoint: def land(arrival: ControlPoint) -> FlightWaypoint:
"""Create descent waypoint for the given arrival airfield or carrier. """Create descent waypoint for the given arrival airfield or carrier.
@ -326,15 +278,6 @@ class WaypointBuilder:
return (self.race_track_start(start, altitude), return (self.race_track_start(start, altitude),
self.race_track_end(end, 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) -> \ def escort(self, ingress: Point, target: MissionTarget, egress: Point) -> \
Tuple[FlightWaypoint, FlightWaypoint, FlightWaypoint]: Tuple[FlightWaypoint, FlightWaypoint, FlightWaypoint]:
"""Creates the waypoints needed to escort the package. """Creates the waypoints needed to escort the package.

View File

@ -44,7 +44,6 @@ class QPredefinedWaypointSelectionComboBox(QFilteredComboBox):
i = 0 i = 0
def add_model_item(i, model, name, wpt): def add_model_item(i, model, name, wpt):
print(name)
item = QStandardItem(name) item = QStandardItem(name)
model.setItem(i, 0, item) model.setItem(i, 0, item)
self.wpts.append(wpt) self.wpts.append(wpt)
@ -79,7 +78,7 @@ class QPredefinedWaypointSelectionComboBox(QFilteredComboBox):
0 0
) )
wpt.alt_type = "RADIO" 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.pretty_name = wpt.name
wpt.obj_name = ground_object.obj_name wpt.obj_name = ground_object.obj_name
wpt.targets.append(ground_object) wpt.targets.append(ground_object)

View File

@ -1,4 +1,4 @@
from typing import List, Optional from typing import Iterable, List, Optional
from PySide2.QtCore import Signal from PySide2.QtCore import Signal
from PySide2.QtWidgets import ( from PySide2.QtWidgets import (
@ -20,7 +20,7 @@ from gen.flights.flightplan import (
) )
from qt_ui.windows.mission.flight.waypoints.QFlightWaypointList import \ from qt_ui.windows.mission.flight.waypoints.QFlightWaypointList import \
QFlightWaypointList QFlightWaypointList
from qt_ui.windows.mission.flight.waypoints\ from qt_ui.windows.mission.flight.waypoints \
.QPredefinedWaypointSelectionWindow import \ .QPredefinedWaypointSelectionWindow import \
QPredefinedWaypointSelectionWindow QPredefinedWaypointSelectionWindow
from theater import FrontLine from theater import FrontLine
@ -38,8 +38,6 @@ class QFlightWaypointTab(QFrame):
self.planner = FlightPlanBuilder(self.game, package, is_player=True) self.planner = FlightPlanBuilder(self.game, package, is_player=True)
self.flight_waypoint_list: Optional[QFlightWaypointList] = None 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.rtb_waypoint: Optional[QPushButton] = None
self.delete_selected: Optional[QPushButton] = None self.delete_selected: Optional[QPushButton] = None
self.open_fast_waypoint_button: Optional[QPushButton] = None self.open_fast_waypoint_button: Optional[QPushButton] = None
@ -82,14 +80,6 @@ class QFlightWaypointTab(QFrame):
rlayout.addWidget(QLabel("<strong>Advanced : </strong>")) rlayout.addWidget(QLabel("<strong>Advanced : </strong>"))
rlayout.addWidget(QLabel("<small>Do not use for AI flights</small>")) rlayout.addWidget(QLabel("<small>Do not use for AI flights</small>"))
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 = QPushButton("Add RTB Waypoint")
self.rtb_waypoint.clicked.connect(self.on_rtb_waypoint) self.rtb_waypoint.clicked.connect(self.on_rtb_waypoint)
rlayout.addWidget(self.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. # 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 # If the waypoint is a target waypoint and is not the last target
# waypoint, we don't need to degrade. # waypoint, we don't need to degrade.
flight_plan = self.flight.flight_plan if isinstance(self.flight.flight_plan, StrikeFlightPlan):
if isinstance(flight_plan, StrikeFlightPlan): is_target = waypoint in self.flight.flight_plan.targets
if waypoint in flight_plan.targets and len(flight_plan.targets) > 1: if is_target and len(self.flight.flight_plan.targets) > 1:
flight_plan.targets.remove(waypoint) self.flight.flight_plan.targets.remove(waypoint)
return return
if not isinstance(flight_plan, CustomFlightPlan): self.degrade_to_custom_flight_plan()
flight_plan = CustomFlightPlan( self.flight.flight_plan.waypoints.remove(waypoint)
package=self.flight.package,
flight=self.flight,
custom_waypoints=flight_plan.waypoints
)
flight_plan.waypoints.remove(waypoint)
self.flight.flight_plan = flight_plan
def on_fast_waypoint(self): def on_fast_waypoint(self):
self.subwindow = QPredefinedWaypointSelectionWindow(self.game, self.flight, self.flight_waypoint_list) 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() self.subwindow.show()
def on_ascend_waypoint(self): def on_waypoints_added(self, waypoints: Iterable[FlightWaypoint]) -> None:
ascend = self.planner.generate_ascend_point(self.flight, if not waypoints:
self.flight.from_cp) return
self.flight.points.append(ascend) self.degrade_to_custom_flight_plan()
self.flight.flight_plan.waypoints.extend(waypoints)
self.flight_waypoint_list.update_list() self.flight_waypoint_list.update_list()
self.on_change() self.on_change()
def on_rtb_waypoint(self): def on_rtb_waypoint(self):
rtb = self.planner.generate_rtb_waypoint(self.flight, rtb = self.planner.generate_rtb_waypoint(self.flight,
self.flight.from_cp) 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.flight_waypoint_list.update_list()
self.on_change() self.on_change()
def on_descend_waypoint(self): def degrade_to_custom_flight_plan(self) -> None:
descend = self.planner.generate_descend_point(self.flight, if not isinstance(self.flight.flight_plan, CustomFlightPlan):
self.flight.from_cp) self.flight.flight_plan = CustomFlightPlan(
self.flight.points.append(descend) package=self.flight.package,
self.flight_waypoint_list.update_list() flight=self.flight,
self.on_change() custom_waypoints=self.flight.flight_plan.waypoints
)
def confirm_recreate(self, task: FlightType) -> None: def confirm_recreate(self, task: FlightType) -> None:
result = QMessageBox.question( result = QMessageBox.question(

View File

@ -1,11 +1,20 @@
from PySide2.QtCore import Qt from PySide2.QtCore import Qt, Signal
from PySide2.QtWidgets import QDialog, QLabel, QHBoxLayout, QVBoxLayout, QPushButton, QCheckBox from PySide2.QtWidgets import (
QCheckBox,
QDialog,
QHBoxLayout,
QLabel,
QPushButton,
QVBoxLayout,
)
from game import Game from game import Game
from gen.flights.flight import Flight from gen.flights.flight import Flight
from qt_ui.uiconstants import EVENT_ICONS from qt_ui.uiconstants import EVENT_ICONS
from qt_ui.widgets.combos.QPredefinedWaypointSelectionComboBox import QPredefinedWaypointSelectionComboBox from qt_ui.widgets.combos.QPredefinedWaypointSelectionComboBox import \
from qt_ui.windows.mission.flight.waypoints.QFlightWaypointInfoBox import QFlightWaypointInfoBox QPredefinedWaypointSelectionComboBox
from qt_ui.windows.mission.flight.waypoints.QFlightWaypointInfoBox import \
QFlightWaypointInfoBox
PREDEFINED_WAYPOINT_CATEGORIES = [ PREDEFINED_WAYPOINT_CATEGORIES = [
"Frontline (CAS AREA)", "Frontline (CAS AREA)",
@ -17,6 +26,8 @@ PREDEFINED_WAYPOINT_CATEGORIES = [
class QPredefinedWaypointSelectionWindow(QDialog): class QPredefinedWaypointSelectionWindow(QDialog):
# List of FlightWaypoint
waypoints_added = Signal(list)
def __init__(self, game: Game, flight: Flight, flight_waypoint_list): def __init__(self, game: Game, flight: Flight, flight_waypoint_list):
super(QPredefinedWaypointSelectionWindow, self).__init__() super(QPredefinedWaypointSelectionWindow, self).__init__()
@ -44,7 +55,6 @@ class QPredefinedWaypointSelectionWindow(QDialog):
self.init_ui() self.init_ui()
self.on_select_wpt_changed() self.on_select_wpt_changed()
print("DONE")
def init_ui(self): def init_ui(self):
@ -77,12 +87,5 @@ class QPredefinedWaypointSelectionWindow(QDialog):
self.add_button.setDisabled(False) self.add_button.setDisabled(False)
def add_waypoint(self): def add_waypoint(self):
self.waypoints_added.emit(self.selected_waypoints)
for wpt in self.selected_waypoints:
self.flight.points.append(wpt)
self.flight_waypoint_list.update_list()
self.close() self.close()

View File

@ -99,6 +99,10 @@ class TheaterGroundObject(MissionTarget):
"""The name of the unit group.""" """The name of the unit group."""
return f"{self.category}|{self.group_id}" return f"{self.category}|{self.group_id}"
@property
def waypoint_name(self) -> str:
return f"[{self.name}] {self.category}"
def __str__(self) -> str: def __str__(self) -> str:
return NAME_BY_CATEGORY[self.category] return NAME_BY_CATEGORY[self.category]
@ -136,6 +140,10 @@ class BuildingGroundObject(TheaterGroundObject):
"""The name of the unit group.""" """The name of the unit group."""
return f"{self.category}|{self.group_id}|{self.object_id}" 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): class GenericCarrierGroundObject(TheaterGroundObject):
pass pass