diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt index f8be8aca5..477e8cced 100644 --- a/cockatrice/CMakeLists.txt +++ b/cockatrice/CMakeLists.txt @@ -7,8 +7,6 @@ project(Cockatrice VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${ set(cockatrice_SOURCES ${VERSION_STRING_CPP} # sort by alphabetical order, so that there is no debate about where to add new sources to the list - src/client/game_logic/abstract_client.cpp - src/client/game_logic/key_signals.cpp src/client/get_text_with_max.cpp src/client/menus/deck_editor/deck_editor_menu.cpp src/client/network/client_update_checker.cpp @@ -201,6 +199,7 @@ set(cockatrice_SOURCES src/game/cards/exact_card.cpp src/game/deckview/deck_view.cpp src/game/deckview/deck_view_container.cpp + src/game/deckview/tabbed_deck_view_container.cpp src/game/filters/deck_filter_string.cpp src/game/filters/filter_builder.cpp src/game/filters/filter_card.cpp @@ -226,6 +225,7 @@ set(cockatrice_SOURCES src/game/zones/view_zone.cpp src/game/zones/view_zone_widget.cpp src/main.cpp + src/server/abstract_client.cpp src/server/chat_view/chat_view.cpp src/server/handle_public_servers.cpp src/server/local_client.cpp @@ -256,6 +256,7 @@ set(cockatrice_SOURCES src/settings/shortcut_treeview.cpp src/settings/shortcuts_settings.cpp src/utility/card_info_comparator.cpp + src/utility/key_signals.cpp src/utility/levenshtein.cpp src/utility/logger.cpp src/utility/sequence_edit.cpp diff --git a/cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp b/cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp index b6908ce94..ce88a75c4 100644 --- a/cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp +++ b/cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp @@ -1,6 +1,5 @@ #include "abstract_tab_deck_editor.h" -#include "../../client/game_logic/abstract_client.h" #include "../../client/tapped_out_interface.h" #include "../../client/ui/widgets/cards/card_info_frame_widget.h" #include "../../deck/deck_stats_interface.h" @@ -9,6 +8,7 @@ #include "../../dialogs/dlg_load_deck_from_website.h" #include "../../game/cards/card_database_manager.h" #include "../../game/cards/card_database_model.h" +#include "../../server/abstract_client.h" #include "../../server/pending_command.h" #include "../../settings/cache_settings.h" #include "../ui/picture_loader/picture_loader.h" @@ -549,6 +549,12 @@ void AbstractTabDeckEditor::filterTreeChanged(FilterTree *filterTree) databaseDisplayDockWidget->setFilterTree(filterTree); } +void AbstractTabDeckEditor::closeEvent(QCloseEvent *event) +{ + emit deckEditorClosing(this); + event->accept(); +} + // Method uses to sync docks state with menu items state bool AbstractTabDeckEditor::eventFilter(QObject *o, QEvent *e) { @@ -592,12 +598,11 @@ bool AbstractTabDeckEditor::confirmClose() return true; } -void AbstractTabDeckEditor::closeRequest(bool forced) +bool AbstractTabDeckEditor::closeRequest() { - if (!forced && !confirmClose()) { - return; + if (!confirmClose()) { + return false; } - emit deckEditorClosing(this); - close(); + return close(); } \ No newline at end of file diff --git a/cockatrice/src/client/tabs/abstract_tab_deck_editor.h b/cockatrice/src/client/tabs/abstract_tab_deck_editor.h index 7b52ff3b6..dd85028dc 100644 --- a/cockatrice/src/client/tabs/abstract_tab_deck_editor.h +++ b/cockatrice/src/client/tabs/abstract_tab_deck_editor.h @@ -78,7 +78,7 @@ public slots: void actDecrementCardFromSideboard(const ExactCard &card); void actOpenRecent(const QString &fileName); void filterTreeChanged(FilterTree *filterTree); - void closeRequest(bool forced = false) override; + bool closeRequest() override; virtual void showPrintingSelector() = 0; virtual void dockTopLevelChanged(bool topLevel) = 0; @@ -117,6 +117,7 @@ protected slots: virtual void freeDocksSize() = 0; virtual void refreshShortcuts() = 0; + void closeEvent(QCloseEvent *event) override; bool eventFilter(QObject *o, QEvent *e) override; virtual void dockVisibleTriggered() = 0; virtual void dockFloatingTriggered() = 0; diff --git a/cockatrice/src/client/tabs/tab.cpp b/cockatrice/src/client/tabs/tab.cpp index dcc1ae0c2..8b098c280 100644 --- a/cockatrice/src/client/tabs/tab.cpp +++ b/cockatrice/src/client/tabs/tab.cpp @@ -43,16 +43,7 @@ void Tab::deleteCardInfoPopup(const QString &cardName) } } -/** - * Overrides the closeEvent in order to emit a close signal - */ -void Tab::closeEvent(QCloseEvent *event) +bool Tab::closeRequest() { - emit closed(); - event->accept(); -} - -void Tab::closeRequest(bool /*forced*/) -{ - close(); + return close(); } \ No newline at end of file diff --git a/cockatrice/src/client/tabs/tab.h b/cockatrice/src/client/tabs/tab.h index 68a1882a7..fc97585c3 100644 --- a/cockatrice/src/client/tabs/tab.h +++ b/cockatrice/src/client/tabs/tab.h @@ -15,12 +15,6 @@ class Tab : public QMainWindow signals: void userEvent(bool globalEvent = true); void tabTextChanged(Tab *tab, const QString &newTabText); - /** - * Emitted when the tab is closed (because Qt doesn't provide a built-in close signal) - * This signal is emitted from this class's overridden Tab::closeEvent method. - * Make sure any subclasses that override closeEvent still emit this signal from there. - */ - void closed(); protected: TabSupervisor *tabSupervisor; @@ -31,7 +25,6 @@ protected: protected slots: void showCardInfoPopup(const QPoint &pos, const CardRef &cardRef); void deleteCardInfoPopup(const QString &cardName); - void closeEvent(QCloseEvent *event) override; private: CardRef currentCard; @@ -59,13 +52,16 @@ public: } virtual QString getTabText() const = 0; virtual void retranslateUi() = 0; + /** - * Sends a request to close the tab. - * Signals for cleanup should be emitted from this method instead of the destructor. + * Nicely asks to close the tab. + * Override this method to do checks or ask for confirmation before closing the tab. + * If you need to force close the tab, just call close() instead. * - * @param forced whether this close request was initiated by the user or forced by the server. + * @return True if the tab is successfully closed. */ - virtual void closeRequest(bool forced = false); + virtual bool closeRequest(); + virtual void tabActivated() { } diff --git a/cockatrice/src/client/tabs/tab_account.cpp b/cockatrice/src/client/tabs/tab_account.cpp index 78517a82d..09261b63f 100644 --- a/cockatrice/src/client/tabs/tab_account.cpp +++ b/cockatrice/src/client/tabs/tab_account.cpp @@ -1,11 +1,11 @@ #include "tab_account.h" #include "../../deck/custom_line_edit.h" +#include "../../server/abstract_client.h" #include "../../server/pending_command.h" #include "../../server/user/user_info_box.h" #include "../../server/user/user_list_manager.h" #include "../../server/user/user_list_widget.h" -#include "../game_logic/abstract_client.h" #include "../sound_engine.h" #include "pb/event_add_to_list.pb.h" #include "pb/event_remove_from_list.pb.h" diff --git a/cockatrice/src/client/tabs/tab_admin.cpp b/cockatrice/src/client/tabs/tab_admin.cpp index 5a8ace0c6..3a46441bd 100644 --- a/cockatrice/src/client/tabs/tab_admin.cpp +++ b/cockatrice/src/client/tabs/tab_admin.cpp @@ -1,7 +1,7 @@ #include "tab_admin.h" +#include "../../server/abstract_client.h" #include "../../server/pending_command.h" -#include "../game_logic/abstract_client.h" #include "pb/admin_commands.pb.h" #include "pb/event_replay_added.pb.h" #include "pb/moderator_commands.pb.h" diff --git a/cockatrice/src/client/tabs/tab_deck_editor.cpp b/cockatrice/src/client/tabs/tab_deck_editor.cpp index 45762a76a..9908225d1 100644 --- a/cockatrice/src/client/tabs/tab_deck_editor.cpp +++ b/cockatrice/src/client/tabs/tab_deck_editor.cpp @@ -1,6 +1,5 @@ #include "tab_deck_editor.h" -#include "../../client/game_logic/abstract_client.h" #include "../../client/tapped_out_interface.h" #include "../../client/ui/widgets/cards/card_info_frame_widget.h" #include "../../dialogs/dlg_load_deck.h" @@ -9,6 +8,7 @@ #include "../../game/cards/card_database_model.h" #include "../../game/filters/filter_builder.h" #include "../../game/filters/filter_tree_model.h" +#include "../../server/abstract_client.h" #include "../../server/pending_command.h" #include "../../settings/cache_settings.h" #include "../menus/deck_editor/deck_editor_menu.h" diff --git a/cockatrice/src/client/tabs/tab_deck_editor.h b/cockatrice/src/client/tabs/tab_deck_editor.h index 710689b8e..c5a7f5302 100644 --- a/cockatrice/src/client/tabs/tab_deck_editor.h +++ b/cockatrice/src/client/tabs/tab_deck_editor.h @@ -2,7 +2,7 @@ #define WINDOW_DECKEDITOR_H #include "../../game/cards/card_info.h" -#include "../game_logic/key_signals.h" +#include "../../utility/key_signals.h" #include "../ui/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h" #include "abstract_tab_deck_editor.h" diff --git a/cockatrice/src/client/tabs/tab_deck_storage.h b/cockatrice/src/client/tabs/tab_deck_storage.h index e207a1187..45c6d9a82 100644 --- a/cockatrice/src/client/tabs/tab_deck_storage.h +++ b/cockatrice/src/client/tabs/tab_deck_storage.h @@ -1,8 +1,8 @@ #ifndef TAB_DECK_STORAGE_H #define TAB_DECK_STORAGE_H +#include "../../server/abstract_client.h" #include "../../server/remote/remote_decklist_tree_widget.h" -#include "../game_logic/abstract_client.h" #include "tab.h" class ServerInfo_User; diff --git a/cockatrice/src/client/tabs/tab_game.cpp b/cockatrice/src/client/tabs/tab_game.cpp index c4a119961..770ba2383 100644 --- a/cockatrice/src/client/tabs/tab_game.cpp +++ b/cockatrice/src/client/tabs/tab_game.cpp @@ -7,17 +7,18 @@ #include "../../game/cards/card_database.h" #include "../../game/cards/card_database_manager.h" #include "../../game/deckview/deck_view_container.h" +#include "../../game/deckview/tabbed_deck_view_container.h" #include "../../game/game_scene.h" #include "../../game/game_view.h" #include "../../game/player/player.h" #include "../../game/player/player_list_widget.h" #include "../../game/zones/card_zone.h" #include "../../main.h" +#include "../../server/abstract_client.h" #include "../../server/message_log_widget.h" #include "../../server/pending_command.h" #include "../../server/user/user_list_manager.h" #include "../../settings/cache_settings.h" -#include "../game_logic/abstract_client.h" #include "../network/replay_timeline_widget.h" #include "../ui/line_edit_completer.h" #include "../ui/phases_toolbar.h" @@ -261,6 +262,10 @@ void TabGame::retranslateUi() sayLabel->setText(tr("&Say:")); } + if (aCardMenu) { + aCardMenu->setText(tr("Selected cards")); + } + viewMenu->setTitle(tr("&View")); cardInfoDockMenu->setTitle(tr("Card Info")); messageLayoutDockMenu->setTitle(tr("Messages")); @@ -288,9 +293,9 @@ void TabGame::retranslateUi() QMapIterator i(players); while (i.hasNext()) i.next().value()->retranslateUi(); - QMapIterator j(deckViewContainers); + QMapIterator j(deckViewContainers); while (j.hasNext()) - j.next().value()->retranslateUi(); + j.next().value()->playerDeckView->retranslateUi(); scene->retranslateUi(); } @@ -376,15 +381,19 @@ void TabGame::refreshShortcuts() } } -void TabGame::closeRequest(bool forced) +bool TabGame::closeRequest() { - if (!forced && !leaveGame()) { - return; + if (!leaveGame()) { + return false; } - emit gameClosing(this); + return close(); +} - close(); +void TabGame::closeEvent(QCloseEvent *event) +{ + emit gameClosing(this); + event->accept(); } void TabGame::incrementGameTime() @@ -407,11 +416,6 @@ void TabGame::adminLockChanged(bool lock) sayEdit->setVisible(v); } -bool TabGame::isSpectator() -{ - return spectator; -} - void TabGame::actGameInfo() { DlgCreateGame dlg(gameInfo, roomGameTypes, this); @@ -561,7 +565,7 @@ void TabGame::actCompleterChanged() Player *TabGame::addPlayer(int playerId, const ServerInfo_User &info) { - bool local = ((clients.size() > 1) || (playerId == localPlayerId)); + bool local = clients.size() > 1 || playerId == localPlayerId; auto *newPlayer = new Player(info, playerId, local, judge, this); connect(newPlayer, SIGNAL(openDeckEditor(const DeckLoader *)), this, SIGNAL(openDeckEditor(const DeckLoader *))); QString newPlayerName = "@" + newPlayer->getName(); @@ -572,14 +576,15 @@ Player *TabGame::addPlayer(int playerId, const ServerInfo_User &info) scene->addPlayer(newPlayer); connect(newPlayer, &Player::newCardAdded, this, &TabGame::newCardAdded); + connect(newPlayer, &Player::cardMenuUpdated, this, &TabGame::setCardMenu); messageLog->connectToPlayer(newPlayer); if (local && !spectator) { if (clients.size() == 1) newPlayer->setShortcutsActive(); - auto *deckView = new DeckViewContainer(playerId, this); - connect(deckView, &DeckViewContainer::newCardAdded, this, &TabGame::newCardAdded); + auto *deckView = new TabbedDeckViewContainer(playerId, this); + connect(deckView->playerDeckView, &DeckViewContainer::newCardAdded, this, &TabGame::newCardAdded); deckViewContainers.insert(playerId, deckView); deckViewContainerLayout->addWidget(deckView); @@ -587,8 +592,8 @@ Player *TabGame::addPlayer(int playerId, const ServerInfo_User &info) QString deckPath = SettingsCache::instance().debug().getDeckPathForPlayer(newPlayer->getName()); if (!deckPath.isEmpty()) { QTimer::singleShot(0, this, [deckView, deckPath] { - deckView->loadDeckFromFile(deckPath); - deckView->readyAndUpdate(); + deckView->playerDeckView->loadDeckFromFile(deckPath); + deckView->playerDeckView->readyAndUpdate(); }); } } @@ -773,11 +778,11 @@ void TabGame::startGame(bool _resuming) { currentPhase = -1; - QMapIterator i(deckViewContainers); + QMapIterator i(deckViewContainers); while (i.hasNext()) { i.next(); - i.value()->setReadyStart(false); - i.value()->setVisualDeckStorageExists(false); + i.value()->playerDeckView->setReadyStart(false); + i.value()->playerDeckView->setVisualDeckStorageExists(false); i.value()->hide(); } @@ -799,7 +804,7 @@ void TabGame::stopGame() currentPhase = -1; activePlayer = -1; - QMapIterator i(deckViewContainers); + QMapIterator i(deckViewContainers); while (i.hasNext()) { i.next(); i.value()->show(); @@ -845,6 +850,9 @@ void TabGame::eventGameStateChanged(const Event_GameStateChanged &event, const GameEventContext & /*context*/) { const int playerListSize = event.player_list_size(); + + QVector>> opponentDecksToDisplay; + for (int i = 0; i < playerListSize; ++i) { const ServerInfo_Player &playerInfo = event.player_list(i); const ServerInfo_PlayerProperties &prop = playerInfo.properties(); @@ -867,16 +875,23 @@ void TabGame::eventGameStateChanged(const Event_GameStateChanged &event, } player->processPlayerInfo(playerInfo); if (player->getLocal()) { - DeckViewContainer *deckViewContainer = deckViewContainers.value(playerId); + TabbedDeckViewContainer *deckViewContainer = deckViewContainers.value(playerId); if (playerInfo.has_deck_list()) { DeckLoader newDeck(QString::fromStdString(playerInfo.deck_list())); PictureLoader::cacheCardPixmaps( CardDatabaseManager::getInstance()->getCards(newDeck.getCardRefList())); - deckViewContainer->setDeck(newDeck); + deckViewContainer->playerDeckView->setDeck(newDeck); player->setDeck(newDeck); } - deckViewContainer->setReadyStart(prop.ready_start()); - deckViewContainer->setSideboardLocked(prop.sideboard_locked()); + deckViewContainer->playerDeckView->setReadyStart(prop.ready_start()); + deckViewContainer->playerDeckView->setSideboardLocked(prop.sideboard_locked()); + } else { + if (!gameInfo.share_decklists_on_load()) { + continue; + } + + opponentDecksToDisplay.append( + qMakePair(playerId, qMakePair(playerName, QString::fromStdString(playerInfo.deck_list())))); } } } @@ -891,6 +906,21 @@ void TabGame::eventGameStateChanged(const Event_GameStateChanged &event, } } + for (const auto &entry : opponentDecksToDisplay) { + int playerId = entry.first; + QString playerName = entry.second.first; + QString deckList = entry.second.second; + + DeckList loader; + loader.loadFromString_Native(deckList); + + QMapIterator it(deckViewContainers); + while (it.hasNext()) { + it.next(); + it.value()->addOpponentDeckView(loader, playerId, playerName); + } + } + secondsElapsed = event.seconds_elapsed(); if (event.game_started() && !gameInfo.started()) { @@ -922,7 +952,7 @@ void TabGame::eventPlayerPropertiesChanged(const Event_PlayerPropertiesChanged & case GameEventContext::READY_START: { bool ready = prop.ready_start(); if (player->getLocal()) - deckViewContainers.value(player->getId())->setReadyStart(ready); + deckViewContainers.value(player->getId())->playerDeckView->setReadyStart(ready); if (ready) messageLog->logReadyStart(player); else @@ -953,11 +983,20 @@ void TabGame::eventPlayerPropertiesChanged(const Event_PlayerPropertiesChanged & Context_DeckSelect deckSelect = context.GetExtension(Context_DeckSelect::ext); messageLog->logDeckSelect(player, QString::fromStdString(deckSelect.deck_hash()), deckSelect.sideboard_size()); + if (gameInfo.share_decklists_on_load() && deckSelect.has_deck_list() && eventPlayerId != localPlayerId) { + DeckList loader; + loader.loadFromString_Native(QString::fromStdString(deckSelect.deck_list())); + QMapIterator i(deckViewContainers); + while (i.hasNext()) { + i.next(); + i.value()->addOpponentDeckView(loader, eventPlayerId, player->getName()); + } + } break; } case GameEventContext::SET_SIDEBOARD_LOCK: { if (player->getLocal()) - deckViewContainers.value(player->getId())->setSideboardLocked(prop.sideboard_locked()); + deckViewContainers.value(player->getId())->playerDeckView->setSideboardLocked(prop.sideboard_locked()); messageLog->logSetSideboardLock(player, prop.sideboard_locked()); break; } @@ -1209,22 +1248,21 @@ Player *TabGame::getActiveLocalPlayer() const void TabGame::setActiveCard(CardItem *card) { activeCard = card; - updateCardMenu(card); } -void TabGame::updateCardMenu(AbstractCardItem *card) +/** + * @param menu The menu to set. Pass in nullptr to set the menu to empty. + */ +void TabGame::setCardMenu(QMenu *menu) { - if (card == nullptr) { + if (!aCardMenu) { return; } - Player *player; - if ((clients.size() > 1) || !players.contains(localPlayerId)) { - player = card->getOwner(); + + if (menu) { + aCardMenu->setMenu(menu); } else { - player = players.value(localPlayerId); - } - if (player != nullptr) { - player->updateCardMenu(static_cast(card)); + aCardMenu->setMenu(new QMenu); } } @@ -1249,7 +1287,7 @@ void TabGame::createMenuItems() aConcede = new QAction(this); connect(aConcede, &QAction::triggered, this, &TabGame::actConcede); aLeaveGame = new QAction(this); - connect(aLeaveGame, &QAction::triggered, this, [this] { closeRequest(); }); + connect(aLeaveGame, &QAction::triggered, this, &TabGame::closeRequest); aFocusChat = new QAction(this); connect(aFocusChat, &QAction::triggered, sayEdit, qOverload<>(&LineEditCompleter::setFocus)); aCloseReplay = nullptr; @@ -1281,6 +1319,11 @@ void TabGame::createMenuItems() gameMenu->addAction(aConcede); gameMenu->addAction(aFocusChat); gameMenu->addAction(aLeaveGame); + + gameMenu->addSeparator(); + + aCardMenu = gameMenu->addMenu(new QMenu(this)); + addTabMenu(gameMenu); } @@ -1299,11 +1342,14 @@ void TabGame::createReplayMenuItems() aFocusChat = nullptr; aLeaveGame = nullptr; aCloseReplay = new QAction(this); - connect(aCloseReplay, &QAction::triggered, this, [this] { closeRequest(); }); + connect(aCloseReplay, &QAction::triggered, this, &TabGame::closeRequest); phasesMenu = nullptr; gameMenu = new QMenu(this); gameMenu->addAction(aCloseReplay); + + aCardMenu = nullptr; + addTabMenu(gameMenu); } diff --git a/cockatrice/src/client/tabs/tab_game.h b/cockatrice/src/client/tabs/tab_game.h index e00a76dc8..e7f69485c 100644 --- a/cockatrice/src/client/tabs/tab_game.h +++ b/cockatrice/src/client/tabs/tab_game.h @@ -13,6 +13,7 @@ #include #include +class TabbedDeckViewContainer; inline Q_LOGGING_CATEGORY(TabGameLog, "tab_game"); class UserListProxy; @@ -105,7 +106,7 @@ private: PhasesToolbar *phasesToolbar; GameScene *scene; GameView *gameView; - QMap deckViewContainers; + QMap deckViewContainers; QVBoxLayout *deckViewContainerLayout; QWidget *gamePlayAreaWidget, *deckViewContainerWidget; QDockWidget *cardInfoDock, *messageLayoutDock, *playerListDock, *replayDock; @@ -118,6 +119,7 @@ private: *aPlayerListDockVisible, *aPlayerListDockFloating, *aReplayDockVisible, *aReplayDockFloating; QAction *aFocusChat; QList phaseActions; + QAction *aCardMenu; Player *addPlayer(int playerId, const ServerInfo_User &info); @@ -171,7 +173,7 @@ private slots: void incrementGameTime(); void adminLockChanged(bool lock); void newCardAdded(AbstractCardItem *card); - void updateCardMenu(AbstractCardItem *card); + void setCardMenu(QMenu *menu); void actGameInfo(); void actConcede(); @@ -202,6 +204,9 @@ private slots: void dockFloatingTriggered(); void dockTopLevelChanged(bool topLevel); +protected slots: + void closeEvent(QCloseEvent *event) override; + public: TabGame(TabSupervisor *_tabSupervisor, QList &_clients, @@ -212,7 +217,7 @@ public: ~TabGame() override; void retranslateUi() override; void updatePlayerListDockTitle(); - void closeRequest(bool forced = false) override; + bool closeRequest() override; const QMap &getPlayers() const { return players; @@ -231,15 +236,14 @@ public: return gameInfo.game_id(); } QString getTabText() const override; - bool getSpectator() const + bool isSpectator() const { return spectator; } - bool getSpectatorsSeeEverything() const + bool isSpectatorsOmniscient() const { return gameInfo.spectators_omniscient(); } - bool isSpectator(); Player *getActiveLocalPlayer() const; AbstractClient *getClientForPlayer(int playerId) const; diff --git a/cockatrice/src/client/tabs/tab_logs.cpp b/cockatrice/src/client/tabs/tab_logs.cpp index 0f75b4c74..cf289b2ed 100644 --- a/cockatrice/src/client/tabs/tab_logs.cpp +++ b/cockatrice/src/client/tabs/tab_logs.cpp @@ -2,8 +2,8 @@ #include "../../deck/custom_line_edit.h" #include "../../dialogs/dlg_manage_sets.h" +#include "../../server/abstract_client.h" #include "../../server/pending_command.h" -#include "../game_logic/abstract_client.h" #include "pb/moderator_commands.pb.h" #include "pb/response_viewlog_history.pb.h" #include "trice_limits.h" diff --git a/cockatrice/src/client/tabs/tab_message.cpp b/cockatrice/src/client/tabs/tab_message.cpp index 9dc53156d..12b52528e 100644 --- a/cockatrice/src/client/tabs/tab_message.cpp +++ b/cockatrice/src/client/tabs/tab_message.cpp @@ -2,11 +2,11 @@ #include "../../deck/custom_line_edit.h" #include "../../main.h" +#include "../../server/abstract_client.h" #include "../../server/chat_view/chat_view.h" #include "../../server/pending_command.h" #include "../../server/user/user_list_manager.h" #include "../../settings/cache_settings.h" -#include "../game_logic/abstract_client.h" #include "../sound_engine.h" #include "pb/event_user_message.pb.h" #include "pb/serverinfo_user.pb.h" @@ -39,7 +39,7 @@ TabMessage::TabMessage(TabSupervisor *_tabSupervisor, vbox->addWidget(sayEdit); aLeave = new QAction(this); - connect(aLeave, &QAction::triggered, this, [this] { closeRequest(); }); + connect(aLeave, &QAction::triggered, this, &TabMessage::closeRequest); messageMenu = new QMenu(this); messageMenu->addAction(aLeave); @@ -86,10 +86,10 @@ QString TabMessage::getTabText() const return tr("%1 - Private chat").arg(QString::fromStdString(otherUserInfo->name())); } -void TabMessage::closeRequest(bool /*forced*/) +void TabMessage::closeEvent(QCloseEvent *event) { emit talkClosing(this); - close(); + event->accept(); } void TabMessage::sendMessage() diff --git a/cockatrice/src/client/tabs/tab_message.h b/cockatrice/src/client/tabs/tab_message.h index dd7424e5d..659d0b804 100644 --- a/cockatrice/src/client/tabs/tab_message.h +++ b/cockatrice/src/client/tabs/tab_message.h @@ -37,6 +37,9 @@ private slots: void addMentionTag(QString mentionTag); void messageClicked(); +protected slots: + void closeEvent(QCloseEvent *event) override; + public: TabMessage(TabSupervisor *_tabSupervisor, AbstractClient *_client, @@ -44,7 +47,6 @@ public: const ServerInfo_User &_otherUserInfo); ~TabMessage() override; void retranslateUi() override; - void closeRequest(bool forced = false) override; void tabActivated() override; QString getUserName() const; QString getTabText() const override; diff --git a/cockatrice/src/client/tabs/tab_replays.cpp b/cockatrice/src/client/tabs/tab_replays.cpp index 123c3d3fc..59f19a9c4 100644 --- a/cockatrice/src/client/tabs/tab_replays.cpp +++ b/cockatrice/src/client/tabs/tab_replays.cpp @@ -1,9 +1,9 @@ #include "tab_replays.h" +#include "../../server/abstract_client.h" #include "../../server/pending_command.h" #include "../../server/remote/remote_replay_list_tree_widget.h" #include "../../settings/cache_settings.h" -#include "../game_logic/abstract_client.h" #include "pb/command_replay_delete_match.pb.h" #include "pb/command_replay_download.pb.h" #include "pb/command_replay_modify_match.pb.h" @@ -29,6 +29,29 @@ TabReplays::TabReplays(TabSupervisor *_tabSupervisor, AbstractClient *_client, const ServerInfo_User *currentUserInfo) : Tab(_tabSupervisor), client(_client) +{ + leftGroupBox = createLeftLayout(); + rightGroupBox = createRightLayout(); + + // combine layouts + QHBoxLayout *hbox = new QHBoxLayout; + hbox->addWidget(leftGroupBox); + hbox->addWidget(rightGroupBox); + + retranslateUi(); + + QWidget *mainWidget = new QWidget(this); + mainWidget->setLayout(hbox); + setCentralWidget(mainWidget); + + connect(client, &AbstractClient::replayAddedEventReceived, this, &TabReplays::replayAddedEventReceived); + + connect(client, &AbstractClient::userInfoChanged, this, &TabReplays::handleConnected); + connect(client, &AbstractClient::statusChanged, this, &TabReplays::handleConnectionChanged); + setRemoteEnabled(currentUserInfo && currentUserInfo->user_level() & ServerInfo_User::IsRegistered); +} + +QGroupBox *TabReplays::createLeftLayout() { localDirModel = new QFileSystemModel(this); localDirModel->setRootPath(SettingsCache::instance().getReplaysPath()); @@ -52,46 +75,24 @@ TabReplays::TabReplays(TabSupervisor *_tabSupervisor, AbstractClient *_client, c dummyToolBar->setSizePolicy(sizePolicy); dummyToolBar->setVisible(false); - leftToolBar = new QToolBar(this); - leftToolBar->setOrientation(Qt::Horizontal); - leftToolBar->setIconSize(QSize(32, 32)); + QToolBar *toolBar = new QToolBar(this); + toolBar->setOrientation(Qt::Horizontal); + toolBar->setIconSize(QSize(32, 32)); - QToolBar *leftRightmostToolBar = new QToolBar(this); - leftRightmostToolBar->setOrientation(Qt::Horizontal); - leftRightmostToolBar->setIconSize(QSize(32, 32)); + QToolBar *rightmostToolBar = new QToolBar(this); + rightmostToolBar->setOrientation(Qt::Horizontal); + rightmostToolBar->setIconSize(QSize(32, 32)); - QGridLayout *leftToolBarLayout = new QGridLayout; - leftToolBarLayout->addWidget(dummyToolBar, 0, 0, Qt::AlignLeft); - leftToolBarLayout->addWidget(leftToolBar, 0, 1, Qt::AlignHCenter); - leftToolBarLayout->addWidget(leftRightmostToolBar, 0, 2, Qt::AlignRight); + QGridLayout *toolBarLayout = new QGridLayout; + toolBarLayout->addWidget(dummyToolBar, 0, 0, Qt::AlignLeft); + toolBarLayout->addWidget(toolBar, 0, 1, Qt::AlignHCenter); + toolBarLayout->addWidget(rightmostToolBar, 0, 2, Qt::AlignRight); - QVBoxLayout *leftVbox = new QVBoxLayout; - leftVbox->addWidget(localDirView); - leftVbox->addLayout(leftToolBarLayout); - leftGroupBox = new QGroupBox; - leftGroupBox->setLayout(leftVbox); - - // Right side layout - rightToolBar = new QToolBar; - rightToolBar->setOrientation(Qt::Horizontal); - rightToolBar->setIconSize(QSize(32, 32)); - QHBoxLayout *rightToolBarLayout = new QHBoxLayout; - rightToolBarLayout->addStretch(); - rightToolBarLayout->addWidget(rightToolBar); - rightToolBarLayout->addStretch(); - - serverDirView = new RemoteReplayList_TreeWidget(client); - - QVBoxLayout *rightVbox = new QVBoxLayout; - rightVbox->addWidget(serverDirView); - rightVbox->addLayout(rightToolBarLayout); - rightGroupBox = new QGroupBox; - rightGroupBox->setLayout(rightVbox); - - // combine layouts - QHBoxLayout *hbox = new QHBoxLayout; - hbox->addWidget(leftGroupBox); - hbox->addWidget(rightGroupBox); + QVBoxLayout *vbox = new QVBoxLayout; + vbox->addWidget(localDirView); + vbox->addLayout(toolBarLayout); + QGroupBox *groupBox = new QGroupBox; + groupBox->setLayout(vbox); // Left side actions aOpenLocalReplay = new QAction(this); @@ -112,6 +113,36 @@ TabReplays::TabReplays(TabSupervisor *_tabSupervisor, AbstractClient *_client, c aOpenReplaysFolder->setIcon(qApp->style()->standardIcon(QStyle::SP_DirOpenIcon)); connect(aOpenReplaysFolder, &QAction::triggered, this, &TabReplays::actOpenReplaysFolder); + // Add actions to toolbars + toolBar->addAction(aOpenLocalReplay); + toolBar->addAction(aRenameLocal); + toolBar->addAction(aNewLocalFolder); + toolBar->addAction(aDeleteLocalReplay); + + rightmostToolBar->addAction(aOpenReplaysFolder); + + return groupBox; +} + +QGroupBox *TabReplays::createRightLayout() +{ + serverDirView = new RemoteReplayList_TreeWidget(client); + + // Right side layout + QToolBar *toolBar = new QToolBar; + toolBar->setOrientation(Qt::Horizontal); + toolBar->setIconSize(QSize(32, 32)); + QHBoxLayout *toolBarLayout = new QHBoxLayout; + toolBarLayout->addStretch(); + toolBarLayout->addWidget(toolBar); + toolBarLayout->addStretch(); + + QVBoxLayout *vbox = new QVBoxLayout; + vbox->addWidget(serverDirView); + vbox->addLayout(toolBarLayout); + QGroupBox *groupBox = new QGroupBox; + groupBox->setLayout(vbox); + // Right side actions aOpenRemoteReplay = new QAction(this); aOpenRemoteReplay->setIcon(QPixmap("theme:icons/view")); @@ -128,29 +159,12 @@ TabReplays::TabReplays(TabSupervisor *_tabSupervisor, AbstractClient *_client, c connect(aDeleteRemoteReplay, &QAction::triggered, this, &TabReplays::actDeleteRemoteReplay); // Add actions to toolbars - leftToolBar->addAction(aOpenLocalReplay); - leftToolBar->addAction(aRenameLocal); - leftToolBar->addAction(aNewLocalFolder); - leftToolBar->addAction(aDeleteLocalReplay); + toolBar->addAction(aOpenRemoteReplay); + toolBar->addAction(aDownload); + toolBar->addAction(aKeep); + toolBar->addAction(aDeleteRemoteReplay); - leftRightmostToolBar->addAction(aOpenReplaysFolder); - - rightToolBar->addAction(aOpenRemoteReplay); - rightToolBar->addAction(aDownload); - rightToolBar->addAction(aKeep); - rightToolBar->addAction(aDeleteRemoteReplay); - - retranslateUi(); - - QWidget *mainWidget = new QWidget(this); - mainWidget->setLayout(hbox); - setCentralWidget(mainWidget); - - connect(client, &AbstractClient::replayAddedEventReceived, this, &TabReplays::replayAddedEventReceived); - - connect(client, &AbstractClient::userInfoChanged, this, &TabReplays::handleConnected); - connect(client, &AbstractClient::statusChanged, this, &TabReplays::handleConnectionChanged); - setRemoteEnabled(currentUserInfo && currentUserInfo->user_level() & ServerInfo_User::IsRegistered); + return groupBox; } void TabReplays::retranslateUi() diff --git a/cockatrice/src/client/tabs/tab_replays.h b/cockatrice/src/client/tabs/tab_replays.h index 7014a7f6e..dafdcb5ae 100644 --- a/cockatrice/src/client/tabs/tab_replays.h +++ b/cockatrice/src/client/tabs/tab_replays.h @@ -1,7 +1,7 @@ #ifndef TAB_REPLAYS_H #define TAB_REPLAYS_H -#include "../game_logic/abstract_client.h" +#include "../../server/abstract_client.h" #include "tab.h" class ServerInfo_User; @@ -23,7 +23,6 @@ private: AbstractClient *client; QTreeView *localDirView; QFileSystemModel *localDirModel; - QToolBar *leftToolBar, *rightToolBar; RemoteReplayList_TreeWidget *serverDirView; QGroupBox *leftGroupBox, *rightGroupBox; @@ -31,6 +30,9 @@ private: QAction *aOpenReplaysFolder; QAction *aOpenRemoteReplay, *aDownload, *aKeep, *aDeleteRemoteReplay; + QGroupBox *createLeftLayout(); + QGroupBox *createRightLayout(); + void setRemoteEnabled(bool enabled); void downloadNodeAtIndex(const QModelIndex &curLeft, const QModelIndex &curRight); diff --git a/cockatrice/src/client/tabs/tab_room.cpp b/cockatrice/src/client/tabs/tab_room.cpp index 1eb648f48..117673743 100644 --- a/cockatrice/src/client/tabs/tab_room.cpp +++ b/cockatrice/src/client/tabs/tab_room.cpp @@ -1,9 +1,9 @@ #include "tab_room.h" -#include "../../client/game_logic/abstract_client.h" #include "../../dialogs/dlg_settings.h" #include "../../game/game_selector.h" #include "../../main.h" +#include "../../server/abstract_client.h" #include "../../server/chat_view/chat_view.h" #include "../../server/pending_command.h" #include "../../server/user/user_list_manager.h" @@ -103,7 +103,7 @@ TabRoom::TabRoom(TabSupervisor *_tabSupervisor, hbox->addWidget(userList, 1); aLeaveRoom = new QAction(this); - connect(aLeaveRoom, &QAction::triggered, this, [this] { closeRequest(); }); + connect(aLeaveRoom, &QAction::triggered, this, &TabRoom::closeRequest); roomMenu = new QMenu(this); roomMenu->addAction(aLeaveRoom); @@ -173,11 +173,11 @@ void TabRoom::actShowPopup(const QString &message) } } -void TabRoom::closeRequest(bool /*forced*/) +void TabRoom::closeEvent(QCloseEvent *event) { sendRoomCommand(prepareRoomCommand(Command_LeaveRoom())); emit roomClosing(this); - close(); + event->accept(); } void TabRoom::tabActivated() diff --git a/cockatrice/src/client/tabs/tab_room.h b/cockatrice/src/client/tabs/tab_room.h index ca88a256f..4c0c6c18f 100644 --- a/cockatrice/src/client/tabs/tab_room.h +++ b/cockatrice/src/client/tabs/tab_room.h @@ -88,13 +88,15 @@ private slots: void processRemoveMessagesEvent(const Event_RemoveMessages &event); void refreshShortcuts(); +protected slots: + void closeEvent(QCloseEvent *event) override; + public: TabRoom(TabSupervisor *_tabSupervisor, AbstractClient *_client, ServerInfo_User *_ownUser, const ServerInfo_Room &info); void retranslateUi() override; - void closeRequest(bool forced = false) override; void tabActivated() override; void processRoomEvent(const RoomEvent &event); int getRoomId() const diff --git a/cockatrice/src/client/tabs/tab_server.cpp b/cockatrice/src/client/tabs/tab_server.cpp index 24c3e7839..989e98131 100644 --- a/cockatrice/src/client/tabs/tab_server.cpp +++ b/cockatrice/src/client/tabs/tab_server.cpp @@ -1,6 +1,6 @@ #include "tab_server.h" -#include "../../client/game_logic/abstract_client.h" +#include "../../server/abstract_client.h" #include "../../server/pending_command.h" #include "../../server/user/user_list_widget.h" #include "pb/event_list_rooms.pb.h" diff --git a/cockatrice/src/client/tabs/tab_supervisor.cpp b/cockatrice/src/client/tabs/tab_supervisor.cpp index 4ed0e5a6b..feb989fbf 100644 --- a/cockatrice/src/client/tabs/tab_supervisor.cpp +++ b/cockatrice/src/client/tabs/tab_supervisor.cpp @@ -1,7 +1,7 @@ #include "tab_supervisor.h" -#include "../../client/game_logic/abstract_client.h" #include "../../main.h" +#include "../../server/abstract_client.h" #include "../../server/user/user_list_manager.h" #include "../../server/user/user_list_widget.h" #include "../../settings/cache_settings.h" @@ -182,7 +182,16 @@ TabSupervisor::TabSupervisor(AbstractClient *_client, QMenu *tabsMenu, QWidget * TabSupervisor::~TabSupervisor() { - stop(); + // Note: this used to call stop(), but stop() is doing a bunch of stuff including emitting some signals, + // and we don't want to do that in a destructor. + + for (auto &localClient : localClients) { + localClient->deleteLater(); + } + localClients.clear(); + + delete userInfo; + userInfo = nullptr; } void TabSupervisor::retranslateUi() @@ -268,26 +277,6 @@ void TabSupervisor::closeEvent(QCloseEvent *event) event->ignore(); } } - - // Close the game tabs in order to make sure they store their layout. - QSet gameTabsToRemove; - for (auto it = gameTabs.begin(), end = gameTabs.end(); it != end; ++it) { - if (it.value()->close()) { - // Hotfix: the tab owns the `QMenu`s so they need to be cleared, - // otherwise we end up with use-after-free bugs. - if (it.value() == currentWidget()) { - emit setMenu(); - } - - gameTabsToRemove.insert(it.key()); - } else { - event->ignore(); - } - } - - for (auto tabId : gameTabsToRemove) { - gameTabs.remove(tabId); - } } AbstractClient *TabSupervisor::getClient() const @@ -375,7 +364,7 @@ void TabSupervisor::addCloseButtonToTab(Tab *tab, int tabIndex, QAction *manager // If managed, all close requests should go through the menu action connect(closeButton, &CloseButton::clicked, this, [manager] { checkAndTrigger(manager, false); }); } else { - connect(closeButton, &CloseButton::clicked, tab, [tab] { tab->closeRequest(); }); + connect(closeButton, &CloseButton::clicked, tab, &Tab::closeRequest); } tabBar()->setTabButton(tabIndex, closeSide, closeButton); } @@ -469,16 +458,16 @@ void TabSupervisor::stop() emit localGameEnded(); } else { if (tabAccount) { - tabAccount->closeRequest(true); + tabAccount->close(); } if (tabServer) { - tabServer->closeRequest(true); + tabServer->close(); } if (tabAdmin) { - tabAdmin->closeRequest(true); + tabAdmin->close(); } if (tabLog) { - tabLog->closeRequest(true); + tabLog->close(); } } @@ -497,7 +486,7 @@ void TabSupervisor::stop() } for (const auto tab : tabsToDelete) { - tab->closeRequest(true); + tab->close(); } userListManager->handleDisconnect(); @@ -521,7 +510,7 @@ void TabSupervisor::openTabVisualDeckStorage() { tabVisualDeckStorage = new TabDeckStorageVisual(this); myAddTab(tabVisualDeckStorage, aTabVisualDeckStorage); - connect(tabVisualDeckStorage, &Tab::closed, this, [this] { + connect(tabVisualDeckStorage, &QObject::destroyed, this, [this] { tabVisualDeckStorage = nullptr; aTabVisualDeckStorage->setChecked(false); }); @@ -544,7 +533,7 @@ void TabSupervisor::openTabServer() tabServer = new TabServer(this, client); connect(tabServer, &TabServer::roomJoined, this, &TabSupervisor::addRoomTab); myAddTab(tabServer, aTabServer); - connect(tabServer, &Tab::closed, this, [this] { + connect(tabServer, &QObject::destroyed, this, [this] { tabServer = nullptr; aTabServer->setChecked(false); }); @@ -569,7 +558,7 @@ void TabSupervisor::openTabAccount() connect(tabAccount, &TabAccount::userJoined, this, &TabSupervisor::processUserJoined); connect(tabAccount, &TabAccount::userLeft, this, &TabSupervisor::processUserLeft); myAddTab(tabAccount, aTabAccount); - connect(tabAccount, &Tab::closed, this, [this] { + connect(tabAccount, &QObject::destroyed, this, [this] { tabAccount = nullptr; aTabAccount->setChecked(false); }); @@ -592,7 +581,7 @@ void TabSupervisor::openTabDeckStorage() tabDeckStorage = new TabDeckStorage(this, client, userInfo); connect(tabDeckStorage, &TabDeckStorage::openDeckEditor, this, &TabSupervisor::openDeckInNewTab); myAddTab(tabDeckStorage, aTabDeckStorage); - connect(tabDeckStorage, &Tab::closed, this, [this] { + connect(tabDeckStorage, &QObject::destroyed, this, [this] { tabDeckStorage = nullptr; aTabDeckStorage->setChecked(false); }); @@ -615,7 +604,7 @@ void TabSupervisor::openTabReplays() tabReplays = new TabReplays(this, client, userInfo); connect(tabReplays, &TabReplays::openReplay, this, &TabSupervisor::openReplay); myAddTab(tabReplays, aTabReplays); - connect(tabReplays, &Tab::closed, this, [this] { + connect(tabReplays, &QObject::destroyed, this, [this] { tabReplays = nullptr; aTabReplays->setChecked(false); }); @@ -638,7 +627,7 @@ void TabSupervisor::openTabAdmin() tabAdmin = new TabAdmin(this, client, (userInfo->user_level() & ServerInfo_User::IsAdmin)); connect(tabAdmin, &TabAdmin::adminLockChanged, this, &TabSupervisor::adminLockChanged); myAddTab(tabAdmin, aTabAdmin); - connect(tabAdmin, &Tab::closed, this, [this] { + connect(tabAdmin, &QObject::destroyed, this, [this] { tabAdmin = nullptr; aTabAdmin->setChecked(false); }); @@ -660,7 +649,7 @@ void TabSupervisor::openTabLog() { tabLog = new TabLog(this, client); myAddTab(tabLog, aTabLog); - connect(tabLog, &Tab::closed, this, [this] { + connect(tabLog, &QObject::destroyed, this, [this] { tabLog = nullptr; aTabAdmin->setChecked(false); }); diff --git a/cockatrice/src/client/ui/picture_loader/picture_loader_worker_work.cpp b/cockatrice/src/client/ui/picture_loader/picture_loader_worker_work.cpp index 1e7600a75..0f31297ab 100644 --- a/cockatrice/src/client/ui/picture_loader/picture_loader_worker_work.cpp +++ b/cockatrice/src/client/ui/picture_loader/picture_loader_worker_work.cpp @@ -11,6 +11,7 @@ #include #include #include +#include // Card back returned by gatherer when card is not found static const QStringList MD5_BLACKLIST = {"db0c48db407a907c16ade38de048a441"}; @@ -28,16 +29,7 @@ PictureLoaderWorkerWork::PictureLoaderWorkerWork(const PictureLoaderWorker *work // Hook up signals to settings connect(&SettingsCache::instance(), SIGNAL(picDownloadChanged()), this, SLOT(picDownloadChanged())); - pictureLoaderThread = new QThread; - moveToThread(pictureLoaderThread); - - connect(pictureLoaderThread, &QThread::started, this, &PictureLoaderWorkerWork::startNextPicDownload); - - // clean up threads once loading finishes - connect(this, &QObject::destroyed, pictureLoaderThread, &QThread::quit); - connect(pictureLoaderThread, &QThread::finished, pictureLoaderThread, &QObject::deleteLater); - - pictureLoaderThread->start(QThread::LowPriority); + startNextPicDownload(); } void PictureLoaderWorkerWork::startNextPicDownload() diff --git a/cockatrice/src/client/ui/picture_loader/picture_loader_worker_work.h b/cockatrice/src/client/ui/picture_loader/picture_loader_worker_work.h index d03160463..a323c2f1d 100644 --- a/cockatrice/src/client/ui/picture_loader/picture_loader_worker_work.h +++ b/cockatrice/src/client/ui/picture_loader/picture_loader_worker_work.h @@ -33,7 +33,6 @@ public slots: void handleNetworkReply(QNetworkReply *reply); private: - QThread *pictureLoaderThread; bool picDownload; void startNextPicDownload(); diff --git a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_database_display_widget.h b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_database_display_widget.h index 053929bef..4e8711b30 100644 --- a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_database_display_widget.h +++ b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_database_display_widget.h @@ -3,7 +3,7 @@ #include "../../../../deck/custom_line_edit.h" #include "../../../../game/cards/card_database_model.h" -#include "../../../game_logic/key_signals.h" +#include "../../../../utility/key_signals.h" #include "../../../tabs/abstract_tab_deck_editor.h" #include diff --git a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.h b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.h index 0530b87a0..b81bf6096 100644 --- a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.h +++ b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.h @@ -3,7 +3,7 @@ #include "../../../../deck/custom_line_edit.h" #include "../../../../game/cards/card_info.h" -#include "../../../game_logic/key_signals.h" +#include "../../../../utility/key_signals.h" #include "../../../tabs/abstract_tab_deck_editor.h" #include "../visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h" diff --git a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_filter_dock_widget.h b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_filter_dock_widget.h index 9cd8d8d6f..46d7f5de1 100644 --- a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_filter_dock_widget.h +++ b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_filter_dock_widget.h @@ -1,7 +1,7 @@ #ifndef DECK_EDITOR_FILTER_DOCK_WIDGET_H #define DECK_EDITOR_FILTER_DOCK_WIDGET_H -#include "../../../game_logic/key_signals.h" +#include "../../../../utility/key_signals.h" #include "../../../tabs/abstract_tab_deck_editor.h" #include diff --git a/cockatrice/src/client/ui/widgets/printing_selector/card_amount_widget.cpp b/cockatrice/src/client/ui/widgets/printing_selector/card_amount_widget.cpp index 62b6031fd..168a21ee7 100644 --- a/cockatrice/src/client/ui/widgets/printing_selector/card_amount_widget.cpp +++ b/cockatrice/src/client/ui/widgets/printing_selector/card_amount_widget.cpp @@ -140,16 +140,22 @@ void CardAmountWidget::updateCardCount() */ void CardAmountWidget::addPrinting(const QString &zone) { + // Add the card and expand the list UI auto newCardIndex = deckModel->addCard(rootCard, zone); recursiveExpand(newCardIndex); + + // Check if a card without a providerId already exists in the deckModel and replace it, if so. QModelIndex find_card = deckModel->findCard(rootCard.getName(), zone); - if (find_card.isValid() && find_card != newCardIndex) { + QString foundProviderId = deckModel->data(find_card.sibling(find_card.row(), 4), Qt::DisplayRole).toString(); + if (find_card.isValid() && find_card != newCardIndex && foundProviderId == "") { auto amount = deckModel->data(find_card, Qt::DisplayRole); for (int i = 0; i < amount.toInt() - 1; i++) { deckModel->addCard(rootCard, zone); } deckModel->removeRow(find_card.row(), find_card.parent()); } + + // Set Index and Focus as if the user had just clicked the new card and modify the deckEditor saveState newCardIndex = deckModel->findCard(rootCard.getName(), zone, rootCard.getPrinting().getUuid(), rootCard.getPrinting().getProperty("num")); deckView->setCurrentIndex(newCardIndex); diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.h b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.h index 9b729069f..eb30bd88f 100644 --- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.h +++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_widget.h @@ -6,7 +6,7 @@ #include "../../../../game/cards/card_database.h" #include "../../../../game/cards/card_database_model.h" #include "../../../../game/filters/filter_tree_model.h" -#include "../../../game_logic/key_signals.h" +#include "../../../../utility/key_signals.h" #include "../../../tabs/abstract_tab_deck_editor.h" #include "../../layouts/flow_layout.h" #include "../cards/card_info_picture_with_text_overlay_widget.h" diff --git a/cockatrice/src/client/ui/window_main.h b/cockatrice/src/client/ui/window_main.h index 420aac214..76901c9d4 100644 --- a/cockatrice/src/client/ui/window_main.h +++ b/cockatrice/src/client/ui/window_main.h @@ -20,7 +20,7 @@ #ifndef WINDOW_H #define WINDOW_H -#include "../game_logic/abstract_client.h" +#include "../../server/abstract_client.h" #include "pb/response.pb.h" #include diff --git a/cockatrice/src/deck/deck_loader.cpp b/cockatrice/src/deck/deck_loader.cpp index 965e71c56..eef8461bc 100644 --- a/cockatrice/src/deck/deck_loader.cpp +++ b/cockatrice/src/deck/deck_loader.cpp @@ -397,6 +397,7 @@ void DeckLoader::clearSetNamesAndNumbers() // Set the providerId on the card card->setCardSetShortName(nullptr); card->setCardCollectorNumber(nullptr); + card->setCardProviderId(nullptr); }; forEachCard(clearSetNameAndNumber); diff --git a/cockatrice/src/dialogs/dlg_create_game.cpp b/cockatrice/src/dialogs/dlg_create_game.cpp index e601b1b95..ea1c7a8f7 100644 --- a/cockatrice/src/dialogs/dlg_create_game.cpp +++ b/cockatrice/src/dialogs/dlg_create_game.cpp @@ -102,9 +102,15 @@ void DlgCreateGame::sharedCtor() startingLifeTotalEdit->setValue(20); startingLifeTotalLabel->setBuddy(startingLifeTotalEdit); + shareDecklistsOnLoadLabel = new QLabel(tr("Open decklists in lobby")); + shareDecklistsOnLoadCheckBox = new QCheckBox(); + shareDecklistsOnLoadLabel->setBuddy(shareDecklistsOnLoadCheckBox); + QGridLayout *gameSetupOptionsLayout = new QGridLayout; gameSetupOptionsLayout->addWidget(startingLifeTotalLabel, 0, 0); gameSetupOptionsLayout->addWidget(startingLifeTotalEdit, 0, 1); + gameSetupOptionsLayout->addWidget(shareDecklistsOnLoadLabel, 1, 0); + gameSetupOptionsLayout->addWidget(shareDecklistsOnLoadCheckBox, 1, 1); gameSetupOptionsGroupBox = new QGroupBox(tr("Game setup options")); gameSetupOptionsGroupBox->setLayout(gameSetupOptionsLayout); @@ -149,6 +155,7 @@ DlgCreateGame::DlgCreateGame(TabRoom *_room, const QMap &_gameType spectatorsSeeEverythingCheckBox->setChecked(SettingsCache::instance().getSpectatorsCanSeeEverything()); createGameAsSpectatorCheckBox->setChecked(SettingsCache::instance().getCreateGameAsSpectator()); startingLifeTotalEdit->setValue(SettingsCache::instance().getDefaultStartingLifeTotal()); + shareDecklistsOnLoadCheckBox->setChecked(SettingsCache::instance().getShareDecklistsOnLoad()); if (!rememberGameSettings->isChecked()) { actReset(); @@ -181,6 +188,7 @@ DlgCreateGame::DlgCreateGame(const ServerInfo_Game &gameInfo, const QMapsetEnabled(false); createGameAsSpectatorCheckBox->setEnabled(false); startingLifeTotalEdit->setEnabled(false); + shareDecklistsOnLoadCheckBox->setEnabled(false); descriptionEdit->setText(QString::fromStdString(gameInfo.description())); maxPlayersEdit->setValue(gameInfo.max_players()); @@ -225,6 +233,7 @@ void DlgCreateGame::actReset() createGameAsSpectatorCheckBox->setChecked(false); startingLifeTotalEdit->setValue(20); + shareDecklistsOnLoadCheckBox->setChecked(false); QMapIterator gameTypeCheckBoxIterator(gameTypeCheckBoxes); while (gameTypeCheckBoxIterator.hasNext()) { @@ -253,6 +262,7 @@ void DlgCreateGame::actOK() cmd.set_join_as_judge(QApplication::keyboardModifiers() & Qt::ShiftModifier); cmd.set_join_as_spectator(createGameAsSpectatorCheckBox->isChecked()); cmd.set_starting_life_total(startingLifeTotalEdit->value()); + cmd.set_share_decklists_on_load(shareDecklistsOnLoadCheckBox->isChecked()); QString _gameTypes = QString(); QMapIterator gameTypeCheckBoxIterator(gameTypeCheckBoxes); @@ -276,6 +286,7 @@ void DlgCreateGame::actOK() SettingsCache::instance().setSpectatorsCanSeeEverything(spectatorsSeeEverythingCheckBox->isChecked()); SettingsCache::instance().setCreateGameAsSpectator(createGameAsSpectatorCheckBox->isChecked()); SettingsCache::instance().setDefaultStartingLifeTotal(startingLifeTotalEdit->value()); + SettingsCache::instance().setShareDecklistsOnLoad(shareDecklistsOnLoadCheckBox->isChecked()); SettingsCache::instance().setGameTypes(_gameTypes); } PendingCommand *pend = room->prepareRoomCommand(cmd); diff --git a/cockatrice/src/dialogs/dlg_create_game.h b/cockatrice/src/dialogs/dlg_create_game.h index e14278aef..ae10bf01b 100644 --- a/cockatrice/src/dialogs/dlg_create_game.h +++ b/cockatrice/src/dialogs/dlg_create_game.h @@ -36,12 +36,13 @@ private: QMap gameTypeCheckBoxes; QGroupBox *generalGroupBox, *spectatorsGroupBox, *gameSetupOptionsGroupBox; - QLabel *descriptionLabel, *passwordLabel, *maxPlayersLabel, *startingLifeTotalLabel; + QLabel *descriptionLabel, *passwordLabel, *maxPlayersLabel, *startingLifeTotalLabel, *shareDecklistsOnLoadLabel; QLineEdit *descriptionEdit, *passwordEdit; QSpinBox *maxPlayersEdit, *startingLifeTotalEdit; QCheckBox *onlyBuddiesCheckBox, *onlyRegisteredCheckBox; QCheckBox *spectatorsAllowedCheckBox, *spectatorsNeedPasswordCheckBox, *spectatorsCanTalkCheckBox, *spectatorsSeeEverythingCheckBox, *createGameAsSpectatorCheckBox; + QCheckBox *shareDecklistsOnLoadCheckBox; QDialogButtonBox *buttonBox; QPushButton *clearButton; QCheckBox *rememberGameSettings; diff --git a/cockatrice/src/dialogs/dlg_create_token.cpp b/cockatrice/src/dialogs/dlg_create_token.cpp index 2f37c7be6..064c77fa1 100644 --- a/cockatrice/src/dialogs/dlg_create_token.cpp +++ b/cockatrice/src/dialogs/dlg_create_token.cpp @@ -198,7 +198,16 @@ void DlgCreateToken::tokenSelectionChanged(const QModelIndex ¤t, const QMo annotationEdit->setText(""); } - pic->setCard(CardDatabaseManager::getInstance()->getPreferredCard(cardInfo)); + const auto &cardProviderId = + SettingsCache::instance().cardOverrides().getCardPreferenceOverride(cardInfo->getName()); + if (!cardProviderId.isEmpty()) { + CardRef ref; + ref.name = cardInfo->getName(); + ref.providerId = cardProviderId; + pic->setCard(CardDatabaseManager::getInstance()->getCard(ref)); + } else { + pic->setCard(CardDatabaseManager::getInstance()->getPreferredCard(cardInfo)); + } } void DlgCreateToken::updateSearchFieldWithoutUpdatingFilter(const QString &newValue) const @@ -250,5 +259,6 @@ TokenInfo DlgCreateToken::getTokenInfo() const .pt = ptEdit->text(), .annotation = annotationEdit->text(), .destroy = destroyCheckBox->isChecked(), - .faceDown = faceDownCheckBox->isChecked()}; + .faceDown = faceDownCheckBox->isChecked(), + .providerId = SettingsCache::instance().cardOverrides().getCardPreferenceOverride(nameEdit->text())}; } diff --git a/cockatrice/src/dialogs/dlg_create_token.h b/cockatrice/src/dialogs/dlg_create_token.h index cd1b48c81..df00e3d75 100644 --- a/cockatrice/src/dialogs/dlg_create_token.h +++ b/cockatrice/src/dialogs/dlg_create_token.h @@ -25,6 +25,7 @@ struct TokenInfo QString annotation; bool destroy = true; bool faceDown = false; + QString providerId; }; class DlgCreateToken : public QDialog diff --git a/cockatrice/src/dialogs/dlg_filter_games.cpp b/cockatrice/src/dialogs/dlg_filter_games.cpp index f0fdaaa92..0c5191f99 100644 --- a/cockatrice/src/dialogs/dlg_filter_games.cpp +++ b/cockatrice/src/dialogs/dlg_filter_games.cpp @@ -40,6 +40,9 @@ DlgFilterGames::DlgFilterGames(const QMap &_allGameTypes, hideNotBuddyCreatedGames = new QCheckBox(tr("Hide games not created by buddy")); hideNotBuddyCreatedGames->setChecked(gamesProxyModel->getHideNotBuddyCreatedGames()); + hideOpenDecklistGames = new QCheckBox(tr("Hide games with forced open decklists")); + hideOpenDecklistGames->setChecked(gamesProxyModel->getHideOpenDecklistGames()); + maxGameAgeComboBox = new QComboBox(); maxGameAgeComboBox->setEditable(false); maxGameAgeComboBox->addItems(gameAgeMap.values()); @@ -115,6 +118,7 @@ DlgFilterGames::DlgFilterGames(const QMap &_allGameTypes, restrictionsLayout->addWidget(hideBuddiesOnlyGames, 3, 0); restrictionsLayout->addWidget(hideIgnoredUserGames, 4, 0); restrictionsLayout->addWidget(hideNotBuddyCreatedGames, 5, 0); + restrictionsLayout->addWidget(hideOpenDecklistGames, 6, 0); auto *restrictionsGroupBox = new QGroupBox(tr("Restrictions")); restrictionsGroupBox->setLayout(restrictionsLayout); @@ -218,6 +222,11 @@ bool DlgFilterGames::getHideNotBuddyCreatedGames() const return hideNotBuddyCreatedGames->isChecked(); } +bool DlgFilterGames::getHideOpenDecklistGames() const +{ + return hideOpenDecklistGames->isChecked(); +} + QString DlgFilterGames::getGameNameFilter() const { return gameNameFilterEdit->text(); diff --git a/cockatrice/src/dialogs/dlg_filter_games.h b/cockatrice/src/dialogs/dlg_filter_games.h index 373af389f..1120a64ee 100644 --- a/cockatrice/src/dialogs/dlg_filter_games.h +++ b/cockatrice/src/dialogs/dlg_filter_games.h @@ -27,6 +27,7 @@ private: QCheckBox *hidePasswordProtectedGames; QCheckBox *hideIgnoredUserGames; QCheckBox *hideNotBuddyCreatedGames; + QCheckBox *hideOpenDecklistGames; QLineEdit *gameNameFilterEdit; QLineEdit *creatorNameFilterEdit; QMap gameTypeFilterCheckBoxes; @@ -57,6 +58,8 @@ public: void setShowPasswordProtectedGames(bool _passwordProtectedGamesHidden); bool getHideBuddiesOnlyGames() const; void setHideBuddiesOnlyGames(bool _hideBuddiesOnlyGames); + bool getHideOpenDecklistGames() const; + void setHideOpenDecklistGames(bool _hideOpenDecklistGames); bool getHideIgnoredUserGames() const; void setHideIgnoredUserGames(bool _hideIgnoredUserGames); bool getHideNotBuddyCreatedGames() const; diff --git a/cockatrice/src/game/board/card_item.cpp b/cockatrice/src/game/board/card_item.cpp index c1d50b2ba..1fb77426e 100644 --- a/cockatrice/src/game/board/card_item.cpp +++ b/cockatrice/src/game/board/card_item.cpp @@ -24,30 +24,17 @@ CardItem::CardItem(Player *_owner, QGraphicsItem *parent, const CardRef &cardRef { owner->addCard(this); - cardMenu = new QMenu; - ptMenu = new QMenu; - moveMenu = new QMenu; - connect(&SettingsCache::instance().cardCounters(), &CardCounterSettings::colorChanged, this, [this](int counterId) { if (counters.contains(counterId)) update(); }); - - retranslateUi(); -} - -CardItem::~CardItem() -{ - delete cardMenu; - delete ptMenu; - delete moveMenu; } void CardItem::prepareDelete() { if (owner != nullptr) { - if (owner->getCardMenu() == cardMenu) { - owner->setCardMenu(nullptr); + if (owner->getGame()->getActiveCard() == this) { + owner->updateCardMenu(nullptr); owner->getGame()->setActiveCard(nullptr); } owner = nullptr; @@ -79,8 +66,6 @@ void CardItem::setZone(CardZone *_zone) void CardItem::retranslateUi() { - moveMenu->setTitle(tr("&Move to")); - ptMenu->setTitle(tr("&Power / toughness")); } void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) @@ -274,7 +259,7 @@ void CardItem::deleteDragItem() void CardItem::drawArrow(const QColor &arrowColor) { - if (static_cast(owner->parent())->getSpectator()) + if (static_cast(owner->parent())->isSpectator()) return; Player *arrowOwner = static_cast(owner->parent())->getActiveLocalPlayer(); @@ -297,7 +282,7 @@ void CardItem::drawArrow(const QColor &arrowColor) void CardItem::drawAttachArrow() { - if (static_cast(owner->parent())->getSpectator()) + if (static_cast(owner->parent())->isSpectator()) return; auto *arrow = new ArrowAttachItem(this); @@ -422,9 +407,13 @@ void CardItem::handleClickedToPlay(bool shiftHeld) void CardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { if (event->button() == Qt::RightButton) { - if (cardMenu != nullptr && !cardMenu->isEmpty() && owner != nullptr) { - cardMenu->popup(event->screenPos()); - return; + + if (owner != nullptr) { + owner->getGame()->setActiveCard(this); + if (QMenu *cardMenu = owner->updateCardMenu(this)) { + cardMenu->popup(event->screenPos()); + return; + } } } else if ((event->modifiers() != Qt::AltModifier) && (event->button() == Qt::LeftButton) && (!SettingsCache::instance().getDoubleClickToPlay())) { @@ -477,11 +466,11 @@ QVariant CardItem::itemChange(GraphicsItemChange change, const QVariant &value) { if ((change == ItemSelectedHasChanged) && owner != nullptr) { if (value == true) { - owner->setCardMenu(cardMenu); owner->getGame()->setActiveCard(this); - } else if (owner->getCardMenu() == cardMenu) { - owner->setCardMenu(nullptr); + owner->updateCardMenu(this); + } else if (owner->scene()->selectedItems().isEmpty()) { owner->getGame()->setActiveCard(nullptr); + owner->updateCardMenu(nullptr); } } return AbstractCardItem::itemChange(change, value); diff --git a/cockatrice/src/game/board/card_item.h b/cockatrice/src/game/board/card_item.h index 565c51fbc..569079092 100644 --- a/cockatrice/src/game/board/card_item.h +++ b/cockatrice/src/game/board/card_item.h @@ -33,8 +33,6 @@ private: CardItem *attachedTo; QList attachedCards; - QMenu *cardMenu, *ptMenu, *moveMenu; - void prepareDelete(); void handleClickedToPlay(bool shiftHeld); public slots: @@ -54,7 +52,7 @@ public: const CardRef &cardRef = {}, int _cardid = -1, CardZone *_zone = nullptr); - ~CardItem() override; + void retranslateUi(); CardZone *getZone() const { @@ -135,19 +133,6 @@ public: void resetState(bool keepAnnotations = false); void processCardInfo(const ServerInfo_Card &_info); - QMenu *getCardMenu() const - { - return cardMenu; - } - QMenu *getPTMenu() const - { - return ptMenu; - } - QMenu *getMoveMenu() const - { - return moveMenu; - } - bool animationEvent(); CardDragItem *createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool faceDown); void deleteDragItem(); diff --git a/cockatrice/src/game/cards/card_database.cpp b/cockatrice/src/game/cards/card_database.cpp index 884919308..f88cb497a 100644 --- a/cockatrice/src/game/cards/card_database.cpp +++ b/cockatrice/src/game/cards/card_database.cpp @@ -458,6 +458,12 @@ bool CardDatabase::isPreferredPrinting(const CardRef &cardRef) const return cardRef.providerId == getPreferredPrintingProviderId(cardRef.name); } +ExactCard CardDatabase::getCardFromSameSet(const QString &cardName, const PrintingInfo &otherPrinting) const +{ + PrintingInfo relatedPrinting = getSpecificPrinting(cardName, otherPrinting.getSet()->getCorrectedShortName(), ""); + return ExactCard(guessCard({cardName}).getCardPtr(), relatedPrinting); +} + void CardDatabase::refreshCachedReverseRelatedCards() { for (const CardInfoPtr &card : cards) diff --git a/cockatrice/src/game/cards/card_database.h b/cockatrice/src/game/cards/card_database.h index 8b1b2926f..0654c7494 100644 --- a/cockatrice/src/game/cards/card_database.h +++ b/cockatrice/src/game/cards/card_database.h @@ -82,6 +82,7 @@ public: getSpecificPrinting(const QString &cardName, const QString &setShortName, const QString &collectorNumber) const; QString getPreferredPrintingProviderId(const QString &cardName) const; bool isPreferredPrinting(const CardRef &cardRef) const; + ExactCard getCardFromSameSet(const QString &cardName, const PrintingInfo &otherPrinting) const; [[nodiscard]] ExactCard guessCard(const CardRef &cardRef) const; diff --git a/cockatrice/src/game/deckview/tabbed_deck_view_container.cpp b/cockatrice/src/game/deckview/tabbed_deck_view_container.cpp new file mode 100644 index 000000000..fc3c63acf --- /dev/null +++ b/cockatrice/src/game/deckview/tabbed_deck_view_container.cpp @@ -0,0 +1,64 @@ +#include "tabbed_deck_view_container.h" + +#include "../../client/tabs/tab_game.h" +#include "deck_view.h" + +TabbedDeckViewContainer::TabbedDeckViewContainer(int _playerId, TabGame *parent) + : QTabWidget(nullptr), playerId(_playerId), parentGame(parent) +{ + setTabsClosable(true); + connect(this, &QTabWidget::tabCloseRequested, this, &TabbedDeckViewContainer::closeTab); + + playerDeckView = new DeckViewContainer(playerId, parentGame); + int playerTabIndex = addTab(playerDeckView, "Your Deck"); + tabBar()->setTabButton(playerTabIndex, QTabBar::RightSide, nullptr); + updateTabBarVisibility(); +} + +void TabbedDeckViewContainer::addOpponentDeckView(const DeckList &opponentDeck, int opponentId, QString opponentName) +{ + if (opponentDeckViews.contains(opponentId)) { + opponentDeckViews[opponentId]->setDeck(opponentDeck); + } else { + auto *opponentDeckView = new DeckView(this); + opponentDeckView->setDeck(opponentDeck); + + addTab(opponentDeckView, QString("%1's Deck").arg(opponentName)); + + opponentDeckViews.insert(opponentId, opponentDeckView); + } + updateTabBarVisibility(); +} + +void TabbedDeckViewContainer::closeTab(int index) +{ + QWidget *widgetToClose = widget(index); + + // Prevent removing the player tab + if (widgetToClose == playerDeckView) { + return; + } + + // Remove it from map if it's an opponent + auto it = opponentDeckViews.begin(); + while (it != opponentDeckViews.end()) { + if (it.value() == widgetToClose) { + it = opponentDeckViews.erase(it); + } else { + ++it; + } + } + + removeTab(index); + widgetToClose->deleteLater(); + updateTabBarVisibility(); +} + +void TabbedDeckViewContainer::updateTabBarVisibility() +{ + if (tabBar()->count() <= 1) { + tabBar()->hide(); + } else { + tabBar()->show(); + } +} diff --git a/cockatrice/src/game/deckview/tabbed_deck_view_container.h b/cockatrice/src/game/deckview/tabbed_deck_view_container.h new file mode 100644 index 000000000..4b4769ece --- /dev/null +++ b/cockatrice/src/game/deckview/tabbed_deck_view_container.h @@ -0,0 +1,23 @@ +#ifndef TABBED_DECK_VIEW_CONTAINER_H +#define TABBED_DECK_VIEW_CONTAINER_H +#include "deck_view_container.h" + +#include + +class TabbedDeckViewContainer : public QTabWidget +{ + Q_OBJECT + +public: + explicit TabbedDeckViewContainer(int _playerId, TabGame *parent); + void closeTab(int index); + void updateTabBarVisibility(); + void addOpponentDeckView(const DeckList &opponentDeck, int opponentId, QString opponentName); + int playerId; + TabGame *parentGame; + DeckViewContainer *playerDeckView; + + QMap opponentDeckViews; +}; + +#endif // TABBED_DECK_VIEW_CONTAINER_H diff --git a/cockatrice/src/game/game_selector.cpp b/cockatrice/src/game/game_selector.cpp index 8b71fe187..e03feae36 100644 --- a/cockatrice/src/game/game_selector.cpp +++ b/cockatrice/src/game/game_selector.cpp @@ -1,6 +1,5 @@ #include "game_selector.h" -#include "../client/game_logic/abstract_client.h" #include "../client/get_text_with_max.h" #include "../client/tabs/tab_account.h" #include "../client/tabs/tab_game.h" @@ -8,6 +7,7 @@ #include "../client/tabs/tab_supervisor.h" #include "../dialogs/dlg_create_game.h" #include "../dialogs/dlg_filter_games.h" +#include "../server/abstract_client.h" #include "../server/pending_command.h" #include "../server/user/user_list_manager.h" #include "games_model.h" @@ -161,6 +161,7 @@ void GameSelector::actSetFilter() gameListProxyModel->setHidePasswordProtectedGames(dlg.getHidePasswordProtectedGames()); gameListProxyModel->setHideIgnoredUserGames(dlg.getHideIgnoredUserGames()); gameListProxyModel->setHideNotBuddyCreatedGames(dlg.getHideNotBuddyCreatedGames()); + gameListProxyModel->setHideOpenDecklistGames(dlg.getHideOpenDecklistGames()); gameListProxyModel->setGameNameFilter(dlg.getGameNameFilter()); gameListProxyModel->setCreatorNameFilter(dlg.getCreatorNameFilter()); gameListProxyModel->setGameTypeFilter(dlg.getGameTypeFilter()); diff --git a/cockatrice/src/game/games_model.cpp b/cockatrice/src/game/games_model.cpp index 03c72b584..fa908344c 100644 --- a/cockatrice/src/game/games_model.cpp +++ b/cockatrice/src/game/games_model.cpp @@ -153,6 +153,8 @@ QVariant GamesModel::data(const QModelIndex &index, int role) const result.append(tr("buddies only")); if (gameentry.only_registered()) result.append(tr("reg. users only")); + if (gameentry.share_decklists_on_load()) + result.append(tr("open decklists")); return result.join(", "); } case Qt::DecorationRole: { @@ -320,6 +322,12 @@ void GamesProxyModel::setHideNotBuddyCreatedGames(bool value) invalidateFilter(); } +void GamesProxyModel::setHideOpenDecklistGames(bool _hideOpenDecklistGames) +{ + hideOpenDecklistGames = _hideOpenDecklistGames; + invalidateFilter(); +} + void GamesProxyModel::setGameNameFilter(const QString &_gameNameFilter) { gameNameFilter = _gameNameFilter; @@ -398,6 +406,7 @@ void GamesProxyModel::resetFilterParameters() hideBuddiesOnlyGames = false; hideIgnoredUserGames = false; hideNotBuddyCreatedGames = false; + hideOpenDecklistGames = false; gameNameFilter = QString(); creatorNameFilter = QString(); gameTypeFilter.clear(); @@ -415,7 +424,7 @@ void GamesProxyModel::resetFilterParameters() bool GamesProxyModel::areFilterParametersSetToDefaults() const { return !hideFullGames && !hideGamesThatStarted && !hidePasswordProtectedGames && !hideBuddiesOnlyGames && - !hideIgnoredUserGames && !hideNotBuddyCreatedGames && gameNameFilter.isEmpty() && + !hideOpenDecklistGames && !hideIgnoredUserGames && !hideNotBuddyCreatedGames && gameNameFilter.isEmpty() && creatorNameFilter.isEmpty() && gameTypeFilter.isEmpty() && maxPlayersFilterMin == DEFAULT_MAX_PLAYERS_MIN && maxPlayersFilterMax == DEFAULT_MAX_PLAYERS_MAX && maxGameAge == DEFAULT_MAX_GAME_AGE && !showOnlyIfSpectatorsCanWatch && !showSpectatorPasswordProtected && !showOnlyIfSpectatorsCanChat && @@ -431,6 +440,7 @@ void GamesProxyModel::loadFilterParameters(const QMap &allGameType hideIgnoredUserGames = gameFilters.isHideIgnoredUserGames(); hideBuddiesOnlyGames = gameFilters.isHideBuddiesOnlyGames(); hideNotBuddyCreatedGames = gameFilters.isHideNotBuddyCreatedGames(); + hideOpenDecklistGames = gameFilters.isHideOpenDecklistGames(); gameNameFilter = gameFilters.getGameNameFilter(); creatorNameFilter = gameFilters.getCreatorNameFilter(); maxPlayersFilterMin = gameFilters.getMinPlayers(); @@ -461,6 +471,7 @@ void GamesProxyModel::saveFilterParameters(const QMap &allGameType gameFilters.setHidePasswordProtectedGames(hidePasswordProtectedGames); gameFilters.setHideIgnoredUserGames(hideIgnoredUserGames); gameFilters.setHideNotBuddyCreatedGames(hideNotBuddyCreatedGames); + gameFilters.setHideOpenDecklistGames(hideOpenDecklistGames); gameFilters.setGameNameFilter(gameNameFilter); gameFilters.setCreatorNameFilter(creatorNameFilter); @@ -504,6 +515,9 @@ bool GamesProxyModel::filterAcceptsRow(int sourceRow) const if (hideBuddiesOnlyGames && game.only_buddies()) { return false; } + if (hideOpenDecklistGames && game.share_decklists_on_load()) { + return false; + } if (hideIgnoredUserGames && userListProxy->isUserIgnored(QString::fromStdString(game.creator_info().name()))) { return false; } diff --git a/cockatrice/src/game/games_model.h b/cockatrice/src/game/games_model.h index f2a5d24d6..4b82a9056 100644 --- a/cockatrice/src/game/games_model.h +++ b/cockatrice/src/game/games_model.h @@ -81,6 +81,7 @@ private: bool hideGamesThatStarted; bool hidePasswordProtectedGames; bool hideNotBuddyCreatedGames; + bool hideOpenDecklistGames; QString gameNameFilter, creatorNameFilter; QSet gameTypeFilter; quint32 maxPlayersFilterMin, maxPlayersFilterMax; @@ -121,6 +122,11 @@ public: return hideNotBuddyCreatedGames; } void setHideNotBuddyCreatedGames(bool value); + bool getHideOpenDecklistGames() const + { + return hideOpenDecklistGames; + } + void setHideOpenDecklistGames(bool _hideOpenDecklistGames); QString getGameNameFilter() const { return gameNameFilter; diff --git a/cockatrice/src/game/player/player.cpp b/cockatrice/src/game/player/player.cpp index 4a83a9ae0..ccdf3e68f 100644 --- a/cockatrice/src/game/player/player.cpp +++ b/cockatrice/src/game/player/player.cpp @@ -150,8 +150,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T stack = addZone(new StackZone(this, (int)table->boundingRect().height(), this)); - hand = addZone(new HandZone(this, - _local || _judge || (_parent->getSpectator() && _parent->getSpectatorsSeeEverything()), + hand = addZone(new HandZone(this, _local || _judge || (_parent->isSpectator() && _parent->isSpectatorsOmniscient()), (int)table->boundingRect().height(), this)); connect(hand, &HandZone::cardCountChanged, handCounter, &HandCounter::updateNumber); connect(handCounter, &HandCounter::showContextMenu, hand, &HandZone::showContextMenu); @@ -210,6 +209,8 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T connect(aViewLibrary, &QAction::triggered, this, &Player::actViewLibrary); aViewHand = new QAction(this); connect(aViewHand, &QAction::triggered, this, &Player::actViewHand); + aSortHand = new QAction(this); + connect(aSortHand, &QAction::triggered, this, &Player::actSortHand); aViewTopCards = new QAction(this); connect(aViewTopCards, &QAction::triggered, this, &Player::actViewTopCards); @@ -298,6 +299,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T if (local || judge) { handMenu = playerMenu->addTearOffMenu(QString()); handMenu->addAction(aViewHand); + handMenu->addAction(aSortHand); playerLists.append(mRevealHand = handMenu->addMenu(QString())); playerLists.append(mRevealRandomHandCard = handMenu->addMenu(QString())); handMenu->addSeparator(); @@ -417,6 +419,9 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T connect(aCreateAnotherToken, &QAction::triggered, this, &Player::actCreateAnotherToken); aCreateAnotherToken->setEnabled(false); + aIncrementAllCardCounters = new QAction(this); + connect(aIncrementAllCardCounters, &QAction::triggered, this, &Player::incrementAllCardCounters); + createPredefinedTokenMenu = new QMenu(QString()); createPredefinedTokenMenu->setEnabled(false); @@ -424,6 +429,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T playerMenu->addSeparator(); countersMenu = playerMenu->addMenu(QString()); + playerMenu->addAction(aIncrementAllCardCounters); playerMenu->addSeparator(); playerMenu->addAction(aUntapAll); playerMenu->addSeparator(); @@ -442,11 +448,6 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T initSayMenu(); } - aCardMenu = new QAction(this); - aCardMenu->setEnabled(false); - playerMenu->addSeparator(); - playerMenu->addAction(aCardMenu); - if (local || judge) { for (auto &playerList : playerLists) { @@ -791,6 +792,7 @@ void Player::retranslateUi() aViewLibrary->setText(tr("&View library")); aViewHand->setText(tr("&View hand")); + aSortHand->setText(tr("&Sort hand")); aViewTopCards->setText(tr("View &top cards of library...")); aViewBottomCards->setText(tr("View bottom cards of library...")); mRevealLibrary->setTitle(tr("Reveal &library to...")); @@ -843,6 +845,7 @@ void Player::retranslateUi() aViewZone->setText(tr("View custom zone '%1'").arg(aViewZone->data().toString())); } + aIncrementAllCardCounters->setText(tr("Increment all card counters")); aUntapAll->setText(tr("&Untap all permanents")); aRollDie->setText(tr("R&oll die...")); aCreateToken->setText(tr("&Create token...")); @@ -861,8 +864,6 @@ void Player::retranslateUi() } } - aCardMenu->setText(tr("Selec&ted cards")); - if (local) { sayMenu->setTitle(tr("S&ay")); } @@ -954,43 +955,17 @@ void Player::setShortcutsActive() aMoveToHand->setShortcuts(shortcuts.getShortcut("Player/aMoveToHand")); aMoveToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveToGraveyard")); aMoveToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveToExile")); + aSortHand->setShortcuts(shortcuts.getShortcut("Player/aSortHand")); aSelectAll->setShortcuts(shortcuts.getShortcut("Player/aSelectAll")); aSelectRow->setShortcuts(shortcuts.getShortcut("Player/aSelectRow")); aSelectColumn->setShortcuts(shortcuts.getShortcut("Player/aSelectColumn")); - QList addCCShortCuts; - addCCShortCuts.append(shortcuts.getSingleShortcut("Player/aCCRed")); - addCCShortCuts.append(shortcuts.getSingleShortcut("Player/aCCYellow")); - addCCShortCuts.append(shortcuts.getSingleShortcut("Player/aCCGreen")); - addCCShortCuts.append(shortcuts.getSingleShortcut("Player/aCCCyan")); - addCCShortCuts.append(shortcuts.getSingleShortcut("Player/aCCPurple")); - addCCShortCuts.append(shortcuts.getSingleShortcut("Player/aCCMagenta")); - - QList removeCCShortCuts; - removeCCShortCuts.append(shortcuts.getSingleShortcut("Player/aRCRed")); - removeCCShortCuts.append(shortcuts.getSingleShortcut("Player/aRCYellow")); - removeCCShortCuts.append(shortcuts.getSingleShortcut("Player/aRCGreen")); - removeCCShortCuts.append(shortcuts.getSingleShortcut("Player/aRCCyan")); - removeCCShortCuts.append(shortcuts.getSingleShortcut("Player/aRCPurple")); - removeCCShortCuts.append(shortcuts.getSingleShortcut("Player/aRCMagenta")); - - QList setCCShortCuts; - setCCShortCuts.append(shortcuts.getSingleShortcut("Player/aSCRed")); - setCCShortCuts.append(shortcuts.getSingleShortcut("Player/aSCYellow")); - setCCShortCuts.append(shortcuts.getSingleShortcut("Player/aSCGreen")); - setCCShortCuts.append(shortcuts.getSingleShortcut("Player/aSCCyan")); - setCCShortCuts.append(shortcuts.getSingleShortcut("Player/aSCPurple")); - setCCShortCuts.append(shortcuts.getSingleShortcut("Player/aSCMagenta")); - - for (int i = 0; i < addCCShortCuts.size(); ++i) { - aAddCounter[i]->setShortcut(addCCShortCuts.at(i)); - } - for (int i = 0; i < removeCCShortCuts.size(); ++i) { - aRemoveCounter[i]->setShortcut(removeCCShortCuts.at(i)); - } - for (int i = 0; i < setCCShortCuts.size(); ++i) { - aSetCounter[i]->setShortcut(setCCShortCuts.at(i)); + static const QStringList colorWords = {"Red", "Yellow", "Green", "Cyan", "Purple", "Magenta"}; + for (int i = 0; i < aAddCounter.size(); i++) { + aAddCounter[i]->setShortcuts(shortcuts.getShortcut("Player/aCC" + colorWords[i])); + aRemoveCounter[i]->setShortcuts(shortcuts.getShortcut("Player/aRC" + colorWords[i])); + aSetCounter[i]->setShortcuts(shortcuts.getShortcut("Player/aSC" + colorWords[i])); } QMapIterator counterIterator(counters); @@ -998,44 +973,45 @@ void Player::setShortcutsActive() counterIterator.next().value()->setShortcutsActive(); } - aViewSideboard->setShortcut(shortcuts.getSingleShortcut("Player/aViewSideboard")); - aViewLibrary->setShortcut(shortcuts.getSingleShortcut("Player/aViewLibrary")); - aViewHand->setShortcut(shortcuts.getSingleShortcut("Player/aViewHand")); - aViewTopCards->setShortcut(shortcuts.getSingleShortcut("Player/aViewTopCards")); - aViewBottomCards->setShortcut(shortcuts.getSingleShortcut("Player/aViewBottomCards")); - aViewGraveyard->setShortcut(shortcuts.getSingleShortcut("Player/aViewGraveyard")); - aDrawCard->setShortcut(shortcuts.getSingleShortcut("Player/aDrawCard")); - aDrawCards->setShortcut(shortcuts.getSingleShortcut("Player/aDrawCards")); - aUndoDraw->setShortcut(shortcuts.getSingleShortcut("Player/aUndoDraw")); - aMulligan->setShortcut(shortcuts.getSingleShortcut("Player/aMulligan")); - aShuffle->setShortcut(shortcuts.getSingleShortcut("Player/aShuffle")); - aShuffleTopCards->setShortcut(shortcuts.getSingleShortcut("Player/aShuffleTopCards")); - aShuffleBottomCards->setShortcut(shortcuts.getSingleShortcut("Player/aShuffleBottomCards")); - aUntapAll->setShortcut(shortcuts.getSingleShortcut("Player/aUntapAll")); - aRollDie->setShortcut(shortcuts.getSingleShortcut("Player/aRollDie")); - aCreateToken->setShortcut(shortcuts.getSingleShortcut("Player/aCreateToken")); - aCreateAnotherToken->setShortcut(shortcuts.getSingleShortcut("Player/aCreateAnotherToken")); - aAlwaysRevealTopCard->setShortcut(shortcuts.getSingleShortcut("Player/aAlwaysRevealTopCard")); - aAlwaysLookAtTopCard->setShortcut(shortcuts.getSingleShortcut("Player/aAlwaysLookAtTopCard")); - aMoveTopToPlay->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopToPlay")); - aMoveTopToPlayFaceDown->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopToPlayFaceDown")); - aMoveTopCardToGraveyard->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardToGraveyard")); - aMoveTopCardsToGraveyard->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardsToGraveyard")); - aMoveTopCardToExile->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardToExile")); - aMoveTopCardsToExile->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardsToExile")); - aMoveTopCardsUntil->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardsUntil")); - aMoveTopCardToBottom->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardToBottom")); - aDrawBottomCard->setShortcut(shortcuts.getSingleShortcut("Player/aDrawBottomCard")); - aDrawBottomCards->setShortcut(shortcuts.getSingleShortcut("Player/aDrawBottomCards")); - aMoveBottomToPlay->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomToPlay")); - aMoveBottomToPlayFaceDown->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomToPlayFaceDown")); - aMoveBottomCardToGraveyard->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomCardToGrave")); - aMoveBottomCardsToGraveyard->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomCardsToGrave")); - aMoveBottomCardToExile->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomCardToExile")); - aMoveBottomCardsToExile->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomCardsToExile")); - aMoveBottomCardToTop->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomCardToTop")); - aPlayFacedown->setShortcut(shortcuts.getSingleShortcut("Player/aPlayFacedown")); - aPlay->setShortcut(shortcuts.getSingleShortcut("Player/aPlay")); + aIncrementAllCardCounters->setShortcuts(shortcuts.getShortcut("Player/aIncrementAllCardCounters")); + aViewSideboard->setShortcuts(shortcuts.getShortcut("Player/aViewSideboard")); + aViewLibrary->setShortcuts(shortcuts.getShortcut("Player/aViewLibrary")); + aViewHand->setShortcuts(shortcuts.getShortcut("Player/aViewHand")); + aViewTopCards->setShortcuts(shortcuts.getShortcut("Player/aViewTopCards")); + aViewBottomCards->setShortcuts(shortcuts.getShortcut("Player/aViewBottomCards")); + aViewGraveyard->setShortcuts(shortcuts.getShortcut("Player/aViewGraveyard")); + aDrawCard->setShortcuts(shortcuts.getShortcut("Player/aDrawCard")); + aDrawCards->setShortcuts(shortcuts.getShortcut("Player/aDrawCards")); + aUndoDraw->setShortcuts(shortcuts.getShortcut("Player/aUndoDraw")); + aMulligan->setShortcuts(shortcuts.getShortcut("Player/aMulligan")); + aShuffle->setShortcuts(shortcuts.getShortcut("Player/aShuffle")); + aShuffleTopCards->setShortcuts(shortcuts.getShortcut("Player/aShuffleTopCards")); + aShuffleBottomCards->setShortcuts(shortcuts.getShortcut("Player/aShuffleBottomCards")); + aUntapAll->setShortcuts(shortcuts.getShortcut("Player/aUntapAll")); + aRollDie->setShortcuts(shortcuts.getShortcut("Player/aRollDie")); + aCreateToken->setShortcuts(shortcuts.getShortcut("Player/aCreateToken")); + aCreateAnotherToken->setShortcuts(shortcuts.getShortcut("Player/aCreateAnotherToken")); + aAlwaysRevealTopCard->setShortcuts(shortcuts.getShortcut("Player/aAlwaysRevealTopCard")); + aAlwaysLookAtTopCard->setShortcuts(shortcuts.getShortcut("Player/aAlwaysLookAtTopCard")); + aMoveTopToPlay->setShortcuts(shortcuts.getShortcut("Player/aMoveTopToPlay")); + aMoveTopToPlayFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveTopToPlayFaceDown")); + aMoveTopCardToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToGraveyard")); + aMoveTopCardsToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToGraveyard")); + aMoveTopCardToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToExile")); + aMoveTopCardsToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToExile")); + aMoveTopCardsUntil->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsUntil")); + aMoveTopCardToBottom->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToBottom")); + aDrawBottomCard->setShortcuts(shortcuts.getShortcut("Player/aDrawBottomCard")); + aDrawBottomCards->setShortcuts(shortcuts.getShortcut("Player/aDrawBottomCards")); + aMoveBottomToPlay->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomToPlay")); + aMoveBottomToPlayFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomToPlayFaceDown")); + aMoveBottomCardToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToGrave")); + aMoveBottomCardsToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToGrave")); + aMoveBottomCardToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToExile")); + aMoveBottomCardsToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToExile")); + aMoveBottomCardToTop->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToTop")); + aPlayFacedown->setShortcuts(shortcuts.getShortcut("Player/aPlayFacedown")); + aPlay->setShortcuts(shortcuts.getShortcut("Player/aPlay")); // Don't enable always-active shortcuts in local games, since it causes keyboard shortcuts to work inconsistently // when there are more than 1 player. @@ -1084,6 +1060,8 @@ void Player::setShortcutsInactive() aMoveBottomCardsToGraveyard->setShortcut(QKeySequence()); aMoveBottomCardToExile->setShortcut(QKeySequence()); aMoveBottomCardsToExile->setShortcut(QKeySequence()); + aIncrementAllCardCounters->setShortcut(QKeySequence()); + aSortHand->setShortcut(QKeySequence()); QMapIterator counterIterator(counters); while (counterIterator.hasNext()) { @@ -1154,6 +1132,11 @@ void Player::actViewHand() static_cast(scene())->toggleZoneView(this, "hand", -1); } +void Player::actSortHand() +{ + hand->sortHand(); +} + void Player::actViewTopCards() { int deckSize = zones.value("deck")->getCards().size(); @@ -1849,7 +1832,8 @@ void Player::actCreateToken() lastTokenInfo = dlg.getTokenInfo(); - ExactCard correctedCard = CardDatabaseManager::getInstance()->guessCard({lastTokenInfo.name}); + ExactCard correctedCard = + CardDatabaseManager::getInstance()->guessCard({lastTokenInfo.name, lastTokenInfo.providerId}); if (correctedCard) { lastTokenInfo.name = correctedCard.getName(); lastTokenTableRow = TableZone::clampValidTableRow(2 - correctedCard.getInfo().getTableRow()); @@ -1872,6 +1856,7 @@ void Player::actCreateAnotherToken() Command_CreateToken cmd; cmd.set_zone("table"); cmd.set_card_name(lastTokenInfo.name.toStdString()); + cmd.set_card_provider_id(lastTokenInfo.providerId.toStdString()); cmd.set_color(lastTokenInfo.color.toStdString()); cmd.set_pt(lastTokenInfo.pt.toStdString()); cmd.set_annotation(lastTokenInfo.annotation.toStdString()); @@ -1912,9 +1897,9 @@ void Player::actCreateRelatedCard() * then let's allow it to be created via "create another token" */ if (createRelatedFromRelation(sourceCard, cardRelation) && cardRelation->getCanCreateAnother()) { - ExactCard cardInfo = - CardDatabaseManager::getInstance()->getCard({cardRelation->getName(), sourceCard->getProviderId()}); - setLastToken(cardInfo.getCardPtr()); + ExactCard relatedCard = CardDatabaseManager::getInstance()->getCardFromSameSet( + cardRelation->getName(), sourceCard->getCard().getPrinting()); + setLastToken(relatedCard.getCardPtr()); } } @@ -2076,13 +2061,18 @@ void Player::createCard(const CardItem *sourceCard, cmd.set_x(gridPoint.x()); cmd.set_y(gridPoint.y()); + ExactCard relatedCard = CardDatabaseManager::getInstance()->getCardFromSameSet(cardInfo->getName(), + sourceCard->getCard().getPrinting()); + switch (attachType) { case CardRelation::DoesNotAttach: cmd.set_target_zone("table"); + cmd.set_card_provider_id(relatedCard.getPrinting().getUuid().toStdString()); break; case CardRelation::AttachTo: cmd.set_target_zone("table"); // We currently only support creating tokens on the table + cmd.set_card_provider_id(relatedCard.getPrinting().getUuid().toStdString()); cmd.set_target_card_id(sourceCard->getId()); cmd.set_target_mode(Command_CreateToken::ATTACH_TO); break; @@ -2791,7 +2781,7 @@ void Player::processPlayerInfo(const ServerInfo_Player &info) switch (zoneInfo.type()) { case ServerInfo_Zone::PrivateZone: - contentsKnown = local || judge || (game->getSpectator() && game->getSpectatorsSeeEverything()); + contentsKnown = local || judge || (game->isSpectator() && game->isSpectatorsOmniscient()); break; case ServerInfo_Zone::PublicZone: @@ -3038,6 +3028,51 @@ void Player::clearCounters() counters.clear(); } +void Player::incrementAllCardCounters() +{ + QList cardsToUpdate; + + auto selectedItems = scene()->selectedItems(); + if (!selectedItems.isEmpty()) { + // If cards are selected, only update those + for (const auto &item : selectedItems) { + auto *card = static_cast(item); + cardsToUpdate.append(card); + } + } else { + // If no cards selected, update all cards on table + const CardList &tableCards = table->getCards(); + cardsToUpdate = tableCards; + } + + QList commandList; + + for (const auto *card : cardsToUpdate) { + const auto &cardCounters = card->getCounters(); + + QMapIterator counterIterator(cardCounters); + while (counterIterator.hasNext()) { + counterIterator.next(); + int counterId = counterIterator.key(); + int currentValue = counterIterator.value(); + if (currentValue >= MAX_COUNTERS_ON_CARD) { + continue; + } + + auto cmd = std::make_unique(); + cmd->set_zone(card->getZone()->getName().toStdString()); + cmd->set_card_id(card->getId()); + cmd->set_counter_id(counterId); + cmd->set_counter_value(currentValue + 1); + commandList.append(cmd.release()); + } + } + + if (!commandList.isEmpty()) { + sendGameCommand(prepareGameCommand(commandList)); + } +} + ArrowItem *Player::addArrow(const ServerInfo_Arrow &arrow) { const QMap &playerList = game->getPlayers(); @@ -3861,20 +3896,12 @@ void Player::refreshShortcuts() } } -void Player::updateCardMenu(const CardItem *card) +QMenu *Player::createCardMenu(const CardItem *card) { - // If bad card OR is a spectator (as spectators don't need card menus), return - // only update the menu if the card is actually selected - if (card == nullptr || (game->isSpectator() && !judge) || game->getActiveCard() != card) { - return; + if (card == nullptr) { + return nullptr; } - QMenu *cardMenu = card->getCardMenu(); - QMenu *ptMenu = card->getPTMenu(); - QMenu *moveMenu = card->getMoveMenu(); - - cardMenu->clear(); - bool revealedCard = false; bool writeableCard = getLocalOrJudge(); if (auto *view = qobject_cast(card->getZone())) { @@ -3887,6 +3914,8 @@ void Player::updateCardMenu(const CardItem *card) } } + QMenu *cardMenu = new QMenu; + if (revealedCard) { cardMenu->addAction(aHide); cardMenu->addAction(aClone); @@ -3897,18 +3926,6 @@ void Player::updateCardMenu(const CardItem *card) } else if (writeableCard) { bool canModifyCard = judge || card->getOwner() == this; - if (moveMenu->isEmpty() && canModifyCard) { - moveMenu->addAction(aMoveToTopLibrary); - moveMenu->addAction(aMoveToXfromTopOfLibrary); - moveMenu->addAction(aMoveToBottomLibrary); - moveMenu->addSeparator(); - moveMenu->addAction(aMoveToHand); - moveMenu->addSeparator(); - moveMenu->addAction(aMoveToGraveyard); - moveMenu->addSeparator(); - moveMenu->addAction(aMoveToExile); - } - if (card->getZone()) { if (card->getZone()->getName() == "table") { // Card is on the battlefield @@ -3924,23 +3941,7 @@ void Player::updateCardMenu(const CardItem *card) cardMenu->addSeparator(); cardMenu->addAction(aSelectAll); cardMenu->addAction(aSelectRow); - return; - } - - if (ptMenu->isEmpty()) { - ptMenu->addAction(aIncP); - ptMenu->addAction(aDecP); - ptMenu->addAction(aFlowP); - ptMenu->addSeparator(); - ptMenu->addAction(aIncT); - ptMenu->addAction(aDecT); - ptMenu->addAction(aFlowT); - ptMenu->addSeparator(); - ptMenu->addAction(aIncPT); - ptMenu->addAction(aDecPT); - ptMenu->addSeparator(); - ptMenu->addAction(aSetPT); - ptMenu->addAction(aResetPT); + return cardMenu; } cardMenu->addAction(aTap); @@ -3960,11 +3961,11 @@ void Player::updateCardMenu(const CardItem *card) } cardMenu->addAction(aDrawArrow); cardMenu->addSeparator(); - cardMenu->addMenu(ptMenu); + cardMenu->addMenu(createPtMenu()); cardMenu->addAction(aSetAnnotation); cardMenu->addSeparator(); cardMenu->addAction(aClone); - cardMenu->addMenu(moveMenu); + cardMenu->addMenu(createMoveMenu()); cardMenu->addSeparator(); cardMenu->addAction(aSelectAll); cardMenu->addAction(aSelectRow); @@ -3988,7 +3989,7 @@ void Player::updateCardMenu(const CardItem *card) cardMenu->addAction(aDrawArrow); cardMenu->addSeparator(); cardMenu->addAction(aClone); - cardMenu->addMenu(moveMenu); + cardMenu->addMenu(createMoveMenu()); cardMenu->addSeparator(); cardMenu->addAction(aSelectAll); } else { @@ -4009,7 +4010,7 @@ void Player::updateCardMenu(const CardItem *card) cardMenu->addSeparator(); cardMenu->addAction(aClone); - cardMenu->addMenu(moveMenu); + cardMenu->addMenu(createMoveMenu()); cardMenu->addSeparator(); cardMenu->addAction(aSelectAll); cardMenu->addAction(aSelectColumn); @@ -4039,7 +4040,7 @@ void Player::updateCardMenu(const CardItem *card) cardMenu->addSeparator(); cardMenu->addAction(aClone); - cardMenu->addMenu(moveMenu); + cardMenu->addMenu(createMoveMenu()); // actions that are really wonky when done from deck or sideboard if (card->getZone()->getName() == "hand") { @@ -4060,7 +4061,7 @@ void Player::updateCardMenu(const CardItem *card) } } } else { - cardMenu->addMenu(moveMenu); + cardMenu->addMenu(createMoveMenu()); } } else { if (card->getZone() && card->getZone()->getName() != "hand") { @@ -4074,6 +4075,42 @@ void Player::updateCardMenu(const CardItem *card) cardMenu->addAction(aSelectAll); } } + + return cardMenu; +} + +QMenu *Player::createMoveMenu() const +{ + QMenu *moveMenu = new QMenu("Move to"); + moveMenu->addAction(aMoveToTopLibrary); + moveMenu->addAction(aMoveToXfromTopOfLibrary); + moveMenu->addAction(aMoveToBottomLibrary); + moveMenu->addSeparator(); + moveMenu->addAction(aMoveToHand); + moveMenu->addSeparator(); + moveMenu->addAction(aMoveToGraveyard); + moveMenu->addSeparator(); + moveMenu->addAction(aMoveToExile); + return moveMenu; +} + +QMenu *Player::createPtMenu() const +{ + QMenu *ptMenu = new QMenu("Power / toughness"); + ptMenu->addAction(aIncP); + ptMenu->addAction(aDecP); + ptMenu->addAction(aFlowP); + ptMenu->addSeparator(); + ptMenu->addAction(aIncT); + ptMenu->addAction(aDecT); + ptMenu->addAction(aFlowT); + ptMenu->addSeparator(); + ptMenu->addAction(aIncPT); + ptMenu->addAction(aDecPT); + ptMenu->addSeparator(); + ptMenu->addAction(aSetPT); + ptMenu->addAction(aResetPT); + return ptMenu; } void Player::addRelatedCardView(const CardItem *card, QMenu *cardMenu) @@ -4130,8 +4167,8 @@ void Player::addRelatedCardActions(const CardItem *card, QMenu *cardMenu) int index = 0; QAction *createRelatedCards = nullptr; for (const CardRelation *cardRelation : relatedCards) { - ExactCard relatedCard = - CardDatabaseManager::getInstance()->getCard({cardRelation->getName(), exactCard.getPrinting().getUuid()}); + ExactCard relatedCard = CardDatabaseManager::getInstance()->getCardFromSameSet(cardRelation->getName(), + card->getCard().getPrinting()); if (!relatedCard) { relatedCard = CardDatabaseManager::getInstance()->getCard({cardRelation->getName()}); } @@ -4175,31 +4212,38 @@ void Player::addRelatedCardActions(const CardItem *card, QMenu *cardMenu) if (createRelatedCards) { if (shortcutsActive) { - createRelatedCards->setShortcut( - SettingsCache::instance().shortcuts().getSingleShortcut("Player/aCreateRelatedTokens")); + createRelatedCards->setShortcuts( + SettingsCache::instance().shortcuts().getShortcut("Player/aCreateRelatedTokens")); } connect(createRelatedCards, &QAction::triggered, this, &Player::actCreateAllRelatedCards); cardMenu->addAction(createRelatedCards); } } -void Player::setCardMenu(QMenu *menu) +/** + * Creates a card menu from the given card and sets it as the currently active card menu. + * Will first check if the card should have a card menu, and no-ops if not. + * + * @param card The card to create the menu for. Pass nullptr to disable the card menu. + * @return The new card menu, or nullptr if failed. + */ +QMenu *Player::updateCardMenu(const CardItem *card) { - if (aCardMenu != nullptr) { - aCardMenu->setEnabled(menu != nullptr); - if (menu) { - aCardMenu->setMenu(menu); - } - } -} - -QMenu *Player::getCardMenu() const -{ - if (aCardMenu != nullptr) { - return aCardMenu->menu(); - } else { + if (!card) { + emit cardMenuUpdated(nullptr); return nullptr; } + + // If is spectator (as spectators don't need card menus), return + // only update the menu if the card is actually selected + if ((game->isSpectator() && !judge) || game->getActiveCard() != card) { + return nullptr; + } + + QMenu *menu = createCardMenu(card); + emit cardMenuUpdated(menu); + + return menu; } QString Player::getName() const @@ -4271,7 +4315,9 @@ void Player::setLastToken(CardInfoPtr cardInfo) .color = cardInfo->getColors().isEmpty() ? QString() : cardInfo->getColors().left(1).toLower(), .pt = cardInfo->getPowTough(), .annotation = SettingsCache::instance().getAnnotateTokens() ? cardInfo->getText() : "", - .destroy = true}; + .destroy = true, + .providerId = + SettingsCache::instance().cardOverrides().getCardPreferenceOverride(cardInfo->getName())}; lastTokenTableRow = TableZone::clampValidTableRow(2 - cardInfo->getTableRow()); aCreateAnotherToken->setText(tr("C&reate another %1 token").arg(lastTokenInfo.name)); diff --git a/cockatrice/src/game/player/player.h b/cockatrice/src/game/player/player.h index 9062ac5b4..b4f901329 100644 --- a/cockatrice/src/game/player/player.h +++ b/cockatrice/src/game/player/player.h @@ -156,6 +156,7 @@ signals: void sizeChanged(); void playerCountChanged(); + void cardMenuUpdated(QMenu *cardMenu); public slots: void actUntapAll(); void actRollDie(); @@ -239,7 +240,7 @@ private slots: void actSetAnnotation(); void actReveal(QAction *action); void refreshShortcuts(); - + void actSortHand(); void initSayMenu(); public: @@ -271,12 +272,11 @@ private: *aMoveBottomToPlayFaceDown, *aMoveBottomCardToTop, *aMoveBottomCardToGraveyard, *aMoveBottomCardToExile, *aMoveBottomCardsToGraveyard, *aMoveBottomCardsToExile, *aDrawBottomCard, *aDrawBottomCards; - QAction *aCardMenu; QList aAddCounter, aSetCounter, aRemoveCounter; QAction *aPlay, *aPlayFacedown, *aHide, *aTap, *aDoesntUntap, *aAttach, *aUnattach, *aDrawArrow, *aSetPT, *aResetPT, *aIncP, *aDecP, *aIncT, *aDecT, *aIncPT, *aDecPT, *aFlowP, *aFlowT, *aSetAnnotation, *aFlip, *aPeek, *aClone, *aMoveToTopLibrary, *aMoveToBottomLibrary, *aMoveToHand, *aMoveToGraveyard, *aMoveToExile, - *aMoveToXfromTopOfLibrary, *aSelectAll, *aSelectRow, *aSelectColumn; + *aMoveToXfromTopOfLibrary, *aSelectAll, *aSelectRow, *aSelectColumn, *aSortHand, *aIncrementAllCardCounters; bool movingCardsUntil; QTimer *moveTopCardTimer; @@ -326,6 +326,8 @@ private: const QString &avalue, bool allCards, EventProcessingOptions options); + QMenu *createMoveMenu() const; + QMenu *createPtMenu() const; void addRelatedCardActions(const CardItem *card, QMenu *cardMenu); void addRelatedCardView(const CardItem *card, QMenu *cardMenu); void createCard(const CardItem *sourceCard, @@ -420,6 +422,7 @@ public: AbstractCounter *addCounter(int counterId, const QString &name, QColor color, int radius, int value); void delCounter(int counterId); void clearCounters(); + void incrementAllCardCounters(); ArrowItem *addArrow(const ServerInfo_Arrow &arrow); ArrowItem *addArrow(int arrowId, CardItem *startCard, ArrowTarget *targetItem, const QColor &color); @@ -483,9 +486,8 @@ public: { return arrows; } - void setCardMenu(QMenu *menu); - QMenu *getCardMenu() const; - void updateCardMenu(const CardItem *card); + QMenu *updateCardMenu(const CardItem *card); + QMenu *createCardMenu(const CardItem *card); bool getActive() const { return active; diff --git a/cockatrice/src/game/player/player_list_widget.cpp b/cockatrice/src/game/player/player_list_widget.cpp index a5901c392..dc7489dce 100644 --- a/cockatrice/src/game/player/player_list_widget.cpp +++ b/cockatrice/src/game/player/player_list_widget.cpp @@ -1,10 +1,10 @@ #include "player_list_widget.h" -#include "../../client/game_logic/abstract_client.h" #include "../../client/tabs/tab_account.h" #include "../../client/tabs/tab_game.h" #include "../../client/tabs/tab_supervisor.h" #include "../../client/ui/pixel_map_generator.h" +#include "../../server/abstract_client.h" #include "../../server/user/user_context_menu.h" #include "../../server/user/user_list_manager.h" #include "../../server/user/user_list_widget.h" diff --git a/cockatrice/src/game/zones/hand_zone.cpp b/cockatrice/src/game/zones/hand_zone.cpp index d645a299e..2d6947c9d 100644 --- a/cockatrice/src/game/zones/hand_zone.cpp +++ b/cockatrice/src/game/zones/hand_zone.cpp @@ -127,6 +127,15 @@ void HandZone::reorganizeCards() update(); } +void HandZone::sortHand() +{ + if (cards.isEmpty()) { + return; + } + cards.sortBy({CardList::SortByMainType, CardList::SortByManaValue, CardList::SortByColorGrouping}); + reorganizeCards(); +} + void HandZone::setWidth(qreal _width) { if (SettingsCache::instance().getHorizontalHand()) { diff --git a/cockatrice/src/game/zones/hand_zone.h b/cockatrice/src/game/zones/hand_zone.h index 8189c7087..3fd55b20b 100644 --- a/cockatrice/src/game/zones/hand_zone.h +++ b/cockatrice/src/game/zones/hand_zone.h @@ -19,6 +19,7 @@ public: QRectF boundingRect() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; void reorganizeCards() override; + void sortHand(); void setWidth(qreal _width); protected: diff --git a/cockatrice/src/client/game_logic/abstract_client.cpp b/cockatrice/src/server/abstract_client.cpp similarity index 99% rename from cockatrice/src/client/game_logic/abstract_client.cpp rename to cockatrice/src/server/abstract_client.cpp index bc227bf68..4f3098871 100644 --- a/cockatrice/src/client/game_logic/abstract_client.cpp +++ b/cockatrice/src/server/abstract_client.cpp @@ -1,6 +1,5 @@ #include "abstract_client.h" -#include "../../server/pending_command.h" #include "featureset.h" #include "get_pb_extension.h" #include "pb/commands.pb.h" @@ -18,6 +17,7 @@ #include "pb/event_user_left.pb.h" #include "pb/event_user_message.pb.h" #include "pb/server_message.pb.h" +#include "pending_command.h" #include diff --git a/cockatrice/src/client/game_logic/abstract_client.h b/cockatrice/src/server/abstract_client.h similarity index 100% rename from cockatrice/src/client/game_logic/abstract_client.h rename to cockatrice/src/server/abstract_client.h diff --git a/cockatrice/src/server/local_client.h b/cockatrice/src/server/local_client.h index 679d43f2b..145887ea8 100644 --- a/cockatrice/src/server/local_client.h +++ b/cockatrice/src/server/local_client.h @@ -1,7 +1,7 @@ #ifndef LOCALCLIENT_H #define LOCALCLIENT_H -#include "../client/game_logic/abstract_client.h" +#include "abstract_client.h" #include diff --git a/cockatrice/src/server/remote/remote_client.h b/cockatrice/src/server/remote/remote_client.h index f34fdb71b..0ab24c798 100644 --- a/cockatrice/src/server/remote/remote_client.h +++ b/cockatrice/src/server/remote/remote_client.h @@ -1,7 +1,7 @@ #ifndef REMOTECLIENT_H #define REMOTECLIENT_H -#include "../../client/game_logic/abstract_client.h" +#include "../abstract_client.h" #include "pb/commands.pb.h" #include diff --git a/cockatrice/src/server/remote/remote_decklist_tree_widget.cpp b/cockatrice/src/server/remote/remote_decklist_tree_widget.cpp index 0e6872646..dfed741f9 100644 --- a/cockatrice/src/server/remote/remote_decklist_tree_widget.cpp +++ b/cockatrice/src/server/remote/remote_decklist_tree_widget.cpp @@ -1,6 +1,6 @@ #include "remote_decklist_tree_widget.h" -#include "../../client/game_logic/abstract_client.h" +#include "../abstract_client.h" #include "../pending_command.h" #include "pb/command_deck_list.pb.h" #include "pb/response_deck_list.pb.h" diff --git a/cockatrice/src/server/remote/remote_replay_list_tree_widget.cpp b/cockatrice/src/server/remote/remote_replay_list_tree_widget.cpp index 953d1e6af..1fa72b20c 100644 --- a/cockatrice/src/server/remote/remote_replay_list_tree_widget.cpp +++ b/cockatrice/src/server/remote/remote_replay_list_tree_widget.cpp @@ -1,6 +1,6 @@ #include "remote_replay_list_tree_widget.h" -#include "../../client/game_logic/abstract_client.h" +#include "../abstract_client.h" #include "../pending_command.h" #include "pb/command_replay_list.pb.h" #include "pb/response_replay_list.pb.h" diff --git a/cockatrice/src/server/user/user_context_menu.cpp b/cockatrice/src/server/user/user_context_menu.cpp index a33b31632..86fa4a8bf 100644 --- a/cockatrice/src/server/user/user_context_menu.cpp +++ b/cockatrice/src/server/user/user_context_menu.cpp @@ -1,10 +1,10 @@ #include "user_context_menu.h" -#include "../../client/game_logic/abstract_client.h" #include "../../client/tabs/tab_account.h" #include "../../client/tabs/tab_game.h" #include "../../client/tabs/tab_supervisor.h" #include "../../game/game_selector.h" +#include "../abstract_client.h" #include "../chat_view/chat_view.h" #include "../pending_command.h" #include "pb/command_kick_from_game.pb.h" diff --git a/cockatrice/src/server/user/user_info_box.cpp b/cockatrice/src/server/user/user_info_box.cpp index 39babbf50..65868927f 100644 --- a/cockatrice/src/server/user/user_info_box.cpp +++ b/cockatrice/src/server/user/user_info_box.cpp @@ -1,11 +1,11 @@ #include "user_info_box.h" -#include "../../client/game_logic/abstract_client.h" #include "../../client/get_text_with_max.h" #include "../../client/ui/pixel_map_generator.h" #include "../../dialogs/dlg_edit_avatar.h" #include "../../dialogs/dlg_edit_password.h" #include "../../dialogs/dlg_edit_user.h" +#include "../abstract_client.h" #include "../pending_command.h" #include "passwordhasher.h" #include "pb/response_get_user_info.pb.h" diff --git a/cockatrice/src/server/user/user_list_manager.cpp b/cockatrice/src/server/user/user_list_manager.cpp index 6cf0c763d..c74706955 100644 --- a/cockatrice/src/server/user/user_list_manager.cpp +++ b/cockatrice/src/server/user/user_list_manager.cpp @@ -1,7 +1,7 @@ #include "user_list_manager.h" -#include "../../client/game_logic/abstract_client.h" #include "../../client/sound_engine.h" +#include "../abstract_client.h" #include "../pending_command.h" #include "pb/event_add_to_list.pb.h" #include "pb/event_remove_from_list.pb.h" diff --git a/cockatrice/src/server/user/user_list_widget.cpp b/cockatrice/src/server/user/user_list_widget.cpp index b1bc4dab7..b960d86ca 100644 --- a/cockatrice/src/server/user/user_list_widget.cpp +++ b/cockatrice/src/server/user/user_list_widget.cpp @@ -1,11 +1,11 @@ #include "user_list_widget.h" -#include "../../client/game_logic/abstract_client.h" #include "../../client/tabs/tab_account.h" #include "../../client/tabs/tab_supervisor.h" #include "../../client/ui/pixel_map_generator.h" #include "../../game/game_selector.h" #include "../../server/user/user_list_manager.h" +#include "../abstract_client.h" #include "../pending_command.h" #include "pb/moderator_commands.pb.h" #include "pb/response_get_games_of_user.pb.h" diff --git a/cockatrice/src/settings/cache_settings.cpp b/cockatrice/src/settings/cache_settings.cpp index 2ad735128..6bfe04e2f 100644 --- a/cockatrice/src/settings/cache_settings.cpp +++ b/cockatrice/src/settings/cache_settings.cpp @@ -355,6 +355,7 @@ SettingsCache::SettingsCache() spectatorsCanSeeEverything = settings->value("game/spectatorscanseeeverything", false).toBool(); createGameAsSpectator = settings->value("game/creategameasspectator", false).toBool(); defaultStartingLifeTotal = settings->value("game/defaultstartinglifetotal", 20).toInt(); + shareDecklistsOnLoad = settings->value("game/sharedecklistsonload", false).toBool(); rememberGameSettings = settings->value("game/remembergamesettings", true).toBool(); clientID = settings->value("personal/clientid", CLIENT_INFO_NOT_SET).toString(); clientVersion = settings->value("personal/clientversion", CLIENT_INFO_NOT_SET).toString(); @@ -1360,7 +1361,13 @@ void SettingsCache::setDefaultStartingLifeTotal(const int _defaultStartingLifeTo { defaultStartingLifeTotal = _defaultStartingLifeTotal; settings->setValue("game/defaultstartinglifetotal", defaultStartingLifeTotal); -}; +} + +void SettingsCache::setShareDecklistsOnLoad(const bool _shareDecklistsOnLoad) +{ + shareDecklistsOnLoad = _shareDecklistsOnLoad; + settings->setValue("game/sharedecklistsonload", shareDecklistsOnLoad); +} void SettingsCache::setCheckUpdatesOnStartup(QT_STATE_CHANGED_T value) { @@ -1373,6 +1380,7 @@ void SettingsCache::setStartupCardUpdateCheckPromptForUpdate(bool value) startupCardUpdateCheckPromptForUpdate = value; settings->setValue("personal/startupCardUpdateCheckPromptForUpdate", startupCardUpdateCheckPromptForUpdate); } + void SettingsCache::setStartupCardUpdateCheckAlwaysUpdate(bool value) { startupCardUpdateCheckAlwaysUpdate = value; diff --git a/cockatrice/src/settings/cache_settings.h b/cockatrice/src/settings/cache_settings.h index 16822d755..ec8b506c5 100644 --- a/cockatrice/src/settings/cache_settings.h +++ b/cockatrice/src/settings/cache_settings.h @@ -302,6 +302,7 @@ private: bool spectatorsCanSeeEverything; bool createGameAsSpectator; int defaultStartingLifeTotal; + bool shareDecklistsOnLoad; int keepalive; int timeout; void translateLegacySettings(); @@ -805,6 +806,10 @@ public: { return defaultStartingLifeTotal; } + bool getShareDecklistsOnLoad() const + { + return shareDecklistsOnLoad; + } bool getCreateGameAsSpectator() const { return createGameAsSpectator; @@ -1032,6 +1037,7 @@ public slots: void setSpectatorsCanSeeEverything(const bool _spectatorsCanSeeEverything); void setCreateGameAsSpectator(const bool _createGameAsSpectator); void setDefaultStartingLifeTotal(const int _defaultStartingLifeTotal); + void setShareDecklistsOnLoad(const bool _shareDecklistsOnLoad); void setRememberGameSettings(const bool _rememberGameSettings); void setCheckUpdatesOnStartup(QT_STATE_CHANGED_T value); void setStartupCardUpdateCheckPromptForUpdate(bool value); diff --git a/cockatrice/src/settings/game_filters_settings.cpp b/cockatrice/src/settings/game_filters_settings.cpp index 041a9a74a..e82b18a47 100644 --- a/cockatrice/src/settings/game_filters_settings.cpp +++ b/cockatrice/src/settings/game_filters_settings.cpp @@ -83,6 +83,17 @@ bool GameFiltersSettings::isHideNotBuddyCreatedGames() return !(previous == QVariant()) && previous.toBool(); } +void GameFiltersSettings::setHideOpenDecklistGames(bool hide) +{ + setValue(hide, "hide_open_decklist_games", "filter_games"); +} + +bool GameFiltersSettings::isHideOpenDecklistGames() +{ + QVariant previous = getValue("hide_open_decklist_games", "filter_games"); + return !(previous == QVariant()) && previous.toBool(); +} + void GameFiltersSettings::setGameNameFilter(QString gameName) { setValue(gameName, "game_name_filter", "filter_games"); diff --git a/cockatrice/src/settings/game_filters_settings.h b/cockatrice/src/settings/game_filters_settings.h index 8ab7d8e5e..a243c74e9 100644 --- a/cockatrice/src/settings/game_filters_settings.h +++ b/cockatrice/src/settings/game_filters_settings.h @@ -15,6 +15,8 @@ public: bool isHidePasswordProtectedGames(); bool isHideIgnoredUserGames(); bool isHideNotBuddyCreatedGames(); + void setHideOpenDecklistGames(bool hide); + bool isHideOpenDecklistGames(); QString getGameNameFilter(); QString getCreatorNameFilter(); int getMinPlayers(); diff --git a/cockatrice/src/settings/shortcuts_settings.cpp b/cockatrice/src/settings/shortcuts_settings.cpp index db5559d8f..53c6f6a23 100644 --- a/cockatrice/src/settings/shortcuts_settings.cpp +++ b/cockatrice/src/settings/shortcuts_settings.cpp @@ -115,6 +115,13 @@ ShortcutKey ShortcutsSettings::getShortcut(const QString &name) const return getDefaultShortcut(name); } +/** + * Gets the first shortcut for the given action. + * + * NOTE: In most cases you should be using ShortcutsSettings::getShortcut instead, + * as that will return all shortcuts if there are multiple shortcuts. + * The only reason to use this method is if an object does not accept multiple shortcuts, such as with QButtons. + */ QKeySequence ShortcutsSettings::getSingleShortcut(const QString &name) const { return getShortcut(name).at(0); diff --git a/cockatrice/src/settings/shortcuts_settings.h b/cockatrice/src/settings/shortcuts_settings.h index 039c6ca8e..fdf422783 100644 --- a/cockatrice/src/settings/shortcuts_settings.h +++ b/cockatrice/src/settings/shortcuts_settings.h @@ -413,6 +413,10 @@ private: {"Player/aSetCounter_storm", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Set Other Counters..."), parseSequenceString("Ctrl+\\"), ShortcutGroup::Player_Counters)}, + {"Player/aIncrementAllCardCounters", + ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Increment all card counters"), + parseSequenceString("Ctrl+Shift+A"), + ShortcutGroup::Playing_Area)}, {"Player/aIncP", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Add Power (+1/+0)"), parseSequenceString("Ctrl++;Ctrl+="), ShortcutGroup::Power_Toughness)}, @@ -552,6 +556,9 @@ private: ShortcutGroup::Move_selected)}, {"Player/aViewHand", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Hand"), parseSequenceString(""), ShortcutGroup::View)}, + {"Player/aSortHand", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Sort Hand"), + parseSequenceString("Ctrl+Shift+H"), + ShortcutGroup::View)}, {"Player/aViewGraveyard", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard"), parseSequenceString("F4"), ShortcutGroup::View)}, {"Player/aViewLibrary", diff --git a/cockatrice/src/client/game_logic/key_signals.cpp b/cockatrice/src/utility/key_signals.cpp similarity index 100% rename from cockatrice/src/client/game_logic/key_signals.cpp rename to cockatrice/src/utility/key_signals.cpp diff --git a/cockatrice/src/client/game_logic/key_signals.h b/cockatrice/src/utility/key_signals.h similarity index 100% rename from cockatrice/src/client/game_logic/key_signals.h rename to cockatrice/src/utility/key_signals.h diff --git a/cockatrice/translations/cockatrice_fr.ts b/cockatrice/translations/cockatrice_fr.ts index f7e0f31a0..fb3acce32 100644 --- a/cockatrice/translations/cockatrice_fr.ts +++ b/cockatrice/translations/cockatrice_fr.ts @@ -25,12 +25,12 @@ &Refresh - + &Rafraîchir Parse Set Name and Number (if available) - + Analyser le nom et le numéro de l'extension (si disponibles) @@ -38,18 +38,19 @@ Open in new tab - + Ouvrir dans un nouvel onglet Are you sure? - + Êtes-vous sûr ? The decklist has been modified. Do you want to save the changes? - + La liste de deck a été modifiée. +Voulez-vous enregistrer les modifications ? @@ -60,44 +61,45 @@ Do you want to save the changes? Error - + Erreur Could not open deck at %1 - + N'a pas pu ouvrir le deck à %1 Could not save remote deck - + N'a pas pu sauvegarder le deck distant The deck could not be saved. Please check that the directory is writable and try again. - + Le deck n'a pas pu être enregistré. +Vérifiez que le répertoire ne soit pas en lecture seule et réessayez. Save deck - + Sauvegarder le deck The deck could not be saved. - + Le deck n'a pas pu être enregistré. There are no cards in your deck to be exported - + Il n'y a pas de cartes dans le deck à exporter No deck was selected to be exported. - + Aucun deck n'a été sélectionné pour être exporté. @@ -105,12 +107,12 @@ Please check that the directory is writable and try again. Update Notes - + Notes de mises à jour Admin Notes for %1 - + Notes d'administrateur pour %1 @@ -118,12 +120,12 @@ Please check that the directory is writable and try again. Mainboard - + Deck principal Sideboard - + Réserve @@ -161,7 +163,7 @@ Please check that the directory is writable and try again. Show keyboard shortcuts in right-click menus - + Montrer les raccourcis clavier dans les menus clic-droit @@ -176,17 +178,17 @@ Please check that the directory is writable and try again. Auto-Rotate cards with sideways layout - + Rotation automatique des cartes avec disposition horizontale Override all card art with personal set preference (Pre-ProviderID change behavior) [Requires Client restart] - + Remplacer toutes les illustrations de cartes par les préférences personnelles (comportement avant modification du ProviderID) [Nécessite le redémarrage du client] Bump sets that the deck contains cards from to the top in the printing selector - + Mettre en avant que ce deck contient des cartes depuis le sommet, dans le sélecteur d'impression @@ -196,38 +198,38 @@ Please check that the directory is writable and try again. Use rounded card corners - + Utiliser des bords de cartes arrondis Minimum overlap percentage of cards on the stack and in vertical hand - + Pourcentage minimum de chevauchement des cartes dans la pile et dans la main verticale Maximum initial height for card view window: - + Hauteur initiale maximale pour la fenêtre d'affichage des cartes : rows - + lignes Maximum expanded height for card view window: - + Hauteur étendue maximale pour la fenêtre d'affichage des cartes : Card counters - + Marqueurs sur la carte Counter %1 - + Marqueur %1 @@ -523,12 +525,12 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa Main Type - + Type principal Sub Type - + Sous-type @@ -546,12 +548,12 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa Both - + Les deux View transformation - + Voir la transformation @@ -559,22 +561,22 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa View related cards - + Voir les cartes associées Add card to deck - + Ajouter la carte au deck Mainboard - + Deck principal Sideboard - + Réserve @@ -587,12 +589,12 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa Related cards: - + Cartes associées : Unknown card: - + Carte inconnue : @@ -742,13 +744,13 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa their custom zone '%1' nominative - + leur zone personnalisée '%1' %1's custom zone '%2' nominative - + La zone personnalisée '%2' de %1 @@ -756,7 +758,7 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa Parse error at line %1 col %2: - + Erreur de lecture à la ligne %1 (colonne %2) @@ -764,7 +766,7 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa Parse error at line %1 col %2: - + Erreur de lecture à la ligne %1 (colonne %2) @@ -772,7 +774,7 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa Card Info - + Infos de la carte @@ -780,47 +782,47 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa Search by card name (or search expressions) - + Rechercher par nom de carte (ou expression de recherche) Add to Deck - + Ajouter au deck Add to Sideboard - + Ajouter à la réserve Select Printing - + Choisir l'impression Show on EDHREC (Commander) - + Afficher sur EDHREC (Commandant) Show on EDHREC (Card) - + Afficher sur EDHREC (carte) Show Related cards - + Afficher les cartes associées Add card to &maindeck - + Ajouter la carte au &deck Add card to &sideboard - + Ajouter carte à la ré&serve @@ -828,87 +830,87 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa Banner Card - + Carte bannière Main Type - + Type principal Mana Cost - + Coût de mana Colors - + Couleurs Select Printing - + Choisir l'impression Deck - + Deck Deck &name: - + &Nom du deck : Banner Card/Tags Visibility Settings - + Paramètres de visibilité de la carte bannière et des étiquettes Show banner card selection menu - + Montrer le menu de sélection de carte bannière Show tags selection menu - + Montrer le menu de sélection d'étiquettes &Comments: - + &Commentaires : Group by: - + Grouper par : Hash: - + Empreinte : &Increment number - + Augmenter quant&ité &Decrement number - + &Diminuer quantité &Remove row - + &Retirer la ligne Swap card to/from sideboard - + Échanger la carte vers/depuis la réserve @@ -916,17 +918,17 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa Filters - + Filtres &Clear all filters - + &Effacer tous les filtres Delete selected - + Enlever la sélection @@ -934,109 +936,109 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa &Deck Editor - + &Éditeur de deck &New deck - + &Nouveau deck &Load deck... - + &Charger un deck... Load recent deck... - + Charger un deck récent... Clear - + Effacer &Save deck - + &Sauvegarder le deck Save deck &as... - + S&auvegarder le deck sous... Load deck from cl&ipboard... - + Charger un deck depuis le presse-pap&ier... Edit deck in clipboard - + Éditer le deck dans le presse-papier Annotated - + Avec annotations Not Annotated - + Sans annotation Save deck to clipboard - + Copier le deck dans le presse-papier Annotated (No set info) - + Annoté (pas d'info sur l'extension) Not Annotated (No set info) - + Pas annoté (pas d'info sur l'extension) &Print deck... - + Im&primer le deck... &Send deck to online service - + Envoyer le deck au service en &ligne Create decklist (decklist.org) - + Créer une liste de deck (decklist.org) Create decklist (decklist.xyz) - + Créer une liste de deck (decklist.xyz) Analyze deck (deckstats.net) - + &Analyser le deck sur deckstats.net Analyze deck (tappedout.net) - + Analyser le deck (tappedout.net) &Close - + &Fermer @@ -1044,7 +1046,7 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa Printing Selector - + Sélection d'impression @@ -1101,22 +1103,22 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa Network Cache Size: - + Taille du cache du réseau : Redirect Cache TTL: - + Rediriger le TTL du cache : How long cached redirects for urls are valid for. - + Combien de temps les redirections mises en cache pour les URL sont-elles valides. Picture Cache Size: - + Taille du cache des images : @@ -1219,12 +1221,12 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa Count - + Compter Set - + Édition @@ -1234,7 +1236,7 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa Provider ID - + Provider ID @@ -1247,12 +1249,12 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa Common deck formats (%1) - + Formats de decks courants (%1) All files (*.*) - + Tous les fichiers (*.*) @@ -1260,17 +1262,17 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa Mode: Exact Match - + Mode : correspondance exacte Mode: Includes - + Mode : inclure Color identity filter mode (AND/OR/NOT conjunctions of filters) - + Mode de filtre par identité de couleur (conjonctions AND/OR/NOT de filtres) @@ -1278,7 +1280,7 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa Edit tags ... - + Éditer les étiquettes... @@ -1286,62 +1288,62 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa Deck Tags Manager - + Gestionnaire d'étiquettes de decks Manage your deck tags. Check or uncheck tags as needed, or add new ones: - + Gérer vos étiquettes de decks. Ajouter ou retirer les étiquettes comme nécessaire, ou en créer de nouveaux : Add a new tag (e.g., Aggro️) - + Ajouter une nouvelle étiquette (e.g., Elfes) Add Tag - + Ajouter Étiquette Filter tags... - + Filtrer les étiquettes... OK - + OK Edit default tags - + Éditer les étiquettes par défaut Cancel - + Annuler Invalid Input - + Entrée invalide Tag name cannot be empty! - + Le nom de l'étiquette ne peut pas être vide ! Duplicate Tag - + Étiquette dupliquée This tag already exists. - + Cette étiquette existe déjà. @@ -1349,94 +1351,94 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa Banner Card - + Carte bannière Open in deck editor - + Ouvrir dans l'éditeur de deck Edit Tags - + Éditer les étiquettes Rename Deck - + Renommer le deck Save Deck to Clipboard - + Copier le deck dans le presse-papier Annotated - + Avec annotations Annotated (No set info) - + Avec annotations (pas d'info sur l'extension) Not Annotated - + Sans annotation Not Annotated (No set info) - + Sans annotation (pas d'info sur l'extension) Rename File - + Renommer le fichier Delete File - + Supprimer le fichier Set Banner Card - + Choisir la carte bannière New name: - + Nouveau nom : Error - + Erreur Rename failed - + Renommage échoué Delete file - + Supprimer le fichier Are you sure you want to delete the selected file? - + Êtes-vous certain de vouloir supprimer le fichier sélectionné ? Delete failed - + Suppression échouée @@ -1468,13 +1470,13 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa Load from clipboard... - + Charger depuis le presse-papier... Unload deck Unload deck... - + Annuler le chargement du deck @@ -1484,7 +1486,7 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa Force start - + Forcer le démarrage @@ -1510,18 +1512,19 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa Deck is greater than maximum file size. - + Le deck est plus grand que la taille maximum de fichier. Are you sure you want to force start? This will kick all non-ready players from the game. - + Êtes-vous sûr de vouloir forcer le démarrage ? +Cela va éjecter de la partie tous les joueurs non prêts à démarrer. Cockatrice - + Cockatrice @@ -1529,19 +1532,21 @@ This will kick all non-ready players from the game. Deck Format Conversion - + Conversion de format de deck You tried to add a tag to a .txt format deck. Tags can only be added to .cod format decks. Do you want to convert the deck to the .cod format? - + Vous avez essayé d'ajouter une étiquette à un deck au format .txt. +Les étiquettes ne peuvent être ajoutées qu'aux decks au format .cod. +Voulez-vous convertir le deck au format .cod ? Remember and automatically apply choice in the future - + Mémoriser et appliquer automatiquement le choix à l'avenir @@ -1559,7 +1564,7 @@ This will kick all non-ready players from the game. Delete the currently selected saved server - + Supprimer le serveur enregistré actuellement sélectionné @@ -1630,7 +1635,7 @@ This will kick all non-ready players from the game. Forgot password? - + Mot de passe oublié ? @@ -1773,12 +1778,12 @@ This will kick all non-ready players from the game. Starting life total: - + Total initial de point de vie Game setup options - + Options de configuration de la partie @@ -1876,7 +1881,7 @@ This will kick all non-ready players from the game. Create face-down (Only hides name) - + Créer face-cachée (cache seulement le nom) @@ -1909,53 +1914,53 @@ This will kick all non-ready players from the game. Edit Tags - + Éditer les étiquettes Add - + Ajouter Confirm - + Confirmer Cancel - + Annuler Enter a tag and press Enter - + Entrer une étiquette et valider avec Entrée ✖ - + Invalid Input - + Entrée invalide Tag name cannot be empty! - + Le nom de l'étiquette ne peut pas être vide ! Duplicate Tag - + Étiquette dupliquée This tag already exists. - + Cette étiquette existe déjà. @@ -2004,17 +2009,17 @@ Pour enlever votre avatar actuel, confirmez sans choisir une nouvelle image. Edit deck in clipboard - + Éditer le deck dans le presse-papier Error - + Erreur Invalid deck list. - + Liste de deck invalide. @@ -2215,32 +2220,32 @@ Assurez-vous d'activer l'édition « Fausse édition contenant les je Hide 'buddies only' games - + Ne pas afficher les parties « amis uniquement » Hide full games - + Cacher les parties pleines Hide games that have started - + Cacher les parties qui ont commencées Hide password protected games - + Cacher les parties protégées par un mot de passe Hide 'ignored user' games - + Cacher les parties des utilisateurs ignorés Hide games not created by buddy - + Cacher les parties non créées par des amis. @@ -2501,7 +2506,7 @@ Assurez-vous d'activer l'édition « Fausse édition contenant les je Load Deck - + Charger un deck @@ -2535,37 +2540,37 @@ Assurez-vous d'activer l'édition « Fausse édition contenant les je Card name (or search expressions): - + Nom de la carte (ou expression de recherche) : Number of hits: - + Nombre de cartes trouvées : Auto play hits - + Jouer les cartes trouvées automatiquement Put top cards on stack until... - + Placer la carte du dessus sur la pile jusqu'à... No cards matching the search expression exists in the card database. Proceed anyways? - + Aucune carte ne correspondant à l'expression recherchée n'existe dans la base de données de cartes. Continuer malgré tout ? Cockatrice - + Cockatrice Invalid filter - + Filtre invalide @@ -2683,27 +2688,27 @@ Your email will be used to verify your account. Unmodified Cards: - + Cartes non modifiées : Modified Cards: - + Cartes modifiées : Check Sets to enable them. Drag-and-Drop to reorder them and change their priority. Cards will use the printing of the highest priority enabled set. - + Cliquer sur des Extensions pour les activer. Glisser-et-déposer pour les réarranger et changer leur priorité. Les cartes utiliseront la version de l'extension activée ayant la plus haut priorité. Clear all set information - + Nettoyer toutes les informations sur les extensions Set all to preferred - + Tout régler selon vos préférences @@ -2854,39 +2859,41 @@ Voulez-vous changer l'emplacement de votre base de données ? Card Update Check - + Vérification de la mise à jour des cartes It has been more than %2 days since you last checked your card database for updates. Choose how you would like to run the card database updater. You can always change this behavior in the 'General' settings tab. - + Cela fait plus de %2 jour(s) que vous n'avez pas vérifié les mises à jour de votre base de données de cartes. +Choisissez comment vous souhaitez exécuter le programme de mise à jour de la base de données de cartes. +Vous pouvez toujours modifier ce comportement dans l'onglet « Général » des paramètres. Run in foreground - + S'exécuter en tâche principale Run in background - + S'exécuter en tâche de fond Run in background and always from now on - + S'exécuter en tâche de fond, et toujours le faire à partir de maintenant Don't prompt again and don't run - + Ne pas demander à nouveau et ne pas exécuter Don't run this time - + Ne pas exécuter cette fois @@ -2953,7 +2960,7 @@ Veuillez s'il vous plaît visiter la page de téléchargement, pour mettre Downloading update: %1 Downloading update... - + Téléchargement de la mise à jour : %1 @@ -3031,13 +3038,14 @@ Veuillez s'il vous plaît visiter la page de téléchargement, pour mettre You may have to manually download the new version. Unfortunately there are no download packages available for your operating system. You may have to build from source yourself. - + Malheureusement, la mise à jour automatique n'a pas pu trouver un téléchargement compatible. +Vous allez peut-être devoir télécharger manuellement la nouvelle version. Please check the <a href="%1">releases page</a> on our Github and download the build for your system. Please check the download page manually and visit the wiki for instructions on compiling. - + Veuillez vérifier la <a href="%1">page "releases"</a> sur notre Github et télécharger le programme pour votre système. @@ -3087,7 +3095,7 @@ You may have to build from source yourself. Copy to clipboard - + Charger vers le presse-papier @@ -3100,12 +3108,12 @@ You may have to build from source yourself. In %1 decks - + Dans %1 deck(s) %1% of %2 decks - + %1% de %2 deck(s) @@ -3113,47 +3121,47 @@ You may have to build from source yourself. Card Hoarder - + Card Hoarder Card Kingdom - + Card Kingdom Card Market - + Card Market Face 2-Face - + Face 2-Face Mana Pool - + Mana Pool MTG Stocks - + MTG Stocks Scg - + Scg Tcgl - + Tcgl Tcgplayer - + Tcgplayer @@ -3161,7 +3169,7 @@ You may have to build from source yourself. %1% Synergy - + %1% synergie @@ -3169,22 +3177,22 @@ You may have to build from source yourself. Combos - + Combos Average Deck - + Deck moyen Game Changers - + Game Changers Budget - + Budget @@ -3192,7 +3200,7 @@ You may have to build from source yourself. Salt: - + Sel : @@ -3208,22 +3216,22 @@ You may have to build from source yourself. Confirm Delete - + Confirmer la suppression Are you sure you want to delete the filter '%1'? - + Êtes-vous sûr de vouloir supprimer le filtre '%1' ? Delete Failed - + Suppression échouée Failed to delete filter '%1'. - + Échec de la suppression du filtre '%1'. @@ -3284,17 +3292,17 @@ You may have to build from source yourself. Join Game - + Rejoindre la partie Spectate Game - + Rejoindre la partie comme spectateur Game Information - + Informations sur la partie @@ -3494,7 +3502,7 @@ You may have to build from source yourself. How to help with translations - + Comment aider avec les traductions @@ -3504,7 +3512,7 @@ You may have to build from source yourself. Filters directory: - + Répertoire des filtres : @@ -3539,37 +3547,37 @@ You may have to build from source yourself. Check for client updates on startup - + Vérifier les mises à jour du client au démarrage Check for card database updates on startup - + Vérifier les mises à jour de la base de données des cartes au démarrage... Don't check - + Ne pas vérifier Prompt for update - + Confirmer les mises à jour Always update in the background - + Toujours mettre à jour en tâche de fond Check for card database updates every - + Vérifier les mises à jour de la base de données des cartes tous les days - + jour(s) @@ -3589,7 +3597,7 @@ You may have to build from source yourself. Last update check on %1 (%2 days ago) - + Dernière vérification de mise à jour le %1 (il y a %2 jours) @@ -4006,7 +4014,7 @@ Cela veut généralement dire que votre client n'est plus à jour, et que l The connection to the server has been lost. - + La connexion au serveur a été perdue. @@ -4152,12 +4160,12 @@ La version locale est %1, la nouvelle version est %2. Reload card database - + Recharger la base de cartes Tabs - + Onglets @@ -4187,12 +4195,12 @@ La version locale est %1, la nouvelle version est %2. Check for Card Updates (Automatic) - + Vérifier les mises à jour des cartes (automatiquement) Show Status Bar - + Montrer la barre de statut @@ -4202,7 +4210,7 @@ La version locale est %1, la nouvelle version est %2. Open Settings Folder - + Ouvrir le dossier des paramètres @@ -4320,43 +4328,44 @@ Pour plus d'informations sur la modification de l'ordre des éditions, Card database update running. - + Une mise à jour de la base de données de cartes est en cours. Failed to start. The file might be missing, or permissions might be incorrect. - + Échec au démarrage. Le fichier peut être manquant, ou les permissions sont incorrectes. The process crashed some time after starting successfully. - + Le processus a échoué quelque temps après avoir démarré avec succès. Timed out. The process took too long to respond. The last waitFor...() function timed out. - + Temps limite dépassé. Le processus a pris trop longtemps pour répondre. La dernière fonction waitFor...() a terminé. An error occurred when attempting to write to the process. For example, the process may not be running, or it may have closed its input channel. - + Une erreur a eu lieu en essayant d'écrire vers le processus. Par exemple, le processus pourrait ne pas tourner, ou il pourrait avoir son canal d'entrée fermé. An error occurred when attempting to read from the process. For example, the process may not be running. - + Une erreur a eu lieu en essayant d'écrire vers le processus. Par exemple, le processus pourrait ne pas tourner, ou il pourrait avoir son canal de sortie inactif. Unknown error occurred. - + Une erreur inconnue est arrivée. The card database updater exited with an error: %1 - + L'outil de mise à jour de la base de données de cartes s'est arrêté avec l'erreur : +%1 @@ -4429,7 +4438,7 @@ Cockactrice va maintenant recharger la base de données de cartes. Mana Base - + Base de mana @@ -4438,7 +4447,7 @@ Cockactrice va maintenant recharger la base de données de cartes. Mana Curve - + Courbe de mana @@ -4447,7 +4456,7 @@ Cockactrice va maintenant recharger la base de données de cartes. Mana Devotion - + Dévotion au mana @@ -4535,7 +4544,7 @@ Cockactrice va maintenant recharger la base de données de cartes. from custom zone '%1' - + depuis la zone personnalisée '%1' @@ -4625,7 +4634,7 @@ Cockactrice va maintenant recharger la base de données de cartes. %1 creates a face down token. - + %1 crée un jeton face-cachée. @@ -4715,7 +4724,7 @@ Cockactrice va maintenant recharger la base de données de cartes. %1 moves %2%3 to custom zone '%4'. - + %1 déplace %2%3 vers la zone personnalisée '%4'. @@ -4737,17 +4746,17 @@ Cockactrice va maintenant recharger la base de données de cartes. %1 is looking at the %4 %3 card(s) %2. %1 is looking at the top %3 card(s) %2. top card for singular, top %3 cards for plural - + %1 regarde la %4 %3 carte %2.%1 regarde les %4 %3 cartes %2.%1 regarde la / les %4 %3 carte(s) %2. bottom - + dessous top - + dessus @@ -4934,12 +4943,12 @@ Cockactrice va maintenant recharger la base de données de cartes. %1 places %2 "%3" counter(s) on %4 (now %5). - + %1 place %2 "%3" compteur sur %4 (désormais %5).%1 place %2 "%3" compteurs sur %4 (désormais %5).%1 place %2 "%3" compteur(s) sur %4 (désormais %5). %1 removes %2 "%3" counter(s) from %4 (now %5). - + %1 retire %2 "%3" compteur sur %4 (désormais %5).%1 retire %2 "%3" compteurs sur %4 (désormais %5).%1 retire %2 "%3" compteur(s) sur %4 (désormais %5). @@ -5206,17 +5215,17 @@ Cockactrice va maintenant recharger la base de données de cartes. Cards to overlap: - + Cartes à superposer : Overlap percentage: - + Pourcentage de superposition : Overlap direction: - + Direction de superposition : @@ -5523,7 +5532,7 @@ Cockactrice va maintenant recharger la base de données de cartes. View bottom cards of library... - + Voir les cartes du dessous de la bibliothèque... @@ -5533,23 +5542,23 @@ Cockactrice va maintenant recharger la base de données de cartes. Shuffle - + Mélanger Put top cards on stack &until... Take top cards &until... - + Placer les cartes du dessus sur la pile j&usqu'à... Shuffle top cards... - + Mélanger les cartes du dessus... Shuffle bottom cards... - + Mélanger les cartes du dessous... @@ -5584,13 +5593,13 @@ Cockactrice va maintenant recharger la base de données de cartes. C&ustom Zones - + &Zones personnalisés View custom zone '%1' - + Voir la zone personnalisée '%1' @@ -5620,7 +5629,7 @@ Cockactrice va maintenant recharger la base de données de cartes. Ca&rd counters - + Ma&rqueurs sur la carte @@ -5641,12 +5650,12 @@ Cockactrice va maintenant recharger la base de données de cartes. S&elect Row - + Sél&ectionne une ligne S&elect Column - + Sél&ectionne une colonne @@ -5778,7 +5787,7 @@ Cockactrice va maintenant recharger la base de données de cartes. &Top of library in random order - + &Dessus de la bibliothèque dans un ordre aléatoire @@ -5798,17 +5807,17 @@ Cockactrice va maintenant recharger la base de données de cartes. View bottom cards of library - + Voir les cartes du dessous de la bibliothèque Shuffle top cards of library - + Mélanger les cartes du dessus de la bibliothèque Shuffle bottom cards of library - + Mélanger les cartes du dessous de la bibliothèque @@ -6013,12 +6022,12 @@ Cockactrice va maintenant recharger la base de données de cartes. Display Navigation Buttons - + Afficher les boutons de navigation <b>Warning:</b> You appear to be using custom card art, which has known bugs when also using the printing selector in this version of Cockatrice. - + <b>Attention :</b> Vous semblez utiliser des illustrations de cartes personnalisées, qui présentent des bugs connus lorsque vous utilisez également le sélecteur d'impression dans cette version de Cockatrice. @@ -6026,22 +6035,22 @@ Cockactrice va maintenant recharger la base de données de cartes. Preference - + Préférence Pin Printing - + Épingler Imprimer Unpin Printing - + Désépingler Imprimer Show Related cards - + Afficher les cartes associées @@ -6049,7 +6058,7 @@ Cockactrice va maintenant recharger la base de données de cartes. Search by set name or set code - + Rechercher par nom d'extension ou code d'extension @@ -6057,17 +6066,17 @@ Cockactrice va maintenant recharger la base de données de cartes. Previous Card in Deck - + Carte précédente dans le deck Bulk Selection - + Sélection groupée Next Card in Deck - + Carte suivante dans le deck @@ -6172,12 +6181,12 @@ Cockactrice va maintenant recharger la base de données de cartes. Overwrite Existing File? - + Écraser le fichier existant ? A .cod version of this deck already exists. Overwrite it? - + Une version en fichier .cod existe déjà pour ce deck. L'écraser ? @@ -6367,7 +6376,7 @@ Cockactrice va maintenant recharger la base de données de cartes. Choose an action from the table - + Choisir une action de la table @@ -6382,7 +6391,7 @@ Cockactrice va maintenant recharger la base de données de cartes. Shortcut already in use by: - + Raccourci déjà utilisé par : @@ -6469,12 +6478,12 @@ Cockactrice va maintenant recharger la base de données de cartes. Clear all shortcuts - + Effacer tous les raccourcis Search by shortcut name - + Rechercher par nom de raccourci @@ -6606,7 +6615,7 @@ Please check your shortcut settings! Default - + Défaut @@ -6634,17 +6643,17 @@ Please check your shortcut settings! Add to Buddy List - + Ajouter à la liste d'amis Add to Ignore List - + Ajouter à la liste noire Account - + Compte @@ -6677,27 +6686,27 @@ Please check your shortcut settings! Server moderator functions - + Fonctions de modérateur du serveur Replay ID - + Replay ID Grant Replay Access - + Accorder l'accès au Replay Username to Activate - + Nom d'utilisateur à activer Force Activate User - + Forcer l'activation d'un utilisateur @@ -6713,12 +6722,12 @@ Please check your shortcut settings! Success - + Succès Replay access granted - + Accès au Replay accordé @@ -6727,37 +6736,37 @@ Please check your shortcut settings! Error - + Erreur Unable to grant replay access. Replay ID invalid - + Incapable d'accorder l'accès au Replay. Le Replay ID est invalide. Unable to grant replay access. Internal error - + Incapable d'accorder l'accès au Replay. Erreur interne. User successfully activated - + Utilisateur activé avec succès Unable to activate user. Username invalid - + Incapable d'activer l'utilisateur. Nom d'utilisateur invalide Unable to activate user. User already active - + Incapable d'activer l'utilisateur. Utilisateur déjà actif Unable to activate user. Internal error - + Incapable d'activer l'utilisateur. Erreur interne @@ -6819,45 +6828,45 @@ Please check your shortcut settings! Visual Deck: %1 - + Deck visuel : %1 &Visual Deck Editor - + &Éditeur de deck visuel Card Info - + Infos de la carte Deck - + Deck Filters - + Filtres &View - + &Voir Deck Analytics - + Analyse de deck Printing - + Imprimer @@ -6866,7 +6875,7 @@ Please check your shortcut settings! Visible - + Visible @@ -6875,12 +6884,12 @@ Please check your shortcut settings! Floating - + Flottant Reset layout - + Réinitialiser l'interface @@ -6888,22 +6897,22 @@ Please check your shortcut settings! Visual Deck View - + Vue de deck visuel Visual Database Display - + Affichage visuel de la base de données Deck Analytics - + Analyse de deck Sample Hand - + Exemple de main @@ -6927,7 +6936,7 @@ Please check your shortcut settings! Rename deck or folder - + Renommer le deck ou le dossier @@ -6956,22 +6965,22 @@ Please check your shortcut settings! Open decks folder - + Ouvrir le dossier des decks Rename local folder - + Renommer le dossier local Rename local file - + Renommer le fichier local New name: - + Nouveau nom : @@ -6984,7 +6993,7 @@ Please check your shortcut settings! Rename failed - + Renommage échoué @@ -7022,17 +7031,17 @@ Veuillez entrer un nom: Are you sure you want to delete the selected files? - + Êtes-vous certain de vouloir supprimer les fichiers sélectionnés ? Delete remote decks - + Supprimer les decks dinstants Are you sure you want to delete the selected decks? - + Êtes-vous certain de vouloir supprimer les decks sélectionnés ? @@ -7043,7 +7052,7 @@ Veuillez entrer un nom: Deck Storage - + Stockage de deck @@ -7051,17 +7060,17 @@ Veuillez entrer un nom: Visual Deck Storage - + Stockage visuel de deck Error - + Erreur Could not open deck at %1 - + N'a pas pu ouvrir le deck à %1 @@ -7069,7 +7078,7 @@ Veuillez entrer un nom: EDHREC: - + EDHREC : @@ -7077,32 +7086,32 @@ Veuillez entrer un nom: &Cards - + &Cartes Top Commanders - + Commandants populaires Tags - + Étiquettes Search for a card ... - + Rechercher une carte ... Search - + Rechercher EDHREC: - + EDHREC : @@ -7197,7 +7206,7 @@ Veuillez entrer un nom: Un&concede - + Annuler la &concession @@ -7539,7 +7548,7 @@ Plus vous entrez d'informations, meilleurs seront les résultats. Rename - + Renommer @@ -7556,7 +7565,7 @@ Plus vous entrez d'informations, meilleurs seront les résultats. Open replays folder - + Ouvrir le dossier des Replays @@ -7571,12 +7580,12 @@ Plus vous entrez d'informations, meilleurs seront les résultats. Rename local folder - + Renommer le dossier local Rename local file - + Renommer le fichier local @@ -7586,12 +7595,12 @@ Plus vous entrez d'informations, meilleurs seront les résultats. Error - + Erreur Rename failed - + Renommage échoué @@ -7621,7 +7630,7 @@ Plus vous entrez d'informations, meilleurs seront les résultats. Game Replays - + Replays de parties @@ -7713,57 +7722,57 @@ Plus vous entrez d'informations, meilleurs seront les résultats. Deck Editor - + Éditeur de deck Visual Deck Editor - + Éditeur de deck visuel EDHRec - + EDHrec &Visual Deck Storage - + Stockage &visuel de decks Visual Database Display - + Affichage visuel de la base de données Server - + Serveur Account - + Compte Deck Storage - + Stockage de deck Game Replays - + Replays de parties Administration - + Administration Logs - + Journaux @@ -7846,7 +7855,7 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Visual Database Display - + Affichage visuel de la base de données @@ -8016,7 +8025,7 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre View admin notes - + Voir les notes d'administrateur @@ -8070,7 +8079,7 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Failed to get admin notes. - + Impossible de récupérer les notes d'administrateur. @@ -8305,7 +8314,7 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre &Clicking plays all selected cards (instead of just the clicked card) - + &Cliquer joue toutes les cartes sélectionnées (à la place de seulement la carte cliquée) @@ -8315,12 +8324,12 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Close card view window when last card is removed - + Fermer la fenêtre d'affichage des cartes lorsque la dernière carte est supprimée Auto focus search bar when card view window is opened - + Focalise automatiquement la barre de recherche lorsque la fenêtre d'affichage des cartes est ouverte @@ -8365,67 +8374,67 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Deck editor/storage settings - + Paramètres d'éditeur et de stockage de deck Open deck in new tab by default - + Ouvre le deck dans un nouvel onglet par défaut Use visual deck storage in game lobby - + Utiliser le stockage visuel de decks dans le lobby des parties Use selection animation for Visual Deck Storage - + Utilisez l'animation de sélection pour le stockage visuel des deck When adding a tag in the visual deck storage to a .txt deck: - + Lorsque vous ajoutez une étiquette dans le stockage visuel du deck à un deck stocké comme un fichier .txt : do nothing - + ne rien faire ask to convert to .cod - + demander à convertir en fichier .cod always convert to .cod - + toujours convertir en fichier .cod Default deck editor type - + Type d'éditeur de deck par défaut Classic Deck Editor - + Éditeur de deck classique Visual Deck Editor - + Éditeur de deck visuel Replay settings - + Paramètres du replay Buffer time for backwards skip via shortcut: - + Temps de tampon pour les sauts en arrière via un raccourci : @@ -8433,22 +8442,22 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Users connected to server: %1 - + Joueurs connectés au serveur : %1 Users in this room: %1 - + Joueurs dans ce salon : %1 Buddies online: %1 / %2 - + Amis connectés : %1 / %2 Ignored users online: %1 / %2 - + Joueurs sur liste noire connectés : %1 / %2 @@ -8456,22 +8465,22 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Mode: Exact Match - + Mode : correspondance exacte Mode: Includes - + Mode : inclure Mode: Include/Exclude - + Mode : inclure / exclure Filter mode (AND/OR/NOT conjunctions of filters) - + Mode de filtre (conjonctions AND/OR/NOT de filtres) @@ -8479,17 +8488,17 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Save Filter - + Sauvegarder le filtre Save all currently applied filters to a file - + Sauvegarder tous les filtres actuellement appliqués dans un fichier Enter filename... - + Entrer le nom du fichier... @@ -8497,22 +8506,22 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Do not display card main-types with less than this amount of cards in the database - + Ne pas afficher les types principaux de cartes dont le nombre est inférieur à ce montant dans la base de données Filter mode (AND/OR/NOT conjunctions of filters) - + Mode de filtre (conjonctions AND/OR/NOT de filtres) Mode: Exact Match - + Mode : correspondance exacte Mode: Includes - + Mode : inclure @@ -8520,27 +8529,27 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Filter by name... - + Filtrer par nom... Load from Deck - + Charger depuis un deck Apply all card names in currently loaded deck as exact match name filters - + Appliquer tous les noms de cartes du deck actuellement chargé comme filtres de nom exacts Load from Clipboard - + Charger depuis le presse-papier... Apply all card names in clipboard as exact match name filters - + Appliquer tous les noms de cartes du presse-papier comme filtres de nom exacts @@ -8548,7 +8557,7 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Filter to most recent sets - + Filtrer par extensions récentes @@ -8556,19 +8565,19 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Search sets... - + Rechercher les extensions... Mode: Exact Match - + Mode : correspondance exacte Mode: Includes - + Mode : inclure @@ -8576,27 +8585,27 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Search subtypes... - + Rechercher par sous-types... Do not display card sub-types with less than this amount of cards in the database - + Ne pas afficher les sous-types de cartes dont le nombre est inférieur à ce montant dans la base de données Filter mode (AND/OR/NOT conjunctions of filters) - + Mode de filtre (conjonctions AND/OR/NOT de filtres) Mode: Exact Match - + Mode : correspondance exacte Mode: Includes - + Mode : inclure @@ -8604,32 +8613,32 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Search by card name (or search expressions) - + Rechercher par nom de carte (ou expression de recherche) Clear all filters - + Effacer tous les filtres Save and load filters - + Sauvegarder et charger des filtres Filter by exact card name - + Filtrer par nom exact de carte Filter by card sub-type - + Filtrer par sous-type de carte Filter by set - + Filtrer par extension @@ -8637,12 +8646,12 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Draw a new sample hand - + Piocher un nouvel exemple de main Sample hand size - + Taille de l'exemple de main @@ -8650,38 +8659,38 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Click and drag to change the sort order within the groups - + Cliquer et glisser pour changer l'ordre dans les groupes Quick search and add card - + Recherche et ajout rapide d'une carte Search for closest match in the database (with auto-suggestions) and add preferred printing to the deck on pressing enter - + Recherchez la correspondance la plus proche dans la base de données (avec suggestions automatiques) et ajoutez l'impression souhaitée au deck en appuyant sur Entrée Configure how cards are sorted within their groups - + Configurez le mode de tri des cartes dans leurs groupes. Overlap Layout - + Interface de superposition Change how cards are displayed within zones (i.e. overlapped or fully visible.) - + Modifier l'affichage des cartes dans les zones (i.e. superposées ou entièrement visibles). Flat Layout - + Interface plate @@ -8689,7 +8698,7 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Deck Storage - + Stockage de deck @@ -8697,47 +8706,47 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Show Folders - + Montrer les dossiers Show Tag Filter - + Montrer le filtre à étiquette Show Tags On Deck Previews - + Montrer les étiquettes sur les aperçus de decks Show Banner Card Selection Option - + Montrer l'option de sélection de carte bannière Draw unused Color Identities - + Affiche les identités de couleurs non utilisées Unused Color Identities Opacity - + Opacité des identités de couleur inutilisées Deck tooltip: - + Aide contextuelle du deck : None - + Aucun(e) Filepath - + Chemin de fichier @@ -8745,7 +8754,7 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Search by filename (or search expression) - + Rechercher par chemin de fichier (ou expressions de recherche) @@ -8753,22 +8762,22 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Sort Alphabetically (Deck Name) - + Trier par ordre alphabétique (nom de deck) Sort Alphabetically (Filename) - + Trier par ordre alphabétique (nom de fichier) Sort by Last Modified - + Trier par date de dernière modification Sort by Last Loaded - + Trier par date de dernier chargement @@ -8776,17 +8785,17 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Loading database ... - + Chargement de la base de données ... Refresh loaded files - + Recharger les fichiers chargés Visual Deck Storage Settings - + Paramètres du stockage visuel des decks @@ -8919,7 +8928,7 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Include cards rebalanced for Alchemy [requires restart] - + Inclure les cartes rééquilibrées pour Alchemy [nécessite un redémarrage] @@ -8972,12 +8981,12 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Search by card name (or search expressions) - + Rechercher par nom de carte (ou expression de recherche) Ungrouped - + Non groupé @@ -8997,7 +9006,7 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Unsorted - + Non trié @@ -9022,12 +9031,12 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Sort by P/T - + Trier par F/E Sort by Set - + Trier par extension @@ -9153,12 +9162,12 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Replays - + Replays Tabs - + Onglets @@ -9209,12 +9218,12 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Analyze Deck (deckstats.net) Analyze Deck - + Analyser le deck (deckstats.net) Analyze Deck (tappedout.net) - + Analyser le deck (tappedout.net) @@ -9249,12 +9258,12 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Export Deck (decklist.org) - + Exporter le deck (decklist.org) Export Deck (decklist.xyz) - + Exporter le deck (decklist.xyz) @@ -9275,12 +9284,12 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Edit Deck in Clipboard, Annotated - + Éditer le deck dans le presse-papier, avec annotations Edit Deck in Clipboard - + Éditer le deck dans le presse-papier @@ -9326,7 +9335,7 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Save Deck to Clipboard, Annotated (No Set Info) - + Copier le deck, avec annotations (sans information d'extension) @@ -9336,7 +9345,7 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Save Deck to Clipboard (No Set Info) - + Copier le deck (sans information d'extension) @@ -9396,107 +9405,107 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Show Status Bar - + Montrer la barre de statut Unload Deck - + Annuler le chargement du deck Force Start - + Forcer le démarrage Add Card Counter (F) - + Ajouter un marqueur de carte (F) Remove Card Counter (F) - + Retirer un marqueur de carte (F) Set Card Counters (F)... - + Nombre de marqueurs de carte (F)... Add Card Counter (E) - + Ajouter un marqueur de carte (E) Remove Card Counter (E) - + Retirer un marqueur de carte (E) Set Card Counters (E)... - + Nombre de marqueurs de carte (E)... Add Card Counter(D) - + Ajouter un marqueur de carte (D) Remove Card Counter (D) - + Retirer un marqueur de carte (D) Set Card Counters (D)... - + Nombre de marqueurs de carte (D)... Add Card Counter (C) - + Ajouter un marqueur de carte (C) Remove Card Counter (C) - + Retirer un marqueur de carte (C) Set Card Counters (C)... - + Nombre de marqueurs de carte (C)... Add Card Counter (B) - + Ajouter un marqueur de carte (B) Remove Card Counter (B) - + Retirer un marqueur de carte (B) Set Card Counters (B)... - + Nombre de marqueurs de carte (B)... Add Card Counter (A) - + Ajouter un marqueur de carte (A) Remove Card Counter (A) - + Retirer un marqueur de carte (A) Set Card Counters (A)... - + Nombre de marqueurs de carte (A)... @@ -9706,7 +9715,7 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Hide Card in Reveal Window - + Cache la carte dans la fenêtre Révéler @@ -9776,17 +9785,17 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Select All Cards in Zone - + Sélectionne toutes les cartes dans la zone Select All Cards in Row - + Sélectionne toutes les cartes dans la ligne Select All Cards in Column - + Sélectionne toutes les cartes dans la colonne @@ -9852,7 +9861,7 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Bottom Cards of Library - + Cartes du dessous de la bibliothèque @@ -9880,7 +9889,7 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Stack Until Found - + Empiler jusqu'à ce que trouvé @@ -9925,12 +9934,12 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Shuffle Top Cards of Library - + Mélanger les cartes du dessus de la bibliothèque Shuffle Bottom Cards of Library - + Mélanger les cartes du dessous de la bibliothèque @@ -9995,22 +10004,22 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Skip Forward - + Avance en avant Skip Backward - + Avant en arrière Skip Forward by a lot - + Avance beaucoup en avant Skip Backward by a lot - + Avance beaucoup en arrière @@ -10020,37 +10029,37 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre Toggle Fast Forward - + Activer l'avance rapide Visual Deck Storage - + Stockage visuel de deck Deck Storage - + Stockage de deck Server - + Serveur Account - + Compte Administration - + Administration Logs - + Journaux \ No newline at end of file diff --git a/cockatrice/translations/cockatrice_it.ts b/cockatrice/translations/cockatrice_it.ts index f014d3ff2..915b5479e 100644 --- a/cockatrice/translations/cockatrice_it.ts +++ b/cockatrice/translations/cockatrice_it.ts @@ -224,17 +224,17 @@ Controlla se la cartella è valida e prova ancora. Card counters - + Segnalini della carta Counter %1 - + Segnalino %1 Hand layout - Layout della mano + Disposizione della mano @@ -249,17 +249,17 @@ Controlla se la cartella è valida e prova ancora. Table grid layout - Layout della griglia tabellare + Disposizione delle aree di gioco Invert vertical coordinate - Inverti le coordinate verticali + Inverti disposizione verticale Minimum player count for multi-column layout: - Numero di giocatori minimo per layout multicolonna: + Numero di giocatori minimo per disposizione multicolonna: @@ -525,12 +525,12 @@ Questa è visibile solo ai moderatori e non alla persona bannata. Main Type - + Tipo Sub Type - + Sottotipo @@ -744,13 +744,13 @@ Questa è visibile solo ai moderatori e non alla persona bannata. their custom zone '%1' nominative - + la sua zona personalizzata '%1' %1's custom zone '%2' nominative - + la zona personalizzata '%2' di %1 @@ -758,7 +758,7 @@ Questa è visibile solo ai moderatori e non alla persona bannata. Parse error at line %1 col %2: - + Errore di lettura alla riga %1 posizione %2: @@ -766,7 +766,7 @@ Questa è visibile solo ai moderatori e non alla persona bannata. Parse error at line %1 col %2: - + Errore di lettura alla riga %1 posizione %2: @@ -835,17 +835,17 @@ Questa è visibile solo ai moderatori e non alla persona bannata. Main Type - + Tipo Mana Cost - + Costo di mana Colors - + Colori @@ -865,17 +865,17 @@ Questa è visibile solo ai moderatori e non alla persona bannata. Banner Card/Tags Visibility Settings - + Impostazioni carta copertina/etichette Show banner card selection menu - + Visualizza menu di selezione carta copertina Show tags selection menu - + Visualizza menu di selezione etichette @@ -885,7 +885,7 @@ Questa è visibile solo ai moderatori e non alla persona bannata. Group by: - + Raggruppa per: @@ -1272,7 +1272,7 @@ Questa è visibile solo ai moderatori e non alla persona bannata. Color identity filter mode (AND/OR/NOT conjunctions of filters) - + Filtraggio identità di colore (utilizzabile con connettivi logici AND/OR/NOT) @@ -1318,7 +1318,7 @@ Questa è visibile solo ai moderatori e non alla persona bannata. Edit default tags - + Modifica etichette @@ -1470,7 +1470,7 @@ Questa è visibile solo ai moderatori e non alla persona bannata. Load from clipboard... - + Carica dagli appunti... @@ -1512,18 +1512,19 @@ Questa è visibile solo ai moderatori e non alla persona bannata. Deck is greater than maximum file size. - + Il mazzo è più grande della dimensione massima del file consentita. Are you sure you want to force start? This will kick all non-ready players from the game. - + Sicuro di voler forzare l'avvio? +Ciò espellerà dalla partita tutti i giocatori che non sono pronti. Cockatrice - + Cockatrice @@ -1875,12 +1876,12 @@ Vuoi convertire il mazzo al formato .cod? &Destroy token when it leaves the table - &Distruggi la pedina quando lascia il tavolo + &Elimina la pedina quando lascia il campo Create face-down (Only hides name) - + Crea a faccia in giù (nasconde solo il nome) @@ -1913,53 +1914,53 @@ Vuoi convertire il mazzo al formato .cod? Edit Tags - + Modifica etichette Add - + Aggiungi Confirm - + Conferma Cancel - + Annulla Enter a tag and press Enter - + Scrivi il nome dell'etichetta e premi Invio ✖ - + Invalid Input - + Input non valido Tag name cannot be empty! - + Il nome dell'etichetta non può essere vuoto! Duplicate Tag - + Duplica Etichetta This tag already exists. - + Questa etichetta esiste già. @@ -2244,7 +2245,7 @@ Assicurati di abilitare il set "Pedine" nella finestra "Organizza Hide games not created by buddy - + Nascondi partite non create dagli amici @@ -2688,27 +2689,27 @@ La tua email verrà utilizzata per verificare il tuo account. Unmodified Cards: - + Carte non modificate: Modified Cards: - + Carte modificate: Check Sets to enable them. Drag-and-Drop to reorder them and change their priority. Cards will use the printing of the highest priority enabled set. - + Seleziona i set per abilitarli. Trascina per riordinarli e modificare la loro priorità. Le carte useranno la stampa del set abilitato con la priorità massima. Clear all set information - + Elimina tutte le info sui set Set all to preferred - + Imposta tutti come preferiti @@ -2858,39 +2859,41 @@ Desideri modificare l'impostazione della posizione del database? Card Update Check - + Controllo aggiornamenti carte It has been more than %2 days since you last checked your card database for updates. Choose how you would like to run the card database updater. You can always change this behavior in the 'General' settings tab. - + Sono passati più di %2 days giorni dall'ultima volta che hai eseguito il controllo aggiornamenti delle carte. +Seleziona la modalità di esecuzione dell'aggiornamento. +Potrai comunque cambiarla in seguito dalle impostazioni, nella scheda 'Generale'. Run in foreground - + Esegui in primo piano Run in background - + Esegui in background Run in background and always from now on - + Esegui in background da ora in poi Don't prompt again and don't run - + Non eseguire e non chiedere più Don't run this time - + Non eseguire stavolta @@ -3093,7 +3096,7 @@ Dovrai scaricare la nuova versione manualmente. Copy to clipboard - + Copia negli appunti @@ -3106,12 +3109,12 @@ Dovrai scaricare la nuova versione manualmente. In %1 decks - + In %1 mazzi %1% of %2 decks - + %1% di %2 mazzi @@ -3119,47 +3122,47 @@ Dovrai scaricare la nuova versione manualmente. Card Hoarder - + Card Hoarder Card Kingdom - + Card Kingdom Card Market - + Card Market Face 2-Face - + Face 2-Face Mana Pool - + Mana Pool MTG Stocks - + MTG Stocks Scg - + Scg Tcgl - + Tcgl Tcgplayer - + Tcgplayer @@ -3167,7 +3170,7 @@ Dovrai scaricare la nuova versione manualmente. %1% Synergy - + Sinergia %1% @@ -3175,22 +3178,22 @@ Dovrai scaricare la nuova versione manualmente. Combos - + Combo Average Deck - + Mazzo medio Game Changers - + Game Changer Budget - + Budget @@ -3206,7 +3209,7 @@ Dovrai scaricare la nuova versione manualmente. Type your filter here - Scrivi qui il tuo filtro + Scrivi il filtro qui @@ -3214,22 +3217,22 @@ Dovrai scaricare la nuova versione manualmente. Confirm Delete - + Conferma eliminazione Are you sure you want to delete the filter '%1'? - + Vuoi davvero eliminare il filtro '%1'? Delete Failed - + Eliminazione non riuscita Failed to delete filter '%1'. - + Impossibile eliminare il filtro '%1'. @@ -3510,7 +3513,7 @@ Dovrai scaricare la nuova versione manualmente. Filters directory: - + Cartella filtri: @@ -3550,32 +3553,32 @@ Dovrai scaricare la nuova versione manualmente. Check for card database updates on startup - + Controlla gli aggiornamenti delle carte all'avvio Don't check - + Non controllare Prompt for update - + Chiedi se aggiornare Always update in the background - + Aggiorna sempre in background Check for card database updates every - + Controlla gli aggiornamenti delle carte ogni days - + giorni @@ -3595,7 +3598,7 @@ Dovrai scaricare la nuova versione manualmente. Last update check on %1 (%2 days ago) - + Ultimo controllo %1 (%2 giorni fa) @@ -4012,7 +4015,7 @@ Solitamente questo significa che stai usando una vecchia versione del programma, The connection to the server has been lost. - + La connessione al server è stata interrotta. @@ -4193,12 +4196,12 @@ La tua versione è la %1, la versione online è la %2. Check for Card Updates (Automatic) - + Controlla aggiornamenti carte in background Show Status Bar - + Mostra barra di stato @@ -4326,7 +4329,7 @@ Scopri metodi alternativi per visualizzare i set o disabilitare set ed effetti n Card database update running. - + Aggiornamento delle carte in corso. @@ -4436,7 +4439,7 @@ Il database delle carte verrà ricaricato. Mana Base - + Base di mana @@ -4445,7 +4448,7 @@ Il database delle carte verrà ricaricato. Mana Curve - + Curva di mana @@ -4454,7 +4457,7 @@ Il database delle carte verrà ricaricato. Mana Devotion - + Simboli di mana @@ -4542,7 +4545,7 @@ Il database delle carte verrà ricaricato. from custom zone '%1' - + dalla zona personalizzata '%1' @@ -4632,7 +4635,7 @@ Il database delle carte verrà ricaricato. %1 creates a face down token. - + %1 crea una pedina a faccia in giù. @@ -4722,7 +4725,7 @@ Il database delle carte verrà ricaricato. %1 moves %2%3 to custom zone '%4'. - + %1 mette %2 nella zona personalizzata '%4'%3. @@ -4941,12 +4944,12 @@ Il database delle carte verrà ricaricato. %1 places %2 "%3" counter(s) on %4 (now %5). - + %1 mette %2 segnalino "%3" su %4 (totale %5).%1 mette %2 segnalini "%3" su %4 (totale %5).%1 mette %2 segnalino(i) "%3" su %4 (totale %5). %1 removes %2 "%3" counter(s) from %4 (now %5). - + %1 toglie %2 segnalino "%3" su %4 (totale %5).%1 toglie %2 segnalini "%3" su %4 (totale %5).%1 toglie %2 segnalino(i) "%3" su %4 (totale %5). @@ -5200,7 +5203,7 @@ Il database delle carte verrà ricaricato. Layout - Layout + Disposizione @@ -5591,13 +5594,13 @@ Il database delle carte verrà ricaricato. C&ustom Zones - + &Zone personalizzate View custom zone '%1' - + Visualizza la zona personalizzata '%1' @@ -5627,7 +5630,7 @@ Il database delle carte verrà ricaricato. Ca&rd counters - + Segnalini delle ca&rte @@ -6069,7 +6072,7 @@ Il database delle carte verrà ricaricato. Bulk Selection - + Selezione massiva @@ -6179,12 +6182,12 @@ Il database delle carte verrà ricaricato. Overwrite Existing File? - + Sovrascrivere il file esistente? A .cod version of this deck already exists. Overwrite it? - + Una versione .cod di questo mazzo esiste già. Sovrascriverla? @@ -6814,7 +6817,7 @@ Controlla le impostazioni! Reset layout - Resetta disposizione + Reimposta disposizione @@ -6827,45 +6830,45 @@ Controlla le impostazioni! Visual Deck: %1 - + Mazzo visuale: %1 &Visual Deck Editor - + Editor &visuale Card Info - + Info carta Deck - + Mazzo Filters - + Filtri &View - + &Visualizza Deck Analytics - + Analisi mazzo Printing - + Stampa @@ -6874,7 +6877,7 @@ Controlla le impostazioni! Visible - + Mostra @@ -6883,12 +6886,12 @@ Controlla le impostazioni! Floating - + Separata Reset layout - + Reimposta disposizione @@ -6896,22 +6899,22 @@ Controlla le impostazioni! Visual Deck View - + Galleria mazzo Visual Database Display - + Galleria database Deck Analytics - + Analisi mazzo Sample Hand - + Mano di esempio @@ -7084,32 +7087,32 @@ Please enter a name: &Cards - + &Carte Top Commanders - + Comandanti più popolari Tags - + Etichette Search for a card ... - + Cerca carta... Search - + Cerca EDHREC: - + EDHREC: @@ -7255,7 +7258,7 @@ Please enter a name: Reset layout - Resetta disposizione + Reimposta disposizione @@ -7725,12 +7728,12 @@ Più informazioni inserisci, più specifici saranno i risultati. Visual Deck Editor - + Editor visuale EDHRec - + EDHRec @@ -7740,7 +7743,7 @@ Più informazioni inserisci, più specifici saranno i risultati. Visual Database Display - + Galleria database @@ -7853,7 +7856,7 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u Visual Database Display - + Galleria database @@ -8327,7 +8330,7 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u Auto focus search bar when card view window is opened - + Passa alla barra di ricerca quando si apre la finestra di visualizzazione carta @@ -8387,42 +8390,42 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u Use selection animation for Visual Deck Storage - + Mostra animazione al passaggio del mouse nella galleria mazzi When adding a tag in the visual deck storage to a .txt deck: - + Quando aggiungi un'etichetta ad un mazzo in formato .txt nella Galleria mazzi: do nothing - + non fare nulla ask to convert to .cod - + chiedi se convertire in file .cod always convert to .cod - + converti sempre in file .cod Default deck editor type - + Editor dei mazzi predefinito Classic Deck Editor - + Editor classico Visual Deck Editor - + Editor visuale @@ -8463,22 +8466,22 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u Mode: Exact Match - + Modalità: Corrispondenza esatta Mode: Includes - + Modalità: Include Mode: Include/Exclude - + Modalità: Include/Esclude Filter mode (AND/OR/NOT conjunctions of filters) - + Modalità di filtraggio (utilizzabile con connettivi logici AND/OR/NOT) @@ -8486,17 +8489,17 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u Save Filter - + Salva filtro Save all currently applied filters to a file - + Salva su file i filtri correnti Enter filename... - + Inserisci il nome del file... @@ -8504,22 +8507,22 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u Do not display card main-types with less than this amount of cards in the database - + Non mostrare i tipi di carta che hanno meno occorrenze nel database di questo numero Filter mode (AND/OR/NOT conjunctions of filters) - + Modalità di filtraggio (utilizzabile con connettivi logici AND/OR/NOT) Mode: Exact Match - + Modalità: Corrispondenza esatta Mode: Includes - + Modalità: Include @@ -8527,27 +8530,27 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u Filter by name... - + Filtra per nome... Load from Deck - + Carica da mazzo Apply all card names in currently loaded deck as exact match name filters - + Usa i nomi delle carte nel mazzo caricato come insieme di filtri a corrispondenza esatta Load from Clipboard - + Carica dagli appunti Apply all card names in clipboard as exact match name filters - + Usa i nomi delle carte negli appunti come insieme di filtri a corrispondenza esatta @@ -8555,7 +8558,7 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u Filter to most recent sets - + Filtra per i set più recenti @@ -8563,19 +8566,19 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u Search sets... - + Ricerca set... Mode: Exact Match - + Modalità: Corrispondenza esatta Mode: Includes - + Modalità: Include @@ -8583,27 +8586,27 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u Search subtypes... - + Ricerca sottotipi... Do not display card sub-types with less than this amount of cards in the database - + Non mostrare i sottotipi che hanno meno occorrenze nel database di questo numero Filter mode (AND/OR/NOT conjunctions of filters) - + Modalità di filtraggio (utilizzabile con connettivi logici AND/OR/NOT) Mode: Exact Match - + Modalità: Corrispondenza esatta Mode: Includes - + Modalità: Include @@ -8611,32 +8614,32 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u Search by card name (or search expressions) - + Cerca per nome della carta (o espressioni di ricerca) Clear all filters - + Elimina tutti i filtri Save and load filters - + Salva e carica filtri Filter by exact card name - + Filtra per nome della carta esatto Filter by card sub-type - + Filtra per sottotipo Filter by set - + Filtra per set @@ -8644,12 +8647,12 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u Draw a new sample hand - + Pesca una nuova mano Sample hand size - + Dimensione della mano @@ -8657,38 +8660,38 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u Click and drag to change the sort order within the groups - + Clicca e trascina per modificare i criteri di ordinamento all'interno dei gruppi Quick search and add card - + Cerca e aggiungi carta al mazzo Search for closest match in the database (with auto-suggestions) and add preferred printing to the deck on pressing enter - + Cerca per la corrispondenza più prossima nel database (con auto-completamento) e premendo Invio, aggiungi la stampa preferita della carta al mazzo. Configure how cards are sorted within their groups - + Configura l'ordinamento delle carte all'interno dei gruppi Overlap Layout - + Disposizione sovrapposta Change how cards are displayed within zones (i.e. overlapped or fully visible.) - + Imposta come le carte vengono mostrate all'interno delle relative sezioni (sovrapposte o affiancate) Flat Layout - + Disposizione affiancata @@ -8704,47 +8707,47 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u Show Folders - + Mostra cartelle Show Tag Filter - + Mostra filtro etichette Show Tags On Deck Previews - + Mostra etichette sulle anteprime dei mazzi Show Banner Card Selection Option - + Mostra opzione per selezione copertina Draw unused Color Identities - + Mostra identità di colore inutilizzate Unused Color Identities Opacity - + Opacità identità di colore inutilizzate Deck tooltip: - + Suggerimento mazzo: None - + Nessuno Filepath - + Percorso file @@ -8752,7 +8755,7 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u Search by filename (or search expression) - + Cerca per nome del file (o espressioni di ricerca) @@ -8788,12 +8791,12 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u Refresh loaded files - + Aggiorna i file caricati Visual Deck Storage Settings - + Impostazioni galleria mazzi @@ -8926,7 +8929,7 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u Include cards rebalanced for Alchemy [requires restart] - + Includi carte ribilanciate per Alchemy [richiede riavvio] @@ -8979,7 +8982,7 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u Search by card name (or search expressions) - + Cerca per nome della carta (o espressioni di ricerca) @@ -9313,7 +9316,7 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u Reset Layout - Reimposta Layout + Reimposta Disposizione @@ -9403,107 +9406,107 @@ Se pregato di evitare di continuare questa attività o potrebbero venire presi u Show Status Bar - + Mostra barra di stato Unload Deck - + Deseleziona mazzo Force Start - + Forza avvio Add Card Counter (F) - + Aggiungi Segnalino (F) Remove Card Counter (F) - + Togli Segnalino (F) Set Card Counters (F)... - + Imposta Segnalini (F)... Add Card Counter (E) - + Aggiungi Segnalino (E) Remove Card Counter (E) - + Togli Segnalino (E) Set Card Counters (E)... - + Imposta Segnalini (E)... Add Card Counter(D) - + Aggiungi Segnalino(D) Remove Card Counter (D) - + Togli Segnalino (D) Set Card Counters (D)... - + Imposta Segnalini (D)... Add Card Counter (C) - + Aggiungi Segnalino (C) Remove Card Counter (C) - + Togli Segnalino (C) Set Card Counters (C)... - + Imposta Segnalini (C)... Add Card Counter (B) - + Aggiungi Segnalino (B) Remove Card Counter (B) - + Togli Segnalino (B) Set Card Counters (B)... - + Imposta Segnalini (B)... Add Card Counter (A) - + Aggiungi Segnalino (A) Remove Card Counter (A) - + Togli Segnalino (A) Set Card Counters (A)... - + Imposta Segnalini (A)... diff --git a/common/pb/context_deck_select.proto b/common/pb/context_deck_select.proto index dbd4ce16e..44abd8583 100644 --- a/common/pb/context_deck_select.proto +++ b/common/pb/context_deck_select.proto @@ -7,4 +7,5 @@ message Context_DeckSelect { } optional string deck_hash = 1; optional int32 sideboard_size = 2 [default = -1]; + optional string deck_list = 3; } diff --git a/common/pb/room_commands.proto b/common/pb/room_commands.proto index fce90e32e..5e8c158ff 100644 --- a/common/pb/room_commands.proto +++ b/common/pb/room_commands.proto @@ -39,6 +39,7 @@ message Command_CreateGame { optional bool join_as_judge = 11; optional bool join_as_spectator = 12; optional uint32 starting_life_total = 13; + optional bool share_decklists_on_load = 14; } message Command_JoinGame { diff --git a/common/pb/serverinfo_game.proto b/common/pb/serverinfo_game.proto index 8ba29eeeb..68739abff 100644 --- a/common/pb/serverinfo_game.proto +++ b/common/pb/serverinfo_game.proto @@ -16,6 +16,7 @@ message ServerInfo_Game { optional bool spectators_need_password = 12; optional bool spectators_can_chat = 13; optional bool spectators_omniscient = 14; + optional bool share_decklists_on_load = 15; optional uint32 player_count = 30; optional uint32 spectators_count = 31; optional bool started = 50; diff --git a/common/server_game.cpp b/common/server_game.cpp index f27772bbb..95d97f1da 100644 --- a/common/server_game.cpp +++ b/common/server_game.cpp @@ -21,6 +21,7 @@ #include "decklist.h" #include "pb/context_connection_state_changed.pb.h" +#include "pb/context_deck_select.pb.h" #include "pb/context_ping_changed.pb.h" #include "pb/event_delete_arrow.pb.h" #include "pb/event_game_closed.pb.h" @@ -62,15 +63,16 @@ Server_Game::Server_Game(const ServerInfo_User &_creatorInfo, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, int _startingLifeTotal, + bool _shareDecklistsOnLoad, Server_Room *_room) : QObject(), room(_room), nextPlayerId(0), hostId(0), creatorInfo(new ServerInfo_User(_creatorInfo)), gameStarted(false), gameClosed(false), gameId(_gameId), password(_password), maxPlayers(_maxPlayers), gameTypes(_gameTypes), activePlayer(-1), activePhase(-1), onlyBuddies(_onlyBuddies), onlyRegistered(_onlyRegistered), spectatorsAllowed(_spectatorsAllowed), spectatorsNeedPassword(_spectatorsNeedPassword), spectatorsCanTalk(_spectatorsCanTalk), - spectatorsSeeEverything(_spectatorsSeeEverything), startingLifeTotal(_startingLifeTotal), inactivityCounter(0), - startTimeOfThisGame(0), secondsElapsed(0), firstGameStarted(false), turnOrderReversed(false), - startTime(QDateTime::currentDateTime()), pingClock(nullptr), + spectatorsSeeEverything(_spectatorsSeeEverything), startingLifeTotal(_startingLifeTotal), + shareDecklistsOnLoad(_shareDecklistsOnLoad), inactivityCounter(0), startTimeOfThisGame(0), secondsElapsed(0), + firstGameStarted(false), turnOrderReversed(false), startTime(QDateTime::currentDateTime()), pingClock(nullptr), #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) gameMutex() #else @@ -800,6 +802,7 @@ void Server_Game::getInfo(ServerInfo_Game &result) const result.set_spectators_need_password(getSpectatorsNeedPassword()); result.set_spectators_can_chat(spectatorsCanTalk); result.set_spectators_omniscient(spectatorsSeeEverything); + result.set_share_decklists_on_load(shareDecklistsOnLoad); result.set_spectators_count(getSpectatorCount()); result.set_start_time(startTime.toSecsSinceEpoch()); } diff --git a/common/server_game.h b/common/server_game.h index 2f8c005b6..226a14149 100644 --- a/common/server_game.h +++ b/common/server_game.h @@ -67,6 +67,7 @@ private: bool spectatorsCanTalk; bool spectatorsSeeEverything; int startingLifeTotal; + bool shareDecklistsOnLoad; int inactivityCounter; int startTimeOfThisGame, secondsElapsed; bool firstGameStarted; @@ -106,7 +107,8 @@ public: bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, - int startingLifeTotal, + int _startingLifeTotal, + bool _shareDecklistsOnLoad, Server_Room *parent); ~Server_Game() override; Server_Room *getRoom() const @@ -168,6 +170,10 @@ public: { return startingLifeTotal; } + bool getShareDecklistsOnLoad() const + { + return shareDecklistsOnLoad; + } Response::ResponseCode checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions, bool asJudge); bool containsUser(const QString &userName) const; diff --git a/common/server_player.cpp b/common/server_player.cpp index 5f0667dee..67c5ef34c 100644 --- a/common/server_player.cpp +++ b/common/server_player.cpp @@ -836,6 +836,9 @@ Server_Player::cmdDeckSelect(const Command_DeckSelect &cmd, ResponseContainer &r Context_DeckSelect context; context.set_deck_hash(deck->getDeckHash().toStdString()); context.set_sideboard_size(deck->getSideboardSize()); + if (game->getShareDecklistsOnLoad()) { + context.set_deck_list(deck->writeToString_Native().toStdString()); + } ges.setGameEventContext(context); auto *re = new Response_DeckDownload; diff --git a/common/server_player.h b/common/server_player.h index b9d414482..45736957d 100644 --- a/common/server_player.h +++ b/common/server_player.h @@ -96,6 +96,10 @@ public: Server_AbstractUserInterface *_handler); ~Server_Player() override; void prepareDestroy(); + const DeckList *getDeckList() const + { + return deck; + } Server_AbstractUserInterface *getUserInterface() const { return userInterface; diff --git a/common/server_protocolhandler.cpp b/common/server_protocolhandler.cpp index 075b3901e..d69ff9ba0 100644 --- a/common/server_protocolhandler.cpp +++ b/common/server_protocolhandler.cpp @@ -818,6 +818,8 @@ Server_ProtocolHandler::cmdCreateGame(const Command_CreateGame &cmd, Server_Room QString description = nameFromStdString(cmd.description()); int startingLifeTotal = cmd.has_starting_life_total() ? cmd.starting_life_total() : 20; + bool shareDecklistsOnLoad = cmd.has_share_decklists_on_load() ? cmd.share_decklists_on_load() : false; + const int gameId = databaseInterface->getNextGameId(); if (gameId == -1) { return Response::RespInternalError; @@ -828,7 +830,7 @@ Server_ProtocolHandler::cmdCreateGame(const Command_CreateGame &cmd, Server_Room Server_Game *game = new Server_Game( copyUserInfo(false), gameId, description, QString::fromStdString(cmd.password()), cmd.max_players(), gameTypes, cmd.only_buddies(), onlyRegisteredUsers, cmd.spectators_allowed(), cmd.spectators_need_password(), - cmd.spectators_can_talk(), cmd.spectators_see_everything(), startingLifeTotal, room); + cmd.spectators_can_talk(), cmd.spectators_see_everything(), startingLifeTotal, shareDecklistsOnLoad, room); game->addPlayer(this, rc, asSpectator, asJudge, false); room->addGame(game); diff --git a/dbconverter/src/mocks.cpp b/dbconverter/src/mocks.cpp index 738a17695..ade0922e4 100644 --- a/dbconverter/src/mocks.cpp +++ b/dbconverter/src/mocks.cpp @@ -402,6 +402,9 @@ void SettingsCache::setCreateGameAsSpectator(const bool /* _createGameAsSpectato void SettingsCache::setDefaultStartingLifeTotal(const int /* _startingLifeTotal */) { } +void SettingsCache::setShareDecklistsOnLoad(const bool /* _shareDecklistsOnLoad */) +{ +} void SettingsCache::setRememberGameSettings(const bool /* _rememberGameSettings */) { } diff --git a/oracle/translations/oracle_fr.ts b/oracle/translations/oracle_fr.ts index 24362f733..b2beca4a4 100644 --- a/oracle/translations/oracle_fr.ts +++ b/oracle/translations/oracle_fr.ts @@ -63,7 +63,7 @@ Sets file (%1) Sets JSON file (%1) - + Choisir le fichier (%1) @@ -144,7 +144,7 @@ Failed to interpret downloaded data. - + Échec lors de l'interprétation des données téléchargées. @@ -303,7 +303,7 @@ A cockatrice database file of %1 MB has been downloaded. - + Un fichier de base de données Cockatrice de %1 MB a été téléchargé. @@ -368,7 +368,7 @@ The provided URL is not valid: - + L'URL fournie n'est pas valide : @@ -401,12 +401,12 @@ Failed to initialize or load zlib library. - + Impossible d'initialiser ou de charger la bibliothèque zlib. zlib library error. - + Erreur avec la bibliothèque zlib. @@ -416,7 +416,7 @@ Partially corrupted archive. Some files might be extracted. - + Archive partiellement corrompue. Certains fichiers ont pu être extraits. @@ -431,47 +431,47 @@ No archive has been created yet. - + Aucune archive n'a été créée pour l'instant. File or directory does not exist. - + Le fichier ou le dossier n'existe pas. File read error. - + Erreur lors de la lecture du fichier. File write error. - + Erreur lors de l'écriture du fichier. File seek error. - + Erreur lors de la recherche dans le fichier. Unable to create a directory. - + Impossible de créer un répertoire. Invalid device. - + Périphérique non valide. Invalid or incompatible zip archive. - + Archive zip non valide ou incompatible. Inconsistent headers. Archive might be corrupted. - + En-têtes inconsistants. L'archive peut être corrompue. @@ -484,17 +484,17 @@ ZIP operation completed successfully. - + Opération ZIP complétée avec succès. Failed to initialize or load zlib library. - + Impossible d'initialiser ou de charger la bibliothèque zlib. zlib library error. - + Erreur avec la bibliothèque zlib. @@ -504,32 +504,32 @@ No archive has been created yet. - + Aucune archive n'a été créée pour l'instant. File or directory does not exist. - + Le fichier ou le dossier n'existe pas. File read error. - + Erreur lors de la lecture du fichier. File write error. - + Erreur lors de l'écriture du fichier. File seek error. - + Erreur lors de la recherche dans le fichier. Unknown error. - + Erreur inconnue. @@ -550,7 +550,7 @@ Run in no-confirm background mode - + S'exécuter en mode tâche de fond sans demande de confirmation \ No newline at end of file diff --git a/oracle/translations/oracle_it.ts b/oracle/translations/oracle_it.ts index 8688f03e3..192e8cc0e 100644 --- a/oracle/translations/oracle_it.ts +++ b/oracle/translations/oracle_it.ts @@ -369,7 +369,7 @@ e pedine che verranno usate da Cockatrice. The provided URL is not valid: - + L'indirizzo fornito non è valido: @@ -551,7 +551,7 @@ e pedine che verranno usate da Cockatrice. Run in no-confirm background mode - + Esegui in background senza conferma \ No newline at end of file diff --git a/tests/carddatabase/mocks.cpp b/tests/carddatabase/mocks.cpp index 9d158217e..4c3a81322 100644 --- a/tests/carddatabase/mocks.cpp +++ b/tests/carddatabase/mocks.cpp @@ -406,6 +406,9 @@ void SettingsCache::setCreateGameAsSpectator(const bool /* _createGameAsSpectato void SettingsCache::setDefaultStartingLifeTotal(const int /* _startingLifeTotal */) { } +void SettingsCache::setShareDecklistsOnLoad(const bool /* _shareDecklistsOnLoad */) +{ +} void SettingsCache::setRememberGameSettings(const bool /* _rememberGameSettings */) { }