Add basic intel window.

Currently only shows the enemy's economic information.

https://github.com/Khopa/dcs_liberation/issues/658
This commit is contained in:
Dan Albert 2020-12-25 03:19:20 -08:00
parent b53cac4c7a
commit 1d76ee4871
7 changed files with 198 additions and 78 deletions

View File

@ -4,7 +4,7 @@ import random
import sys
from datetime import date, datetime, timedelta
from enum import Enum
from typing import Any, Dict, List
from typing import Any, Dict, Iterator, List, Tuple
from dcs.action import Coalition
from dcs.mapping import Point
@ -27,6 +27,7 @@ from .debriefing import Debriefing
from .event.event import Event, UnitsDeliveryEvent
from .event.frontlineattack import FrontlineAttackEvent
from .factions.faction import Faction
from .income import Income
from .infos.information import Information
from .navmesh import NavMesh
from .procurement import ProcurementAi
@ -189,30 +190,14 @@ class Game:
front_line.control_point_a,
front_line.control_point_b)
@property
def budget_reward_amount(self) -> int:
reward = PLAYER_BUDGET_BASE * len(self.theater.player_points())
for cp in self.theater.player_points():
for g in cp.ground_objects:
if g.category in REWARDS.keys() and not g.is_dead:
reward += REWARDS[g.category]
return int(reward * self.settings.player_income_multiplier)
def process_player_income(self):
self.budget += self.budget_reward_amount
self.budget += Income(self, player=True).total
def process_enemy_income(self):
# TODO: Clean up save compat.
if not hasattr(self, "enemy_budget"):
self.enemy_budget = 0
production = 0.0
for enemy_point in self.theater.enemy_points():
for g in enemy_point.ground_objects:
if g.category in REWARDS.keys() and not g.is_dead:
production = production + REWARDS[g.category]
self.enemy_budget += production * self.settings.enemy_income_multiplier
self.enemy_budget += Income(self, player=False).total
def units_delivery_event(self, to_cp: ControlPoint) -> UnitsDeliveryEvent:
event = UnitsDeliveryEvent(attacker_name=self.player_name,

64
game/income.py Normal file
View File

@ -0,0 +1,64 @@
from __future__ import annotations
from dataclasses import dataclass
from typing import TYPE_CHECKING
from game.db import PLAYER_BUDGET_BASE, REWARDS
from game.theater import ControlPoint
if TYPE_CHECKING:
from game import Game
@dataclass(frozen=True)
class BuildingIncome:
name: str
category: str
number: int
income_per_building: int
@property
def income(self) -> int:
return self.number * self.income_per_building
@dataclass(frozen=True)
class ControlPointIncome:
control_point: ControlPoint
income: int
class Income:
def __init__(self, game: Game, player: bool) -> None:
if player:
self.multiplier = game.settings.player_income_multiplier
else:
self.multiplier = game.settings.enemy_income_multiplier
self.control_points = []
self.buildings = []
self.income_per_base = PLAYER_BUDGET_BASE if player else 0
names = set()
for cp in game.theater.control_points_for(player):
self.control_points.append(
ControlPointIncome(cp, self.income_per_base))
for tgo in cp.ground_objects:
names.add(tgo.obj_name)
for name in names:
count = 0
tgos = game.theater.find_ground_objects_by_obj_name(name)
category = tgos[0].category
if category not in REWARDS:
continue
for tgo in tgos:
if not tgo.is_dead:
count += 1
self.buildings.append(BuildingIncome(name, category, count,
REWARDS[category]))
self.from_bases = sum(cp.income for cp in self.control_points)
self.total_buildings = sum(b.income for b in self.buildings)
self.total = ((self.total_buildings + self.from_bases) *
self.multiplier)

View File

@ -502,8 +502,13 @@ class ConflictTheater:
)
return new_point
def control_points_for(self, player: bool) -> Iterator[ControlPoint]:
for point in self.controlpoints:
if point.captured == player:
yield point
def player_points(self) -> List[ControlPoint]:
return [point for point in self.controlpoints if point.captured]
return list(self.control_points_for(player=True))
def conflicts(self, from_player=True) -> Iterator[FrontLine]:
for cp in [x for x in self.controlpoints if x.captured == from_player]:
@ -511,7 +516,7 @@ class ConflictTheater:
yield FrontLine(cp, connected_point, self)
def enemy_points(self) -> List[ControlPoint]:
return [point for point in self.controlpoints if not point.captured]
return list(self.control_points_for(player=False))
def closest_control_point(self, point: Point) -> ControlPoint:
closest = self.controlpoints[0]

View File

@ -1,6 +1,7 @@
from PySide2.QtWidgets import QLabel, QHBoxLayout, QGroupBox, QPushButton
import qt_ui.uiconstants as CONST
from game.income import Income
from qt_ui.windows.finances.QFinancesMenu import QFinancesMenu
@ -41,7 +42,7 @@ class QBudgetBox(QGroupBox):
return
self.game = game
self.setBudget(self.game.budget, self.game.budget_reward_amount)
self.setBudget(self.game.budget, Income(self.game, player=True).total)
self.finances.setEnabled(True)
def openFinances(self):

View File

@ -1,8 +1,15 @@
from typing import Optional
from PySide2.QtWidgets import QGroupBox, QHBoxLayout, QLabel, QVBoxLayout
from PySide2.QtWidgets import (
QGroupBox,
QHBoxLayout,
QLabel,
QPushButton,
QVBoxLayout,
)
from game import Game
from qt_ui.windows.intel import IntelWindow
class QIntelBox(QGroupBox):
@ -21,8 +28,14 @@ class QIntelBox(QGroupBox):
self.total_ground_forces = QLabel()
summary.addWidget(self.total_ground_forces)
details = QPushButton("Details")
columns.addWidget(details)
details.clicked.connect(self.open_details_window)
self.update_summary()
self.details_window: Optional[IntelWindow] = None
def set_game(self, game: Optional[Game]) -> None:
self.game = game
self.update_summary()
@ -38,3 +51,7 @@ class QIntelBox(QGroupBox):
self.total_aircraft.setText(f"Total enemy aircraft: {aircraft}")
self.total_ground_forces.setText(
f"Total enemy ground units: {ground_units}")
def open_details_window(self) -> None:
self.details_window = IntelWindow(self.game)
self.details_window.show()

View File

@ -1,19 +1,68 @@
from PySide2.QtWidgets import QDialog, QGridLayout, QLabel, QFrame, QSizePolicy
from PySide2.QtWidgets import (
QDialog,
QFrame,
QGridLayout,
QLabel,
QSizePolicy,
)
import qt_ui.uiconstants as CONST
from game.db import REWARDS, PLAYER_BUDGET_BASE
from game.game import Game
from game.income import Income
class QHorizontalSeparationLine(QFrame):
def __init__(self):
super().__init__()
self.setMinimumWidth(1)
self.setFixedHeight(20)
self.setFrameShape(QFrame.HLine)
self.setFrameShadow(QFrame.Sunken)
self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum)
def __init__(self):
super().__init__()
self.setMinimumWidth(1)
self.setFixedHeight(20)
self.setFrameShape(QFrame.HLine)
self.setFrameShadow(QFrame.Sunken)
self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum)
class FinancesLayout(QGridLayout):
def __init__(self, game: Game, player: bool) -> None:
super().__init__()
income = Income(game, player)
self.addWidget(QLabel("<b>Control Points</b>"), 0, 0)
self.addWidget(QLabel(
f"{len(income.control_points)} bases x {income.income_per_base}M"),
0, 1)
self.addWidget(QLabel(f"{income.from_bases}M"), 0, 2)
self.addWidget(QHorizontalSeparationLine(), 1, 0, 1, 3)
buildings = reversed(sorted(income.buildings, key=lambda b: b.income))
row = 2
for row, building in enumerate(buildings, row):
self.addWidget(
QLabel(f"<b>{building.category.upper()} [{building.name}]</b>"),
row, 0)
self.addWidget(QLabel(
f"{building.number} buildings x {building.income_per_building}M"),
row, 1)
rlabel = QLabel(f"{building.income}M")
rlabel.setProperty("style", "green")
self.addWidget(rlabel, row, 2)
self.addWidget(QHorizontalSeparationLine(), row + 1, 0, 1, 3)
self.addWidget(QLabel(
f"Income multiplier: {income.multiplier:.1f}"),
row + 2, 1
)
self.addWidget(QLabel(f"<b>{income.total}M</b>"), row + 2, 2)
if player:
budget = game.budget
else:
budget = game.enemy_budget
self.addWidget(QLabel(f"Balance"), row + 3, 1)
self.addWidget(QLabel(f"<b>{budget}M</b>"), row + 3, 2)
class QFinancesMenu(QDialog):
@ -26,49 +75,4 @@ class QFinancesMenu(QDialog):
self.setWindowIcon(CONST.ICONS["Money"])
self.setMinimumSize(450, 200)
reward = PLAYER_BUDGET_BASE * len(self.game.theater.player_points())
layout = QGridLayout()
layout.addWidget(QLabel("<b>Control Points</b>"), 0, 0)
layout.addWidget(QLabel(str(len(self.game.theater.player_points())) + " bases x " + str(PLAYER_BUDGET_BASE) + "M"), 0, 1)
layout.addWidget(QLabel(str(reward) + "M"), 0, 2)
layout.addWidget(QHorizontalSeparationLine(), 1, 0, 1, 3)
i = 2
for cp in self.game.theater.player_points():
obj_names = []
[obj_names.append(ground_object.obj_name) for ground_object in cp.ground_objects if ground_object.obj_name not in obj_names]
for obj_name in obj_names:
reward = 0
g = None
cat = None
number = 0
for ground_object in cp.ground_objects:
if ground_object.obj_name != obj_name or ground_object.is_dead:
continue
else:
if g is None:
g = ground_object
cat = g.category
if cat in REWARDS.keys():
number = number + 1
reward += REWARDS[cat]
if g is not None and cat in REWARDS.keys():
layout.addWidget(QLabel("<b>" + g.category.upper() + " [" + obj_name + "]</b>"), i, 0)
layout.addWidget(QLabel(str(number) + " buildings x " + str(REWARDS[cat]) + "M"), i, 1)
rlabel = QLabel(str(reward) + "M")
rlabel.setProperty("style", "green")
layout.addWidget(rlabel, i, 2)
i = i + 1
self.setLayout(layout)
layout.addWidget(QHorizontalSeparationLine(), i + 1, 0, 1, 3)
layout.addWidget(QLabel(
f"Income multiplier: {game.settings.player_income_multiplier:.1f}"),
i + 2, 1
)
layout.addWidget(
QLabel("<b>" + str(self.game.budget_reward_amount) + "M </b>"),
i + 2, 2)
self.setLayout(FinancesLayout(game, player=True))

44
qt_ui/windows/intel.py Normal file
View File

@ -0,0 +1,44 @@
from PySide2.QtWidgets import (
QDialog,
QGroupBox,
QScrollArea, QVBoxLayout, QWidget,
)
from game.game import Game
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")
widget = QWidget()
scroll_area = QScrollArea()
scroll_area.setWidgetResizable(True)
scroll_area.setWidget(widget)
scrolling_layout = QVBoxLayout()
widget.setLayout(scrolling_layout)
self.setLayout(QVBoxLayout())
self.layout().addWidget(scroll_area)
scrolling_layout.addLayout(FinancesLayout(game, player=False))
class IntelWindow(QDialog):
def __init__(self, game: Game):
super().__init__()
self.game = game
self.setModal(True)
self.setWindowTitle("Intelligence")
self.setWindowIcon(ICONS["Statistics"])
self.setMinimumSize(600, 250)
layout = QVBoxLayout()
self.setLayout(layout)
layout.addWidget(EconomyIntelBox(game))