Cockatrice/cockatrice/src/game_graphics/player/menu/hand_menu.cpp

330 lines
13 KiB
C++

#include "hand_menu.h"
#include "../../../client/settings/cache_settings.h"
#include "../../../client/settings/shortcuts_settings.h"
#include "../../../interface/widgets/menus/tearoff_menu.h"
#include "../player_graphics_item.h"
#include <QAction>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QInputDialog>
#include <QKeySequence>
#include <QList>
#include <QMap>
#include <QMenu>
#include <QMessageBox>
#include <QObject>
#include <QPointer>
#include <QString>
#include <QVariant>
#include <libcockatrice/game/abstract_game.h>
#include <libcockatrice/game/board/card_list.h>
#include <libcockatrice/game/player/player_actions.h>
#include <libcockatrice/game/player/player_info.h>
#include <libcockatrice/game/player/player_logic.h>
#include <libcockatrice/game/player/player_manager.h>
#include <libcockatrice/game/zones/hand_zone_logic.h>
#include <libcockatrice/network/client/abstract/abstract_client.h>
#include <libcockatrice/utility/zone_names.h>
class QWidget;
HandMenu::HandMenu(PlayerGraphicsItem *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
{
auto *actions = player->getLogic()->getPlayerActions();
connect(actions, &PlayerActions::randomHandRevealFailed, this, &HandMenu::onRandomHandRevealFailed);
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
aViewHand = new QAction(this);
connect(aViewHand, &QAction::triggered, actions, &PlayerActions::actViewHand);
addAction(aViewHand);
mSortHand = addMenu(QString());
aSortHandByName = new QAction(this);
aSortHandByName->setData(CardList::SortByName);
aSortHandByType = new QAction(this);
aSortHandByType->setData(CardList::SortByMainType);
aSortHandByManaValue = new QAction(this);
aSortHandByManaValue->setData(CardList::SortByManaValue);
connect(aSortHandByType, &QAction::triggered, actions, &PlayerActions::actSortHand);
connect(aSortHandByName, &QAction::triggered, actions, &PlayerActions::actSortHand);
connect(aSortHandByManaValue, &QAction::triggered, actions, &PlayerActions::actSortHand);
mSortHand->addAction(aSortHandByName);
mSortHand->addAction(aSortHandByType);
mSortHand->addAction(aSortHandByManaValue);
}
mRevealHand = addMenu(QString());
connect(mRevealHand, &QMenu::aboutToShow, this, &HandMenu::populateRevealHandMenuWithActivePlayers);
aRevealHandToAll = new QAction(this);
aRevealHandToAll->setData(-1);
connect(aRevealHandToAll, &QAction::triggered, this, &HandMenu::onRevealHandTriggered);
mRevealRandomHandCard = addMenu(QString());
connect(mRevealRandomHandCard, &QMenu::aboutToShow, this,
&HandMenu::populateRevealRandomHandCardMenuWithActivePlayers);
aRevealRandomHandCardToAll = new QAction(this);
aRevealRandomHandCardToAll->setData(-1);
connect(aRevealRandomHandCardToAll, &QAction::triggered, this, &HandMenu::onRevealRandomHandCardTriggered);
mRevealRandomHandCards = addMenu(QString());
mRevealRandomHandCards->setObjectName("revealRandomHandCardsMenu");
connect(mRevealRandomHandCards, &QMenu::aboutToShow, this,
&HandMenu::populateRevealRandomHandCardsMenuWithActivePlayers);
aRevealRandomHandCardsToAll = new QAction(this);
aRevealRandomHandCardsToAll->setData(-1);
connect(aRevealRandomHandCardsToAll, &QAction::triggered, this, &HandMenu::onRevealRandomHandCardsTriggered);
mRevealRandomHandCards->addAction(aRevealRandomHandCardsToAll);
// We still need to add these actions to menu here so that the shortcuts are active right away
mRevealHand->addAction(aRevealHandToAll);
mRevealRandomHandCard->addAction(aRevealRandomHandCardToAll);
addSeparator();
aMulligan = new QAction(this);
connect(aMulligan, &QAction::triggered, actions, &PlayerActions::actRequestMulliganDialog);
addAction(aMulligan);
// Mulligan same size
aMulliganSame = new QAction(this);
connect(aMulliganSame, &QAction::triggered, actions, &PlayerActions::actMulliganSameSize);
addAction(aMulliganSame);
// Mulligan -1
aMulliganMinusOne = new QAction(this);
connect(aMulliganMinusOne, &QAction::triggered, actions, &PlayerActions::actMulliganMinusOne);
addAction(aMulliganMinusOne);
addSeparator();
mMoveHandMenu = addTearOffMenu(QString());
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
aMoveHandToTopLibrary = new QAction(this);
aMoveHandToTopLibrary->setData(QList<QVariant>() << ZoneNames::DECK << 0);
aMoveHandToBottomLibrary = new QAction(this);
aMoveHandToBottomLibrary->setData(QList<QVariant>() << ZoneNames::DECK << -1);
aMoveHandToGrave = new QAction(this);
aMoveHandToGrave->setData(QList<QVariant>() << ZoneNames::GRAVE << 0);
aMoveHandToRfg = new QAction(this);
aMoveHandToRfg->setData(QList<QVariant>() << ZoneNames::EXILE << 0);
auto hand = player->getLogic()->getHandZone();
connect(aMoveHandToTopLibrary, &QAction::triggered, hand, &HandZoneLogic::moveAllToZone);
connect(aMoveHandToBottomLibrary, &QAction::triggered, hand, &HandZoneLogic::moveAllToZone);
connect(aMoveHandToGrave, &QAction::triggered, hand, &HandZoneLogic::moveAllToZone);
connect(aMoveHandToRfg, &QAction::triggered, hand, &HandZoneLogic::moveAllToZone);
mMoveHandMenu->addAction(aMoveHandToTopLibrary);
mMoveHandMenu->addAction(aMoveHandToBottomLibrary);
mMoveHandMenu->addSeparator();
mMoveHandMenu->addAction(aMoveHandToGrave);
mMoveHandMenu->addSeparator();
mMoveHandMenu->addAction(aMoveHandToRfg);
}
retranslateUi();
}
void HandMenu::retranslateUi()
{
setTitle(tr("&Hand"));
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
aViewHand->setText(tr("&View hand"));
mSortHand->setTitle(tr("Sort hand by..."));
aSortHandByName->setText(tr("Name"));
aSortHandByType->setText(tr("Type"));
aSortHandByManaValue->setText(tr("Mana Value"));
aMulligan->setText(tr("Take &mulligan (Choose hand size)"));
aMulliganSame->setText(tr("Take mulligan (Same hand size)"));
aMulliganMinusOne->setText(tr("Take mulligan (Hand size - 1)"));
mMoveHandMenu->setTitle(tr("&Move hand to..."));
aMoveHandToTopLibrary->setText(tr("&Top of library"));
aMoveHandToBottomLibrary->setText(tr("&Bottom of library"));
aMoveHandToGrave->setText(tr("&Graveyard"));
aMoveHandToRfg->setText(tr("&Exile"));
mRevealHand->setTitle(tr("&Reveal hand to..."));
aRevealHandToAll->setText(tr("All players"));
mRevealRandomHandCard->setTitle(tr("Reveal r&andom card to..."));
aRevealRandomHandCardToAll->setText(tr("All players"));
mRevealRandomHandCards->setTitle(tr("Reveal a chosen number of random cards to..."));
aRevealRandomHandCardsToAll->setText(tr("All players"));
}
}
void HandMenu::setShortcutsActive()
{
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
aViewHand->setShortcuts(shortcuts.getShortcut("Player/aViewHand"));
aSortHandByName->setShortcuts(shortcuts.getShortcut("Player/aSortHandByName"));
aSortHandByType->setShortcuts(shortcuts.getShortcut("Player/aSortHandByType"));
aSortHandByManaValue->setShortcuts(shortcuts.getShortcut("Player/aSortHandByManaValue"));
aMulligan->setShortcuts(shortcuts.getShortcut("Player/aMulligan"));
aMulliganSame->setShortcuts(shortcuts.getShortcut("Player/aMulliganSame"));
aMulliganMinusOne->setShortcuts(shortcuts.getShortcut("Player/aMulliganMinusOne"));
aRevealHandToAll->setShortcuts(shortcuts.getShortcut("Player/aRevealHandToAll"));
aRevealRandomHandCardToAll->setShortcuts(shortcuts.getShortcut("Player/aRevealRandomHandCardToAll"));
}
void HandMenu::setShortcutsInactive()
{
aViewHand->setShortcut(QKeySequence());
aSortHandByName->setShortcut(QKeySequence());
aSortHandByType->setShortcut(QKeySequence());
aSortHandByManaValue->setShortcut(QKeySequence());
aMulligan->setShortcut(QKeySequence());
aRevealHandToAll->setShortcut(QKeySequence());
aRevealRandomHandCardToAll->setShortcut(QKeySequence());
}
void HandMenu::populateRevealHandMenuWithActivePlayers()
{
mRevealHand->clear();
mRevealHand->addAction(aRevealHandToAll);
mRevealHand->addSeparator();
const auto &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) {
if (other == player->getLogic()) {
continue;
}
QAction *a = mRevealHand->addAction(other->getPlayerInfo()->getName());
a->setData(other->getPlayerInfo()->getId());
connect(a, &QAction::triggered, this, &HandMenu::onRevealHandTriggered);
}
}
void HandMenu::populateRevealRandomHandCardMenuWithActivePlayers()
{
mRevealRandomHandCard->clear();
mRevealRandomHandCard->addAction(aRevealRandomHandCardToAll);
mRevealRandomHandCard->addSeparator();
const auto &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) {
if (other == player->getLogic()) {
continue;
}
QAction *a = mRevealRandomHandCard->addAction(other->getPlayerInfo()->getName());
a->setData(other->getPlayerInfo()->getId());
connect(a, &QAction::triggered, this, &HandMenu::onRevealRandomHandCardTriggered);
}
}
void HandMenu::onRevealHandTriggered()
{
auto *action = qobject_cast<QAction *>(sender());
if (!action) {
return;
}
const int targetId = action->data().toInt();
player->getLogic()->getPlayerActions()->actRevealHand(targetId);
}
void HandMenu::onRevealRandomHandCardTriggered()
{
auto *action = qobject_cast<QAction *>(sender());
if (!action) {
return;
}
const int targetId = action->data().toInt();
player->getLogic()->getPlayerActions()->actRevealRandomHandCard(targetId);
}
void HandMenu::populateRevealRandomHandCardsMenuWithActivePlayers()
{
const bool hasCards = !player->getLogic()->getHandZone()->getCards().isEmpty();
mRevealRandomHandCards->clear();
aRevealRandomHandCardsToAll->setEnabled(hasCards);
mRevealRandomHandCards->addAction(aRevealRandomHandCardsToAll);
mRevealRandomHandCards->addSeparator();
const auto &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) {
if (other == player->getLogic()) {
continue;
}
auto *action = mRevealRandomHandCards->addAction(other->getPlayerInfo()->getName());
action->setData(other->getPlayerInfo()->getId());
action->setEnabled(hasCards);
connect(action, &QAction::triggered, this, &HandMenu::onRevealRandomHandCardsTriggered);
}
}
void HandMenu::onRevealRandomHandCardsTriggered()
{
const auto *action = qobject_cast<QAction *>(sender());
const int handSize = player->getLogic()->getHandZone()->getCards().size();
if (!action || handSize == 0) {
return;
}
const int targetId = action->data().toInt();
QPointer<PlayerActions> actions = player->getLogic()->getPlayerActions();
QPointer<AbstractClient> client =
player->getLogic()->getGame()->getClientForPlayer(player->getLogic()->getPlayerInfo()->getId());
if (!client) {
return;
}
auto *dialog = new QInputDialog(dialogParent());
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->setWindowTitle(tr("Reveal Random Hand Cards"));
dialog->setLabelText(tr("Number of distinct random cards to reveal to %1:").arg(action->text()));
dialog->setInputMode(QInputDialog::IntInput);
dialog->setIntRange(1, handSize);
dialog->setIntValue(qMin(2, handSize));
connect(this, &QObject::destroyed, dialog, &QDialog::reject);
connect(client, &QObject::destroyed, dialog, &QDialog::reject);
connect(actions, &QObject::destroyed, dialog, &QDialog::reject);
connect(dialog, &QDialog::accepted, this, [dialog, actions, client, targetId] {
if (!actions || !client) {
return;
}
actions->actRevealRandomHandCards(targetId, dialog->intValue());
});
dialog->open();
}
QWidget *HandMenu::dialogParent() const
{
if (auto *view = player->scene() ? player->scene()->views().value(0) : nullptr) {
return view->window();
}
return nullptr;
}
void HandMenu::onRandomHandRevealFailed(bool unsupported)
{
const QString text =
unsupported ? tr("This server does not support revealing multiple random cards. No cards were revealed.")
: tr("The random reveal could not be completed. The hand or recipient may have changed.");
auto *message =
new QMessageBox(QMessageBox::Warning, tr("Reveal Random Hand Cards"), text, QMessageBox::Ok, dialogParent());
message->setAttribute(Qt::WA_DeleteOnClose);
connect(this, &QObject::destroyed, message, &QDialog::reject);
connect(player->getLogic()->getPlayerActions(), &QObject::destroyed, message, &QDialog::reject);
if (auto *client =
player->getLogic()->getGame()->getClientForPlayer(player->getLogic()->getPlayerInfo()->getId())) {
connect(client, &QObject::destroyed, message, &QDialog::reject);
}
message->open();
}