From 16caae5e5a31d37ff192a2332851231d345e4032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Wed, 7 Oct 2026 10:08:54 +0200 Subject: [PATCH] [Refactor] Move card item creation out of game logic --- cockatrice/src/game/abstract_game.h | 1 - cockatrice/src/game/board/card_state.h | 10 ++- .../src/game/player/player_event_handler.cpp | 64 +++++++++++-------- .../src/game/player/player_event_handler.h | 7 +- cockatrice/src/game/player/player_logic.cpp | 19 +++--- cockatrice/src/game/player/player_logic.h | 4 +- cockatrice/src/game/zones/card_zone_logic.cpp | 23 ++++--- cockatrice/src/game/zones/card_zone_logic.h | 5 +- cockatrice/src/game/zones/view_zone_logic.cpp | 2 +- .../src/game_graphics/board/card_item.cpp | 18 ++++-- .../src/game_graphics/board/card_item.h | 6 +- cockatrice/src/game_graphics/game_scene.cpp | 12 ++-- cockatrice/src/game_graphics/game_scene.h | 2 +- .../game_graphics/player/menu/player_menu.cpp | 8 ++- .../game_graphics/player/menu/player_menu.h | 4 +- .../src/game_graphics/zones/card_zone.cpp | 9 +++ .../src/game_graphics/zones/card_zone.h | 2 + .../src/game_graphics/zones/table_zone.cpp | 7 +- 18 files changed, 121 insertions(+), 82 deletions(-) diff --git a/cockatrice/src/game/abstract_game.h b/cockatrice/src/game/abstract_game.h index 4bf8c120e..00a95a3b8 100644 --- a/cockatrice/src/game/abstract_game.h +++ b/cockatrice/src/game/abstract_game.h @@ -11,7 +11,6 @@ #include #include -class CardItem; class AbstractClient; class CardState; class GameEventHandler; diff --git a/cockatrice/src/game/board/card_state.h b/cockatrice/src/game/board/card_state.h index bce5a298d..fa1e81393 100644 --- a/cockatrice/src/game/board/card_state.h +++ b/cockatrice/src/game/board/card_state.h @@ -12,8 +12,6 @@ #include class CardZoneLogic; -class CardItem; - class CardState : public QObject { Q_OBJECT @@ -35,7 +33,7 @@ private: QString color; CardState *attachedTo = nullptr; - QList attachedCards; + QList attachedCards; CardZoneLogic *zone = nullptr; signals: @@ -226,17 +224,17 @@ public: void setAttachedTo(CardState *_attachedTo); - void addAttachedCard(CardItem *card) + void addAttachedCard(CardState *card) { attachedCards.append(card); } - void removeAttachedCard(CardItem *card) + void removeAttachedCard(CardState *card) { attachedCards.removeOne(card); } - const QList &getAttachedCards() const + const QList &getAttachedCards() const { return attachedCards; } diff --git a/cockatrice/src/game/player/player_event_handler.cpp b/cockatrice/src/game/player/player_event_handler.cpp index 8b2ea0024..2ca05106d 100644 --- a/cockatrice/src/game/player/player_event_handler.cpp +++ b/cockatrice/src/game/player/player_event_handler.cpp @@ -1,9 +1,9 @@ #include "player_event_handler.h" -#include "../../game_graphics/board/card_item.h" #include "../abstract_game.h" #include "../board/arrow_data.h" #include "../board/card_list.h" +#include "../board/card_state.h" #include "../board/counter_state.h" #include "../zones/card_zone_logic.h" #include "../zones/hand_zone_logic.h" @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include #include @@ -49,15 +51,11 @@ #include #include #include +#include #include #include #include -static CardItem *toCardItem(CardState *card) -{ - return card == nullptr ? nullptr : qobject_cast(card->parent()); -} - PlayerEventHandler::PlayerEventHandler(PlayerLogic *_player) : QObject(_player), player(_player) { connect(this, &PlayerEventHandler::requestCardMenuUpdate, player, &PlayerLogic::requestCardMenuUpdate); @@ -160,23 +158,29 @@ void PlayerEventHandler::eventCreateToken(const Event_CreateToken &event) } CardRef cardRef = {QString::fromStdString(event.card_name()), QString::fromStdString(event.card_provider_id())}; - CardItem *card = new CardItem(player, nullptr, cardRef, event.card_id()); // use db PT if not provided in event and not face-down - if (!QString::fromStdString(event.pt()).isEmpty()) { - card->setPT(QString::fromStdString(event.pt())); - } else if (!event.face_down()) { - ExactCard dbCard = card->getCard(); + QString pt = QString::fromStdString(event.pt()); + if (pt.isEmpty() && !event.face_down()) { + ExactCard dbCard = CardDatabaseManager::query()->getCard(cardRef); if (dbCard) { - card->setPT(dbCard.getInfo().getPowTough()); + pt = dbCard.getInfo().getPowTough(); } } - card->setColor(QString::fromStdString(event.color())); - card->setAnnotation(QString::fromStdString(event.annotation())); - card->setDestroyOnZoneChange(event.destroy_on_zone_change()); - card->setFaceDown(event.face_down()); - emit logCreateToken(player, card->getName(), card->getPT(), card->getFaceDown()); - zone->addCard(card->getState(), true, event.x(), event.y()); + emit logCreateToken(player, cardRef.name, pt, event.face_down()); + + ServerInfo_Card cardInfo; + cardInfo.set_id(event.card_id()); + cardInfo.set_name(event.card_name()); + cardInfo.set_provider_id(event.card_provider_id()); + cardInfo.set_pt(pt.toStdString()); + cardInfo.set_color(event.color()); + cardInfo.set_annotation(event.annotation()); + cardInfo.set_destroy_on_zone_change(event.destroy_on_zone_change()); + cardInfo.set_face_down(event.face_down()); + cardInfo.set_x(event.x()); + cardInfo.set_y(event.y()); + emit zone->requestCreateCard(cardInfo, true); } void PlayerEventHandler::eventSetCardAttr(const Event_SetCardAttr &event, @@ -276,7 +280,7 @@ void PlayerEventHandler::eventSetCardCounter(const Event_SetCardCounter &event) int oldValue = card->getCounters().value(event.counter_id(), 0); card->setCounter(event.counter_id(), event.counter_value()); - emit requestCardMenuUpdate(toCardItem(card)); + emit requestCardMenuUpdate(card); emit logSetCardCounter(player, card->getName(), event.counter_id(), event.counter_value(), oldValue); } @@ -375,9 +379,9 @@ void PlayerEventHandler::eventMoveCard(const Event_MoveCard &event, const GameEv card->setId(event.new_card_id()); card->setFaceDown(event.face_down()); if (startZone != targetZone) { - const QList &attachedCards = card->getAttachedCards(); + const QList &attachedCards = card->getAttachedCards(); for (auto attachedCard : attachedCards) { - emit targetZone->cardAdded(attachedCard->getState()); + emit targetZone->cardAdded(attachedCard); } } @@ -391,8 +395,8 @@ void PlayerEventHandler::eventMoveCard(const Event_MoveCard &event, const GameEv targetZone->addCard(card, true, x, y); - emit cardZoneChanged(toCardItem(card), startZone == targetZone); - emit requestCardMenuUpdate(toCardItem(card)); + emit cardZoneChanged(card, startZone == targetZone); + emit requestCardMenuUpdate(card); if (player->getPlayerActions()->isMovingCardsUntil() && startZoneString == ZoneNames::DECK && targetZone->getName() == ZoneNames::STACK) { @@ -419,7 +423,7 @@ void PlayerEventHandler::eventFlipCard(const Event_FlipCard &event) emit logFlipCard(player, card->getName(), event.face_down()); card->setFaceDown(event.face_down()); - emit requestCardMenuUpdate(toCardItem(card)); + emit requestCardMenuUpdate(card); } void PlayerEventHandler::eventDestroyCard(const Event_DestroyCard &event) @@ -434,10 +438,18 @@ void PlayerEventHandler::eventDestroyCard(const Event_DestroyCard &event) return; } - QList attachedCards = card->getAttachedCards(); + QList attachedCards = card->getAttachedCards(); // This list is always empty except for buggy server implementations. for (auto &attachedCard : attachedCards) { + card->removeAttachedCard(attachedCard); + attachedCard->setGridPoint(QPoint(-1, attachedCard->getGridPoint().y())); attachedCard->setAttachedTo(nullptr); + if (attachedCard->getZone() == nullptr) { + attachedCard->deleteView(); + } else { + emit attachedCard->getZone()->cardAdded(attachedCard); + attachedCard->getZone()->reorganizeCards(); + } } emit logDestroyCard(player, card->getName()); @@ -495,7 +507,7 @@ void PlayerEventHandler::eventAttachCard(const Event_AttachCard &event) } else { emit logUnattachCard(player, startCard->getName()); } - emit requestCardMenuUpdate(toCardItem(startCard)); + emit requestCardMenuUpdate(startCard); } void PlayerEventHandler::eventDrawCards(const Event_DrawCards &event) diff --git a/cockatrice/src/game/player/player_event_handler.h b/cockatrice/src/game/player/player_event_handler.h index 6b721bf61..d253deef0 100644 --- a/cockatrice/src/game/player/player_event_handler.h +++ b/cockatrice/src/game/player/player_event_handler.h @@ -27,7 +27,6 @@ #include #include -class CardItem; class CardState; class CardZoneLogic; class PlayerLogic; @@ -62,7 +61,7 @@ template class QList; * Design notes: * - All event handlers assume events are authoritative and already validated * by the server. - * - Most handlers mutate both logical state (CardItem, CardZoneLogic, counters) + * - Most handlers mutate both logical state (CardState, CardZoneLogic, counters) * and visual/UI state (views, arrows, menus). * - Logging signals are emitted *after* or *during* state mutation, depending * on whether later mutations would invalidate log data. @@ -267,8 +266,8 @@ signals: void logAlwaysLookAtTopCard(PlayerLogic *player, CardZoneLogic *zone, bool reveal); /** @} */ - void cardZoneChanged(CardItem *card, bool sameZone); - void requestCardMenuUpdate(CardItem *card); + void cardZoneChanged(CardState *card, bool sameZone); + void requestCardMenuUpdate(CardState *card); /** * @brief A card was just moved by the server and its view needs refreshing. * diff --git a/cockatrice/src/game/player/player_logic.cpp b/cockatrice/src/game/player/player_logic.cpp index f6a3a50e7..3437d2319 100644 --- a/cockatrice/src/game/player/player_logic.cpp +++ b/cockatrice/src/game/player/player_logic.cpp @@ -1,8 +1,9 @@ #include "player_logic.h" -#include "../../game_graphics/board/card_item.h" #include "../abstract_game.h" #include "../board/arrow_data.h" +#include "../board/card_list.h" +#include "../board/card_state.h" #include "../board/counter_state.h" #include "../game_meta_info.h" #include "../zones/hand_zone_logic.h" @@ -177,22 +178,20 @@ void PlayerLogic::processPlayerInfo(const ServerInfo_Player &info) const int cardListSize = zoneInfo.card_list_size(); if (!cardListSize) { for (int j = 0; j < zoneInfo.card_count(); ++j) { - zone->addCard((new CardItem(this))->getState(), false, -1); + emit zone->requestCreateCard(ServerInfo_Card(), false); } } else { for (int j = 0; j < cardListSize; ++j) { - const ServerInfo_Card &cardInfo = zoneInfo.card_list(j); - auto *card = new CardItem(this); - card->processCardInfo(cardInfo); + ServerInfo_Card cardInfo = zoneInfo.card_list(j); // Zones without coordinates (hand, piles, stack) preserve the order // they arrive in on the server in the positions of their cards list. // The x coordinate of such cards is always 0, so inserting at it // would reverse the list on reconnect. Append instead. - if (zoneInfo.with_coords()) { - zone->addCard(card->getState(), false, cardInfo.x(), cardInfo.y()); - } else { - zone->addCard(card->getState(), false, -1); + if (!zoneInfo.with_coords()) { + cardInfo.set_x(-1); + cardInfo.set_y(-1); } + emit zone->requestCreateCard(cardInfo, false); } } if (zoneInfo.has_always_reveal_top_card()) { @@ -250,7 +249,7 @@ void PlayerLogic::processCardAttachment(const ServerInfo_Player &info) } } -void PlayerLogic::addCard(CardItem *card) +void PlayerLogic::addCard(AbstractCardItem *card) { emit newCardAdded(card); } diff --git a/cockatrice/src/game/player/player_logic.h b/cockatrice/src/game/player/player_logic.h index ceaeff10b..196ee8ebe 100644 --- a/cockatrice/src/game/player/player_logic.h +++ b/cockatrice/src/game/player/player_logic.h @@ -73,7 +73,7 @@ signals: /** @brief Emitted when the remote playmat (card/params) is updated from player properties. */ void playmatChanged(); void newCardAdded(AbstractCardItem *card); - void requestCardMenuUpdate(CardItem *card); + void requestCardMenuUpdate(CardState *card); void counterAdded(CounterState *state); void counterRemoved(int counterId); void rearrangeCounters(); @@ -103,7 +103,7 @@ public: void processPlayerInfo(const ServerInfo_Player &info); void processCardAttachment(const ServerInfo_Player &info); - void addCard(CardItem *c); + void addCard(AbstractCardItem *c); void deleteCard(CardState *c); bool clearCardsToDelete(); diff --git a/cockatrice/src/game/zones/card_zone_logic.cpp b/cockatrice/src/game/zones/card_zone_logic.cpp index 8cce9f957..0f3deff6c 100644 --- a/cockatrice/src/game/zones/card_zone_logic.cpp +++ b/cockatrice/src/game/zones/card_zone_logic.cpp @@ -1,7 +1,9 @@ #include "card_zone_logic.h" #include "../../client/translation.h" -#include "../../game_graphics/board/card_item.h" +#include "../../game_graphics/zones/card_zone.h" +#include "../board/card_list.h" +#include "../board/card_state.h" #include "../player/player_actions.h" #include "../player/player_info.h" #include "../player/player_logic.h" @@ -50,10 +52,15 @@ void CardZoneLogic::addCard(CardState *card, const bool reorganize, const int x, for (auto *viewLogic : views) { if (viewLogic->prepareAddCard(x)) { - auto copy = new CardItem(player, nullptr, card->getCardRef(), card->getId()); - copy->setFaceDown(card->getFaceDown()); - - viewLogic->addCard(copy->getState(), reorganize, x, y); + ServerInfo_Card cardInfo; + const CardRef &cardRef = card->getCardRef(); + cardInfo.set_name(cardRef.name.toStdString()); + cardInfo.set_provider_id(cardRef.providerId.toStdString()); + cardInfo.set_id(card->getId()); + cardInfo.set_face_down(card->getFaceDown()); + cardInfo.set_x(x); + cardInfo.set_y(y); + emit viewLogic->requestCreateCard(cardInfo, reorganize); } } @@ -168,9 +175,9 @@ void CardZoneLogic::clearContents() for (CardState *card : toClear) { // If an incorrectly implemented server doesn't return attached cards to whom they belong before dropping a // player, we have to return them to avoid a crash. - const QList &attachedCards = card->getAttachedCards(); - for (CardItem *attachedCard : attachedCards) { - emit attachedCard->getZone()->cardAdded(attachedCard->getState()); + const QList &attachedCards = card->getAttachedCards(); + for (CardState *attachedCard : attachedCards) { + emit attachedCard->getZone()->cardAdded(attachedCard); } } diff --git a/cockatrice/src/game/zones/card_zone_logic.h b/cockatrice/src/game/zones/card_zone_logic.h index 2a6b50c5c..cde73bf76 100644 --- a/cockatrice/src/game/zones/card_zone_logic.h +++ b/cockatrice/src/game/zones/card_zone_logic.h @@ -14,10 +14,9 @@ #include #include #include +#include #include -class CardItem; - inline Q_LOGGING_CATEGORY(CardZoneLogicLog, "card_zone_logic"); class PlayerLogic; @@ -33,6 +32,8 @@ class CardZoneLogic : public QObject signals: void cardAdded(CardState *addedCard); + /** @brief Asks the graphics side to build the card item for @p cardInfo and add it to this zone. */ + void requestCreateCard(const ServerInfo_Card &cardInfo, bool reorganize); void cardCountChanged(); void reorganizeCards(); void updateGraphics(); diff --git a/cockatrice/src/game/zones/view_zone_logic.cpp b/cockatrice/src/game/zones/view_zone_logic.cpp index a9c763954..ef6c2bacf 100644 --- a/cockatrice/src/game/zones/view_zone_logic.cpp +++ b/cockatrice/src/game/zones/view_zone_logic.cpp @@ -35,7 +35,7 @@ ZoneViewZoneLogic::ZoneViewZoneLogic(PlayerLogic *_player, * Note that this method can end up modifying the cardIds despite returning false. * (for example, if the card is inserted into a hidden portion of the deck while the view is reversed) * - * Make sure to call this method once before calling addCard(), so that you skip creating a new CardItem and calling + * Make sure to call this method once before calling addCard(), so that you skip creating the card and calling * addCard() if it's not required. * * @param x The position to insert the card at. diff --git a/cockatrice/src/game_graphics/board/card_item.cpp b/cockatrice/src/game_graphics/board/card_item.cpp index e56b5848c..593eab29f 100644 --- a/cockatrice/src/game_graphics/board/card_item.cpp +++ b/cockatrice/src/game_graphics/board/card_item.cpp @@ -89,14 +89,18 @@ void CardItem::prepareDelete() owner = nullptr; } - const QList &attachedCards = state->getAttachedCards(); - while (!attachedCards.isEmpty()) { - attachedCards.first()->setZone(nullptr); // so that it won't try to call reorganizeCards() - attachedCards.first()->setAttachedTo(nullptr); + const QList &attachedStates = state->getAttachedCards(); + while (!attachedStates.isEmpty()) { + auto *attachedItem = qobject_cast(attachedStates.first()->parent()); + if (attachedItem == nullptr) { + break; + } + attachedItem->setZone(nullptr); // so that it won't try to call reorganizeCards() + attachedItem->setAttachedTo(nullptr); } if (state->getAttachedTo() != nullptr) { - state->getAttachedTo()->removeAttachedCard(this); + state->getAttachedTo()->removeAttachedCard(state); state->setAttachedTo(nullptr); } } @@ -226,7 +230,7 @@ void CardItem::setPT(const QString &_pt) void CardItem::setAttachedTo(CardItem *_attachedTo) { if (state->getAttachedTo() != nullptr) { - state->getAttachedTo()->removeAttachedCard(this); + state->getAttachedTo()->removeAttachedCard(state); } state->setGridPoint(QPoint(-1, state->getGridPoint().y())); @@ -238,7 +242,7 @@ void CardItem::setAttachedTo(CardItem *_attachedTo) deleteLater(); } else { emit state->getAttachedTo()->getZone()->cardAdded(state); - state->getAttachedTo()->addAttachedCard(this); + state->getAttachedTo()->addAttachedCard(state); if (state->getZone() != state->getAttachedTo()->getZone()) { state->getAttachedTo()->getZone()->reorganizeCards(); } diff --git a/cockatrice/src/game_graphics/board/card_item.h b/cockatrice/src/game_graphics/board/card_item.h index 79c3dcdbd..706c00195 100644 --- a/cockatrice/src/game_graphics/board/card_item.h +++ b/cockatrice/src/game_graphics/board/card_item.h @@ -120,15 +120,15 @@ public: return state->getAttachedTo(); } void setAttachedTo(CardItem *_attachedTo); - void addAttachedCard(CardItem *card) + void addAttachedCard(CardState *card) { state->addAttachedCard(card); } - void removeAttachedCard(CardItem *card) + void removeAttachedCard(CardState *card) { state->removeAttachedCard(card); } - [[nodiscard]] const QList &getAttachedCards() const + [[nodiscard]] const QList &getAttachedCards() const { return state->getAttachedCards(); } diff --git a/cockatrice/src/game_graphics/game_scene.cpp b/cockatrice/src/game_graphics/game_scene.cpp index 1814ebc5d..dc3ce1161 100644 --- a/cockatrice/src/game_graphics/game_scene.cpp +++ b/cockatrice/src/game_graphics/game_scene.cpp @@ -205,7 +205,7 @@ void GameScene::onCardSelectionChanged(AbstractCardItem *abstractCard, bool sele auto *owner = card->getOwner(); if (selected) { - owner->requestCardMenuUpdate(card); + owner->requestCardMenuUpdate(card->getState()); return; } @@ -231,7 +231,7 @@ void GameScene::onCardRightClicked(AbstractCardItem *abstractCard, QPoint screen setActiveCard(card); - if (auto *menu = view->getPlayerMenu()->updateCardMenu(card)) { + if (auto *menu = view->getPlayerMenu()->updateCardMenu(card->getState())) { menu->popup(screenPos); } } @@ -650,11 +650,15 @@ void GameScene::requestArrowDeletion(int playerId, int arrowId) } } -void GameScene::onCardZoneChanged(CardItem *card, bool sameZone) +void GameScene::onCardZoneChanged(CardState *card, bool sameZone) { + auto *item = qobject_cast(card->parent()); + if (!item) { + return; + } QList toDelete; for (auto *arrow : arrowRegistry.all()) { - if (arrow->getStartItem() == card || arrow->getTargetItem() == card) { + if (arrow->getStartItem() == item || arrow->getTargetItem() == item) { if (sameZone) { arrow->updatePath(); } else { diff --git a/cockatrice/src/game_graphics/game_scene.h b/cockatrice/src/game_graphics/game_scene.h index 5856d718d..3f7d40ed0 100644 --- a/cockatrice/src/game_graphics/game_scene.h +++ b/cockatrice/src/game_graphics/game_scene.h @@ -283,7 +283,7 @@ public slots: /// Queues up arrow deletion but doesn't directly modify the scene void requestArrowDeletion(int playerId, int arrowId); - void onCardZoneChanged(CardItem *card, bool sameZone); + void onCardZoneChanged(CardState *card, bool sameZone); /** * @brief Refreshes the view of a card that the server just moved. * diff --git a/cockatrice/src/game_graphics/player/menu/player_menu.cpp b/cockatrice/src/game_graphics/player/menu/player_menu.cpp index 7e69df66e..10e7a7ddc 100644 --- a/cockatrice/src/game_graphics/player/menu/player_menu.cpp +++ b/cockatrice/src/game_graphics/player/menu/player_menu.cpp @@ -87,22 +87,24 @@ void PlayerMenu::setMenusForGraphicItems() } } -QMenu *PlayerMenu::updateCardMenu(CardItem *card) +QMenu *PlayerMenu::updateCardMenu(CardState *card) { if (!card) { emit cardMenuUpdated(nullptr); return nullptr; } + auto *cardItem = qobject_cast(card->parent()); + // If is spectator (as spectators don't need card menus), return // only update the menu if the card is actually selected if ((player->getLogic()->getGame()->getPlayerManager()->isSpectator() && !player->getLogic()->getGame()->getPlayerManager()->isJudge()) || - player->getGameScene()->getActiveCard() != card) { + cardItem == nullptr || player->getGameScene()->getActiveCard() != cardItem) { return nullptr; } - CardMenu *menu = new CardMenu(player, card, shortcutsActive); + CardMenu *menu = new CardMenu(player, cardItem, shortcutsActive); connect(menu, &CardMenu::cardInfoRequested, this, &PlayerMenu::cardInfoRequested); emit cardMenuUpdated(menu); diff --git a/cockatrice/src/game_graphics/player/menu/player_menu.h b/cockatrice/src/game_graphics/player/menu/player_menu.h index 27a5efe7e..e21a689de 100644 --- a/cockatrice/src/game_graphics/player/menu/player_menu.h +++ b/cockatrice/src/game_graphics/player/menu/player_menu.h @@ -14,7 +14,7 @@ #include #include -class CardItem; +class CardState; class CardMenu; class PlayerGraphicsItem; class AbstractPlayerComponent; @@ -43,7 +43,7 @@ signals: public slots: void setMenusForGraphicItems(); - QMenu *updateCardMenu(CardItem *card); + QMenu *updateCardMenu(CardState *card); private slots: void refreshShortcuts(); diff --git a/cockatrice/src/game_graphics/zones/card_zone.cpp b/cockatrice/src/game_graphics/zones/card_zone.cpp index b29ad3666..5f45bf0b0 100644 --- a/cockatrice/src/game_graphics/zones/card_zone.cpp +++ b/cockatrice/src/game_graphics/zones/card_zone.cpp @@ -24,6 +24,7 @@ CardZone::CardZone(CardZoneLogic *_logic, QGraphicsItem *parent) connect(logic, &CardZoneLogic::cardCountChanged, this, &CardZone::invalidateItems); connect(logic, &CardZoneLogic::reorganizeCards, this, &CardZone::invalidateItems); connect(logic, &CardZoneLogic::cardAdded, this, &CardZone::onCardAdded); + connect(logic, &CardZoneLogic::requestCreateCard, this, &CardZone::onCreateCardRequested); connect(logic, &CardZoneLogic::setGraphicsVisibility, this, [this](bool v) { this->setVisible(v); }); connect(logic, &CardZoneLogic::updateGraphics, this, [this]() { update(); }); connect(logic, &CardZoneLogic::reorganizeCards, this, &CardZone::reorganizeCards); @@ -59,6 +60,14 @@ void CardZone::onCardAdded(CardState *addedCard) addedItem->update(); } +void CardZone::onCreateCardRequested(const ServerInfo_Card &cardInfo, bool reorganize) +{ + CardRef cardRef = {QString::fromStdString(cardInfo.name()), QString::fromStdString(cardInfo.provider_id())}; + auto *card = new CardItem(getLogic()->getPlayer(), nullptr, cardRef, cardInfo.id()); + card->processCardInfo(cardInfo); + getLogic()->addCard(card->getState(), reorganize, cardInfo.x(), cardInfo.y()); +} + void CardZone::retranslateUi() { for (auto *card : cardItems()) { diff --git a/cockatrice/src/game_graphics/zones/card_zone.h b/cockatrice/src/game_graphics/zones/card_zone.h index 10215003f..50b5b5c23 100644 --- a/cockatrice/src/game_graphics/zones/card_zone.h +++ b/cockatrice/src/game_graphics/zones/card_zone.h @@ -58,6 +58,8 @@ public slots: * connection in CardZone's constructor dispatches through the vtable. */ virtual void onCardAdded(CardState *addedCard); + /** @brief Builds the card item for @p cardInfo and hands it to this zone's logic. */ + void onCreateCardRequested(const ServerInfo_Card &cardInfo, bool reorganize); public: enum diff --git a/cockatrice/src/game_graphics/zones/table_zone.cpp b/cockatrice/src/game_graphics/zones/table_zone.cpp index 2fcff1d8a..8cb209c5a 100644 --- a/cockatrice/src/game_graphics/zones/table_zone.cpp +++ b/cockatrice/src/game_graphics/zones/table_zone.cpp @@ -248,11 +248,14 @@ void TableZone::reorganizeCards() cardItems()[i]->setPos(actualX, actualY); cardItems()[i]->setRealZValue(ZValues::tableCardZValue(actualX, actualY)); - QListIterator attachedCardIterator(cardItems()[i]->getAttachedCards()); + QListIterator attachedCardIterator(cardItems()[i]->getAttachedCards()); int j = 0; while (attachedCardIterator.hasNext()) { ++j; - CardItem *attachedCard = attachedCardIterator.next(); + CardItem *attachedCard = qobject_cast(attachedCardIterator.next()->parent()); + if (attachedCard == nullptr) { + continue; + } qreal childX = actualX - j * STACKED_CARD_OFFSET_X; qreal childY = y + 5; attachedCard->setPos(childX, childY);