From 7c20e9ab349b0e65b57d3e9dfd158b25fb52f94f Mon Sep 17 00:00:00 2001 From: ebbit1q Date: Sun, 6 Aug 2023 23:53:07 +0200 Subject: [PATCH] add move cards from top of library until dialog (#4648) a bit of a hack, the client will use the play top card action and then compare it with the propmpted expression, as if you were cascading normally but really fast the new keybind for this is ctrl shift y I have ratelimited the action to 10 cards a second --- cockatrice/src/filter_string.cpp | 9 ++++- cockatrice/src/filter_string.h | 1 + cockatrice/src/player.cpp | 56 ++++++++++++++++++++++++++++-- cockatrice/src/player.h | 19 ++++++---- cockatrice/src/shortcutssettings.h | 3 ++ 5 files changed, 79 insertions(+), 9 deletions(-) diff --git a/cockatrice/src/filter_string.cpp b/cockatrice/src/filter_string.cpp index e412ae5a3..e45108cfa 100644 --- a/cockatrice/src/filter_string.cpp +++ b/cockatrice/src/filter_string.cpp @@ -3,6 +3,7 @@ #include "../../common/lib/peglib.h" #include +#include #include #include @@ -334,6 +335,12 @@ static void setupParserRules() }; } +FilterString::FilterString() +{ + result = [](CardData) -> bool { return false; }; + _error = "Not initialized"; +} + FilterString::FilterString(const QString &expr) { QByteArray ba = expr.simplified().toUtf8(); @@ -352,7 +359,7 @@ FilterString::FilterString(const QString &expr) }; if (!search.parse(ba.data(), result)) { - std::cout << "Error!" << _error.toStdString() << std::endl; + qDebug() << "Filter string error" << _error; result = [](CardData) -> bool { return false; }; } } diff --git a/cockatrice/src/filter_string.h b/cockatrice/src/filter_string.h index 690ff2d75..2a29ed2a4 100644 --- a/cockatrice/src/filter_string.h +++ b/cockatrice/src/filter_string.h @@ -24,6 +24,7 @@ typedef AstBase Ast; class FilterString { public: + FilterString(); explicit FilterString(const QString &exp); bool check(const CardData &card) { diff --git a/cockatrice/src/player.cpp b/cockatrice/src/player.cpp index cd64dadff..05918c307 100644 --- a/cockatrice/src/player.cpp +++ b/cockatrice/src/player.cpp @@ -66,10 +66,12 @@ #include #include +#include #include #include #include #include +#include PlayerArea::PlayerArea(QGraphicsItem *parentItem) : QObject(), QGraphicsItem(parentItem) { @@ -253,6 +255,8 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T connect(aMoveTopCardsToGraveyard, SIGNAL(triggered()), this, SLOT(actMoveTopCardsToGrave())); aMoveTopCardsToExile = new QAction(this); connect(aMoveTopCardsToExile, SIGNAL(triggered()), this, SLOT(actMoveTopCardsToExile())); + aMoveTopCardsUntil = new QAction(this); + connect(aMoveTopCardsUntil, SIGNAL(triggered()), this, SLOT(actMoveTopCardsUntil())); aMoveTopCardToBottom = new QAction(this); connect(aMoveTopCardToBottom, SIGNAL(triggered()), this, SLOT(actMoveTopCardToBottom())); @@ -325,6 +329,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T topLibraryMenu->addAction(aMoveTopCardsToGraveyard); topLibraryMenu->addAction(aMoveTopCardToExile); topLibraryMenu->addAction(aMoveTopCardsToExile); + topLibraryMenu->addAction(aMoveTopCardsUntil); bottomLibraryMenu->addAction(aDrawBottomCard); bottomLibraryMenu->addAction(aDrawBottomCards); @@ -754,11 +759,12 @@ void Player::retranslateUi() aMoveTopToPlay->setText(tr("&Play top card")); aMoveTopToPlayFaceDown->setText(tr("Play top card &face down")); + aMoveTopCardToBottom->setText(tr("Put top card on &bottom")); aMoveTopCardToGraveyard->setText(tr("Move top card to grave&yard")); aMoveTopCardToExile->setText(tr("Move top card to e&xile")); aMoveTopCardsToGraveyard->setText(tr("Move top cards to &graveyard...")); aMoveTopCardsToExile->setText(tr("Move top cards to &exile...")); - aMoveTopCardToBottom->setText(tr("Put top card on &bottom")); + aMoveTopCardsUntil->setText(tr("Take top cards &until...")); aDrawBottomCard->setText(tr("&Draw bottom card")); aDrawBottomCards->setText(tr("D&raw bottom cards...")); @@ -938,6 +944,7 @@ void Player::setShortcutsActive() 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")); @@ -978,6 +985,7 @@ void Player::setShortcutsInactive() aMoveTopCardsToGraveyard->setShortcut(QKeySequence()); aMoveTopCardToExile->setShortcut(QKeySequence()); aMoveTopCardsToExile->setShortcut(QKeySequence()); + aMoveTopCardsUntil->setShortcut(QKeySequence()); aDrawBottomCard->setShortcut(QKeySequence()); aDrawBottomCards->setShortcut(QKeySequence()); aMoveBottomToPlay->setShortcut(QKeySequence()); @@ -1291,6 +1299,45 @@ void Player::actMoveTopCardsToExile() sendGameCommand(cmd); } +void Player::actMoveTopCardsUntil() +{ + QString expr = previousMovingCardsUntilExpr; + for (;;) { + bool ok; + expr = + QInputDialog::getText(game, "Take top cards until", "Select card (accepts search syntax)", {}, expr, &ok); + if (!ok) { + return; + } + movingCardsUntilFilter = FilterString(expr); + if (movingCardsUntilFilter.valid()) { + break; + } else { + auto button = QMessageBox::warning(game, "Invalid filter", movingCardsUntilFilter.error()); + if (button != QMessageBox::Ok) { + return; + } + } + } + previousMovingCardsUntilExpr = expr; + if (zones.value("deck")->getCards().empty()) { + movingCardsUntil = false; + } else { + movingCardsUntil = true; + actMoveTopCardToPlay(); + } +} + +void Player::moveOneCardUntil(const QString &cardName) +{ + auto card = db->getCard(cardName); + if (zones.value("deck")->getCards().empty() || card.isNull() || movingCardsUntilFilter.check(card)) { + movingCardsUntil = false; + } else { + QTimer::singleShot(100, [this]() { actMoveTopCardToPlay(); }); + } +} + void Player::actMoveTopCardToBottom() { if (zones.value("deck")->getCards().empty()) { @@ -2041,7 +2088,8 @@ void Player::eventMoveCard(const Event_MoveCard &event, const GameEventContext & if (!startPlayer) { return; } - CardZone *startZone = startPlayer->getZones().value(QString::fromStdString(event.start_zone()), 0); + QString startZoneString = QString::fromStdString(event.start_zone()); + CardZone *startZone = startPlayer->getZones().value(startZoneString, 0); Player *targetPlayer = game->getPlayers().value(event.target_player_id()); if (!targetPlayer) { return; @@ -2133,6 +2181,10 @@ void Player::eventMoveCard(const Event_MoveCard &event, const GameEventContext & } } updateCardMenu(card); + + if (movingCardsUntil && startZoneString == "deck" && targetZone->getName() == "stack") { + moveOneCardUntil(card->getName()); + } } void Player::eventFlipCard(const Event_FlipCard &event) diff --git a/cockatrice/src/player.h b/cockatrice/src/player.h index 7f14b7d59..96e2ba959 100644 --- a/cockatrice/src/player.h +++ b/cockatrice/src/player.h @@ -3,6 +3,7 @@ #include "abstractgraphicsitem.h" #include "carddatabase.h" +#include "filter_string.h" #include "pb/card_attributes.pb.h" #include "pb/game_event.pb.h" #include "tearoffmenu.h" @@ -162,6 +163,7 @@ public slots: void actMoveTopCardToExile(); void actMoveTopCardsToGrave(); void actMoveTopCardsToExile(); + void actMoveTopCardsUntil(); void actMoveTopCardToBottom(); void actDrawBottomCard(); void actDrawBottomCards(); @@ -233,12 +235,12 @@ private: *aMoveGraveToTopLibrary, *aMoveGraveToBottomLibrary, *aMoveGraveToHand, *aMoveGraveToRfg, *aMoveRfgToTopLibrary, *aMoveRfgToBottomLibrary, *aMoveRfgToHand, *aMoveRfgToGrave, *aViewHand, *aViewLibrary, *aViewTopCards, *aAlwaysRevealTopCard, *aAlwaysLookAtTopCard, *aOpenDeckInDeckEditor, *aMoveTopCardToGraveyard, - *aMoveTopCardToExile, *aMoveTopCardsToGraveyard, *aMoveTopCardsToExile, *aMoveTopCardToBottom, *aViewGraveyard, - *aViewRfg, *aViewSideboard, *aDrawCard, *aDrawCards, *aUndoDraw, *aMulligan, *aShuffle, *aMoveTopToPlay, - *aMoveTopToPlayFaceDown, *aUntapAll, *aRollDie, *aCreateToken, *aCreateAnotherToken, *aCardMenu, - *aMoveBottomToPlay, *aMoveBottomToPlayFaceDown, *aMoveBottomCardToTop, *aMoveBottomCardToGraveyard, - *aMoveBottomCardToExile, *aMoveBottomCardsToGraveyard, *aMoveBottomCardsToExile, *aDrawBottomCard, - *aDrawBottomCards; + *aMoveTopCardToExile, *aMoveTopCardsToGraveyard, *aMoveTopCardsToExile, *aMoveTopCardsUntil, + *aMoveTopCardToBottom, *aViewGraveyard, *aViewRfg, *aViewSideboard, *aDrawCard, *aDrawCards, *aUndoDraw, + *aMulligan, *aShuffle, *aMoveTopToPlay, *aMoveTopToPlayFaceDown, *aUntapAll, *aRollDie, *aCreateToken, + *aCreateAnotherToken, *aCardMenu, *aMoveBottomToPlay, *aMoveBottomToPlayFaceDown, *aMoveBottomCardToTop, + *aMoveBottomCardToGraveyard, *aMoveBottomCardToExile, *aMoveBottomCardsToGraveyard, *aMoveBottomCardsToExile, + *aDrawBottomCard, *aDrawBottomCards; QList aAddCounter, aSetCounter, aRemoveCounter; QAction *aPlay, *aPlayFacedown, *aHide, *aTap, *aDoesntUntap, *aAttach, *aUnattach, *aDrawArrow, *aSetPT, *aResetPT, @@ -246,6 +248,10 @@ private: *aMoveToTopLibrary, *aMoveToBottomLibrary, *aMoveToHand, *aMoveToGraveyard, *aMoveToExile, *aMoveToXfromTopOfLibrary; + bool movingCardsUntil; + QString previousMovingCardsUntilExpr = {}; + FilterString movingCardsUntilFilter; + bool shortcutsActive; int defaultNumberTopCards = 1; int defaultNumberTopCardsToPlaceBelow = 1; @@ -292,6 +298,7 @@ private: CardRelation::AttachType attach = CardRelation::DoesNotAttach, bool persistent = false); bool createRelatedFromRelation(const CardItem *sourceCard, const CardRelation *cardRelation); + void moveOneCardUntil(const QString &cardName); QRectF bRect; diff --git a/cockatrice/src/shortcutssettings.h b/cockatrice/src/shortcutssettings.h index b76623947..e3a2e8968 100644 --- a/cockatrice/src/shortcutssettings.h +++ b/cockatrice/src/shortcutssettings.h @@ -499,6 +499,9 @@ private: {"Player/aMoveTopCardsToExile", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile (Multiple)"), parseSequenceString(""), ShortcutGroup::Move_top)}, + {"Player/aMoveTopCardsUntil", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Stack"), + parseSequenceString("Ctrl+Shift+Y"), + ShortcutGroup::Move_top)}, {"Player/aMoveTopCardToBottom", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Bottom of Library"), parseSequenceString(""), ShortcutGroup::Move_top)},