diff --git a/changelog.md b/changelog.md
index 7c501e91..57427840 100644
--- a/changelog.md
+++ b/changelog.md
@@ -15,6 +15,7 @@
* **[Factions]** Germany 1944, added Stug III and Stug IV
* **[Factions]** Added factions Insurgents (Hard) with better and more weapons
* **[Plugins]** [The EWRS plugin](https://github.com/Bob7heBuilder/EWRS) is now included.
+* **[UI]** Added enemy intelligence summary and details window.
## Fixes:
* **[Factions]** AI would never buy artillery units for the frontline - fixed
diff --git a/qt_ui/widgets/QIntelBox.py b/qt_ui/widgets/QIntelBox.py
index 639e0afa..3925baf3 100644
--- a/qt_ui/widgets/QIntelBox.py
+++ b/qt_ui/widgets/QIntelBox.py
@@ -1,32 +1,42 @@
from typing import Optional
from PySide2.QtWidgets import (
+ QGridLayout,
QGroupBox,
QHBoxLayout,
QLabel,
QPushButton,
- QVBoxLayout,
)
from game import Game
+from game.income import Income
from qt_ui.windows.intel import IntelWindow
class QIntelBox(QGroupBox):
def __init__(self, game: Game) -> None:
super().__init__("Intel")
+ self.setProperty("style", "IntelSummary")
+
self.game = game
columns = QHBoxLayout()
self.setLayout(columns)
- summary = QVBoxLayout()
+ summary = QGridLayout()
columns.addLayout(summary)
- self.total_aircraft = QLabel()
- summary.addWidget(self.total_aircraft)
- self.total_ground_forces = QLabel()
- summary.addWidget(self.total_ground_forces)
+ summary.addWidget(QLabel("Air superiority:"), 0, 0)
+ self.air_strength = QLabel()
+ summary.addWidget(self.air_strength, 0, 1)
+
+ summary.addWidget(QLabel("Front line:"), 1, 0)
+ self.ground_strength = QLabel()
+ summary.addWidget(self.ground_strength, 1, 1)
+
+ summary.addWidget(QLabel("Economic strength:"), 2, 0)
+ self.economic_strength = QLabel()
+ summary.addWidget(self.economic_strength, 2, 1)
details = QPushButton("Details")
columns.addWidget(details)
@@ -40,17 +50,57 @@ class QIntelBox(QGroupBox):
self.game = game
self.update_summary()
+ @staticmethod
+ def forces_strength_text(own: int, enemy: int) -> str:
+ if not enemy:
+ return "enemy eliminated"
+
+ ratio = own / enemy
+ if ratio < 0.6:
+ return "outnumbered"
+ if ratio < 0.8:
+ return "slightly outnumbered"
+ if ratio < 1.2:
+ return "evenly matched"
+ if ratio < 1.4:
+ return "slight advantage"
+ return "strong advantage"
+
+ def economic_strength_text(self) -> str:
+ assert self.game is not None
+ own = Income(self.game, player=True).total
+ enemy = Income(self.game, player=False).total
+
+ if not enemy:
+ return "enemy economy ruined"
+
+ ratio = own / enemy
+ if ratio < 0.6:
+ return "strong disadvantage"
+ if ratio < 0.8:
+ return "slight disadvantage"
+ if ratio < 1.2:
+ return "evenly matched"
+ if ratio < 1.4:
+ return "slight advantage"
+ return "strong advantage"
+
def update_summary(self) -> None:
if self.game is None:
- aircraft = 0
- ground_units = 0
- else:
- data = self.game.game_stats.data_per_turn[-1]
- aircraft = data.enemy_units.aircraft_count
- ground_units = data.enemy_units.vehicles_count
- self.total_aircraft.setText(f"Total enemy aircraft: {aircraft}")
- self.total_ground_forces.setText(
- f"Total enemy ground units: {ground_units}")
+ self.air_strength.setText("no data")
+ self.ground_strength.setText("no data")
+ self.economic_strength.setText("no data")
+ return
+
+ data = self.game.game_stats.data_per_turn[-1]
+
+ self.air_strength.setText(self.forces_strength_text(
+ data.allied_units.aircraft_count,
+ data.enemy_units.aircraft_count))
+ self.ground_strength.setText(self.forces_strength_text(
+ data.allied_units.vehicles_count,
+ data.enemy_units.vehicles_count))
+ self.economic_strength.setText(self.economic_strength_text())
def open_details_window(self) -> None:
self.details_window = IntelWindow(self.game)
diff --git a/qt_ui/windows/intel.py b/qt_ui/windows/intel.py
index e104af44..497d65fb 100644
--- a/qt_ui/windows/intel.py
+++ b/qt_ui/windows/intel.py
@@ -1,7 +1,15 @@
+import itertools
+
from PySide2.QtWidgets import (
QDialog,
- QGroupBox,
+ QFrame,
+ QGridLayout,
+ QLabel,
+ QLayout,
QScrollArea,
+ QSizePolicy,
+ QSpacerItem,
+ QTabWidget,
QVBoxLayout,
QWidget,
)
@@ -11,22 +19,115 @@ from qt_ui.uiconstants import ICONS
from qt_ui.windows.finances.QFinancesMenu import FinancesLayout
-class EconomyIntelBox(QGroupBox):
- def __init__(self, game: Game) -> None:
- super().__init__("Economy")
+class ScrollingFrame(QFrame):
+ def __init__(self) -> None:
+ super().__init__()
widget = QWidget()
scroll_area = QScrollArea()
scroll_area.setWidgetResizable(True)
scroll_area.setWidget(widget)
- scrolling_layout = QVBoxLayout()
- widget.setLayout(scrolling_layout)
+ self.scrolling_layout = QVBoxLayout()
+ widget.setLayout(self.scrolling_layout)
self.setLayout(QVBoxLayout())
self.layout().addWidget(scroll_area)
- scrolling_layout.addLayout(FinancesLayout(game, player=False))
+ def addWidget(self, widget: QWidget, *args, **kwargs) -> None:
+ self.scrolling_layout.addWidget(widget, *args, **kwargs)
+
+ def addLayout(self, layout: QLayout, *args, **kwargs) -> None:
+ self.scrolling_layout.addLayout(layout, *args, **kwargs)
+
+
+class EconomyIntelTab(ScrollingFrame):
+ def __init__(self, game: Game) -> None:
+ super().__init__()
+ self.addLayout(FinancesLayout(game, player=False))
+
+
+class IntelTableLayout(QGridLayout):
+ def __init__(self) -> None:
+ super().__init__()
+ self.row = itertools.count(0)
+
+ def add_header(self, text: str) -> None:
+ self.addWidget(QLabel(f"{text}"), next(self.row), 0)
+
+ def add_spacer(self) -> None:
+ self.addItem(
+ QSpacerItem(0, 0, QSizePolicy.Preferred, QSizePolicy.Expanding),
+ next(self.row), 0)
+
+ def add_row(self, text: str, count: int) -> None:
+ row = next(self.row)
+ self.addWidget(QLabel(text), row, 0)
+ self.addWidget(QLabel(str(count)), row, 1)
+
+
+class AircraftIntelLayout(IntelTableLayout):
+ def __init__(self, game: Game, player: bool) -> None:
+ super().__init__()
+
+ total = 0
+ for control_point in game.theater.control_points_for(player):
+ base = control_point.base
+ total += base.total_aircraft
+ if not base.total_aircraft:
+ continue
+
+ self.add_header(control_point.name)
+ for airframe, count in base.aircraft.items():
+ if not count:
+ continue
+ self.add_row(airframe.id, count)
+
+ self.add_spacer()
+ self.add_row("Total", total)
+
+
+class AircraftIntelTab(ScrollingFrame):
+ def __init__(self, game: Game) -> None:
+ super().__init__()
+ self.addLayout(AircraftIntelLayout(game, player=False))
+
+
+class ArmyIntelLayout(IntelTableLayout):
+ def __init__(self, game: Game, player: bool) -> None:
+ super().__init__()
+
+ total = 0
+ for control_point in game.theater.control_points_for(player):
+ base = control_point.base
+ total += base.total_armor
+ if not base.total_armor:
+ continue
+
+ self.add_header(control_point.name)
+ for vehicle, count in base.armor.items():
+ if not count:
+ continue
+ self.add_row(vehicle.id, count)
+
+ self.add_spacer()
+ self.add_row("Total", total)
+
+
+class ArmyIntelTab(ScrollingFrame):
+ def __init__(self, game: Game) -> None:
+ super().__init__()
+ self.addLayout(ArmyIntelLayout(game, player=False))
+
+
+class IntelTabs(QTabWidget):
+
+ def __init__(self, game: Game):
+ super().__init__()
+
+ self.addTab(EconomyIntelTab(game), "Economy")
+ self.addTab(AircraftIntelTab(game), "Air forces")
+ self.addTab(ArmyIntelTab(game), "Ground forces")
class IntelWindow(QDialog):
@@ -38,9 +139,9 @@ class IntelWindow(QDialog):
self.setModal(True)
self.setWindowTitle("Intelligence")
self.setWindowIcon(ICONS["Statistics"])
- self.setMinimumSize(800, 600)
+ self.setMinimumSize(600, 500)
layout = QVBoxLayout()
self.setLayout(layout)
- layout.addWidget(EconomyIntelBox(game), stretch=1)
+ layout.addWidget(IntelTabs(game), stretch=1)
diff --git a/resources/stylesheets/style-dcs.css b/resources/stylesheets/style-dcs.css
index 5cf07d77..f8539e83 100644
--- a/resources/stylesheets/style-dcs.css
+++ b/resources/stylesheets/style-dcs.css
@@ -546,7 +546,7 @@ QGroupBox[style="QWeatherWidget"] {
padding: 0px;
margin-left: 0px;
margin-right: 5px;
- margin-top: 1ex;
+ margin-top: 1px;
margin-bottom: 5px;
}
@@ -555,4 +555,22 @@ QGroupBox[style="QWeatherWidget"] QLabel[style="text-sm"] {
margin: 0px;
font-size: 9px;
line-height: 9px;
+}
+
+QGroupBox[style="IntelSummary"] {
+ padding-left: 40px;
+ padding-right: 0px;
+ padding-top: 0px;
+ padding-bottom: 0px;
+ margin-left: 0px;
+ margin-right: 5px;
+ margin-top: 1px;
+ margin-bottom: 5px;
+}
+
+QGroupBox[style="IntelSummary"] QLabel {
+ padding: 0px;
+ margin: 0px;
+ font-size: 9px;
+ line-height: 9px;
}
\ No newline at end of file