diff --git a/cockatrice/src/game/board/card_drag_item.cpp b/cockatrice/src/game/board/card_drag_item.cpp index 9eadadeda..5ae56ccba 100644 --- a/cockatrice/src/game/board/card_drag_item.cpp +++ b/cockatrice/src/game/board/card_drag_item.cpp @@ -13,9 +13,10 @@ CardDragItem::CardDragItem(CardItem *_item, int _id, const QPointF &_hotSpot, - bool _faceDown, + bool _forceFaceDown, AbstractCardDragItem *parentDrag) - : AbstractCardDragItem(_item, _hotSpot, parentDrag), id(_id), faceDown(_faceDown), occupied(false), currentZone(0) + : AbstractCardDragItem(_item, _hotSpot, parentDrag), id(_id), forceFaceDown(_forceFaceDown), occupied(false), + currentZone(0) { } diff --git a/cockatrice/src/game/board/card_drag_item.h b/cockatrice/src/game/board/card_drag_item.h index 257fde150..930c6be6f 100644 --- a/cockatrice/src/game/board/card_drag_item.h +++ b/cockatrice/src/game/board/card_drag_item.h @@ -16,7 +16,7 @@ class CardDragItem : public AbstractCardDragItem Q_OBJECT private: int id; - bool faceDown; + bool forceFaceDown; bool occupied; CardZone *currentZone; @@ -24,15 +24,15 @@ public: CardDragItem(CardItem *_item, int _id, const QPointF &_hotSpot, - bool _faceDown, + bool _forceFaceDown, AbstractCardDragItem *parentDrag = 0); int getId() const { return id; } - bool getFaceDown() const + bool isForceFaceDown() const { - return faceDown; + return forceFaceDown; } void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; void updatePosition(const QPointF &cursorScenePos) override; diff --git a/cockatrice/src/game/board/card_item.cpp b/cockatrice/src/game/board/card_item.cpp index 34c2f9a98..8b9549f07 100644 --- a/cockatrice/src/game/board/card_item.cpp +++ b/cockatrice/src/game/board/card_item.cpp @@ -212,10 +212,12 @@ void CardItem::setAttachedTo(CardItem *_attachedTo) } } +/** + * @brief Resets the fields that should be reset after a zone transition + */ void CardItem::resetState(bool keepAnnotations) { attacking = false; - facedown = false; counters.clear(); pt.clear(); if (!keepAnnotations) { @@ -251,10 +253,10 @@ void CardItem::processCardInfo(const ServerInfo_Card &_info) setDoesntUntap(_info.doesnt_untap()); } -CardDragItem *CardItem::createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool faceDown) +CardDragItem *CardItem::createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool forceFaceDown) { deleteDragItem(); - dragItem = new CardDragItem(this, _id, _pos, faceDown); + dragItem = new CardDragItem(this, _id, _pos, forceFaceDown); dragItem->setVisible(false); scene()->addItem(dragItem); dragItem->updatePosition(_scenePos); @@ -352,7 +354,7 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) // Use the buttonDownPos to align the hot spot with the position when // the user originally clicked - createDragItem(id, event->buttonDownPos(Qt::LeftButton), event->scenePos(), facedown || forceFaceDown); + createDragItem(id, event->buttonDownPos(Qt::LeftButton), event->scenePos(), forceFaceDown); dragItem->grabMouse(); int childIndex = 0; @@ -366,8 +368,7 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) childPos = card->pos() - pos(); else childPos = QPointF(childIndex * CARD_WIDTH / 2, 0); - CardDragItem *drag = - new CardDragItem(card, card->getId(), childPos, card->getFaceDown() || forceFaceDown, dragItem); + CardDragItem *drag = new CardDragItem(card, card->getId(), childPos, forceFaceDown, dragItem); drag->setPos(dragItem->pos() + childPos); scene()->addItem(drag); } diff --git a/cockatrice/src/game/board/card_item.h b/cockatrice/src/game/board/card_item.h index 86c4fe594..875c3f4d0 100644 --- a/cockatrice/src/game/board/card_item.h +++ b/cockatrice/src/game/board/card_item.h @@ -142,7 +142,7 @@ public: void processCardInfo(const ServerInfo_Card &_info); bool animationEvent(); - CardDragItem *createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool faceDown); + CardDragItem *createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool forceFaceDown); void deleteDragItem(); void drawArrow(const QColor &arrowColor); void drawAttachArrow(); diff --git a/cockatrice/src/game/log/message_log_widget.cpp b/cockatrice/src/game/log/message_log_widget.cpp index 1ff3e32ff..645974994 100644 --- a/cockatrice/src/game/log/message_log_widget.cpp +++ b/cockatrice/src/game/log/message_log_widget.cpp @@ -314,9 +314,17 @@ void MessageLogWidget::logMoveCard(Player *player, finalStr = tr("%1 puts %2 into play%3."); } } else if (targetZoneName == GRAVE_ZONE_NAME) { - finalStr = tr("%1 puts %2%3 into their graveyard."); + if (card->getFaceDown()) { + finalStr = tr("%1 puts %2%3 into their graveyard face down."); + } else { + finalStr = tr("%1 puts %2%3 into their graveyard."); + } } else if (targetZoneName == EXILE_ZONE_NAME) { - finalStr = tr("%1 exiles %2%3."); + if (card->getFaceDown()) { + finalStr = tr("%1 exiles %2%3 face down."); + } else { + finalStr = tr("%1 exiles %2%3."); + } } else if (targetZoneName == HAND_ZONE_NAME) { finalStr = tr("%1 moves %2%3 to their hand."); } else if (targetZoneName == DECK_ZONE_NAME) { @@ -335,10 +343,18 @@ void MessageLogWidget::logMoveCard(Player *player, finalStr = tr("%1 moves %2%3 to sideboard."); } else if (targetZoneName == STACK_ZONE_NAME) { soundEngine->playSound("play_card"); - finalStr = tr("%1 plays %2%3."); + if (card->getFaceDown()) { + finalStr = tr("%1 plays %2%3 face down."); + } else { + finalStr = tr("%1 plays %2%3."); + } } else { fourthArg = targetZoneName; - finalStr = tr("%1 moves %2%3 to custom zone '%4'."); + if (card->getFaceDown()) { + finalStr = tr("%1 moves %2%3 to custom zone '%4' face down."); + } else { + finalStr = tr("%1 moves %2%3 to custom zone '%4'."); + } } QString message = finalStr.arg(sanitizeHtml(player->getPlayerInfo()->getName()), cardStr, nameFrom.second); diff --git a/cockatrice/src/game/player/player_actions.cpp b/cockatrice/src/game/player/player_actions.cpp index ed77808b0..1a09836e4 100644 --- a/cockatrice/src/game/player/player_actions.cpp +++ b/cockatrice/src/game/player/player_actions.cpp @@ -424,37 +424,15 @@ void PlayerActions::actMoveTopCardToExile() void PlayerActions::actMoveTopCardsToGrave() { - const int maxCards = player->getDeckZone()->getCards().size(); - if (maxCards == 0) { - return; - } - - bool ok; - int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Move top cards to grave"), - tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberTopCards, 1, - maxCards, 1, &ok); - if (!ok) { - return; - } else if (number > maxCards) { - number = maxCards; - } - defaultNumberTopCards = number; - - Command_MoveCard cmd; - cmd.set_start_zone("deck"); - cmd.set_target_player_id(player->getPlayerInfo()->getId()); - cmd.set_target_zone("grave"); - cmd.set_x(0); - cmd.set_y(0); - - for (int i = number - 1; i >= 0; --i) { - cmd.mutable_cards_to_move()->add_card()->set_card_id(i); - } - - sendGameCommand(cmd); + moveTopCardsTo("grave", tr("grave")); } void PlayerActions::actMoveTopCardsToExile() +{ + moveTopCardsTo("rfg", tr("exile")); +} + +void PlayerActions::moveTopCardsTo(const QString &targetZone, const QString &zoneDisplayName) { const int maxCards = player->getDeckZone()->getCards().size(); if (maxCards == 0) { @@ -462,12 +440,14 @@ void PlayerActions::actMoveTopCardsToExile() } bool ok; - int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Move top cards to exile"), + int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Move top cards to %1").arg(zoneDisplayName), tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberTopCards, 1, maxCards, 1, &ok); if (!ok) { return; - } else if (number > maxCards) { + } + + if (number > maxCards) { number = maxCards; } defaultNumberTopCards = number; @@ -475,7 +455,7 @@ void PlayerActions::actMoveTopCardsToExile() Command_MoveCard cmd; cmd.set_start_zone("deck"); cmd.set_target_player_id(player->getPlayerInfo()->getId()); - cmd.set_target_zone("rfg"); + cmd.set_target_zone(targetZone.toStdString()); cmd.set_x(0); cmd.set_y(0); @@ -628,37 +608,15 @@ void PlayerActions::actMoveBottomCardToExile() void PlayerActions::actMoveBottomCardsToGrave() { - const int maxCards = player->getDeckZone()->getCards().size(); - if (maxCards == 0) { - return; - } - - bool ok; - int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Move bottom cards to grave"), - tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberBottomCards, 1, - maxCards, 1, &ok); - if (!ok) { - return; - } else if (number > maxCards) { - number = maxCards; - } - defaultNumberBottomCards = number; - - Command_MoveCard cmd; - cmd.set_start_zone("deck"); - cmd.set_target_player_id(player->getPlayerInfo()->getId()); - cmd.set_target_zone("grave"); - cmd.set_x(0); - cmd.set_y(0); - - for (int i = maxCards - number; i < maxCards; ++i) { - cmd.mutable_cards_to_move()->add_card()->set_card_id(i); - } - - sendGameCommand(cmd); + moveBottomCardsTo("grave", tr("grave")); } void PlayerActions::actMoveBottomCardsToExile() +{ + moveBottomCardsTo("rfg", tr("exile")); +} + +void PlayerActions::moveBottomCardsTo(const QString &targetZone, const QString &zoneDisplayName) { const int maxCards = player->getDeckZone()->getCards().size(); if (maxCards == 0) { @@ -666,12 +624,14 @@ void PlayerActions::actMoveBottomCardsToExile() } bool ok; - int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Move bottom cards to exile"), + int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Move bottom cards to %1").arg(zoneDisplayName), tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberBottomCards, 1, maxCards, 1, &ok); if (!ok) { return; - } else if (number > maxCards) { + } + + if (number > maxCards) { number = maxCards; } defaultNumberBottomCards = number; @@ -679,7 +639,7 @@ void PlayerActions::actMoveBottomCardsToExile() Command_MoveCard cmd; cmd.set_start_zone("deck"); cmd.set_target_player_id(player->getPlayerInfo()->getId()); - cmd.set_target_zone("rfg"); + cmd.set_target_zone(targetZone.toStdString()); cmd.set_x(0); cmd.set_y(0); diff --git a/cockatrice/src/game/player/player_actions.h b/cockatrice/src/game/player/player_actions.h index b294b5946..beed2c241 100644 --- a/cockatrice/src/game/player/player_actions.h +++ b/cockatrice/src/game/player/player_actions.h @@ -180,6 +180,9 @@ private: FilterString movingCardsUntilFilter; int movingCardsUntilCounter = 0; + void moveTopCardsTo(const QString &targetZone, const QString &zoneDisplayName); + void moveBottomCardsTo(const QString &targetZone, const QString &zoneDisplayName); + void createCard(const CardItem *sourceCard, const QString &dbCardName, CardRelationType attach = CardRelationType::DoesNotAttach, diff --git a/cockatrice/src/game/zones/logic/card_zone_logic.cpp b/cockatrice/src/game/zones/logic/card_zone_logic.cpp index bd32eab3e..1872ba95e 100644 --- a/cockatrice/src/game/zones/logic/card_zone_logic.cpp +++ b/cockatrice/src/game/zones/logic/card_zone_logic.cpp @@ -43,8 +43,10 @@ void CardZoneLogic::addCard(CardItem *card, const bool reorganize, const int x, for (auto *view : views) { if (qobject_cast(view->getLogic())->prepareAddCard(x)) { - view->getLogic()->addCard(new CardItem(player, nullptr, card->getCardRef(), card->getId()), reorganize, x, - y); + auto copy = new CardItem(player, nullptr, card->getCardRef(), card->getId()); + copy->setFaceDown(card->getFaceDown()); + + view->getLogic()->addCard(copy, reorganize, x, y); } } diff --git a/cockatrice/src/game/zones/pile_zone.cpp b/cockatrice/src/game/zones/pile_zone.cpp index 2d1390826..87a60fc03 100644 --- a/cockatrice/src/game/zones/pile_zone.cpp +++ b/cockatrice/src/game/zones/pile_zone.cpp @@ -68,8 +68,13 @@ void PileZone::handleDropEvent(const QList &dragItems, CardZoneL cmd.set_x(0); cmd.set_y(0); - for (int i = 0; i < dragItems.size(); ++i) - cmd.mutable_cards_to_move()->add_card()->set_card_id(dragItems[i]->getId()); + for (int i = 0; i < dragItems.size(); ++i) { + auto cardToMove = cmd.mutable_cards_to_move()->add_card(); + cardToMove->set_card_id(dragItems[i]->getId()); + if (dragItems[i]->isForceFaceDown()) { + cardToMove->set_face_down(true); + } + } getLogic()->getPlayer()->getPlayerActions()->sendGameCommand(cmd); } @@ -101,12 +106,12 @@ void PileZone::mouseMoveEvent(QGraphicsSceneMouseEvent *event) if (getLogic()->getCards().isEmpty()) return; - bool faceDown = event->modifiers().testFlag(Qt::ShiftModifier); + bool forceFaceDown = event->modifiers().testFlag(Qt::ShiftModifier); bool bottomCard = event->modifiers().testFlag(Qt::ControlModifier); CardItem *card = bottomCard ? getLogic()->getCards().last() : getLogic()->getCards().first(); const int cardid = getLogic()->contentsKnown() ? card->getId() : (bottomCard ? getLogic()->getCards().size() - 1 : 0); - CardDragItem *drag = card->createDragItem(cardid, event->pos(), event->scenePos(), faceDown); + CardDragItem *drag = card->createDragItem(cardid, event->pos(), event->scenePos(), forceFaceDown); drag->grabMouse(); setCursor(Qt::OpenHandCursor); } diff --git a/cockatrice/src/game/zones/stack_zone.cpp b/cockatrice/src/game/zones/stack_zone.cpp index 820008b27..a9d649a4a 100644 --- a/cockatrice/src/game/zones/stack_zone.cpp +++ b/cockatrice/src/game/zones/stack_zone.cpp @@ -78,7 +78,11 @@ void StackZone::handleDropEvent(const QList &dragItems, for (CardDragItem *item : dragItems) { if (item) { - cmd.mutable_cards_to_move()->add_card()->set_card_id(item->getId()); + auto cardToMove = cmd.mutable_cards_to_move()->add_card(); + cardToMove->set_card_id(item->getId()); + if (item->isForceFaceDown()) { + cardToMove->set_face_down(true); + } } } diff --git a/cockatrice/src/game/zones/table_zone.cpp b/cockatrice/src/game/zones/table_zone.cpp index c76514350..ca1052d20 100644 --- a/cockatrice/src/game/zones/table_zone.cpp +++ b/cockatrice/src/game/zones/table_zone.cpp @@ -134,8 +134,10 @@ void TableZone::handleDropEventByGrid(const QList &dragItems, for (const auto &item : dragItems) { CardToMove *ctm = cmd.mutable_cards_to_move()->add_card(); ctm->set_card_id(item->getId()); - ctm->set_face_down(item->getFaceDown()); - if (startZone->getName() != getLogic()->getName() && !item->getFaceDown()) { + if (item->isForceFaceDown()) { + ctm->set_face_down(true); + } + if (startZone->getName() != getLogic()->getName() && !item->isForceFaceDown()) { const auto &card = item->getItem()->getCard(); if (card) { ctm->set_pt(card.getInfo().getPowTough().toStdString()); diff --git a/cockatrice/src/game/zones/view_zone.cpp b/cockatrice/src/game/zones/view_zone.cpp index 4ae25989e..348ed6e87 100644 --- a/cockatrice/src/game/zones/view_zone.cpp +++ b/cockatrice/src/game/zones/view_zone.cpp @@ -73,7 +73,10 @@ void ZoneViewZone::initializeCards(const QList &cardLis for (int i = 0; i < cardList.size(); ++i) { auto card = cardList[i]; CardRef cardRef = {QString::fromStdString(card->name()), QString::fromStdString(card->provider_id())}; - getLogic()->addCard(new CardItem(getLogic()->getPlayer(), this, cardRef, card->id()), false, i); + auto copy = new CardItem(getLogic()->getPlayer(), this, cardRef, card->id()); + copy->setFaceDown(card->face_down()); + + getLogic()->addCard(copy, false, i); } reorganizeCards(); } else if (!qobject_cast(getLogic())->getOriginalZone()->contentsKnown()) { @@ -91,8 +94,10 @@ void ZoneViewZone::initializeCards(const QList &cardLis int number = numberCards == -1 ? c.size() : (numberCards < c.size() ? numberCards : c.size()); for (int i = 0; i < number; i++) { CardItem *card = c.at(i); - getLogic()->addCard(new CardItem(getLogic()->getPlayer(), this, card->getCardRef(), card->getId()), false, - i); + auto copy = new CardItem(getLogic()->getPlayer(), this, card->getCardRef(), card->getId()); + copy->setFaceDown(card->getFaceDown()); + + getLogic()->addCard(copy, false, i); } reorganizeCards(); } @@ -107,6 +112,7 @@ void ZoneViewZone::zoneDumpReceived(const Response &r) auto cardName = QString::fromStdString(cardInfo.name()); auto cardProviderId = QString::fromStdString(cardInfo.provider_id()); auto card = new CardItem(getLogic()->getPlayer(), this, {cardName, cardProviderId}, cardInfo.id(), getLogic()); + card->setFaceDown(cardInfo.face_down()); getLogic()->rawInsertCard(card, i); } @@ -279,8 +285,13 @@ void ZoneViewZone::handleDropEvent(const QList &dragItems, cmd.set_y(0); cmd.set_is_reversed(qobject_cast(getLogic())->getIsReversed()); - for (int i = 0; i < dragItems.size(); ++i) - cmd.mutable_cards_to_move()->add_card()->set_card_id(dragItems[i]->getId()); + for (int i = 0; i < dragItems.size(); ++i) { + auto cardToMove = cmd.mutable_cards_to_move()->add_card(); + cardToMove->set_card_id(dragItems[i]->getId()); + if (dragItems[i]->isForceFaceDown()) { + cardToMove->set_face_down(true); + } + } getLogic()->getPlayer()->getPlayerActions()->sendGameCommand(cmd); } diff --git a/cockatrice/src/interface/widgets/cards/card_info_picture_art_crop_widget.cpp b/cockatrice/src/interface/widgets/cards/card_info_picture_art_crop_widget.cpp index 451104d17..e5b0c4872 100644 --- a/cockatrice/src/interface/widgets/cards/card_info_picture_art_crop_widget.cpp +++ b/cockatrice/src/interface/widgets/cards/card_info_picture_art_crop_widget.cpp @@ -8,7 +8,7 @@ CardInfoPictureArtCropWidget::CardInfoPictureArtCropWidget(QWidget *parent) hide(); } -QPixmap CardInfoPictureArtCropWidget::getProcessedBackground(const QSize &targetSize) +QPixmap CardInfoPictureArtCropWidget::getBackground() { // Load the full-resolution card image, not a pre-scaled one QPixmap fullResPixmap; @@ -17,10 +17,8 @@ QPixmap CardInfoPictureArtCropWidget::getProcessedBackground(const QSize &target } else { CardPictureLoader::getCardBackPixmap(fullResPixmap, QSize(745, 1040)); } - - // Fail-safe if loading failed if (fullResPixmap.isNull()) { - return QPixmap(targetSize); + return QPixmap(); // return null qpixmap } const QSize sz = fullResPixmap.size(); @@ -33,9 +31,7 @@ QPixmap CardInfoPictureArtCropWidget::getProcessedBackground(const QSize &target foilRect = foilRect.intersected(fullResPixmap.rect()); // always clamp to source bounds - // Crop first, then scale for best quality + // return full resolution image crop QPixmap cropped = fullResPixmap.copy(foilRect); - QPixmap scaled = cropped.scaled(targetSize, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); - - return scaled; + return cropped; } diff --git a/cockatrice/src/interface/widgets/cards/card_info_picture_art_crop_widget.h b/cockatrice/src/interface/widgets/cards/card_info_picture_art_crop_widget.h index aed951cc6..0185f758c 100644 --- a/cockatrice/src/interface/widgets/cards/card_info_picture_art_crop_widget.h +++ b/cockatrice/src/interface/widgets/cards/card_info_picture_art_crop_widget.h @@ -16,8 +16,8 @@ class CardInfoPictureArtCropWidget : public CardInfoPictureWidget public: explicit CardInfoPictureArtCropWidget(QWidget *parent = nullptr); - // Returns a processed (cropped & scaled) version of the pixmap - QPixmap getProcessedBackground(const QSize &targetSize); + // Returns a cropped version of the pixmap + QPixmap getBackground(); }; #endif // CARD_INFO_PICTURE_ART_CROP_WIDGET_H diff --git a/cockatrice/src/interface/widgets/general/home_widget.cpp b/cockatrice/src/interface/widgets/general/home_widget.cpp index 269326257..750ddd000 100644 --- a/cockatrice/src/interface/widgets/general/home_widget.cpp +++ b/cockatrice/src/interface/widgets/general/home_widget.cpp @@ -58,20 +58,24 @@ void HomeWidget::initializeBackgroundFromSource() auto backgroundSourceType = BackgroundSources::fromId(SettingsCache::instance().getHomeTabBackgroundSource()); - cardChangeTimer->stop(); - switch (backgroundSourceType) { case BackgroundSources::Theme: + cardChangeTimer->stop(); background = QPixmap("theme:backgrounds/home"); + backgroundSourceDeck = DeckList(); + backgroundSourceCard->setCard(ExactCard()); updateButtonsToBackgroundColor(); update(); break; case BackgroundSources::RandomCardArt: - cardChangeTimer->start(SettingsCache::instance().getHomeTabBackgroundShuffleFrequency() * 1000); + backgroundSourceDeck = DeckList(); + updateRandomCard(); + onBackgroundShuffleFrequencyChanged(); break; case BackgroundSources::DeckFileArt: loadBackgroundSourceDeck(); - cardChangeTimer->start(SettingsCache::instance().getHomeTabBackgroundShuffleFrequency() * 1000); + updateRandomCard(); + onBackgroundShuffleFrequencyChanged(); break; } } @@ -83,6 +87,20 @@ void HomeWidget::loadBackgroundSourceDeck() backgroundSourceDeck = deckOpt.has_value() ? deckOpt.value().deckList : DeckList(); } +void HomeWidget::setRandomCard(ExactCard &newCard) +{ + static constexpr int ATTEMPTS = 10; + for (int i = 0; i < ATTEMPTS; ++i) { + ExactCard tmpCard = CardDatabaseManager::query()->getRandomCard(); + if (tmpCard != backgroundSourceCard->getCard() && tmpCard.getCardPtr()->getProperty("layout") == "normal" && + tmpCard.getPrinting().getSet() != nullptr) { + newCard = tmpCard; + return; + } + } + qWarning() << "failed to set random card image after" << ATTEMPTS << "attempts"; +} + void HomeWidget::updateRandomCard() { auto backgroundSourceType = BackgroundSources::fromId(SettingsCache::instance().getHomeTabBackgroundSource()); @@ -93,10 +111,7 @@ void HomeWidget::updateRandomCard() case BackgroundSources::Theme: break; case BackgroundSources::RandomCardArt: - do { - newCard = CardDatabaseManager::query()->getRandomCard(); - } while (newCard == backgroundSourceCard->getCard() && - newCard.getCardPtr()->getProperty("layout") != "normal"); + setRandomCard(newCard); break; case BackgroundSources::DeckFileArt: QList cardRefs = backgroundSourceDeck.getCardRefList(); @@ -124,25 +139,20 @@ void HomeWidget::updateRandomCard() connect(newCard.getCardPtr().data(), &CardInfo::pixmapUpdated, this, &HomeWidget::updateBackgroundProperties); backgroundSourceCard->setCard(newCard); - background = backgroundSourceCard->getProcessedBackground(size()); - - if (SettingsCache::instance().getHomeTabBackgroundShuffleFrequency() <= 0) { - cardChangeTimer->stop(); - } + background = backgroundSourceCard->getBackground(); } void HomeWidget::onBackgroundShuffleFrequencyChanged() { cardChangeTimer->stop(); - if (SettingsCache::instance().getHomeTabBackgroundShuffleFrequency() <= 0) { - return; + if (SettingsCache::instance().getHomeTabBackgroundShuffleFrequency() > 0) { + cardChangeTimer->start(SettingsCache::instance().getHomeTabBackgroundShuffleFrequency() * 1000); } - cardChangeTimer->start(SettingsCache::instance().getHomeTabBackgroundShuffleFrequency() * 1000); } void HomeWidget::updateBackgroundProperties() { - background = backgroundSourceCard->getProcessedBackground(size()); + background = backgroundSourceCard->getBackground(); updateButtonsToBackgroundColor(); update(); // Triggers repaint } @@ -300,14 +310,17 @@ void HomeWidget::paintEvent(QPaintEvent *event) QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); - background = background.scaled(size(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); + if (!background.isNull()) { + QSize widgetSize = size() * devicePixelRatio(); + QPixmap toDraw = background.scaled(widgetSize, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); - // Draw already-scaled background centered - QSize widgetSize = size(); - QSize bgSize = background.size(); - QPoint topLeft((widgetSize.width() - bgSize.width()) / 2, (widgetSize.height() - bgSize.height()) / 2); + // Draw scaled background centered + QSize bgSize = toDraw.size(); + QPoint topLeft((widgetSize.width() - bgSize.width()) / (devicePixelRatio() * 2), // undo scaling for painter + (widgetSize.height() - bgSize.height()) / (devicePixelRatio() * 2)); - painter.drawPixmap(topLeft, background); + painter.drawPixmap(topLeft, toDraw); + } // Draw translucent black overlay with rounded corners QRectF overlayRect(5, 5, width() - 10, height() - 10); @@ -321,8 +334,11 @@ void HomeWidget::paintEvent(QPaintEvent *event) QString cardName; ExactCard card = backgroundSourceCard->getCard(); if (card) { - cardName = card.getCardPtr()->getName() + " (" + card.getPrinting().getSet()->getCorrectedShortName() + ") " + - card.getPrinting().getProperty("num"); + cardName = card.getCardPtr()->getName(); + if (card.getPrinting().getSet() != nullptr) { + cardName += " (" + card.getPrinting().getSet()->getCorrectedShortName() + ") " + + card.getPrinting().getProperty("num"); + } } if (!cardName.isEmpty() && SettingsCache::instance().getHomeTabDisplayCardName()) { diff --git a/cockatrice/src/interface/widgets/general/home_widget.h b/cockatrice/src/interface/widgets/general/home_widget.h index 233fda543..b30bb5407 100644 --- a/cockatrice/src/interface/widgets/general/home_widget.h +++ b/cockatrice/src/interface/widgets/general/home_widget.h @@ -45,6 +45,7 @@ private: QPair gradientColors; HomeStyledButton *connectButton; + void setRandomCard(ExactCard &newCard); void loadBackgroundSourceDeck(); }; diff --git a/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.cpp b/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.cpp index b08495bad..00561bef2 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.cpp +++ b/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.cpp @@ -198,6 +198,35 @@ shouldDestroyOnMove(const Server_Card *card, const Server_CardZone *startZone, c return true; } +/** + * @brief Determines whether the moved card should be face-down + */ +static bool +shouldBeFaceDown(const MoveCardStruct &cardStruct, const Server_CardZone *startZone, const Server_CardZone *targetZone) +{ + if (!targetZone) { + return false; + } + + // being face-down only makes sense for public zones + if (targetZone->getType() != ServerInfo_Zone::PublicZone) { + return false; + } + + // face-down property in proto takes precedence + if (cardStruct.cardToMove->has_face_down()) { + return cardStruct.cardToMove->face_down(); + } + + // Default to keep face-down the same if zone didn't change. + // Compare using zone names because face-down is maintained when changing controllers. + if (startZone && startZone->getName() == targetZone->getName()) { + return cardStruct.card->getFaceDown(); + } + + return false; +} + Response::ResponseCode Server_AbstractPlayer::moveCard(GameEventStorage &ges, Server_CardZone *startzone, const QList &_cards, @@ -257,10 +286,7 @@ Response::ResponseCode Server_AbstractPlayer::moveCard(GameEventStorage &ges, for (auto cardStruct : cardsToMove) { Server_Card *card = cardStruct.card; - const CardToMove *thisCardProperties = cardStruct.cardToMove; int originalPosition = cardStruct.position; - bool faceDown = targetzone->hasCoords() && - (thisCardProperties->has_face_down() ? thisCardProperties->face_down() : card->getFaceDown()); bool sourceBeingLookedAt; int position = startzone->removeCard(card, sourceBeingLookedAt); @@ -315,6 +341,8 @@ Response::ResponseCode Server_AbstractPlayer::moveCard(GameEventStorage &ges, ++xIndex; int newX = isReversed ? targetzone->getCards().size() - xCoord + xIndex : xCoord + xIndex; + bool faceDown = shouldBeFaceDown(cardStruct, startzone, targetzone); + if (targetzone->hasCoords()) { newX = targetzone->getFreeGridColumn(newX, yCoord, card->getName(), faceDown); } else { diff --git a/libcockatrice_protocol/libcockatrice/protocol/pb/command_move_card.proto b/libcockatrice_protocol/libcockatrice/protocol/pb/command_move_card.proto index 6e9301d27..a5b96da2e 100644 --- a/libcockatrice_protocol/libcockatrice/protocol/pb/command_move_card.proto +++ b/libcockatrice_protocol/libcockatrice/protocol/pb/command_move_card.proto @@ -6,7 +6,9 @@ message CardToMove { // Id of the card in its current zone optional sint32 card_id = 1 [default = -1]; - // Places the card face down, hiding its name + // If true, places the card face down, hiding its name. + // If false, forcibly turns the card face up. + // If not set, defers the resulting face down state to the server. optional bool face_down = 2; // When moving add this value to the power/toughness field of the card