Remove the old map.

This commit is contained in:
Dan Albert
2021-05-30 19:45:50 -07:00
parent acd3e87996
commit 30f6220c3e
15 changed files with 16 additions and 2286 deletions

View File

@@ -1,117 +0,0 @@
"""Common base for objects drawn on the game map."""
from typing import Optional
from PySide2.QtCore import Qt
from PySide2.QtGui import QPen
from PySide2.QtWidgets import (
QAction,
QGraphicsLineItem,
QGraphicsSceneContextMenuEvent,
QGraphicsSceneHoverEvent,
QGraphicsSceneMouseEvent,
QMenu,
)
import qt_ui.uiconstants as const
from game.theater import FrontLine
from qt_ui.dialogs import Dialog
from qt_ui.models import GameModel
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
from qt_ui.windows.mission.QPackageDialog import QNewPackageDialog
class QFrontLine(QGraphicsLineItem):
"""Base class for objects drawn on the game map.
Game map objects have an on_click behavior that triggers on left click, and
change the mouse cursor on hover.
"""
def __init__(
self,
x1: float,
y1: float,
x2: float,
y2: float,
mission_target: FrontLine,
game_model: GameModel,
) -> None:
super().__init__(x1, y1, x2, y2)
self.mission_target = mission_target
self.game_model = game_model
self.new_package_dialog: Optional[QNewPackageDialog] = None
self.setAcceptHoverEvents(True)
pen = QPen(brush=const.COLORS["bright_red"])
pen.setColor(const.COLORS["orange"])
pen.setWidth(8)
self.setPen(pen)
def hoverEnterEvent(self, event: QGraphicsSceneHoverEvent):
self.setCursor(Qt.PointingHandCursor)
def mousePressEvent(self, event: QGraphicsSceneMouseEvent):
if event.button() == Qt.LeftButton:
self.on_click()
def contextMenuEvent(self, event: QGraphicsSceneContextMenuEvent) -> None:
menu = QMenu("Menu")
object_details_action = QAction(self.object_dialog_text)
object_details_action.triggered.connect(self.on_click)
menu.addAction(object_details_action)
new_package_action = QAction(f"New package")
new_package_action.triggered.connect(self.open_new_package_dialog)
menu.addAction(new_package_action)
if self.game_model.game.settings.enable_frontline_cheats:
cheat_forward = QAction(f"CHEAT: Advance Frontline")
cheat_forward.triggered.connect(self.cheat_forward)
menu.addAction(cheat_forward)
cheat_backward = QAction(f"CHEAT: Retreat Frontline")
cheat_backward.triggered.connect(self.cheat_backward)
menu.addAction(cheat_backward)
menu.exec_(event.screenPos())
@property
def object_dialog_text(self) -> str:
"""Text to for the object's dialog in the context menu.
Right clicking a map object will open a context menu and the first item
will open the details dialog for this object. This menu action has the
same behavior as the on_click event.
Return:
The text that should be displayed for the menu item.
"""
return "Details"
def on_click(self) -> None:
"""The action to take when this map object is left-clicked.
Typically this should open a details view of the object.
"""
raise NotImplementedError
def open_new_package_dialog(self) -> None:
"""Opens the dialog for planning a new mission package."""
Dialog.open_new_package_dialog(self.mission_target)
def cheat_forward(self) -> None:
self.mission_target.blue_cp.base.affect_strength(0.1)
self.mission_target.red_cp.base.affect_strength(-0.1)
# Clear the ATO to replan missions affected by the front line.
self.game_model.game.reset_ato()
self.game_model.game.initialize_turn()
GameUpdateSignal.get_instance().updateGame(self.game_model.game)
def cheat_backward(self) -> None:
self.mission_target.blue_cp.base.affect_strength(-0.1)
self.mission_target.red_cp.base.affect_strength(0.1)
# Clear the ATO to replan missions affected by the front line.
self.game_model.game.reset_ato()
self.game_model.game.initialize_turn()
GameUpdateSignal.get_instance().updateGame(self.game_model.game)

File diff suppressed because it is too large Load Diff

View File

@@ -1,21 +0,0 @@
from PySide2.QtWidgets import QGraphicsScene, QGraphicsSceneMouseEvent
import qt_ui.uiconstants as CONST
class QLiberationScene(QGraphicsScene):
def __init__(self, parent):
super().__init__(parent)
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,
)
item.setDefaultTextColor(CONST.COLORS["white"])
def mouseMoveEvent(self, event: QGraphicsSceneMouseEvent):
super(QLiberationScene, self).mouseMoveEvent(event)
self.parent().sceneMouseMovedEvent(event)
def mousePressEvent(self, event: QGraphicsSceneMouseEvent):
super(QLiberationScene, self).mousePressEvent(event)
self.parent().sceneMousePressEvent(event)

View File

@@ -1,125 +0,0 @@
from typing import Optional
from PySide2.QtGui import QColor, QPainter
from PySide2.QtWidgets import QAction, QMenu
import qt_ui.uiconstants as const
from game.theater import ControlPoint, NavalControlPoint
from qt_ui.models import GameModel
from qt_ui.windows.basemenu.QBaseMenu2 import QBaseMenu2
from .QMapObject import QMapObject
from ...displayoptions import DisplayOptions
from ...windows.GameUpdateSignal import GameUpdateSignal
class QMapControlPoint(QMapObject):
def __init__(
self,
parent,
x: float,
y: float,
w: float,
h: float,
control_point: ControlPoint,
game_model: GameModel,
) -> None:
super().__init__(x, y, w, h, mission_target=control_point)
self.game_model = game_model
self.control_point = control_point
self.parent = parent
self.setZValue(1)
self.setToolTip(self.control_point.name)
self.base_details_dialog: Optional[QBaseMenu2] = None
self.capture_action = QAction(f"CHEAT: Capture {self.control_point.name}")
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:
if DisplayOptions.control_points:
painter.save()
painter.setRenderHint(QPainter.Antialiasing)
painter.setBrush(self.brush_color)
painter.setPen(self.pen_color)
if not self.control_point.runway_is_operational():
painter.setBrush(const.COLORS["black"])
painter.setPen(self.brush_color)
r = option.rect
painter.drawEllipse(r.x(), r.y(), r.width(), r.height())
# TODO: Draw sunk carriers differently.
# Either don't draw them at all, or perhaps use a sunk ship icon.
painter.restore()
@property
def brush_color(self) -> QColor:
if self.control_point.captured:
return const.COLORS["blue"]
else:
return const.COLORS["super_red"]
@property
def pen_color(self) -> QColor:
return const.COLORS["white"]
@property
def object_dialog_text(self) -> str:
if self.control_point.captured:
return "Open base menu"
else:
return "Open intel menu"
def on_click(self) -> None:
self.base_details_dialog = QBaseMenu2(
self.window(), self.control_point, self.game_model
)
self.base_details_dialog.show()
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:
return
if self.control_point.captured:
return
for connected in self.control_point.connected_points:
if (
connected.captured
and self.game_model.game.settings.enable_base_capture_cheat
):
menu.addAction(self.capture_action)
break
def cheat_capture(self) -> None:
self.control_point.capture(self.game_model.game, for_player=True)
# Reinitialized ground planners and the like. The ATO needs to be reset because
# missions planned against the flipped base are no longer valid.
self.game_model.game.reset_ato()
self.game_model.game.initialize_turn()
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:
"""Extends the default packagedialog to redirect to base menu for red air base."""
is_navy = isinstance(self.control_point, NavalControlPoint)
if self.control_point.captured or is_navy:
super().open_new_package_dialog()
return
self.on_click()

View File

@@ -1,167 +0,0 @@
from typing import List, Optional
from PySide2.QtCore import QRect
from PySide2.QtGui import QBrush
from PySide2.QtWidgets import QGraphicsItem
import qt_ui.uiconstants as const
from game import Game
from game.data.building_data import FORTIFICATION_BUILDINGS
from game.db import REWARDS
from game.theater import ControlPoint, TheaterGroundObject
from game.theater.theatergroundobject import (
MissileSiteGroundObject,
CoastalSiteGroundObject,
)
from qt_ui.windows.groundobject.QGroundObjectMenu import QGroundObjectMenu
from .QMapObject import QMapObject
from ...displayoptions import DisplayOptions
class QMapGroundObject(QMapObject):
def __init__(
self,
parent,
x: float,
y: float,
w: float,
h: float,
control_point: ControlPoint,
ground_object: TheaterGroundObject,
game: Game,
buildings: Optional[List[TheaterGroundObject]] = None,
) -> None:
super().__init__(x, y, w, h, mission_target=ground_object)
self.ground_object = ground_object
self.control_point = control_point
self.parent = parent
self.game = game
self.setZValue(2)
self.buildings = buildings if buildings is not None else []
self.setFlag(QGraphicsItem.ItemIgnoresTransformations, False)
self.ground_object_dialog: Optional[QGroundObjectMenu] = None
self.setToolTip(self.tooltip)
@property
def tooltip(self) -> str:
lines = [
f"[{self.ground_object.obj_name}]",
f"${self.production_per_turn} per turn",
]
if self.ground_object.groups:
units = {}
for g in self.ground_object.groups:
for u in g.units:
if u.type in units:
units[u.type] = units[u.type] + 1
else:
units[u.type] = 1
for unit in units.keys():
lines.append(f"{unit} x {units[unit]}")
else:
for building in self.buildings:
if not building.is_dead:
lines.append(f"{building.dcs_identifier}")
return "\n".join(lines)
@property
def production_per_turn(self) -> int:
production = 0
for building in self.buildings:
if building.is_dead:
continue
if building.category in REWARDS.keys():
production += REWARDS[building.category]
return production
def paint(self, painter, option, widget=None) -> None:
player_icons = "_blue"
enemy_icons = ""
if DisplayOptions.ground_objects:
painter.save()
cat = self.ground_object.category
rect = QRect(
option.rect.x() + 2,
option.rect.y(),
option.rect.width() - 2,
option.rect.height(),
)
is_dead = self.ground_object.is_dead
for building in self.buildings:
if not building.is_dead:
is_dead = False
break
if cat == "aa":
has_threat = False
for group in self.ground_object.groups:
if self.ground_object.threat_range(group).distance_in_meters > 0:
has_threat = True
if not is_dead and not self.control_point.captured:
if cat == "aa" and not has_threat:
painter.drawPixmap(rect, const.ICONS["nothreat" + enemy_icons])
else:
painter.drawPixmap(rect, const.ICONS[cat + enemy_icons])
elif not is_dead:
if cat == "aa" and not has_threat:
painter.drawPixmap(rect, const.ICONS["nothreat" + player_icons])
else:
painter.drawPixmap(rect, const.ICONS[cat + player_icons])
else:
painter.drawPixmap(rect, const.ICONS["destroyed"])
self.draw_health_gauge(painter, option)
painter.restore()
def draw_health_gauge(self, painter, option) -> None:
units_alive = 0
units_dead = 0
if len(self.ground_object.groups) == 0:
for building in self.buildings:
if building.dcs_identifier in FORTIFICATION_BUILDINGS:
continue
if building.is_dead:
units_dead += 1
else:
units_alive += 1
for g in self.ground_object.groups:
units_alive += len(g.units)
if hasattr(g, "units_losts"):
units_dead += len(g.units_losts)
if units_dead + units_alive > 0:
ratio = float(units_alive) / (float(units_dead) + float(units_alive))
bar_height = ratio * option.rect.height()
painter.fillRect(
option.rect.x(),
option.rect.y(),
2,
option.rect.height(),
QBrush(const.COLORS["dark_red"]),
)
painter.fillRect(
option.rect.x(),
option.rect.y(),
2,
bar_height,
QBrush(const.COLORS["green"]),
)
def on_click(self) -> None:
self.ground_object_dialog = QGroundObjectMenu(
self.window(),
self.ground_object,
self.buildings,
self.control_point,
self.game,
)
self.ground_object_dialog.show()

View File

@@ -1,84 +0,0 @@
"""Common base for objects drawn on the game map."""
from typing import Optional
from PySide2.QtCore import Qt
from PySide2.QtWidgets import (
QAction,
QGraphicsRectItem,
QGraphicsSceneContextMenuEvent,
QGraphicsSceneHoverEvent,
QGraphicsSceneMouseEvent,
QMenu,
)
from qt_ui.dialogs import Dialog
from qt_ui.windows.mission.QPackageDialog import QNewPackageDialog
from game.theater.missiontarget import MissionTarget
class QMapObject(QGraphicsRectItem):
"""Base class for objects drawn on the game map.
Game map objects have an on_click behavior that triggers on left click, and
change the mouse cursor on hover.
"""
def __init__(
self, x: float, y: float, w: float, h: float, mission_target: MissionTarget
) -> None:
super().__init__(x, y, w, h)
self.mission_target = mission_target
self.new_package_dialog: Optional[QNewPackageDialog] = None
self.setAcceptHoverEvents(True)
def hoverEnterEvent(self, event: QGraphicsSceneHoverEvent):
self.setCursor(Qt.PointingHandCursor)
def mousePressEvent(self, event: QGraphicsSceneMouseEvent):
if event.button() == Qt.LeftButton:
self.on_click()
def add_context_menu_actions(self, menu: QMenu) -> None:
pass
def contextMenuEvent(self, event: QGraphicsSceneContextMenuEvent) -> None:
menu = QMenu("Menu", self.parent)
object_details_action = QAction(self.object_dialog_text)
object_details_action.triggered.connect(self.on_click)
menu.addAction(object_details_action)
# Not all locations have valid objectives. Off-map spawns, for example,
# have no mission types.
if list(self.mission_target.mission_types(for_player=True)):
new_package_action = QAction(f"New package")
new_package_action.triggered.connect(self.open_new_package_dialog)
menu.addAction(new_package_action)
self.add_context_menu_actions(menu)
menu.exec_(event.screenPos())
@property
def object_dialog_text(self) -> str:
"""Text to for the object's dialog in the context menu.
Right clicking a map object will open a context menu and the first item
will open the details dialog for this object. This menu action has the
same behavior as the on_click event.
Return:
The text that should be displayed for the menu item.
"""
return "Details"
def on_click(self) -> None:
"""The action to take when this map object is left-clicked.
Typically this should open a details view of the object.
"""
raise NotImplementedError
def open_new_package_dialog(self) -> None:
"""Opens the dialog for planning a new mission package."""
Dialog.open_new_package_dialog(self.mission_target)

View File

@@ -1,70 +0,0 @@
from typing import List, Optional
from PySide2.QtCore import Qt
from PySide2.QtGui import QColor, QPen
from PySide2.QtWidgets import (
QGraphicsItem,
QGraphicsLineItem,
)
from game.theater import ControlPoint
from game.transfers import CargoShip
from qt_ui.uiconstants import COLORS
class ShippingLaneSegment(QGraphicsLineItem):
def __init__(
self,
x0: float,
y0: float,
x1: float,
y1: float,
control_point_a: ControlPoint,
control_point_b: ControlPoint,
ships: List[CargoShip],
parent: Optional[QGraphicsItem] = None,
) -> None:
super().__init__(x0, y0, x1, y1, parent)
self.control_point_a = control_point_a
self.control_point_b = control_point_b
self.ships = ships
self.setPen(self.make_pen())
self.setToolTip(self.make_tooltip())
self.setAcceptHoverEvents(True)
@property
def has_ships(self) -> bool:
return bool(self.ships)
def make_tooltip(self) -> str:
if not self.has_ships:
return "No ships present in this shipping lane."
ships = []
for ship in self.ships:
units = "units" if ship.size > 1 else "unit"
ships.append(
f"{ship.size} {units} transferring from {ship.origin} to "
f"{ship.destination}."
)
return "\n".join(ships)
@property
def line_color(self) -> QColor:
if self.control_point_a.captured:
return COLORS["dark_blue"]
else:
return COLORS["dark_red"]
@property
def line_style(self) -> Qt.PenStyle:
if self.has_ships:
return Qt.PenStyle.SolidLine
return Qt.PenStyle.DotLine
def make_pen(self) -> QPen:
pen = QPen(brush=self.line_color)
pen.setColor(self.line_color)
pen.setStyle(self.line_style)
pen.setWidth(2)
return pen

View File

@@ -1,76 +0,0 @@
from functools import cached_property
from typing import List, Optional
from PySide2.QtCore import Qt
from PySide2.QtGui import QColor, QPen
from PySide2.QtWidgets import (
QGraphicsItem,
QGraphicsLineItem,
)
from game.theater import ControlPoint
from game.transfers import Convoy
from qt_ui.uiconstants import COLORS
class SupplyRouteSegment(QGraphicsLineItem):
def __init__(
self,
x0: float,
y0: float,
x1: float,
y1: float,
control_point_a: ControlPoint,
control_point_b: ControlPoint,
convoys: List[Convoy],
parent: Optional[QGraphicsItem] = None,
) -> None:
super().__init__(x0, y0, x1, y1, parent)
self.control_point_a = control_point_a
self.control_point_b = control_point_b
self.convoys = convoys
self.setPen(self.make_pen())
self.setToolTip(self.make_tooltip())
self.setAcceptHoverEvents(True)
@property
def has_convoys(self) -> bool:
return bool(self.convoys)
def make_tooltip(self) -> str:
if not self.has_convoys:
return "No convoys present on this supply route."
convoys = []
for convoy in self.convoys:
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
def line_color(self) -> QColor:
if self.control_point_a.front_is_active(self.control_point_b):
return COLORS["red"]
elif self.control_point_a.captured:
return COLORS["dark_blue"]
else:
return COLORS["dark_red"]
@property
def line_style(self) -> Qt.PenStyle:
if (
self.control_point_a.front_is_active(self.control_point_b)
or self.has_convoys
):
return Qt.PenStyle.SolidLine
return Qt.PenStyle.DotLine
def make_pen(self) -> QPen:
pen = QPen(brush=self.line_color)
pen.setColor(self.line_color)
pen.setStyle(self.line_style)
pen.setWidth(6)
return pen

View File

@@ -36,6 +36,8 @@ from qt_ui.windows.groundobject.QGroundObjectMenu import QGroundObjectMenu
LeafletLatLon = list[float]
LeafletPoly = list[LeafletLatLon]
MAX_SHIP_DISTANCE = nautical_miles(80)
# **EVERY PROPERTY NEEDS A NOTIFY SIGNAL**
#
# https://bugreports.qt.io/browse/PYSIDE-1426