diff --git a/cockatrice/src/game/player/player_actions.cpp b/cockatrice/src/game/player/player_actions.cpp index 0156146ca..bdef380e5 100644 --- a/cockatrice/src/game/player/player_actions.cpp +++ b/cockatrice/src/game/player/player_actions.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -2035,6 +2036,40 @@ void PlayerActions::moveCards(CardZoneLogic *startZone, sendGameCommand(cmd); } +PendingCommand *PlayerActions::prepareZoneDump(CardZoneLogic *zone, int numberCards) +{ + if (!zone) { + return nullptr; + } + + Command_DumpZone cmd; + cmd.set_player_id(zone->getPlayer()->getPlayerInfo()->getId()); + cmd.set_zone_name(zone->getName().toStdString()); + cmd.set_number_cards(numberCards); + if (auto *viewLogic = qobject_cast(zone)) { + cmd.set_is_reversed(viewLogic->getIsReversed()); + } + + return prepareGameCommand(cmd); +} + +void PlayerActions::actToggleTapped(const QString &zoneName, const QList &cards, bool tapped) +{ + QList cmdList; + for (CardItem *card : cards) { + if (card->getTapped() != tapped) { + auto *cmd = new Command_SetCardAttr; + cmd->set_zone(zoneName.toStdString()); + cmd->set_card_id(card->getId()); + cmd->set_attribute(AttrTapped); + cmd->set_attr_value(tapped ? "1" : "0"); + cmdList.append(cmd); + } + } + + sendGameCommand(prepareGameCommand(cmdList)); +} + void PlayerActions::sendGameCommand(const google::protobuf::Message &command) { if (player->getPlayerInfo()->getJudge() && !player->getPlayerInfo()->getLocal()) { diff --git a/cockatrice/src/game/player/player_actions.h b/cockatrice/src/game/player/player_actions.h index 89e4dbbf7..d8b2b3030 100644 --- a/cockatrice/src/game/player/player_actions.h +++ b/cockatrice/src/game/player/player_actions.h @@ -71,6 +71,21 @@ public: void moveCards(CardZoneLogic *startZone, CardZoneLogic *targetZone, int x, int y, const QList &cards); + /** + * @brief Prepares a dump of the given zone, for the caller to connect to and send. + * @param zone Zone to dump. + * @param numberCards How many cards to dump, -1 for all. + */ + PendingCommand *prepareZoneDump(CardZoneLogic *zone, int numberCards); + + /** + * @brief Sets the tapped state of the cards that do not already have it. + * @param zoneName Zone the cards belong to. + * @param cards Cards the view wants toggled. + * @param tapped Desired tapped state. + */ + void actToggleTapped(const QString &zoneName, const QList &cards, bool tapped); + void moveOneCardUntil(CardItem *card); void stopMoveTopCardsUntil(); diff --git a/cockatrice/src/game/zones/view_zone_logic.cpp b/cockatrice/src/game/zones/view_zone_logic.cpp index eb3b7715f..fbda8eaae 100644 --- a/cockatrice/src/game/zones/view_zone_logic.cpp +++ b/cockatrice/src/game/zones/view_zone_logic.cpp @@ -3,6 +3,8 @@ #include "../../client/settings/cache_settings.h" #include "../../game_graphics/board/card_item.h" #include "../board/card_list.h" +#include "../player/player_actions.h" +#include "../player/player_logic.h" #include #include @@ -177,4 +179,14 @@ void ZoneViewZoneLogic::setWriteableRevealZone(bool _writeableRevealZone) emit removeFromViews(); } writeableRevealZone = _writeableRevealZone; -} \ No newline at end of file +} + +PendingCommand *ZoneViewZoneLogic::requestZoneDump() +{ + PlayerActions *actions = getPlayer()->getPlayerActions(); + PendingCommand *pend = actions->prepareZoneDump(this, numberCards); + if (pend != nullptr) { + actions->sendGameCommand(pend); + } + return pend; +} diff --git a/cockatrice/src/game/zones/view_zone_logic.h b/cockatrice/src/game/zones/view_zone_logic.h index 6fae301e4..1abcd0516 100644 --- a/cockatrice/src/game/zones/view_zone_logic.h +++ b/cockatrice/src/game/zones/view_zone_logic.h @@ -12,6 +12,7 @@ class PlayerLogic; class QObject; +class PendingCommand; class ZoneViewZoneLogic : public CardZoneLogic { @@ -73,6 +74,16 @@ public: return origZone; } + /** + * @brief Prepares and sends the zone-dump command for this view. + * @return The pending command, or nullptr when there is no zone to dump. + * + * Keeps command construction in game/ so graphics views don't reach + * through the player into PlayerActions to set it up. The command is sent + * asynchronously, so callers connect to finished() after calling this. + */ + PendingCommand *requestZoneDump(); + protected: void addCardImpl(CardItem *card, int x, int y) override; }; diff --git a/cockatrice/src/game_graphics/zones/table_zone.cpp b/cockatrice/src/game_graphics/zones/table_zone.cpp index 9d6a3830b..748434033 100644 --- a/cockatrice/src/game_graphics/zones/table_zone.cpp +++ b/cockatrice/src/game_graphics/zones/table_zone.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -267,35 +266,18 @@ void TableZone::reorganizeCards() void TableZone::toggleTapped() { - QList selectedItemsRaw = scene()->selectedItems(); - QList selectedItems; - - auto isCardOnTable = [](const QGraphicsItem *item) { - if (auto card = qgraphicsitem_cast(item)) { - return card->getZone()->getName() == ZoneNames::TABLE; - } - return false; - }; - - std::copy_if(selectedItemsRaw.begin(), selectedItemsRaw.end(), std::back_inserter(selectedItems), isCardOnTable); - - bool tapAll = std::any_of(selectedItems.begin(), selectedItems.end(), [](const QGraphicsItem *item) { - return !qgraphicsitem_cast(item)->getTapped(); - }); - QList cmdList; - for (const auto &selectedItem : selectedItems) { - CardItem *temp = qgraphicsitem_cast(selectedItem); - if (temp->getTapped() != tapAll) { - Command_SetCardAttr *cmd = new Command_SetCardAttr; - cmd->set_zone(getLogic()->getName().toStdString()); - cmd->set_card_id(temp->getId()); - cmd->set_attribute(AttrTapped); - cmd->set_attr_value(tapAll ? "1" : "0"); - cmdList.append(cmd); + QList selectedCards; + for (auto *item : scene()->selectedItems()) { + auto *card = qgraphicsitem_cast(item); + if (card && card->getZone()->getName() == ZoneNames::TABLE) { + selectedCards.append(card); } } - getLogic()->getPlayer()->getPlayerActions()->sendGameCommand( - getLogic()->getPlayer()->getPlayerActions()->prepareGameCommand(cmdList)); + + const bool tapAll = std::any_of(selectedCards.begin(), selectedCards.end(), + [](const CardItem *card) { return !card->getTapped(); }); + + getLogic()->getPlayer()->getPlayerActions()->actToggleTapped(getLogic()->getName(), selectedCards, tapAll); } void TableZone::resizeToContents() diff --git a/cockatrice/src/game_graphics/zones/view_zone.cpp b/cockatrice/src/game_graphics/zones/view_zone.cpp index b6659ddda..716d2b963 100644 --- a/cockatrice/src/game_graphics/zones/view_zone.cpp +++ b/cockatrice/src/game_graphics/zones/view_zone.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -98,15 +97,10 @@ void ZoneViewZone::initializeCards(const QList &cardLis } reorganizeCards(); } else if (!qobject_cast(getLogic())->getOriginalZone()->contentsKnown()) { - Command_DumpZone cmd; - cmd.set_player_id(getLogic()->getPlayer()->getPlayerInfo()->getId()); - cmd.set_zone_name(getLogic()->getName().toStdString()); - cmd.set_number_cards(numberCards); - cmd.set_is_reversed(qobject_cast(getLogic())->getIsReversed()); - - PendingCommand *pend = getLogic()->getPlayer()->getPlayerActions()->prepareGameCommand(cmd); - connect(pend, &PendingCommand::finished, this, &ZoneViewZone::zoneDumpReceived); - getLogic()->getPlayer()->getPlayerActions()->sendGameCommand(pend); + PendingCommand *pend = qobject_cast(getLogic())->requestZoneDump(); + if (pend != nullptr) { + connect(pend, &PendingCommand::finished, this, &ZoneViewZone::zoneDumpReceived); + } } else { const CardList &c = qobject_cast(getLogic())->getOriginalZone()->getCards(); int number = numberCards == -1 ? c.size() : (numberCards < c.size() ? numberCards : c.size()); diff --git a/cockatrice/src/game_graphics/zones/view_zone_widget.cpp b/cockatrice/src/game_graphics/zones/view_zone_widget.cpp index 8c82d6401..d6d42c3d9 100644 --- a/cockatrice/src/game_graphics/zones/view_zone_widget.cpp +++ b/cockatrice/src/game_graphics/zones/view_zone_widget.cpp @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include @@ -570,7 +569,7 @@ void ZoneViewWidget::closeEvent(QCloseEvent *event) // manually call zone->close in order to remove it from the origZones views zone->close(); if (shuffleCheckBox.isChecked()) { - player->getPlayerActions()->sendGameCommand(Command_Shuffle()); + player->getPlayerActions()->actShuffle(); } zoneDeleted(); event->accept();