mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Clean up convoy code.
This commit is contained in:
parent
50d8e08a34
commit
6cffc47f3c
@ -206,7 +206,7 @@ class Debriefing:
|
|||||||
|
|
||||||
convoy_unit = self.unit_map.convoy_unit(unit_name)
|
convoy_unit = self.unit_map.convoy_unit(unit_name)
|
||||||
if convoy_unit is not None:
|
if convoy_unit is not None:
|
||||||
if convoy_unit.transfer.player:
|
if convoy_unit.convoy.player_owned:
|
||||||
losses.player_convoy.append(convoy_unit)
|
losses.player_convoy.append(convoy_unit)
|
||||||
else:
|
else:
|
||||||
losses.enemy_convoy.append(convoy_unit)
|
losses.enemy_convoy.append(convoy_unit)
|
||||||
|
|||||||
@ -159,9 +159,9 @@ class Event:
|
|||||||
def commit_convoy_losses(debriefing: Debriefing) -> None:
|
def commit_convoy_losses(debriefing: Debriefing) -> None:
|
||||||
for loss in debriefing.convoy_losses:
|
for loss in debriefing.convoy_losses:
|
||||||
unit_type = loss.unit_type
|
unit_type = loss.unit_type
|
||||||
transfer = loss.transfer
|
convoy = loss.convoy
|
||||||
available = loss.transfer.units.get(unit_type, 0)
|
available = loss.convoy.units.get(unit_type, 0)
|
||||||
convoy_name = f"convoy from {transfer.position} to {transfer.destination}"
|
convoy_name = f"convoy from {convoy.origin} to {convoy.destination}"
|
||||||
if available <= 0:
|
if available <= 0:
|
||||||
logging.error(
|
logging.error(
|
||||||
f"Found killed {unit_type} in {convoy_name} but that convoy has "
|
f"Found killed {unit_type} in {convoy_name} but that convoy has "
|
||||||
@ -170,7 +170,7 @@ class Event:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
logging.info(f"{unit_type} destroyed in {convoy_name}")
|
logging.info(f"{unit_type} destroyed in {convoy_name}")
|
||||||
transfer.units[unit_type] -= 1
|
convoy.kill_unit(unit_type)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def commit_ground_object_losses(debriefing: Debriefing) -> None:
|
def commit_ground_object_losses(debriefing: Debriefing) -> None:
|
||||||
|
|||||||
12
game/game.py
12
game/game.py
@ -34,7 +34,7 @@ from .settings import Settings
|
|||||||
from .theater import ConflictTheater, ControlPoint, TheaterGroundObject
|
from .theater import ConflictTheater, ControlPoint, TheaterGroundObject
|
||||||
from game.theater.theatergroundobject import MissileSiteGroundObject
|
from game.theater.theatergroundobject import MissileSiteGroundObject
|
||||||
from .threatzones import ThreatZones
|
from .threatzones import ThreatZones
|
||||||
from .transfers import PendingTransfers, RoadTransferOrder
|
from .transfers import Convoy, ConvoyMap, PendingTransfers, RoadTransferOrder
|
||||||
from .unitmap import UnitMap
|
from .unitmap import UnitMap
|
||||||
from .weather import Conditions, TimeOfDay
|
from .weather import Conditions, TimeOfDay
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ class Game:
|
|||||||
|
|
||||||
self.aircraft_inventory = GlobalAircraftInventory(self.theater.controlpoints)
|
self.aircraft_inventory = GlobalAircraftInventory(self.theater.controlpoints)
|
||||||
|
|
||||||
self._transfers = PendingTransfers()
|
self.transfers = PendingTransfers()
|
||||||
|
|
||||||
self.sanitize_sides()
|
self.sanitize_sides()
|
||||||
|
|
||||||
@ -154,14 +154,6 @@ class Game:
|
|||||||
# Regenerate any state that was not persisted.
|
# Regenerate any state that was not persisted.
|
||||||
self.on_load()
|
self.on_load()
|
||||||
|
|
||||||
@property
|
|
||||||
def transfers(self) -> PendingTransfers:
|
|
||||||
try:
|
|
||||||
return self._transfers
|
|
||||||
except AttributeError:
|
|
||||||
self._transfers = PendingTransfers()
|
|
||||||
return self._transfers
|
|
||||||
|
|
||||||
def generate_conditions(self) -> Conditions:
|
def generate_conditions(self) -> Conditions:
|
||||||
return Conditions.generate(
|
return Conditions.generate(
|
||||||
self.theater, self.current_day, self.current_turn_time_of_day, self.settings
|
self.theater, self.current_day, self.current_turn_time_of_day, self.settings
|
||||||
|
|||||||
@ -1,8 +1,14 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
from collections import defaultdict
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import Dict, Iterator, List, Type
|
from typing import Dict, Iterator, List, Optional, TYPE_CHECKING, Type
|
||||||
|
|
||||||
from dcs.unittype import VehicleType
|
from dcs.unittype import VehicleType
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
pass
|
||||||
from game.theater import ControlPoint, MissionTarget
|
from game.theater import ControlPoint, MissionTarget
|
||||||
from game.theater.supplyroutes import SupplyRoute
|
from game.theater.supplyroutes import SupplyRoute
|
||||||
from gen.naming import namegen
|
from gen.naming import namegen
|
||||||
@ -37,8 +43,6 @@ class RoadTransferOrder(TransferOrder):
|
|||||||
#: point a turn through the supply line.
|
#: point a turn through the supply line.
|
||||||
position: ControlPoint = field(init=False)
|
position: ControlPoint = field(init=False)
|
||||||
|
|
||||||
name: str = field(init=False, default_factory=namegen.next_convoy_name)
|
|
||||||
|
|
||||||
def __post_init__(self) -> None:
|
def __post_init__(self) -> None:
|
||||||
self.position = self.origin
|
self.position = self.origin
|
||||||
|
|
||||||
@ -51,14 +55,11 @@ class RoadTransferOrder(TransferOrder):
|
|||||||
|
|
||||||
|
|
||||||
class Convoy(MissionTarget):
|
class Convoy(MissionTarget):
|
||||||
def __init__(self, transfer: RoadTransferOrder) -> None:
|
def __init__(self, origin: ControlPoint, destination: ControlPoint) -> None:
|
||||||
self.transfer = transfer
|
super().__init__(namegen.next_convoy_name(), origin.position)
|
||||||
count = sum(c for c in transfer.units.values())
|
self.origin = origin
|
||||||
super().__init__(
|
self.destination = destination
|
||||||
f"{transfer.name} of {count} units moving from {transfer.position} to "
|
self.transfers: List[RoadTransferOrder] = []
|
||||||
f"{transfer.destination}",
|
|
||||||
transfer.position.position,
|
|
||||||
)
|
|
||||||
|
|
||||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||||
if self.is_friendly(for_player):
|
if self.is_friendly(for_player):
|
||||||
@ -68,11 +69,93 @@ class Convoy(MissionTarget):
|
|||||||
yield from super().mission_types(for_player)
|
yield from super().mission_types(for_player)
|
||||||
|
|
||||||
def is_friendly(self, to_player: bool) -> bool:
|
def is_friendly(self, to_player: bool) -> bool:
|
||||||
return self.transfer.position.captured
|
return self.origin.captured
|
||||||
|
|
||||||
|
def add_units(self, transfer: RoadTransferOrder) -> None:
|
||||||
|
self.transfers.append(transfer)
|
||||||
|
|
||||||
|
def remove_units(self, transfer: RoadTransferOrder) -> None:
|
||||||
|
self.transfers.remove(transfer)
|
||||||
|
|
||||||
|
def kill_unit(self, unit_type: Type[VehicleType]) -> None:
|
||||||
|
for transfer in self.transfers:
|
||||||
|
if unit_type in transfer.units:
|
||||||
|
transfer.units[unit_type] -= 1
|
||||||
|
return
|
||||||
|
raise KeyError
|
||||||
|
|
||||||
|
@property
|
||||||
|
def size(self) -> int:
|
||||||
|
return sum(sum(t.units.values()) for t in self.transfers)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def units(self) -> Dict[Type[VehicleType], int]:
|
||||||
|
units: Dict[Type[VehicleType], int] = defaultdict(int)
|
||||||
|
for transfer in self.transfers:
|
||||||
|
for unit_type, count in transfer.units.items():
|
||||||
|
units[unit_type] += count
|
||||||
|
return units
|
||||||
|
|
||||||
|
@property
|
||||||
|
def player_owned(self) -> bool:
|
||||||
|
return self.origin.captured
|
||||||
|
|
||||||
|
|
||||||
|
class ConvoyMap:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
# Dict of origin -> destination -> convoy.
|
||||||
|
self.convoys: Dict[ControlPoint, Dict[ControlPoint, Convoy]] = defaultdict(dict)
|
||||||
|
|
||||||
|
def convoy_exists(self, origin: ControlPoint, destination: ControlPoint) -> bool:
|
||||||
|
return destination in self.convoys[origin]
|
||||||
|
|
||||||
|
def find_convoy(
|
||||||
|
self, origin: ControlPoint, destination: ControlPoint
|
||||||
|
) -> Optional[Convoy]:
|
||||||
|
return self.convoys[origin].get(destination)
|
||||||
|
|
||||||
|
def find_or_create_convoy(
|
||||||
|
self, origin: ControlPoint, destination: ControlPoint
|
||||||
|
) -> Convoy:
|
||||||
|
convoy = self.find_convoy(origin, destination)
|
||||||
|
if convoy is None:
|
||||||
|
convoy = Convoy(origin, destination)
|
||||||
|
self.convoys[origin][destination] = convoy
|
||||||
|
return convoy
|
||||||
|
|
||||||
|
def departing_from(self, origin: ControlPoint) -> Iterator[Convoy]:
|
||||||
|
yield from self.convoys[origin].values()
|
||||||
|
|
||||||
|
def disband_convoy(self, convoy: Convoy) -> None:
|
||||||
|
del self.convoys[convoy.origin][convoy.destination]
|
||||||
|
|
||||||
|
def add(self, transfer: RoadTransferOrder) -> None:
|
||||||
|
next_stop = transfer.next_stop()
|
||||||
|
self.find_or_create_convoy(transfer.position, next_stop).add_units(transfer)
|
||||||
|
|
||||||
|
def remove(self, transfer: RoadTransferOrder) -> None:
|
||||||
|
next_stop = transfer.next_stop()
|
||||||
|
convoy = self.find_convoy(transfer.position, next_stop)
|
||||||
|
if convoy is None:
|
||||||
|
logging.error(
|
||||||
|
f"Attempting to remove {transfer} from convoy but it is in no convoy."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
convoy.remove_units(transfer)
|
||||||
|
if not convoy.transfers:
|
||||||
|
self.disband_convoy(convoy)
|
||||||
|
|
||||||
|
def disband_all(self) -> None:
|
||||||
|
self.convoys = defaultdict(dict)
|
||||||
|
|
||||||
|
def __iter__(self) -> Iterator[Convoy]:
|
||||||
|
for destination_dict in self.convoys.values():
|
||||||
|
yield from destination_dict.values()
|
||||||
|
|
||||||
|
|
||||||
class PendingTransfers:
|
class PendingTransfers:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
|
self.convoys = ConvoyMap()
|
||||||
self.pending_transfers: List[RoadTransferOrder] = []
|
self.pending_transfers: List[RoadTransferOrder] = []
|
||||||
|
|
||||||
def __iter__(self) -> Iterator[RoadTransferOrder]:
|
def __iter__(self) -> Iterator[RoadTransferOrder]:
|
||||||
@ -88,8 +171,10 @@ class PendingTransfers:
|
|||||||
def new_transfer(self, transfer: RoadTransferOrder) -> None:
|
def new_transfer(self, transfer: RoadTransferOrder) -> None:
|
||||||
transfer.origin.base.commit_losses(transfer.units)
|
transfer.origin.base.commit_losses(transfer.units)
|
||||||
self.pending_transfers.append(transfer)
|
self.pending_transfers.append(transfer)
|
||||||
|
self.convoys.add(transfer)
|
||||||
|
|
||||||
def cancel_transfer(self, transfer: RoadTransferOrder) -> None:
|
def cancel_transfer(self, transfer: RoadTransferOrder) -> None:
|
||||||
|
self.convoys.remove(transfer)
|
||||||
self.pending_transfers.remove(transfer)
|
self.pending_transfers.remove(transfer)
|
||||||
transfer.origin.base.commision_units(transfer.units)
|
transfer.origin.base.commision_units(transfer.units)
|
||||||
|
|
||||||
@ -99,8 +184,16 @@ class PendingTransfers:
|
|||||||
if not self.perform_transfer(transfer):
|
if not self.perform_transfer(transfer):
|
||||||
incomplete.append(transfer)
|
incomplete.append(transfer)
|
||||||
self.pending_transfers = incomplete
|
self.pending_transfers = incomplete
|
||||||
|
self.rebuild_convoys()
|
||||||
|
|
||||||
|
def rebuild_convoys(self) -> None:
|
||||||
|
self.convoys.disband_all()
|
||||||
|
for transfer in self.pending_transfers:
|
||||||
|
self.convoys.add(transfer)
|
||||||
|
|
||||||
def perform_transfer(self, transfer: RoadTransferOrder) -> bool:
|
def perform_transfer(self, transfer: RoadTransferOrder) -> bool:
|
||||||
|
# TODO: Can be improved to use the convoy map.
|
||||||
|
# The convoy map already has a lot of the data that we're recomputing here.
|
||||||
if transfer.player != transfer.destination.captured:
|
if transfer.player != transfer.destination.captured:
|
||||||
logging.info(
|
logging.info(
|
||||||
f"Transfer destination {transfer.destination.name} was captured."
|
f"Transfer destination {transfer.destination.name} was captured."
|
||||||
|
|||||||
@ -9,7 +9,7 @@ from dcs.unittype import VehicleType
|
|||||||
from game import db
|
from game import db
|
||||||
from game.theater import Airfield, ControlPoint, TheaterGroundObject
|
from game.theater import Airfield, ControlPoint, TheaterGroundObject
|
||||||
from game.theater.theatergroundobject import BuildingGroundObject
|
from game.theater.theatergroundobject import BuildingGroundObject
|
||||||
from game.transfers import RoadTransferOrder
|
from game.transfers import Convoy, RoadTransferOrder
|
||||||
from gen.flights.flight import Flight
|
from gen.flights.flight import Flight
|
||||||
|
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ class GroundObjectUnit:
|
|||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class ConvoyUnit:
|
class ConvoyUnit:
|
||||||
unit_type: Type[VehicleType]
|
unit_type: Type[VehicleType]
|
||||||
transfer: RoadTransferOrder
|
convoy: Convoy
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
@ -121,7 +121,7 @@ class UnitMap:
|
|||||||
def ground_object_unit(self, name: str) -> Optional[GroundObjectUnit]:
|
def ground_object_unit(self, name: str) -> Optional[GroundObjectUnit]:
|
||||||
return self.ground_object_units.get(name, None)
|
return self.ground_object_units.get(name, None)
|
||||||
|
|
||||||
def add_convoy_units(self, group: Group, transfer: RoadTransferOrder) -> None:
|
def add_convoy_units(self, group: Group, convoy: Convoy) -> None:
|
||||||
for unit in group.units:
|
for unit in group.units:
|
||||||
# The actual name is a String (the pydcs translatable string), which
|
# The actual name is a String (the pydcs translatable string), which
|
||||||
# doesn't define __eq__.
|
# doesn't define __eq__.
|
||||||
@ -135,7 +135,7 @@ class UnitMap:
|
|||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
f"{name} is a {unit_type.__name__}, expected a VehicleType"
|
f"{name} is a {unit_type.__name__}, expected a VehicleType"
|
||||||
)
|
)
|
||||||
self.convoys[name] = ConvoyUnit(unit_type, transfer)
|
self.convoys[name] = ConvoyUnit(unit_type, convoy)
|
||||||
|
|
||||||
def convoy_unit(self, name: str) -> Optional[ConvoyUnit]:
|
def convoy_unit(self, name: str) -> Optional[ConvoyUnit]:
|
||||||
return self.convoys.get(name, None)
|
return self.convoys.get(name, None)
|
||||||
|
|||||||
@ -1697,7 +1697,7 @@ class BaiIngressBuilder(PydcsWaypointBuilder):
|
|||||||
if isinstance(target_group, TheaterGroundObject):
|
if isinstance(target_group, TheaterGroundObject):
|
||||||
group_name = target_group.group_name
|
group_name = target_group.group_name
|
||||||
elif isinstance(target_group, Convoy):
|
elif isinstance(target_group, Convoy):
|
||||||
group_name = target_group.transfer.name
|
group_name = target_group.name
|
||||||
else:
|
else:
|
||||||
logging.error(
|
logging.error(
|
||||||
"Unexpected target type for BAI mission: %s",
|
"Unexpected target type for BAI mission: %s",
|
||||||
|
|||||||
@ -10,7 +10,7 @@ from dcs.unit import Vehicle
|
|||||||
from dcs.unitgroup import VehicleGroup
|
from dcs.unitgroup import VehicleGroup
|
||||||
from dcs.unittype import VehicleType
|
from dcs.unittype import VehicleType
|
||||||
|
|
||||||
from game.transfers import RoadTransferOrder
|
from game.transfers import Convoy, RoadTransferOrder
|
||||||
from game.unitmap import UnitMap
|
from game.unitmap import UnitMap
|
||||||
from game.utils import kph
|
from game.utils import kph
|
||||||
|
|
||||||
@ -27,25 +27,23 @@ class ConvoyGenerator:
|
|||||||
|
|
||||||
def generate(self) -> None:
|
def generate(self) -> None:
|
||||||
# Reset the count to make generation deterministic.
|
# Reset the count to make generation deterministic.
|
||||||
for transfer in self.game.transfers:
|
for convoy in self.game.transfers.convoys:
|
||||||
self.generate_convoy_for(transfer)
|
self.generate_convoy(convoy)
|
||||||
|
|
||||||
def generate_convoy_for(self, transfer: RoadTransferOrder) -> VehicleGroup:
|
|
||||||
next_hop = transfer.path()[0]
|
|
||||||
origin = transfer.position.convoy_spawns[next_hop]
|
|
||||||
destination = next_hop.convoy_spawns[transfer.position]
|
|
||||||
|
|
||||||
|
def generate_convoy(self, convoy: Convoy) -> VehicleGroup:
|
||||||
group = self._create_mixed_unit_group(
|
group = self._create_mixed_unit_group(
|
||||||
transfer.name,
|
convoy.name,
|
||||||
origin,
|
convoy.origin.position,
|
||||||
transfer.units,
|
convoy.units,
|
||||||
transfer.player,
|
convoy.player_owned,
|
||||||
)
|
)
|
||||||
group.add_waypoint(
|
group.add_waypoint(
|
||||||
destination, speed=kph(40).kph, move_formation=PointAction.OnRoad
|
convoy.destination.position,
|
||||||
|
speed=kph(40).kph,
|
||||||
|
move_formation=PointAction.OnRoad,
|
||||||
)
|
)
|
||||||
self.make_drivable(group)
|
self.make_drivable(group)
|
||||||
self.unit_map.add_convoy_units(group, transfer)
|
self.unit_map.add_convoy_units(group, convoy)
|
||||||
return group
|
return group
|
||||||
|
|
||||||
def _create_mixed_unit_group(
|
def _create_mixed_unit_group(
|
||||||
|
|||||||
@ -333,7 +333,7 @@ class NameGenerator:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def next_convoy_name(cls) -> str:
|
def next_convoy_name(cls) -> str:
|
||||||
cls.convoy_number += 1
|
cls.convoy_number += 1
|
||||||
return f"Convoy {cls.convoy_number:04}"
|
return f"Convoy {cls.convoy_number:03}"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def random_objective_name(cls):
|
def random_objective_name(cls):
|
||||||
|
|||||||
@ -44,7 +44,7 @@ from game.theater.conflicttheater import FrontLine, ReferencePoint
|
|||||||
from game.theater.theatergroundobject import (
|
from game.theater.theatergroundobject import (
|
||||||
TheaterGroundObject,
|
TheaterGroundObject,
|
||||||
)
|
)
|
||||||
from game.transfers import RoadTransferOrder
|
from game.transfers import Convoy, RoadTransferOrder
|
||||||
from game.utils import Distance, meters, nautical_miles
|
from game.utils import Distance, meters, nautical_miles
|
||||||
from game.weather import TimeOfDay
|
from game.weather import TimeOfDay
|
||||||
from gen import Conflict, Package
|
from gen import Conflict, Package
|
||||||
@ -827,7 +827,7 @@ class QLiberationMap(QGraphicsView):
|
|||||||
self,
|
self,
|
||||||
scene: QGraphicsScene,
|
scene: QGraphicsScene,
|
||||||
frontline: FrontLine,
|
frontline: FrontLine,
|
||||||
convoys: List[RoadTransferOrder],
|
convoys: List[Convoy],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Thanks to Alquimista for sharing a python implementation of the bezier algorithm this is adapted from.
|
Thanks to Alquimista for sharing a python implementation of the bezier algorithm this is adapted from.
|
||||||
@ -895,7 +895,15 @@ class QLiberationMap(QGraphicsView):
|
|||||||
def draw_supply_route_between(self, a: ControlPoint, b: ControlPoint) -> None:
|
def draw_supply_route_between(self, a: ControlPoint, b: ControlPoint) -> None:
|
||||||
scene = self.scene()
|
scene = self.scene()
|
||||||
|
|
||||||
convoys = self._transfers_between(a, b)
|
convoy_map = self.game.transfers.convoys
|
||||||
|
convoys = []
|
||||||
|
convoy = convoy_map.find_convoy(a, b)
|
||||||
|
if convoy is not None:
|
||||||
|
convoys.append(convoy)
|
||||||
|
convoy = convoy_map.find_convoy(b, a)
|
||||||
|
if convoy is not None:
|
||||||
|
convoys.append(convoy)
|
||||||
|
|
||||||
frontline = FrontLine(a, b, self.game.theater)
|
frontline = FrontLine(a, b, self.game.theater)
|
||||||
if a.front_is_active(b):
|
if a.front_is_active(b):
|
||||||
if DisplayOptions.actual_frontline_pos:
|
if DisplayOptions.actual_frontline_pos:
|
||||||
@ -909,7 +917,7 @@ class QLiberationMap(QGraphicsView):
|
|||||||
self,
|
self,
|
||||||
scene: QGraphicsScene,
|
scene: QGraphicsScene,
|
||||||
frontline: FrontLine,
|
frontline: FrontLine,
|
||||||
convoys: List[RoadTransferOrder],
|
convoys: List[Convoy],
|
||||||
) -> None:
|
) -> None:
|
||||||
posx = frontline.position
|
posx = frontline.position
|
||||||
h = frontline.attack_heading
|
h = frontline.attack_heading
|
||||||
@ -925,7 +933,7 @@ class QLiberationMap(QGraphicsView):
|
|||||||
self,
|
self,
|
||||||
scene: QGraphicsScene,
|
scene: QGraphicsScene,
|
||||||
frontline: FrontLine,
|
frontline: FrontLine,
|
||||||
convoys: List[RoadTransferOrder],
|
convoys: List[Convoy],
|
||||||
) -> None:
|
) -> None:
|
||||||
self.draw_bezier_frontline(scene, frontline, convoys)
|
self.draw_bezier_frontline(scene, frontline, convoys)
|
||||||
vector = Conflict.frontline_vector(
|
vector = Conflict.frontline_vector(
|
||||||
|
|||||||
@ -9,7 +9,7 @@ from PySide2.QtWidgets import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from game.theater import ControlPoint
|
from game.theater import ControlPoint
|
||||||
from game.transfers import RoadTransferOrder
|
from game.transfers import Convoy
|
||||||
from qt_ui.uiconstants import COLORS
|
from qt_ui.uiconstants import COLORS
|
||||||
|
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ class SupplyRouteSegment(QGraphicsLineItem):
|
|||||||
y1: float,
|
y1: float,
|
||||||
control_point_a: ControlPoint,
|
control_point_a: ControlPoint,
|
||||||
control_point_b: ControlPoint,
|
control_point_b: ControlPoint,
|
||||||
convoys: List[RoadTransferOrder],
|
convoys: List[Convoy],
|
||||||
parent: Optional[QGraphicsItem] = None,
|
parent: Optional[QGraphicsItem] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(x0, y0, x1, y1, parent)
|
super().__init__(x0, y0, x1, y1, parent)
|
||||||
@ -37,19 +37,18 @@ class SupplyRouteSegment(QGraphicsLineItem):
|
|||||||
def has_convoys(self) -> bool:
|
def has_convoys(self) -> bool:
|
||||||
return bool(self.convoys)
|
return bool(self.convoys)
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def convoy_size(self) -> int:
|
|
||||||
return sum(sum(c.units.values()) for c in self.convoys)
|
|
||||||
|
|
||||||
def make_tooltip(self) -> str:
|
def make_tooltip(self) -> str:
|
||||||
if not self.has_convoys:
|
if not self.has_convoys:
|
||||||
return "No convoys present on this supply route."
|
return "No convoys present on this supply route."
|
||||||
units = "units" if self.convoy_size > 1 else "unit"
|
|
||||||
|
|
||||||
return (
|
convoys = []
|
||||||
f"{self.convoy_size} {units} transferring between {self.control_point_a} "
|
for convoy in self.convoys:
|
||||||
f"and {self.control_point_b}."
|
units = "units" if convoy.size > 1 else "unit"
|
||||||
)
|
convoys.append(
|
||||||
|
f"{convoy.size} {units} transferring from {convoy.origin} to "
|
||||||
|
f"{convoy.destination}"
|
||||||
|
)
|
||||||
|
return "\n".join(convoys)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def line_color(self) -> QColor:
|
def line_color(self) -> QColor:
|
||||||
|
|||||||
@ -12,15 +12,15 @@ from PySide2.QtWidgets import (
|
|||||||
|
|
||||||
from game import db
|
from game import db
|
||||||
from game.theater import ControlPoint
|
from game.theater import ControlPoint
|
||||||
from game.transfers import Convoy, RoadTransferOrder
|
from game.transfers import Convoy
|
||||||
from qt_ui.dialogs import Dialog
|
from qt_ui.dialogs import Dialog
|
||||||
from qt_ui.models import GameModel
|
from qt_ui.models import GameModel
|
||||||
from qt_ui.uiconstants import VEHICLES_ICONS
|
from qt_ui.uiconstants import VEHICLES_ICONS
|
||||||
|
|
||||||
|
|
||||||
class DepartingConvoyInfo(QGroupBox):
|
class DepartingConvoyInfo(QGroupBox):
|
||||||
def __init__(self, convoy: RoadTransferOrder, game_model: GameModel) -> None:
|
def __init__(self, convoy: Convoy, game_model: GameModel) -> None:
|
||||||
super().__init__(f"To {convoy.destination}")
|
super().__init__(f"{convoy.name} to {convoy.destination}")
|
||||||
self.convoy = convoy
|
self.convoy = convoy
|
||||||
|
|
||||||
main_layout = QVBoxLayout()
|
main_layout = QVBoxLayout()
|
||||||
@ -61,7 +61,7 @@ class DepartingConvoyInfo(QGroupBox):
|
|||||||
# complicated. We could instead generate this at the start of the turn (and
|
# complicated. We could instead generate this at the start of the turn (and
|
||||||
# update whenever transfers are created or canceled) and also use that time to
|
# update whenever transfers are created or canceled) and also use that time to
|
||||||
# precalculate things like the next stop and group names.
|
# precalculate things like the next stop and group names.
|
||||||
Dialog.open_new_package_dialog(Convoy(self.convoy), parent=self.window())
|
Dialog.open_new_package_dialog(self.convoy, parent=self.window())
|
||||||
|
|
||||||
|
|
||||||
class DepartingConvoysList(QFrame):
|
class DepartingConvoysList(QFrame):
|
||||||
@ -78,9 +78,8 @@ class DepartingConvoysList(QFrame):
|
|||||||
task_box_layout = QGridLayout()
|
task_box_layout = QGridLayout()
|
||||||
scroll_content.setLayout(task_box_layout)
|
scroll_content.setLayout(task_box_layout)
|
||||||
|
|
||||||
for convoy in game_model.game.transfers:
|
convoy_map = game_model.game.transfers.convoys
|
||||||
if convoy.position != cp:
|
for convoy in convoy_map.departing_from(cp):
|
||||||
continue
|
|
||||||
group_info = DepartingConvoyInfo(convoy, game_model)
|
group_info = DepartingConvoyInfo(convoy, game_model)
|
||||||
task_box_layout.addWidget(group_info)
|
task_box_layout.addWidget(group_info)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user