Add shipping lane support to campaign files.

These don't actually do anything yet, this is just the campaign support
and UI.

https://github.com/Khopa/dcs_liberation/issues/826
This commit is contained in:
Dan Albert
2021-04-24 21:32:37 -07:00
parent 97b73e1a01
commit 5e67ce0ab2
6 changed files with 173 additions and 40 deletions

View File

@@ -45,7 +45,7 @@ from game.theater.theatergroundobject import (
TheaterGroundObject,
)
from game.transfers import Convoy
from game.utils import Distance, meters, nautical_miles
from game.utils import Distance, meters, nautical_miles, pairwise
from game.weather import TimeOfDay
from gen import Conflict, Package
from gen.flights.flight import (
@@ -67,12 +67,16 @@ from qt_ui.widgets.map.QFrontLine import QFrontLine
from qt_ui.widgets.map.QLiberationScene import QLiberationScene
from qt_ui.widgets.map.QMapControlPoint import QMapControlPoint
from qt_ui.widgets.map.QMapGroundObject import QMapGroundObject
from qt_ui.widgets.map.ShippingLaneSegment import ShippingLaneSegment
from qt_ui.widgets.map.SupplyRouteSegment import SupplyRouteSegment
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
MAX_SHIP_DISTANCE = nautical_miles(80)
MapPoint = Tuple[float, float]
def binomial(i: int, n: int) -> float:
"""Binomial coefficient"""
return math.factorial(n) / float(math.factorial(i) * math.factorial(n - i))
@@ -821,47 +825,64 @@ class QLiberationMap(QGraphicsView):
)
)
def bezier_points(
self, points: Iterable[Point]
) -> Iterator[Tuple[MapPoint, MapPoint]]:
# Thanks to Alquimista for sharing a python implementation of the bezier
# algorithm this is adapted from.
# https://gist.github.com/Alquimista/1274149#file-bezdraw-py
bezier_fixed_points = []
for a, b in pairwise(points):
bezier_fixed_points.append(self._transform_point(a))
bezier_fixed_points.append(self._transform_point(b))
old_point = bezier_fixed_points[0]
for point in bezier_curve_range(
int(len(bezier_fixed_points) * 2), bezier_fixed_points
):
yield old_point, point
old_point = point
def draw_bezier_frontline(
self,
scene: QGraphicsScene,
frontline: FrontLine,
convoys: List[Convoy],
) -> None:
"""
Thanks to Alquimista for sharing a python implementation of the bezier algorithm this is adapted from.
https://gist.github.com/Alquimista/1274149#file-bezdraw-py
"""
bezier_fixed_points = []
for segment in frontline.segments:
bezier_fixed_points.append(self._transform_point(segment.point_a))
bezier_fixed_points.append(self._transform_point(segment.point_b))
old_point = bezier_fixed_points[0]
for point in bezier_curve_range(
int(len(bezier_fixed_points) * 2), bezier_fixed_points
):
for a, b in self.bezier_points(frontline.points):
scene.addItem(
SupplyRouteSegment(
old_point[0],
old_point[1],
point[0],
point[1],
a[0],
a[1],
b[0],
b[1],
frontline.control_point_a,
frontline.control_point_b,
convoys,
)
)
old_point = point
def draw_supply_routes(self) -> None:
if not DisplayOptions.lines:
return
seen = set()
for cp in self.game.theater.controlpoints:
seen.add(cp)
for connected in cp.connected_points:
if connected in seen:
continue
if DisplayOptions.lines:
self.draw_supply_route_between(cp, connected)
self.draw_supply_route_between(cp, connected)
for destination, shipping_lane in cp.shipping_lanes.items():
if destination in seen:
continue
if cp.is_friendly(destination.captured):
self.draw_shipping_lane_between(cp, destination)
def draw_shipping_lane_between(self, a: ControlPoint, b: ControlPoint) -> None:
scene = self.scene()
for pa, pb in self.bezier_points(a.shipping_lanes[b]):
scene.addItem(ShippingLaneSegment(pa[0], pa[1], pb[0], pb[1], a, b))
def draw_supply_route_between(self, a: ControlPoint, b: ControlPoint) -> None:
scene = self.scene()

View File

@@ -0,0 +1,68 @@
from typing import Optional
from PySide2.QtCore import Qt
from PySide2.QtGui import QColor, QPen
from PySide2.QtWidgets import (
QGraphicsItem,
QGraphicsLineItem,
)
from game.theater import ControlPoint
from qt_ui.uiconstants import COLORS
class ShippingLaneSegment(QGraphicsLineItem):
def __init__(
self,
x0: float,
y0: float,
x1: float,
y1: float,
control_point_a: ControlPoint,
control_point_b: ControlPoint,
parent: Optional[QGraphicsItem] = None,
) -> None:
super().__init__(x0, y0, x1, y1, parent)
self.control_point_a = control_point_a
self.control_point_b = control_point_b
self.ships = []
self.setPen(self.make_pen())
self.setToolTip(self.make_tooltip())
self.setAcceptHoverEvents(True)
@property
def has_ships(self) -> bool:
return bool(self.ships)
def make_tooltip(self) -> str:
if not self.has_ships:
return "No ships present in this shipping lane."
ships = []
for ship in self.ships:
units = "units" if ship.size > 1 else "unit"
ships.append(
f"{ship.size} {units} transferring from {ship.origin} to "
f"{ship.destination}."
)
return "\n".join(ships)
@property
def line_color(self) -> QColor:
if self.control_point_a.captured:
return COLORS["dark_blue"]
else:
return COLORS["dark_red"]
@property
def line_style(self) -> Qt.PenStyle:
if self.has_ships:
return Qt.PenStyle.SolidLine
return Qt.PenStyle.DotLine
def make_pen(self) -> QPen:
pen = QPen(brush=self.line_color)
pen.setColor(self.line_color)
pen.setStyle(self.line_style)
pen.setWidth(2)
return pen