Exemple #1
0
class QRecruitBehaviour:
    game_model: GameModel
    cp: ControlPoint
    purchase_groups: dict[UnitType, PurchaseGroup]
    existing_units_labels = None
    maximum_units = -1
    BUDGET_FORMAT = "Available Budget: <b>${:.2f}M</b>"

    def __init__(self) -> None:
        self.existing_units_labels = {}
        self.purchase_groups = {}
        self.update_available_budget()

    @property
    def pending_deliveries(self) -> PendingUnitDeliveries:
        return self.cp.pending_unit_deliveries

    @property
    def budget(self) -> float:
        return self.game_model.game.budget

    @budget.setter
    def budget(self, value: int) -> None:
        self.game_model.game.budget = value

    def add_purchase_row(
        self,
        unit_type: UnitType,
        layout: QGridLayout,
        row: int,
    ) -> None:
        exist = QGroupBox()
        exist.setProperty("style", "buy-box")
        exist.setMaximumHeight(36)
        exist.setMinimumHeight(36)
        existLayout = QHBoxLayout()
        exist.setLayout(existLayout)

        existing_units = self.cp.base.total_units_of_type(unit_type)

        unitName = QLabel(f"<b>{unit_type.name}</b>")
        unitName.setSizePolicy(
            QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))

        existing_units = QLabel(str(existing_units))
        existing_units.setSizePolicy(
            QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))

        self.existing_units_labels[unit_type] = existing_units

        price = QLabel(f"<b>$ {unit_type.price}</b> M")
        price.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))

        purchase_group = PurchaseGroup(unit_type, self)
        self.purchase_groups[unit_type] = purchase_group

        info = QGroupBox()
        info.setProperty("style", "buy-box")
        info.setMaximumHeight(36)
        info.setMinimumHeight(36)
        infolayout = QHBoxLayout()
        info.setLayout(infolayout)

        unitInfo = QPushButton("i")
        unitInfo.setProperty("style", "btn-info")
        unitInfo.setMinimumSize(16, 16)
        unitInfo.setMaximumSize(16, 16)
        unitInfo.clicked.connect(lambda: self.info(unit_type))
        unitInfo.setSizePolicy(
            QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))

        existLayout.addWidget(unitName)
        existLayout.addItem(
            QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum))
        existLayout.addWidget(existing_units)
        existLayout.addItem(
            QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum))
        existLayout.addWidget(price)

        infolayout.addWidget(unitInfo)

        layout.addWidget(exist, row, 1)
        layout.addWidget(purchase_group, row, 2)
        layout.addWidget(info, row, 3)

    def update_available_budget(self) -> None:
        GameUpdateSignal.get_instance().updateBudget(self.game_model.game)

    def recruit_handler(self, recruit_type: RecruitType,
                        unit_type: UnitType) -> None:
        # Lookup if Keyboard Modifiers were pressed
        # Shift = 10 times
        # CTRL = 5 Times
        modifiers = QApplication.keyboardModifiers()
        if modifiers == Qt.ShiftModifier:
            amount = 10
        elif modifiers == Qt.ControlModifier:
            amount = 5
        else:
            amount = 1

        for i in range(amount):
            if recruit_type == RecruitType.SELL:
                if not self.sell(unit_type):
                    return
            elif recruit_type == RecruitType.BUY:
                if not self.buy(unit_type):
                    return

    def buy(self, unit_type: UnitType) -> bool:

        if not self.enable_purchase(unit_type):
            logging.error(
                f"Purchase of {unit_type} not allowed at {self.cp.name}")
            return False

        self.pending_deliveries.order({unit_type: 1})
        self.budget -= unit_type.price
        self.update_purchase_controls()
        self.update_available_budget()
        return True

    def sell(self, unit_type: UnitType) -> bool:
        if self.pending_deliveries.available_next_turn(unit_type) > 0:
            self.budget += unit_type.price
            self.pending_deliveries.sell({unit_type: 1})
        self.update_purchase_controls()
        self.update_available_budget()
        return True

    def update_purchase_controls(self) -> None:
        for group in self.purchase_groups.values():
            group.update_state()

    def enable_purchase(self, unit_type: UnitType) -> bool:
        return self.budget >= unit_type.price

    def enable_sale(self, unit_type: UnitType) -> bool:
        return True

    def info(self, unit_type: UnitType) -> None:
        self.info_window = QUnitInfoWindow(self.game_model.game, unit_type)
        self.info_window.show()

    def set_maximum_units(self, maximum_units):
        """
        Set the maximum number of units that can be bought
        """
        self.maximum_units = maximum_units
Exemple #2
0
 def info(self, unit_type: UnitType) -> None:
     self.info_window = QUnitInfoWindow(self.game_model.game, unit_type)
     self.info_window.show()
 def info(self, item: TransactionItemType) -> None:
     self.info_window = QUnitInfoWindow(
         self.game_model.game, self.purchase_adapter.unit_type_of(item)
     )
     self.info_window.show()
Exemple #4
0
class QRecruitBehaviour:
    game_model: GameModel
    cp: ControlPoint
    existing_units_labels = None
    bought_amount_labels = None
    maximum_units = -1
    recruitable_types = []
    BUDGET_FORMAT = "Available Budget: <b>${}M</b>"

    def __init__(self) -> None:
        self.bought_amount_labels = {}
        self.existing_units_labels = {}
        self.recruitable_types = []
        self.update_available_budget()

    @property
    def pending_deliveries(self) -> UnitsDeliveryEvent:
        return self.cp.pending_unit_deliveries

    @property
    def budget(self) -> int:
        return self.game_model.game.budget

    @budget.setter
    def budget(self, value: int) -> None:
        self.game_model.game.budget = value

    def add_purchase_row(self, unit_type: Type[UnitType], layout: QLayout,
                         row: int, disabled: bool = False) -> int:
        exist = QGroupBox()
        exist.setProperty("style", "buy-box")
        exist.setMaximumHeight(36)
        exist.setMinimumHeight(36)
        existLayout = QHBoxLayout()
        exist.setLayout(existLayout)

        existing_units = self.cp.base.total_units_of_type(unit_type)
        scheduled_units = self.pending_deliveries.units.get(unit_type, 0)

        unitName = QLabel("<b>" + db.unit_get_expanded_info(self.game_model.game.player_country, unit_type, 'name') + "</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("<b>{}</b>".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("<b>$ {:02d}</b> m".format(db.PRICES[unit_type]))
        price.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))

        buysell = QGroupBox()
        buysell.setProperty("style", "buy-box")
        buysell.setMaximumHeight(36)
        buysell.setMinimumHeight(36)
        buysellayout = QHBoxLayout()
        buysell.setLayout(buysellayout)

        buy = QPushButton("+")
        buy.setProperty("style", "btn-buy")
        buy.setDisabled(disabled)
        buy.setMinimumSize(16, 16)
        buy.setMaximumSize(16, 16)
        buy.clicked.connect(lambda: self.buy(unit_type))
        buy.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))

        sell = QPushButton("-")
        sell.setProperty("style", "btn-sell")
        sell.setDisabled(disabled)
        sell.setMinimumSize(16, 16)
        sell.setMaximumSize(16, 16)
        sell.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        sell.clicked.connect(lambda: self.sell(unit_type))

        info = QGroupBox()
        info.setProperty("style", "buy-box")
        info.setMaximumHeight(36)
        info.setMinimumHeight(36)
        infolayout = QHBoxLayout()
        info.setLayout(infolayout)
        
        unitInfo = QPushButton("i")
        unitInfo.setProperty("style", "btn-info")
        unitInfo.setDisabled(disabled)
        unitInfo.setMinimumSize(16, 16)
        unitInfo.setMaximumSize(16, 16)
        unitInfo.clicked.connect(lambda: self.info(unit_type))
        unitInfo.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))

        existLayout.addWidget(unitName)
        existLayout.addItem(QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum))
        existLayout.addWidget(existing_units)
        existLayout.addItem(QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum))
        existLayout.addWidget(price)

        buysellayout.addWidget(sell)
        buysellayout.addWidget(amount_bought)
        buysellayout.addWidget(buy)

        infolayout.addWidget(unitInfo)

        layout.addWidget(exist, row, 1)
        layout.addWidget(buysell, row, 2)
        layout.addWidget(info, row, 3)

        return row + 1

    def _update_count_label(self, unit_type: Type[UnitType]):

        self.bought_amount_labels[unit_type].setText("<b>{}</b>".format(
            unit_type in self.pending_deliveries.units and "{}".format(self.pending_deliveries.units[unit_type]) or "0"
        ))

        self.existing_units_labels[unit_type].setText("<b>{}</b>".format(
            self.cp.base.total_units_of_type(unit_type)
        ))

    def update_available_budget(self) -> None:
        GameUpdateSignal.get_instance().updateBudget(self.game_model.game)

    def buy(self, unit_type: Type[UnitType]):
        price = db.PRICES[unit_type]
        if self.budget >= price:
            self.pending_deliveries.order({unit_type: 1})
            self.budget -= price
        else:
            # TODO : display modal warning
            logging.info("Not enough money !")
        self._update_count_label(unit_type)
        self.update_available_budget()

    def sell(self, unit_type):
        if self.pending_deliveries.available_next_turn(unit_type) > 0:
            price = db.PRICES[unit_type]
            self.budget += price
            self.pending_deliveries.sell({unit_type: 1})
            if self.pending_deliveries.units[unit_type] == 0:
                del self.pending_deliveries.units[unit_type]
        self._update_count_label(unit_type)
        self.update_available_budget()

    def info(self, unit_type):
        self.info_window = QUnitInfoWindow(self.game_model.game, unit_type)
        self.info_window.show()

    def set_maximum_units(self, maximum_units):
        """
        Set the maximum number of units that can be bought
        """
        self.maximum_units = maximum_units

    def set_recruitable_types(self, recruitables_types):
        """
        Set the maximum number of units that can be bought
        """
        self.recruitables_types = recruitables_types
class UnitTransactionFrame(QFrame, Generic[TransactionItemType]):
    BUDGET_FORMAT = "Available Budget: <b>${:.2f}M</b>"

    def __init__(
        self,
        game_model: GameModel,
        purchase_adapter: PurchaseAdapter[TransactionItemType],
    ) -> None:
        super().__init__()
        self.game_model = game_model
        self.purchase_adapter = purchase_adapter
        self.existing_units_labels = {}
        self.purchase_groups: dict[
            TransactionItemType, PurchaseGroup[TransactionItemType]
        ] = {}
        self.update_available_budget()

    def current_quantity_of(self, item: TransactionItemType) -> int:
        return self.purchase_adapter.current_quantity_of(item)

    def pending_delivery_quantity(self, item: TransactionItemType) -> int:
        return self.purchase_adapter.pending_delivery_quantity(item)

    def expected_quantity_next_turn(self, item: TransactionItemType) -> int:
        return self.purchase_adapter.expected_quantity_next_turn(item)

    def display_name_of(
        self, item: TransactionItemType, multiline: bool = False
    ) -> str:
        return self.purchase_adapter.name_of(item, multiline)

    def price_of(self, item: TransactionItemType) -> int:
        return self.purchase_adapter.price_of(item)

    @property
    def budget(self) -> float:
        return self.game_model.game.blue.budget

    @budget.setter
    def budget(self, value: int) -> None:
        self.game_model.game.blue.budget = value

    def add_purchase_row(
        self,
        item: TransactionItemType,
        layout: QGridLayout,
        row: int,
    ) -> None:
        exist = QGroupBox()
        exist.setProperty("style", "buy-box")
        exist.setMaximumHeight(72)
        exist.setMinimumHeight(36)
        existLayout = QHBoxLayout()
        existLayout.setSizeConstraint(QLayout.SetMinimumSize)
        exist.setLayout(existLayout)

        existing_units = self.current_quantity_of(item)

        unitName = QLabel(f"<b>{self.display_name_of(item, multiline=True)}</b>")
        unitName.setSizePolicy(
            QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        )

        existing_units = QLabel(str(existing_units))
        existing_units.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))

        self.existing_units_labels[item] = existing_units

        price = QLabel(f"<b>$ {self.price_of(item)}</b> M")
        price.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))

        purchase_group = PurchaseGroup(item, self)
        self.purchase_groups[item] = purchase_group

        info = QGroupBox()
        info.setProperty("style", "buy-box")
        info.setMaximumHeight(72)
        info.setMinimumHeight(36)
        infolayout = QHBoxLayout()
        info.setLayout(infolayout)

        unitInfo = QPushButton("i")
        unitInfo.setProperty("style", "btn-info")
        unitInfo.setMinimumSize(16, 16)
        unitInfo.setMaximumSize(16, 16)
        unitInfo.clicked.connect(lambda: self.info(item))
        unitInfo.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))

        existLayout.addWidget(unitName)
        existLayout.addItem(
            QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum)
        )
        existLayout.addWidget(existing_units)
        existLayout.addItem(
            QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum)
        )
        existLayout.addWidget(price)

        infolayout.addWidget(unitInfo)

        layout.addWidget(exist, row, 1)
        layout.addWidget(purchase_group, row, 2)
        layout.addWidget(info, row, 3)

    def update_available_budget(self) -> None:
        GameUpdateSignal.get_instance().updateBudget(self.game_model.game)

    def recruit_handler(
        self, recruit_type: RecruitType, item: TransactionItemType
    ) -> None:
        # Lookup if Keyboard Modifiers were pressed
        # Shift = 10 times
        # CTRL = 5 Times
        modifiers = QApplication.keyboardModifiers()
        if modifiers == Qt.ShiftModifier:
            amount = 10
        elif modifiers == Qt.ControlModifier:
            amount = 5
        else:
            amount = 1

        if recruit_type == RecruitType.SELL:
            self.sell(item, amount)
        elif recruit_type == RecruitType.BUY:
            self.buy(item, amount)

    def post_transaction_update(self) -> None:
        self.update_purchase_controls()
        self.update_available_budget()

    def buy(self, item: TransactionItemType, quantity: int) -> None:
        try:
            self.purchase_adapter.buy(item, quantity)
        except TransactionError as ex:
            logging.exception(f"Purchase of {self.display_name_of(item)} failed")
            QMessageBox.warning(self, "Purchase failed", str(ex), QMessageBox.Ok)
        finally:
            self.post_transaction_update()

    def sell(self, item: TransactionItemType, quantity: int) -> None:
        try:
            self.purchase_adapter.sell(item, quantity)
        except TransactionError as ex:
            logging.exception(f"Sale of {self.display_name_of(item)} failed")
            QMessageBox.warning(self, "Sale failed", str(ex), QMessageBox.Ok)
        finally:
            self.post_transaction_update()

    def update_purchase_controls(self) -> None:
        for group in self.purchase_groups.values():
            group.update_state()

    def enable_purchase(self, item: TransactionItemType) -> bool:
        return self.purchase_adapter.can_buy(item)

    def enable_sale(self, item: TransactionItemType) -> bool:
        return self.purchase_adapter.can_sell_or_cancel(item)

    @staticmethod
    def purchase_tooltip(is_enabled: bool) -> str:
        if is_enabled:
            return "Buy unit. Use Shift or Ctrl key to buy multiple units at once."
        else:
            return "Unit can not be bought."

    @staticmethod
    def sell_tooltip(is_enabled: bool) -> str:
        if is_enabled:
            return "Sell unit. Use Shift or Ctrl key to buy multiple units at once."
        else:
            return "Unit can not be sold."

    def info(self, item: TransactionItemType) -> None:
        self.info_window = QUnitInfoWindow(
            self.game_model.game, self.purchase_adapter.unit_type_of(item)
        )
        self.info_window.show()