From 284f2bc323ac8e237dfe80b55e68a8b90a74493a Mon Sep 17 00:00:00 2001 From: Dan Albert Date: Mon, 31 May 2021 14:17:57 -0700 Subject: [PATCH] Show runway status on the new map. Fixes https://github.com/dcs-liberation/dcs_liberation/issues/1105 --- game/theater/controlpoint.py | 65 ++++++++++++++++++++++++++++------- qt_ui/widgets/map/mapmodel.py | 13 +++++++ resources/ui/map/map.js | 4 +-- 3 files changed, 67 insertions(+), 15 deletions(-) diff --git a/game/theater/controlpoint.py b/game/theater/controlpoint.py index ad316afc..adedb330 100644 --- a/game/theater/controlpoint.py +++ b/game/theater/controlpoint.py @@ -6,7 +6,7 @@ import logging from abc import ABC, abstractmethod from collections import defaultdict from dataclasses import dataclass, field -from enum import Enum +from enum import Enum, unique, auto, IntEnum from functools import total_ordering, cached_property from typing import ( Any, @@ -219,6 +219,13 @@ class GroundUnitDestination: return self.total_value < other.total_value +@unique +class ControlPointStatus(IntEnum): + Functional = auto() + Damaged = auto() + Destroyed = auto() + + class ControlPoint(MissionTarget, ABC): position = None # type: Point @@ -710,6 +717,11 @@ class ControlPoint(MissionTarget, ABC): def category(self) -> str: ... + @property + @abstractmethod + def status(self) -> ControlPointStatus: + ... + class Airfield(ControlPoint): def __init__( @@ -794,6 +806,15 @@ class Airfield(ControlPoint): def category(self) -> str: return "airfield" + @property + def status(self) -> ControlPointStatus: + runway_staus = self.runway_status + if runway_staus.needs_repair: + return ControlPointStatus.Destroyed + elif runway_staus.damaged: + return ControlPointStatus.Damaged + return ControlPointStatus.Functional + class NavalControlPoint(ControlPoint, ABC): @property @@ -818,20 +839,24 @@ class NavalControlPoint(ControlPoint, ABC): def heading(self) -> int: return 0 # TODO compute heading + def find_main_tgo(self) -> TheaterGroundObject: + for g in self.ground_objects: + if g.dcs_identifier in ["CARRIER", "LHA"]: + return g + raise RuntimeError(f"Found no carrier/LHA group for {self.name}") + def runway_is_operational(self) -> bool: # Necessary because it's possible for the carrier itself to have sunk # while its escorts are still alive. - for g in self.ground_objects: - if g.dcs_identifier in ["CARRIER", "LHA"]: - for group in g.groups: - for u in group.units: - if db.unit_type_from_name(u.type) in [ - CVN_74_John_C__Stennis, - LHA_1_Tarawa, - CV_1143_5_Admiral_Kuznetsov, - Type_071_Amphibious_Transport_Dock, - ]: - return True + for group in self.find_main_tgo().groups: + for u in group.units: + if db.unit_type_from_name(u.type) in [ + CVN_74_John_C__Stennis, + LHA_1_Tarawa, + CV_1143_5_Admiral_Kuznetsov, + Type_071_Amphibious_Transport_Dock, + ]: + return True return False def active_runway( @@ -857,6 +882,14 @@ class NavalControlPoint(ControlPoint, ABC): def can_deploy_ground_units(self) -> bool: return False + @property + def status(self) -> ControlPointStatus: + if not self.runway_is_operational(): + return ControlPointStatus.Destroyed + if self.find_main_tgo().dead_units: + return ControlPointStatus.Damaged + return ControlPointStatus.Functional + class Carrier(NavalControlPoint): def __init__(self, name: str, at: Point, cp_id: int): @@ -986,6 +1019,10 @@ class OffMapSpawn(ControlPoint): def category(self) -> str: return "offmap" + @property + def status(self) -> ControlPointStatus: + return ControlPointStatus.Functional + class Fob(ControlPoint): def __init__(self, name: str, at: Point, cp_id: int): @@ -1046,3 +1083,7 @@ class Fob(ControlPoint): @property def category(self) -> str: return "fob" + + @property + def status(self) -> ControlPointStatus: + return ControlPointStatus.Functional diff --git a/qt_ui/widgets/map/mapmodel.py b/qt_ui/widgets/map/mapmodel.py index 6ae67fdf..a4f84ff5 100644 --- a/qt_ui/widgets/map/mapmodel.py +++ b/qt_ui/widgets/map/mapmodel.py @@ -20,6 +20,7 @@ from game.theater import ( TheaterGroundObject, FrontLine, LatLon, + ControlPointStatus, ) from game.threatzones import ThreatZones from game.transfers import MultiGroupTransport, TransportMap @@ -79,6 +80,7 @@ class ControlPointJs(QObject): mobileChanged = Signal() destinationChanged = Signal(list) categoryChanged = Signal() + statusChanged = Signal() def __init__( self, @@ -104,6 +106,17 @@ class ControlPointJs(QObject): def category(self) -> str: return self.control_point.category + @Property(str, notify=statusChanged) + def status(self) -> str: + status = self.control_point.status + if status is ControlPointStatus.Functional: + return "alive" + elif status is ControlPointStatus.Damaged: + return "damaged" + elif status is ControlPointStatus.Destroyed: + return "destroyed" + raise ValueError(f"Unhandled ControlPointStatus: {status.name}") + @Property(list, notify=positionChanged) def position(self) -> LeafletLatLon: ll = self.theater.point_to_ll(self.control_point.position) diff --git a/resources/ui/map/map.js b/resources/ui/map/map.js index 5a48323f..5a8dee3d 100644 --- a/resources/ui/map/map.js +++ b/resources/ui/map/map.js @@ -290,12 +290,10 @@ class ControlPoint { } icon() { - // TODO: Runway status. - // https://github.com/dcs-liberation/dcs_liberation/issues/1105 return Icons.ControlPoints.icon( this.cp.category, this.cp.blue, - UnitState.Alive + this.cp.status ); }