diff --git a/changelog.md b/changelog.md index 2e16299e..3db324c2 100644 --- a/changelog.md +++ b/changelog.md @@ -13,6 +13,8 @@ Saves from 2.3 are not compatible with 2.4. * **[Mission Generator]** Multiple groups are created for complex SAM sites (SAMs with additional point defense or SHORADS), improving Skynet behavior. * **[Skynet]** Point defenses are now configured to remain on to protect the site they accompany. * **[Balance]** Opfor now gains income using the same rules as the player, significantly increasing their income relative to the player for most campaigns. +* **[Economy]** FOBs generate only $10M per turn (previously $20M like airbases). +* **[Economy]** Carriers and off-map spawns generate no income (previously $20M like airbases). # 2.3.3 diff --git a/game/income.py b/game/income.py index a9cbecfc..d4e05993 100644 --- a/game/income.py +++ b/game/income.py @@ -4,7 +4,6 @@ from dataclasses import dataclass from typing import TYPE_CHECKING from game.db import REWARDS -from game.theater import ControlPoint if TYPE_CHECKING: from game import Game @@ -22,12 +21,6 @@ class BuildingIncome: 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: @@ -37,12 +30,10 @@ class Income: self.control_points = [] self.buildings = [] - self.income_per_base = 20 - names = set() for cp in game.theater.control_points_for(player): - self.control_points.append( - ControlPointIncome(cp, self.income_per_base)) + if cp.income_per_turn: + self.control_points.append(cp) for tgo in cp.ground_objects: names.add(tgo.obj_name) @@ -58,7 +49,7 @@ class Income: self.buildings.append(BuildingIncome(name, category, count, REWARDS[category])) - self.from_bases = sum(cp.income for cp in self.control_points) + self.from_bases = sum(cp.income_per_turn 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) diff --git a/game/theater/controlpoint.py b/game/theater/controlpoint.py index a22ea097..8904e9b0 100644 --- a/game/theater/controlpoint.py +++ b/game/theater/controlpoint.py @@ -478,6 +478,10 @@ class ControlPoint(MissionTarget, ABC): else: return 0 + @property + def income_per_turn(self) -> int: + return 0 + class Airfield(ControlPoint): @@ -542,6 +546,10 @@ class Airfield(ControlPoint): def can_deploy_ground_units(self) -> bool: return True + @property + def income_per_turn(self) -> int: + return 20 + class NavalControlPoint(ControlPoint, ABC): @@ -741,3 +749,7 @@ class Fob(ControlPoint): @property def can_deploy_ground_units(self) -> bool: return True + + @property + def income_per_turn(self) -> int: + return 10 diff --git a/qt_ui/windows/finances/QFinancesMenu.py b/qt_ui/windows/finances/QFinancesMenu.py index 3dfb195b..e1151b64 100644 --- a/qt_ui/windows/finances/QFinancesMenu.py +++ b/qt_ui/windows/finances/QFinancesMenu.py @@ -1,3 +1,6 @@ +import itertools +from typing import Optional + from PySide2.QtWidgets import ( QDialog, QFrame, @@ -8,7 +11,8 @@ from PySide2.QtWidgets import ( import qt_ui.uiconstants as CONST from game.game import Game -from game.income import Income +from game.income import BuildingIncome, Income +from game.theater import ControlPoint class QHorizontalSeparationLine(QFrame): @@ -25,44 +29,65 @@ class QHorizontalSeparationLine(QFrame): class FinancesLayout(QGridLayout): def __init__(self, game: Game, player: bool) -> None: super().__init__() + self.row = itertools.count(0) income = Income(game, player) - self.addWidget(QLabel("Control Points"), 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) + control_points = reversed( + sorted(income.control_points, key=lambda c: c.income_per_turn)) + for control_point in control_points: + self.add_control_point(control_point) - self.addWidget(QHorizontalSeparationLine(), 1, 0, 1, 3) + self.add_line() buildings = reversed(sorted(income.buildings, key=lambda b: b.income)) - row = 2 - for row, building in enumerate(buildings, row): - self.addWidget( - QLabel(f"{building.category.upper()} [{building.name}]"), - 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) + for building in buildings: + self.add_building(building) - self.addWidget(QHorizontalSeparationLine(), row + 1, 0, 1, 3) - self.addWidget(QLabel( - f"Income multiplier: {income.multiplier:.1f}"), - row + 2, 1 - ) - self.addWidget(QLabel(f"{income.total}M"), row + 2, 2) + self.add_line() + + self.add_row(middle=f"Income multiplier: {income.multiplier:.1f}", + right=f"{income.total}M") if player: budget = game.budget else: budget = game.enemy_budget - self.addWidget(QLabel(f"Balance"), row + 3, 1) - self.addWidget(QLabel(f"{budget}M"), row + 3, 2) - self.setRowStretch(row + 4, 1) + + self.add_row(middle="Balance", right=f"{budget}M") + self.setRowStretch(next(self.row), 1) + + def add_row(self, left: Optional[str] = None, middle: Optional[str] = None, + right: Optional[str] = None) -> None: + if not any([left, middle, right]): + raise ValueError + + row = next(self.row) + if left is not None: + self.addWidget(QLabel(left), row, 0) + if middle is not None: + self.addWidget(QLabel(middle), row, 1) + if right is not None: + self.addWidget(QLabel(right), row, 2) + + def add_control_point(self, control_point: ControlPoint) -> None: + self.add_row(left=f"{control_point.name}", + right=f"{control_point.income_per_turn}M") + + def add_building(self, building: BuildingIncome) -> None: + row = next(self.row) + self.addWidget( + QLabel(f"{building.category.upper()} [{building.name}]"), + 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) + + def add_line(self) -> None: + self.addWidget(QHorizontalSeparationLine(), next(self.row), 0, 1, 3) class QFinancesMenu(QDialog):