#include "player.h" #include "cardzone.h" #include "playertarget.h" #include "counter_general.h" #include "arrowitem.h" #include "zoneviewzone.h" #include "zoneviewwidget.h" #include "pilezone.h" #include "stackzone.h" #include "tablezone.h" #include "handzone.h" #include "handcounter.h" #include "carditem.h" #include "cardlist.h" #include "tab_game.h" #include "gamescene.h" #include "settingscache.h" #include "dlg_create_token.h" #include "carddatabase.h" #include "color.h" #include #include #include #include #include "pb/command_reveal_cards.pb.h" #include "pb/command_shuffle.pb.h" #include "pb/command_attach_card.pb.h" #include "pb/command_set_card_attr.pb.h" #include "pb/command_set_card_counter.pb.h" #include "pb/command_mulligan.pb.h" #include "pb/command_move_card.pb.h" #include "pb/command_draw_cards.pb.h" #include "pb/command_undo_draw.pb.h" #include "pb/command_roll_die.pb.h" #include "pb/command_create_token.pb.h" #include "pb/command_flip_card.pb.h" #include "pb/command_game_say.pb.h" #include "pb/serverinfo_user.pb.h" #include "pb/serverinfo_player.pb.h" #include "pb/serverinfo_zone.pb.h" #include "pb/context_move_card.pb.h" #include "pb/context_undo_draw.pb.h" #include "pb/event_game_say.pb.h" #include "pb/event_shuffle.pb.h" #include "pb/event_roll_die.pb.h" #include "pb/event_create_arrow.pb.h" #include "pb/event_delete_arrow.pb.h" #include "pb/event_create_token.pb.h" #include "pb/event_set_card_attr.pb.h" #include "pb/event_set_card_counter.pb.h" #include "pb/event_create_counter.pb.h" #include "pb/event_set_counter.pb.h" #include "pb/event_del_counter.pb.h" #include "pb/event_dump_zone.pb.h" #include "pb/event_stop_dump_zone.pb.h" #include "pb/event_move_card.pb.h" #include "pb/event_flip_card.pb.h" #include "pb/event_destroy_card.pb.h" #include "pb/event_attach_card.pb.h" #include "pb/event_draw_cards.pb.h" #include "pb/event_reveal_cards.pb.h" PlayerArea::PlayerArea(QGraphicsItem *parentItem) : QObject(), QGraphicsItem(parentItem) { setCacheMode(DeviceCoordinateCache); connect(settingsCache, SIGNAL(playerBgPathChanged()), this, SLOT(updateBgPixmap())); updateBgPixmap(); } void PlayerArea::updateBgPixmap() { QString bgPath = settingsCache->getPlayerBgPath(); if (bgPath.isEmpty()) bgPixmapBrush = QBrush(QColor(200, 200, 200)); else { qDebug() << "loading" << bgPath; bgPixmapBrush = QBrush(QPixmap(bgPath)); } update(); } void PlayerArea::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) { painter->fillRect(bRect, bgPixmapBrush); } void PlayerArea::setSize(qreal width, qreal height) { prepareGeometryChange(); bRect = QRectF(0, 0, width, height); } Player::Player(const ServerInfo_User &info, int _id, bool _local, TabGame *_parent) : QObject(_parent), game(_parent), shortcutsActive(false), defaultNumberTopCards(3), lastTokenDestroy(true), id(_id), active(false), local(_local), mirrored(false), handVisible(false), conceded(false), dialogSemaphore(false) { userInfo = new ServerInfo_User; userInfo->CopyFrom(info); connect(settingsCache, SIGNAL(horizontalHandChanged()), this, SLOT(rearrangeZones())); playerArea = new PlayerArea(this); playerTarget = new PlayerTarget(this, playerArea); 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; HandCounter *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) { connect(_parent, SIGNAL(playerAdded(Player *)), this, SLOT(addPlayer(Player *))); connect(_parent, SIGNAL(playerRemoved(Player *)), this, SLOT(removePlayer(Player *))); aMoveHandToTopLibrary = new QAction(this); aMoveHandToTopLibrary->setData(QList() << "deck" << 0); aMoveHandToBottomLibrary = new QAction(this); aMoveHandToBottomLibrary->setData(QList() << "deck" << -1); aMoveHandToGrave = new QAction(this); aMoveHandToGrave->setData(QList() << "grave" << 0); aMoveHandToRfg = new QAction(this); aMoveHandToRfg->setData(QList() << "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() << "deck" << 0); aMoveGraveToBottomLibrary = new QAction(this); aMoveGraveToBottomLibrary->setData(QList() << "deck" << -1); aMoveGraveToHand = new QAction(this); aMoveGraveToHand->setData(QList() << "hand" << 0); aMoveGraveToRfg = new QAction(this); aMoveGraveToRfg->setData(QList() << "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() << "deck" << 0); aMoveRfgToBottomLibrary = new QAction(this); aMoveRfgToBottomLibrary->setData(QList() << "deck" << -1); aMoveRfgToHand = new QAction(this); aMoveRfgToHand->setData(QList() << "hand" << 0); aMoveRfgToGrave = new QAction(this); aMoveRfgToGrave->setData(QList() << "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())); aViewTopCards = new QAction(this); connect(aViewTopCards, SIGNAL(triggered()), this, SLOT(actViewTopCards())); } aViewGraveyard = new QAction(this); connect(aViewGraveyard, SIGNAL(triggered()), this, SLOT(actViewGraveyard())); aViewRfg = new QAction(this); connect(aViewRfg, SIGNAL(triggered()), this, SLOT(actViewRfg())); if (local) { 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())); aMoveTopCardsToGrave = new QAction(this); connect(aMoveTopCardsToGrave, 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())); } playerMenu = new QMenu(QString()); if (local) { handMenu = playerMenu->addMenu(QString()); handMenu->addAction(aMulligan); handMenu->addAction(aMoveHandToTopLibrary); handMenu->addAction(aMoveHandToBottomLibrary); handMenu->addAction(aMoveHandToGrave); handMenu->addAction(aMoveHandToRfg); handMenu->addSeparator(); playerLists.append(mRevealHand = handMenu->addMenu(QString())); playerLists.append(mRevealRandomHandCard = handMenu->addMenu(QString())); hand->setMenu(handMenu); libraryMenu = playerMenu->addMenu(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->addSeparator(); libraryMenu->addAction(aMoveTopCardsToGrave); libraryMenu->addAction(aMoveTopCardsToExile); libraryMenu->addAction(aMoveTopCardToBottom); deck->setMenu(libraryMenu, aDrawCard); } else { handMenu = 0; libraryMenu = 0; } graveMenu = playerMenu->addMenu(QString()); graveMenu->addAction(aViewGraveyard); grave->setMenu(graveMenu, aViewGraveyard); rfgMenu = playerMenu->addMenu(QString()); rfgMenu->addAction(aViewRfg); rfg->setMenu(rfgMenu, aViewRfg); if (local) { graveMenu->addSeparator(); graveMenu->addAction(aMoveGraveToTopLibrary); graveMenu->addAction(aMoveGraveToBottomLibrary); graveMenu->addAction(aMoveGraveToHand); graveMenu->addAction(aMoveGraveToRfg); rfgMenu->addSeparator(); rfgMenu->addAction(aMoveRfgToTopLibrary); rfgMenu->addAction(aMoveRfgToBottomLibrary); rfgMenu->addAction(aMoveRfgToHand); rfgMenu->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); 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->addSeparator(); sayMenu = playerMenu->addMenu(QString()); initSayMenu(); aCardMenu = new QAction(this); playerMenu->addSeparator(); playerMenu->addAction(aCardMenu); for (int i = 0; i < playerLists.size(); ++i) { QAction *newAction = playerLists[i]->addAction(QString()); newAction->setData(-1); connect(newAction, SIGNAL(triggered()), this, SLOT(playerListActionTriggered())); allPlayersActions.append(newAction); playerLists[i]->addSeparator(); } } else { countersMenu = 0; sbMenu = 0; aCreateAnotherToken = 0; aCardMenu = 0; } aTap = new QAction(this); aTap->setData(cmTap); connect(aTap, SIGNAL(triggered()), this, SLOT(cardMenuAction())); aUntap = new QAction(this); aUntap->setData(cmUntap); connect(aUntap, 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())); aSetPT = new QAction(this); connect(aSetPT, SIGNAL(triggered()), this, SLOT(actSetPT())); 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); aMoveToGraveyard = new QAction(this); 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(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())); for (int i = 0; i < 3; ++i) { QAction *tempAddCounter = new QAction(this); tempAddCounter->setData(9 + i * 1000); QAction *tempRemoveCounter = new QAction(this); tempRemoveCounter->setData(10 + i * 1000); QAction *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 &players = game->getPlayers().values(); for (int i = 0; i < players.size(); ++i) addPlayer(players[i]); rearrangeZones(); retranslateUi(); } Player::~Player() { qDebug() << "Player destructor:" << getName(); static_cast(scene())->removePlayer(this); clear(); QMapIterator i(zones); while (i.hasNext()) delete i.next().value(); zones.clear(); delete playerMenu; delete userInfo; } void Player::clear() { clearArrows(); QMapIterator i(zones); while (i.hasNext()) i.next().value()->clearContents(); clearCounters(); } void Player::addPlayer(Player *player) { if (player == this) return; for (int i = 0; i < playerLists.size(); ++i) { QAction *newAction = playerLists[i]->addAction(player->getName()); newAction->setData(player->getId()); connect(newAction, SIGNAL(triggered()), this, SLOT(playerListActionTriggered())); } } void Player::removePlayer(Player *player) { for (int i = 0; i < playerLists.size(); ++i) { QList actionList = playerLists[i]->actions(); for (int j = 0; j < actionList.size(); ++j) if (actionList[j]->data().toInt() == player->getId()) { playerLists[i]->removeAction(actionList[j]); actionList[j]->deleteLater(); } } } void Player::playerListActionTriggered() { QAction *action = static_cast(sender()); QMenu *menu = static_cast(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"); cmd.set_grant_write_access(true); } else if (menu == mRevealTopCard) { cmd.set_zone_name("deck"); 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(-2); } 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) { aMoveHandToTopLibrary->setText(tr("Move to &top of library")); aMoveHandToBottomLibrary->setText(tr("Move to &bottom of library")); aMoveHandToGrave->setText(tr("Move to &graveyard")); aMoveHandToRfg->setText(tr("Move to &exile")); aMoveGraveToTopLibrary->setText(tr("Move to &top of library")); aMoveGraveToBottomLibrary->setText(tr("Move to &bottom of library")); aMoveGraveToHand->setText(tr("Move to &hand")); aMoveGraveToRfg->setText(tr("Move to &exile")); aMoveRfgToTopLibrary->setText(tr("Move to &top of library")); aMoveRfgToBottomLibrary->setText(tr("Move to &bottom of library")); aMoveRfgToHand->setText(tr("Move to &hand")); aMoveRfgToGrave->setText(tr("Move to &graveyard")); aViewLibrary->setText(tr("&View library")); aViewTopCards->setText(tr("View &top cards of library...")); mRevealLibrary->setTitle(tr("Reveal &library to")); mRevealTopCard->setTitle(tr("Reveal t&op card to")); 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")); aMoveTopCardsToGrave->setText(tr("Move top cards to &graveyard...")); aMoveTopCardsToExile->setText(tr("Move top cards to &exile...")); aMoveTopCardToBottom->setText(tr("Put top card on &bottom")); handMenu->setTitle(tr("&Hand")); mRevealHand->setTitle(tr("&Reveal to")); mRevealRandomHandCard->setTitle(tr("Reveal r&andom 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")); sayMenu->setTitle(tr("S&ay")); QMapIterator counterIterator(counters); while (counterIterator.hasNext()) counterIterator.next().value()->retranslateUi(); aCardMenu->setText(tr("C&ard")); for (int i = 0; i < allPlayersActions.size(); ++i) allPlayersActions[i]->setText(tr("&All players")); } aPlay->setText(tr("&Play")); aHide->setText(tr("&Hide")); aTap->setText(tr("&Tap")); aUntap->setText(tr("&Untap")); aDoesntUntap->setText(tr("Toggle &normal untapping")); aFlip->setText(tr("&Flip")); aPeek->setText(tr("&Peek at card face")); aClone->setText(tr("&Clone")); aClone->setShortcut(tr("Ctrl+H")); aAttach->setText(tr("&Attach to card...")); aAttach->setShortcut(tr("Ctrl+A")); aUnattach->setText(tr("Unattac&h")); aDrawArrow->setText(tr("&Draw arrow...")); aIncP->setText(tr("&Increase power")); aIncP->setShortcut(tr("Ctrl++")); aDecP->setText(tr("&Decrease power")); aDecP->setShortcut(tr("Ctrl+-")); aIncT->setText(tr("I&ncrease toughness")); aIncT->setShortcut(tr("Alt++")); aDecT->setText(tr("D&ecrease toughness")); aDecT->setShortcut(tr("Alt+-")); aIncPT->setText(tr("In&crease power and toughness")); aIncPT->setShortcut(tr("Ctrl+Alt++")); aDecPT->setText(tr("Dec&rease power and toughness")); aDecPT->setShortcut(tr("Ctrl+Alt+-")); aSetPT->setText(tr("Set &power and toughness...")); aSetPT->setShortcut(tr("Ctrl+P")); 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")); aMoveToBottomLibrary->setText(tr("&bottom of library")); aMoveToGraveyard->setText(tr("&graveyard")); aMoveToGraveyard->setShortcut(tr("Ctrl+Del")); aMoveToExile->setText(tr("&exile")); QMapIterator zoneIterator(zones); while (zoneIterator.hasNext()) zoneIterator.next().value()->retranslateUi(); } void Player::setShortcutsActive() { shortcutsActive = true; aViewSideboard->setShortcut(tr("Ctrl+F3")); aViewLibrary->setShortcut(tr("F3")); aViewTopCards->setShortcut(tr("Ctrl+W")); aViewGraveyard->setShortcut(tr("F4")); aDrawCard->setShortcut(tr("Ctrl+D")); aDrawCards->setShortcut(tr("Ctrl+E")); aUndoDraw->setShortcut(tr("Ctrl+Shift+D")); aMulligan->setShortcut(tr("Ctrl+M")); aShuffle->setShortcut(tr("Ctrl+S")); aUntapAll->setShortcut(tr("Ctrl+U")); aRollDie->setShortcut(tr("Ctrl+I")); aCreateToken->setShortcut(tr("Ctrl+T")); aCreateAnotherToken->setShortcut(tr("Ctrl+G")); QMapIterator counterIterator(counters); while (counterIterator.hasNext()) counterIterator.next().value()->setShortcutsActive(); } void Player::setShortcutsInactive() { shortcutsActive = false; aViewSideboard->setShortcut(QKeySequence()); aViewLibrary->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()); QMapIterator counterIterator(counters); while (counterIterator.hasNext()) counterIterator.next().value()->setShortcutsInactive(); } void Player::initSayMenu() { sayMenu->clear(); QSettings settings; settings.beginGroup("messages"); int count = settings.value("count", 0).toInt(); for (int i = 0; i < count; i++) { QAction *newAction = new QAction(settings.value(QString("msg%1").arg(i)).toString(), this); if (i <= 10) newAction->setShortcut(QString("Ctrl+%1").arg((i + 1) % 10)); connect(newAction, SIGNAL(triggered()), this, SLOT(actSayMessage())); sayMenu->addAction(newAction); } } void Player::actViewLibrary() { static_cast(scene())->toggleZoneView(this, "deck", -1); } void Player::actViewTopCards() { bool ok; int number = QInputDialog::getInteger(0, tr("View top cards of library"), tr("Number of cards:"), defaultNumberTopCards, 1, 2000000000, 1, &ok); if (ok) { defaultNumberTopCards = number; static_cast(scene())->toggleZoneView(this, "deck", number); } } void Player::actViewGraveyard() { static_cast(scene())->toggleZoneView(this, "grave", -1); } void Player::actViewRfg() { static_cast(scene())->toggleZoneView(this, "rfg", -1); } void Player::actViewSideboard() { static_cast(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() { sendGameCommand(Command_Mulligan()); } void Player::actDrawCards() { int number = QInputDialog::getInteger(0, tr("Draw cards"), tr("Number:")); if (number) { Command_DrawCards cmd; cmd.set_number(number); sendGameCommand(cmd); } } void Player::actUndoDraw() { sendGameCommand(Command_UndoDraw()); } void Player::actMoveTopCardsToGrave() { int number = QInputDialog::getInteger(0, 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 = 0; i < number; ++i) cmd.mutable_cards_to_move()->add_card()->set_card_id(i); sendGameCommand(cmd); } void Player::actMoveTopCardsToExile() { int number = QInputDialog::getInteger(0, 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 = 0; i < number; ++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::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::getInteger(0, tr("Roll die"), tr("Number of sides:"), 20, 2, 1000, 1, &ok); if (ok) { Command_RollDie cmd; cmd.set_sides(sides); sendGameCommand(cmd); } } void Player::actCreateToken() { DlgCreateToken dlg; if (!dlg.exec()) return; lastTokenName = dlg.getName(); lastTokenColor = dlg.getColor(); lastTokenPT = dlg.getPT(); lastTokenAnnotation = dlg.getAnnotation(); lastTokenDestroy = dlg.getDestroy(); aCreateAnotherToken->setEnabled(true); actCreateAnotherToken(); } void Player::actCreateAnotherToken() { 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(0); sendGameCommand(cmd); } void Player::actSayMessage() { QAction *a = qobject_cast(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) { 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()) if (zone->getView()->getRevealZone()) zone->getView()->setWriteableRevealZone(false); emit logShuffle(this, zone); } 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; CardItem *startCard = static_cast(arrow->getStartItem()); CardItem *targetCard = qgraphicsitem_cast(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()); card->setColor(QString::fromStdString(event.color())); card->setPT(QString::fromStdString(event.pt())); 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, 0, 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()); 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 *c = counters.value(event.counter_id(), 0); if (!c) return; int oldValue = c->getValue(); c->setValue(event.value()); emit logSetCounter(this, c->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(0); 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 &attachedCards = card->getAttachedCards(); for (int i = 0; i < attachedCards.size(); ++i) attachedCards[i]->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 playerIterator(game->getPlayers()); while (playerIterator.hasNext()) { Player *p = playerIterator.next().value(); QList arrowsToDelete; QMapIterator 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 (int i = 0; i < arrowsToDelete.size(); ++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 attachedCards = card->getAttachedCards(); // This list is always empty except for buggy server implementations. for (int i = 0; i < attachedCards.size(); ++i) attachedCards[i]->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 &playerList = game->getPlayers(); Player *targetPlayer = 0; CardZone *targetZone = 0; CardItem *targetCard = 0; 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 = 0; if (event.has_other_player_id()) { otherPlayer = game->getPlayers().value(event.other_player_id()); if (!otherPlayer) return; } bool peeking = false; QList 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 (int i = 0; i < cardList.size(); ++i) { QString cardName = QString::fromStdString(cardList.at(i)->name()); CardItem *card = zone->getCard(cardList.at(i)->id(), QString()); if (!card) continue; card->setName(cardName); emit logRevealCards(this, zone, cardList.at(i)->id(), cardName, this, true); } } else { if (!cardList.isEmpty()) static_cast(scene())->addRevealedZoneView(this, zone, cardList, event.grant_write_access()); QString cardName; if (cardList.size() == 1) cardName = QString::fromStdString(cardList.first()->name()); emit logRevealCards(this, zone, event.card_id(), cardName, otherPlayer, false); } } 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; default: { qDebug() << "unhandled game event"; } } } 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 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()); } } zone->reorganizeCards(); } const int counterListSize = info.counter_list_size(); for (int i = 0; i < counterListSize; ++i) addCounter(info.counter_list(i)); const int arrowListSize = info.arrow_list_size(); for (int i = 0; i < arrowListSize; ++i) addArrow(info.arrow_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); } } } } void Player::playCard(CardItem *c, bool faceDown, bool tapped) { Command_MoveCard cmd; cmd.set_start_player_id(c->getZone()->getPlayer()->getId()); cmd.set_start_zone(c->getZone()->getName().toStdString()); cmd.set_target_player_id(getId()); CardToMove *cardToMove = cmd.mutable_cards_to_move()->add_card(); cardToMove->set_card_id(c->getId()); CardInfo *ci = c->getInfo(); if (ci->getTableRow() == 3) { cmd.set_target_zone("stack"); cmd.set_x(0); cmd.set_y(0); } else { QPoint gridPoint = QPoint(-1, 2 - ci->getTableRow()); cardToMove->set_face_down(faceDown); cardToMove->set_pt(ci->getPowTough().toStdString()); cardToMove->set_tapped(tapped); cmd.set_target_zone("table"); cmd.set_x(gridPoint.x()); cmd.set_y(gridPoint.y()); } sendGameCommand(cmd); } void Player::addCard(CardItem *c) { emit newCardAdded(c); } void Player::deleteCard(CardItem *c) { if (dialogSemaphore) cardsToDelete.append(c); else c->deleteLater(); } void Player::addZone(CardZone *z) { zones.insert(z->getName(), z); } 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 0; AbstractCounter *c; if (name == "life") c = playerTarget->addCounter(counterId, name, value); else c = new GeneralCounter(this, counterId, name, color, radius, value, this); counters.insert(counterId, c); if (countersMenu) countersMenu->addMenu(c->getMenu()); if (shortcutsActive) c->setShortcutsActive(); rearrangeCounters(); return c; } void Player::delCounter(int counterId) { AbstractCounter *c = counters.value(counterId, 0); if (!c) return; if (c->getName() == "life") playerTarget->delCounter(); counters.remove(counterId); c->delCounter(); rearrangeCounters(); } void Player::clearCounters() { QMapIterator counterIterator(counters); while (counterIterator.hasNext()) counterIterator.next().value()->delCounter(); counters.clear(); playerTarget->delCounter(); } ArrowItem *Player::addArrow(const ServerInfo_Arrow &arrow) { const QMap &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 0; CardZone *startZone = startPlayer->getZones().value(QString::fromStdString(arrow.start_zone()), 0); CardZone *targetZone = 0; if (arrow.has_target_zone()) targetZone = targetPlayer->getZones().value(QString::fromStdString(arrow.target_zone()), 0); if (!startZone || (!targetZone && arrow.has_target_zone())) return 0; CardItem *startCard = startZone->getCard(arrow.start_card_id(), QString()); CardItem *targetCard = 0; if (targetZone) targetCard = targetZone->getCard(arrow.target_card_id(), QString()); if (!startCard || (!targetCard && arrow.has_target_card_id())) return 0; 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) { ArrowItem *arrow = new ArrowItem(this, arrowId, startCard, targetItem, color); arrows.insert(arrowId, arrow); scene()->addItem(arrow); return arrow; } void Player::delArrow(int arrowId) { ArrowItem *a = arrows.value(arrowId, 0); if (!a) return; a->delArrow(); } void Player::removeArrow(ArrowItem *arrow) { if (arrow->getId() != -1) arrows.remove(arrow->getId()); } void Player::clearArrows() { QMapIterator 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; QMapIterator counterIterator(counters); while (counterIterator.hasNext()) { counterIterator.next(); if (counterIterator.value()->getShownInCounterArea()) totalHeight += counterIterator.value()->boundingRect().height(); } const qreal padding = 5; qreal y = boundingRect().y() + marginTop; // Place objects for (counterIterator.toFront(); counterIterator.hasNext(); ) { AbstractCounter *c = counterIterator.next().value(); if (!c->getShownInCounterArea()) continue; QRectF br = c->boundingRect(); c->setPos((counterAreaWidth - br.width()) / 2, y); y += br.height() + padding; } } PendingCommand * Player::prepareGameCommand(const google::protobuf::Message &cmd) { return game->prepareGameCommand(cmd); } PendingCommand * Player::prepareGameCommand(const QList &cmdList) { return game->prepareGameCommand(cmdList); } void Player::sendGameCommand(const google::protobuf::Message &command) { game->sendGameCommand(command, id); } void Player::sendGameCommand(PendingCommand *pend) { game->sendGameCommand(pend, id); } bool Player::clearCardsToDelete() { if (cardsToDelete.isEmpty()) return false; for (int i = 0; i < cardsToDelete.size(); ++i) cardsToDelete[i]->deleteLater(); cardsToDelete.clear(); return true; } void Player::cardMenuAction() { QAction *a = static_cast(sender()); QList sel = scene()->selectedItems(); QList cardList; while (!sel.isEmpty()) cardList.append(qgraphicsitem_cast(sel.takeFirst())); QList< const ::google::protobuf::Message * > commandList; if (a->data().toInt() <= 4) for (int i = 0; i < cardList.size(); ++i) { CardItem *card = cardList[i]; switch (static_cast(a->data().toInt())) { case cmTap: if (!card->getTapped()) { Command_SetCardAttr *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("1"); commandList.append(cmd); } break; case cmUntap: if (card->getTapped()) { Command_SetCardAttr *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("0"); commandList.append(cmd); } break; case cmDoesntUntap: { Command_SetCardAttr *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: { Command_FlipCard *cmd = new Command_FlipCard; cmd->set_zone(card->getZone()->getName().toStdString()); cmd->set_card_id(card->getId()); cmd->set_face_down(!card->getFaceDown()); commandList.append(cmd); break; } case cmPeek: { Command_RevealCards *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: { Command_CreateToken *cmd = new Command_CreateToken; cmd->set_zone(card->getZone()->getName().toStdString()); 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; } } } else { ListOfCardsToMove idList; for (int i = 0; i < cardList.size(); ++i) idList.add_card()->set_card_id(cardList[i]->getId()); int startPlayerId = cardList[0]->getZone()->getPlayer()->getId(); QString startZone = cardList[0]->getZone()->getName(); switch (static_cast(a->data().toInt())) { case cmMoveToTopLibrary: { Command_MoveCard *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: { Command_MoveCard *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); commandList.append(cmd); break; } case cmMoveToGraveyard: { Command_MoveCard *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: { Command_MoveCard *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: ; } } game->sendGameCommand(prepareGameCommand(commandList)); } void Player::actIncPT(int deltaP, int deltaT) { QString ptString = "+" + QString::number(deltaP) + "/+" + QString::number(deltaT); QList< const ::google::protobuf::Message * > commandList; QListIterator j(scene()->selectedItems()); while (j.hasNext()) { CardItem *card = static_cast(j.next()); Command_SetCardAttr *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(ptString.toStdString()); commandList.append(cmd); } sendGameCommand(prepareGameCommand(commandList)); } void Player::actSetPT() { QString oldPT; QListIterator i(scene()->selectedItems()); while (i.hasNext()) { CardItem *card = static_cast(i.next()); if (!card->getPT().isEmpty()) oldPT = card->getPT(); } bool ok; dialogSemaphore = true; QString pt = QInputDialog::getText(0, tr("Set power/toughness"), tr("Please enter the new PT:"), QLineEdit::Normal, oldPT, &ok); dialogSemaphore = false; if (clearCardsToDelete()) return; if (!ok) return; QList< const ::google::protobuf::Message * > commandList; QListIterator j(scene()->selectedItems()); while (j.hasNext()) { CardItem *card = static_cast(j.next()); Command_SetCardAttr *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(pt.toStdString()); commandList.append(cmd); } sendGameCommand(prepareGameCommand(commandList)); } void Player::actDrawArrow() { 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::actSetAnnotation() { QString oldAnnotation; QListIterator i(scene()->selectedItems()); while (i.hasNext()) { CardItem *card = static_cast(i.next()); if (!card->getAnnotation().isEmpty()) oldAnnotation = card->getAnnotation(); } bool ok; dialogSemaphore = true; QString annotation = QInputDialog::getText(0, tr("Set annotation"), tr("Please enter the new annotation:"), QLineEdit::Normal, oldAnnotation, &ok); dialogSemaphore = false; if (clearCardsToDelete()) return; if (!ok) return; QList< const ::google::protobuf::Message * > commandList; i.toFront(); while (i.hasNext()) { CardItem *card = static_cast(i.next()); Command_SetCardAttr *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() { ArrowAttachItem *arrow = new ArrowAttachItem(game->getActiveCard()); scene()->addItem(arrow); arrow->grabMouse(); } void Player::actUnattach() { Command_AttachCard cmd; cmd.set_start_zone(game->getActiveCard()->getZone()->getName().toStdString()); cmd.set_card_id(game->getActiveCard()->getId()); sendGameCommand(cmd); } void Player::actCardCounterTrigger() { QAction *a = static_cast(sender()); int counterId = a->data().toInt() / 1000; int action = a->data().toInt() % 1000; QList< const ::google::protobuf::Message * > commandList; switch (action) { case 9: { QListIterator i(scene()->selectedItems()); while (i.hasNext()) { CardItem *card = static_cast(i.next()); if (card->getCounters().value(counterId, 0) < MAX_COUNTERS_ON_CARD) { Command_SetCardCounter *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: { QListIterator i(scene()->selectedItems()); while (i.hasNext()) { CardItem *card = static_cast(i.next()); if (card->getCounters().value(counterId, 0)) { Command_SetCardCounter *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: { bool ok; dialogSemaphore = true; int number = QInputDialog::getInteger(0, tr("Set counters"), tr("Number:"), 0, 0, MAX_COUNTERS_ON_CARD, 1, &ok); dialogSemaphore = false; if (clearCardsToDelete()) return; if (!ok) return; QListIterator i(scene()->selectedItems()); while (i.hasNext()) { CardItem *card = static_cast(i.next()); Command_SetCardCounter *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() { playCard(game->getActiveCard(), false, game->getActiveCard()->getInfo()->getCipt()); } void Player::actHide() { game->getActiveCard()->getZone()->removeCard(game->getActiveCard()); } void Player::updateCardMenu(CardItem *card) { QMenu *cardMenu = card->getCardMenu(); QMenu *ptMenu = card->getPTMenu(); QMenu *moveMenu = card->getMoveMenu(); cardMenu->clear(); bool revealedCard = false; bool writeableCard = getLocal(); if (card->getZone()) if (card->getZone()->getIsView()) { ZoneViewZone *view = static_cast(card->getZone()); if (view->getRevealZone()) { if (view->getWriteableRevealZone()) writeableCard = true; else revealedCard = true; } } if (revealedCard) cardMenu->addAction(aHide); else if (writeableCard) { if (moveMenu->isEmpty()) { moveMenu->addAction(aMoveToTopLibrary); moveMenu->addAction(aMoveToBottomLibrary); moveMenu->addAction(aMoveToGraveyard); moveMenu->addAction(aMoveToExile); } if (card->getZone()) { if (card->getZone()->getName() == "table") { if (ptMenu->isEmpty()) { ptMenu->addAction(aIncP); ptMenu->addAction(aDecP); ptMenu->addSeparator(); ptMenu->addAction(aIncT); ptMenu->addAction(aDecT); ptMenu->addSeparator(); ptMenu->addAction(aIncPT); ptMenu->addAction(aDecPT); ptMenu->addSeparator(); ptMenu->addAction(aSetPT); } cardMenu->addAction(aTap); cardMenu->addAction(aUntap); cardMenu->addAction(aDoesntUntap); cardMenu->addAction(aFlip); if (card->getFaceDown()) cardMenu->addAction(aPeek); 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]); cardMenu->addAction(aRemoveCounter[i]); cardMenu->addAction(aSetCounter[i]); } cardMenu->addSeparator(); } else if (card->getZone()->getName() == "stack") { cardMenu->addAction(aDrawArrow); cardMenu->addMenu(moveMenu); } else { cardMenu->addAction(aPlay); cardMenu->addMenu(moveMenu); } } else cardMenu->addMenu(moveMenu); } } void Player::setCardMenu(QMenu *menu) { if (aCardMenu) aCardMenu->setMenu(menu); } QMenu *Player::getCardMenu() const { if (aCardMenu) return aCardMenu->menu(); return 0; } 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::setConceded(bool _conceded) { conceded = _conceded; setVisible(!conceded); if (conceded) { clear(); emit gameConceded(); } } void Player::setMirrored(bool _mirrored) { if (mirrored != _mirrored) { mirrored = _mirrored; rearrangeZones(); } } void Player::processSceneSizeChange(int newPlayerWidth) { 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()); }