Possible to plan ships movements on the map (UI only)

This commit is contained in:
Khopa 2020-12-03 01:01:15 +01:00
parent bf275fe564
commit 72ac806cb8
4 changed files with 95 additions and 10 deletions

View File

@ -230,6 +230,8 @@ class ControlPoint(MissionTarget, ABC):
self.stances: Dict[int, CombatStance] = {} self.stances: Dict[int, CombatStance] = {}
self.pending_unit_deliveries: Optional[UnitsDeliveryEvent] = None self.pending_unit_deliveries: Optional[UnitsDeliveryEvent] = None
self.target_position = None
def __repr__(self): def __repr__(self):
return f"<{__class__}: {self.name}>" return f"<{__class__}: {self.name}>"
@ -271,6 +273,13 @@ class ControlPoint(MissionTarget, ABC):
""" """
return False return False
@property
def moveable(self) -> bool:
"""
:return: Whether this control point can be moved around
"""
return False
@property @property
@abstractmethod @abstractmethod
def total_aircraft_parking(self): def total_aircraft_parking(self):
@ -491,6 +500,7 @@ class Airfield(ControlPoint):
class NavalControlPoint(ControlPoint, ABC): class NavalControlPoint(ControlPoint, ABC):
@property @property
def is_fleet(self) -> bool: def is_fleet(self) -> bool:
return True return True
@ -539,6 +549,10 @@ class NavalControlPoint(ControlPoint, ABC):
def runway_can_be_repaired(self) -> bool: def runway_can_be_repaired(self) -> bool:
return False return False
@property
def moveable(self) -> bool:
return True
class Carrier(NavalControlPoint): class Carrier(NavalControlPoint):
@ -546,8 +560,7 @@ class Carrier(NavalControlPoint):
import game.theater.conflicttheater import game.theater.conflicttheater
super().__init__(cp_id, name, at, at, super().__init__(cp_id, name, at, at,
game.theater.conflicttheater.SIZE_SMALL, 1, game.theater.conflicttheater.SIZE_SMALL, 1,
has_frontline=False, has_frontline=False, cptype=ControlPointType.AIRCRAFT_CARRIER_GROUP)
cptype=ControlPointType.AIRCRAFT_CARRIER_GROUP)
def capture(self, game: Game, for_player: bool) -> None: def capture(self, game: Game, for_player: bool) -> None:
raise RuntimeError("Carriers cannot be captured") raise RuntimeError("Carriers cannot be captured")

View File

@ -5,7 +5,8 @@ import logging
import math import math
from typing import Iterable, Iterator, List, Optional, Tuple from typing import Iterable, Iterator, List, Optional, Tuple
from PySide2.QtCore import QPointF, Qt from PySide2 import QtWidgets, QtCore
from PySide2.QtCore import QPointF, Qt, QLineF
from PySide2.QtGui import ( from PySide2.QtGui import (
QBrush, QBrush,
QColor, QColor,
@ -13,21 +14,20 @@ from PySide2.QtGui import (
QPen, QPen,
QPixmap, QPixmap,
QPolygonF, QPolygonF,
QWheelEvent, QWheelEvent, )
)
from PySide2.QtWidgets import ( from PySide2.QtWidgets import (
QFrame, QFrame,
QGraphicsItem, QGraphicsItem,
QGraphicsOpacityEffect, QGraphicsOpacityEffect,
QGraphicsScene, QGraphicsScene,
QGraphicsView, QGraphicsView, QGraphicsSceneMouseEvent,
) )
from dcs import Point from dcs import Point
from dcs.mapping import point_from_heading from dcs.mapping import point_from_heading
import qt_ui.uiconstants as CONST import qt_ui.uiconstants as CONST
from game import Game, db from game import Game, db
from game.theater import ControlPoint from game.theater import ControlPoint, Enum
from game.theater.conflicttheater import FrontLine from game.theater.conflicttheater import FrontLine
from game.theater.theatergroundobject import ( from game.theater.theatergroundobject import (
EwrGroundObject, EwrGroundObject,
@ -76,6 +76,12 @@ def bezier_curve_range(n: int, points: Iterable[Tuple[float, float]]) -> Iterato
t = i / float(n - 1) t = i / float(n - 1)
yield bezier(t, points) yield bezier(t, points)
class QLiberationMapState(Enum):
NORMAL = 0
MOVING_UNIT = 1
class QLiberationMap(QGraphicsView): class QLiberationMap(QGraphicsView):
WAYPOINT_SIZE = 4 WAYPOINT_SIZE = 4
@ -86,6 +92,7 @@ class QLiberationMap(QGraphicsView):
QLiberationMap.instance = self QLiberationMap.instance = self
self.game_model = game_model self.game_model = game_model
self.game: Optional[Game] = game_model.game self.game: Optional[Game] = game_model.game
self.state = QLiberationMapState.NORMAL
self.waypoint_info_font = QFont() self.waypoint_info_font = QFont()
self.waypoint_info_font.setPointSize(12) self.waypoint_info_font.setPointSize(12)
@ -102,6 +109,11 @@ class QLiberationMap(QGraphicsView):
self.init_scene() self.init_scene()
self.setGame(game_model.game) self.setGame(game_model.game)
# Object displayed when unit is selected
self.movement_line = QtWidgets.QGraphicsLineItem(QtCore.QLineF(QPointF(0,0),QPointF(0,0)))
self.movement_line.setPen(QPen(CONST.COLORS["orange"], width=10.0))
self.selected_cp: QMapControlPoint = None
GameUpdateSignal.get_instance().flight_paths_changed.connect( GameUpdateSignal.get_instance().flight_paths_changed.connect(
lambda: self.draw_flight_plans(self.scene()) lambda: self.draw_flight_plans(self.scene())
) )
@ -316,6 +328,12 @@ class QLiberationMap(QGraphicsView):
self.draw_ground_objects(scene, cp) self.draw_ground_objects(scene, cp)
if cp.target_position is not None:
tpos = cp.target_position
scene.addLine(QLineF(QPointF(pos[0], pos[1]), QPointF(tpos[0], tpos[1])),
QPen(CONST.COLORS["green"], width=10, s=Qt.DashDotLine))
for cp in self.game.theater.enemy_points(): for cp in self.game.theater.enemy_points():
if DisplayOptions.lines: if DisplayOptions.lines:
self.scene_create_lines_for_cp(cp, playerColor, enemyColor) self.scene_create_lines_for_cp(cp, playerColor, enemyColor)
@ -572,6 +590,10 @@ class QLiberationMap(QGraphicsView):
return X > treshold and X or treshold, Y > treshold and Y or treshold return X > treshold and X or treshold, Y > treshold and Y or treshold
def _scene_to_dcs_coords(self, x, y):
pass
def highlight_color(self, transparent: Optional[bool] = False) -> QColor: def highlight_color(self, transparent: Optional[bool] = False) -> QColor:
return QColor(255, 255, 0, 20 if transparent else 255) return QColor(255, 255, 0, 20 if transparent else 255)
@ -657,6 +679,32 @@ class QLiberationMap(QGraphicsView):
poly = QPolygonF([QPointF(*self._transform_point(Point(point[0], point[1]))) for point in exclusion_zone]) poly = QPolygonF([QPointF(*self._transform_point(Point(point[0], point[1]))) for point in exclusion_zone])
scene.addPolygon(poly, CONST.COLORS["grey"], CONST.COLORS["dark_dark_grey"]) scene.addPolygon(poly, CONST.COLORS["grey"], CONST.COLORS["dark_dark_grey"])
def setSelectedUnit(self, selected_cp: QMapControlPoint):
self.state = QLiberationMapState.MOVING_UNIT
self.selected_cp = selected_cp
position = self._transform_point(selected_cp.control_point.position)
self.movement_line = QtWidgets.QGraphicsLineItem(QLineF(QPointF(*position), QPointF(*position)))
self.scene().addItem(self.movement_line)
def sceneMouseMovedEvent(self, event: QGraphicsSceneMouseEvent):
if self.state == QLiberationMapState.MOVING_UNIT:
self.setCursor(Qt.PointingHandCursor)
p1 = self.movement_line.line().p1()
self.movement_line.setLine(QLineF(p1, event.scenePos()))
def sceneMousePressEvent(self, event: QGraphicsSceneMouseEvent):
if self.state == QLiberationMapState.MOVING_UNIT:
if event.buttons() == Qt.RightButton:
pass
elif event.buttons() == Qt.LeftButton:
if self.selected_cp is not None:
# Set movement position for the cp
pos = event.scenePos()
point = Point(int(pos.x()), int(pos.y()))
self.selected_cp.control_point.target_position = point.x, point.y # TODO : convert to DCS coords !
GameUpdateSignal.get_instance().updateGame(self.game_model.game)
else:
return
self.state = QLiberationMapState.NORMAL
self.scene().removeItem(self.movement_line)
self.selected_cp = None

View File

@ -1,5 +1,4 @@
from PySide2.QtGui import QFont from PySide2.QtWidgets import QGraphicsScene, QGraphicsSceneMouseEvent
from PySide2.QtWidgets import QGraphicsScene
import qt_ui.uiconstants as CONST import qt_ui.uiconstants as CONST
@ -11,3 +10,9 @@ class QLiberationScene(QGraphicsScene):
item = self.addText("Go to \"File/New Game\" to setup a new campaign or go to \"File/Open\" to load an existing save game.", item = self.addText("Go to \"File/New Game\" to setup a new campaign or go to \"File/Open\" to load an existing save game.",
CONST.FONT_PRIMARY) CONST.FONT_PRIMARY)
item.setDefaultTextColor(CONST.COLORS["white"]) item.setDefaultTextColor(CONST.COLORS["white"])
def mouseMoveEvent(self, event: QGraphicsSceneMouseEvent):
self.parent().sceneMouseMovedEvent(event)
def mousePressEvent(self, event:QGraphicsSceneMouseEvent):
self.parent().sceneMousePressEvent(event)

View File

@ -26,6 +26,12 @@ class QMapControlPoint(QMapObject):
f"CHEAT: Capture {self.control_point.name}") f"CHEAT: Capture {self.control_point.name}")
self.capture_action.triggered.connect(self.cheat_capture) self.capture_action.triggered.connect(self.cheat_capture)
self.move_action = QAction("Move")
self.move_action.triggered.connect(self.move)
self.cancel_move_action = QAction("Cancel Move")
self.cancel_move_action.triggered.connect(self.cancel_move)
def paint(self, painter, option, widget=None) -> None: def paint(self, painter, option, widget=None) -> None:
if DisplayOptions.control_points: if DisplayOptions.control_points:
painter.save() painter.save()
@ -70,6 +76,12 @@ class QMapControlPoint(QMapObject):
self.base_details_dialog.show() self.base_details_dialog.show()
def add_context_menu_actions(self, menu: QMenu) -> None: def add_context_menu_actions(self, menu: QMenu) -> None:
if self.control_point.moveable and self.control_point.captured:
menu.addAction(self.move_action)
if self.control_point.target_position is not None:
menu.addAction(self.cancel_move_action)
if self.control_point.is_fleet: if self.control_point.is_fleet:
return return
@ -87,6 +99,13 @@ class QMapControlPoint(QMapObject):
self.game_model.game.initialize_turn() self.game_model.game.initialize_turn()
GameUpdateSignal.get_instance().updateGame(self.game_model.game) GameUpdateSignal.get_instance().updateGame(self.game_model.game)
def move(self):
self.parent.setSelectedUnit(self)
def cancel_move(self):
self.control_point.target_position = None
GameUpdateSignal.get_instance().updateGame(self.game_model.game)
def open_new_package_dialog(self) -> None: def open_new_package_dialog(self) -> None:
"""Extends the default packagedialog to redirect to base menu for red air base.""" """Extends the default packagedialog to redirect to base menu for red air base."""
if not self.control_point.captured: if not self.control_point.captured: