diff --git a/game/db.py b/game/db.py index 61848136..0ff1e24d 100644 --- a/game/db.py +++ b/game/db.py @@ -739,6 +739,14 @@ TIME_PERIODS = { "Syrian War [2011]": datetime(2011, 8, 7), } +REWARDS = { + "power": 4, "warehouse": 2, "fuel": 2, "ammo": 2, + "farp": 1, "fob": 1, "factory": 10, "comms": 10, "oil": 10 +} + +# Base post-turn bonus value +PLAYER_BUDGET_BASE = 20 + CARRIER_CAPABLE = [ FA_18C_hornet, F_14B, diff --git a/game/event/event.py b/game/event/event.py index be3fb9eb..25309856 100644 --- a/game/event/event.py +++ b/game/event/event.py @@ -8,6 +8,7 @@ from dcs.vehicles import AirDefence from dcs.unittype import UnitType from game import * +from game.infos.information import Information from theater import * from gen.environmentgen import EnvironmentSettings from gen.conflictgen import Conflict @@ -220,6 +221,10 @@ class Event: cp.base.aa = {} for g in cp.ground_objects: g.groups = [] + info = Information(cp.name + " lost !", + "The ennemy took control of " + cp.name + "\nShame on us !", + self.game.turn) + self.game.informations.append(info) elif not(cp.captured) and new_owner_coalition == coalition: cp.captured = True cp.base.aircraft = {} @@ -227,6 +232,10 @@ class Event: cp.base.aa = {} for g in cp.ground_objects: g.groups = [] + info = Information(cp.name + " captured !", + "The ennemy took control of " + cp.name + "\nShame on us !", + self.game.turn) + self.game.informations.append(info) except Exception as e: print(e) @@ -281,17 +290,25 @@ class Event: # No progress with defensive strategies if player_won and cp.stances[enemy_cp.id] in [CombatStance.DEFENSIVE, CombatStance.AMBUSH]: - print("Defensive stance, no progress") - delta = 0 + print("Defensive stance, progress is limited") + delta = MINOR_DEFEAT_INFLUENCE if player_won: print(cp.name + " won ! factor > " + str(delta)) cp.base.affect_strength(delta) enemy_cp.base.affect_strength(-delta) + info = Information("Frontline Report", + "Our ground forces from " + cp.name + " are making progress toward " + enemy_cp.name, + self.game.turn) + self.game.informations.append(info) else: - print(enemy_cp.name + " won ! factor > " + str(delta)) + print(cp.name + " lost ! factor > " + str(delta)) enemy_cp.base.affect_strength(delta) cp.base.affect_strength(-delta) + info = Information("Frontline Report", + "Our ground forces from " + cp.name + " are losing ground against the enemy forces from" + enemy_cp.name, + self.game.turn) + self.game.informations.append(info) def skip(self): pass @@ -319,4 +336,9 @@ class UnitsDeliveryEvent(Event): self.units[k] = self.units.get(k, 0) + v def skip(self): + + for k, v in self.units.items(): + info = Information("Ally Reinforcement", str(k.id) + " x " + str(v) + " at " + self.to_cp.name, self.game.turn) + self.game.informations.append(info) + self.to_cp.base.commision_units(self.units) diff --git a/game/factions/libya_2011.py b/game/factions/libya_2011.py index fbde9f03..eca6247b 100644 --- a/game/factions/libya_2011.py +++ b/game/factions/libya_2011.py @@ -4,7 +4,7 @@ from dcs.planes import * from dcs.helicopters import * Lybia_2011 = { - "country": "Libya", + "country": "Russia", "side": "red", "units": [ diff --git a/game/game.py b/game/game.py index 51f6afbc..330e8d2f 100644 --- a/game/game.py +++ b/game/game.py @@ -6,6 +6,7 @@ import math from dcs.task import * from dcs.vehicles import * +from game.db import REWARDS, PLAYER_BUDGET_BASE from game.game_stats import GameStats from game.infos.information import Information from gen.conflictgen import Conflict @@ -50,10 +51,7 @@ ENEMY_BASE_STRENGTH_RECOVERY = 0.05 AWACS_BUDGET_COST = 4 # Initial budget value -PLAYER_BUDGET_INITIAL = 450 - -# Base post-turn bonus value -PLAYER_BUDGET_BASE = 20 +PLAYER_BUDGET_INITIAL = 650 # Bonus multiplier logarithm base PLAYER_BUDGET_IMPORTANCE_LOG = 2 @@ -86,6 +84,7 @@ class Game: self.planners = {} self.ground_planners = {} self.informations = [] + self.informations.append(Information("Game Start", "-" * 40, 0)) def _roll(self, prob, mult): if self.settings.version == "dev": @@ -111,10 +110,12 @@ class Game: def _commision_units(self, cp: ControlPoint): for for_task in [CAS, CAP, AirDefence]: - limit = COMMISION_LIMITS_FACTORS[for_task] * math.pow(cp.importance, COMMISION_LIMITS_SCALE) * self.settings.multiplier + limit = COMMISION_LIMITS_FACTORS[for_task] * math.pow(cp.importance, + COMMISION_LIMITS_SCALE) * self.settings.multiplier missing_units = limit - cp.base.total_units(for_task) if missing_units > 0: - awarded_points = COMMISION_AMOUNTS_FACTORS[for_task] * math.pow(cp.importance, COMMISION_AMOUNTS_SCALE) * self.settings.multiplier + awarded_points = COMMISION_AMOUNTS_FACTORS[for_task] * math.pow(cp.importance, + COMMISION_AMOUNTS_SCALE) * self.settings.multiplier points_to_spend = cp.base.append_commision_points(for_task, awarded_points) if points_to_spend > 0: unittypes = self.commision_unit_types(cp, for_task) @@ -130,25 +131,8 @@ class Game: reward = PLAYER_BUDGET_BASE * len(self.theater.player_points()) for cp in self.theater.player_points(): for g in cp.ground_objects: - # (Reward is per building) - if g.category == "power": - reward = reward + 4 - elif g.category == "warehouse": - reward = reward + 2 - elif g.category == "fuel": - reward = reward + 2 - elif g.category == "ammo": - reward = reward + 2 - elif g.category == "farp": - reward = reward + 1 - elif g.category == "fob": - reward = reward + 1 - elif g.category == "factory": - reward = reward + 10 - elif g.category == "comms": - reward = reward + 10 - elif g.category == "oil": - reward = reward + 10 + if g.category in REWARDS.keys(): + reward = reward + REWARDS[g.category] return reward else: return reward @@ -197,9 +181,9 @@ class Game: else: return event.name == self.player_name - def pass_turn(self, no_action=False, ignored_cps: typing.Collection[ControlPoint]=None): + def pass_turn(self, no_action=False, ignored_cps: typing.Collection[ControlPoint] = None): logging.info("Pass turn") - + self.informations.append(Information("End of turn #" + str(self.turn), "-" * 40, 0)) self.turn = self.turn + 1 for event in self.events: @@ -210,7 +194,6 @@ class Game: else: event.skip() - self._enemy_reinforcement() self._budget_player() @@ -246,34 +229,17 @@ class Game: gplanner.plan_groundwar() self.ground_planners[cp.id] = gplanner - - def _enemy_reinforcement(self): - MAX_ARMOR = 50 * self.settings.multiplier - MAX_AIRCRAFT = 50 * self.settings.multiplier + MAX_ARMOR = 30 * self.settings.multiplier + MAX_AIRCRAFT = 25 * self.settings.multiplier - production = 0 + production = 0.0 for enemy_point in self.theater.enemy_points(): for g in enemy_point.ground_objects: - if g.category == "power": - production = production + 4 - elif g.category == "warehouse": - production = production + 2 - elif g.category == "fuel": - production = production + 2 - elif g.category == "ammo": - production = production + 2 - elif g.category == "farp": - production = production + 1 - elif g.category == "fob": - production = production + 1 - elif g.category == "factory": - production = production + 10 - elif g.category == "comms": - production = production + 8 - elif g.category == "oil": - production = production + 8 + if g.category in REWARDS.keys(): + production = production + REWARDS[g.category] + production = production * 0.75 budget_for_armored_units = production / 2 budget_for_aircraft = production / 2 @@ -302,7 +268,7 @@ class Game: if target_cp.base.total_armor >= MAX_ARMOR: continue unit = random.choice(potential_units) - price = db.PRICES[unit]*2 + price = db.PRICES[unit] * 2 budget_for_armored_units -= price * 2 target_cp.base.armor[unit] = target_cp.base.armor.get(unit, 0) + 2 info = Information("Enemy Reinforcement", unit.id + " x 2 at " + target_cp.name, self.turn) @@ -312,7 +278,8 @@ class Game: if budget_for_armored_units > 0: budget_for_aircraft += budget_for_armored_units - potential_units = [u for u in db.FACTIONS[self.enemy_name]["units"] if u in db.UNIT_BY_TASK[CAS] or u in db.UNIT_BY_TASK[CAP]] + potential_units = [u for u in db.FACTIONS[self.enemy_name]["units"] if + u in db.UNIT_BY_TASK[CAS] or u in db.UNIT_BY_TASK[CAP]] if len(potential_units) > 0 and len(potential_cp_armor) > 0: while budget_for_aircraft > 0: i = i + 1 @@ -322,22 +289,20 @@ class Game: if target_cp.base.total_planes >= MAX_AIRCRAFT: continue unit = random.choice(potential_units) - price = db.PRICES[unit]*2 + price = db.PRICES[unit] * 2 budget_for_aircraft -= price * 2 target_cp.base.aircraft[unit] = target_cp.base.aircraft.get(unit, 0) + 2 info = Information("Enemy Reinforcement", unit.id + " x 2 at " + target_cp.name, self.turn) print(str(info)) self.informations.append(info) - - @property def current_turn_daytime(self): return ["dawn", "day", "dusk", "night"][self.turn % 4] @property def current_day(self): - return self.date + timedelta(days=self.turn//4) + return self.date + timedelta(days=self.turn // 4) def next_unit_id(self): """ diff --git a/gen/flights/flight.py b/gen/flights/flight.py index 654c080b..b6e6ea68 100644 --- a/gen/flights/flight.py +++ b/gen/flights/flight.py @@ -39,6 +39,8 @@ class FlightWaypoint(): self.name = "" self.description = "" self.targets = [] + self.obj_name = "" + self.pretty_name = "" class Flight: diff --git a/gen/naming.py b/gen/naming.py index 59a04118..ab2c9e60 100644 --- a/gen/naming.py +++ b/gen/naming.py @@ -1,9 +1,48 @@ from game import db +import random +ALPHA_MILITARY = ["Alpha","Bravo","Charlie","Delta","Echo","Foxtrot", + "Golf","Hotel","India","Juliet","Kilo","Lima","Mike", + "November","Oscar","Papa","Quebec","Romeo","Sierra", + "Tango","Uniform","Victor","Whisky","XRay","Yankee", + "Zulu","Zero"] class NameGenerator: number = 0 + ANIMALS = [ + "SHARK", "TORTOISE", "BAT", "PANGOLIN", "AARDWOLF", + "MONKEY", "BUFFALO", "DOG", "BOBCAT", "LYNX", "PANTHER", "TIGER", + "LION", "OWL", "BUTTERFLY", "BISON", "DUCK", "COBRA", "MAMBA", + "DOLPHIN", "PHEASANT", "ARMADILLLO", "RACOON", "ZEBRA", "COW", "COYOTE", "FOX", + "LIGHTFOOT", "COTTONMOUTH", "TAURUS", "VIPER", "CASTOR", "GIRAFFE", "SNAKE", + "MONSTER", "ALBATROSS", "HAWK", "DOVE", "MOCKINGBIRD", "GECKO", "ORYX", "GORILLA", + "HARAMBE", "GOOSE", "MAVERICK", "HARE", "JACKAL", "LEOPARD", "CAT", "MUSK", "ORCA", + "OCELOT", "BEAR", "PANDA", "GULL", "PENGUIN", "PYTHON", "RAVEN", "DEER", "MOOSE", + "REINDEER", "SHEEP", "GAZELLE", "INSECT", "VULTURE", "WALLABY", "KANGAROO", "KOALA", + "KIWI", "WHALE", "FISH", "RHINO", "HIPPO", "RAT", "WOODPECKER", "WORM", "BABOON", + "YAK", "SCORPIO", "HORSE", "POODLE", "CENTIPEDE", "CHICKEN", "CHEETAH", "CHAMELEON", + "CATFISH", "CATERPILLAR", "CARACAL", "CAMEL", "CAIMAN", "BARRACUDA", "BANDICOOT", + "ALLIGATOR", "BONGO", "CORAL", "ELEPHANT", "ANTELOPE", "CRAB", "DACHSHUND", "DODO", + "FLAMINGO", "FERRET", "FALCON", "BULLDOG", "DONKEY", "IGUANA", "TAMARIN", "HARRIER", + "GRIZZLY", "GREYHOUND", "GRASSHOPPER", "JAGUAR", "LADYBUG", "KOMODO", "DRAGON", "LIZARD", + "LLAMA", "LOBSTER", "OCTOPUS", "MANATEE", "MAGPIE", "MACAW", "OSTRICH", "OYSTER", + "MOLE", "MULE", "MOTH", "MONGOOSE", "MOLLY", "MEERKAT", "MOUSE", "PEACOCK", "PIKE", "ROBIN", + "RAGDOLL", "PLATYPUS", "PELICAN", "PARROT", "PORCUPINE", "PIRANHA", "PUMA", "PUG", "TAPIR", + "TERMITE", "URCHIN", "SHRIMP", "TURKEY", "TOUCAN", "TETRA", "HUSKY", "STARFISH", "SWAN", + "FROG", "SQUIRREL", "WALRUS", "WARTHOG", "CORGI", "WEASEL", "WOMBAT", "WOLVERINE", "MAMMOTH", + "TOAD", "WOLF", "ZEBU", "SEAL", "SKATE", "JELLYFISH", "MOSQUITO", "LOCUST", "SLUG", "SNAIL", + "HEDGEHOG", "PIGLET", "FENNEC", "BADGER", "ALPACA" + ] + + def __init__(self): + self.number = 0 + self.ANIMALS = NameGenerator.ANIMALS.copy() + + def reset(self): + self.number = 0 + self.ANIMALS = NameGenerator.ANIMALS.copy() + def next_unit_name(self, country, parent_base_id, unit_type): self.number += 1 return "unit|{}|{}|{}|{}|".format(country.id, self.number, parent_base_id, db.unit_type_name(unit_type)) @@ -27,6 +66,16 @@ class NameGenerator: self.number += 1 return "carrier|{}|{}|0|".format(country.id, self.number) + def random_objective_name(self): + if len(self.ANIMALS) == 0: + random.choice(ALPHA_MILITARY).upper() + " #" + str(random.randint(0, 100)) + else: + animal = random.choice(self.ANIMALS) + self.ANIMALS.remove(animal) + return animal + namegen = NameGenerator() + + diff --git a/qt_ui/uiconstants.py b/qt_ui/uiconstants.py index 1c40423b..63e8ccb2 100644 --- a/qt_ui/uiconstants.py +++ b/qt_ui/uiconstants.py @@ -88,12 +88,10 @@ EVENT_ICONS: Dict[str, QPixmap] = {} def load_event_icons(): - for category, image in { - "strike": "strike", - FrontlineAttackEvent: "attack", - UnitsDeliveryEvent: "delivery"}.items(): - EVENT_ICONS[category] = QPixmap("./resources/ui/events/" + image + ".png") - + for image in os.listdir("./resources/ui/events/"): + print(image) + if image.endswith(".PNG"): + EVENT_ICONS[image[:-4]] = QPixmap(os.path.join("./resources/ui/events/", image)) def load_aircraft_icons(): for aircraft in os.listdir("./resources/ui/units/aircrafts/"): diff --git a/qt_ui/widgets/QBudgetBox.py b/qt_ui/widgets/QBudgetBox.py index f8157b4b..27233559 100644 --- a/qt_ui/widgets/QBudgetBox.py +++ b/qt_ui/widgets/QBudgetBox.py @@ -1,6 +1,7 @@ -from PySide2.QtWidgets import QLabel, QHBoxLayout, QGroupBox +from PySide2.QtWidgets import QLabel, QHBoxLayout, QGroupBox, QPushButton import qt_ui.uiconstants as CONST +from qt_ui.windows.finances.QFinancesMenu import QFinancesMenu class QBudgetBox(QGroupBox): @@ -8,16 +9,22 @@ class QBudgetBox(QGroupBox): UI Component to display current budget and player's money """ - def __init__(self): + def __init__(self, game): super(QBudgetBox, self).__init__("Budget") + self.game = game self.money_icon = QLabel() self.money_icon.setPixmap(CONST.ICONS["Money"]) self.money_amount = QLabel() + self.finances = QPushButton("Details") + self.finances.setProperty("style", "btn-primary") + self.finances.clicked.connect(self.openFinances) + self.layout = QHBoxLayout() self.layout.addWidget(self.money_icon) self.layout.addWidget(self.money_amount) + self.layout.addWidget(self.finances) self.setLayout(self.layout) def setBudget(self, budget, reward): @@ -26,4 +33,12 @@ class QBudgetBox(QGroupBox): :param budget: Current money available :param reward: Planned reward for next turn """ - self.money_amount.setText(str(budget) + "M (+" + str(reward) + "M)") \ No newline at end of file + self.money_amount.setText(str(budget) + "M (+" + str(reward) + "M)") + + def setGame(self, game): + self.game = game + self.setBudget(self.game.budget, self.game.budget_reward_amount) + + def openFinances(self): + self.subwindow = QFinancesMenu(self.game) + self.subwindow.show() \ No newline at end of file diff --git a/qt_ui/widgets/QFactionsInfos.py b/qt_ui/widgets/QFactionsInfos.py index 51240ae4..79b5848d 100644 --- a/qt_ui/widgets/QFactionsInfos.py +++ b/qt_ui/widgets/QFactionsInfos.py @@ -15,6 +15,7 @@ class QFactionsInfos(QGroupBox): self.setGame(game) self.layout = QGridLayout() + self.layout.setSpacing(0) self.layout.addWidget(QLabel("Player : "),0,0) self.layout.addWidget(self.player_name,0,1) self.layout.addWidget(QLabel("Enemy : "),1,0) diff --git a/qt_ui/widgets/QPredefinedWaypointSelectionComboBox.py b/qt_ui/widgets/QPredefinedWaypointSelectionComboBox.py new file mode 100644 index 00000000..ef8cdcaa --- /dev/null +++ b/qt_ui/widgets/QPredefinedWaypointSelectionComboBox.py @@ -0,0 +1,146 @@ +from PySide2.QtCore import QSortFilterProxyModel, Qt, QModelIndex +from PySide2.QtGui import QStandardItem, QStandardItemModel +from PySide2.QtWidgets import QComboBox, QCompleter +from game import Game +from gen.flights.flight import FlightWaypoint +from theater import ControlPointType + + +class QPredefinedWaypointSelectionComboBox(QComboBox): + + def __init__(self, game: Game, parent=None): + super(QPredefinedWaypointSelectionComboBox, self).__init__(parent) + + self.game = game + self.setFocusPolicy(Qt.StrongFocus) + self.setEditable(True) + self.completer = QCompleter(self) + + # always show all completions + self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) + self.pFilterModel = QSortFilterProxyModel(self) + self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive) + + self.completer.setPopup(self.view()) + + self.setCompleter(self.completer) + + self.lineEdit().textEdited.connect(self.pFilterModel.setFilterFixedString) + self.completer.activated.connect(self.setTextIfCompleterIsClicked) + + self.find_possible_waypoints() + + def setModel(self, model): + super(QPredefinedWaypointSelectionComboBox, self).setModel(model) + self.pFilterModel.setSourceModel(model) + self.completer.setModel(self.pFilterModel) + + def setModelColumn(self, column): + self.completer.setCompletionColumn(column) + self.pFilterModel.setFilterKeyColumn(column) + super(QPredefinedWaypointSelectionComboBox, self).setModelColumn(column) + + def view(self): + return self.completer.popup() + + def index(self): + return self.currentIndex() + + def setTextIfCompleterIsClicked(self, text): + if text: + index = self.findText(text) + self.setCurrentIndex(index) + + def get_selected_waypoints(self, include_all_from_same_location=False): + n = self.currentText() + + first_waypoint = None + for w in self.wpts: + if w.pretty_name == n: + first_waypoint = w + break + + if first_waypoint is None: + return [] + + waypoints = [first_waypoint] + if include_all_from_same_location: + for w in self.wpts: + if w is not first_waypoint and w.obj_name and w.obj_name == first_waypoint.obj_name: + waypoints.append(w) + + return waypoints + + def find_possible_waypoints(self): + + self.wpts = [] + model = QStandardItemModel() + i = 0 + + def add_model_item(i, model, name, wpt): + print(name) + item = QStandardItem(name) + model.setItem(i, 0, item) + self.wpts.append(wpt) + return i + 1 + + for cp in self.game.theater.controlpoints: + print(cp) + if cp.captured: + enemy_cp = [ecp for ecp in cp.connected_points if ecp.captured != cp.captured] + for ecp in enemy_cp: + wpt = FlightWaypoint((cp.position.x + ecp.position.x)/2, (cp.position.y + ecp.position.y)/2, 800) + wpt.name = "Frontline " + cp.name + "/" + ecp.name + " [CAS]" + wpt.pretty_name = wpt.name + wpt.description = "Frontline" + i = add_model_item(i, model, wpt.pretty_name, wpt) + + + for cp in self.game.theater.controlpoints: + for ground_object in cp.ground_objects: + if not ground_object.is_dead and not ground_object.dcs_identifier == "AA": + wpt = FlightWaypoint(ground_object.position.x,ground_object.position.y, 0) + wpt.name = wpt.name = "[" + str(ground_object.obj_name) + "] : " + ground_object.category + " #" + str(ground_object.object_id) + wpt.pretty_name = wpt.name + wpt.obj_name = ground_object.obj_name + if cp.captured: + wpt.description = "Friendly Building" + else: + wpt.description = "Enemy Building" + i = add_model_item(i, model, wpt.pretty_name, wpt) + + for cp in self.game.theater.controlpoints: + + for ground_object in cp.ground_objects: + if not ground_object.is_dead and ground_object.dcs_identifier == "AA": + for g in ground_object.groups: + for j, u in enumerate(g.units): + wpt = FlightWaypoint(u.position.x, u.position.y, 0) + wpt.name = wpt.name = "[" + str(ground_object.obj_name) + "] : " + u.type + " #" + str(j) + wpt.pretty_name = wpt.name + wpt.obj_name = ground_object.obj_name + if cp.captured: + wpt.description = "Friendly unit : " + u.type + else: + wpt.description = "Enemy unit : " + u.type + i = add_model_item(i, model, wpt.pretty_name, wpt) + + for cp in self.game.theater.controlpoints: + + wpt = FlightWaypoint(cp.position.x, cp.position.y, 0) + wpt.name = cp.name + if cp.captured: + wpt.description = "Position of " + cp.name + " [Friendly Airbase]" + else: + wpt.description = "Position of " + cp.name + " [Enemy Airbase]" + + if cp.cptype == ControlPointType.AIRCRAFT_CARRIER_GROUP: + wpt.pretty_name = cp.name + " (Aircraft Carrier Group)" + elif cp.cptype == ControlPointType.LHA_GROUP: + wpt.pretty_name = cp.name + " (LHA Group)" + else: + wpt.pretty_name = cp.name + " (Airbase)" + + i = add_model_item(i, model, wpt.pretty_name, wpt) + + self.setModel(model) diff --git a/qt_ui/widgets/QTopPanel.py b/qt_ui/widgets/QTopPanel.py index 114f8097..b741f3cf 100644 --- a/qt_ui/widgets/QTopPanel.py +++ b/qt_ui/widgets/QTopPanel.py @@ -1,8 +1,9 @@ -from PySide2.QtWidgets import QFrame, QHBoxLayout, QPushButton, QVBoxLayout +from PySide2.QtWidgets import QFrame, QHBoxLayout, QPushButton, QVBoxLayout, QGroupBox from game import Game from qt_ui.widgets.QBudgetBox import QBudgetBox from qt_ui.widgets.QFactionsInfos import QFactionsInfos +from qt_ui.windows.finances.QFinancesMenu import QFinancesMenu from qt_ui.windows.stats.QStatsWindow import QStatsWindow from qt_ui.widgets.QTurnCounter import QTurnCounter @@ -17,13 +18,14 @@ class QTopPanel(QFrame): def __init__(self, game: Game): super(QTopPanel, self).__init__() self.game = game + self.setMaximumHeight(70) self.init_ui() GameUpdateSignal.get_instance().gameupdated.connect(self.setGame) def init_ui(self): self.turnCounter = QTurnCounter() - self.budgetBox = QBudgetBox() + self.budgetBox = QBudgetBox(self.game) self.passTurnButton = QPushButton("Pass Turn") self.passTurnButton.setIcon(CONST.ICONS["PassTurn"]) @@ -36,14 +38,9 @@ class QTopPanel(QFrame): self.proceedButton.clicked.connect(self.proceed) if self.game and self.game.turn == 0: self.proceedButton.setEnabled(False) - elif not len(self.game.planners.keys()) == self.game.theater.controlpoints: - self.proceedButton.setEnabled(False) - else: - self.proceedButton.setEnabled(True) self.factionsInfos = QFactionsInfos(self.game) - self.submenus = QVBoxLayout() self.settings = QPushButton("Settings") self.settings.setIcon(CONST.ICONS["Settings"]) self.settings.setProperty("style", "btn-primary") @@ -54,28 +51,40 @@ class QTopPanel(QFrame): self.statistics.setProperty("style", "btn-primary") self.statistics.clicked.connect(self.openStatisticsWindow) - self.submenus.addWidget(self.settings) - self.submenus.addWidget(self.statistics) + self.buttonBox = QGroupBox("Misc") + self.buttonBoxLayout = QHBoxLayout() + self.buttonBoxLayout.addWidget(self.settings) + self.buttonBoxLayout.addWidget(self.statistics) + self.buttonBox.setLayout(self.buttonBoxLayout) + + self.proceedBox = QGroupBox("Proceed") + self.proceedBoxLayout = QHBoxLayout() + self.proceedBoxLayout.addWidget(self.passTurnButton) + self.proceedBoxLayout.addWidget(self.proceedButton) + self.proceedBox.setLayout(self.proceedBoxLayout) self.layout = QHBoxLayout() self.layout.addWidget(self.factionsInfos) self.layout.addWidget(self.turnCounter) self.layout.addWidget(self.budgetBox) - self.layout.addLayout(self.submenus) + self.layout.addWidget(self.buttonBox) self.layout.addStretch(1) - self.layout.addWidget(self.passTurnButton) - self.layout.addWidget(self.proceedButton) + self.layout.addWidget(self.proceedBox) + + self.layout.setContentsMargins(0,0,0,0) self.setLayout(self.layout) def setGame(self, game:Game): self.game = game if game is not None: self.turnCounter.setCurrentTurn(self.game.turn, self.game.current_day) - self.budgetBox.setBudget(self.game.budget, self.game.budget_reward_amount) + self.budgetBox.setGame(self.game) self.factionsInfos.setGame(self.game) - if not len(self.game.planners.keys()) == self.game.theater.controlpoints: + if not len(self.game.planners.keys()) == len(self.game.theater.controlpoints): self.proceedButton.setEnabled(False) + else: + self.proceedButton.setEnabled(True) def openSettings(self): self.subwindow = QSettingsWindow(self.game) diff --git a/qt_ui/widgets/map/QLiberationMap.py b/qt_ui/widgets/map/QLiberationMap.py index 25f6e0e2..19c6505c 100644 --- a/qt_ui/widgets/map/QLiberationMap.py +++ b/qt_ui/widgets/map/QLiberationMap.py @@ -76,13 +76,6 @@ class QLiberationMap(QGraphicsView): scene.addItem(QMapControlPoint(self, pos[0] - CONST.CP_SIZE / 2, pos[1] - CONST.CP_SIZE / 2, CONST.CP_SIZE, CONST.CP_SIZE, cp, self.game)) - text = scene.addText(cp.name, font=QFont("Trebuchet MS", 10, weight=5, italic=False)) - text.setPos(pos[0] + CONST.CP_SIZE, pos[1] - CONST.CP_SIZE / 2) - - text = scene.addText(cp.name, font=QFont("Trebuchet MS", 10, weight=5, italic=False)) - text.setDefaultTextColor(Qt.white) - text.setPos(pos[0] + CONST.CP_SIZE + 1, pos[1] - CONST.CP_SIZE / 2 + 1) - if cp.captured: pen = QPen(brush=CONST.COLORS["blue"]) @@ -105,7 +98,7 @@ class QLiberationMap(QGraphicsView): go_pos = self._transform_point(ground_object.position) if not ground_object.airbase_group: - scene.addItem(QMapGroundObject(self, go_pos[0], go_pos[1], 16, 16, cp, ground_object)) + scene.addItem(QMapGroundObject(self, go_pos[0], go_pos[1], 12, 12, cp, ground_object)) if ground_object.category == "aa" and self.get_display_rule("sam"): max_range = 0 @@ -126,6 +119,7 @@ class QLiberationMap(QGraphicsView): self.scene_create_lines_for_cp(cp) for cp in self.game.theater.controlpoints: + pos = self._transform_point(cp.position) if self.get_display_rule("flight_paths"): if cp.id in self.game.planners.keys(): planner = self.game.planners[cp.id] @@ -139,6 +133,14 @@ class QLiberationMap(QGraphicsView): prev_pos = list(new_pos) scene.addLine(prev_pos[0] + 2, prev_pos[1] + 2, pos[0] + 2, pos[1] + 2, flight_path_pen) + for cp in self.game.theater.controlpoints: + pos = self._transform_point(cp.position) + text = scene.addText(cp.name, font=QFont("Trebuchet MS", 10, weight=5, italic=False)) + text.setPos(pos[0] + CONST.CP_SIZE, pos[1] - CONST.CP_SIZE / 2) + text = scene.addText(cp.name, font=QFont("Trebuchet MS", 10, weight=5, italic=False)) + text.setDefaultTextColor(Qt.white) + text.setPos(pos[0] + CONST.CP_SIZE + 1, pos[1] - CONST.CP_SIZE / 2 + 1) + def scene_create_lines_for_cp(self, cp: ControlPoint): scene = self.scene() pos = self._transform_point(cp.position) diff --git a/qt_ui/widgets/map/QMapGroundObject.py b/qt_ui/widgets/map/QMapGroundObject.py index 9af06fee..357c2755 100644 --- a/qt_ui/widgets/map/QMapGroundObject.py +++ b/qt_ui/widgets/map/QMapGroundObject.py @@ -27,12 +27,12 @@ class QMapGroundObject(QGraphicsRectItem): units[u.type] = units[u.type]+1 else: units[u.type] = 1 - tooltip = "" + tooltip = "[" + self.model.obj_name + "]" + "\n" for unit in units.keys(): tooltip = tooltip + str(unit) + "x" + str(units[unit]) + "\n" self.setToolTip(tooltip[:-1]) else: - self.setToolTip(cp.name + "'s " + self.model.category) + self.setToolTip("[" + self.model.obj_name + "] : " + self.model.category) def paint(self, painter, option, widget=None): diff --git a/qt_ui/windows/QLiberationWindow.py b/qt_ui/windows/QLiberationWindow.py index f2332caf..31ba3bac 100644 --- a/qt_ui/windows/QLiberationWindow.py +++ b/qt_ui/windows/QLiberationWindow.py @@ -4,7 +4,8 @@ import webbrowser from PySide2 import QtGui from PySide2.QtCore import Qt from PySide2.QtGui import QIcon -from PySide2.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QMainWindow, QAction, QMessageBox, QDesktopWidget +from PySide2.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QMainWindow, QAction, QMessageBox, QDesktopWidget, \ + QSplitter import qt_ui.uiconstants as CONST from game import Game @@ -14,6 +15,7 @@ from qt_ui.widgets.map.QLiberationMap import QLiberationMap from qt_ui.windows.GameUpdateSignal import GameUpdateSignal, DebriefingSignal from qt_ui.windows.QDebriefingWindow import QDebriefingWindow from qt_ui.windows.QNewGameWizard import NewGameWizard +from qt_ui.windows.infos.QInfoPanel import QInfoPanel from userdata import persistency @@ -22,6 +24,7 @@ class QLiberationWindow(QMainWindow): def __init__(self): super(QLiberationWindow, self).__init__() + self.info_panel = None self.setGame(persistency.restore_game()) self.setGeometry(300, 100, 270, 100) @@ -44,11 +47,16 @@ class QLiberationWindow(QMainWindow): def initUi(self): self.liberation_map = QLiberationMap(self.game) + self.info_panel = QInfoPanel(self.game) + + hbox = QSplitter(Qt.Horizontal) + hbox.addWidget(self.info_panel) + hbox.addWidget(self.liberation_map) vbox = QVBoxLayout() vbox.setMargin(0) vbox.addWidget(QTopPanel(self.game)) - vbox.addWidget(self.liberation_map) + vbox.addWidget(hbox) central_widget = QWidget() central_widget.setLayout(vbox) @@ -164,6 +172,8 @@ class QLiberationWindow(QMainWindow): def setGame(self, game: Game): self.game = game + if self.info_panel: + self.info_panel.setGame(game) def showAboutDialog(self): text = "