3296 lines
111 KiB
C++
3296 lines
111 KiB
C++
#include "player.h"
|
|
|
|
#include "arrowitem.h"
|
|
#include "carddatabase.h"
|
|
#include "carditem.h"
|
|
#include "cardlist.h"
|
|
#include "cardzone.h"
|
|
#include "color.h"
|
|
#include "counter_general.h"
|
|
#include "deck_loader.h"
|
|
#include "dlg_create_token.h"
|
|
#include "gamescene.h"
|
|
#include "handcounter.h"
|
|
#include "handzone.h"
|
|
#include "main.h"
|
|
#include "pb/command_attach_card.pb.h"
|
|
#include "pb/command_change_zone_properties.pb.h"
|
|
#include "pb/command_concede.pb.h"
|
|
#include "pb/command_create_token.pb.h"
|
|
#include "pb/command_draw_cards.pb.h"
|
|
#include "pb/command_flip_card.pb.h"
|
|
#include "pb/command_game_say.pb.h"
|
|
#include "pb/command_move_card.pb.h"
|
|
#include "pb/command_mulligan.pb.h"
|
|
#include "pb/command_reveal_cards.pb.h"
|
|
#include "pb/command_roll_die.pb.h"
|
|
#include "pb/command_set_card_attr.pb.h"
|
|
#include "pb/command_set_card_counter.pb.h"
|
|
#include "pb/command_shuffle.pb.h"
|
|
#include "pb/command_undo_draw.pb.h"
|
|
#include "pb/context_move_card.pb.h"
|
|
#include "pb/context_undo_draw.pb.h"
|
|
#include "pb/event_attach_card.pb.h"
|
|
#include "pb/event_change_zone_properties.pb.h"
|
|
#include "pb/event_create_arrow.pb.h"
|
|
#include "pb/event_create_counter.pb.h"
|
|
#include "pb/event_create_token.pb.h"
|
|
#include "pb/event_del_counter.pb.h"
|
|
#include "pb/event_delete_arrow.pb.h"
|
|
#include "pb/event_destroy_card.pb.h"
|
|
#include "pb/event_draw_cards.pb.h"
|
|
#include "pb/event_dump_zone.pb.h"
|
|
#include "pb/event_flip_card.pb.h"
|
|
#include "pb/event_game_say.pb.h"
|
|
#include "pb/event_move_card.pb.h"
|
|
#include "pb/event_reveal_cards.pb.h"
|
|
#include "pb/event_roll_die.pb.h"
|
|
#include "pb/event_set_card_attr.pb.h"
|
|
#include "pb/event_set_card_counter.pb.h"
|
|
#include "pb/event_set_counter.pb.h"
|
|
#include "pb/event_shuffle.pb.h"
|
|
#include "pb/event_stop_dump_zone.pb.h"
|
|
#include "pb/serverinfo_player.pb.h"
|
|
#include "pb/serverinfo_user.pb.h"
|
|
#include "pb/serverinfo_zone.pb.h"
|
|
#include "pilezone.h"
|
|
#include "playertarget.h"
|
|
#include "settingscache.h"
|
|
#include "stackzone.h"
|
|
#include "tab_game.h"
|
|
#include "tablezone.h"
|
|
#include "thememanager.h"
|
|
#include "zoneviewwidget.h"
|
|
#include "zoneviewzone.h"
|
|
|
|
#include <QDebug>
|
|
#include <QMenu>
|
|
#include <QPainter>
|
|
#include <QRegularExpression>
|
|
#include <QRegularExpressionMatch>
|
|
|
|
PlayerArea::PlayerArea(QGraphicsItem *parentItem) : QObject(), QGraphicsItem(parentItem)
|
|
{
|
|
setCacheMode(DeviceCoordinateCache);
|
|
connect(themeManager, SIGNAL(themeChanged()), this, SLOT(updateBg()));
|
|
updateBg();
|
|
}
|
|
|
|
void PlayerArea::updateBg()
|
|
{
|
|
update();
|
|
}
|
|
|
|
void PlayerArea::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
|
{
|
|
painter->fillRect(bRect, themeManager->getPlayerBgBrush());
|
|
}
|
|
|
|
void PlayerArea::setSize(qreal width, qreal height)
|
|
{
|
|
prepareGeometryChange();
|
|
bRect = QRectF(0, 0, width, height);
|
|
}
|
|
|
|
Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, TabGame *_parent)
|
|
: QObject(_parent), game(_parent), shortcutsActive(false), defaultNumberTopCards(1),
|
|
defaultNumberTopCardsToPlaceBelow(1), lastTokenDestroy(true), lastTokenTableRow(0), id(_id), active(false),
|
|
local(_local), judge(_judge), mirrored(false), handVisible(false), conceded(false), dialogSemaphore(false),
|
|
deck(nullptr)
|
|
{
|
|
userInfo = new ServerInfo_User;
|
|
userInfo->CopyFrom(info);
|
|
|
|
connect(settingsCache, SIGNAL(horizontalHandChanged()), this, SLOT(rearrangeZones()));
|
|
connect(settingsCache, SIGNAL(handJustificationChanged()), this, SLOT(rearrangeZones()));
|
|
|
|
playerArea = new PlayerArea(this);
|
|
|
|
playerTarget = new PlayerTarget(this, playerArea, game);
|
|
qreal avatarMargin = (counterAreaWidth + CARD_HEIGHT + 15 - playerTarget->boundingRect().width()) / 2.0;
|
|
playerTarget->setPos(QPointF(avatarMargin, avatarMargin));
|
|
|
|
PileZone *deck = new PileZone(this, "deck", true, false, playerArea);
|
|
QPointF base = QPointF(counterAreaWidth + (CARD_HEIGHT - CARD_WIDTH + 15) / 2.0,
|
|
10 + playerTarget->boundingRect().height() + 5 - (CARD_HEIGHT - CARD_WIDTH) / 2.0);
|
|
deck->setPos(base);
|
|
|
|
qreal h = deck->boundingRect().width() + 5;
|
|
|
|
auto *handCounter = new HandCounter(playerArea);
|
|
handCounter->setPos(base + QPointF(0, h + 10));
|
|
qreal h2 = handCounter->boundingRect().height();
|
|
|
|
PileZone *grave = new PileZone(this, "grave", false, true, playerArea);
|
|
grave->setPos(base + QPointF(0, h + h2 + 10));
|
|
|
|
PileZone *rfg = new PileZone(this, "rfg", false, true, playerArea);
|
|
rfg->setPos(base + QPointF(0, 2 * h + h2 + 10));
|
|
|
|
PileZone *sb = new PileZone(this, "sb", false, false, playerArea);
|
|
sb->setVisible(false);
|
|
|
|
table = new TableZone(this, this);
|
|
connect(table, SIGNAL(sizeChanged()), this, SLOT(updateBoundingRect()));
|
|
|
|
stack = new StackZone(this, (int)table->boundingRect().height(), this);
|
|
|
|
hand = new HandZone(this, _local || (_parent->getSpectator() && _parent->getSpectatorsSeeEverything()),
|
|
(int)table->boundingRect().height(), this);
|
|
connect(hand, SIGNAL(cardCountChanged()), handCounter, SLOT(updateNumber()));
|
|
connect(handCounter, SIGNAL(showContextMenu(const QPoint &)), hand, SLOT(showContextMenu(const QPoint &)));
|
|
|
|
updateBoundingRect();
|
|
|
|
if (local || judge) {
|
|
connect(_parent, SIGNAL(playerAdded(Player *)), this, SLOT(addPlayer(Player *)));
|
|
connect(_parent, SIGNAL(playerRemoved(Player *)), this, SLOT(removePlayer(Player *)));
|
|
}
|
|
|
|
if (local || judge) {
|
|
aMoveHandToTopLibrary = new QAction(this);
|
|
aMoveHandToTopLibrary->setData(QList<QVariant>() << "deck" << 0);
|
|
aMoveHandToBottomLibrary = new QAction(this);
|
|
aMoveHandToBottomLibrary->setData(QList<QVariant>() << "deck" << -1);
|
|
aMoveHandToGrave = new QAction(this);
|
|
aMoveHandToGrave->setData(QList<QVariant>() << "grave" << 0);
|
|
aMoveHandToRfg = new QAction(this);
|
|
aMoveHandToRfg->setData(QList<QVariant>() << "rfg" << 0);
|
|
|
|
connect(aMoveHandToTopLibrary, SIGNAL(triggered()), hand, SLOT(moveAllToZone()));
|
|
connect(aMoveHandToBottomLibrary, SIGNAL(triggered()), hand, SLOT(moveAllToZone()));
|
|
connect(aMoveHandToGrave, SIGNAL(triggered()), hand, SLOT(moveAllToZone()));
|
|
connect(aMoveHandToRfg, SIGNAL(triggered()), hand, SLOT(moveAllToZone()));
|
|
|
|
aMoveGraveToTopLibrary = new QAction(this);
|
|
aMoveGraveToTopLibrary->setData(QList<QVariant>() << "deck" << 0);
|
|
aMoveGraveToBottomLibrary = new QAction(this);
|
|
aMoveGraveToBottomLibrary->setData(QList<QVariant>() << "deck" << -1);
|
|
aMoveGraveToHand = new QAction(this);
|
|
aMoveGraveToHand->setData(QList<QVariant>() << "hand" << 0);
|
|
aMoveGraveToRfg = new QAction(this);
|
|
aMoveGraveToRfg->setData(QList<QVariant>() << "rfg" << 0);
|
|
|
|
connect(aMoveGraveToTopLibrary, SIGNAL(triggered()), grave, SLOT(moveAllToZone()));
|
|
connect(aMoveGraveToBottomLibrary, SIGNAL(triggered()), grave, SLOT(moveAllToZone()));
|
|
connect(aMoveGraveToHand, SIGNAL(triggered()), grave, SLOT(moveAllToZone()));
|
|
connect(aMoveGraveToRfg, SIGNAL(triggered()), grave, SLOT(moveAllToZone()));
|
|
|
|
aMoveRfgToTopLibrary = new QAction(this);
|
|
aMoveRfgToTopLibrary->setData(QList<QVariant>() << "deck" << 0);
|
|
aMoveRfgToBottomLibrary = new QAction(this);
|
|
aMoveRfgToBottomLibrary->setData(QList<QVariant>() << "deck" << -1);
|
|
aMoveRfgToHand = new QAction(this);
|
|
aMoveRfgToHand->setData(QList<QVariant>() << "hand" << 0);
|
|
aMoveRfgToGrave = new QAction(this);
|
|
aMoveRfgToGrave->setData(QList<QVariant>() << "grave" << 0);
|
|
|
|
connect(aMoveRfgToTopLibrary, SIGNAL(triggered()), rfg, SLOT(moveAllToZone()));
|
|
connect(aMoveRfgToBottomLibrary, SIGNAL(triggered()), rfg, SLOT(moveAllToZone()));
|
|
connect(aMoveRfgToHand, SIGNAL(triggered()), rfg, SLOT(moveAllToZone()));
|
|
connect(aMoveRfgToGrave, SIGNAL(triggered()), rfg, SLOT(moveAllToZone()));
|
|
|
|
aViewLibrary = new QAction(this);
|
|
connect(aViewLibrary, SIGNAL(triggered()), this, SLOT(actViewLibrary()));
|
|
aViewHand = new QAction(this);
|
|
connect(aViewHand, SIGNAL(triggered()), this, SLOT(actViewHand()));
|
|
|
|
aViewTopCards = new QAction(this);
|
|
connect(aViewTopCards, SIGNAL(triggered()), this, SLOT(actViewTopCards()));
|
|
aAlwaysRevealTopCard = new QAction(this);
|
|
aAlwaysRevealTopCard->setCheckable(true);
|
|
connect(aAlwaysRevealTopCard, SIGNAL(triggered()), this, SLOT(actAlwaysRevealTopCard()));
|
|
aOpenDeckInDeckEditor = new QAction(this);
|
|
aOpenDeckInDeckEditor->setEnabled(false);
|
|
connect(aOpenDeckInDeckEditor, SIGNAL(triggered()), this, SLOT(actOpenDeckInDeckEditor()));
|
|
}
|
|
|
|
aViewGraveyard = new QAction(this);
|
|
connect(aViewGraveyard, SIGNAL(triggered()), this, SLOT(actViewGraveyard()));
|
|
|
|
aViewRfg = new QAction(this);
|
|
connect(aViewRfg, SIGNAL(triggered()), this, SLOT(actViewRfg()));
|
|
|
|
if (local || judge) {
|
|
aViewSideboard = new QAction(this);
|
|
connect(aViewSideboard, SIGNAL(triggered()), this, SLOT(actViewSideboard()));
|
|
|
|
aDrawCard = new QAction(this);
|
|
connect(aDrawCard, SIGNAL(triggered()), this, SLOT(actDrawCard()));
|
|
aDrawCards = new QAction(this);
|
|
connect(aDrawCards, SIGNAL(triggered()), this, SLOT(actDrawCards()));
|
|
aUndoDraw = new QAction(this);
|
|
connect(aUndoDraw, SIGNAL(triggered()), this, SLOT(actUndoDraw()));
|
|
aShuffle = new QAction(this);
|
|
connect(aShuffle, SIGNAL(triggered()), this, SLOT(actShuffle()));
|
|
aMulligan = new QAction(this);
|
|
connect(aMulligan, SIGNAL(triggered()), this, SLOT(actMulligan()));
|
|
aMoveTopToPlay = new QAction(this);
|
|
connect(aMoveTopToPlay, SIGNAL(triggered()), this, SLOT(actMoveTopCardToPlay()));
|
|
aMoveTopToPlayFaceDown = new QAction(this);
|
|
connect(aMoveTopToPlayFaceDown, SIGNAL(triggered()), this, SLOT(actMoveTopCardToPlayFaceDown()));
|
|
aMoveTopCardToGraveyard = new QAction(this);
|
|
connect(aMoveTopCardToGraveyard, SIGNAL(triggered()), this, SLOT(actMoveTopCardToGrave()));
|
|
aMoveTopCardToExile = new QAction(this);
|
|
connect(aMoveTopCardToExile, SIGNAL(triggered()), this, SLOT(actMoveTopCardToExile()));
|
|
aMoveTopCardsToGraveyard = new QAction(this);
|
|
connect(aMoveTopCardsToGraveyard, SIGNAL(triggered()), this, SLOT(actMoveTopCardsToGrave()));
|
|
aMoveTopCardsToExile = new QAction(this);
|
|
connect(aMoveTopCardsToExile, SIGNAL(triggered()), this, SLOT(actMoveTopCardsToExile()));
|
|
aMoveTopCardToBottom = new QAction(this);
|
|
connect(aMoveTopCardToBottom, SIGNAL(triggered()), this, SLOT(actMoveTopCardToBottom()));
|
|
aMoveBottomCardToGrave = new QAction(this);
|
|
connect(aMoveBottomCardToGrave, SIGNAL(triggered()), this, SLOT(actMoveBottomCardToGrave()));
|
|
}
|
|
|
|
playerMenu = new TearOffMenu();
|
|
table->setMenu(playerMenu);
|
|
|
|
if (local || judge) {
|
|
handMenu = playerMenu->addTearOffMenu(QString());
|
|
handMenu->addAction(aViewHand);
|
|
playerLists.append(mRevealHand = handMenu->addMenu(QString()));
|
|
playerLists.append(mRevealRandomHandCard = handMenu->addMenu(QString()));
|
|
handMenu->addSeparator();
|
|
handMenu->addAction(aMulligan);
|
|
handMenu->addSeparator();
|
|
moveHandMenu = handMenu->addTearOffMenu(QString());
|
|
moveHandMenu->addAction(aMoveHandToTopLibrary);
|
|
moveHandMenu->addAction(aMoveHandToBottomLibrary);
|
|
moveHandMenu->addSeparator();
|
|
moveHandMenu->addAction(aMoveHandToGrave);
|
|
moveHandMenu->addSeparator();
|
|
moveHandMenu->addAction(aMoveHandToRfg);
|
|
hand->setMenu(handMenu);
|
|
|
|
libraryMenu = playerMenu->addTearOffMenu(QString());
|
|
libraryMenu->addAction(aDrawCard);
|
|
libraryMenu->addAction(aDrawCards);
|
|
libraryMenu->addAction(aUndoDraw);
|
|
libraryMenu->addSeparator();
|
|
libraryMenu->addAction(aShuffle);
|
|
libraryMenu->addSeparator();
|
|
libraryMenu->addAction(aViewLibrary);
|
|
libraryMenu->addAction(aViewTopCards);
|
|
libraryMenu->addSeparator();
|
|
playerLists.append(mRevealLibrary = libraryMenu->addMenu(QString()));
|
|
playerLists.append(mRevealTopCard = libraryMenu->addMenu(QString()));
|
|
libraryMenu->addAction(aAlwaysRevealTopCard);
|
|
libraryMenu->addSeparator();
|
|
libraryMenu->addAction(aMoveTopToPlay);
|
|
libraryMenu->addAction(aMoveTopToPlayFaceDown);
|
|
libraryMenu->addAction(aMoveTopCardToBottom);
|
|
libraryMenu->addAction(aMoveBottomCardToGrave);
|
|
libraryMenu->addSeparator();
|
|
libraryMenu->addAction(aMoveTopCardToGraveyard);
|
|
libraryMenu->addAction(aMoveTopCardToExile);
|
|
libraryMenu->addAction(aMoveTopCardsToGraveyard);
|
|
libraryMenu->addAction(aMoveTopCardsToExile);
|
|
libraryMenu->addSeparator();
|
|
libraryMenu->addAction(aOpenDeckInDeckEditor);
|
|
deck->setMenu(libraryMenu, aDrawCard);
|
|
} else {
|
|
handMenu = nullptr;
|
|
libraryMenu = nullptr;
|
|
}
|
|
|
|
graveMenu = playerMenu->addTearOffMenu(QString());
|
|
graveMenu->addAction(aViewGraveyard);
|
|
|
|
if (local || judge) {
|
|
mRevealRandomGraveyardCard = graveMenu->addMenu(QString());
|
|
QAction *newAction = mRevealRandomGraveyardCard->addAction(QString());
|
|
newAction->setData(-1);
|
|
connect(newAction, SIGNAL(triggered()), this, SLOT(actRevealRandomGraveyardCard()));
|
|
allPlayersActions.append(newAction);
|
|
mRevealRandomGraveyardCard->addSeparator();
|
|
}
|
|
grave->setMenu(graveMenu, aViewGraveyard);
|
|
|
|
rfgMenu = playerMenu->addTearOffMenu(QString());
|
|
rfgMenu->addAction(aViewRfg);
|
|
rfg->setMenu(rfgMenu, aViewRfg);
|
|
|
|
if (local || judge) {
|
|
graveMenu->addSeparator();
|
|
moveGraveMenu = graveMenu->addTearOffMenu(QString());
|
|
moveGraveMenu->addAction(aMoveGraveToTopLibrary);
|
|
moveGraveMenu->addAction(aMoveGraveToBottomLibrary);
|
|
moveGraveMenu->addSeparator();
|
|
moveGraveMenu->addAction(aMoveGraveToHand);
|
|
moveGraveMenu->addSeparator();
|
|
moveGraveMenu->addAction(aMoveGraveToRfg);
|
|
|
|
rfgMenu->addSeparator();
|
|
moveRfgMenu = rfgMenu->addTearOffMenu(QString());
|
|
moveRfgMenu->addAction(aMoveRfgToTopLibrary);
|
|
moveRfgMenu->addAction(aMoveRfgToBottomLibrary);
|
|
moveRfgMenu->addSeparator();
|
|
moveRfgMenu->addAction(aMoveRfgToHand);
|
|
moveRfgMenu->addSeparator();
|
|
moveRfgMenu->addAction(aMoveRfgToGrave);
|
|
|
|
sbMenu = playerMenu->addMenu(QString());
|
|
sbMenu->addAction(aViewSideboard);
|
|
sb->setMenu(sbMenu, aViewSideboard);
|
|
|
|
aUntapAll = new QAction(this);
|
|
connect(aUntapAll, SIGNAL(triggered()), this, SLOT(actUntapAll()));
|
|
|
|
aRollDie = new QAction(this);
|
|
connect(aRollDie, SIGNAL(triggered()), this, SLOT(actRollDie()));
|
|
|
|
aCreateToken = new QAction(this);
|
|
connect(aCreateToken, SIGNAL(triggered()), this, SLOT(actCreateToken()));
|
|
|
|
aCreateAnotherToken = new QAction(this);
|
|
connect(aCreateAnotherToken, SIGNAL(triggered()), this, SLOT(actCreateAnotherToken()));
|
|
aCreateAnotherToken->setEnabled(false);
|
|
|
|
createPredefinedTokenMenu = new QMenu(QString());
|
|
|
|
playerMenu->addSeparator();
|
|
countersMenu = playerMenu->addMenu(QString());
|
|
playerMenu->addSeparator();
|
|
playerMenu->addAction(aUntapAll);
|
|
playerMenu->addSeparator();
|
|
playerMenu->addAction(aRollDie);
|
|
playerMenu->addSeparator();
|
|
playerMenu->addAction(aCreateToken);
|
|
playerMenu->addAction(aCreateAnotherToken);
|
|
playerMenu->addMenu(createPredefinedTokenMenu);
|
|
playerMenu->addSeparator();
|
|
}
|
|
|
|
if (local) {
|
|
sayMenu = playerMenu->addMenu(QString());
|
|
initSayMenu();
|
|
}
|
|
|
|
if (local || judge) {
|
|
aCardMenu = new QAction(this);
|
|
playerMenu->addSeparator();
|
|
playerMenu->addAction(aCardMenu);
|
|
} else {
|
|
aCardMenu = nullptr;
|
|
}
|
|
|
|
if (local || judge) {
|
|
|
|
for (auto &playerList : playerLists) {
|
|
QAction *newAction = playerList->addAction(QString());
|
|
newAction->setData(-1);
|
|
connect(newAction, SIGNAL(triggered()), this, SLOT(playerListActionTriggered()));
|
|
allPlayersActions.append(newAction);
|
|
playerList->addSeparator();
|
|
}
|
|
}
|
|
|
|
if (!local && !judge) {
|
|
countersMenu = nullptr;
|
|
sbMenu = nullptr;
|
|
aCreateAnotherToken = nullptr;
|
|
createPredefinedTokenMenu = nullptr;
|
|
}
|
|
|
|
aTap = new QAction(this);
|
|
aTap->setData(cmTap);
|
|
connect(aTap, SIGNAL(triggered()), this, SLOT(cardMenuAction()));
|
|
aDoesntUntap = new QAction(this);
|
|
aDoesntUntap->setData(cmDoesntUntap);
|
|
connect(aDoesntUntap, SIGNAL(triggered()), this, SLOT(cardMenuAction()));
|
|
aAttach = new QAction(this);
|
|
connect(aAttach, SIGNAL(triggered()), this, SLOT(actAttach()));
|
|
aUnattach = new QAction(this);
|
|
connect(aUnattach, SIGNAL(triggered()), this, SLOT(actUnattach()));
|
|
aDrawArrow = new QAction(this);
|
|
connect(aDrawArrow, SIGNAL(triggered()), this, SLOT(actDrawArrow()));
|
|
aIncP = new QAction(this);
|
|
connect(aIncP, SIGNAL(triggered()), this, SLOT(actIncP()));
|
|
aDecP = new QAction(this);
|
|
connect(aDecP, SIGNAL(triggered()), this, SLOT(actDecP()));
|
|
aIncT = new QAction(this);
|
|
connect(aIncT, SIGNAL(triggered()), this, SLOT(actIncT()));
|
|
aDecT = new QAction(this);
|
|
connect(aDecT, SIGNAL(triggered()), this, SLOT(actDecT()));
|
|
aIncPT = new QAction(this);
|
|
connect(aIncPT, SIGNAL(triggered()), this, SLOT(actIncPT()));
|
|
aDecPT = new QAction(this);
|
|
connect(aDecPT, SIGNAL(triggered()), this, SLOT(actDecPT()));
|
|
aFlowP = new QAction(this);
|
|
connect(aFlowP, SIGNAL(triggered()), this, SLOT(actFlowP()));
|
|
aFlowT = new QAction(this);
|
|
connect(aFlowT, SIGNAL(triggered()), this, SLOT(actFlowT()));
|
|
aSetPT = new QAction(this);
|
|
connect(aSetPT, SIGNAL(triggered()), this, SLOT(actSetPT()));
|
|
aResetPT = new QAction(this);
|
|
connect(aResetPT, SIGNAL(triggered()), this, SLOT(actResetPT()));
|
|
aSetAnnotation = new QAction(this);
|
|
connect(aSetAnnotation, SIGNAL(triggered()), this, SLOT(actSetAnnotation()));
|
|
aFlip = new QAction(this);
|
|
aFlip->setData(cmFlip);
|
|
connect(aFlip, SIGNAL(triggered()), this, SLOT(cardMenuAction()));
|
|
aPeek = new QAction(this);
|
|
aPeek->setData(cmPeek);
|
|
connect(aPeek, SIGNAL(triggered()), this, SLOT(cardMenuAction()));
|
|
aClone = new QAction(this);
|
|
aClone->setData(cmClone);
|
|
connect(aClone, SIGNAL(triggered()), this, SLOT(cardMenuAction()));
|
|
aMoveToTopLibrary = new QAction(this);
|
|
aMoveToTopLibrary->setData(cmMoveToTopLibrary);
|
|
aMoveToBottomLibrary = new QAction(this);
|
|
aMoveToBottomLibrary->setData(cmMoveToBottomLibrary);
|
|
aMoveToXfromTopOfLibrary = new QAction(this);
|
|
aMoveToGraveyard = new QAction(this);
|
|
aMoveToHand = new QAction(this);
|
|
aMoveToHand->setData(cmMoveToHand);
|
|
aMoveToGraveyard->setData(cmMoveToGraveyard);
|
|
aMoveToExile = new QAction(this);
|
|
aMoveToExile->setData(cmMoveToExile);
|
|
connect(aMoveToTopLibrary, SIGNAL(triggered()), this, SLOT(cardMenuAction()));
|
|
connect(aMoveToBottomLibrary, SIGNAL(triggered()), this, SLOT(cardMenuAction()));
|
|
connect(aMoveToXfromTopOfLibrary, SIGNAL(triggered()), this, SLOT(actMoveCardXCardsFromTop()));
|
|
connect(aMoveToHand, SIGNAL(triggered()), this, SLOT(cardMenuAction()));
|
|
connect(aMoveToGraveyard, SIGNAL(triggered()), this, SLOT(cardMenuAction()));
|
|
connect(aMoveToExile, SIGNAL(triggered()), this, SLOT(cardMenuAction()));
|
|
|
|
aPlay = new QAction(this);
|
|
connect(aPlay, SIGNAL(triggered()), this, SLOT(actPlay()));
|
|
aHide = new QAction(this);
|
|
connect(aHide, SIGNAL(triggered()), this, SLOT(actHide()));
|
|
aPlayFacedown = new QAction(this);
|
|
connect(aPlayFacedown, SIGNAL(triggered()), this, SLOT(actPlayFacedown()));
|
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
auto *tempAddCounter = new QAction(this);
|
|
tempAddCounter->setData(9 + i * 1000);
|
|
auto *tempRemoveCounter = new QAction(this);
|
|
tempRemoveCounter->setData(10 + i * 1000);
|
|
auto *tempSetCounter = new QAction(this);
|
|
tempSetCounter->setData(11 + i * 1000);
|
|
aAddCounter.append(tempAddCounter);
|
|
aRemoveCounter.append(tempRemoveCounter);
|
|
aSetCounter.append(tempSetCounter);
|
|
connect(tempAddCounter, SIGNAL(triggered()), this, SLOT(actCardCounterTrigger()));
|
|
connect(tempRemoveCounter, SIGNAL(triggered()), this, SLOT(actCardCounterTrigger()));
|
|
connect(tempSetCounter, SIGNAL(triggered()), this, SLOT(actCardCounterTrigger()));
|
|
}
|
|
|
|
const QList<Player *> &players = game->getPlayers().values();
|
|
for (const auto player : players) {
|
|
addPlayer(player);
|
|
}
|
|
|
|
rearrangeZones();
|
|
retranslateUi();
|
|
connect(&settingsCache->shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
|
|
refreshShortcuts();
|
|
}
|
|
|
|
Player::~Player()
|
|
{
|
|
qDebug() << "Player destructor:" << getName();
|
|
|
|
static_cast<GameScene *>(scene())->removePlayer(this);
|
|
|
|
clear();
|
|
QMapIterator<QString, CardZone *> i(zones);
|
|
while (i.hasNext())
|
|
delete i.next().value();
|
|
zones.clear();
|
|
|
|
delete playerMenu;
|
|
delete userInfo;
|
|
}
|
|
|
|
void Player::clear()
|
|
{
|
|
clearArrows();
|
|
|
|
QMapIterator<QString, CardZone *> i(zones);
|
|
while (i.hasNext()) {
|
|
i.next().value()->clearContents();
|
|
}
|
|
|
|
clearCounters();
|
|
}
|
|
|
|
void Player::addPlayer(Player *player)
|
|
{
|
|
if (player == nullptr || player == this) {
|
|
return;
|
|
}
|
|
|
|
for (auto &playerList : playerLists) {
|
|
QAction *newAction = playerList->addAction(player->getName());
|
|
newAction->setData(player->getId());
|
|
connect(newAction, SIGNAL(triggered()), this, SLOT(playerListActionTriggered()));
|
|
}
|
|
}
|
|
|
|
void Player::removePlayer(Player *player)
|
|
{
|
|
if (player == nullptr) {
|
|
return;
|
|
}
|
|
|
|
for (auto &playerList : playerLists) {
|
|
QList<QAction *> actionList = playerList->actions();
|
|
for (auto &j : actionList)
|
|
if (j->data().toInt() == player->getId()) {
|
|
playerList->removeAction(j);
|
|
j->deleteLater();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::playerListActionTriggered()
|
|
{
|
|
auto *action = static_cast<QAction *>(sender());
|
|
auto *menu = static_cast<QMenu *>(action->parentWidget());
|
|
|
|
Command_RevealCards cmd;
|
|
const int otherPlayerId = action->data().toInt();
|
|
if (otherPlayerId != -1) {
|
|
cmd.set_player_id(otherPlayerId);
|
|
}
|
|
|
|
if (menu == mRevealLibrary) {
|
|
cmd.set_zone_name("deck");
|
|
} else if (menu == mRevealTopCard) {
|
|
int decksize = zones.value("deck")->getCards().size();
|
|
bool ok;
|
|
int number = QInputDialog::getInt(game, tr("Reveal top cards of library"),
|
|
tr("Number of cards: (max. %1)").arg(decksize), defaultNumberTopCards, 1,
|
|
decksize, 1, &ok);
|
|
if (ok) {
|
|
cmd.set_zone_name("deck");
|
|
cmd.set_top_cards(number);
|
|
// backward compatibility: servers before #1051 only permits to reveal the first card
|
|
cmd.set_card_id(0);
|
|
}
|
|
|
|
} else if (menu == mRevealHand) {
|
|
cmd.set_zone_name("hand");
|
|
} else if (menu == mRevealRandomHandCard) {
|
|
cmd.set_zone_name("hand");
|
|
cmd.set_card_id(RANDOM_CARD_FROM_ZONE);
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
sendGameCommand(cmd);
|
|
}
|
|
|
|
void Player::rearrangeZones()
|
|
{
|
|
QPointF base = QPointF(CARD_HEIGHT + counterAreaWidth + 15, 0);
|
|
if (settingsCache->getHorizontalHand()) {
|
|
if (mirrored) {
|
|
if (hand->contentsKnown()) {
|
|
handVisible = true;
|
|
hand->setPos(base);
|
|
base += QPointF(0, hand->boundingRect().height());
|
|
} else
|
|
handVisible = false;
|
|
|
|
stack->setPos(base);
|
|
base += QPointF(stack->boundingRect().width(), 0);
|
|
|
|
table->setPos(base);
|
|
} else {
|
|
stack->setPos(base);
|
|
|
|
table->setPos(base.x() + stack->boundingRect().width(), 0);
|
|
base += QPointF(0, table->boundingRect().height());
|
|
|
|
if (hand->contentsKnown()) {
|
|
handVisible = true;
|
|
hand->setPos(base);
|
|
} else
|
|
handVisible = false;
|
|
}
|
|
hand->setWidth(table->getWidth() + stack->boundingRect().width());
|
|
} else {
|
|
handVisible = true;
|
|
|
|
hand->setPos(base);
|
|
base += QPointF(hand->boundingRect().width(), 0);
|
|
|
|
stack->setPos(base);
|
|
base += QPointF(stack->boundingRect().width(), 0);
|
|
|
|
table->setPos(base);
|
|
}
|
|
hand->setVisible(handVisible);
|
|
hand->updateOrientation();
|
|
table->reorganizeCards();
|
|
updateBoundingRect();
|
|
rearrangeCounters();
|
|
}
|
|
|
|
void Player::updateZones()
|
|
{
|
|
table->reorganizeCards();
|
|
}
|
|
|
|
void Player::updateBoundingRect()
|
|
{
|
|
prepareGeometryChange();
|
|
qreal width = CARD_HEIGHT + 15 + counterAreaWidth + stack->boundingRect().width();
|
|
if (settingsCache->getHorizontalHand()) {
|
|
qreal handHeight = handVisible ? hand->boundingRect().height() : 0;
|
|
bRect = QRectF(0, 0, width + table->boundingRect().width(), table->boundingRect().height() + handHeight);
|
|
} else {
|
|
bRect = QRectF(0, 0, width + hand->boundingRect().width() + table->boundingRect().width(),
|
|
table->boundingRect().height());
|
|
}
|
|
playerArea->setSize(CARD_HEIGHT + counterAreaWidth + 15, bRect.height());
|
|
|
|
emit sizeChanged();
|
|
}
|
|
|
|
void Player::retranslateUi()
|
|
{
|
|
aViewGraveyard->setText(tr("&View graveyard"));
|
|
aViewRfg->setText(tr("&View exile"));
|
|
|
|
playerMenu->setTitle(tr("Player \"%1\"").arg(QString::fromStdString(userInfo->name())));
|
|
graveMenu->setTitle(tr("&Graveyard"));
|
|
rfgMenu->setTitle(tr("&Exile"));
|
|
|
|
if (local || judge) {
|
|
moveHandMenu->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"));
|
|
|
|
moveGraveMenu->setTitle(tr("&Move graveyard to..."));
|
|
aMoveGraveToTopLibrary->setText(tr("&Top of library"));
|
|
aMoveGraveToBottomLibrary->setText(tr("&Bottom of library"));
|
|
aMoveGraveToHand->setText(tr("&Hand"));
|
|
aMoveGraveToRfg->setText(tr("&Exile"));
|
|
|
|
moveRfgMenu->setTitle(tr("&Move exile to..."));
|
|
aMoveRfgToTopLibrary->setText(tr("&Top of library"));
|
|
aMoveRfgToBottomLibrary->setText(tr("&Bottom of library"));
|
|
aMoveRfgToHand->setText(tr("&Hand"));
|
|
aMoveRfgToGrave->setText(tr("&Graveyard"));
|
|
|
|
aViewLibrary->setText(tr("&View library"));
|
|
aViewHand->setText(tr("&View hand"));
|
|
aViewTopCards->setText(tr("View &top cards of library..."));
|
|
mRevealLibrary->setTitle(tr("Reveal &library to..."));
|
|
mRevealTopCard->setTitle(tr("Reveal t&op cards to..."));
|
|
aAlwaysRevealTopCard->setText(tr("&Always reveal top card"));
|
|
aOpenDeckInDeckEditor->setText(tr("O&pen deck in deck editor"));
|
|
aViewSideboard->setText(tr("&View sideboard"));
|
|
aDrawCard->setText(tr("&Draw card"));
|
|
aDrawCards->setText(tr("D&raw cards..."));
|
|
aUndoDraw->setText(tr("&Undo last draw"));
|
|
aMulligan->setText(tr("Take &mulligan"));
|
|
aShuffle->setText(tr("&Shuffle"));
|
|
aMoveTopToPlay->setText(tr("Play top card"));
|
|
aMoveTopToPlayFaceDown->setText(tr("Play top card &face down"));
|
|
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"));
|
|
aMoveBottomCardToGrave->setText(tr("Put bottom card &in graveyard"));
|
|
|
|
handMenu->setTitle(tr("&Hand"));
|
|
mRevealHand->setTitle(tr("&Reveal hand to..."));
|
|
mRevealRandomHandCard->setTitle(tr("Reveal r&andom card to..."));
|
|
mRevealRandomGraveyardCard->setTitle(tr("Reveal random card to..."));
|
|
sbMenu->setTitle(tr("&Sideboard"));
|
|
libraryMenu->setTitle(tr("&Library"));
|
|
countersMenu->setTitle(tr("&Counters"));
|
|
|
|
aUntapAll->setText(tr("&Untap all permanents"));
|
|
aRollDie->setText(tr("R&oll die..."));
|
|
aCreateToken->setText(tr("&Create token..."));
|
|
aCreateAnotherToken->setText(tr("C&reate another token"));
|
|
createPredefinedTokenMenu->setTitle(tr("Cr&eate predefined token"));
|
|
|
|
QMapIterator<int, AbstractCounter *> counterIterator(counters);
|
|
while (counterIterator.hasNext()) {
|
|
counterIterator.next().value()->retranslateUi();
|
|
}
|
|
|
|
aCardMenu->setText(tr("C&ard"));
|
|
|
|
for (auto &allPlayersAction : allPlayersActions) {
|
|
allPlayersAction->setText(tr("&All players"));
|
|
}
|
|
}
|
|
|
|
if (local) {
|
|
sayMenu->setTitle(tr("S&ay"));
|
|
}
|
|
|
|
aPlay->setText(tr("&Play"));
|
|
aHide->setText(tr("&Hide"));
|
|
aPlayFacedown->setText(tr("Play &Face Down"));
|
|
//: Turn sideways or back again
|
|
aTap->setText(tr("&Tap / Untap"));
|
|
aDoesntUntap->setText(tr("Toggle &normal untapping"));
|
|
//: Turn face up/face down
|
|
aFlip->setText(tr("T&urn Over")); // Only the user facing names in client got renamed to "turn over"
|
|
// All code and proto bits are still unchanged (flip) for compatibility reasons
|
|
// A protocol rewrite with v3 could incorporate that, see #3100
|
|
aPeek->setText(tr("&Peek at card face"));
|
|
aClone->setText(tr("&Clone"));
|
|
aAttach->setText(tr("Attac&h to card..."));
|
|
aUnattach->setText(tr("Unattac&h"));
|
|
aDrawArrow->setText(tr("&Draw arrow..."));
|
|
aIncP->setText(tr("&Increase power"));
|
|
aDecP->setText(tr("&Decrease power"));
|
|
aIncT->setText(tr("I&ncrease toughness"));
|
|
aDecT->setText(tr("D&ecrease toughness"));
|
|
aIncPT->setText(tr("In&crease power and toughness"));
|
|
aDecPT->setText(tr("Dec&rease power and toughness"));
|
|
aFlowP->setText(tr("Increase power and decrease toughness"));
|
|
aFlowT->setText(tr("Decrease power and increase toughness"));
|
|
aSetPT->setText(tr("Set &power and toughness..."));
|
|
aResetPT->setText(tr("Reset p&ower and toughness"));
|
|
aSetAnnotation->setText(tr("&Set annotation..."));
|
|
|
|
QStringList counterColors;
|
|
counterColors.append(tr("Red"));
|
|
counterColors.append(tr("Yellow"));
|
|
counterColors.append(tr("Green"));
|
|
|
|
for (int i = 0; i < aAddCounter.size(); ++i) {
|
|
aAddCounter[i]->setText(tr("&Add counter (%1)").arg(counterColors[i]));
|
|
}
|
|
for (int i = 0; i < aRemoveCounter.size(); ++i) {
|
|
aRemoveCounter[i]->setText(tr("&Remove counter (%1)").arg(counterColors[i]));
|
|
}
|
|
for (int i = 0; i < aSetCounter.size(); ++i) {
|
|
aSetCounter[i]->setText(tr("&Set counters (%1)...").arg(counterColors[i]));
|
|
}
|
|
|
|
aMoveToTopLibrary->setText(tr("&Top of library"));
|
|
aMoveToXfromTopOfLibrary->setText(tr("X cards from the top of library..."));
|
|
aMoveToBottomLibrary->setText(tr("&Bottom of library in random order"));
|
|
aMoveToHand->setText(tr("&Hand"));
|
|
aMoveToGraveyard->setText(tr("&Graveyard"));
|
|
aMoveToExile->setText(tr("&Exile"));
|
|
|
|
QMapIterator<QString, CardZone *> zoneIterator(zones);
|
|
while (zoneIterator.hasNext()) {
|
|
zoneIterator.next().value()->retranslateUi();
|
|
}
|
|
}
|
|
|
|
void Player::setShortcutsActive()
|
|
{
|
|
shortcutsActive = true;
|
|
ShortcutsSettings &shortcuts = settingsCache->shortcuts();
|
|
|
|
aPlay->setShortcuts(shortcuts.getShortcut("Player/aPlay"));
|
|
aTap->setShortcuts(shortcuts.getShortcut("Player/aTap"));
|
|
aDoesntUntap->setShortcuts(shortcuts.getShortcut("Player/aDoesntUntap"));
|
|
aFlip->setShortcuts(shortcuts.getShortcut("Player/aFlip"));
|
|
aPeek->setShortcuts(shortcuts.getShortcut("Player/aPeek"));
|
|
aClone->setShortcuts(shortcuts.getShortcut("Player/aClone"));
|
|
aAttach->setShortcuts(shortcuts.getShortcut("Player/aAttach"));
|
|
aUnattach->setShortcuts(shortcuts.getShortcut("Player/aUnattach"));
|
|
aDrawArrow->setShortcuts(shortcuts.getShortcut("Player/aDrawArrow"));
|
|
aIncP->setShortcuts(shortcuts.getShortcut("Player/aIncP"));
|
|
aDecP->setShortcuts(shortcuts.getShortcut("Player/aDecP"));
|
|
aIncT->setShortcuts(shortcuts.getShortcut("Player/aIncT"));
|
|
aDecT->setShortcuts(shortcuts.getShortcut("Player/aDecT"));
|
|
aIncPT->setShortcuts(shortcuts.getShortcut("Player/aIncPT"));
|
|
aDecPT->setShortcuts(shortcuts.getShortcut("Player/aDecPT"));
|
|
aFlowP->setShortcuts(shortcuts.getShortcut("Player/aFlowP"));
|
|
aFlowT->setShortcuts(shortcuts.getShortcut("Player/aFlowT"));
|
|
aSetPT->setShortcuts(shortcuts.getShortcut("Player/aSetPT"));
|
|
aResetPT->setShortcuts(shortcuts.getShortcut("Player/aResetPT"));
|
|
aSetAnnotation->setShortcuts(shortcuts.getShortcut("Player/aSetAnnotation"));
|
|
aMoveToTopLibrary->setShortcuts(shortcuts.getShortcut("Player/aMoveToTopLibrary"));
|
|
aMoveToBottomLibrary->setShortcuts(shortcuts.getShortcut("Player/aMoveToBottomLibrary"));
|
|
aMoveToHand->setShortcuts(shortcuts.getShortcut("Player/aMoveToHand"));
|
|
aMoveToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveToGraveyard"));
|
|
aMoveToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveToExile"));
|
|
|
|
QList<QKeySequence> addCCShortCuts;
|
|
addCCShortCuts.append(shortcuts.getSingleShortcut("Player/aCCRed"));
|
|
addCCShortCuts.append(shortcuts.getSingleShortcut("Player/aCCYellow"));
|
|
addCCShortCuts.append(shortcuts.getSingleShortcut("Player/aCCGreen"));
|
|
|
|
QList<QKeySequence> removeCCShortCuts;
|
|
removeCCShortCuts.append(shortcuts.getSingleShortcut("Player/aRCRed"));
|
|
removeCCShortCuts.append(shortcuts.getSingleShortcut("Player/aRCYellow"));
|
|
removeCCShortCuts.append(shortcuts.getSingleShortcut("Player/aRCGreen"));
|
|
|
|
QList<QKeySequence> setCCShortCuts;
|
|
setCCShortCuts.append(shortcuts.getSingleShortcut("Player/aSCRed"));
|
|
setCCShortCuts.append(shortcuts.getSingleShortcut("Player/aSCYellow"));
|
|
setCCShortCuts.append(shortcuts.getSingleShortcut("Player/aSCGreen"));
|
|
|
|
for (int i = 0; i < aAddCounter.size(); ++i) {
|
|
aAddCounter[i]->setShortcut(addCCShortCuts.at(i));
|
|
}
|
|
for (int i = 0; i < aRemoveCounter.size(); ++i) {
|
|
aRemoveCounter[i]->setShortcut(removeCCShortCuts.at(i));
|
|
}
|
|
for (int i = 0; i < aSetCounter.size(); ++i) {
|
|
aSetCounter[i]->setShortcut(setCCShortCuts.at(i));
|
|
}
|
|
|
|
QMapIterator<int, AbstractCounter *> counterIterator(counters);
|
|
while (counterIterator.hasNext()) {
|
|
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"));
|
|
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"));
|
|
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"));
|
|
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"));
|
|
}
|
|
|
|
void Player::setShortcutsInactive()
|
|
{
|
|
shortcutsActive = false;
|
|
|
|
aViewSideboard->setShortcut(QKeySequence());
|
|
aViewLibrary->setShortcut(QKeySequence());
|
|
aViewHand->setShortcut(QKeySequence());
|
|
aViewTopCards->setShortcut(QKeySequence());
|
|
aViewGraveyard->setShortcut(QKeySequence());
|
|
aDrawCard->setShortcut(QKeySequence());
|
|
aDrawCards->setShortcut(QKeySequence());
|
|
aUndoDraw->setShortcut(QKeySequence());
|
|
aMulligan->setShortcut(QKeySequence());
|
|
aShuffle->setShortcut(QKeySequence());
|
|
aUntapAll->setShortcut(QKeySequence());
|
|
aRollDie->setShortcut(QKeySequence());
|
|
aCreateToken->setShortcut(QKeySequence());
|
|
aCreateAnotherToken->setShortcut(QKeySequence());
|
|
aAlwaysRevealTopCard->setShortcut(QKeySequence());
|
|
aMoveTopToPlay->setShortcut(QKeySequence());
|
|
aMoveTopToPlayFaceDown->setShortcut(QKeySequence());
|
|
aMoveTopCardToGraveyard->setShortcut(QKeySequence());
|
|
aMoveTopCardsToGraveyard->setShortcut(QKeySequence());
|
|
aMoveTopCardToExile->setShortcut(QKeySequence());
|
|
aMoveTopCardsToExile->setShortcut(QKeySequence());
|
|
|
|
QMapIterator<int, AbstractCounter *> counterIterator(counters);
|
|
while (counterIterator.hasNext()) {
|
|
counterIterator.next().value()->setShortcutsInactive();
|
|
}
|
|
}
|
|
|
|
void Player::initSayMenu()
|
|
{
|
|
sayMenu->clear();
|
|
|
|
int count = settingsCache->messages().getCount();
|
|
|
|
for (int i = 0; i < count; ++i) {
|
|
QAction *newAction = new QAction(settingsCache->messages().getMessageAt(i), this);
|
|
if (i <= 10) {
|
|
newAction->setShortcut(QKeySequence("Ctrl+" + QString::number((i + 1) % 10)));
|
|
}
|
|
connect(newAction, SIGNAL(triggered()), this, SLOT(actSayMessage()));
|
|
sayMenu->addAction(newAction);
|
|
}
|
|
}
|
|
|
|
void Player::setDeck(const DeckLoader &_deck)
|
|
{
|
|
deck = new DeckLoader(_deck);
|
|
aOpenDeckInDeckEditor->setEnabled(deck);
|
|
|
|
createPredefinedTokenMenu->clear();
|
|
predefinedTokens.clear();
|
|
InnerDecklistNode *tokenZone = dynamic_cast<InnerDecklistNode *>(deck->getRoot()->findChild(DECK_ZONE_TOKENS));
|
|
|
|
if (tokenZone)
|
|
for (int i = 0; i < tokenZone->size(); ++i) {
|
|
const QString tokenName = tokenZone->at(i)->getName();
|
|
predefinedTokens.append(tokenName);
|
|
QAction *a = createPredefinedTokenMenu->addAction(tokenName);
|
|
if (i < 10) {
|
|
a->setShortcut(QKeySequence("Alt+" + QString::number((i + 1) % 10)));
|
|
}
|
|
connect(a, SIGNAL(triggered()), this, SLOT(actCreatePredefinedToken()));
|
|
}
|
|
}
|
|
|
|
void Player::actViewLibrary()
|
|
{
|
|
static_cast<GameScene *>(scene())->toggleZoneView(this, "deck", -1);
|
|
}
|
|
|
|
void Player::actViewHand()
|
|
{
|
|
static_cast<GameScene *>(scene())->toggleZoneView(this, "hand", -1);
|
|
}
|
|
|
|
void Player::actViewTopCards()
|
|
{
|
|
bool ok;
|
|
int number = QInputDialog::getInt(game, tr("View top cards of library"), tr("Number of cards:"),
|
|
defaultNumberTopCards, 1, 2000000000, 1, &ok);
|
|
if (ok) {
|
|
defaultNumberTopCards = number;
|
|
static_cast<GameScene *>(scene())->toggleZoneView(this, "deck", number);
|
|
}
|
|
}
|
|
|
|
void Player::actAlwaysRevealTopCard()
|
|
{
|
|
Command_ChangeZoneProperties cmd;
|
|
cmd.set_zone_name("deck");
|
|
cmd.set_always_reveal_top_card(aAlwaysRevealTopCard->isChecked());
|
|
|
|
sendGameCommand(cmd);
|
|
}
|
|
|
|
void Player::actOpenDeckInDeckEditor()
|
|
{
|
|
emit openDeckEditor(deck);
|
|
}
|
|
|
|
void Player::actViewGraveyard()
|
|
{
|
|
dynamic_cast<GameScene *>(scene())->toggleZoneView(this, "grave", -1);
|
|
}
|
|
|
|
void Player::actRevealRandomGraveyardCard()
|
|
{
|
|
Command_RevealCards cmd;
|
|
auto *action = dynamic_cast<QAction *>(sender());
|
|
const int otherPlayerId = action->data().toInt();
|
|
if (otherPlayerId != -1) {
|
|
cmd.set_player_id(otherPlayerId);
|
|
}
|
|
cmd.set_zone_name("grave");
|
|
cmd.set_card_id(RANDOM_CARD_FROM_ZONE);
|
|
sendGameCommand(cmd);
|
|
}
|
|
|
|
void Player::actViewRfg()
|
|
{
|
|
static_cast<GameScene *>(scene())->toggleZoneView(this, "rfg", -1);
|
|
}
|
|
|
|
void Player::actViewSideboard()
|
|
{
|
|
static_cast<GameScene *>(scene())->toggleZoneView(this, "sb", -1);
|
|
}
|
|
|
|
void Player::actShuffle()
|
|
{
|
|
sendGameCommand(Command_Shuffle());
|
|
}
|
|
|
|
void Player::actDrawCard()
|
|
{
|
|
Command_DrawCards cmd;
|
|
cmd.set_number(1);
|
|
sendGameCommand(cmd);
|
|
}
|
|
|
|
void Player::actMulligan()
|
|
{
|
|
int startSize = settingsCache->getStartingHandSize();
|
|
int handSize = zones.value("hand")->getCards().size();
|
|
int deckSize = zones.value("deck")->getCards().size() + handSize;
|
|
bool ok;
|
|
int number = QInputDialog::getInt(
|
|
game, tr("Draw hand"), tr("Number of cards:") + '\n' + tr("0 and lower are in comparison to current hand size"),
|
|
startSize, -handSize, deckSize, 1, &ok);
|
|
if (!ok) {
|
|
return;
|
|
}
|
|
Command_Mulligan cmd;
|
|
if (number < 1) {
|
|
if (handSize == 0) {
|
|
return;
|
|
}
|
|
cmd.set_number(handSize + number);
|
|
} else {
|
|
cmd.set_number(number);
|
|
}
|
|
sendGameCommand(cmd);
|
|
if (startSize != number) {
|
|
settingsCache->setStartingHandSize(number);
|
|
}
|
|
}
|
|
|
|
void Player::actDrawCards()
|
|
{
|
|
int number = QInputDialog::getInt(game, tr("Draw cards"), tr("Number:"));
|
|
if (number) {
|
|
Command_DrawCards cmd;
|
|
cmd.set_number(static_cast<google::protobuf::uint32>(number));
|
|
sendGameCommand(cmd);
|
|
}
|
|
}
|
|
|
|
void Player::actUndoDraw()
|
|
{
|
|
sendGameCommand(Command_UndoDraw());
|
|
}
|
|
|
|
void Player::actMoveTopCardToGrave()
|
|
{
|
|
if (zones.value("deck")->getCards().empty()) {
|
|
return;
|
|
}
|
|
|
|
Command_MoveCard cmd;
|
|
cmd.set_start_zone("deck");
|
|
cmd.mutable_cards_to_move()->add_card()->set_card_id(0);
|
|
cmd.set_target_player_id(getId());
|
|
cmd.set_target_zone("grave");
|
|
cmd.set_x(0);
|
|
cmd.set_y(0);
|
|
|
|
sendGameCommand(cmd);
|
|
}
|
|
|
|
void Player::actMoveTopCardToExile()
|
|
{
|
|
if (zones.value("deck")->getCards().empty()) {
|
|
return;
|
|
}
|
|
|
|
Command_MoveCard cmd;
|
|
cmd.set_start_zone("deck");
|
|
cmd.mutable_cards_to_move()->add_card()->set_card_id(0);
|
|
cmd.set_target_player_id(getId());
|
|
cmd.set_target_zone("rfg");
|
|
cmd.set_x(0);
|
|
cmd.set_y(0);
|
|
|
|
sendGameCommand(cmd);
|
|
}
|
|
|
|
void Player::actMoveTopCardsToGrave()
|
|
{
|
|
int number = QInputDialog::getInt(game, tr("Move top cards to grave"), tr("Number:"));
|
|
if (!number) {
|
|
return;
|
|
}
|
|
|
|
const int maxCards = zones.value("deck")->getCards().size();
|
|
if (number > maxCards) {
|
|
number = maxCards;
|
|
}
|
|
|
|
Command_MoveCard cmd;
|
|
cmd.set_start_zone("deck");
|
|
cmd.set_target_player_id(getId());
|
|
cmd.set_target_zone("grave");
|
|
cmd.set_x(0);
|
|
cmd.set_y(0);
|
|
|
|
for (int i = number - 1; i >= 0; --i) {
|
|
cmd.mutable_cards_to_move()->add_card()->set_card_id(i);
|
|
}
|
|
|
|
sendGameCommand(cmd);
|
|
}
|
|
|
|
void Player::actMoveTopCardsToExile()
|
|
{
|
|
int number = QInputDialog::getInt(game, tr("Move top cards to exile"), tr("Number:"));
|
|
if (!number) {
|
|
return;
|
|
}
|
|
|
|
const int maxCards = zones.value("deck")->getCards().size();
|
|
if (number > maxCards) {
|
|
number = maxCards;
|
|
}
|
|
|
|
Command_MoveCard cmd;
|
|
cmd.set_start_zone("deck");
|
|
cmd.set_target_player_id(getId());
|
|
cmd.set_target_zone("rfg");
|
|
cmd.set_x(0);
|
|
cmd.set_y(0);
|
|
|
|
for (int i = number - 1; i >= 0; --i) {
|
|
cmd.mutable_cards_to_move()->add_card()->set_card_id(i);
|
|
}
|
|
|
|
sendGameCommand(cmd);
|
|
}
|
|
|
|
void Player::actMoveTopCardToBottom()
|
|
{
|
|
Command_MoveCard cmd;
|
|
cmd.set_start_zone("deck");
|
|
cmd.mutable_cards_to_move()->add_card()->set_card_id(0);
|
|
cmd.set_target_player_id(getId());
|
|
cmd.set_target_zone("deck");
|
|
cmd.set_x(-1);
|
|
cmd.set_y(0);
|
|
|
|
sendGameCommand(cmd);
|
|
}
|
|
|
|
void Player::actMoveTopCardToPlay()
|
|
{
|
|
Command_MoveCard cmd;
|
|
cmd.set_start_zone("deck");
|
|
CardToMove *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
|
cardToMove->set_card_id(0);
|
|
cmd.set_target_player_id(getId());
|
|
cmd.set_target_zone("stack");
|
|
cmd.set_x(-1);
|
|
cmd.set_y(0);
|
|
|
|
sendGameCommand(cmd);
|
|
}
|
|
|
|
void Player::actMoveTopCardToPlayFaceDown()
|
|
{
|
|
Command_MoveCard cmd;
|
|
cmd.set_start_zone("deck");
|
|
CardToMove *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
|
cardToMove->set_card_id(0);
|
|
cardToMove->set_face_down(true);
|
|
cmd.set_target_player_id(getId());
|
|
cmd.set_target_zone("table");
|
|
cmd.set_x(-1);
|
|
cmd.set_y(0);
|
|
|
|
sendGameCommand(cmd);
|
|
}
|
|
|
|
void Player::actMoveBottomCardToGrave()
|
|
{
|
|
CardZone *zone = zones.value("deck");
|
|
Command_MoveCard cmd;
|
|
cmd.set_start_zone("deck");
|
|
cmd.mutable_cards_to_move()->add_card()->set_card_id(zone->getCards().size() - 1);
|
|
cmd.set_target_player_id(getId());
|
|
cmd.set_target_zone("grave");
|
|
cmd.set_x(0);
|
|
cmd.set_y(0);
|
|
|
|
sendGameCommand(cmd);
|
|
}
|
|
|
|
void Player::actUntapAll()
|
|
{
|
|
Command_SetCardAttr cmd;
|
|
cmd.set_zone("table");
|
|
cmd.set_attribute(AttrTapped);
|
|
cmd.set_attr_value("0");
|
|
|
|
sendGameCommand(cmd);
|
|
}
|
|
|
|
void Player::actRollDie()
|
|
{
|
|
bool ok;
|
|
int sides = QInputDialog::getInt(game, tr("Roll die"), tr("Number of sides:"), 20, 2, 1000, 1, &ok);
|
|
if (ok) {
|
|
Command_RollDie cmd;
|
|
cmd.set_sides(static_cast<google::protobuf::uint32>(sides));
|
|
sendGameCommand(cmd);
|
|
}
|
|
}
|
|
|
|
void Player::actCreateToken()
|
|
{
|
|
DlgCreateToken dlg(predefinedTokens, game);
|
|
if (!dlg.exec()) {
|
|
return;
|
|
}
|
|
|
|
lastTokenName = dlg.getName();
|
|
lastTokenPT = dlg.getPT();
|
|
CardInfoPtr correctedCard = db->getCardBySimpleName(lastTokenName);
|
|
if (correctedCard) {
|
|
lastTokenName = correctedCard->getName();
|
|
lastTokenTableRow = TableZone::clampValidTableRow(2 - correctedCard->getTableRow());
|
|
if (lastTokenPT.isEmpty()) {
|
|
lastTokenPT = correctedCard->getPowTough();
|
|
}
|
|
}
|
|
lastTokenColor = dlg.getColor();
|
|
lastTokenAnnotation = dlg.getAnnotation();
|
|
lastTokenDestroy = dlg.getDestroy();
|
|
aCreateAnotherToken->setEnabled(true);
|
|
aCreateAnotherToken->setText(tr("C&reate another %1 token").arg(lastTokenName));
|
|
actCreateAnotherToken();
|
|
}
|
|
|
|
void Player::actCreateAnotherToken()
|
|
{
|
|
if (lastTokenName.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
Command_CreateToken cmd;
|
|
cmd.set_zone("table");
|
|
cmd.set_card_name(lastTokenName.toStdString());
|
|
cmd.set_color(lastTokenColor.toStdString());
|
|
cmd.set_pt(lastTokenPT.toStdString());
|
|
cmd.set_annotation(lastTokenAnnotation.toStdString());
|
|
cmd.set_destroy_on_zone_change(lastTokenDestroy);
|
|
cmd.set_x(-1);
|
|
cmd.set_y(lastTokenTableRow);
|
|
|
|
sendGameCommand(cmd);
|
|
}
|
|
|
|
void Player::actCreatePredefinedToken()
|
|
{
|
|
auto *action = static_cast<QAction *>(sender());
|
|
CardInfoPtr cardInfo = db->getCard(action->text());
|
|
if (!cardInfo) {
|
|
return;
|
|
}
|
|
|
|
setLastToken(cardInfo);
|
|
|
|
actCreateAnotherToken();
|
|
}
|
|
|
|
void Player::actCreateRelatedCard()
|
|
{
|
|
CardItem *sourceCard = game->getActiveCard();
|
|
if (!sourceCard) {
|
|
return;
|
|
}
|
|
auto *action = static_cast<QAction *>(sender());
|
|
// If there is a better way of passing a CardRelation through a QAction, please add it here.
|
|
auto relatedCards = sourceCard->getInfo()->getAllRelatedCards();
|
|
CardRelation *cardRelation = relatedCards.at(action->data().toInt());
|
|
|
|
/*
|
|
* If we make a token via "Token: TokenName"
|
|
* then let's allow it to be created via "create another token"
|
|
*/
|
|
if (createRelatedFromRelation(sourceCard, cardRelation) && cardRelation->getCanCreateAnother()) {
|
|
CardInfoPtr cardInfo = db->getCard(cardRelation->getName());
|
|
setLastToken(cardInfo);
|
|
}
|
|
}
|
|
|
|
void Player::actCreateAllRelatedCards()
|
|
{
|
|
CardItem *sourceCard = game->getActiveCard();
|
|
if (!sourceCard) {
|
|
return;
|
|
}
|
|
|
|
auto relatedCards = sourceCard->getInfo()->getAllRelatedCards();
|
|
if (relatedCards.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
CardRelation *cardRelation = nullptr;
|
|
int tokensTypesCreated = 0;
|
|
|
|
if (relatedCards.length() == 1) {
|
|
cardRelation = relatedCards.at(0);
|
|
if (createRelatedFromRelation(sourceCard, cardRelation)) {
|
|
++tokensTypesCreated;
|
|
}
|
|
} else {
|
|
QList<CardRelation *> nonExcludedRelatedCards;
|
|
QString dbName;
|
|
for (CardRelation *cardRelationTemp : relatedCards) {
|
|
if (!cardRelationTemp->getIsCreateAllExclusion() && !cardRelationTemp->getDoesAttach()) {
|
|
nonExcludedRelatedCards.append(cardRelationTemp);
|
|
}
|
|
}
|
|
switch (nonExcludedRelatedCards.length()) {
|
|
case 1: // if nonExcludedRelatedCards == 1
|
|
cardRelation = nonExcludedRelatedCards.at(0);
|
|
if (createRelatedFromRelation(sourceCard, cardRelation)) {
|
|
++tokensTypesCreated;
|
|
}
|
|
break;
|
|
// If all are marked "Exclude", then treat the situation as if none of them are.
|
|
// We won't accept "garbage in, garbage out", here.
|
|
case 0: // else if nonExcludedRelatedCards == 0
|
|
for (CardRelation *cardRelationAll : relatedCards) {
|
|
if (!cardRelationAll->getDoesAttach() && !cardRelationAll->getIsVariable()) {
|
|
dbName = cardRelationAll->getName();
|
|
for (int i = 0; i < cardRelationAll->getDefaultCount(); ++i) {
|
|
createCard(sourceCard, dbName);
|
|
}
|
|
++tokensTypesCreated;
|
|
if (tokensTypesCreated == 1) {
|
|
cardRelation = cardRelationAll;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default: // else
|
|
for (CardRelation *cardRelationNotExcluded : nonExcludedRelatedCards) {
|
|
if (!cardRelationNotExcluded->getDoesAttach() && !cardRelationNotExcluded->getIsVariable()) {
|
|
dbName = cardRelationNotExcluded->getName();
|
|
for (int i = 0; i < cardRelationNotExcluded->getDefaultCount(); ++i) {
|
|
createCard(sourceCard, dbName);
|
|
}
|
|
++tokensTypesCreated;
|
|
if (tokensTypesCreated == 1) {
|
|
cardRelation = cardRelationNotExcluded;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If we made at least one token via "Create All Tokens"
|
|
* then assign the first to the "Create another" shortcut.
|
|
*/
|
|
if (cardRelation != nullptr && cardRelation->getCanCreateAnother()) {
|
|
CardInfoPtr cardInfo = db->getCard(cardRelation->getName());
|
|
setLastToken(cardInfo);
|
|
}
|
|
}
|
|
|
|
bool Player::createRelatedFromRelation(const CardItem *sourceCard, const CardRelation *cardRelation)
|
|
{
|
|
if (sourceCard == nullptr || cardRelation == nullptr) {
|
|
return false;
|
|
}
|
|
QString dbName = cardRelation->getName();
|
|
if (cardRelation->getIsVariable()) {
|
|
bool ok;
|
|
dialogSemaphore = true;
|
|
int count = QInputDialog::getInt(game, tr("Create tokens"), tr("Number:"), cardRelation->getDefaultCount(), 1,
|
|
MAX_TOKENS_PER_DIALOG, 1, &ok);
|
|
dialogSemaphore = false;
|
|
if (!ok) {
|
|
return false;
|
|
}
|
|
for (int i = 0; i < count; ++i) {
|
|
createCard(sourceCard, dbName);
|
|
}
|
|
} else if (cardRelation->getDefaultCount() > 1) {
|
|
for (int i = 0; i < cardRelation->getDefaultCount(); ++i) {
|
|
createCard(sourceCard, dbName);
|
|
}
|
|
} else {
|
|
if (cardRelation->getDoesAttach()) {
|
|
createAttachedCard(sourceCard, dbName);
|
|
} else {
|
|
createCard(sourceCard, dbName);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void Player::createCard(const CardItem *sourceCard, const QString &dbCardName, bool attach)
|
|
{
|
|
CardInfoPtr cardInfo = db->getCard(dbCardName);
|
|
|
|
if (cardInfo == nullptr || sourceCard == nullptr) {
|
|
return;
|
|
}
|
|
|
|
// get the target token's location
|
|
// TODO: Define this QPoint into its own function along with the one below
|
|
QPoint gridPoint = QPoint(-1, TableZone::clampValidTableRow(2 - cardInfo->getTableRow()));
|
|
|
|
// create the token for the related card
|
|
Command_CreateToken cmd;
|
|
cmd.set_zone("table");
|
|
cmd.set_card_name(cardInfo->getName().toStdString());
|
|
switch (cardInfo->getColors().size()) {
|
|
case 0:
|
|
cmd.set_color("");
|
|
break;
|
|
case 1:
|
|
cmd.set_color("m");
|
|
break;
|
|
default:
|
|
cmd.set_color(cardInfo->getColors().left(1).toLower().toStdString());
|
|
break;
|
|
}
|
|
|
|
cmd.set_pt(cardInfo->getPowTough().toStdString());
|
|
if (settingsCache->getAnnotateTokens()) {
|
|
cmd.set_annotation(cardInfo->getText().toStdString());
|
|
} else {
|
|
cmd.set_annotation("");
|
|
}
|
|
cmd.set_destroy_on_zone_change(true);
|
|
cmd.set_target_zone(sourceCard->getZone()->getName().toStdString());
|
|
cmd.set_x(gridPoint.x());
|
|
cmd.set_y(gridPoint.y());
|
|
|
|
if (attach) {
|
|
cmd.set_target_card_id(sourceCard->getId());
|
|
}
|
|
|
|
sendGameCommand(cmd);
|
|
}
|
|
|
|
void Player::createAttachedCard(const CardItem *sourceCard, const QString &dbCardName)
|
|
{
|
|
createCard(sourceCard, dbCardName, true);
|
|
}
|
|
|
|
void Player::actSayMessage()
|
|
{
|
|
auto *a = qobject_cast<QAction *>(sender());
|
|
Command_GameSay cmd;
|
|
cmd.set_message(a->text().toStdString());
|
|
sendGameCommand(cmd);
|
|
}
|
|
|
|
void Player::setCardAttrHelper(const GameEventContext &context,
|
|
CardItem *card,
|
|
CardAttribute attribute,
|
|
const QString &avalue,
|
|
bool allCards)
|
|
{
|
|
if (card == nullptr) {
|
|
return;
|
|
}
|
|
|
|
bool moveCardContext = context.HasExtension(Context_MoveCard::ext);
|
|
switch (attribute) {
|
|
case AttrTapped: {
|
|
bool tapped = avalue == "1";
|
|
if (!(!tapped && card->getDoesntUntap() && allCards)) {
|
|
if (!allCards) {
|
|
emit logSetTapped(this, card, tapped);
|
|
}
|
|
card->setTapped(tapped, !moveCardContext);
|
|
}
|
|
break;
|
|
}
|
|
case AttrAttacking: {
|
|
card->setAttacking(avalue == "1");
|
|
break;
|
|
}
|
|
case AttrFaceDown: {
|
|
card->setFaceDown(avalue == "1");
|
|
break;
|
|
}
|
|
case AttrColor: {
|
|
card->setColor(avalue);
|
|
break;
|
|
}
|
|
case AttrAnnotation: {
|
|
emit logSetAnnotation(this, card, avalue);
|
|
card->setAnnotation(avalue);
|
|
break;
|
|
}
|
|
case AttrDoesntUntap: {
|
|
bool value = (avalue == "1");
|
|
emit logSetDoesntUntap(this, card, value);
|
|
card->setDoesntUntap(value);
|
|
break;
|
|
}
|
|
case AttrPT: {
|
|
emit logSetPT(this, card, avalue);
|
|
card->setPT(avalue);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::eventGameSay(const Event_GameSay &event)
|
|
{
|
|
emit logSay(this, QString::fromStdString(event.message()));
|
|
}
|
|
|
|
void Player::eventShuffle(const Event_Shuffle &event)
|
|
{
|
|
CardZone *zone = zones.value(QString::fromStdString(event.zone_name()));
|
|
if (!zone) {
|
|
return;
|
|
}
|
|
if (zone->getView() && zone->getView()->getRevealZone()) {
|
|
zone->getView()->setWriteableRevealZone(false);
|
|
}
|
|
emit logShuffle(this, zone, event.start(), event.end());
|
|
}
|
|
|
|
void Player::eventRollDie(const Event_RollDie &event)
|
|
{
|
|
emit logRollDie(this, event.sides(), event.value());
|
|
}
|
|
|
|
void Player::eventCreateArrow(const Event_CreateArrow &event)
|
|
{
|
|
ArrowItem *arrow = addArrow(event.arrow_info());
|
|
if (!arrow) {
|
|
return;
|
|
}
|
|
|
|
auto *startCard = static_cast<CardItem *>(arrow->getStartItem());
|
|
auto *targetCard = qgraphicsitem_cast<CardItem *>(arrow->getTargetItem());
|
|
if (targetCard) {
|
|
emit logCreateArrow(this, startCard->getOwner(), startCard->getName(), targetCard->getOwner(),
|
|
targetCard->getName(), false);
|
|
} else {
|
|
emit logCreateArrow(this, startCard->getOwner(), startCard->getName(), arrow->getTargetItem()->getOwner(),
|
|
QString(), true);
|
|
}
|
|
}
|
|
|
|
void Player::eventDeleteArrow(const Event_DeleteArrow &event)
|
|
{
|
|
delArrow(event.arrow_id());
|
|
}
|
|
|
|
void Player::eventCreateToken(const Event_CreateToken &event)
|
|
{
|
|
CardZone *zone = zones.value(QString::fromStdString(event.zone_name()), 0);
|
|
if (!zone) {
|
|
return;
|
|
}
|
|
|
|
CardItem *card = new CardItem(this, QString::fromStdString(event.card_name()), event.card_id());
|
|
// use db PT if not provided in event
|
|
if (!QString::fromStdString(event.pt()).isEmpty()) {
|
|
card->setPT(QString::fromStdString(event.pt()));
|
|
} else {
|
|
CardInfoPtr dbCard = card->getInfo();
|
|
if (dbCard) {
|
|
card->setPT(dbCard->getPowTough());
|
|
}
|
|
}
|
|
card->setColor(QString::fromStdString(event.color()));
|
|
card->setAnnotation(QString::fromStdString(event.annotation()));
|
|
card->setDestroyOnZoneChange(event.destroy_on_zone_change());
|
|
|
|
emit logCreateToken(this, card->getName(), card->getPT());
|
|
zone->addCard(card, true, event.x(), event.y());
|
|
}
|
|
|
|
void Player::eventSetCardAttr(const Event_SetCardAttr &event, const GameEventContext &context)
|
|
{
|
|
CardZone *zone = zones.value(QString::fromStdString(event.zone_name()), 0);
|
|
if (!zone) {
|
|
return;
|
|
}
|
|
|
|
if (!event.has_card_id()) {
|
|
const CardList &cards = zone->getCards();
|
|
for (int i = 0; i < cards.size(); ++i) {
|
|
setCardAttrHelper(context, cards.at(i), event.attribute(), QString::fromStdString(event.attr_value()),
|
|
true);
|
|
}
|
|
if (event.attribute() == AttrTapped) {
|
|
emit logSetTapped(this, nullptr, event.attr_value() == "1");
|
|
}
|
|
} else {
|
|
CardItem *card = zone->getCard(event.card_id(), QString());
|
|
if (!card) {
|
|
qDebug() << "Player::eventSetCardAttr: card id=" << event.card_id() << "not found";
|
|
return;
|
|
}
|
|
setCardAttrHelper(context, card, event.attribute(), QString::fromStdString(event.attr_value()), false);
|
|
}
|
|
}
|
|
|
|
void Player::eventSetCardCounter(const Event_SetCardCounter &event)
|
|
{
|
|
CardZone *zone = zones.value(QString::fromStdString(event.zone_name()), 0);
|
|
if (!zone) {
|
|
return;
|
|
}
|
|
|
|
CardItem *card = zone->getCard(event.card_id(), QString());
|
|
if (!card) {
|
|
return;
|
|
}
|
|
|
|
int oldValue = card->getCounters().value(event.counter_id(), 0);
|
|
card->setCounter(event.counter_id(), event.counter_value());
|
|
updateCardMenu(card);
|
|
emit logSetCardCounter(this, card->getName(), event.counter_id(), event.counter_value(), oldValue);
|
|
}
|
|
|
|
void Player::eventCreateCounter(const Event_CreateCounter &event)
|
|
{
|
|
addCounter(event.counter_info());
|
|
}
|
|
|
|
void Player::eventSetCounter(const Event_SetCounter &event)
|
|
{
|
|
AbstractCounter *ctr = counters.value(event.counter_id(), 0);
|
|
if (!ctr) {
|
|
return;
|
|
}
|
|
int oldValue = ctr->getValue();
|
|
ctr->setValue(event.value());
|
|
emit logSetCounter(this, ctr->getName(), event.value(), oldValue);
|
|
}
|
|
|
|
void Player::eventDelCounter(const Event_DelCounter &event)
|
|
{
|
|
delCounter(event.counter_id());
|
|
}
|
|
|
|
void Player::eventDumpZone(const Event_DumpZone &event)
|
|
{
|
|
Player *zoneOwner = game->getPlayers().value(event.zone_owner_id(), 0);
|
|
if (!zoneOwner) {
|
|
return;
|
|
}
|
|
CardZone *zone = zoneOwner->getZones().value(QString::fromStdString(event.zone_name()), 0);
|
|
if (!zone) {
|
|
return;
|
|
}
|
|
emit logDumpZone(this, zone, event.number_cards());
|
|
}
|
|
|
|
void Player::eventStopDumpZone(const Event_StopDumpZone &event)
|
|
{
|
|
Player *zoneOwner = game->getPlayers().value(event.zone_owner_id(), 0);
|
|
if (!zoneOwner) {
|
|
return;
|
|
}
|
|
CardZone *zone = zoneOwner->getZones().value(QString::fromStdString(event.zone_name()), 0);
|
|
if (!zone) {
|
|
return;
|
|
}
|
|
emit logStopDumpZone(this, zone);
|
|
}
|
|
|
|
void Player::eventMoveCard(const Event_MoveCard &event, const GameEventContext &context)
|
|
{
|
|
Player *startPlayer = game->getPlayers().value(event.start_player_id());
|
|
if (!startPlayer) {
|
|
return;
|
|
}
|
|
CardZone *startZone = startPlayer->getZones().value(QString::fromStdString(event.start_zone()), 0);
|
|
Player *targetPlayer = game->getPlayers().value(event.target_player_id());
|
|
if (!targetPlayer) {
|
|
return;
|
|
}
|
|
CardZone *targetZone;
|
|
if (event.has_target_zone()) {
|
|
targetZone = targetPlayer->getZones().value(QString::fromStdString(event.target_zone()), 0);
|
|
} else {
|
|
targetZone = startZone;
|
|
}
|
|
if (!startZone || !targetZone) {
|
|
return;
|
|
}
|
|
|
|
int position = event.position();
|
|
int x = event.x();
|
|
int y = event.y();
|
|
|
|
int logPosition = position;
|
|
int logX = x;
|
|
if (x == -1) {
|
|
x = 0;
|
|
}
|
|
CardItem *card = startZone->takeCard(position, event.card_id(), startZone != targetZone);
|
|
if (!card) {
|
|
return;
|
|
}
|
|
if (startZone != targetZone) {
|
|
card->deleteCardInfoPopup();
|
|
}
|
|
if (event.has_card_name()) {
|
|
card->setName(QString::fromStdString(event.card_name()));
|
|
}
|
|
|
|
if (card->getAttachedTo() && (startZone != targetZone)) {
|
|
CardItem *parentCard = card->getAttachedTo();
|
|
card->setAttachedTo(nullptr);
|
|
parentCard->getZone()->reorganizeCards();
|
|
}
|
|
|
|
card->deleteDragItem();
|
|
|
|
card->setId(event.new_card_id());
|
|
card->setFaceDown(event.face_down());
|
|
if (startZone != targetZone) {
|
|
card->setBeingPointedAt(false);
|
|
card->setHovered(false);
|
|
|
|
const QList<CardItem *> &attachedCards = card->getAttachedCards();
|
|
for (auto attachedCard : attachedCards) {
|
|
attachedCard->setParentItem(targetZone);
|
|
}
|
|
|
|
if (startZone->getPlayer() != targetZone->getPlayer()) {
|
|
card->setOwner(targetZone->getPlayer());
|
|
}
|
|
}
|
|
|
|
// The log event has to be sent before the card is added to the target zone
|
|
// because the addCard function can modify the card object.
|
|
if (context.HasExtension(Context_UndoDraw::ext)) {
|
|
emit logUndoDraw(this, card->getName());
|
|
} else {
|
|
emit logMoveCard(this, card, startZone, logPosition, targetZone, logX);
|
|
}
|
|
|
|
targetZone->addCard(card, true, x, y);
|
|
|
|
// Look at all arrows from and to the card.
|
|
// If the card was moved to another zone, delete the arrows, otherwise update them.
|
|
QMapIterator<int, Player *> playerIterator(game->getPlayers());
|
|
while (playerIterator.hasNext()) {
|
|
Player *p = playerIterator.next().value();
|
|
|
|
QList<ArrowItem *> arrowsToDelete;
|
|
QMapIterator<int, ArrowItem *> arrowIterator(p->getArrows());
|
|
while (arrowIterator.hasNext()) {
|
|
ArrowItem *arrow = arrowIterator.next().value();
|
|
if ((arrow->getStartItem() == card) || (arrow->getTargetItem() == card)) {
|
|
if (startZone == targetZone) {
|
|
arrow->updatePath();
|
|
} else {
|
|
arrowsToDelete.append(arrow);
|
|
}
|
|
}
|
|
}
|
|
for (auto &i : arrowsToDelete) {
|
|
i->delArrow();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::eventFlipCard(const Event_FlipCard &event)
|
|
{
|
|
CardZone *zone = zones.value(QString::fromStdString(event.zone_name()), 0);
|
|
if (!zone) {
|
|
return;
|
|
}
|
|
CardItem *card = zone->getCard(event.card_id(), QString::fromStdString(event.card_name()));
|
|
if (!card) {
|
|
return;
|
|
}
|
|
emit logFlipCard(this, card->getName(), event.face_down());
|
|
card->setFaceDown(event.face_down());
|
|
}
|
|
|
|
void Player::eventDestroyCard(const Event_DestroyCard &event)
|
|
{
|
|
CardZone *zone = zones.value(QString::fromStdString(event.zone_name()), 0);
|
|
if (!zone) {
|
|
return;
|
|
}
|
|
|
|
CardItem *card = zone->getCard(event.card_id(), QString());
|
|
if (!card) {
|
|
return;
|
|
}
|
|
|
|
QList<CardItem *> attachedCards = card->getAttachedCards();
|
|
// This list is always empty except for buggy server implementations.
|
|
for (auto &attachedCard : attachedCards) {
|
|
attachedCard->setAttachedTo(0);
|
|
}
|
|
|
|
emit logDestroyCard(this, card->getName());
|
|
zone->takeCard(-1, event.card_id(), true);
|
|
card->deleteLater();
|
|
}
|
|
|
|
void Player::eventAttachCard(const Event_AttachCard &event)
|
|
{
|
|
const QMap<int, Player *> &playerList = game->getPlayers();
|
|
Player *targetPlayer = nullptr;
|
|
CardZone *targetZone = nullptr;
|
|
CardItem *targetCard = nullptr;
|
|
if (event.has_target_player_id()) {
|
|
targetPlayer = playerList.value(event.target_player_id(), 0);
|
|
if (targetPlayer) {
|
|
targetZone = targetPlayer->getZones().value(QString::fromStdString(event.target_zone()), 0);
|
|
if (targetZone) {
|
|
targetCard = targetZone->getCard(event.target_card_id(), QString());
|
|
}
|
|
}
|
|
}
|
|
|
|
CardZone *startZone = getZones().value(QString::fromStdString(event.start_zone()), 0);
|
|
if (!startZone) {
|
|
return;
|
|
}
|
|
|
|
CardItem *startCard = startZone->getCard(event.card_id(), QString());
|
|
if (!startCard) {
|
|
return;
|
|
}
|
|
|
|
CardItem *oldParent = startCard->getAttachedTo();
|
|
|
|
startCard->setAttachedTo(targetCard);
|
|
|
|
startZone->reorganizeCards();
|
|
if ((startZone != targetZone) && targetZone) {
|
|
targetZone->reorganizeCards();
|
|
}
|
|
if (oldParent) {
|
|
oldParent->getZone()->reorganizeCards();
|
|
}
|
|
|
|
if (targetCard) {
|
|
emit logAttachCard(this, startCard->getName(), targetPlayer, targetCard->getName());
|
|
} else {
|
|
emit logUnattachCard(this, startCard->getName());
|
|
}
|
|
}
|
|
|
|
void Player::eventDrawCards(const Event_DrawCards &event)
|
|
{
|
|
CardZone *deck = zones.value("deck");
|
|
CardZone *hand = zones.value("hand");
|
|
|
|
const int listSize = event.cards_size();
|
|
if (listSize) {
|
|
for (int i = 0; i < listSize; ++i) {
|
|
const ServerInfo_Card &cardInfo = event.cards(i);
|
|
CardItem *card = deck->takeCard(0, cardInfo.id());
|
|
card->setName(QString::fromStdString(cardInfo.name()));
|
|
hand->addCard(card, false, -1);
|
|
}
|
|
} else {
|
|
const int number = event.number();
|
|
for (int i = 0; i < number; ++i) {
|
|
hand->addCard(deck->takeCard(0, -1), false, -1);
|
|
}
|
|
}
|
|
|
|
hand->reorganizeCards();
|
|
deck->reorganizeCards();
|
|
emit logDrawCards(this, event.number());
|
|
}
|
|
|
|
void Player::eventRevealCards(const Event_RevealCards &event)
|
|
{
|
|
CardZone *zone = zones.value(QString::fromStdString(event.zone_name()));
|
|
if (!zone) {
|
|
return;
|
|
}
|
|
Player *otherPlayer = nullptr;
|
|
if (event.has_other_player_id()) {
|
|
otherPlayer = game->getPlayers().value(event.other_player_id());
|
|
if (!otherPlayer) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
bool peeking = false;
|
|
QList<const ServerInfo_Card *> cardList;
|
|
const int cardListSize = event.cards_size();
|
|
for (int i = 0; i < cardListSize; ++i) {
|
|
const ServerInfo_Card *temp = &event.cards(i);
|
|
if (temp->face_down()) {
|
|
peeking = true;
|
|
}
|
|
cardList.append(temp);
|
|
}
|
|
|
|
if (peeking) {
|
|
for (const auto &card : cardList) {
|
|
QString cardName = QString::fromStdString(card->name());
|
|
CardItem *cardItem = zone->getCard(card->id(), QString());
|
|
if (!cardItem) {
|
|
continue;
|
|
}
|
|
cardItem->setName(cardName);
|
|
emit logRevealCards(this, zone, card->id(), cardName, this, true, 1);
|
|
}
|
|
} else {
|
|
bool showZoneView = true;
|
|
QString cardName;
|
|
if (cardList.size() == 1) {
|
|
cardName = QString::fromStdString(cardList.first()->name());
|
|
if ((event.card_id() == 0) && dynamic_cast<PileZone *>(zone)) {
|
|
zone->getCards().first()->setName(cardName);
|
|
zone->update();
|
|
showZoneView = false;
|
|
}
|
|
}
|
|
if (showZoneView && !cardList.isEmpty()) {
|
|
static_cast<GameScene *>(scene())->addRevealedZoneView(this, zone, cardList, event.grant_write_access());
|
|
}
|
|
|
|
emit logRevealCards(this, zone, event.card_id(), cardName, otherPlayer, false,
|
|
event.has_number_of_cards() ? event.number_of_cards() : cardList.size());
|
|
}
|
|
}
|
|
|
|
void Player::eventChangeZoneProperties(const Event_ChangeZoneProperties &event)
|
|
{
|
|
CardZone *zone = zones.value(QString::fromStdString(event.zone_name()));
|
|
if (!zone) {
|
|
return;
|
|
}
|
|
|
|
if (event.has_always_reveal_top_card()) {
|
|
zone->setAlwaysRevealTopCard(event.always_reveal_top_card());
|
|
emit logAlwaysRevealTopCard(this, zone, event.always_reveal_top_card());
|
|
}
|
|
}
|
|
|
|
void Player::processGameEvent(GameEvent::GameEventType type, const GameEvent &event, const GameEventContext &context)
|
|
{
|
|
switch (type) {
|
|
case GameEvent::GAME_SAY:
|
|
eventGameSay(event.GetExtension(Event_GameSay::ext));
|
|
break;
|
|
case GameEvent::SHUFFLE:
|
|
eventShuffle(event.GetExtension(Event_Shuffle::ext));
|
|
break;
|
|
case GameEvent::ROLL_DIE:
|
|
eventRollDie(event.GetExtension(Event_RollDie::ext));
|
|
break;
|
|
case GameEvent::CREATE_ARROW:
|
|
eventCreateArrow(event.GetExtension(Event_CreateArrow::ext));
|
|
break;
|
|
case GameEvent::DELETE_ARROW:
|
|
eventDeleteArrow(event.GetExtension(Event_DeleteArrow::ext));
|
|
break;
|
|
case GameEvent::CREATE_TOKEN:
|
|
eventCreateToken(event.GetExtension(Event_CreateToken::ext));
|
|
break;
|
|
case GameEvent::SET_CARD_ATTR:
|
|
eventSetCardAttr(event.GetExtension(Event_SetCardAttr::ext), context);
|
|
break;
|
|
case GameEvent::SET_CARD_COUNTER:
|
|
eventSetCardCounter(event.GetExtension(Event_SetCardCounter::ext));
|
|
break;
|
|
case GameEvent::CREATE_COUNTER:
|
|
eventCreateCounter(event.GetExtension(Event_CreateCounter::ext));
|
|
break;
|
|
case GameEvent::SET_COUNTER:
|
|
eventSetCounter(event.GetExtension(Event_SetCounter::ext));
|
|
break;
|
|
case GameEvent::DEL_COUNTER:
|
|
eventDelCounter(event.GetExtension(Event_DelCounter::ext));
|
|
break;
|
|
case GameEvent::DUMP_ZONE:
|
|
eventDumpZone(event.GetExtension(Event_DumpZone::ext));
|
|
break;
|
|
case GameEvent::STOP_DUMP_ZONE:
|
|
eventStopDumpZone(event.GetExtension(Event_StopDumpZone::ext));
|
|
break;
|
|
case GameEvent::MOVE_CARD:
|
|
eventMoveCard(event.GetExtension(Event_MoveCard::ext), context);
|
|
break;
|
|
case GameEvent::FLIP_CARD:
|
|
eventFlipCard(event.GetExtension(Event_FlipCard::ext));
|
|
break;
|
|
case GameEvent::DESTROY_CARD:
|
|
eventDestroyCard(event.GetExtension(Event_DestroyCard::ext));
|
|
break;
|
|
case GameEvent::ATTACH_CARD:
|
|
eventAttachCard(event.GetExtension(Event_AttachCard::ext));
|
|
break;
|
|
case GameEvent::DRAW_CARDS:
|
|
eventDrawCards(event.GetExtension(Event_DrawCards::ext));
|
|
break;
|
|
case GameEvent::REVEAL_CARDS:
|
|
eventRevealCards(event.GetExtension(Event_RevealCards::ext));
|
|
break;
|
|
case GameEvent::CHANGE_ZONE_PROPERTIES:
|
|
eventChangeZoneProperties(event.GetExtension(Event_ChangeZoneProperties::ext));
|
|
break;
|
|
default: {
|
|
qDebug() << "unhandled game event" << type;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::setActive(bool _active)
|
|
{
|
|
active = _active;
|
|
table->setActive(active);
|
|
update();
|
|
}
|
|
|
|
QRectF Player::boundingRect() const
|
|
{
|
|
return bRect;
|
|
}
|
|
|
|
void Player::paint(QPainter * /*painter*/, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
|
{
|
|
}
|
|
|
|
void Player::processPlayerInfo(const ServerInfo_Player &info)
|
|
{
|
|
clearCounters();
|
|
clearArrows();
|
|
|
|
QMapIterator<QString, CardZone *> zoneIt(zones);
|
|
while (zoneIt.hasNext()) {
|
|
zoneIt.next().value()->clearContents();
|
|
}
|
|
|
|
const int zoneListSize = info.zone_list_size();
|
|
for (int i = 0; i < zoneListSize; ++i) {
|
|
const ServerInfo_Zone &zoneInfo = info.zone_list(i);
|
|
CardZone *zone = zones.value(QString::fromStdString(zoneInfo.name()), 0);
|
|
if (!zone) {
|
|
continue;
|
|
}
|
|
|
|
const int cardListSize = zoneInfo.card_list_size();
|
|
if (!cardListSize) {
|
|
for (int j = 0; j < zoneInfo.card_count(); ++j) {
|
|
zone->addCard(new CardItem(this), false, -1);
|
|
}
|
|
} else {
|
|
for (int j = 0; j < cardListSize; ++j) {
|
|
const ServerInfo_Card &cardInfo = zoneInfo.card_list(j);
|
|
CardItem *card = new CardItem(this);
|
|
card->processCardInfo(cardInfo);
|
|
zone->addCard(card, false, cardInfo.x(), cardInfo.y());
|
|
}
|
|
}
|
|
if (zoneInfo.has_always_reveal_top_card()) {
|
|
zone->setAlwaysRevealTopCard(zoneInfo.always_reveal_top_card());
|
|
}
|
|
|
|
zone->reorganizeCards();
|
|
}
|
|
|
|
const int counterListSize = info.counter_list_size();
|
|
for (int i = 0; i < counterListSize; ++i) {
|
|
addCounter(info.counter_list(i));
|
|
}
|
|
|
|
setConceded(info.properties().conceded());
|
|
}
|
|
|
|
void Player::processCardAttachment(const ServerInfo_Player &info)
|
|
{
|
|
const int zoneListSize = info.zone_list_size();
|
|
for (int i = 0; i < zoneListSize; ++i) {
|
|
const ServerInfo_Zone &zoneInfo = info.zone_list(i);
|
|
CardZone *zone = zones.value(QString::fromStdString(zoneInfo.name()), 0);
|
|
if (!zone) {
|
|
continue;
|
|
}
|
|
|
|
const int cardListSize = zoneInfo.card_list_size();
|
|
for (int j = 0; j < cardListSize; ++j) {
|
|
const ServerInfo_Card &cardInfo = zoneInfo.card_list(j);
|
|
if (cardInfo.has_attach_player_id()) {
|
|
CardItem *startCard = zone->getCard(cardInfo.id(), QString());
|
|
CardItem *targetCard =
|
|
game->getCard(cardInfo.attach_player_id(), QString::fromStdString(cardInfo.attach_zone()),
|
|
cardInfo.attach_card_id());
|
|
if (!targetCard) {
|
|
continue;
|
|
}
|
|
|
|
startCard->setAttachedTo(targetCard);
|
|
}
|
|
}
|
|
}
|
|
|
|
const int arrowListSize = info.arrow_list_size();
|
|
for (int i = 0; i < arrowListSize; ++i) {
|
|
addArrow(info.arrow_list(i));
|
|
}
|
|
}
|
|
|
|
void Player::playCard(CardItem *card, bool faceDown, bool tapped)
|
|
{
|
|
if (card == nullptr) {
|
|
return;
|
|
}
|
|
|
|
Command_MoveCard cmd;
|
|
cmd.set_start_player_id(card->getZone()->getPlayer()->getId());
|
|
cmd.set_start_zone(card->getZone()->getName().toStdString());
|
|
cmd.set_target_player_id(getId());
|
|
CardToMove *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
|
cardToMove->set_card_id(card->getId());
|
|
|
|
CardInfoPtr info = card->getInfo();
|
|
if (!info) {
|
|
return;
|
|
}
|
|
|
|
int tableRow = info->getTableRow();
|
|
bool playToStack = settingsCache->getPlayToStack();
|
|
QString currentZone = card->getZone()->getName();
|
|
if (currentZone == "stack" && tableRow == 3) {
|
|
cmd.set_target_zone("grave");
|
|
cmd.set_x(0);
|
|
cmd.set_y(0);
|
|
} else if (!faceDown &&
|
|
((!playToStack && tableRow == 3) || ((playToStack && tableRow != 0) && currentZone != "stack"))) {
|
|
cmd.set_target_zone("stack");
|
|
cmd.set_x(0);
|
|
cmd.set_y(0);
|
|
} else {
|
|
tableRow = faceDown ? 2 : info->getTableRow();
|
|
QPoint gridPoint = QPoint(-1, TableZone::clampValidTableRow(2 - tableRow));
|
|
cardToMove->set_face_down(faceDown);
|
|
if (!faceDown) {
|
|
cardToMove->set_pt(info->getPowTough().toStdString());
|
|
}
|
|
cardToMove->set_tapped(faceDown ? false : tapped);
|
|
if (tableRow != 3)
|
|
cmd.set_target_zone("table");
|
|
cmd.set_x(gridPoint.x());
|
|
cmd.set_y(gridPoint.y());
|
|
}
|
|
sendGameCommand(cmd);
|
|
}
|
|
|
|
void Player::addCard(CardItem *card)
|
|
{
|
|
emit newCardAdded(card);
|
|
}
|
|
|
|
void Player::deleteCard(CardItem *card)
|
|
{
|
|
if (card == nullptr) {
|
|
return;
|
|
} else if (dialogSemaphore) {
|
|
cardsToDelete.append(card);
|
|
} else {
|
|
card->deleteLater();
|
|
}
|
|
}
|
|
|
|
void Player::addZone(CardZone *zone)
|
|
{
|
|
zones.insert(zone->getName(), zone);
|
|
}
|
|
|
|
AbstractCounter *Player::addCounter(const ServerInfo_Counter &counter)
|
|
{
|
|
return addCounter(counter.id(), QString::fromStdString(counter.name()),
|
|
convertColorToQColor(counter.counter_color()), counter.radius(), counter.count());
|
|
}
|
|
|
|
AbstractCounter *Player::addCounter(int counterId, const QString &name, QColor color, int radius, int value)
|
|
{
|
|
qDebug() << "addCounter:" << getName() << counterId << name;
|
|
if (counters.contains(counterId)) {
|
|
return nullptr;
|
|
}
|
|
|
|
AbstractCounter *ctr;
|
|
if (name == "life") {
|
|
ctr = playerTarget->addCounter(counterId, name, value);
|
|
} else {
|
|
ctr = new GeneralCounter(this, counterId, name, color, radius, value, true, this, game);
|
|
}
|
|
counters.insert(counterId, ctr);
|
|
if (countersMenu && ctr->getMenu()) {
|
|
countersMenu->addMenu(ctr->getMenu());
|
|
}
|
|
if (shortcutsActive) {
|
|
ctr->setShortcutsActive();
|
|
}
|
|
rearrangeCounters();
|
|
return ctr;
|
|
}
|
|
|
|
void Player::delCounter(int counterId)
|
|
{
|
|
AbstractCounter *ctr = counters.value(counterId, 0);
|
|
if (!ctr) {
|
|
return;
|
|
}
|
|
|
|
ctr->delCounter();
|
|
counters.remove(counterId);
|
|
rearrangeCounters();
|
|
}
|
|
|
|
void Player::clearCounters()
|
|
{
|
|
QMapIterator<int, AbstractCounter *> counterIterator(counters);
|
|
while (counterIterator.hasNext()) {
|
|
counterIterator.next().value()->delCounter();
|
|
}
|
|
counters.clear();
|
|
}
|
|
|
|
ArrowItem *Player::addArrow(const ServerInfo_Arrow &arrow)
|
|
{
|
|
const QMap<int, Player *> &playerList = game->getPlayers();
|
|
Player *startPlayer = playerList.value(arrow.start_player_id(), 0);
|
|
Player *targetPlayer = playerList.value(arrow.target_player_id(), 0);
|
|
if (!startPlayer || !targetPlayer) {
|
|
return nullptr;
|
|
}
|
|
|
|
CardZone *startZone = startPlayer->getZones().value(QString::fromStdString(arrow.start_zone()), 0);
|
|
CardZone *targetZone = nullptr;
|
|
if (arrow.has_target_zone()) {
|
|
targetZone = targetPlayer->getZones().value(QString::fromStdString(arrow.target_zone()), 0);
|
|
}
|
|
if (!startZone || (!targetZone && arrow.has_target_zone())) {
|
|
return nullptr;
|
|
}
|
|
|
|
CardItem *startCard = startZone->getCard(arrow.start_card_id(), QString());
|
|
CardItem *targetCard = nullptr;
|
|
if (targetZone) {
|
|
targetCard = targetZone->getCard(arrow.target_card_id(), QString());
|
|
}
|
|
if (!startCard || (!targetCard && arrow.has_target_card_id())) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (targetCard) {
|
|
return addArrow(arrow.id(), startCard, targetCard, convertColorToQColor(arrow.arrow_color()));
|
|
} else {
|
|
return addArrow(arrow.id(), startCard, targetPlayer->getPlayerTarget(),
|
|
convertColorToQColor(arrow.arrow_color()));
|
|
}
|
|
}
|
|
|
|
ArrowItem *Player::addArrow(int arrowId, CardItem *startCard, ArrowTarget *targetItem, const QColor &color)
|
|
{
|
|
auto *arrow = new ArrowItem(this, arrowId, startCard, targetItem, color);
|
|
arrows.insert(arrowId, arrow);
|
|
scene()->addItem(arrow);
|
|
return arrow;
|
|
}
|
|
|
|
void Player::delArrow(int arrowId)
|
|
{
|
|
ArrowItem *arr = arrows.value(arrowId, 0);
|
|
if (!arr) {
|
|
return;
|
|
}
|
|
arr->delArrow();
|
|
}
|
|
|
|
void Player::removeArrow(ArrowItem *arrow)
|
|
{
|
|
if (arrow->getId() != -1) {
|
|
arrows.remove(arrow->getId());
|
|
}
|
|
}
|
|
|
|
void Player::clearArrows()
|
|
{
|
|
QMapIterator<int, ArrowItem *> arrowIterator(arrows);
|
|
while (arrowIterator.hasNext()) {
|
|
arrowIterator.next().value()->delArrow();
|
|
}
|
|
arrows.clear();
|
|
}
|
|
|
|
void Player::rearrangeCounters()
|
|
{
|
|
qreal marginTop = 80;
|
|
|
|
// Determine total height of bounding rectangles
|
|
qreal totalHeight = 0;
|
|
for (const auto &counter : counters) {
|
|
if (counter->getShownInCounterArea()) {
|
|
totalHeight += counter->boundingRect().height();
|
|
}
|
|
}
|
|
|
|
const qreal padding = 5;
|
|
qreal ySize = boundingRect().y() + marginTop;
|
|
|
|
// Place objects
|
|
for (const auto &counter : counters) {
|
|
AbstractCounter *ctr = counter;
|
|
|
|
if (!ctr->getShownInCounterArea()) {
|
|
continue;
|
|
}
|
|
|
|
QRectF br = ctr->boundingRect();
|
|
ctr->setPos((counterAreaWidth - br.width()) / 2, ySize);
|
|
ySize += br.height() + padding;
|
|
}
|
|
}
|
|
|
|
PendingCommand *Player::prepareGameCommand(const google::protobuf::Message &cmd)
|
|
{
|
|
|
|
if (judge && !local) {
|
|
Command_Judge base;
|
|
GameCommand *c = base.add_game_command();
|
|
base.set_target_id(id);
|
|
c->GetReflection()->MutableMessage(c, cmd.GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(cmd);
|
|
return game->prepareGameCommand(base);
|
|
} else {
|
|
return game->prepareGameCommand(cmd);
|
|
}
|
|
}
|
|
|
|
PendingCommand *Player::prepareGameCommand(const QList<const ::google::protobuf::Message *> &cmdList)
|
|
{
|
|
if (judge && !local) {
|
|
Command_Judge base;
|
|
base.set_target_id(id);
|
|
for (int i = 0; i < cmdList.size(); ++i) {
|
|
GameCommand *c = base.add_game_command();
|
|
c->GetReflection()
|
|
->MutableMessage(c, cmdList[i]->GetDescriptor()->FindExtensionByName("ext"))
|
|
->CopyFrom(*cmdList[i]);
|
|
delete cmdList[i];
|
|
}
|
|
return game->prepareGameCommand(base);
|
|
} else {
|
|
return game->prepareGameCommand(cmdList);
|
|
}
|
|
}
|
|
|
|
void Player::sendGameCommand(const google::protobuf::Message &command)
|
|
{
|
|
if (judge && !local) {
|
|
Command_Judge base;
|
|
GameCommand *c = base.add_game_command();
|
|
base.set_target_id(id);
|
|
c->GetReflection()->MutableMessage(c, command.GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(command);
|
|
game->sendGameCommand(base, id);
|
|
} else {
|
|
game->sendGameCommand(command, id);
|
|
}
|
|
}
|
|
|
|
void Player::sendGameCommand(PendingCommand *pend)
|
|
{
|
|
game->sendGameCommand(pend, id);
|
|
}
|
|
|
|
bool Player::clearCardsToDelete()
|
|
{
|
|
if (cardsToDelete.isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
for (auto &i : cardsToDelete) {
|
|
if (i != nullptr) {
|
|
i->deleteLater();
|
|
}
|
|
}
|
|
cardsToDelete.clear();
|
|
|
|
return true;
|
|
}
|
|
|
|
void Player::actMoveCardXCardsFromTop()
|
|
{
|
|
bool ok;
|
|
int number = QInputDialog::getInt(game, tr("Place card X cards from top of library"),
|
|
tr("How many cards from the top of the deck should this card be placed:"),
|
|
defaultNumberTopCardsToPlaceBelow, 1, 2000000000, 1, &ok);
|
|
number--;
|
|
|
|
if (!ok) {
|
|
return;
|
|
}
|
|
|
|
defaultNumberTopCardsToPlaceBelow = number;
|
|
|
|
QList<QGraphicsItem *> sel = scene()->selectedItems();
|
|
if (sel.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
QList<CardItem *> cardList;
|
|
while (!sel.isEmpty()) {
|
|
cardList.append(qgraphicsitem_cast<CardItem *>(sel.takeFirst()));
|
|
}
|
|
|
|
QList<const ::google::protobuf::Message *> commandList;
|
|
ListOfCardsToMove idList;
|
|
for (const auto &i : cardList) {
|
|
idList.add_card()->set_card_id(i->getId());
|
|
}
|
|
|
|
int startPlayerId = cardList[0]->getZone()->getPlayer()->getId();
|
|
QString startZone = cardList[0]->getZone()->getName();
|
|
|
|
auto *cmd = new Command_MoveCard;
|
|
cmd->set_start_player_id(startPlayerId);
|
|
cmd->set_start_zone(startZone.toStdString());
|
|
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
|
cmd->set_target_player_id(getId());
|
|
cmd->set_target_zone("deck");
|
|
cmd->set_x(number);
|
|
cmd->set_y(0);
|
|
commandList.append(cmd);
|
|
|
|
if (local) {
|
|
sendGameCommand(prepareGameCommand(commandList));
|
|
} else {
|
|
game->sendGameCommand(prepareGameCommand(commandList));
|
|
}
|
|
}
|
|
|
|
void Player::cardMenuAction()
|
|
{
|
|
auto *a = dynamic_cast<QAction *>(sender());
|
|
QList<QGraphicsItem *> sel = scene()->selectedItems();
|
|
QList<CardItem *> cardList;
|
|
while (!sel.isEmpty()) {
|
|
cardList.append(qgraphicsitem_cast<CardItem *>(sel.takeFirst()));
|
|
}
|
|
|
|
QList<const ::google::protobuf::Message *> commandList;
|
|
if (a->data().toInt() <= (int)cmClone) {
|
|
for (const auto &card : cardList) {
|
|
switch (static_cast<CardMenuActionType>(a->data().toInt())) {
|
|
// Leaving both for compatibility with server
|
|
case cmUntap:
|
|
// fallthrough
|
|
case cmTap: {
|
|
auto *cmd = new Command_SetCardAttr;
|
|
cmd->set_zone(card->getZone()->getName().toStdString());
|
|
cmd->set_card_id(card->getId());
|
|
cmd->set_attribute(AttrTapped);
|
|
cmd->set_attr_value(std::to_string(1 - static_cast<int>(card->getTapped())));
|
|
commandList.append(cmd);
|
|
break;
|
|
}
|
|
case cmDoesntUntap: {
|
|
auto *cmd = new Command_SetCardAttr;
|
|
cmd->set_zone(card->getZone()->getName().toStdString());
|
|
cmd->set_card_id(card->getId());
|
|
cmd->set_attribute(AttrDoesntUntap);
|
|
cmd->set_attr_value(card->getDoesntUntap() ? "0" : "1");
|
|
commandList.append(cmd);
|
|
break;
|
|
}
|
|
case cmFlip: {
|
|
auto *cmd = new Command_FlipCard;
|
|
cmd->set_zone(card->getZone()->getName().toStdString());
|
|
cmd->set_card_id(card->getId());
|
|
cmd->set_face_down(!card->getFaceDown());
|
|
if (card->getFaceDown()) {
|
|
CardInfoPtr ci = card->getInfo();
|
|
if (ci) {
|
|
cmd->set_pt(ci->getPowTough().toStdString());
|
|
}
|
|
}
|
|
commandList.append(cmd);
|
|
break;
|
|
}
|
|
case cmPeek: {
|
|
auto *cmd = new Command_RevealCards;
|
|
cmd->set_zone_name(card->getZone()->getName().toStdString());
|
|
cmd->set_card_id(card->getId());
|
|
cmd->set_player_id(id);
|
|
commandList.append(cmd);
|
|
break;
|
|
}
|
|
case cmClone: {
|
|
auto *cmd = new Command_CreateToken;
|
|
cmd->set_zone("table");
|
|
cmd->set_card_name(card->getName().toStdString());
|
|
cmd->set_color(card->getColor().toStdString());
|
|
cmd->set_pt(card->getPT().toStdString());
|
|
cmd->set_annotation(card->getAnnotation().toStdString());
|
|
cmd->set_destroy_on_zone_change(true);
|
|
cmd->set_x(-1);
|
|
cmd->set_y(card->getGridPoint().y());
|
|
commandList.append(cmd);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
ListOfCardsToMove idList;
|
|
for (const auto &i : cardList) {
|
|
idList.add_card()->set_card_id(i->getId());
|
|
}
|
|
int startPlayerId = cardList[0]->getZone()->getPlayer()->getId();
|
|
QString startZone = cardList[0]->getZone()->getName();
|
|
|
|
switch (static_cast<CardMenuActionType>(a->data().toInt())) {
|
|
case cmMoveToTopLibrary: {
|
|
auto *cmd = new Command_MoveCard;
|
|
cmd->set_start_player_id(startPlayerId);
|
|
cmd->set_start_zone(startZone.toStdString());
|
|
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
|
cmd->set_target_player_id(getId());
|
|
cmd->set_target_zone("deck");
|
|
cmd->set_x(0);
|
|
cmd->set_y(0);
|
|
commandList.append(cmd);
|
|
break;
|
|
}
|
|
case cmMoveToBottomLibrary: {
|
|
auto *cmd = new Command_MoveCard;
|
|
cmd->set_start_player_id(startPlayerId);
|
|
cmd->set_start_zone(startZone.toStdString());
|
|
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
|
cmd->set_target_player_id(getId());
|
|
cmd->set_target_zone("deck");
|
|
cmd->set_x(-1);
|
|
cmd->set_y(0);
|
|
|
|
if (idList.card_size() > 1) {
|
|
auto *scmd = new Command_Shuffle;
|
|
scmd->set_zone_name("deck");
|
|
scmd->set_start(-idList.card_size());
|
|
scmd->set_end(-1);
|
|
// Server process events backwards, so...
|
|
commandList.append(scmd);
|
|
}
|
|
|
|
commandList.append(cmd);
|
|
break;
|
|
}
|
|
case cmMoveToHand: {
|
|
auto *cmd = new Command_MoveCard;
|
|
cmd->set_start_player_id(startPlayerId);
|
|
cmd->set_start_zone(startZone.toStdString());
|
|
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
|
cmd->set_target_player_id(getId());
|
|
cmd->set_target_zone("hand");
|
|
cmd->set_x(0);
|
|
cmd->set_y(0);
|
|
commandList.append(cmd);
|
|
break;
|
|
}
|
|
case cmMoveToGraveyard: {
|
|
auto *cmd = new Command_MoveCard;
|
|
cmd->set_start_player_id(startPlayerId);
|
|
cmd->set_start_zone(startZone.toStdString());
|
|
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
|
cmd->set_target_player_id(getId());
|
|
cmd->set_target_zone("grave");
|
|
cmd->set_x(0);
|
|
cmd->set_y(0);
|
|
commandList.append(cmd);
|
|
break;
|
|
}
|
|
case cmMoveToExile: {
|
|
auto *cmd = new Command_MoveCard;
|
|
cmd->set_start_player_id(startPlayerId);
|
|
cmd->set_start_zone(startZone.toStdString());
|
|
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
|
cmd->set_target_player_id(getId());
|
|
cmd->set_target_zone("rfg");
|
|
cmd->set_x(0);
|
|
cmd->set_y(0);
|
|
commandList.append(cmd);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (local) {
|
|
sendGameCommand(prepareGameCommand(commandList));
|
|
} else {
|
|
game->sendGameCommand(prepareGameCommand(commandList));
|
|
}
|
|
}
|
|
|
|
void Player::actIncPT(int deltaP, int deltaT)
|
|
{
|
|
int playerid = id;
|
|
|
|
QList<const ::google::protobuf::Message *> commandList;
|
|
for (const auto &item : scene()->selectedItems()) {
|
|
auto *card = static_cast<CardItem *>(item);
|
|
QString pt = card->getPT();
|
|
const auto ptList = parsePT(pt);
|
|
QString newpt;
|
|
if (ptList.isEmpty()) {
|
|
newpt = QString::number(deltaP) + (deltaT ? "/" + QString::number(deltaT) : "");
|
|
} else if (ptList.size() == 1) {
|
|
newpt = QString::number(ptList.at(0).toInt() + deltaP) + (deltaT ? "/" + QString::number(deltaT) : "");
|
|
} else {
|
|
newpt =
|
|
QString::number(ptList.at(0).toInt() + deltaP) + "/" + QString::number(ptList.at(1).toInt() + deltaT);
|
|
}
|
|
|
|
auto *cmd = new Command_SetCardAttr;
|
|
cmd->set_zone(card->getZone()->getName().toStdString());
|
|
cmd->set_card_id(card->getId());
|
|
cmd->set_attribute(AttrPT);
|
|
cmd->set_attr_value(newpt.toStdString());
|
|
commandList.append(cmd);
|
|
|
|
if (local) {
|
|
playerid = card->getZone()->getPlayer()->getId();
|
|
}
|
|
}
|
|
|
|
game->sendGameCommand(prepareGameCommand(commandList), playerid);
|
|
}
|
|
|
|
void Player::actResetPT()
|
|
{
|
|
int playerid = id;
|
|
QList<const ::google::protobuf::Message *> commandList;
|
|
for (const auto &item : scene()->selectedItems()) {
|
|
auto *card = static_cast<CardItem *>(item);
|
|
QString ptString;
|
|
if (!card->getFaceDown()) { // leave the pt empty if the card is face down
|
|
CardInfoPtr info = card->getInfo();
|
|
if (info) {
|
|
ptString = info->getPowTough();
|
|
}
|
|
}
|
|
if (ptString == card->getPT()) {
|
|
continue;
|
|
}
|
|
QString zoneName = card->getZone()->getName();
|
|
auto *cmd = new Command_SetCardAttr;
|
|
cmd->set_zone(zoneName.toStdString());
|
|
cmd->set_card_id(card->getId());
|
|
cmd->set_attribute(AttrPT);
|
|
cmd->set_attr_value(ptString.toStdString());
|
|
commandList.append(cmd);
|
|
|
|
if (local) {
|
|
playerid = card->getZone()->getPlayer()->getId();
|
|
}
|
|
}
|
|
|
|
game->sendGameCommand(prepareGameCommand(commandList), playerid);
|
|
}
|
|
|
|
QVariantList Player::parsePT(const QString &pt)
|
|
{
|
|
QVariantList ptList = QVariantList();
|
|
if (!pt.isEmpty()) {
|
|
int sep = pt.indexOf('/');
|
|
if (sep == 0) {
|
|
ptList.append(QVariant(pt.mid(1))); // cut off starting '/' and take full string
|
|
} else {
|
|
int start = 0;
|
|
for (;;) {
|
|
QString item = pt.mid(start, sep - start);
|
|
if (item.isEmpty()) {
|
|
ptList.append(QVariant(QString()));
|
|
} else if (item[0] == '+') {
|
|
ptList.append(QVariant(item.mid(1).toInt())); // add as int
|
|
} else if (item[0] == '-') {
|
|
ptList.append(QVariant(item.toInt())); // add as int
|
|
} else {
|
|
ptList.append(QVariant(item)); // add as qstring
|
|
}
|
|
if (sep == -1) {
|
|
break;
|
|
}
|
|
start = sep + 1;
|
|
sep = pt.indexOf('/', start);
|
|
}
|
|
}
|
|
}
|
|
return ptList;
|
|
}
|
|
|
|
void Player::actSetPT()
|
|
{
|
|
QString oldPT;
|
|
int playerid = id;
|
|
|
|
auto sel = scene()->selectedItems();
|
|
for (const auto &item : sel) {
|
|
auto *card = static_cast<CardItem *>(item);
|
|
if (!card->getPT().isEmpty()) {
|
|
oldPT = card->getPT();
|
|
}
|
|
}
|
|
bool ok;
|
|
dialogSemaphore = true;
|
|
QString pt = QInputDialog::getText(nullptr, tr("Change power/toughness"), tr("Change stats to:"), QLineEdit::Normal,
|
|
oldPT, &ok);
|
|
dialogSemaphore = false;
|
|
if (clearCardsToDelete() || !ok) {
|
|
return;
|
|
}
|
|
|
|
const auto ptList = parsePT(pt);
|
|
bool empty = ptList.isEmpty();
|
|
|
|
QList<const ::google::protobuf::Message *> commandList;
|
|
for (const auto &item : sel) {
|
|
auto *card = static_cast<CardItem *>(item);
|
|
auto *cmd = new Command_SetCardAttr;
|
|
QString newpt = QString();
|
|
if (!empty) {
|
|
const auto oldpt = parsePT(card->getPT());
|
|
int ptIter = 0;
|
|
for (const auto &item : ptList) {
|
|
if (item.type() == QVariant::Int) {
|
|
int oldItem = ptIter < oldpt.size() ? oldpt.at(ptIter).toInt() : 0;
|
|
newpt += '/' + QString::number(oldItem + item.toInt());
|
|
} else {
|
|
newpt += '/' + item.toString();
|
|
}
|
|
++ptIter;
|
|
}
|
|
newpt = newpt.mid(1);
|
|
}
|
|
|
|
cmd->set_zone(card->getZone()->getName().toStdString());
|
|
cmd->set_card_id(card->getId());
|
|
cmd->set_attribute(AttrPT);
|
|
cmd->set_attr_value(newpt.toStdString());
|
|
commandList.append(cmd);
|
|
|
|
if (local) {
|
|
playerid = card->getZone()->getPlayer()->getId();
|
|
}
|
|
}
|
|
|
|
game->sendGameCommand(prepareGameCommand(commandList), playerid);
|
|
}
|
|
|
|
void Player::actDrawArrow()
|
|
{
|
|
if (!game->getActiveCard()) {
|
|
return;
|
|
}
|
|
|
|
game->getActiveCard()->drawArrow(Qt::red);
|
|
}
|
|
|
|
void Player::actIncP()
|
|
{
|
|
actIncPT(1, 0);
|
|
}
|
|
|
|
void Player::actDecP()
|
|
{
|
|
actIncPT(-1, 0);
|
|
}
|
|
|
|
void Player::actIncT()
|
|
{
|
|
actIncPT(0, 1);
|
|
}
|
|
|
|
void Player::actDecT()
|
|
{
|
|
actIncPT(0, -1);
|
|
}
|
|
|
|
void Player::actIncPT()
|
|
{
|
|
actIncPT(1, 1);
|
|
}
|
|
|
|
void Player::actDecPT()
|
|
{
|
|
actIncPT(-1, -1);
|
|
}
|
|
|
|
void Player::actFlowP()
|
|
{
|
|
actIncPT(1, -1);
|
|
}
|
|
|
|
void Player::actFlowT()
|
|
{
|
|
actIncPT(-1, 1);
|
|
}
|
|
|
|
void Player::actSetAnnotation()
|
|
{
|
|
QString oldAnnotation;
|
|
auto sel = scene()->selectedItems();
|
|
for (const auto &item : sel) {
|
|
auto *card = static_cast<CardItem *>(item);
|
|
if (!card->getAnnotation().isEmpty()) {
|
|
oldAnnotation = card->getAnnotation();
|
|
}
|
|
}
|
|
|
|
bool ok;
|
|
dialogSemaphore = true;
|
|
QString annotation = QInputDialog::getText(nullptr, tr("Set annotation"), tr("Please enter the new annotation:"),
|
|
QLineEdit::Normal, oldAnnotation, &ok);
|
|
dialogSemaphore = false;
|
|
if (clearCardsToDelete() || !ok) {
|
|
return;
|
|
}
|
|
|
|
QList<const ::google::protobuf::Message *> commandList;
|
|
for (const auto &item : sel) {
|
|
auto *card = static_cast<CardItem *>(item);
|
|
auto *cmd = new Command_SetCardAttr;
|
|
cmd->set_zone(card->getZone()->getName().toStdString());
|
|
cmd->set_card_id(card->getId());
|
|
cmd->set_attribute(AttrAnnotation);
|
|
cmd->set_attr_value(annotation.toStdString());
|
|
commandList.append(cmd);
|
|
}
|
|
sendGameCommand(prepareGameCommand(commandList));
|
|
}
|
|
|
|
void Player::actAttach()
|
|
{
|
|
auto *card = game->getActiveCard();
|
|
if (!card) {
|
|
return;
|
|
}
|
|
|
|
auto *arrow = new ArrowAttachItem(card);
|
|
scene()->addItem(arrow);
|
|
arrow->grabMouse();
|
|
}
|
|
|
|
void Player::actUnattach()
|
|
{
|
|
if (!game->getActiveCard()) {
|
|
return;
|
|
}
|
|
|
|
Command_AttachCard cmd;
|
|
cmd.set_start_zone(game->getActiveCard()->getZone()->getName().toStdString());
|
|
cmd.set_card_id(game->getActiveCard()->getId());
|
|
sendGameCommand(cmd);
|
|
}
|
|
|
|
void Player::actCardCounterTrigger()
|
|
{
|
|
auto *action = static_cast<QAction *>(sender());
|
|
int counterId = action->data().toInt() / 1000;
|
|
QList<const ::google::protobuf::Message *> commandList;
|
|
switch (action->data().toInt() % 1000) {
|
|
case 9: { // increment counter
|
|
for (const auto &item : scene()->selectedItems()) {
|
|
auto *card = static_cast<CardItem *>(item);
|
|
if (card->getCounters().value(counterId, 0) < MAX_COUNTERS_ON_CARD) {
|
|
auto *cmd = new Command_SetCardCounter;
|
|
cmd->set_zone(card->getZone()->getName().toStdString());
|
|
cmd->set_card_id(card->getId());
|
|
cmd->set_counter_id(counterId);
|
|
cmd->set_counter_value(card->getCounters().value(counterId, 0) + 1);
|
|
commandList.append(cmd);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 10: { // decrement counter
|
|
for (const auto &item : scene()->selectedItems()) {
|
|
auto *card = static_cast<CardItem *>(item);
|
|
if (card->getCounters().value(counterId, 0)) {
|
|
auto *cmd = new Command_SetCardCounter;
|
|
cmd->set_zone(card->getZone()->getName().toStdString());
|
|
cmd->set_card_id(card->getId());
|
|
cmd->set_counter_id(counterId);
|
|
cmd->set_counter_value(card->getCounters().value(counterId, 0) - 1);
|
|
commandList.append(cmd);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 11: { // set counter with dialog
|
|
bool ok;
|
|
dialogSemaphore = true;
|
|
|
|
int oldValue = 0;
|
|
if (scene()->selectedItems().size() == 1) {
|
|
auto *card = static_cast<CardItem *>(scene()->selectedItems().first());
|
|
oldValue = card->getCounters().value(counterId, 0);
|
|
}
|
|
int number = QInputDialog::getInt(game, tr("Set counters"), tr("Number:"), oldValue, 0,
|
|
MAX_COUNTERS_ON_CARD, 1, &ok);
|
|
dialogSemaphore = false;
|
|
if (clearCardsToDelete() || !ok) {
|
|
return;
|
|
}
|
|
|
|
for (const auto &item : scene()->selectedItems()) {
|
|
auto *card = static_cast<CardItem *>(item);
|
|
auto *cmd = new Command_SetCardCounter;
|
|
cmd->set_zone(card->getZone()->getName().toStdString());
|
|
cmd->set_card_id(card->getId());
|
|
cmd->set_counter_id(counterId);
|
|
cmd->set_counter_value(number);
|
|
commandList.append(cmd);
|
|
}
|
|
break;
|
|
}
|
|
default:;
|
|
}
|
|
sendGameCommand(prepareGameCommand(commandList));
|
|
}
|
|
|
|
void Player::actPlay()
|
|
{
|
|
if (!game->getActiveCard()) {
|
|
return;
|
|
}
|
|
|
|
bool cipt = game->getActiveCard()->getInfo() ? game->getActiveCard()->getInfo()->getCipt() : false;
|
|
playCard(game->getActiveCard(), false, cipt);
|
|
}
|
|
|
|
void Player::actHide()
|
|
{
|
|
if (!game->getActiveCard()) {
|
|
return;
|
|
}
|
|
|
|
game->getActiveCard()->getZone()->removeCard(game->getActiveCard());
|
|
}
|
|
|
|
void Player::actPlayFacedown()
|
|
{
|
|
if (!game->getActiveCard()) {
|
|
return;
|
|
}
|
|
|
|
playCard(game->getActiveCard(), true, false);
|
|
}
|
|
|
|
void Player::refreshShortcuts()
|
|
{
|
|
if (shortcutsActive) {
|
|
setShortcutsActive();
|
|
|
|
for (const CardItem *cardItem : table->getCards()) {
|
|
updateCardMenu(cardItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::updateCardMenu(const CardItem *card)
|
|
{
|
|
// If bad card OR is a spectator (as spectators don't need card menus), return
|
|
if (card == nullptr || (game->isSpectator() && !judge)) {
|
|
return;
|
|
}
|
|
|
|
QMenu *cardMenu = card->getCardMenu();
|
|
QMenu *ptMenu = card->getPTMenu();
|
|
QMenu *moveMenu = card->getMoveMenu();
|
|
|
|
cardMenu->clear();
|
|
|
|
bool revealedCard = false;
|
|
bool writeableCard = getLocalOrJudge();
|
|
if (card->getZone() && card->getZone()->getIsView()) {
|
|
auto *view = dynamic_cast<ZoneViewZone *>(card->getZone());
|
|
if (view->getRevealZone()) {
|
|
if (view->getWriteableRevealZone()) {
|
|
writeableCard = true;
|
|
} else {
|
|
revealedCard = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (revealedCard) {
|
|
cardMenu->addAction(aHide);
|
|
addRelatedCardView(card, cardMenu);
|
|
} else if (writeableCard) {
|
|
if (moveMenu->isEmpty()) {
|
|
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
|
|
|
|
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);
|
|
}
|
|
|
|
cardMenu->addAction(aTap);
|
|
cardMenu->addAction(aDoesntUntap);
|
|
cardMenu->addAction(aFlip);
|
|
if (card->getFaceDown()) {
|
|
cardMenu->addAction(aPeek);
|
|
}
|
|
|
|
addRelatedCardView(card, cardMenu);
|
|
addRelatedCardActions(card, cardMenu);
|
|
|
|
cardMenu->addSeparator();
|
|
cardMenu->addAction(aAttach);
|
|
if (card->getAttachedTo()) {
|
|
cardMenu->addAction(aUnattach);
|
|
}
|
|
cardMenu->addAction(aDrawArrow);
|
|
cardMenu->addSeparator();
|
|
cardMenu->addMenu(ptMenu);
|
|
cardMenu->addAction(aSetAnnotation);
|
|
cardMenu->addSeparator();
|
|
cardMenu->addAction(aClone);
|
|
cardMenu->addMenu(moveMenu);
|
|
|
|
for (int i = 0; i < aAddCounter.size(); ++i) {
|
|
cardMenu->addSeparator();
|
|
cardMenu->addAction(aAddCounter[i]);
|
|
if (card->getCounters().contains(i)) {
|
|
cardMenu->addAction(aRemoveCounter[i]);
|
|
}
|
|
cardMenu->addAction(aSetCounter[i]);
|
|
}
|
|
cardMenu->addSeparator();
|
|
} else if (card->getZone()->getName() == "stack") {
|
|
// Card is on the stack
|
|
cardMenu->addAction(aDrawArrow);
|
|
cardMenu->addSeparator();
|
|
cardMenu->addAction(aClone);
|
|
cardMenu->addMenu(moveMenu);
|
|
|
|
addRelatedCardView(card, cardMenu);
|
|
addRelatedCardActions(card, cardMenu);
|
|
} else if (card->getZone()->getName() == "rfg" || card->getZone()->getName() == "grave") {
|
|
// Card is in the graveyard or exile
|
|
cardMenu->addAction(aPlay);
|
|
cardMenu->addAction(aPlayFacedown);
|
|
cardMenu->addSeparator();
|
|
cardMenu->addAction(aClone);
|
|
cardMenu->addMenu(moveMenu);
|
|
|
|
addRelatedCardView(card, cardMenu);
|
|
addRelatedCardActions(card, cardMenu);
|
|
} else {
|
|
// Card is in hand or a custom zone specified by server
|
|
cardMenu->addAction(aPlay);
|
|
cardMenu->addAction(aPlayFacedown);
|
|
cardMenu->addMenu(moveMenu);
|
|
addRelatedCardView(card, cardMenu);
|
|
}
|
|
} else {
|
|
cardMenu->addMenu(moveMenu);
|
|
}
|
|
} else {
|
|
if (card->getZone() && card->getZone()->getName() != "hand") {
|
|
cardMenu->addAction(aDrawArrow);
|
|
cardMenu->addSeparator();
|
|
addRelatedCardView(card, cardMenu);
|
|
addRelatedCardActions(card, cardMenu);
|
|
cardMenu->addSeparator();
|
|
cardMenu->addAction(aClone);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::addRelatedCardView(const CardItem *card, QMenu *cardMenu)
|
|
{
|
|
if (!card || !cardMenu) {
|
|
return;
|
|
}
|
|
auto cardInfo = card->getInfo();
|
|
if (!cardInfo) {
|
|
return;
|
|
}
|
|
|
|
bool atLeastOneGoodRelationFound = false;
|
|
QList<CardRelation *> relatedCards = cardInfo->getAllRelatedCards();
|
|
for (const CardRelation *cardRelation : relatedCards) {
|
|
CardInfoPtr relatedCard = db->getCard(cardRelation->getName());
|
|
if (relatedCard != nullptr) {
|
|
atLeastOneGoodRelationFound = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!atLeastOneGoodRelationFound) {
|
|
return;
|
|
}
|
|
|
|
cardMenu->addSeparator();
|
|
auto viewRelatedCards = new QMenu(tr("View related cards"));
|
|
cardMenu->addMenu(viewRelatedCards);
|
|
for (const CardRelation *relatedCard : relatedCards) {
|
|
QString relatedCardName = relatedCard->getName();
|
|
QAction *viewCard = viewRelatedCards->addAction(relatedCardName);
|
|
connect(viewCard, &QAction::triggered, game, [this, relatedCardName] { game->viewCardInfo(relatedCardName); });
|
|
}
|
|
}
|
|
|
|
void Player::addRelatedCardActions(const CardItem *card, QMenu *cardMenu)
|
|
{
|
|
if (!card || !cardMenu) {
|
|
return;
|
|
}
|
|
auto cardInfo = card->getInfo();
|
|
if (!cardInfo) {
|
|
return;
|
|
}
|
|
|
|
QList<CardRelation *> relatedCards = cardInfo->getAllRelatedCards();
|
|
if (relatedCards.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
cardMenu->addSeparator();
|
|
int index = 0;
|
|
QAction *createRelatedCards = nullptr;
|
|
for (const CardRelation *cardRelation : relatedCards) {
|
|
CardInfoPtr relatedCard = db->getCard(cardRelation->getName());
|
|
if (relatedCard == nullptr)
|
|
continue;
|
|
QString relatedCardName;
|
|
if (relatedCard->getPowTough().size() > 0) {
|
|
relatedCardName = relatedCard->getPowTough() + " " + relatedCard->getName(); // "n/n name"
|
|
} else {
|
|
relatedCardName = relatedCard->getName(); // "name"
|
|
}
|
|
|
|
QString text = tr("Token: ");
|
|
if (cardRelation->getDoesAttach()) {
|
|
text += tr("Attach to ") + "\"" + relatedCardName + "\"";
|
|
} else if (cardRelation->getIsVariable()) {
|
|
text += "X " + relatedCardName;
|
|
} else if (cardRelation->getDefaultCount() != 1) {
|
|
text += QString::number(cardRelation->getDefaultCount()) + "x " + relatedCardName;
|
|
} else {
|
|
text += relatedCardName;
|
|
}
|
|
|
|
if (createRelatedCards == nullptr) {
|
|
if (relatedCards.length() == 1) {
|
|
createRelatedCards = new QAction(text, this); // set actCreateAllRelatedCards with this text
|
|
break; // do not set an individual entry as there is only one entry
|
|
} else {
|
|
createRelatedCards = new QAction(tr("All tokens"), this);
|
|
}
|
|
}
|
|
|
|
auto *createRelated = new QAction(text, this);
|
|
createRelated->setData(QVariant(index++));
|
|
connect(createRelated, SIGNAL(triggered()), this, SLOT(actCreateRelatedCard()));
|
|
cardMenu->addAction(createRelated);
|
|
}
|
|
|
|
if (createRelatedCards) {
|
|
if (shortcutsActive) {
|
|
createRelatedCards->setShortcut(
|
|
settingsCache->shortcuts().getSingleShortcut("Player/aCreateRelatedTokens"));
|
|
}
|
|
connect(createRelatedCards, SIGNAL(triggered()), this, SLOT(actCreateAllRelatedCards()));
|
|
cardMenu->addAction(createRelatedCards);
|
|
}
|
|
}
|
|
|
|
void Player::setCardMenu(QMenu *menu)
|
|
{
|
|
if (aCardMenu) {
|
|
aCardMenu->setMenu(menu);
|
|
}
|
|
}
|
|
|
|
QMenu *Player::getCardMenu() const
|
|
{
|
|
if (aCardMenu) {
|
|
return aCardMenu->menu();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
QString Player::getName() const
|
|
{
|
|
return QString::fromStdString(userInfo->name());
|
|
}
|
|
|
|
qreal Player::getMinimumWidth() const
|
|
{
|
|
qreal result = table->getMinimumWidth() + CARD_HEIGHT + 15 + counterAreaWidth + stack->boundingRect().width();
|
|
if (!settingsCache->getHorizontalHand()) {
|
|
result += hand->boundingRect().width();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void Player::setGameStarted()
|
|
{
|
|
if (local) {
|
|
aAlwaysRevealTopCard->setChecked(false);
|
|
}
|
|
setConceded(false);
|
|
}
|
|
|
|
void Player::setConceded(bool _conceded)
|
|
{
|
|
conceded = _conceded;
|
|
setVisible(!conceded);
|
|
if (conceded) {
|
|
clear();
|
|
}
|
|
emit playerCountChanged();
|
|
}
|
|
|
|
void Player::setMirrored(bool _mirrored)
|
|
{
|
|
if (mirrored != _mirrored) {
|
|
mirrored = _mirrored;
|
|
rearrangeZones();
|
|
}
|
|
}
|
|
|
|
void Player::processSceneSizeChange(int newPlayerWidth)
|
|
{
|
|
// Extend table (and hand, if horizontal) to accommodate the new player width.
|
|
qreal tableWidth = newPlayerWidth - CARD_HEIGHT - 15 - counterAreaWidth - stack->boundingRect().width();
|
|
if (!settingsCache->getHorizontalHand()) {
|
|
tableWidth -= hand->boundingRect().width();
|
|
}
|
|
|
|
table->setWidth(tableWidth);
|
|
hand->setWidth(tableWidth + stack->boundingRect().width());
|
|
}
|
|
|
|
void Player::setLastToken(CardInfoPtr cardInfo)
|
|
{
|
|
if (cardInfo == nullptr || aCreateAnotherToken == nullptr) {
|
|
return;
|
|
}
|
|
|
|
lastTokenName = cardInfo->getName();
|
|
lastTokenColor = cardInfo->getColors().isEmpty() ? QString() : cardInfo->getColors().left(1).toLower();
|
|
lastTokenPT = cardInfo->getPowTough();
|
|
lastTokenAnnotation = settingsCache->getAnnotateTokens() ? cardInfo->getText() : "";
|
|
lastTokenTableRow = TableZone::clampValidTableRow(2 - cardInfo->getTableRow());
|
|
lastTokenDestroy = true;
|
|
aCreateAnotherToken->setText(tr("C&reate another %1 token").arg(lastTokenName));
|
|
aCreateAnotherToken->setEnabled(true);
|
|
}
|