mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
121 lines
4.0 KiB
Python
121 lines
4.0 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Optional
|
|
|
|
from PySide2.QtCore import Property, QObject, Signal, Slot
|
|
from dcs import Point
|
|
from dcs.mapping import LatLng
|
|
|
|
from game.server.leaflet import LeafletLatLon
|
|
from game.theater import ConflictTheater, ControlPoint, ControlPointStatus
|
|
from game.utils import meters, nautical_miles
|
|
from qt_ui.dialogs import Dialog
|
|
from qt_ui.models import GameModel
|
|
from qt_ui.windows.basemenu.QBaseMenu2 import QBaseMenu2
|
|
|
|
MAX_SHIP_DISTANCE = nautical_miles(80)
|
|
|
|
|
|
class ControlPointJs(QObject):
|
|
nameChanged = Signal()
|
|
blueChanged = Signal()
|
|
positionChanged = Signal()
|
|
mobileChanged = Signal()
|
|
destinationChanged = Signal(list)
|
|
categoryChanged = Signal()
|
|
statusChanged = Signal()
|
|
|
|
def __init__(
|
|
self,
|
|
control_point: ControlPoint,
|
|
game_model: GameModel,
|
|
theater: ConflictTheater,
|
|
) -> None:
|
|
super().__init__()
|
|
self.control_point = control_point
|
|
self.game_model = game_model
|
|
self.theater = theater
|
|
self.dialog: Optional[QBaseMenu2] = None
|
|
|
|
@Property(str, notify=nameChanged)
|
|
def name(self) -> str:
|
|
return self.control_point.name
|
|
|
|
@Property(bool, notify=blueChanged)
|
|
def blue(self) -> bool:
|
|
return self.control_point.captured
|
|
|
|
@Property(str, notify=categoryChanged)
|
|
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:
|
|
return self.control_point.position.latlng().as_list()
|
|
|
|
@Property(bool, notify=mobileChanged)
|
|
def mobile(self) -> bool:
|
|
return self.control_point.moveable and self.control_point.captured
|
|
|
|
@Property(list, notify=destinationChanged)
|
|
def destination(self) -> LeafletLatLon:
|
|
if self.control_point.target_position is None:
|
|
# Qt seems to convert None to [] for list Properties :(
|
|
return []
|
|
return self.control_point.target_position.latlng().as_list()
|
|
|
|
def destination_in_range(self, destination: Point) -> bool:
|
|
move_distance = meters(
|
|
destination.distance_to_point(self.control_point.position)
|
|
)
|
|
return move_distance <= MAX_SHIP_DISTANCE
|
|
|
|
@Slot(list, result=bool)
|
|
def destinationInRange(self, destination: LeafletLatLon) -> bool:
|
|
return self.destination_in_range(
|
|
Point.from_latlng(LatLng(*destination), self.theater.terrain)
|
|
)
|
|
|
|
@Slot(list, result=str)
|
|
def setDestination(self, destination: LeafletLatLon) -> str:
|
|
if not self.control_point.moveable:
|
|
return f"{self.control_point} is not mobile"
|
|
if not self.control_point.captured:
|
|
return f"{self.control_point} is not owned by player"
|
|
|
|
point = Point.from_latlng(LatLng(*destination), self.theater.terrain)
|
|
if not self.destination_in_range(point):
|
|
return (
|
|
f"Cannot move {self.control_point} more than "
|
|
f"{MAX_SHIP_DISTANCE.nautical_miles}nm."
|
|
)
|
|
self.control_point.target_position = point
|
|
self.destinationChanged.emit(destination)
|
|
return ""
|
|
|
|
@Slot()
|
|
def cancelTravel(self) -> None:
|
|
self.control_point.target_position = None
|
|
self.destinationChanged.emit([])
|
|
|
|
@Slot()
|
|
def showInfoDialog(self) -> None:
|
|
if self.dialog is None:
|
|
self.dialog = QBaseMenu2(None, self.control_point, self.game_model)
|
|
self.dialog.show()
|
|
|
|
@Slot()
|
|
def showPackageDialog(self) -> None:
|
|
Dialog.open_new_package_dialog(self.control_point)
|