diff --git a/cockatrice/src/messagelogwidget.cpp b/cockatrice/src/messagelogwidget.cpp index 3fc76e21..22f4e8bd 100644 --- a/cockatrice/src/messagelogwidget.cpp +++ b/cockatrice/src/messagelogwidget.cpp @@ -152,6 +152,14 @@ void MessageLogWidget::logAlwaysRevealTopCard(Player *player, CardZone *zone, bo .arg(zone->getTranslatedName(true, CaseTopCardsOfZone))); } +void MessageLogWidget::logAlwaysLookAtTopCard(Player *player, CardZone *zone, bool reveal) +{ + appendHtmlServerMessage((reveal ? tr("%1 can now look at top card %2 at any time.") + : tr("%1 no longer can look at top card %2 at any time.")) + .arg(sanitizeHtml(player->getName())) + .arg(zone->getTranslatedName(true, CaseTopCardsOfZone))); +} + void MessageLogWidget::logAttachCard(Player *player, QString cardName, Player *targetPlayer, QString targetCardName) { appendHtmlServerMessage(tr("%1 attaches %2 to %3's %4.") @@ -823,6 +831,8 @@ void MessageLogWidget::connectToPlayer(Player *player) SLOT(logRevealCards(Player *, CardZone *, int, QString, Player *, bool, int))); connect(player, SIGNAL(logAlwaysRevealTopCard(Player *, CardZone *, bool)), this, SLOT(logAlwaysRevealTopCard(Player *, CardZone *, bool))); + connect(player, SIGNAL(logAlwaysLookAtTopCard(Player *, CardZone *, bool)), this, + SLOT(logAlwaysLookAtTopCard(Player *, CardZone *, bool))); } MessageLogWidget::MessageLogWidget(const TabSupervisor *_tabSupervisor, diff --git a/cockatrice/src/messagelogwidget.h b/cockatrice/src/messagelogwidget.h index 94878fd3..645c54f4 100644 --- a/cockatrice/src/messagelogwidget.h +++ b/cockatrice/src/messagelogwidget.h @@ -42,6 +42,7 @@ public slots: void containerProcessingDone(); void containerProcessingStarted(const GameEventContext &context); void logAlwaysRevealTopCard(Player *player, CardZone *zone, bool reveal); + void logAlwaysLookAtTopCard(Player *player, CardZone *zone, bool reveal); void logAttachCard(Player *player, QString cardName, Player *targetPlayer, QString targetCardName); void logConcede(Player *player); void logUnconcede(Player *player); diff --git a/cockatrice/src/player.cpp b/cockatrice/src/player.cpp index 87d36458..7c1eafe7 100644 --- a/cockatrice/src/player.cpp +++ b/cockatrice/src/player.cpp @@ -211,6 +211,9 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T aAlwaysRevealTopCard = new QAction(this); aAlwaysRevealTopCard->setCheckable(true); connect(aAlwaysRevealTopCard, SIGNAL(triggered()), this, SLOT(actAlwaysRevealTopCard())); + aAlwaysLookAtTopCard = new QAction(this); + aAlwaysLookAtTopCard->setCheckable(true); + connect(aAlwaysLookAtTopCard, SIGNAL(triggered()), this, SLOT(actAlwaysLookAtTopCard())); aOpenDeckInDeckEditor = new QAction(this); aOpenDeckInDeckEditor->setEnabled(false); connect(aOpenDeckInDeckEditor, SIGNAL(triggered()), this, SLOT(actOpenDeckInDeckEditor())); @@ -287,6 +290,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T playerLists.append(mRevealLibrary = libraryMenu->addMenu(QString())); playerLists.append(mRevealTopCard = libraryMenu->addMenu(QString())); libraryMenu->addAction(aAlwaysRevealTopCard); + libraryMenu->addAction(aAlwaysLookAtTopCard); libraryMenu->addSeparator(); libraryMenu->addAction(aMoveTopToPlay); libraryMenu->addAction(aMoveTopToPlayFaceDown); @@ -697,6 +701,7 @@ void Player::retranslateUi() mRevealLibrary->setTitle(tr("Reveal &library to...")); mRevealTopCard->setTitle(tr("Reveal t&op cards to...")); aAlwaysRevealTopCard->setText(tr("&Always reveal top card")); + aAlwaysLookAtTopCard->setText(tr("Al&ways look at top card")); aOpenDeckInDeckEditor->setText(tr("O&pen deck in deck editor")); aViewSideboard->setText(tr("&View sideboard")); aDrawCard->setText(tr("&Draw card")); @@ -874,6 +879,7 @@ void Player::setShortcutsActive() 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")); @@ -905,6 +911,7 @@ void Player::setShortcutsInactive() aCreateToken->setShortcut(QKeySequence()); aCreateAnotherToken->setShortcut(QKeySequence()); aAlwaysRevealTopCard->setShortcut(QKeySequence()); + aAlwaysLookAtTopCard->setShortcut(QKeySequence()); aMoveTopToPlay->setShortcut(QKeySequence()); aMoveTopToPlayFaceDown->setShortcut(QKeySequence()); aMoveTopCardToGraveyard->setShortcut(QKeySequence()); @@ -991,6 +998,15 @@ void Player::actAlwaysRevealTopCard() sendGameCommand(cmd); } +void Player::actAlwaysLookAtTopCard() +{ + Command_ChangeZoneProperties cmd; + cmd.set_zone_name("deck"); + cmd.set_always_look_at_top_card(aAlwaysLookAtTopCard->isChecked()); + + sendGameCommand(cmd); +} + void Player::actOpenDeckInDeckEditor() { emit openDeckEditor(deck); @@ -1976,6 +1992,10 @@ void Player::eventChangeZoneProperties(const Event_ChangeZoneProperties &event) zone->setAlwaysRevealTopCard(event.always_reveal_top_card()); emit logAlwaysRevealTopCard(this, zone, event.always_reveal_top_card()); } + if (event.has_always_look_at_top_card()) { + zone->setAlwaysRevealTopCard(event.always_look_at_top_card()); + emit logAlwaysLookAtTopCard(this, zone, event.always_look_at_top_card()); + } } void Player::processGameEvent(GameEvent::GameEventType type, const GameEvent &event, const GameEventContext &context) @@ -3271,6 +3291,7 @@ void Player::setGameStarted() { if (local) { aAlwaysRevealTopCard->setChecked(false); + aAlwaysLookAtTopCard->setChecked(false); } setConceded(false); } diff --git a/cockatrice/src/player.h b/cockatrice/src/player.h index b86287bb..9b26065d 100644 --- a/cockatrice/src/player.h +++ b/cockatrice/src/player.h @@ -144,6 +144,7 @@ signals: bool faceDown, int amount); void logAlwaysRevealTopCard(Player *player, CardZone *zone, bool reveal); + void logAlwaysLookAtTopCard(Player *player, CardZone *zone, bool reveal); void sizeChanged(); void playerCountChanged(); @@ -170,6 +171,7 @@ public slots: void actViewHand(); void actViewTopCards(); void actAlwaysRevealTopCard(); + void actAlwaysLookAtTopCard(); void actViewGraveyard(); void actRevealRandomGraveyardCard(); void actViewRfg(); @@ -221,9 +223,9 @@ private: QAction *aMoveHandToTopLibrary, *aMoveHandToBottomLibrary, *aMoveHandToGrave, *aMoveHandToRfg, *aMoveGraveToTopLibrary, *aMoveGraveToBottomLibrary, *aMoveGraveToHand, *aMoveGraveToRfg, *aMoveRfgToTopLibrary, *aMoveRfgToBottomLibrary, *aMoveRfgToHand, *aMoveRfgToGrave, *aViewHand, *aViewLibrary, *aViewTopCards, - *aAlwaysRevealTopCard, *aOpenDeckInDeckEditor, *aMoveTopCardToGraveyard, *aMoveTopCardToExile, - *aMoveTopCardsToGraveyard, *aMoveTopCardsToExile, *aMoveTopCardToBottom, *aViewGraveyard, *aViewRfg, - *aViewSideboard, *aDrawCard, *aDrawCards, *aUndoDraw, *aMulligan, *aShuffle, *aMoveTopToPlay, + *aAlwaysRevealTopCard, *aAlwaysLookAtTopCard, *aOpenDeckInDeckEditor, *aMoveTopCardToGraveyard, + *aMoveTopCardToExile, *aMoveTopCardsToGraveyard, *aMoveTopCardsToExile, *aMoveTopCardToBottom, *aViewGraveyard, + *aViewRfg, *aViewSideboard, *aDrawCard, *aDrawCards, *aUndoDraw, *aMulligan, *aShuffle, *aMoveTopToPlay, *aMoveTopToPlayFaceDown, *aUntapAll, *aRollDie, *aCreateToken, *aCreateAnotherToken, *aCardMenu, *aMoveBottomCardToGrave; diff --git a/cockatrice/src/shortcutssettings.h b/cockatrice/src/shortcutssettings.h index 1c1989ee..0b400d0b 100644 --- a/cockatrice/src/shortcutssettings.h +++ b/cockatrice/src/shortcutssettings.h @@ -537,6 +537,9 @@ private: {"Player/aAlwaysRevealTopCard", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Always Reveal Top Card"), parseSequenceString("Ctrl+N"), ShortcutGroup::Drawing)}, + {"Player/aAlwaysLookAtTopCard", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Always Look At Top Card"), + parseSequenceString("Ctrl+A"), + ShortcutGroup::Drawing)}, {"Player/aRotateViewCW", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Rotate View Clockwise"), parseSequenceString(""), ShortcutGroup::Gameplay)}, diff --git a/common/pb/command_change_zone_properties.proto b/common/pb/command_change_zone_properties.proto index 99659dda..027cc572 100644 --- a/common/pb/command_change_zone_properties.proto +++ b/common/pb/command_change_zone_properties.proto @@ -7,5 +7,8 @@ message Command_ChangeZoneProperties { } optional string zone_name = 1; + // Reveal top card to all players. optional bool always_reveal_top_card = 10; + // reveal top card to the owner. + optional bool always_look_at_top_card = 11; } diff --git a/common/pb/event_change_zone_properties.proto b/common/pb/event_change_zone_properties.proto index 5dd56c7e..35b077b3 100644 --- a/common/pb/event_change_zone_properties.proto +++ b/common/pb/event_change_zone_properties.proto @@ -7,5 +7,8 @@ message Event_ChangeZoneProperties { } optional string zone_name = 1; + // Reveal top card to all players. optional bool always_reveal_top_card = 10; + // reveal top card to the owner. + optional bool always_look_at_top_card = 11; } diff --git a/common/pb/serverinfo_zone.proto b/common/pb/serverinfo_zone.proto index 0f0e53cc..0efa2d9b 100644 --- a/common/pb/serverinfo_zone.proto +++ b/common/pb/serverinfo_zone.proto @@ -21,5 +21,8 @@ message ServerInfo_Zone { optional bool with_coords = 3; optional sint32 card_count = 4; repeated ServerInfo_Card card_list = 5; + // Reveal top card to all players. optional bool always_reveal_top_card = 10; + // reveal top card to the owner. + optional bool always_look_at_top_card = 11; } diff --git a/common/server_cardzone.cpp b/common/server_cardzone.cpp index 6d519a59..a35bd218 100644 --- a/common/server_cardzone.cpp +++ b/common/server_cardzone.cpp @@ -32,7 +32,7 @@ Server_CardZone::Server_CardZone(Server_Player *_player, bool _has_coords, ServerInfo_Zone::ZoneType _type) : player(_player), name(_name), has_coords(_has_coords), type(_type), cardsBeingLookedAt(0), - alwaysRevealTopCard(false) + alwaysRevealTopCard(false), alwaysLookAtTopCard(false) { } @@ -305,6 +305,7 @@ void Server_CardZone::getInfo(ServerInfo_Zone *info, Server_Player *playerWhosAs info->set_with_coords(has_coords); info->set_card_count(cards.size()); info->set_always_reveal_top_card(alwaysRevealTopCard); + info->set_always_look_at_top_card(alwaysLookAtTopCard); if ((((playerWhosAsking == player) || omniscient) && (type != ServerInfo_Zone::HiddenZone)) || ((playerWhosAsking != player) && (type == ServerInfo_Zone::PublicZone))) { QListIterator cardIterator(cards); diff --git a/common/server_cardzone.h b/common/server_cardzone.h index b9fa8ba9..536ca58a 100644 --- a/common/server_cardzone.h +++ b/common/server_cardzone.h @@ -42,6 +42,7 @@ private: int cardsBeingLookedAt; QSet playersWithWritePermission; bool alwaysRevealTopCard; + bool alwaysLookAtTopCard; QList cards; QMap> coordinateMap; // y -> (x -> card) QMap> freePilesMap; // y -> (cardName -> x) @@ -108,6 +109,14 @@ public: { alwaysRevealTopCard = _alwaysRevealTopCard; } + bool getAlwaysLookAtTopCard() const + { + return alwaysLookAtTopCard; + } + void setAlwaysLookAtTopCard(bool _alwaysLookAtTopCard) + { + alwaysLookAtTopCard = _alwaysLookAtTopCard; + } }; #endif diff --git a/common/server_player.cpp b/common/server_player.cpp index 3d184e9a..78667866 100644 --- a/common/server_player.cpp +++ b/common/server_player.cpp @@ -318,18 +318,41 @@ Response::ResponseCode Server_Player::drawCards(GameEventStorage &ges, int numbe ges.enqueueGameEvent(eventPrivate, playerId, GameEventStorageItem::SendToPrivate, playerId); ges.enqueueGameEvent(eventOthers, playerId, GameEventStorageItem::SendToOthers); - if (deckZone->getAlwaysRevealTopCard() && !deckZone->getCards().isEmpty()) { - Event_RevealCards revealEvent; - revealEvent.set_zone_name(deckZone->getName().toStdString()); - revealEvent.set_card_id(0); - deckZone->getCards().first()->getInfo(revealEvent.add_cards()); - - ges.enqueueGameEvent(revealEvent, playerId); - } + revealTopCardIfNeeded(deckZone, ges); return Response::RespOk; } +void Server_Player::revealTopCardIfNeeded(Server_CardZone *zone, GameEventStorage &ges) +{ + if (zone->getCards().isEmpty()) { + return; + } + if (zone->getAlwaysRevealTopCard()) { + Event_RevealCards revealEvent; + revealEvent.set_zone_name(zone->getName().toStdString()); + revealEvent.set_card_id(0); + zone->getCards().first()->getInfo(revealEvent.add_cards()); + + ges.enqueueGameEvent(revealEvent, playerId); + return; + } + if (zone->getAlwaysLookAtTopCard()) { + Event_DumpZone dumpEvent; + dumpEvent.set_zone_owner_id(playerId); + dumpEvent.set_zone_name(zone->getName().toStdString()); + dumpEvent.set_number_cards(1); + ges.enqueueGameEvent(dumpEvent, playerId, GameEventStorageItem::SendToOthers); + + Event_RevealCards revealEvent; + revealEvent.set_zone_name(zone->getName().toStdString()); + revealEvent.set_number_of_cards(1); + revealEvent.set_card_id(0); + zone->getCards().first()->getInfo(revealEvent.add_cards()); + ges.enqueueGameEvent(revealEvent, playerId, GameEventStorageItem::SendToPrivate, playerId); + } +} + class Server_Player::MoveCardCompareFunctor { private: @@ -594,21 +617,11 @@ Response::ResponseCode Server_Player::moveCard(GameEventStorage &ges, setCardAttrHelper(ges, targetzone->getPlayer()->getPlayerId(), targetzone->getName(), card->getId(), AttrPT, ptString); } - if (startzone->getAlwaysRevealTopCard() && !startzone->getCards().isEmpty() && (originalPosition == 0)) { - Event_RevealCards revealEvent; - revealEvent.set_zone_name(startzone->getName().toStdString()); - revealEvent.set_card_id(0); - startzone->getCards().first()->getInfo(revealEvent.add_cards()); - - ges.enqueueGameEvent(revealEvent, playerId); + if (originalPosition == 0) { + revealTopCardIfNeeded(startzone, ges); } - if (targetzone->getAlwaysRevealTopCard() && !targetzone->getCards().isEmpty() && (newX == 0)) { - Event_RevealCards revealEvent; - revealEvent.set_zone_name(targetzone->getName().toStdString()); - revealEvent.set_card_id(0); - targetzone->getCards().first()->getInfo(revealEvent.add_cards()); - - ges.enqueueGameEvent(revealEvent, playerId); + if (newX == 0) { + revealTopCardIfNeeded(targetzone, ges); } } } @@ -977,15 +990,7 @@ Server_Player::cmdShuffle(const Command_Shuffle &cmd, ResponseContainer & /*rc*/ event.set_start(cmd.start()); event.set_end(cmd.end()); ges.enqueueGameEvent(event, playerId); - - if (zone->getAlwaysRevealTopCard() && !zone->getCards().isEmpty()) { - Event_RevealCards revealEvent; - revealEvent.set_zone_name(zone->getName().toStdString()); - revealEvent.set_card_id(0); - zone->getCards().first()->getInfo(revealEvent.add_cards()); - - ges.enqueueGameEvent(revealEvent, playerId); - } + revealTopCardIfNeeded(zone, ges); return Response::RespOk; } @@ -1980,27 +1985,31 @@ Response::ResponseCode Server_Player::cmdChangeZoneProperties(const Command_Chan Event_ChangeZoneProperties event; event.set_zone_name(cmd.zone_name()); - if (cmd.has_always_reveal_top_card()) { - if (zone->getAlwaysRevealTopCard() == cmd.always_reveal_top_card()) { - return Response::RespContextError; - } - zone->setAlwaysRevealTopCard(cmd.always_reveal_top_card()); - event.set_always_reveal_top_card(cmd.always_reveal_top_card()); - - ges.enqueueGameEvent(event, playerId); - - if (!zone->getCards().isEmpty() && cmd.always_reveal_top_card()) { - Event_RevealCards revealEvent; - revealEvent.set_zone_name(zone->getName().toStdString()); - revealEvent.set_card_id(0); - zone->getCards().first()->getInfo(revealEvent.add_cards()); - - ges.enqueueGameEvent(revealEvent, playerId); - } - return Response::RespOk; - } else { + // Neither value set -> error. + if (!cmd.has_always_look_at_top_card() && !cmd.has_always_reveal_top_card()) { return Response::RespContextError; } + + // Neither value changed -> error. + bool alwaysRevealChanged = + cmd.has_always_reveal_top_card() && zone->getAlwaysRevealTopCard() != cmd.always_reveal_top_card(); + bool alwaysLookAtTopChanged = + cmd.has_always_look_at_top_card() && zone->getAlwaysLookAtTopCard() != cmd.always_look_at_top_card(); + if (!alwaysRevealChanged && !alwaysLookAtTopChanged) { + return Response::RespContextError; + } + + if (cmd.has_always_reveal_top_card()) { + zone->setAlwaysRevealTopCard(cmd.always_reveal_top_card()); + event.set_always_reveal_top_card(cmd.always_reveal_top_card()); + } + if (cmd.has_always_look_at_top_card()) { + zone->setAlwaysLookAtTopCard(cmd.always_look_at_top_card()); + event.set_always_look_at_top_card(cmd.always_look_at_top_card()); + } + ges.enqueueGameEvent(event, playerId); + revealTopCardIfNeeded(zone, ges); + return Response::RespOk; } Response::ResponseCode diff --git a/common/server_player.h b/common/server_player.h index a7f3eaeb..69e885aa 100644 --- a/common/server_player.h +++ b/common/server_player.h @@ -84,6 +84,7 @@ private: bool readyStart; bool conceded; bool sideboardLocked; + void revealTopCardIfNeeded(Server_CardZone *zone, GameEventStorage &ges); public: mutable QMutex playerMutex;