diff --git a/cockatrice/src/game/abstract_game.cpp b/cockatrice/src/game/abstract_game.cpp index 7c342d1a9..a93f44018 100644 --- a/cockatrice/src/game/abstract_game.cpp +++ b/cockatrice/src/game/abstract_game.cpp @@ -46,7 +46,7 @@ void AbstractGame::loadReplay(const GameReplay *replay) gameMetaInfo->setSpectatorsOmniscient(true); } -CardItem *AbstractGame::getCard(int playerId, const QString &zoneName, int cardId) const +CardState *AbstractGame::getCard(int playerId, const QString &zoneName, int cardId) const { PlayerLogic *player = playerManager->getPlayer(playerId); if (!player) { diff --git a/cockatrice/src/game/abstract_game.h b/cockatrice/src/game/abstract_game.h index 093916aa9..505bfc1b5 100644 --- a/cockatrice/src/game/abstract_game.h +++ b/cockatrice/src/game/abstract_game.h @@ -13,6 +13,7 @@ class CardItem; class AbstractClient; +class CardState; class GameEventHandler; class GameMetaInfo; class GameReplay; @@ -57,7 +58,7 @@ public: void loadReplay(const GameReplay *replay); - CardItem *getCard(int playerId, const QString &zoneName, int cardId) const; + CardState *getCard(int playerId, const QString &zoneName, int cardId) const; }; #endif // COCKATRICE_ABSTRACT_GAME_H diff --git a/cockatrice/src/game/board/card_list.cpp b/cockatrice/src/game/board/card_list.cpp index 94bae67cd..361c51502 100644 --- a/cockatrice/src/game/board/card_list.cpp +++ b/cockatrice/src/game/board/card_list.cpp @@ -1,7 +1,6 @@ #include "card_list.h" -#include "../../game_graphics/board/card_item.h" -#include "libcockatrice/card/printing/exact_card.h" +#include "card_state.h" #include #include @@ -11,26 +10,26 @@ #include #include -CardList::CardList(bool _contentsKnown) : QList(), contentsKnown(_contentsKnown) +CardList::CardList(bool _contentsKnown) : QList(), contentsKnown(_contentsKnown) { } /** - * @brief Finds the CardItem with the given id in the list. + * @brief Finds the CardState with the given id in the list. * If contentsKnown is false, then this just returns the first element of the list. * * @param cardId The id of the card to find. * - * @returns A pointer to the CardItem, or a nullptr if not found. + * @returns A pointer to the CardState, or a nullptr if not found. */ -CardItem *CardList::findCard(const int cardId) const +CardState *CardList::findCard(const int cardId) const { if (!contentsKnown && !empty()) { return at(0); } else { - for (auto *cardItem : *this) { - if (cardItem->getId() == cardId) { - return cardItem; + for (auto *cardState : *this) { + if (cardState->getId() == cardId) { + return cardState; } } } @@ -38,7 +37,7 @@ CardItem *CardList::findCard(const int cardId) const } /** - * @brief sorts the list by using string comparison on properties extracted from the CardItem + * @brief sorts the list by using string comparison on properties extracted from the CardState * The cards are compared using each property in order. * If two cards have the same value for a property, then the next property in the list is used. * @@ -51,7 +50,7 @@ void CardList::sortBy(const QList &option) return; } - auto comparator = [&option](CardItem *a, CardItem *b) { + auto comparator = [&option](CardState *a, CardState *b) { for (auto prop : option) { auto extractor = getExtractorFor(prop); QString t1 = extractor(a); @@ -116,26 +115,26 @@ static QString getColorSortString(const CardInfo &c, bool appendAtEnd) } /** - * @brief returns the function that extracts the given property from the CardItem. + * @brief returns the function that extracts the given property from the CardState. */ -std::function CardList::getExtractorFor(SortOption option) +std::function CardList::getExtractorFor(SortOption option) { switch (option) { case NoSort: - return [](CardItem *) { return ""; }; + return [](CardState *) { return ""; }; case SortByMainType: - return [](CardItem *c) { return c->getCardInfo().getMainCardType(); }; + return [](CardState *c) { return c->getCardInfo().getMainCardType(); }; case SortByManaValue: // getCmc returns the int as a string. We pad with 0's so that string comp also works on it - return [](CardItem *c) { return c->getCard() ? c->getCardInfo().getCmc().rightJustified(4, '0') : ""; }; + return [](CardState *c) { return c->getCard() ? c->getCardInfo().getCmc().rightJustified(4, '0') : ""; }; case SortByColorGrouping: - return [](CardItem *c) { return c->getCard() ? getColorSortString(c->getCardInfo(), false) : ""; }; + return [](CardState *c) { return c->getCard() ? getColorSortString(c->getCardInfo(), false) : ""; }; case SortByName: - return [](CardItem *c) { return c->getName(); }; + return [](CardState *c) { return c->getName(); }; case SortByType: - return [](CardItem *c) { return c->getCardInfo().getCardType(); }; + return [](CardState *c) { return c->getCardInfo().getCardType(); }; case SortByManaCost: - return [](CardItem *c) { + return [](CardState *c) { if (!c->getCard()) { return QString(); } @@ -147,18 +146,18 @@ std::function CardList::getExtractorFor(SortOption option) return QString("%1%2").arg(info.getCmc(), 4, QChar('0')).arg(info.getManaCost()); }; case SortByColors: - return [](CardItem *c) { return c->getCard() ? getColorSortString(c->getCardInfo(), true) : ""; }; + return [](CardState *c) { return c->getCard() ? getColorSortString(c->getCardInfo(), true) : ""; }; case SortByPt: // do the same padding trick as above return - [](CardItem *c) { return c->getCard() ? c->getCardInfo().getPowTough().rightJustified(10, '0') : ""; }; + [](CardState *c) { return c->getCard() ? c->getCardInfo().getPowTough().rightJustified(10, '0') : ""; }; case SortBySet: - return [](CardItem *c) { return c->getCardInfo().getSetsNames(); }; + return [](CardState *c) { return c->getCardInfo().getSetsNames(); }; case SortByPrinting: - return [](CardItem *c) { return c->getProviderId(); }; + return [](CardState *c) { return c->getProviderId(); }; } // this line should never be reached qCWarning(CardListLog) << "cardlist.cpp: Could not find extractor for SortOption" << option; - return [](CardItem *) { return ""; }; + return [](CardState *) { return ""; }; } \ No newline at end of file diff --git a/cockatrice/src/game/board/card_list.h b/cockatrice/src/game/board/card_list.h index b5427df0d..b3037d0f6 100644 --- a/cockatrice/src/game/board/card_list.h +++ b/cockatrice/src/game/board/card_list.h @@ -14,9 +14,9 @@ inline Q_LOGGING_CATEGORY(CardListLog, "card_list"); -class CardItem; +class CardState; -class CardList : public QList +class CardList : public QList { protected: bool contentsKnown; @@ -43,7 +43,7 @@ public: SortByPrinting }; explicit CardList(bool _contentsKnown); - CardItem *findCard(const int cardId) const; + CardState *findCard(const int cardId) const; bool getContentsKnown() const { return contentsKnown; @@ -51,7 +51,7 @@ public: void sortBy(const QList &options); - static std::function getExtractorFor(SortOption option); + static std::function getExtractorFor(SortOption option); }; #endif diff --git a/cockatrice/src/game/player/player_actions.cpp b/cockatrice/src/game/player/player_actions.cpp index 1a91d28a5..c0f4ef11d 100644 --- a/cockatrice/src/game/player/player_actions.cpp +++ b/cockatrice/src/game/player/player_actions.cpp @@ -1614,7 +1614,9 @@ void PlayerActions::actIncrementAllCardCounters(QList cardsToUpdate) { if (cardsToUpdate.isEmpty()) { // If no cards selected, update all cards on table - cardsToUpdate = static_cast>(player->getTableZone()->getCards()); + for (auto *state : player->getTableZone()->getCards()) { + cardsToUpdate.append(qobject_cast(state->parent())); + } } QList commandList; @@ -1687,7 +1689,7 @@ void PlayerActions::actHide(QList selectedCards) for (const auto &item : selectedCards) { auto *card = static_cast(item); if (card && isUnwritableRevealZone(card->getZone())) { - card->getZone()->removeCard(card); + card->getZone()->removeCard(card->getState()); } } } diff --git a/cockatrice/src/game/player/player_event_handler.cpp b/cockatrice/src/game/player/player_event_handler.cpp index ff81498ac..4698aeced 100644 --- a/cockatrice/src/game/player/player_event_handler.cpp +++ b/cockatrice/src/game/player/player_event_handler.cpp @@ -53,6 +53,11 @@ #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); @@ -171,7 +176,7 @@ void PlayerEventHandler::eventCreateToken(const Event_CreateToken &event) card->setFaceDown(event.face_down()); emit logCreateToken(player, card->getName(), card->getPT(), card->getFaceDown()); - zone->addCard(card, true, event.x(), event.y()); + zone->addCard(card->getState(), true, event.x(), event.y()); } void PlayerEventHandler::eventSetCardAttr(const Event_SetCardAttr &event, @@ -193,7 +198,7 @@ void PlayerEventHandler::eventSetCardAttr(const Event_SetCardAttr &event, emit logSetTapped(player, nullptr, event.attr_value() == "1"); } } else { - CardItem *card = zone->getCard(event.card_id()); + CardState *card = zone->getCard(event.card_id()); if (!card) { qWarning() << "PlayerEventHandler::eventSetCardAttr: card id=" << event.card_id() << "not found"; return; @@ -203,7 +208,7 @@ void PlayerEventHandler::eventSetCardAttr(const Event_SetCardAttr &event, } void PlayerEventHandler::setCardAttrHelper(const GameEventContext &context, - CardItem *card, + CardState *card, CardAttribute attribute, const QString &avalue, bool allCards, @@ -264,14 +269,14 @@ void PlayerEventHandler::eventSetCardCounter(const Event_SetCardCounter &event) return; } - CardItem *card = zone->getCard(event.card_id()); + CardState *card = zone->getCard(event.card_id()); if (!card) { return; } int oldValue = card->getCounters().value(event.counter_id(), 0); card->setCounter(event.counter_id(), event.counter_value()); - emit requestCardMenuUpdate(card); + emit requestCardMenuUpdate(toCardItem(card)); emit logSetCardCounter(player, card->getName(), event.counter_id(), event.counter_value(), oldValue); } @@ -341,13 +346,13 @@ void PlayerEventHandler::eventMoveCard(const Event_MoveCard &event, const GameEv if (x == -1) { x = 0; } - CardItem *card = startZone->takeCard(position, event.card_id(), startZone != targetZone); + CardState *card = startZone->takeCard(position, event.card_id(), startZone != targetZone); if (card == nullptr) { return; } const bool zoneChanged = startZone != targetZone; const bool ownerChanged = zoneChanged && startZone->getPlayer() != targetZone->getPlayer(); - emit cardViewRefreshRequested(card->getState(), zoneChanged, ownerChanged ? targetZone->getPlayer() : nullptr); + emit cardViewRefreshRequested(card, zoneChanged, ownerChanged ? targetZone->getPlayer() : nullptr); if (event.has_card_name()) { QString name = QString::fromStdString(event.card_name()); QString providerId = @@ -357,7 +362,13 @@ void PlayerEventHandler::eventMoveCard(const Event_MoveCard &event, const GameEv if (card->getAttachedTo() && (startZone != targetZone)) { CardState *parentCard = card->getAttachedTo(); - card->setAttachedTo(nullptr); + // Route through CardItem so the old parent's attachedCards list is cleaned up: CardState::setAttachedTo + // only repoints the pointer, leaving a dangling entry that reorganizeCards/prepareDelete would dereference. + if (CardItem *item = toCardItem(card)) { + item->setAttachedTo(nullptr); + } else { + card->setAttachedTo(nullptr); + } parentCard->getZone()->reorganizeCards(); } @@ -366,7 +377,7 @@ void PlayerEventHandler::eventMoveCard(const Event_MoveCard &event, const GameEv if (startZone != targetZone) { const QList &attachedCards = card->getAttachedCards(); for (auto attachedCard : attachedCards) { - emit targetZone->cardAdded(attachedCard); + emit targetZone->cardAdded(attachedCard->getState()); } } @@ -380,12 +391,12 @@ void PlayerEventHandler::eventMoveCard(const Event_MoveCard &event, const GameEv targetZone->addCard(card, true, x, y); - emit cardZoneChanged(card, startZone == targetZone); - emit requestCardMenuUpdate(card); + emit cardZoneChanged(toCardItem(card), startZone == targetZone); + emit requestCardMenuUpdate(toCardItem(card)); if (player->getPlayerActions()->isMovingCardsUntil() && startZoneString == ZoneNames::DECK && targetZone->getName() == ZoneNames::STACK) { - player->getPlayerActions()->moveOneCardUntil(card); + player->getPlayerActions()->moveOneCardUntil(toCardItem(card)); } } @@ -395,7 +406,7 @@ void PlayerEventHandler::eventFlipCard(const Event_FlipCard &event) if (!zone) { return; } - CardItem *card = zone->getCard(event.card_id()); + CardState *card = zone->getCard(event.card_id()); if (!card) { return; } @@ -408,7 +419,7 @@ void PlayerEventHandler::eventFlipCard(const Event_FlipCard &event) emit logFlipCard(player, card->getName(), event.face_down()); card->setFaceDown(event.face_down()); - emit requestCardMenuUpdate(card); + emit requestCardMenuUpdate(toCardItem(card)); } void PlayerEventHandler::eventDestroyCard(const Event_DestroyCard &event) @@ -418,7 +429,7 @@ void PlayerEventHandler::eventDestroyCard(const Event_DestroyCard &event) return; } - CardItem *card = zone->getCard(event.card_id()); + CardState *card = zone->getCard(event.card_id()); if (!card) { return; } @@ -431,7 +442,7 @@ void PlayerEventHandler::eventDestroyCard(const Event_DestroyCard &event) emit logDestroyCard(player, card->getName()); zone->takeCard(-1, event.card_id(), true); - card->getState()->deleteView(); + card->deleteView(); } void PlayerEventHandler::eventAttachCard(const Event_AttachCard &event) @@ -439,7 +450,7 @@ void PlayerEventHandler::eventAttachCard(const Event_AttachCard &event) const QMap &playerList = player->getGame()->getPlayerManager()->getPlayers(); PlayerLogic *targetPlayer = nullptr; CardZoneLogic *targetZone = nullptr; - CardItem *targetCard = nullptr; + CardState *targetCard = nullptr; if (event.has_target_player_id()) { targetPlayer = playerList.value(event.target_player_id(), 0); if (targetPlayer) { @@ -455,14 +466,21 @@ void PlayerEventHandler::eventAttachCard(const Event_AttachCard &event) return; } - CardItem *startCard = startZone->getCard(event.card_id()); + CardState *startCard = startZone->getCard(event.card_id()); if (!startCard) { return; } CardState *oldParent = startCard->getAttachedTo(); - startCard->setAttachedTo(targetCard); + // Route through CardItem::setAttachedTo to keep the attachedCards graph, grid-x reset and zone emits intact: + // CardState::setAttachedTo alone only repoints the pointer, so the target would never list the card and the old + // parent would keep a dangling pointer. + if (CardItem *startItem = toCardItem(startCard)) { + startItem->setAttachedTo(toCardItem(targetCard)); + } else { + startCard->setAttachedTo(targetCard); + } startZone->reorganizeCards(); if ((startZone != targetZone) && targetZone) { @@ -477,7 +495,7 @@ void PlayerEventHandler::eventAttachCard(const Event_AttachCard &event) } else { emit logUnattachCard(player, startCard->getName()); } - emit requestCardMenuUpdate(startCard); + emit requestCardMenuUpdate(toCardItem(startCard)); } void PlayerEventHandler::eventDrawCards(const Event_DrawCards &event) @@ -489,7 +507,7 @@ void PlayerEventHandler::eventDrawCards(const Event_DrawCards &event) if (listSize) { for (int i = 0; i < listSize; ++i) { const ServerInfo_Card &cardInfo = event.cards(i); - CardItem *card = _deck->takeCard(0, cardInfo.id()); + CardState *card = _deck->takeCard(0, cardInfo.id()); QString cardName = QString::fromStdString(cardInfo.name()); QString providerId = QString::fromStdString(cardInfo.provider_id()); card->setCardRef({cardName, providerId}); @@ -537,7 +555,7 @@ void PlayerEventHandler::eventRevealCards(const Event_RevealCards &event, EventP for (const auto &card : cardList) { QString cardName = QString::fromStdString(card->name()); QString providerId = QString::fromStdString(card->provider_id()); - CardItem *cardItem = zone->getCard(card->id()); + CardState *cardItem = zone->getCard(card->id()); if (!cardItem) { continue; } diff --git a/cockatrice/src/game/player/player_event_handler.h b/cockatrice/src/game/player/player_event_handler.h index 37215d61d..6b721bf61 100644 --- a/cockatrice/src/game/player/player_event_handler.h +++ b/cockatrice/src/game/player/player_event_handler.h @@ -239,7 +239,7 @@ signals: void logUndoDraw(PlayerLogic *player, QString cardName); void logUndoDrawFailed(PlayerLogic *player); void logMoveCard(PlayerLogic *player, - CardItem *card, + CardState *card, CardZoneLogic *startZone, int oldX, CardZoneLogic *targetZone, @@ -249,11 +249,11 @@ signals: void logAttachCard(PlayerLogic *player, QString cardName, PlayerLogic *targetPlayer, QString targetCardName); void logUnattachCard(PlayerLogic *player, QString cardName); void logSetCardCounter(PlayerLogic *player, QString cardName, int counterId, int value, int oldValue); - void logSetTapped(PlayerLogic *player, CardItem *card, bool tapped); + void logSetTapped(PlayerLogic *player, CardState *card, bool tapped); void logSetCounter(PlayerLogic *player, QString counterName, int value, int oldValue); - void logSetDoesntUntap(PlayerLogic *player, CardItem *card, bool doesntUntap); - void logSetPT(PlayerLogic *player, CardItem *card, QString newPT); - void logSetAnnotation(PlayerLogic *player, CardItem *card, QString newAnnotation); + void logSetDoesntUntap(PlayerLogic *player, CardState *card, bool doesntUntap); + void logSetPT(PlayerLogic *player, CardState *card, QString newPT); + void logSetAnnotation(PlayerLogic *player, CardState *card, QString newAnnotation); void logDumpZone(PlayerLogic *player, CardZoneLogic *zone, int numberCards, bool isReversed = false); void logRevealCards(PlayerLogic *player, CardZoneLogic *zone, @@ -283,7 +283,7 @@ private: PlayerLogic *player; void setCardAttrHelper(const GameEventContext &context, - CardItem *card, + CardState *card, CardAttribute attribute, const QString &avalue, bool allCards, diff --git a/cockatrice/src/game/player/player_logic.cpp b/cockatrice/src/game/player/player_logic.cpp index 552e9f44c..f6a3a50e7 100644 --- a/cockatrice/src/game/player/player_logic.cpp +++ b/cockatrice/src/game/player/player_logic.cpp @@ -33,6 +33,11 @@ #include #include +static CardItem *toCardItem(CardState *card) +{ + return card == nullptr ? nullptr : qobject_cast(card->parent()); +} + PlayerLogic::PlayerLogic(const ServerInfo_User &info, int _id, bool _local, bool _judge, AbstractGame *_parent) : QObject(_parent), game(_parent), playerInfo(new PlayerInfo(info, _id, _local, _judge)), playerEventHandler(new PlayerEventHandler(this)), playerActions(new PlayerActions(this)), active(false), @@ -172,7 +177,7 @@ 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), false, -1); + zone->addCard((new CardItem(this))->getState(), false, -1); } } else { for (int j = 0; j < cardListSize; ++j) { @@ -184,9 +189,9 @@ void PlayerLogic::processPlayerInfo(const ServerInfo_Player &info) // 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, false, cardInfo.x(), cardInfo.y()); + zone->addCard(card->getState(), false, cardInfo.x(), cardInfo.y()); } else { - zone->addCard(card, false, -1); + zone->addCard(card->getState(), false, -1); } } } @@ -219,15 +224,21 @@ void PlayerLogic::processCardAttachment(const ServerInfo_Player &info) for (int j = 0; j < cardListSize; ++j) { const ServerInfo_Card &cardInfo = zoneInfo.card_list(j); if (cardInfo.has_attach_player_id()) { - CardItem *startCard = zone->getCard(cardInfo.id()); - CardItem *targetCard = + CardState *startCard = zone->getCard(cardInfo.id()); + CardState *targetCard = game->getCard(cardInfo.attach_player_id(), QString::fromStdString(cardInfo.attach_zone()), cardInfo.attach_card_id()); if (!targetCard) { continue; } - startCard->setAttachedTo(targetCard); + // Route through CardItem::setAttachedTo to maintain the attachedCards graph and reparenting; + // CardState::setAttachedTo alone only repoints the pointer. + if (CardItem *startItem = toCardItem(startCard)) { + startItem->setAttachedTo(toCardItem(targetCard)); + } else { + startCard->setAttachedTo(targetCard); + } } } } @@ -244,14 +255,14 @@ void PlayerLogic::addCard(CardItem *card) emit newCardAdded(card); } -void PlayerLogic::deleteCard(CardItem *card) +void PlayerLogic::deleteCard(CardState *card) { if (card == nullptr) { return; } else if (dialogSemaphore) { cardsToDelete.append(card); } else { - card->getState()->deleteView(); + card->deleteView(); } } @@ -332,7 +343,7 @@ bool PlayerLogic::clearCardsToDelete() for (auto &i : cardsToDelete) { if (i != nullptr) { - i->getState()->deleteView(); + i->deleteView(); } } cardsToDelete.clear(); diff --git a/cockatrice/src/game/player/player_logic.h b/cockatrice/src/game/player/player_logic.h index d516fede0..ceaeff10b 100644 --- a/cockatrice/src/game/player/player_logic.h +++ b/cockatrice/src/game/player/player_logic.h @@ -104,7 +104,7 @@ public: void processCardAttachment(const ServerInfo_Player &info); void addCard(CardItem *c); - void deleteCard(CardItem *c); + void deleteCard(CardState *c); bool clearCardsToDelete(); @@ -256,7 +256,7 @@ private: QMap counters; bool dialogSemaphore; - QList cardsToDelete; + QList cardsToDelete; // Playmat from player properties (for opponent display) CardRef remotePlaymatCard; diff --git a/cockatrice/src/game/zones/card_zone_logic.cpp b/cockatrice/src/game/zones/card_zone_logic.cpp index c4431f20a..8cce9f957 100644 --- a/cockatrice/src/game/zones/card_zone_logic.cpp +++ b/cockatrice/src/game/zones/card_zone_logic.cpp @@ -41,7 +41,7 @@ CardZoneLogic::CardZoneLogic(PlayerLogic *_player, &CardZoneLogic::refreshCardInfos); } -void CardZoneLogic::addCard(CardItem *card, const bool reorganize, const int x, const int y) +void CardZoneLogic::addCard(CardState *card, const bool reorganize, const int x, const int y) { if (!card) { qCWarning(CardZoneLogicLog) << "CardZoneLogic::addCard() card is null; this shouldn't normally happen"; @@ -53,7 +53,7 @@ void CardZoneLogic::addCard(CardItem *card, const bool reorganize, const int x, auto copy = new CardItem(player, nullptr, card->getCardRef(), card->getId()); copy->setFaceDown(card->getFaceDown()); - viewLogic->addCard(copy, reorganize, x, y); + viewLogic->addCard(copy->getState(), reorganize, x, y); } } @@ -68,7 +68,7 @@ void CardZoneLogic::addCard(CardItem *card, const bool reorganize, const int x, emit cardCountChanged(); } -CardItem *CardZoneLogic::takeCard(int position, int cardId, bool toNewZone) +CardState *CardZoneLogic::takeCard(int position, int cardId, bool toNewZone) { if (position == -1) { // position == -1 means either that the zone is indexed by card id @@ -91,7 +91,7 @@ CardItem *CardZoneLogic::takeCard(int position, int cardId, bool toNewZone) viewLogic->removeCard(position, toNewZone); } - CardItem *c = cards.takeAt(position); + CardState *c = cards.takeAt(position); c->setId(cardId); @@ -100,9 +100,9 @@ CardItem *CardZoneLogic::takeCard(int position, int cardId, bool toNewZone) return c; } -CardItem *CardZoneLogic::getCard(int cardId) +CardState *CardZoneLogic::getCard(int cardId) { - CardItem *c = cards.findCard(cardId); + CardState *c = cards.findCard(cardId); if (!c) { qCWarning(CardZoneLogicLog) << "CardZoneLogic::getCard: card id=" << cardId << "not found"; return nullptr; @@ -116,7 +116,7 @@ CardItem *CardZoneLogic::getCard(int cardId) return c; } -void CardZoneLogic::removeCard(CardItem *card) +void CardZoneLogic::removeCard(CardState *card) { if (!card) { qCWarning(CardZoneLogicLog) << "CardZoneLogic::removeCard: card is null, this shouldn't normally happen"; @@ -132,8 +132,8 @@ void CardZoneLogic::removeCard(CardItem *card) void CardZoneLogic::refreshCardInfos() { - for (const auto &cardItem : cards) { - cardItem->refreshCardInfo(); + for (const auto &cardState : cards) { + cardState->refreshCardInfo(); } } @@ -165,17 +165,17 @@ void CardZoneLogic::clearContents() const CardList toClear = cards; // Detach and notify attached cards and zones *before* deleting anything. - for (CardItem *card : toClear) { + 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); + emit attachedCard->getZone()->cardAdded(attachedCard->getState()); } } // Now request deletions after all manipulations are done. - for (CardItem *card : toClear) { + for (CardState *card : toClear) { player->deleteCard(card); } diff --git a/cockatrice/src/game/zones/card_zone_logic.h b/cockatrice/src/game/zones/card_zone_logic.h index e01eec74c..2a6b50c5c 100644 --- a/cockatrice/src/game/zones/card_zone_logic.h +++ b/cockatrice/src/game/zones/card_zone_logic.h @@ -32,7 +32,7 @@ class CardZoneLogic : public QObject Q_OBJECT signals: - void cardAdded(CardItem *addedCard); + void cardAdded(CardState *addedCard); void cardCountChanged(); void reorganizeCards(); void updateGraphics(); @@ -47,14 +47,14 @@ public: bool _contentsKnown, QObject *parent = nullptr); - void addCard(CardItem *card, bool reorganize, int x, int y = -1); + void addCard(CardState *card, bool reorganize, int x, int y = -1); // getCard() finds a card by id. - CardItem *getCard(int cardId); - void removeCard(CardItem *card); + CardState *getCard(int cardId); + void removeCard(CardState *card); // takeCard() finds a card by position and removes it from the zone and from all of its views. - virtual CardItem *takeCard(int position, int cardId, bool canResize = true); + virtual CardState *takeCard(int position, int cardId, bool canResize = true); - void rawInsertCard(CardItem *card, int index) + void rawInsertCard(CardState *card, int index) { cards.insert(index, card); emit cardCountChanged(); @@ -120,7 +120,7 @@ protected: bool isShufflable; bool alwaysRevealTopCard; - virtual void addCardImpl(CardItem *card, int x, int y) = 0; + virtual void addCardImpl(CardState *card, int x, int y) = 0; }; #endif // COCKATRICE_CARD_ZONE_LOGIC_H diff --git a/cockatrice/src/game/zones/hand_zone_logic.cpp b/cockatrice/src/game/zones/hand_zone_logic.cpp index cea17d031..1d3f54929 100644 --- a/cockatrice/src/game/zones/hand_zone_logic.cpp +++ b/cockatrice/src/game/zones/hand_zone_logic.cpp @@ -1,6 +1,6 @@ #include "hand_zone_logic.h" -#include "../../game_graphics/board/card_item.h" +#include "../board/card_state.h" #include "card_zone_algorithms.h" class PlayerLogic; @@ -16,7 +16,7 @@ HandZoneLogic::HandZoneLogic(PlayerLogic *_player, { } -void HandZoneLogic::addCardImpl(CardItem *card, int x, int /*y*/) +void HandZoneLogic::addCardImpl(CardState *card, int x, int /*y*/) { CardZoneAlgorithms::addCardToList(cards, card, x, false); } diff --git a/cockatrice/src/game/zones/hand_zone_logic.h b/cockatrice/src/game/zones/hand_zone_logic.h index c7d63bc0d..f8756eafd 100644 --- a/cockatrice/src/game/zones/hand_zone_logic.h +++ b/cockatrice/src/game/zones/hand_zone_logic.h @@ -26,7 +26,7 @@ public: QObject *parent = nullptr); protected: - void addCardImpl(CardItem *card, int x, int y) override; + void addCardImpl(CardState *card, int x, int y) override; }; #endif // COCKATRICE_HAND_ZONE_LOGIC_H diff --git a/cockatrice/src/game/zones/pile_zone_logic.cpp b/cockatrice/src/game/zones/pile_zone_logic.cpp index acb9f529b..42ef4f0b2 100644 --- a/cockatrice/src/game/zones/pile_zone_logic.cpp +++ b/cockatrice/src/game/zones/pile_zone_logic.cpp @@ -1,7 +1,7 @@ #include "pile_zone_logic.h" -#include "../../game_graphics/board/card_item.h" #include "../board/card_list.h" +#include "../board/card_state.h" class PlayerLogic; class QObject; @@ -16,9 +16,9 @@ PileZoneLogic::PileZoneLogic(PlayerLogic *_player, { } -void PileZoneLogic::addCardImpl(CardItem *card, int x, int /*y*/) +void PileZoneLogic::addCardImpl(CardState *card, int x, int /*y*/) { - connect(card->getState(), &CardState::cardPixmapUpdated, this, &PileZoneLogic::callUpdate); + connect(card, &CardState::cardPixmapUpdated, this, &PileZoneLogic::callUpdate); // if x is negative set it to add at end if (x < 0 || x >= cards.size()) { x = cards.size(); @@ -32,5 +32,5 @@ void PileZoneLogic::addCardImpl(CardItem *card, int x, int /*y*/) cards.at(x + 1)->setCardRef({}); } } - card->resetState(); + card->resetState(false); } \ No newline at end of file diff --git a/cockatrice/src/game/zones/pile_zone_logic.h b/cockatrice/src/game/zones/pile_zone_logic.h index ed6841b75..662b0377f 100644 --- a/cockatrice/src/game/zones/pile_zone_logic.h +++ b/cockatrice/src/game/zones/pile_zone_logic.h @@ -31,7 +31,7 @@ public: QObject *parent = nullptr); protected: - void addCardImpl(CardItem *card, int x, int y) override; + void addCardImpl(CardState *card, int x, int y) override; }; #endif // COCKATRICE_PILE_ZONE_LOGIC_H diff --git a/cockatrice/src/game/zones/stack_zone_logic.cpp b/cockatrice/src/game/zones/stack_zone_logic.cpp index 454274971..ccf0d32f3 100644 --- a/cockatrice/src/game/zones/stack_zone_logic.cpp +++ b/cockatrice/src/game/zones/stack_zone_logic.cpp @@ -1,6 +1,6 @@ #include "stack_zone_logic.h" -#include "../../game_graphics/board/card_item.h" +#include "../board/card_state.h" #include "card_zone_algorithms.h" class PlayerLogic; @@ -16,7 +16,7 @@ StackZoneLogic::StackZoneLogic(PlayerLogic *_player, { } -void StackZoneLogic::addCardImpl(CardItem *card, int x, int /*y*/) +void StackZoneLogic::addCardImpl(CardState *card, int x, int /*y*/) { CardZoneAlgorithms::addCardToList(cards, card, x, true); } diff --git a/cockatrice/src/game/zones/stack_zone_logic.h b/cockatrice/src/game/zones/stack_zone_logic.h index 657d44ecf..ac6c4617c 100644 --- a/cockatrice/src/game/zones/stack_zone_logic.h +++ b/cockatrice/src/game/zones/stack_zone_logic.h @@ -26,7 +26,7 @@ public: QObject *parent = nullptr); protected: - void addCardImpl(CardItem *card, int x, int y) override; + void addCardImpl(CardState *card, int x, int y) override; }; #endif // COCKATRICE_STACK_ZONE_LOGIC_H diff --git a/cockatrice/src/game/zones/table_zone_logic.cpp b/cockatrice/src/game/zones/table_zone_logic.cpp index 83e5e55eb..7a6e74adf 100644 --- a/cockatrice/src/game/zones/table_zone_logic.cpp +++ b/cockatrice/src/game/zones/table_zone_logic.cpp @@ -1,7 +1,7 @@ #include "table_zone_logic.h" -#include "../../game_graphics/board/card_item.h" #include "../board/card_list.h" +#include "../board/card_state.h" #include "libcockatrice/card/card_info.h" #include @@ -19,7 +19,7 @@ TableZoneLogic::TableZoneLogic(PlayerLogic *_player, { } -void TableZoneLogic::addCardImpl(CardItem *card, int _x, int _y) +void TableZoneLogic::addCardImpl(CardState *card, int _x, int _y) { cards.append(card); if (!card->getFaceDown() && card->getPT().isEmpty()) { @@ -31,9 +31,9 @@ void TableZoneLogic::addCardImpl(CardItem *card, int _x, int _y) card->setGridPoint(QPoint(_x, _y)); } -CardItem *TableZoneLogic::takeCard(int position, int cardId, bool toNewZone) +CardState *TableZoneLogic::takeCard(int position, int cardId, bool toNewZone) { - CardItem *result = CardZoneLogic::takeCard(position, cardId); + CardState *result = CardZoneLogic::takeCard(position, cardId); if (toNewZone) { emit contentSizeChanged(); diff --git a/cockatrice/src/game/zones/table_zone_logic.h b/cockatrice/src/game/zones/table_zone_logic.h index 353a497e9..c828d8b91 100644 --- a/cockatrice/src/game/zones/table_zone_logic.h +++ b/cockatrice/src/game/zones/table_zone_logic.h @@ -45,7 +45,7 @@ public: static int tableRowToGridY(int tableRow); protected: - void addCardImpl(CardItem *card, int x, int y) override; + void addCardImpl(CardState *card, int x, int y) override; /** * @brief Removes a card from view. @@ -53,9 +53,9 @@ protected: * @param position card position * @param cardId id of card to take * @param toNewZone Whether the destination of the card is not the same as the starting zone. Defaults to true - * @return CardItem that has been removed + * @return CardState that has been removed */ - CardItem *takeCard(int position, int cardId, bool toNewZone = true) override; + CardState *takeCard(int position, int cardId, bool toNewZone = true) override; }; #endif // COCKATRICE_TABLE_ZONE_LOGIC_H diff --git a/cockatrice/src/game/zones/view_zone_logic.cpp b/cockatrice/src/game/zones/view_zone_logic.cpp index f5e597abe..5e5e0b5fe 100644 --- a/cockatrice/src/game/zones/view_zone_logic.cpp +++ b/cockatrice/src/game/zones/view_zone_logic.cpp @@ -1,8 +1,8 @@ #include "view_zone_logic.h" #include "../../client/settings/cache_settings.h" -#include "../../game_graphics/board/card_item.h" #include "../board/card_list.h" +#include "../board/card_state.h" #include "../player/player_actions.h" #include "../player/player_logic.h" @@ -77,7 +77,7 @@ bool ZoneViewZoneLogic::prepareAddCard(int x) * Make sure prepareAddCard() was called before calling addCard(). * This method assumes we already checked that the card is being inserted into the visible portion */ -void ZoneViewZoneLogic::addCardImpl(CardItem *card, int x, int /*y*/) +void ZoneViewZoneLogic::addCardImpl(CardState *card, int x, int /*y*/) { if (!isReversed) { // if x is negative set it to add at end @@ -146,8 +146,8 @@ void ZoneViewZoneLogic::removeCard(int position, bool toNewZone) return; } - CardItem *card = cards.takeAt(position); - card->getState()->deleteView(); + CardState *card = cards.takeAt(position); + card->deleteView(); // The toNewZone check is to prevent the view from auto-closing if the view contains only a single card and that // card gets dragged within the view. @@ -170,7 +170,7 @@ void ZoneViewZoneLogic::requestClose() void ZoneViewZoneLogic::clearCards() { for (auto card : cards) { - card->getState()->deleteView(); + card->deleteView(); } cards.clear(); emit cardCountChanged(); diff --git a/cockatrice/src/game/zones/view_zone_logic.h b/cockatrice/src/game/zones/view_zone_logic.h index 71261e204..66d4d4791 100644 --- a/cockatrice/src/game/zones/view_zone_logic.h +++ b/cockatrice/src/game/zones/view_zone_logic.h @@ -92,7 +92,7 @@ public: PendingCommand *requestZoneDump(); protected: - void addCardImpl(CardItem *card, int x, int y) override; + void addCardImpl(CardState *card, int x, int y) override; }; #endif // COCKATRICE_VIEW_ZONE_LOGIC_H diff --git a/cockatrice/src/game_graphics/board/card_item.cpp b/cockatrice/src/game_graphics/board/card_item.cpp index 0b2b3cf82..9a308ba51 100644 --- a/cockatrice/src/game_graphics/board/card_item.cpp +++ b/cockatrice/src/game_graphics/board/card_item.cpp @@ -71,6 +71,10 @@ CardItem::CardItem(PlayerLogic *_owner, update(); }); + // The retyped logic layer drives CardState setters directly (bypassing the CardItem wrappers that called + // update()), so repaint on every state change: attacking, annotation, doesntUntap, P/T and counters. + connect(state, &CardState::stateChanged, this, [this] { update(); }); + connect(state, &CardState::viewDeleteRequested, this, &CardItem::deleteLater); } @@ -233,7 +237,7 @@ void CardItem::setAttachedTo(CardItem *_attachedTo) if (state->getAttachedTo()->getZone() == nullptr) { deleteLater(); } else { - emit state->getAttachedTo()->getZone()->cardAdded(this); + emit state->getAttachedTo()->getZone()->cardAdded(state); state->getAttachedTo()->addAttachedCard(this); if (state->getZone() != state->getAttachedTo()->getZone()) { state->getAttachedTo()->getZone()->reorganizeCards(); @@ -245,7 +249,7 @@ void CardItem::setAttachedTo(CardItem *_attachedTo) if (state->getZone() == nullptr) { deleteLater(); } else { - emit state->getZone()->cardAdded(this); + emit state->getZone()->cardAdded(state); } } @@ -467,7 +471,7 @@ void CardItem::handleClickedToPlay(bool shiftHeld) if (SettingsCache::instance().userInterface().getClickPlaysAllSelected()) { emit hideSelected(this); } else { - state->getZone()->removeCard(this); + state->getZone()->removeCard(state); } } else { playCard(shiftHeld); diff --git a/cockatrice/src/game_graphics/game_scene.cpp b/cockatrice/src/game_graphics/game_scene.cpp index f54e3ae28..3422ce28f 100644 --- a/cockatrice/src/game_graphics/game_scene.cpp +++ b/cockatrice/src/game_graphics/game_scene.cpp @@ -137,7 +137,8 @@ static void selectCardsInZone( return; } - for (auto &cardItem : zone->getCards()) { + for (auto *cardState : zone->getCards()) { + auto *cardItem = cardState == nullptr ? nullptr : qobject_cast(cardState->parent()); if (cardItem && filter(cardItem)) { cardItem->setSelected(true); } @@ -596,7 +597,11 @@ void GameScene::addArrow(QSharedPointer data) return; } - CardItem *startCard = startZone->getCard(data->startCardId); + CardState *startCardState = startZone->getCard(data->startCardId); + if (!startCardState) { + return; + } + CardItem *startCard = qobject_cast(startCardState->parent()); if (!startCard) { return; } @@ -607,7 +612,8 @@ void GameScene::addArrow(QSharedPointer data) } else { auto *zone = targetView->getLogic()->getZones().value(data->targetZone); if (zone) { - targetItem = zone->getCard(data->targetCardId); + CardState *targetCardState = zone->getCard(data->targetCardId); + targetItem = targetCardState == nullptr ? nullptr : qobject_cast(targetCardState->parent()); } } if (!targetItem) { diff --git a/cockatrice/src/game_graphics/log/message_log_widget.cpp b/cockatrice/src/game_graphics/log/message_log_widget.cpp index 4a9750fca..ab244dc0b 100644 --- a/cockatrice/src/game_graphics/log/message_log_widget.cpp +++ b/cockatrice/src/game_graphics/log/message_log_widget.cpp @@ -283,7 +283,7 @@ void MessageLogWidget::logDestroyCard(PlayerLogic *player, QString cardName) } void MessageLogWidget::logMoveCard(PlayerLogic *player, - CardItem *card, + CardState *card, CardZoneLogic *startZone, int oldX, CardZoneLogic *targetZone, @@ -662,7 +662,7 @@ void MessageLogWidget::logSetActivePlayer(PlayerLogic *player) QString(tr("%1's turn.")).arg(player->getPlayerInfo()->getName()) + "
"); } -void MessageLogWidget::logSetAnnotation(PlayerLogic *player, CardItem *card, QString newAnnotation) +void MessageLogWidget::logSetAnnotation(PlayerLogic *player, CardState *card, QString newAnnotation) { appendHtmlServerMessage( QString(tr("%1 sets annotation of %2 to %3.")) @@ -706,7 +706,7 @@ void MessageLogWidget::logSetCounter(PlayerLogic *player, QString counterName, i .arg(value - oldValue)); } -void MessageLogWidget::logSetDoesntUntap(PlayerLogic *player, CardItem *card, bool doesntUntap) +void MessageLogWidget::logSetDoesntUntap(PlayerLogic *player, CardState *card, bool doesntUntap) { QString str; if (doesntUntap) { @@ -717,7 +717,7 @@ void MessageLogWidget::logSetDoesntUntap(PlayerLogic *player, CardItem *card, bo appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(cardLink(card->getName()))); } -void MessageLogWidget::logSetPT(PlayerLogic *player, CardItem *card, QString newPT) +void MessageLogWidget::logSetPT(PlayerLogic *player, CardState *card, QString newPT) { if (currentContext == MessageContext_MoveCard) { return; @@ -755,7 +755,7 @@ void MessageLogWidget::logSetSideboardLock(PlayerLogic *player, bool locked) } } -void MessageLogWidget::logSetTapped(PlayerLogic *player, CardItem *card, bool tapped) +void MessageLogWidget::logSetTapped(PlayerLogic *player, CardState *card, bool tapped) { if (currentContext == MessageContext_MoveCard) { return; diff --git a/cockatrice/src/game_graphics/log/message_log_widget.h b/cockatrice/src/game_graphics/log/message_log_widget.h index 6800ba8ed..5642a76e9 100644 --- a/cockatrice/src/game_graphics/log/message_log_widget.h +++ b/cockatrice/src/game_graphics/log/message_log_widget.h @@ -14,6 +14,7 @@ #include #include +class CardState; class AbstractGame; class CardItem; class GameEventContext; @@ -76,7 +77,7 @@ public slots: void logLeaveSpectator(QString name, QString reason); void logNotReadyStart(PlayerLogic *player); void logMoveCard(PlayerLogic *player, - CardItem *card, + CardState *card, CardZoneLogic *startZone, int oldX, CardZoneLogic *targetZone, @@ -97,13 +98,13 @@ public slots: void logSay(PlayerLogic *player, QString message); void logSetActivePhase(int phase); void logSetActivePlayer(PlayerLogic *player); - void logSetAnnotation(PlayerLogic *player, CardItem *card, QString newAnnotation); + void logSetAnnotation(PlayerLogic *player, CardState *card, QString newAnnotation); void logSetCardCounter(PlayerLogic *player, QString cardName, int counterId, int value, int oldValue); void logSetCounter(PlayerLogic *player, QString counterName, int value, int oldValue); - void logSetDoesntUntap(PlayerLogic *player, CardItem *card, bool doesntUntap); - void logSetPT(PlayerLogic *player, CardItem *card, QString newPT); + void logSetDoesntUntap(PlayerLogic *player, CardState *card, bool doesntUntap); + void logSetPT(PlayerLogic *player, CardState *card, QString newPT); void logSetSideboardLock(PlayerLogic *player, bool locked); - void logSetTapped(PlayerLogic *player, CardItem *card, bool tapped); + void logSetTapped(PlayerLogic *player, CardState *card, bool tapped); void logShuffle(PlayerLogic *player, CardZoneLogic *zone, int start, int end); void logSpectatorSay(const ServerInfo_User &spectator, QString message); void logUnattachCard(PlayerLogic *player, QString cardName); diff --git a/cockatrice/src/game_graphics/player/player_graphics_item.cpp b/cockatrice/src/game_graphics/player/player_graphics_item.cpp index 419816087..14c0dba1c 100644 --- a/cockatrice/src/game_graphics/player/player_graphics_item.cpp +++ b/cockatrice/src/game_graphics/player/player_graphics_item.cpp @@ -177,6 +177,22 @@ void PlayerGraphicsItem::initializeZones() void PlayerGraphicsItem::onCustomZoneAdded(QString customZoneName) { + // Custom zones have no board view, but their cards still need a graphics owner. + // Without one, PileZone::onCardAdded never runs and cards moved from the table + // or hand into a custom zone stay drawn at their old spot. Give them a hidden + // pile zone so added cards are reparented to (0, 0) and hidden. + CardZoneLogic *logic = player->getZone(customZoneName); + if (auto *pileLogic = qobject_cast(logic)) { + auto *hiddenZone = new PileZone(pileLogic, this); + hiddenZone->setVisible(false); + hiddenZone->setPos(0, 0); + zoneGraphicsItems.insert(customZoneName, hiddenZone); + // Hide any cards that arrived before the graphics item existed. + for (CardState *state : pileLogic->getCards()) { + hiddenZone->onCardAdded(state); + } + return; + } zoneGraphicsItems.insert(customZoneName, nullptr); // Custom zone view goes here, if we ever implement it. } diff --git a/cockatrice/src/game_graphics/zones/card_zone.cpp b/cockatrice/src/game_graphics/zones/card_zone.cpp index 8ab942a67..b29ad3666 100644 --- a/cockatrice/src/game_graphics/zones/card_zone.cpp +++ b/cockatrice/src/game_graphics/zones/card_zone.cpp @@ -37,17 +37,26 @@ void CardZone::invalidateItems() const QList &CardZone::cardItems() const { if (itemsDirty) { - items = getLogic()->getCards(); + items.clear(); + for (auto *cardState : getLogic()->getCards()) { + if (auto *cardItem = qobject_cast(cardState->parent())) { + items.append(cardItem); + } + } itemsDirty = false; } return items; } -void CardZone::onCardAdded(CardItem *addedCard) +void CardZone::onCardAdded(CardState *addedCard) { - addedCard->setParentItem(this); - addedCard->setVisible(true); - addedCard->update(); + auto *addedItem = addedCard == nullptr ? nullptr : qobject_cast(addedCard->parent()); + if (addedItem == nullptr) { + return; + } + addedItem->setParentItem(this); + addedItem->setVisible(true); + addedItem->update(); } void CardZone::retranslateUi() diff --git a/cockatrice/src/game_graphics/zones/card_zone.h b/cockatrice/src/game_graphics/zones/card_zone.h index 950b54446..7568cf25f 100644 --- a/cockatrice/src/game_graphics/zones/card_zone.h +++ b/cockatrice/src/game_graphics/zones/card_zone.h @@ -16,6 +16,7 @@ class CardDragItem; class CardItem; +class CardState; class CardZoneLogic; class QAction; class QGraphicsItem; @@ -23,6 +24,8 @@ class QMenu; class QPoint; template class QList; +class CardItem; + inline Q_LOGGING_CATEGORY(CardZoneLog, "card_zone"); /** @@ -55,7 +58,7 @@ public slots: * Virtual so subclasses (e.g. SelectZone) can override parenting behavior — the Qt signal * connection in CardZone's constructor dispatches through the vtable. */ - virtual void onCardAdded(CardItem *addedCard); + virtual void onCardAdded(CardState *addedCard); public: enum diff --git a/cockatrice/src/game_graphics/zones/pile_zone.cpp b/cockatrice/src/game_graphics/zones/pile_zone.cpp index 7696ceafd..61946bea1 100644 --- a/cockatrice/src/game_graphics/zones/pile_zone.cpp +++ b/cockatrice/src/game_graphics/zones/pile_zone.cpp @@ -87,12 +87,13 @@ void PileZone::handleDropEvent(const QList &dragItems, CardZoneL getLogic()->getPlayer()->getPlayerActions()->moveCards(startZone, getLogic(), 0, 0, cards); } -void PileZone::onCardAdded(CardItem *addedCard) +void PileZone::onCardAdded(CardState *addedCard) { CardZone::onCardAdded(addedCard); - if (addedCard) { - addedCard->setPos(0, 0); - addedCard->setVisible(false); + auto *addedItem = addedCard == nullptr ? nullptr : qobject_cast(addedCard->parent()); + if (addedItem) { + addedItem->setPos(0, 0); + addedItem->setVisible(false); } } diff --git a/cockatrice/src/game_graphics/zones/pile_zone.h b/cockatrice/src/game_graphics/zones/pile_zone.h index 5dc02a0e4..fa510ad52 100644 --- a/cockatrice/src/game_graphics/zones/pile_zone.h +++ b/cockatrice/src/game_graphics/zones/pile_zone.h @@ -33,7 +33,7 @@ public: [[nodiscard]] QPainterPath shape() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; void reorganizeCards() override; - void onCardAdded(CardItem *addedCard) override; + void onCardAdded(CardState *addedCard) override; void handleDropEvent(const QList &dragItems, CardZoneLogic *startZone, const QPoint &dropPoint) override; diff --git a/cockatrice/src/game_graphics/zones/select_zone.cpp b/cockatrice/src/game_graphics/zones/select_zone.cpp index 9b0c4e60a..7a74c5342 100644 --- a/cockatrice/src/game_graphics/zones/select_zone.cpp +++ b/cockatrice/src/game_graphics/zones/select_zone.cpp @@ -172,12 +172,13 @@ SelectZone::~SelectZone() } } -void SelectZone::onCardAdded(CardItem *addedCard) +void SelectZone::onCardAdded(CardState *addedCard) { - if (cardClipContainer && addedCard) { - addedCard->setParentItem(cardClipContainer); - addedCard->setVisible(true); - addedCard->update(); + auto *addedItem = addedCard == nullptr ? nullptr : qobject_cast(addedCard->parent()); + if (cardClipContainer && addedItem) { + addedItem->setParentItem(cardClipContainer); + addedItem->setVisible(true); + addedItem->update(); } else { CardZone::onCardAdded(addedCard); } diff --git a/cockatrice/src/game_graphics/zones/select_zone.h b/cockatrice/src/game_graphics/zones/select_zone.h index 8a56949e3..8c81f0dbf 100644 --- a/cockatrice/src/game_graphics/zones/select_zone.h +++ b/cockatrice/src/game_graphics/zones/select_zone.h @@ -35,7 +35,7 @@ public: SelectZone(CardZoneLogic *logic, QGraphicsItem *parent = nullptr); ~SelectZone() override; - void onCardAdded(CardItem *addedCard) override; + void onCardAdded(CardState *addedCard) override; /** * @brief Temporarily reparents a card from the clip container to this zone so hover scaling is visible beyond clip diff --git a/cockatrice/src/game_graphics/zones/view_zone.cpp b/cockatrice/src/game_graphics/zones/view_zone.cpp index 7d47b3259..27041e04c 100644 --- a/cockatrice/src/game_graphics/zones/view_zone.cpp +++ b/cockatrice/src/game_graphics/zones/view_zone.cpp @@ -95,7 +95,7 @@ void ZoneViewZone::initializeCards(const QList &cardLis auto copy = new CardItem(getLogic()->getPlayer(), this, cardRef, card->id()); copy->setFaceDown(card->face_down()); - getLogic()->addCard(copy, false, i); + getLogic()->addCard(copy->getState(), false, i); } reorganizeCards(); } else if (!qobject_cast(getLogic())->getOriginalZone()->contentsKnown()) { @@ -107,11 +107,11 @@ void ZoneViewZone::initializeCards(const QList &cardLis const CardList &c = qobject_cast(getLogic())->getOriginalZone()->getCards(); int number = numberCards == -1 ? c.size() : (numberCards < c.size() ? numberCards : c.size()); for (int i = 0; i < number; i++) { - CardItem *card = c.at(i); + CardState *card = c.at(i); auto copy = new CardItem(getLogic()->getPlayer(), this, card->getCardRef(), card->getId()); copy->setFaceDown(card->getFaceDown()); - getLogic()->addCard(copy, false, i); + getLogic()->addCard(copy->getState(), false, i); } reorganizeCards(); } @@ -127,7 +127,7 @@ void ZoneViewZone::zoneDumpReceived(const Response &r) 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); + getLogic()->rawInsertCard(card->getState(), i); } qobject_cast(getLogic())->updateCardIds(ZoneViewZoneLogic::INITIALIZE); @@ -145,7 +145,7 @@ void ZoneViewZone::reorganizeCards() for (auto card : cardItems()) { if (filterString.check(card->getCard().getCardPtr())) { card->show(); - cardsToDisplay.append(card); + cardsToDisplay.append(card->getState()); } else { card->hide(); } @@ -213,7 +213,8 @@ ZoneViewZone::GridSize ZoneViewZone::positionCardsForDisplay(CardList &cards, Ca const auto extractor = CardList::getExtractorFor(pileOption); for (int i = 0; i < cardCount; i++) { - CardItem *c = cards.at(i); + CardState *c = cards.at(i); + CardItem *cItem = qobject_cast(c->parent()); QString columnProp = extractor(c); if (i) { // if not the first card @@ -228,8 +229,8 @@ ZoneViewZone::GridSize ZoneViewZone::positionCardsForDisplay(CardList &cards, Ca lastColumnProp = columnProp; qreal x = col * CardDimensions::WIDTH_F; qreal y = row * CardDimensions::HEIGHT_F / 3; - c->setPos(HORIZONTAL_PADDING + x, VERTICAL_PADDING + y); - c->setRealZValue(i); + cItem->setPos(HORIZONTAL_PADDING + x, VERTICAL_PADDING + y); + cItem->setRealZValue(i); longestRow = qMax(row, longestRow); } @@ -254,11 +255,11 @@ ZoneViewZone::GridSize ZoneViewZone::positionCardsForDisplay(CardList &cards, Ca qCDebug(ViewZoneLog) << "reorganizeCards: rows=" << rows << "cols=" << cols; for (int i = 0; i < cardCount; i++) { - CardItem *c = cards.at(i); + auto *cItem = qobject_cast(cards.at(i)->parent()); qreal x = (i / rows) * CardDimensions::WIDTH_F; qreal y = (i % rows) * CardDimensions::HEIGHT_F / 3; - c->setPos(HORIZONTAL_PADDING + x, VERTICAL_PADDING + y); - c->setRealZValue(i); + cItem->setPos(HORIZONTAL_PADDING + x, VERTICAL_PADDING + y); + cItem->setRealZValue(i); } return GridSize{rows, qMax(cols, 1)};