diff --git a/game/theater/theatergroundobject.py b/game/theater/theatergroundobject.py index a748c28d..00203ade 100644 --- a/game/theater/theatergroundobject.py +++ b/game/theater/theatergroundobject.py @@ -260,6 +260,18 @@ class TheaterGroundObject(MissionTarget, SidcDescribable, ABC): return group return None + def rotate(self, heading: Heading) -> None: + """Rotate the whole TGO clockwise to the new heading""" + rotation = heading - self.heading + if rotation.degrees < 0: + rotation = Heading.from_degrees(rotation.degrees + 360) + + self.heading = heading + # Rotate the whole TGO to match the new heading + for unit in self.units: + unit.position.heading += rotation + unit.position.rotate(self.position, rotation) + class BuildingGroundObject(TheaterGroundObject): def __init__( diff --git a/qt_ui/uiconstants.py b/qt_ui/uiconstants.py index bc646469..0409cf4a 100644 --- a/qt_ui/uiconstants.py +++ b/qt_ui/uiconstants.py @@ -166,6 +166,8 @@ def load_icons(): "./resources/ui/conditions/weather/night-totally-cloud.png" ) + ICONS["heading"] = QPixmap("./resources/ui/misc/heading.png") + EVENT_ICONS: Dict[str, QPixmap] = {} diff --git a/qt_ui/windows/groundobject/QGroundObjectBuyMenu.py b/qt_ui/windows/groundobject/QGroundObjectBuyMenu.py index 0a7bfc6e..2cbdc3c8 100644 --- a/qt_ui/windows/groundobject/QGroundObjectBuyMenu.py +++ b/qt_ui/windows/groundobject/QGroundObjectBuyMenu.py @@ -27,8 +27,6 @@ from game.layout.layout import ( TgoLayout, TgoLayoutGroup, ) -from game.server import EventStream -from game.sim.gameupdateevents import GameUpdateEvents from game.theater import TheaterGroundObject from game.theater.theatergroundobject import ( EwrGroundObject, @@ -36,7 +34,6 @@ from game.theater.theatergroundobject import ( VehicleGroupGroundObject, ) from qt_ui.uiconstants import EVENT_ICONS -from qt_ui.windows.GameUpdateSignal import GameUpdateSignal @dataclass @@ -208,6 +205,12 @@ class QGroundObjectTemplateLayout(QGroupBox): # Something went wrong. Buy button should be disabled! logging.error("Not enough money to buy the group") return + + # Change the heading of the new group to head to the conflict + self.ground_object.heading = ( + self.game.theater.heading_to_conflict_from(self.ground_object.position) + or self.ground_object.heading + ) self.game.blue.budget -= price - self.current_group_value self.ground_object.groups = [] for group_name, groups in self.layout_model.groups.items(): diff --git a/qt_ui/windows/groundobject/QGroundObjectMenu.py b/qt_ui/windows/groundobject/QGroundObjectMenu.py index 4353a3cb..ae846347 100644 --- a/qt_ui/windows/groundobject/QGroundObjectMenu.py +++ b/qt_ui/windows/groundobject/QGroundObjectMenu.py @@ -1,5 +1,6 @@ import logging +from PySide2.QtGui import QTransform from PySide2.QtWidgets import ( QDialog, QGridLayout, @@ -8,6 +9,7 @@ from PySide2.QtWidgets import ( QLabel, QPushButton, QVBoxLayout, + QSpinBox, ) from dcs import Point @@ -20,7 +22,8 @@ from game.theater import ControlPoint, TheaterGroundObject from game.theater.theatergroundobject import ( BuildingGroundObject, ) -from qt_ui.uiconstants import EVENT_ICONS +from game.utils import Heading +from qt_ui.uiconstants import EVENT_ICONS, ICONS from qt_ui.widgets.QBudgetBox import QBudgetBox from qt_ui.windows.GameUpdateSignal import GameUpdateSignal from qt_ui.windows.groundobject.QBuildingInfo import QBuildingInfo @@ -46,6 +49,7 @@ class QGroundObjectMenu(QDialog): self.setWindowIcon(EVENT_ICONS["capture"]) self.intelBox = QGroupBox("Units :") self.buildingBox = QGroupBox("Buildings :") + self.orientationBox = QGroupBox("Orientation :") self.intelLayout = QGridLayout() self.buildingsLayout = QGridLayout() self.sell_all_button = None @@ -66,6 +70,7 @@ class QGroundObjectMenu(QDialog): self.mainLayout.addWidget(self.financesBox) else: self.mainLayout.addWidget(self.intelBox) + self.mainLayout.addWidget(self.orientationBox) self.actionLayout = QHBoxLayout() @@ -141,13 +146,49 @@ class QGroundObjectMenu(QDialog): QLabel("Receiving: " + str(received_income) + "M"), 2, 2 ) + # Orientation Box + self.orientationBox = QGroupBox("Orientation :") + self.orientationBoxLayout = QHBoxLayout() + + heading_image = QLabel() + heading_image.setPixmap( + ICONS["heading"].transformed( + QTransform().rotate(self.ground_object.heading.degrees) + ) + ) + self.orientationBoxLayout.addWidget(heading_image) + self.headingLabel = QLabel("Heading:") + self.orientationBoxLayout.addWidget(self.headingLabel) + self.headingSelector = QSpinBox() + self.headingSelector.setEnabled(False) # Disable for now + self.headingSelector.setMinimum(0) + self.headingSelector.setMaximum(360) + self.headingSelector.setValue(self.ground_object.heading.degrees) + self.orientationBoxLayout.addWidget(self.headingSelector) + if self.cp.captured: + # TODO Let the user choose the heading with the SpinBox + self.headingSelector.setEnabled(False) + self.head_to_conflict_button = QPushButton("Head to conflict") + heading = ( + self.game.theater.heading_to_conflict_from(self.ground_object.position) + or self.ground_object.heading + ) + self.head_to_conflict_button.clicked.connect( + lambda: self.rotate_tgo(heading) + ) + self.orientationBoxLayout.addWidget(self.head_to_conflict_button) + else: + self.headingSelector.setEnabled(False) + + # Set the layouts self.financesBox.setLayout(self.financesBoxLayout) self.buildingBox.setLayout(self.buildingsLayout) self.intelBox.setLayout(self.intelLayout) + self.orientationBox.setLayout(self.orientationBoxLayout) def do_refresh_layout(self): try: - for i in range(self.mainLayout.count()): + for i in reversed(range(self.mainLayout.count())): item = self.mainLayout.itemAt(i) if item is not None and item.widget() is not None: item.widget().setParent(None) @@ -160,6 +201,7 @@ class QGroundObjectMenu(QDialog): self.mainLayout.addWidget(self.buildingBox) else: self.mainLayout.addWidget(self.intelBox) + self.mainLayout.addWidget(self.orientationBox) self.actionLayout = QHBoxLayout() if self.total_value > 0: @@ -198,6 +240,10 @@ class QGroundObjectMenu(QDialog): self.do_refresh_layout() + def rotate_tgo(self, heading: Heading) -> None: + self.ground_object.rotate(heading) + self.do_refresh_layout() + def sell_all(self): self.update_total_value() self.game.blue.budget = self.game.blue.budget + self.total_value diff --git a/resources/ui/misc/heading.png b/resources/ui/misc/heading.png new file mode 100644 index 00000000..f05288cf Binary files /dev/null and b/resources/ui/misc/heading.png differ