diff --git a/cockatrice/src/game_graphics/deckview/deck_view_container.cpp b/cockatrice/src/game_graphics/deckview/deck_view_container.cpp index c97767ec7..a6e541fca 100644 --- a/cockatrice/src/game_graphics/deckview/deck_view_container.cpp +++ b/cockatrice/src/game_graphics/deckview/deck_view_container.cpp @@ -354,6 +354,19 @@ void DeckViewContainer::resolveAndSendPlaymat() pp->set_vertical_offset(resolved.params.verticalOffset); pp->set_zoom(resolved.params.zoom); PendingCommand *playmatPend = parentGame->getGame()->getGameEventHandler()->prepareGameCommand(playmatCmd); + const QString sentName = resolved.card.name; + connect(playmatPend, &PendingCommand::finished, this, [this, sentName](const Response &r) { + // Only RespFunctionNotAllowed signals a card art DENY rule. Older servers that predate + // playmats answer RespInvalidCommand and strip the mat from DeckSelect, which must stay silent. + if (r.response_code() == Response::RespFunctionNotAllowed) { + if (!sentName.isEmpty()) { + notifyPlaymatBlacklisted( + sentName, tr("The selected playmat card is blacklisted on this server, so it was not applied.")); + } + } else if (r.response_code() == Response::RespOk && !sentName.isEmpty()) { + lastBlacklistedPlaymatNotice.clear(); + } + }); parentGame->getGame()->getGameEventHandler()->sendGameCommand(playmatPend, playerId); } @@ -412,6 +425,15 @@ void DeckViewContainer::deckSelectFinished(const Response &r) switchToDeckLoadedView(); } +void DeckViewContainer::notifyPlaymatBlacklisted(const QString &cardName, const QString &message) +{ + if (cardName.isEmpty() || cardName == lastBlacklistedPlaymatNotice) { + return; + } + lastBlacklistedPlaymatNotice = cardName; + QMessageBox::critical(this, tr("Error"), message); +} + void DeckViewContainer::readyStart() { sendReadyStartCommand(!readyStartButton->getState()); diff --git a/cockatrice/src/game_graphics/deckview/deck_view_container.h b/cockatrice/src/game_graphics/deckview/deck_view_container.h index 80b82b6e5..c064a5b5a 100644 --- a/cockatrice/src/game_graphics/deckview/deck_view_container.h +++ b/cockatrice/src/game_graphics/deckview/deck_view_container.h @@ -60,12 +60,14 @@ private: VisualDeckStorageWidget *visualDeckStorageWidget; TabGame *parentGame; int playerId; - int playmatRotationIndex = 0; ///< Per-match cursor for round-robin playmat mode. - DeckList currentDeck; ///< Cached deck for live settings re-resolution. - PlaymatInfo lastResolvedPlaymat; ///< Tracks last sent playmat to avoid repeats in random mode. + int playmatRotationIndex = 0; ///< Per-match cursor for round-robin playmat mode. + DeckList currentDeck; ///< Cached deck for live settings re-resolution. + PlaymatInfo lastResolvedPlaymat; ///< Tracks last sent playmat to avoid repeats in random mode. + QString lastBlacklistedPlaymatNotice; ///< Card name already reported as blacklisted, to avoid repeat popups. void tryCreateVisualDeckStorageWidget(); void sendReadyStartCommand(bool ready); + void notifyPlaymatBlacklisted(const QString &cardName, const QString &message); private slots: void switchToDeckSelectView(); void switchToDeckLoadedView();