mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Show convoys on the map.
This commit is contained in:
parent
cabbd234af
commit
2a5b37b9ad
@ -711,6 +711,12 @@ class ControlPoint(MissionTarget, ABC):
|
||||
def has_active_frontline(self) -> bool:
|
||||
return any(not c.is_friendly(self.captured) for c in self.connected_points)
|
||||
|
||||
def front_is_active(self, other: ControlPoint) -> bool:
|
||||
if other not in self.connected_points:
|
||||
raise ValueError
|
||||
|
||||
return self.captured != other.captured
|
||||
|
||||
|
||||
class Airfield(ControlPoint):
|
||||
def __init__(
|
||||
|
||||
@ -42,6 +42,9 @@ class RoadTransferOrder(TransferOrder):
|
||||
supply_route = SupplyRoute.for_control_point(self.position)
|
||||
return supply_route.shortest_path_between(self.position, self.destination)
|
||||
|
||||
def next_stop(self) -> ControlPoint:
|
||||
return self.path()[0]
|
||||
|
||||
|
||||
class PendingTransfers:
|
||||
def __init__(self) -> None:
|
||||
|
||||
@ -4,7 +4,7 @@ import datetime
|
||||
import logging
|
||||
import math
|
||||
from functools import singledispatchmethod
|
||||
from typing import Iterable, Iterator, List, Optional, Tuple
|
||||
from typing import Iterable, Iterator, List, Optional, Set, Tuple
|
||||
|
||||
from PySide2 import QtCore, QtWidgets
|
||||
from PySide2.QtCore import QLineF, QPointF, QRectF, Qt
|
||||
@ -39,7 +39,7 @@ from shapely.geometry import (
|
||||
import qt_ui.uiconstants as CONST
|
||||
from game import Game
|
||||
from game.navmesh import NavMesh
|
||||
from game.theater import ControlPoint, Enum
|
||||
from game.theater import ControlPoint, Enum, SupplyRoute
|
||||
from game.theater.conflicttheater import FrontLine, ReferencePoint
|
||||
from game.theater.theatergroundobject import (
|
||||
TheaterGroundObject,
|
||||
@ -644,14 +644,7 @@ class QLiberationMap(QGraphicsView):
|
||||
QPen(CONST.COLORS["green"], width=10, s=Qt.DashDotLine),
|
||||
)
|
||||
|
||||
for cp in self.game.theater.enemy_points():
|
||||
if DisplayOptions.lines:
|
||||
self.scene_create_lines_for_cp(cp, playerColor, enemyColor)
|
||||
|
||||
for cp in self.game.theater.player_points():
|
||||
if DisplayOptions.lines:
|
||||
self.scene_create_lines_for_cp(cp, playerColor, enemyColor)
|
||||
|
||||
self.draw_supply_routes()
|
||||
self.draw_flight_plans(scene)
|
||||
|
||||
for cp in self.game.theater.controlpoints:
|
||||
@ -829,7 +822,11 @@ class QLiberationMap(QGraphicsView):
|
||||
)
|
||||
|
||||
def draw_bezier_frontline(
|
||||
self, scene: QGraphicsScene, pen: QPen, frontline: FrontLine
|
||||
self,
|
||||
scene: QGraphicsScene,
|
||||
pen: QPen,
|
||||
frontline: FrontLine,
|
||||
convoy_size: int = 0,
|
||||
) -> None:
|
||||
"""
|
||||
Thanks to Alquimista for sharing a python implementation of the bezier algorithm this is adapted from.
|
||||
@ -844,32 +841,93 @@ class QLiberationMap(QGraphicsView):
|
||||
for point in bezier_curve_range(
|
||||
int(len(bezier_fixed_points) * 2), bezier_fixed_points
|
||||
):
|
||||
scene.addLine(old_point[0], old_point[1], point[0], point[1], pen=pen)
|
||||
line = scene.addLine(
|
||||
old_point[0], old_point[1], point[0], point[1], pen=pen
|
||||
)
|
||||
if convoy_size:
|
||||
units = "units" if convoy_size > 1 else "unit"
|
||||
tooltip = (
|
||||
f"{convoy_size} {units} transferring between "
|
||||
f"{frontline.control_point_a} and {frontline.control_point_b}."
|
||||
)
|
||||
else:
|
||||
tooltip = "No convoys present on this supply route."
|
||||
line.setToolTip(tooltip)
|
||||
old_point = point
|
||||
|
||||
def scene_create_lines_for_cp(self, cp: ControlPoint, playerColor, enemyColor):
|
||||
def draw_supply_routes(self) -> None:
|
||||
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)
|
||||
|
||||
def _count_units_tranferring_between(self, a: ControlPoint, b: ControlPoint) -> int:
|
||||
# We attempt to short circuit the expensive shortest path computation for the
|
||||
# cases where there is never a transfer, but caching might be needed.
|
||||
|
||||
if a.captured != b.captured:
|
||||
# Cannot transfer to enemy CPs.
|
||||
return 0
|
||||
|
||||
# This is only called for drawing lines between nodes and have rules out routes
|
||||
# to enemy bases, so a and b are guaranteed to be in the same supply route.
|
||||
supply_route = SupplyRoute.for_control_point(a)
|
||||
|
||||
count = 0
|
||||
points = {a, b}
|
||||
for transfer in self.game.transfers:
|
||||
# No possible route from our network to this transfer.
|
||||
if transfer.position not in supply_route:
|
||||
continue
|
||||
|
||||
# Anything left is a transfer within our supply route.
|
||||
transfer_points = {transfer.position, transfer.next_stop()}
|
||||
if points == transfer_points:
|
||||
count += sum(transfer.units.values())
|
||||
return count
|
||||
|
||||
def supply_route_color(self, a: ControlPoint, b: ControlPoint) -> QColor:
|
||||
if a.front_is_active(b):
|
||||
return CONST.COLORS["red"]
|
||||
elif a.captured:
|
||||
return CONST.COLORS["dark_" + self.game.get_player_color()]
|
||||
else:
|
||||
return CONST.COLORS["dark_" + self.game.get_enemy_color()]
|
||||
|
||||
def supply_route_style(
|
||||
self, a: ControlPoint, b: ControlPoint, has_transfer: bool
|
||||
) -> Qt.PenStyle:
|
||||
if a.front_is_active(b) or has_transfer:
|
||||
return Qt.PenStyle.SolidLine
|
||||
return Qt.PenStyle.DotLine
|
||||
|
||||
def supply_route_pen(
|
||||
self, a: ControlPoint, b: ControlPoint, has_transfer: bool
|
||||
) -> QPen:
|
||||
color = self.supply_route_color(a, b)
|
||||
pen = QPen(brush=color)
|
||||
pen.setColor(color)
|
||||
pen.setStyle(self.supply_route_style(a, b, has_transfer))
|
||||
pen.setWidth(6)
|
||||
return pen
|
||||
|
||||
def draw_supply_route_between(self, a: ControlPoint, b: ControlPoint) -> None:
|
||||
scene = self.scene()
|
||||
for connected_cp in cp.connected_points:
|
||||
pos2 = self._transform_point(connected_cp.position)
|
||||
if not cp.captured:
|
||||
color = CONST.COLORS["dark_" + enemyColor]
|
||||
|
||||
convoy_size = self._count_units_tranferring_between(a, b)
|
||||
pen = self.supply_route_pen(a, b, convoy_size > 0)
|
||||
frontline = FrontLine(a, b, self.game.theater)
|
||||
if a.front_is_active(b):
|
||||
if DisplayOptions.actual_frontline_pos:
|
||||
self.draw_actual_frontline(frontline, scene, pen)
|
||||
else:
|
||||
color = CONST.COLORS["dark_" + playerColor]
|
||||
pen = QPen(brush=color)
|
||||
pen.setColor(color)
|
||||
pen.setWidth(6)
|
||||
frontline = FrontLine(cp, connected_cp, self.game.theater)
|
||||
if (
|
||||
cp.captured
|
||||
and not connected_cp.captured
|
||||
and Conflict.has_frontline_between(cp, connected_cp)
|
||||
):
|
||||
if DisplayOptions.actual_frontline_pos:
|
||||
self.draw_actual_frontline(frontline, scene, pen)
|
||||
else:
|
||||
self.draw_frontline_approximation(frontline, scene, pen)
|
||||
else:
|
||||
self.draw_bezier_frontline(scene, pen, frontline)
|
||||
self.draw_frontline_approximation(frontline, scene, pen)
|
||||
else:
|
||||
self.draw_bezier_frontline(scene, pen, frontline, convoy_size)
|
||||
|
||||
def draw_frontline_approximation(
|
||||
self, frontline: FrontLine, scene: QGraphicsScene, pen: QPen
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user