Ground war rework

This commit is contained in:
Khopa
2020-05-24 20:32:45 +02:00
parent 5884d9d120
commit f57e453d8d
74 changed files with 1255 additions and 1965 deletions

View File

@@ -4,8 +4,7 @@ from typing import Dict
from PySide2.QtGui import QColor, QFont, QPixmap
from game.event import BaseAttackEvent, FrontlinePatrolEvent, FrontlineAttackEvent, InfantryTransportEvent, \
InsurgentAttackEvent, ConvoyStrikeEvent, InterceptEvent, NavalInterceptEvent, StrikeEvent, UnitsDeliveryEvent
from game.event import UnitsDeliveryEvent, FrontlineAttackEvent
from theater.theatergroundobject import CATEGORY_MAP
URLS : Dict[str, str] = {
@@ -85,15 +84,9 @@ EVENT_ICONS: Dict[str, QPixmap] = {}
def load_event_icons():
for category, image in {BaseAttackEvent: "capture",
FrontlinePatrolEvent: "attack",
for category, image in {
"strike": "strike",
FrontlineAttackEvent: "attack",
InfantryTransportEvent: "infantry",
InsurgentAttackEvent: "insurgent_attack",
ConvoyStrikeEvent: "convoy",
InterceptEvent: "air_intercept",
NavalInterceptEvent: "naval_intercept",
StrikeEvent: "strike",
UnitsDeliveryEvent: "delivery"}.items():
EVENT_ICONS[category] = QPixmap("./resources/ui/events/" + image + ".png")

View File

@@ -11,6 +11,7 @@ class QBaseInformation(QGroupBox):
super(QBaseInformation, self).__init__("Base defenses")
self.cp = cp
self.airport = airport
self.setMinimumWidth(500)
self.init_ui()
def init_ui(self):

View File

@@ -8,8 +8,7 @@ from dcs import Point
import qt_ui.uiconstants as CONST
from game import Game, db
from game.event import InfantryTransportEvent, StrikeEvent, BaseAttackEvent, UnitsDeliveryEvent, Event, \
FrontlineAttackEvent, FrontlinePatrolEvent, ConvoyStrikeEvent, ControlPointType
from game.event import UnitsDeliveryEvent, Event, ControlPointType
from gen import Conflict
from qt_ui.widgets.map.QLiberationScene import QLiberationScene
from qt_ui.widgets.map.QMapControlPoint import QMapControlPoint

View File

@@ -5,7 +5,8 @@ from PySide2.QtWidgets import QGraphicsRectItem, QGraphicsSceneHoverEvent, QGrap
import qt_ui.uiconstants as CONST
from game import Game
from qt_ui.windows.QBaseMenu import QBaseMenu
from qt_ui.windows.basemenu.QBaseMenu import QBaseMenu
from qt_ui.windows.basemenu.QBaseMenu2 import QBaseMenu2
from theater import ControlPoint, db
@@ -98,5 +99,5 @@ class QMapControlPoint(QGraphicsRectItem):
return self.model.captured and CONST.COLORS["bright_red"] or CONST.COLORS["dark_blue"]
def openBaseMenu(self):
self.baseMenu = QBaseMenu(self.window(), self.model, self.game)
self.baseMenu = QBaseMenu2(self.window(), self.model, self.game)
self.baseMenu.show()

View File

@@ -5,7 +5,7 @@ from PySide2.QtWidgets import QHBoxLayout, QLabel, QWidget, QDialog, QVBoxLayout
QSpinBox, QPushButton, QMessageBox, QComboBox
from pip._internal.utils import typing
from game.game import AWACS_BUDGET_COST, PinpointStrike, db, Event, FrontlineAttackEvent, FrontlinePatrolEvent, Task, \
from game.game import AWACS_BUDGET_COST, PinpointStrike, db, Event, FrontlineAttackEvent, Task, \
UnitType
from qt_ui.windows.QWaitingForMissionResultWindow import QWaitingForMissionResultWindow
from userdata.persistency import base_path
@@ -234,14 +234,14 @@ class QBriefingWindow(QDialog):
return
if self.game.is_player_attack(self.gameEvent):
if isinstance(self.gameEvent, FrontlineAttackEvent) or isinstance(self.gameEvent, FrontlinePatrolEvent):
if isinstance(self.gameEvent, FrontlineAttackEvent):
if self.base.total_armor == 0:
self.showErrorMessage("No ground vehicles available to attack!")
return
self.gameEvent.player_attacking(flights)
else:
if isinstance(self.gameEvent, FrontlineAttackEvent) or isinstance(self.gameEvent, FrontlinePatrolEvent):
if isinstance(self.gameEvent, FrontlineAttackEvent):
if self.gameEvent.to_cp.base.total_armor == 0:
self.showErrorMessage("No ground vehicles available to defend!")
return

View File

@@ -0,0 +1,73 @@
import traceback
from PySide2.QtCore import Qt
from PySide2.QtGui import QCloseEvent
from PySide2.QtWidgets import QHBoxLayout, QLabel, QWidget, QDialog, QVBoxLayout, QGridLayout, QPushButton, \
QGroupBox, QSizePolicy, QSpacerItem
from dcs.unittype import UnitType
from game.event import UnitsDeliveryEvent, ControlPointType
from qt_ui.widgets.QBudgetBox import QBudgetBox
from qt_ui.widgets.base.QAirportInformation import QAirportInformation
from qt_ui.widgets.base.QBaseInformation import QBaseInformation
from qt_ui.windows.basemenu.QBaseMenuTabs import QBaseMenuTabs
from qt_ui.windows.mission.QPlannedFlightsView import QPlannedFlightsView
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
from theater import ControlPoint, CAP, Embarking, CAS, PinpointStrike, db
from game import Game
class QBaseMenu2(QDialog):
def __init__(self, parent, cp: ControlPoint, game: Game):
super(QBaseMenu2, self).__init__(parent)
# Attrs
self.cp = cp
self.game = game
self.is_carrier = self.cp.cptype in [ControlPointType.AIRCRAFT_CARRIER_GROUP, ControlPointType.LHA_GROUP]
# Widgets
self.qbase_menu_tab = QBaseMenuTabs(cp, game)
try:
self.airport = game.theater.terrain.airport_by_id(self.cp.id)
except:
self.airport = None
if self.cp.captured:
self.deliveryEvent = None
self.setWindowFlags(Qt.WindowStaysOnTopHint)
self.setMinimumSize(300, 200)
self.setModal(True)
self.initUi()
def initUi(self):
self.setWindowTitle(self.cp.name)
self.topLayoutWidget = QWidget()
self.topLayout = QHBoxLayout()
self.topLayoutWidget = QWidget()
self.topLayout = QHBoxLayout()
title = QLabel("<b>" + self.cp.name + "</b>")
title.setAlignment(Qt.AlignLeft | Qt.AlignTop)
title.setProperty("style", "base-title")
unitsPower = QLabel("{} / {} / Runway : {}".format(self.cp.base.total_planes, self.cp.base.total_armor,
"Available" if self.cp.has_runway() else "Unavailable"))
self.topLayout.addWidget(title)
self.topLayout.addWidget(unitsPower)
self.topLayout.setAlignment(Qt.AlignTop)
self.topLayoutWidget.setProperty("style", "baseMenuHeader")
self.topLayoutWidget.setLayout(self.topLayout)
self.mainLayout = QGridLayout()
self.mainLayout.addWidget(self.topLayoutWidget, 0, 0)
self.mainLayout.addWidget(self.qbase_menu_tab, 1, 0)
self.setLayout(self.mainLayout)
def closeEvent(self, closeEvent:QCloseEvent):
GameUpdateSignal.get_instance().updateGame(self.game)

View File

@@ -0,0 +1,37 @@
from PySide2.QtWidgets import QTabWidget, QFrame, QGridLayout, QLabel
from game import Game
from qt_ui.windows.basemenu.airfield.QAirfieldCommand import QAirfieldCommand
from qt_ui.windows.basemenu.base_defenses.QBaseDefensesHQ import QBaseDefensesHQ
from qt_ui.windows.basemenu.ground_forces.QGroundForcesHQ import QGroundForcesHQ
from qt_ui.windows.basemenu.intel.QIntelInfo import QIntelInfo
from theater import ControlPoint
class QBaseMenuTabs(QTabWidget):
def __init__(self, cp: ControlPoint, game: Game):
super(QBaseMenuTabs, self).__init__()
self.cp = cp
if cp:
if not cp.captured:
self.intel = QIntelInfo(cp, game)
self.addTab(self.intel, "Intel")
else:
if cp.has_runway():
self.airfield_command = QAirfieldCommand(cp, game)
self.addTab(self.airfield_command, "Airfield Command")
if not cp.is_carrier:
self.ground_forces_hq = QGroundForcesHQ(cp, game)
self.addTab(self.ground_forces_hq, "Ground Forces HQ")
self.base_defenses_hq = QBaseDefensesHQ(cp, game)
self.addTab(self.base_defenses_hq, "Base Defenses")
else:
tabError = QFrame()
l = QGridLayout()
l.addWidget(QLabel("No Control Point"))
tabError.setLayout(l)
self.addTab(tabError, "No Control Point")

View File

@@ -0,0 +1,92 @@
from PySide2.QtWidgets import QLabel, QPushButton, \
QSizePolicy, QSpacerItem
from dcs.unittype import UnitType
from theater import db
class QRecruitBehaviour:
game = None
cp = None
deliveryEvent = None
existing_units_labels = None
bought_amount_labels = None
def __init__(self):
self.bought_amount_labels = {}
self.existing_units_labels = {}
def add_purchase_row(self, unit_type, layout, row):
existing_units = self.cp.base.total_units_of_type(unit_type)
scheduled_units = self.deliveryEvent.units.get(unit_type, 0)
unitName = QLabel("<b>" + db.unit_type_name(unit_type) + "</b>")
unitName.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
existing_units = QLabel(str(existing_units))
existing_units.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
amount_bought = QLabel("[{}]".format(str(scheduled_units)))
amount_bought.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
self.existing_units_labels[unit_type] = existing_units
self.bought_amount_labels[unit_type] = amount_bought
price = QLabel("{}m".format(db.PRICES[unit_type]))
price.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
buy = QPushButton("+")
buy.setProperty("style", "btn-success")
buy.setMinimumSize(24, 24)
buy.clicked.connect(lambda: self.buy(unit_type))
buy.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
sell = QPushButton("-")
sell.setProperty("style", "btn-danger")
sell.setMinimumSize(24, 24)
sell.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
sell.clicked.connect(lambda: self.sell(unit_type))
layout.addWidget(unitName, row, 0)
layout.addItem(QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum), row, 1)
layout.addWidget(existing_units, row, 2)
layout.addWidget(amount_bought, row, 3)
layout.addWidget(price, row, 4)
layout.addItem(QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum), row, 5)
layout.addWidget(buy, row, 6)
layout.addWidget(sell, row, 7)
return row + 1
def _update_count_label(self, unit_type: UnitType):
self.bought_amount_labels[unit_type].setText("[{}]".format(
unit_type in self.deliveryEvent.units and "{}".format(self.deliveryEvent.units[unit_type]) or "0"
))
self.existing_units_labels[unit_type].setText("{}".format(
self.cp.base.total_units_of_type(unit_type)
))
def buy(self, unit_type):
price = db.PRICES[unit_type]
if self.game.budget >= price:
self.deliveryEvent.deliver({unit_type: 1})
self.game.budget -= price
self._update_count_label(unit_type)
def sell(self, unit_type):
if self.deliveryEvent.units.get(unit_type, 0) > 0:
price = db.PRICES[unit_type]
self.game.budget += price
self.deliveryEvent.units[unit_type] = self.deliveryEvent.units[unit_type] - 1
if self.deliveryEvent.units[unit_type] == 0:
del self.deliveryEvent.units[unit_type]
elif self.cp.base.total_units_of_type(unit_type) > 0:
price = db.PRICES[unit_type]
self.game.budget += price
self.cp.base.commit_losses({unit_type: 1})
self._update_count_label(unit_type)

View File

@@ -0,0 +1,63 @@
import traceback
from PySide2.QtCore import Qt
from PySide2.QtGui import QCloseEvent
from PySide2.QtWidgets import QHBoxLayout, QLabel, QWidget, QDialog, QVBoxLayout, QGridLayout, QPushButton, \
QGroupBox, QSizePolicy, QSpacerItem, QFrame
from dcs.unittype import UnitType
from game.event import UnitsDeliveryEvent, ControlPointType
from qt_ui.widgets.QBudgetBox import QBudgetBox
from qt_ui.widgets.base.QAirportInformation import QAirportInformation
from qt_ui.widgets.base.QBaseInformation import QBaseInformation
from qt_ui.windows.basemenu.QRecruitBehaviour import QRecruitBehaviour
from qt_ui.windows.mission.QPlannedFlightsView import QPlannedFlightsView
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
from theater import ControlPoint, CAP, Embarking, CAS, PinpointStrike, db
from game import Game
class QAircraftRecruitmentMenu(QGroupBox, QRecruitBehaviour):
def __init__(self, cp:ControlPoint, game:Game):
QGroupBox.__init__(self, "Recruitment")
self.cp = cp
self.game = game
self.bought_amount_labels = {}
self.existing_units_labels = {}
for event in self.game.events:
if event.__class__ == UnitsDeliveryEvent and event.from_cp == self.cp:
self.deliveryEvent = event
if not self.deliveryEvent:
self.deliveryEvent = self.game.units_delivery_event(self.cp)
self.init_ui()
def init_ui(self):
layout = QVBoxLayout()
units = {
CAP: db.find_unittype(CAP, self.game.player_name),
CAS: db.find_unittype(CAS, self.game.player_name),
}
task_box_layout = QGridLayout()
row = 0
for task_type in units.keys():
units_column = list(set(units[task_type]))
if len(units_column) == 0: continue
units_column.sort(key=lambda x: db.PRICES[x])
for unit_type in units_column:
if self.cp.is_carrier and not unit_type in db.CARRIER_CAPABLE:
continue
row = self.add_purchase_row(unit_type, task_box_layout, row)
stretch = QVBoxLayout()
stretch.addStretch()
task_box_layout.addLayout(stretch, row, 0)
layout.addLayout(task_box_layout)
layout.addStretch()
self.setLayout(layout)

View File

@@ -0,0 +1,31 @@
from PySide2.QtWidgets import QFrame, QGridLayout, QLabel, QHBoxLayout, QGroupBox, QVBoxLayout
from game import Game
from qt_ui.widgets.base.QAirportInformation import QAirportInformation
from qt_ui.windows.basemenu.airfield.QAircraftRecruitmentMenu import QAircraftRecruitmentMenu
from qt_ui.windows.mission.QPlannedFlightsView import QPlannedFlightsView
from theater import ControlPoint
class QAirfieldCommand(QFrame):
def __init__(self, cp:ControlPoint, game:Game):
super(QAirfieldCommand, self).__init__()
self.cp = cp
self.game = game
self.init_ui()
def init_ui(self):
layout = QGridLayout()
layout.addWidget(QAircraftRecruitmentMenu(self.cp, self.game), 0, 0)
try:
planned = QGroupBox("Planned Flights")
planned_layout = QVBoxLayout()
planned_layout.addWidget(QPlannedFlightsView(self.game.planners[self.cp.id]))
planned.setLayout(planned_layout)
layout.addWidget(planned, 0, 1)
except:
pass
#layout.addWidget(QAirportInformation(self.cp, self.game.theater.terrain.airport_by_id(self.cp.id)), 0, 2)
self.setLayout(layout)

View File

@@ -0,0 +1,20 @@
from PySide2.QtWidgets import QFrame, QGridLayout, QLabel
from game import Game
from qt_ui.widgets.base.QBaseInformation import QBaseInformation
from theater import ControlPoint
class QBaseDefensesHQ(QFrame):
def __init__(self, cp:ControlPoint, game:Game):
super(QBaseDefensesHQ, self).__init__()
self.cp = cp
self.game = game
self.init_ui()
def init_ui(self):
airport = self.game.theater.terrain.airport_by_id(self.cp.id)
layout = QGridLayout()
layout.addWidget(QBaseInformation(self.cp, airport))
self.setLayout(layout)

View File

@@ -0,0 +1,49 @@
from PySide2.QtWidgets import QVBoxLayout, QGridLayout, QGroupBox
from game import Game
from game.event import UnitsDeliveryEvent
from qt_ui.windows.basemenu.QRecruitBehaviour import QRecruitBehaviour
from theater import ControlPoint, PinpointStrike, db
class QArmorRecruitmentMenu(QGroupBox, QRecruitBehaviour):
def __init__(self, cp:ControlPoint, game:Game):
QGroupBox.__init__(self, "Recruitment")
self.cp = cp
self.game = game
self.bought_amount_labels = {}
self.existing_units_labels = {}
for event in self.game.events:
if event.__class__ == UnitsDeliveryEvent and event.from_cp == self.cp:
self.deliveryEvent = event
if not self.deliveryEvent:
self.deliveryEvent = self.game.units_delivery_event(self.cp)
self.init_ui()
def init_ui(self):
layout = QVBoxLayout()
units = {
PinpointStrike: db.find_unittype(PinpointStrike, self.game.player_name),
}
task_box_layout = QGridLayout()
row = 0
for task_type in units.keys():
units_column = list(set(units[task_type]))
if len(units_column) == 0: continue
units_column.sort(key=lambda x: db.PRICES[x])
for unit_type in units_column:
row = self.add_purchase_row(unit_type, task_box_layout, row)
stretch = QVBoxLayout()
stretch.addStretch()
task_box_layout.addLayout(stretch, row, 0)
layout.addLayout(task_box_layout)
layout.addStretch()
self.setLayout(layout)

View File

@@ -0,0 +1,21 @@
from PySide2.QtWidgets import QFrame, QGridLayout
from game import Game
from qt_ui.windows.basemenu.ground_forces.QArmorRecruitmentMenu import QArmorRecruitmentMenu
from qt_ui.windows.basemenu.ground_forces.QGroundForcesStrategy import QGroundForcesStrategy
from theater import ControlPoint
class QGroundForcesHQ(QFrame):
def __init__(self, cp:ControlPoint, game:Game):
super(QGroundForcesHQ, self).__init__()
self.cp = cp
self.game = game
self.init_ui()
def init_ui(self):
layout = QGridLayout()
layout.addWidget(QArmorRecruitmentMenu(self.cp, self.game), 0, 0)
layout.addWidget(QGroundForcesStrategy(self.cp, self.game), 0, 1)
self.setLayout(layout)

View File

@@ -0,0 +1,23 @@
from PySide2.QtWidgets import QLabel, QGroupBox, QVBoxLayout
from game import Game
from qt_ui.windows.basemenu.ground_forces.QGroundForcesStrategySelector import QGroundForcesStrategySelector
from theater import ControlPoint
class QGroundForcesStrategy(QGroupBox):
def __init__(self, cp:ControlPoint, game:Game):
super(QGroundForcesStrategy, self).__init__("Frontline operations :")
self.cp = cp
self.game = game
self.init_ui()
def init_ui(self):
layout = QVBoxLayout()
for enemy_cp in self.cp.connected_points:
if not enemy_cp.captured:
layout.addWidget(QLabel(enemy_cp.name))
layout.addWidget(QGroundForcesStrategySelector(self.cp, enemy_cp))
layout.addStretch()
self.setLayout(layout)

View File

@@ -0,0 +1,25 @@
from PySide2.QtWidgets import QComboBox
from theater import ControlPoint, CombatStance
class QGroundForcesStrategySelector(QComboBox):
def __init__(self, cp:ControlPoint, enemy_cp:ControlPoint):
super(QGroundForcesStrategySelector, self).__init__()
self.cp = cp
self.enemy_cp = enemy_cp
if enemy_cp.id not in self.cp.stances:
self.cp.stances[enemy_cp.id] = CombatStance.DEFENSIVE
for i, stance in enumerate(CombatStance):
self.addItem(stance.name, userData=stance.value)
if self.cp.stances[enemy_cp.id] == stance.value:
self.setCurrentIndex(i)
self.currentTextChanged.connect(self.on_change)
def on_change(self):
print(self.currentData())
self.cp.stances[self.enemy_cp.id] = self.currentData()

View File

@@ -0,0 +1,56 @@
from PySide2.QtWidgets import QLabel, QGroupBox, QVBoxLayout, QFrame, QGridLayout
from dcs.task import Embarking, CAS, PinpointStrike, CAP
from game import Game
from qt_ui.windows.basemenu.ground_forces.QGroundForcesStrategySelector import QGroundForcesStrategySelector
from theater import ControlPoint, db
class QIntelInfo(QFrame):
def __init__(self, cp:ControlPoint, game:Game):
super(QIntelInfo, self).__init__()
self.cp = cp
self.game = game
self.init_ui()
def init_ui(self):
layout = QVBoxLayout()
intel = QGroupBox("Intel")
intelLayout = QVBoxLayout()
units = {
CAP: db.find_unittype(CAP, self.game.enemy_name),
Embarking: db.find_unittype(Embarking, self.game.enemy_name),
CAS: db.find_unittype(CAS, self.game.enemy_name),
PinpointStrike: db.find_unittype(PinpointStrike, self.game.enemy_name),
}
for task_type in units.keys():
units_column = list(set(units[task_type]))
if sum([self.cp.base.total_units_of_type(u) for u in units_column]) > 0:
group = QGroupBox(db.task_name(task_type))
groupLayout = QGridLayout()
group.setLayout(groupLayout)
row = 0
for unit_type in units_column:
existing_units = self.cp.base.total_units_of_type(unit_type)
if existing_units == 0:
continue
groupLayout.addWidget(QLabel("<b>" + db.unit_type_name(unit_type) + "</b>"), row, 0)
groupLayout.addWidget(QLabel(str(existing_units)), row, 1)
row += 1
intelLayout.addWidget(group)
intelLayout.addStretch()
intel.setLayout(intelLayout)
layout.addWidget(intel)
layout.addStretch()
self.setLayout(layout)

View File

@@ -1,7 +1,7 @@
from PySide2.QtCore import Qt, Slot, QItemSelectionModel, QPoint
from PySide2.QtWidgets import QDialog, QGridLayout, QScrollArea, QVBoxLayout, QPushButton
from game import Game
from game.event import StrikeEvent, InsurgentAttackEvent, FrontlineAttackEvent, CAP, CAS
from game.event import CAP, CAS, FrontlineAttackEvent
from qt_ui.uiconstants import EVENT_ICONS
from qt_ui.windows.QWaitingForMissionResultWindow import QWaitingForMissionResultWindow
from qt_ui.windows.mission.QPlannedFlightsView import QPlannedFlightsView
@@ -18,7 +18,7 @@ class QMissionPlanning(QDialog):
self.setMinimumSize(750, 420)
self.setModal(True)
self.setWindowTitle("Mission Preparation")
self.setWindowIcon(EVENT_ICONS[StrikeEvent])
self.setWindowIcon(EVENT_ICONS["strike"])
self.init_ui()
print("DONE")
@@ -84,14 +84,10 @@ class QMissionPlanning(QDialog):
# self.game.awacs_expense_commit()
#else:
# self.gameEvent.is_awacs_enabled = False
self.gameEvent.is_awacs_enabled = False
self.gameEvent.is_awacs_enabled = True
self.gameEvent.ca_slots = 1
self.gameEvent.departure_cp = self.game.theater.controlpoints[0]
if self.game.is_player_attack(self.gameEvent):
self.gameEvent.player_attacking({CAS:{}, CAP:{}})
else:
self.gameEvent.player_defending({CAS: {}, CAP: {}})
self.gameEvent.player_attacking({CAS:{}, CAP:{}})
self.gameEvent.depart_from = self.game.theater.controlpoints[0]
self.game.initiate_event(self.gameEvent)