mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
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:
parent
b53cac4c7a
commit
1d76ee4871
23
game/game.py
23
game/game.py
@ -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
64
game/income.py
Normal 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)
|
||||
@ -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]
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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
44
qt_ui/windows/intel.py
Normal 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))
|
||||
Loading…
x
Reference in New Issue
Block a user