From 9c527fb5aa3f5e482bcf4c4458b1837eaa6cbe1a Mon Sep 17 00:00:00 2001 From: Max-Wilhelm Bruker Date: Sat, 15 Jan 2011 21:39:24 +0100 Subject: [PATCH] Click to hide revealed cards; MultiMove function --- cockatrice/src/carddragitem.cpp | 7 +- cockatrice/src/carditem.cpp | 29 +++- cockatrice/src/carditem.h | 5 +- cockatrice/src/cardzone.cpp | 17 +- cockatrice/src/cardzone.h | 3 +- cockatrice/src/handzone.cpp | 8 +- cockatrice/src/handzone.h | 2 +- cockatrice/src/pilezone.cpp | 8 +- cockatrice/src/pilezone.h | 2 +- cockatrice/src/player.cpp | 82 ++++++---- cockatrice/src/stackzone.cpp | 9 +- cockatrice/src/stackzone.h | 2 +- cockatrice/src/tablezone.cpp | 12 +- cockatrice/src/tablezone.h | 4 +- cockatrice/src/zoneviewzone.cpp | 15 +- cockatrice/src/zoneviewzone.h | 2 +- common/protocol.cpp | 17 ++ common/protocol.h | 17 ++ common/protocol_datastructures.h | 6 + common/protocol_item_ids.h | 97 ++++++----- common/protocol_items.cpp | 13 -- common/protocol_items.dat | 1 - common/protocol_items.h | 15 -- common/server_cardzone.cpp | 53 +++--- common/server_cardzone.h | 3 +- common/server_player.cpp | 261 +++++++++++++++++------------- common/server_player.h | 5 +- common/server_protocolhandler.cpp | 13 +- 28 files changed, 424 insertions(+), 284 deletions(-) diff --git a/cockatrice/src/carddragitem.cpp b/cockatrice/src/carddragitem.cpp index f3ab1a54..56d6c2c6 100644 --- a/cockatrice/src/carddragitem.cpp +++ b/cockatrice/src/carddragitem.cpp @@ -72,17 +72,18 @@ void CardDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) QPointF sp = pos(); sc->removeItem(this); + QList dragItemList; CardZone *startZone = static_cast(item)->getZone(); if (currentZone && !(static_cast(item)->getAttachedTo() && (startZone == currentZone))) { - if (!occupied) - currentZone->handleDropEvent(this, startZone, (sp - currentZone->scenePos()).toPoint(), faceDown); + dragItemList.append(this); for (int i = 0; i < childDrags.size(); i++) { CardDragItem *c = static_cast(childDrags[i]); if (!(static_cast(c->item)->getAttachedTo() && (startZone == currentZone)) && !c->occupied) - currentZone->handleDropEvent(static_cast(c), startZone, (sp - currentZone->scenePos() + c->getHotSpot()).toPoint(), faceDown); + dragItemList.append(c); sc->removeItem(c); } } + currentZone->handleDropEvent(dragItemList, startZone, (sp - currentZone->scenePos()).toPoint(), faceDown); event->accept(); } diff --git a/cockatrice/src/carditem.cpp b/cockatrice/src/carditem.cpp index 7e76cfa7..5bd4d655 100644 --- a/cockatrice/src/carditem.cpp +++ b/cockatrice/src/carditem.cpp @@ -16,8 +16,8 @@ #include "settingscache.h" #include "tab_game.h" -CardItem::CardItem(Player *_owner, const QString &_name, int _cardid, QGraphicsItem *parent) - : AbstractCardItem(_name, _owner, parent), zone(0), id(_cardid), attacking(false), facedown(false), destroyOnZoneChange(false), doesntUntap(false), dragItem(0), attachedTo(0) +CardItem::CardItem(Player *_owner, const QString &_name, int _cardid, bool _revealedCard, QGraphicsItem *parent) + : AbstractCardItem(_name, _owner, parent), zone(0), id(_cardid), revealedCard(_revealedCard), attacking(false), facedown(false), destroyOnZoneChange(false), doesntUntap(false), dragItem(0), attachedTo(0) { owner->addCard(this); @@ -59,6 +59,8 @@ CardItem::CardItem(Player *_owner, const QString &_name, int _cardid, QGraphicsI 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); @@ -128,7 +130,9 @@ void CardItem::updateCardMenu() { cardMenu->clear(); - if (owner->getLocal()) { + if (revealedCard) + cardMenu->addAction(aHide); + else if (owner->getLocal()) { if (zone) { if (zone->getName() == "table") { cardMenu->addAction(aTap); @@ -169,6 +173,7 @@ void CardItem::updateCardMenu() void CardItem::retranslateUi() { aPlay->setText(tr("&Play")); + aHide->setText(tr("&Hide")); aTap->setText(tr("&Tap")); aUntap->setText(tr("&Untap")); @@ -426,7 +431,10 @@ void CardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) cardMenu->exec(event->screenPos()); } else if ((event->button() == Qt::LeftButton) && !settingsCache->getDoubleClickToPlay()) { setCursor(Qt::OpenHandCursor); - playCard(event->modifiers().testFlag(Qt::ShiftModifier)); + if (revealedCard) + actHide(); + else + playCard(event->modifiers().testFlag(Qt::ShiftModifier)); } AbstractCardItem::mouseReleaseEvent(event); @@ -434,8 +442,12 @@ void CardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) void CardItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { - if (settingsCache->getDoubleClickToPlay()) - playCard(event->modifiers().testFlag(Qt::ShiftModifier)); + if (settingsCache->getDoubleClickToPlay()) { + if (revealedCard) + actHide(); + else + playCard(event->modifiers().testFlag(Qt::ShiftModifier)); + } event->accept(); } @@ -483,4 +495,9 @@ void CardItem::actCardCounterTrigger() void CardItem::actPlay() { playCard(false); +} + +void CardItem::actHide() +{ + zone->removeCard(this); } \ No newline at end of file diff --git a/cockatrice/src/carditem.h b/cockatrice/src/carditem.h index 844b3198..97b86774 100644 --- a/cockatrice/src/carditem.h +++ b/cockatrice/src/carditem.h @@ -17,6 +17,7 @@ class CardItem : public AbstractCardItem { private: CardZone *zone; int id; + bool revealedCard; bool attacking; bool facedown; QMap counters; @@ -31,6 +32,7 @@ private: QList aAddCounter, aSetCounter, aRemoveCounter; QAction *aPlay, + *aHide, *aTap, *aUntap, *aDoesntUntap, *aAttach, *aUnattach, *aSetPT, *aSetAnnotation, *aFlip, *aClone, *aMoveToTopLibrary, *aMoveToBottomLibrary, *aMoveToGraveyard, *aMoveToExile; QMenu *cardMenu, *moveMenu; @@ -45,12 +47,13 @@ private slots: void actSetPT(); void actSetAnnotation(); void actPlay(); + void actHide(); public slots: void deleteLater(); public: enum { Type = typeCard }; int type() const { return Type; } - CardItem(Player *_owner, const QString &_name = QString(), int _cardid = -1, QGraphicsItem *parent = 0); + CardItem(Player *_owner, const QString &_name = QString(), int _cardid = -1, bool revealedCard = false, QGraphicsItem *parent = 0); ~CardItem(); void retranslateUi(); CardZone *getZone() const { return zone; } diff --git a/cockatrice/src/cardzone.cpp b/cockatrice/src/cardzone.cpp index bae26ceb..9f9c275a 100644 --- a/cockatrice/src/cardzone.cpp +++ b/cockatrice/src/cardzone.cpp @@ -157,16 +157,25 @@ CardItem *CardZone::takeCard(int position, int cardId, bool /*canResize*/) return c; } +void CardZone::removeCard(CardItem *card) +{ + cards.removeAt(cards.indexOf(card)); + reorganizeCards(); + emit cardCountChanged(); + player->deleteCard(card); +} + void CardZone::moveAllToZone() { QList data = static_cast(sender())->data().toList(); QString targetZone = data[0].toString(); int targetX = data[1].toInt(); - // Cards need to be moved in reverse order so that the other - // cards' list index doesn't change - for (int i = cards.size() - 1; i >= 0; i--) - player->sendGameCommand(new Command_MoveCard(-1, getName(), cards.at(i)->getId(), player->getId(), targetZone, targetX)); + QList idList; + for (int i = 0; i < cards.size(); ++i) + idList.append(new CardId(cards[i]->getId())); + + player->sendGameCommand(new Command_MoveCard(-1, getName(), idList, player->getId(), targetZone, targetX)); } QPointF CardZone::closestGridPoint(const QPointF &point) diff --git a/cockatrice/src/cardzone.h b/cockatrice/src/cardzone.h index b8caf9ab..0b1809bb 100644 --- a/cockatrice/src/cardzone.h +++ b/cockatrice/src/cardzone.h @@ -35,7 +35,7 @@ public slots: public: enum { Type = typeZone }; int type() const { return Type; } - virtual void handleDropEvent(CardDragItem *dragItem, CardZone *startZone, const QPoint &dropPoint, bool faceDown) = 0; + virtual void handleDropEvent(const QList &dragItem, CardZone *startZone, const QPoint &dropPoint, bool faceDown) = 0; CardZone(Player *_player, const QString &_name, bool _hasCardAttr, bool _isShufflable, bool _contentsKnown, QGraphicsItem *parent = 0, bool isView = false); ~CardZone(); void retranslateUi(); @@ -54,6 +54,7 @@ public: CardItem *getCard(int cardId, const QString &cardName); // takeCard() finds a card by position and removes it from the zone and from all of its views. virtual CardItem *takeCard(int position, int cardId, bool canResize = true); + void removeCard(CardItem *card); ZoneViewZone *getView() const { return view; } void setView(ZoneViewZone *_view) { view = _view; } virtual void reorganizeCards() = 0; diff --git a/cockatrice/src/handzone.cpp b/cockatrice/src/handzone.cpp index 75b90d28..258567e3 100644 --- a/cockatrice/src/handzone.cpp +++ b/cockatrice/src/handzone.cpp @@ -37,9 +37,13 @@ void HandZone::addCardImpl(CardItem *card, int x, int /*y*/) card->update(); } -void HandZone::handleDropEvent(CardDragItem *dragItem, CardZone *startZone, const QPoint &/*dropPoint*/, bool /*faceDown*/) +void HandZone::handleDropEvent(const QList &dragItems, CardZone *startZone, const QPoint &/*dropPoint*/, bool /*faceDown*/) { - player->sendGameCommand(new Command_MoveCard(-1, startZone->getName(), dragItem->getId(), player->getId(), getName(), cards.size(), -1, false)); + QList idList; + for (int i = 0; i < dragItems.size(); ++i) + idList.append(new CardId(dragItems[i]->getId())); + + player->sendGameCommand(new Command_MoveCard(-1, startZone->getName(), idList, player->getId(), getName(), cards.size(), -1, false)); } QRectF HandZone::boundingRect() const diff --git a/cockatrice/src/handzone.h b/cockatrice/src/handzone.h index cde11e83..85dde951 100644 --- a/cockatrice/src/handzone.h +++ b/cockatrice/src/handzone.h @@ -14,7 +14,7 @@ public slots: void updateOrientation(); public: HandZone(Player *_p, bool _contentsKnown, int _zoneHeight, QGraphicsItem *parent = 0); - void handleDropEvent(CardDragItem *dragItem, CardZone *startZone, const QPoint &dropPoint, bool faceDown); + void handleDropEvent(const QList &dragItems, CardZone *startZone, const QPoint &dropPoint, bool faceDown); QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); void reorganizeCards(); diff --git a/cockatrice/src/pilezone.cpp b/cockatrice/src/pilezone.cpp index cf57df21..1c9df8f9 100644 --- a/cockatrice/src/pilezone.cpp +++ b/cockatrice/src/pilezone.cpp @@ -48,9 +48,13 @@ void PileZone::addCardImpl(CardItem *card, int x, int /*y*/) card->setParentItem(this); } -void PileZone::handleDropEvent(CardDragItem *dragItem, CardZone *startZone, const QPoint &/*dropPoint*/, bool /*faceDown*/) +void PileZone::handleDropEvent(const QList &dragItems, CardZone *startZone, const QPoint &/*dropPoint*/, bool /*faceDown*/) { - player->sendGameCommand(new Command_MoveCard(-1, startZone->getName(), dragItem->getId(), player->getId(), getName(), 0, 0, false)); + QList idList; + for (int i = 0; i < dragItems.size(); ++i) + idList.append(new CardId(dragItems[i]->getId())); + + player->sendGameCommand(new Command_MoveCard(-1, startZone->getName(), idList, player->getId(), getName(), 0, 0, false)); } void PileZone::reorganizeCards() diff --git a/cockatrice/src/pilezone.h b/cockatrice/src/pilezone.h index 7dbb4699..0e946066 100644 --- a/cockatrice/src/pilezone.h +++ b/cockatrice/src/pilezone.h @@ -9,7 +9,7 @@ public: QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); void reorganizeCards(); - void handleDropEvent(CardDragItem *dragItem, CardZone *startZone, const QPoint &dropPoint, bool faceDown); + void handleDropEvent(const QList &dragItems, CardZone *startZone, const QPoint &dropPoint, bool faceDown); protected: void mousePressEvent(QGraphicsSceneMouseEvent *event); void mouseMoveEvent(QGraphicsSceneMouseEvent *event); diff --git a/cockatrice/src/player.cpp b/cockatrice/src/player.cpp index 742ff67d..0d7ab7a4 100644 --- a/cockatrice/src/player.cpp +++ b/cockatrice/src/player.cpp @@ -563,9 +563,10 @@ void Player::actMoveTopCardsToGrave() const int maxCards = zones.value("deck")->getCards().size(); if (number > maxCards) number = maxCards; + QList idList; for (int i = 0; i < number; ++i) - commandList.append(new Command_MoveCard(-1, "deck", 0, getId(), "grave", 0, 0, false)); - sendCommandContainer(new CommandContainer(commandList)); + idList.append(new CardId(i)); + sendGameCommand(new Command_MoveCard(-1, "deck", idList, getId(), "grave", 0, 0, false)); } void Player::actMoveTopCardsToExile() @@ -578,14 +579,15 @@ void Player::actMoveTopCardsToExile() const int maxCards = zones.value("deck")->getCards().size(); if (number > maxCards) number = maxCards; + QList idList; for (int i = 0; i < number; ++i) - commandList.append(new Command_MoveCard(-1, "deck", 0, getId(), "rfg", 0, 0, false)); - sendCommandContainer(new CommandContainer(commandList)); + idList.append(new CardId(i)); + sendGameCommand(new Command_MoveCard(-1, "deck", idList, getId(), "rfg", 0, 0, false)); } void Player::actMoveTopCardToBottom() { - sendGameCommand(new Command_MoveCard(-1, "deck", 0, getId(), "deck", -1, 0, false)); + sendGameCommand(new Command_MoveCard(-1, "deck", QList() << new CardId(0), getId(), "deck", -1, 0, false)); } void Player::actUntapAll() @@ -1088,10 +1090,10 @@ void Player::playCard(CardItem *c, bool faceDown, bool tapped) { CardInfo *ci = c->getInfo(); if (ci->getTableRow() == 3) - sendGameCommand(new Command_MoveCard(-1, c->getZone()->getName(), c->getId(), getId(), "stack", 0, 0, false)); + sendGameCommand(new Command_MoveCard(-1, c->getZone()->getName(), QList() << new CardId(c->getId()), getId(), "stack", 0, 0, false)); else { QPoint gridPoint = QPoint(-1, 2 - ci->getTableRow()); - sendGameCommand(new Command_MoveCard(-1, c->getZone()->getName(), c->getId(), getId(), "table", gridPoint.x(), gridPoint.y(), faceDown, tapped)); + sendGameCommand(new Command_MoveCard(-1, c->getZone()->getName(), QList() << new CardId(c->getId()), getId(), "table", gridPoint.x(), gridPoint.y(), faceDown, tapped)); } } @@ -1276,42 +1278,54 @@ bool Player::clearCardsToDelete() void Player::cardMenuAction(QAction *a) { QList sel = scene()->selectedItems(); + QList cardList; + while (!sel.isEmpty()) + cardList.append(qgraphicsitem_cast(sel.takeFirst())); + QList commandList; - while (!sel.isEmpty()) { - unsigned int i = (unsigned int) (((double) sel.size()) * qrand() / (RAND_MAX + 1.0)); - CardItem *card = qgraphicsitem_cast(sel.takeAt(i)); - - switch (a->data().toInt()) { - case 0: - if (!card->getTapped()) - commandList.append(new Command_SetCardAttr(-1, card->getZone()->getName(), card->getId(), "tapped", "1")); - break; - case 1: - if (card->getTapped()) - commandList.append(new Command_SetCardAttr(-1, card->getZone()->getName(), card->getId(), "tapped", "0")); - break; - case 2: - commandList.append(new Command_SetCardAttr(-1, card->getZone()->getName(), card->getId(), "doesnt_untap", QString::number(!card->getDoesntUntap()))); - break; - case 3: { - QString zone = card->getZone()->getName(); - commandList.append(new Command_FlipCard(-1, zone, card->getId(), !card->getFaceDown())); - break; + if (a->data().toInt() <= 4) + for (int i = 0; i < cardList.size(); ++i) { + CardItem *card = cardList[i]; + switch (a->data().toInt()) { + case 0: + if (!card->getTapped()) + commandList.append(new Command_SetCardAttr(-1, card->getZone()->getName(), card->getId(), "tapped", "1")); + break; + case 1: + if (card->getTapped()) + commandList.append(new Command_SetCardAttr(-1, card->getZone()->getName(), card->getId(), "tapped", "0")); + break; + case 2: + commandList.append(new Command_SetCardAttr(-1, card->getZone()->getName(), card->getId(), "doesnt_untap", QString::number(!card->getDoesntUntap()))); + break; + case 3: { + QString zone = card->getZone()->getName(); + commandList.append(new Command_FlipCard(-1, zone, card->getId(), !card->getFaceDown())); + break; + } + case 4: + commandList.append(new Command_CreateToken(-1, card->getZone()->getName(), card->getName(), card->getColor(), card->getPT(), card->getAnnotation(), true, -1, card->getGridPoint().y())); + break; } - case 4: - commandList.append(new Command_CreateToken(-1, card->getZone()->getName(), card->getName(), card->getColor(), card->getPT(), card->getAnnotation(), true, -1, card->getGridPoint().y())); - break; + } + else { + QList idList; + for (int i = 0; i < cardList.size(); ++i) + idList.append(new CardId(cardList[i]->getId())); + QString startZone = cardList[0]->getZone()->getName(); + + switch (a->data().toInt()) { case 5: - commandList.append(new Command_MoveCard(-1, card->getZone()->getName(), card->getId(), getId(), "deck", 0, 0, false)); + commandList.append(new Command_MoveCard(-1, startZone, idList, getId(), "deck", 0, 0, false)); break; case 6: - commandList.append(new Command_MoveCard(-1, card->getZone()->getName(), card->getId(), getId(), "deck", -1, 0, false)); + commandList.append(new Command_MoveCard(-1, startZone, idList, getId(), "deck", -1, 0, false)); break; case 7: - commandList.append(new Command_MoveCard(-1, card->getZone()->getName(), card->getId(), getId(), "grave", 0, 0, false)); + commandList.append(new Command_MoveCard(-1, startZone, idList, getId(), "grave", 0, 0, false)); break; case 8: - commandList.append(new Command_MoveCard(-1, card->getZone()->getName(), card->getId(), getId(), "rfg", 0, 0, false)); + commandList.append(new Command_MoveCard(-1, startZone, idList, getId(), "rfg", 0, 0, false)); break; default: ; } diff --git a/cockatrice/src/stackzone.cpp b/cockatrice/src/stackzone.cpp index fa368d8e..2a2cc4cb 100644 --- a/cockatrice/src/stackzone.cpp +++ b/cockatrice/src/stackzone.cpp @@ -52,11 +52,16 @@ void StackZone::paint(QPainter *painter, const QStyleOptionGraphicsItem */*optio painter->fillRect(boundingRect(), QBrush(bgPixmap)); } -void StackZone::handleDropEvent(CardDragItem *dragItem, CardZone *startZone, const QPoint &/*dropPoint*/, bool /*faceDown*/) +void StackZone::handleDropEvent(const QList &dragItems, CardZone *startZone, const QPoint &/*dropPoint*/, bool /*faceDown*/) { if (startZone == this) return; - player->sendGameCommand(new Command_MoveCard(-1, startZone->getName(), dragItem->getId(), player->getId(), getName(), 0, 0, false)); + + QList idList; + for (int i = 0; i < dragItems.size(); ++i) + idList.append(new CardId(dragItems[i]->getId())); + + player->sendGameCommand(new Command_MoveCard(-1, startZone->getName(), idList, player->getId(), getName(), 0, 0, false)); } void StackZone::reorganizeCards() diff --git a/cockatrice/src/stackzone.h b/cockatrice/src/stackzone.h index 5bb11ce6..d03f151a 100644 --- a/cockatrice/src/stackzone.h +++ b/cockatrice/src/stackzone.h @@ -12,7 +12,7 @@ private slots: void updateBgPixmap(); public: StackZone(Player *_p, int _zoneHeight, QGraphicsItem *parent = 0); - void handleDropEvent(CardDragItem *dragItem, CardZone *startZone, const QPoint &dropPoint, bool faceDown); + void handleDropEvent(const QList &dragItems, CardZone *startZone, const QPoint &dropPoint, bool faceDown); QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); void reorganizeCards(); diff --git a/cockatrice/src/tablezone.cpp b/cockatrice/src/tablezone.cpp index 2551c8cb..bb74b403 100644 --- a/cockatrice/src/tablezone.cpp +++ b/cockatrice/src/tablezone.cpp @@ -85,14 +85,18 @@ void TableZone::addCardImpl(CardItem *card, int _x, int _y) card->update(); } -void TableZone::handleDropEvent(CardDragItem *dragItem, CardZone *startZone, const QPoint &dropPoint, bool faceDown) +void TableZone::handleDropEvent(const QList &dragItems, CardZone *startZone, const QPoint &dropPoint, bool faceDown) { - handleDropEventByGrid(dragItem, startZone, mapToGrid(dropPoint), faceDown); + handleDropEventByGrid(dragItems, startZone, mapToGrid(dropPoint), faceDown); } -void TableZone::handleDropEventByGrid(CardDragItem *dragItem, CardZone *startZone, const QPoint &gridPoint, bool faceDown, bool tapped) +void TableZone::handleDropEventByGrid(const QList &dragItems, CardZone *startZone, const QPoint &gridPoint, bool faceDown, bool tapped) { - static_cast(dragItem->getItem())->getZone()->getPlayer()->sendGameCommand(new Command_MoveCard(-1, startZone->getName(), dragItem->getId(), player->getId(), getName(), gridPoint.x(), gridPoint.y(), faceDown, tapped)); + QList idList; + for (int i = 0; i < dragItems.size(); ++i) + idList.append(new CardId(dragItems[i]->getId())); + + startZone->getPlayer()->sendGameCommand(new Command_MoveCard(-1, startZone->getName(), idList, player->getId(), getName(), gridPoint.x(), gridPoint.y(), faceDown, tapped)); } void TableZone::reorganizeCards() diff --git a/cockatrice/src/tablezone.h b/cockatrice/src/tablezone.h index 9761f8ea..b6566b4e 100644 --- a/cockatrice/src/tablezone.h +++ b/cockatrice/src/tablezone.h @@ -29,8 +29,8 @@ public: QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); void toggleTapped(); - void handleDropEvent(CardDragItem *dragItem, CardZone *startZone, const QPoint &dropPoint, bool faceDown = false); - void handleDropEventByGrid(CardDragItem *dragItem, CardZone *startZone, const QPoint &gridPoint, bool faceDown = false, bool tapped = false); + void handleDropEvent(const QList &dragItems, CardZone *startZone, const QPoint &dropPoint, bool faceDown = false); + void handleDropEventByGrid(const QList &dragItems, CardZone *startZone, const QPoint &gridPoint, bool faceDown = false, bool tapped = false); CardItem *getCardFromGrid(const QPoint &gridPoint) const; CardItem *getCardFromCoords(const QPointF &point) const; QPointF mapFromGrid(QPoint gridPoint) const; diff --git a/cockatrice/src/zoneviewzone.cpp b/cockatrice/src/zoneviewzone.cpp index f8034541..5e3f1edc 100644 --- a/cockatrice/src/zoneviewzone.cpp +++ b/cockatrice/src/zoneviewzone.cpp @@ -33,7 +33,7 @@ void ZoneViewZone::initializeCards(const QList &cardList) { if (!cardList.isEmpty()) { for (int i = 0; i < cardList.size(); ++i) - addCard(new CardItem(player, cardList[i]->getName(), cardList[i]->getId(), this), false, i); + addCard(new CardItem(player, cardList[i]->getName(), cardList[i]->getId(), revealZone, this), false, i); reorganizeCards(); } else if (!origZone->contentsKnown()) { Command_DumpZone *command = new Command_DumpZone(-1, player->getId(), name, numberCards); @@ -44,7 +44,7 @@ void ZoneViewZone::initializeCards(const QList &cardList) int number = numberCards == -1 ? c.size() : (numberCards < c.size() ? numberCards : c.size()); for (int i = 0; i < number; i++) { CardItem *card = c.at(i); - addCard(new CardItem(player, card->getName(), card->getId(), this), false, i); + addCard(new CardItem(player, card->getName(), card->getId(), revealZone, this), false, i); } reorganizeCards(); } @@ -58,7 +58,7 @@ void ZoneViewZone::zoneDumpReceived(ProtocolResponse *r) const QList &respCardList = resp->getZone()->getCardList(); for (int i = 0; i < respCardList.size(); i++) { - CardItem *card = new CardItem(player, respCardList[i]->getName(), respCardList[i]->getId(), this); + CardItem *card = new CardItem(player, respCardList[i]->getName(), respCardList[i]->getId(), revealZone, this); addCard(card, false, i); } @@ -87,7 +87,6 @@ void ZoneViewZone::reorganizeCards() cols = 2; qDebug() << "reorganizeCards: rows=" << rows << "cols=" << cols; - qDebug() << "SORT BY NAME:" << sortByName << "SORT BY TYPE:" << sortByType; CardList cardsToDisplay(cards); if (sortByName || sortByType) @@ -125,9 +124,13 @@ void ZoneViewZone::addCardImpl(CardItem *card, int x, int /*y*/) card->update(); } -void ZoneViewZone::handleDropEvent(CardDragItem *dragItem, CardZone *startZone, const QPoint &/*dropPoint*/, bool /*faceDown*/) +void ZoneViewZone::handleDropEvent(const QList &dragItems, CardZone *startZone, const QPoint &/*dropPoint*/, bool /*faceDown*/) { - player->sendGameCommand(new Command_MoveCard(-1, startZone->getName(), dragItem->getId(), player->getId(), getName(), 0, 0, false)); + QList idList; + for (int i = 0; i < dragItems.size(); ++i) + idList.append(new CardId(dragItems[i]->getId())); + + player->sendGameCommand(new Command_MoveCard(-1, startZone->getName(), idList, player->getId(), getName(), 0, 0, false)); } void ZoneViewZone::removeCard(int position) diff --git a/cockatrice/src/zoneviewzone.h b/cockatrice/src/zoneviewzone.h index d1c1acd2..b6fe2bfd 100644 --- a/cockatrice/src/zoneviewzone.h +++ b/cockatrice/src/zoneviewzone.h @@ -13,7 +13,7 @@ class ZoneViewZone : public SelectZone, public QGraphicsLayoutItem { private: QRectF bRect, optimumRect; int minRows, numberCards; - void handleDropEvent(CardDragItem *dragItem, CardZone *startZone, const QPoint &dropPoint, bool faceDown); + void handleDropEvent(const QList &dragItems, CardZone *startZone, const QPoint &dropPoint, bool faceDown); CardZone *origZone; bool revealZone; bool sortByName, sortByType; diff --git a/common/protocol.cpp b/common/protocol.cpp index b913b5a7..3448de77 100644 --- a/common/protocol.cpp +++ b/common/protocol.cpp @@ -27,6 +27,7 @@ void ProtocolItem::initializeHash() registerSerializableItem("player_ping", ServerInfo_PlayerPing::newItem); registerSerializableItem("file", DeckList_File::newItem); registerSerializableItem("directory", DeckList_Directory::newItem); + registerSerializableItem("card_id", CardId::newItem); registerSerializableItem("containercmd", CommandContainer::newItem); registerSerializableItem("containergame_event", GameEventContainer::newItem); @@ -34,6 +35,7 @@ void ProtocolItem::initializeHash() registerSerializableItem("cmddeck_upload", Command_DeckUpload::newItem); registerSerializableItem("cmddeck_select", Command_DeckSelect::newItem); registerSerializableItem("cmdset_sideboard_plan", Command_SetSideboardPlan::newItem); + registerSerializableItem("cmdmove_card", Command_MoveCard::newItem); registerSerializableItem("resp", ProtocolResponse::newItem); ProtocolResponse::initializeHash(); @@ -198,6 +200,21 @@ QList Command_SetSideboardPlan::getMoveList() const return typecastItemList(); } +Command_MoveCard::Command_MoveCard(int _gameId, const QString &_startZone, const QList &_cardIds, int _targetPlayerId, const QString &_targetZone, int _x, int _y, bool _faceDown, bool _tapped) + : GameCommand("move_card", _gameId) +{ + insertItem(new SerializableItem_String("start_zone", _startZone)); + insertItem(new SerializableItem_Int("target_player_id", _targetPlayerId)); + insertItem(new SerializableItem_String("target_zone", _targetZone)); + insertItem(new SerializableItem_Int("x", _x)); + insertItem(new SerializableItem_Int("y", _y)); + insertItem(new SerializableItem_Bool("face_down", _faceDown)); + insertItem(new SerializableItem_Bool("tapped", _tapped)); + + for (int i = 0; i < _cardIds.size(); ++i) + itemList.append(_cardIds[i]); +} + QHash ProtocolResponse::responseHash; ProtocolResponse::ProtocolResponse(int _cmdId, ResponseCode _responseCode, const QString &_itemName) diff --git a/common/protocol.h b/common/protocol.h index 7b7ba5c8..6b5954e0 100644 --- a/common/protocol.h +++ b/common/protocol.h @@ -25,6 +25,7 @@ enum ItemId { ItemId_Command_DeckUpload = ItemId_Other + 100, ItemId_Command_DeckSelect = ItemId_Other + 101, ItemId_Command_SetSideboardPlan = ItemId_Other + 102, + ItemId_Command_MoveCard = ItemId_Other + 103, ItemId_Event_ListRooms = ItemId_Other + 200, ItemId_Event_JoinRoom = ItemId_Other + 201, ItemId_Event_ListGames = ItemId_Other + 203, @@ -189,6 +190,22 @@ public: QList getMoveList() const; }; +class Command_MoveCard : public GameCommand { + Q_OBJECT +public: + Command_MoveCard(int _gameId = -1, const QString &_startZone = QString(), const QList &_cardIds = QList(), int _targetPlayerId = -1, const QString &_targetZone = QString(), int _x = -1, int _y = -1, bool _faceDown = false, bool _tapped = false); + QString getStartZone() const { return static_cast(itemMap.value("start_zone"))->getData(); } + QList getCardIds() const { return typecastItemList(); } + int getTargetPlayerId() const { return static_cast(itemMap.value("target_player_id"))->getData(); } + QString getTargetZone() const { return static_cast(itemMap.value("target_zone"))->getData(); } + int getX() const { return static_cast(itemMap.value("x"))->getData(); } + int getY() const { return static_cast(itemMap.value("y"))->getData(); } + bool getFaceDown() const { return static_cast(itemMap.value("face_down"))->getData(); } + bool getTapped() const { return static_cast(itemMap.value("tapped"))->getData(); } + static SerializableItem *newItem() { return new Command_MoveCard; } + int getItemId() const { return ItemId_Command_MoveCard; } +}; + // ----------------- // --- RESPONSES --- // ----------------- diff --git a/common/protocol_datastructures.h b/common/protocol_datastructures.h index 5e2ab4d6..a6a9c9ac 100644 --- a/common/protocol_datastructures.h +++ b/common/protocol_datastructures.h @@ -20,6 +20,12 @@ enum ResponseCode { RespNothing, RespOk, RespInvalidCommand, RespInvalidData, Re // list index, whereas cards in any other zone are referenced by their ids. enum ZoneType { PrivateZone, PublicZone, HiddenZone }; +class CardId : public SerializableItem_Int { +public: + CardId(int _cardId = -1) : SerializableItem_Int("card_id", _cardId) { } + static SerializableItem *newItem() { return new CardId; } +}; + class ServerInfo_User : public SerializableItem_Map { public: enum UserLevelFlags { diff --git a/common/protocol_item_ids.h b/common/protocol_item_ids.h index 428a3f17..77013b38 100644 --- a/common/protocol_item_ids.h +++ b/common/protocol_item_ids.h @@ -21,53 +21,52 @@ ItemId_Command_Shuffle = 1019, ItemId_Command_Mulligan = 1020, ItemId_Command_RollDie = 1021, ItemId_Command_DrawCards = 1022, -ItemId_Command_MoveCard = 1023, -ItemId_Command_FlipCard = 1024, -ItemId_Command_AttachCard = 1025, -ItemId_Command_CreateToken = 1026, -ItemId_Command_CreateArrow = 1027, -ItemId_Command_DeleteArrow = 1028, -ItemId_Command_SetCardAttr = 1029, -ItemId_Command_SetCardCounter = 1030, -ItemId_Command_IncCardCounter = 1031, -ItemId_Command_ReadyStart = 1032, -ItemId_Command_Concede = 1033, -ItemId_Command_IncCounter = 1034, -ItemId_Command_CreateCounter = 1035, -ItemId_Command_SetCounter = 1036, -ItemId_Command_DelCounter = 1037, -ItemId_Command_NextTurn = 1038, -ItemId_Command_SetActivePhase = 1039, -ItemId_Command_DumpZone = 1040, -ItemId_Command_StopDumpZone = 1041, -ItemId_Command_RevealCards = 1042, -ItemId_Event_Say = 1043, -ItemId_Event_Leave = 1044, -ItemId_Event_GameClosed = 1045, -ItemId_Event_Shuffle = 1046, -ItemId_Event_RollDie = 1047, -ItemId_Event_MoveCard = 1048, -ItemId_Event_FlipCard = 1049, -ItemId_Event_DestroyCard = 1050, -ItemId_Event_AttachCard = 1051, -ItemId_Event_CreateToken = 1052, -ItemId_Event_DeleteArrow = 1053, -ItemId_Event_SetCardAttr = 1054, -ItemId_Event_SetCardCounter = 1055, -ItemId_Event_SetCounter = 1056, -ItemId_Event_DelCounter = 1057, -ItemId_Event_SetActivePlayer = 1058, -ItemId_Event_SetActivePhase = 1059, -ItemId_Event_DumpZone = 1060, -ItemId_Event_StopDumpZone = 1061, -ItemId_Event_ServerMessage = 1062, -ItemId_Event_Message = 1063, -ItemId_Event_GameJoined = 1064, -ItemId_Event_UserLeft = 1065, -ItemId_Event_LeaveRoom = 1066, -ItemId_Event_RoomSay = 1067, -ItemId_Context_ReadyStart = 1068, -ItemId_Context_Concede = 1069, -ItemId_Context_DeckSelect = 1070, -ItemId_Other = 1071 +ItemId_Command_FlipCard = 1023, +ItemId_Command_AttachCard = 1024, +ItemId_Command_CreateToken = 1025, +ItemId_Command_CreateArrow = 1026, +ItemId_Command_DeleteArrow = 1027, +ItemId_Command_SetCardAttr = 1028, +ItemId_Command_SetCardCounter = 1029, +ItemId_Command_IncCardCounter = 1030, +ItemId_Command_ReadyStart = 1031, +ItemId_Command_Concede = 1032, +ItemId_Command_IncCounter = 1033, +ItemId_Command_CreateCounter = 1034, +ItemId_Command_SetCounter = 1035, +ItemId_Command_DelCounter = 1036, +ItemId_Command_NextTurn = 1037, +ItemId_Command_SetActivePhase = 1038, +ItemId_Command_DumpZone = 1039, +ItemId_Command_StopDumpZone = 1040, +ItemId_Command_RevealCards = 1041, +ItemId_Event_Say = 1042, +ItemId_Event_Leave = 1043, +ItemId_Event_GameClosed = 1044, +ItemId_Event_Shuffle = 1045, +ItemId_Event_RollDie = 1046, +ItemId_Event_MoveCard = 1047, +ItemId_Event_FlipCard = 1048, +ItemId_Event_DestroyCard = 1049, +ItemId_Event_AttachCard = 1050, +ItemId_Event_CreateToken = 1051, +ItemId_Event_DeleteArrow = 1052, +ItemId_Event_SetCardAttr = 1053, +ItemId_Event_SetCardCounter = 1054, +ItemId_Event_SetCounter = 1055, +ItemId_Event_DelCounter = 1056, +ItemId_Event_SetActivePlayer = 1057, +ItemId_Event_SetActivePhase = 1058, +ItemId_Event_DumpZone = 1059, +ItemId_Event_StopDumpZone = 1060, +ItemId_Event_ServerMessage = 1061, +ItemId_Event_Message = 1062, +ItemId_Event_GameJoined = 1063, +ItemId_Event_UserLeft = 1064, +ItemId_Event_LeaveRoom = 1065, +ItemId_Event_RoomSay = 1066, +ItemId_Context_ReadyStart = 1067, +ItemId_Context_Concede = 1068, +ItemId_Context_DeckSelect = 1069, +ItemId_Other = 1070 }; diff --git a/common/protocol_items.cpp b/common/protocol_items.cpp index 652f1a4c..dcf61af6 100644 --- a/common/protocol_items.cpp +++ b/common/protocol_items.cpp @@ -114,18 +114,6 @@ Command_DrawCards::Command_DrawCards(int _gameId, int _number) { insertItem(new SerializableItem_Int("number", _number)); } -Command_MoveCard::Command_MoveCard(int _gameId, const QString &_startZone, int _cardId, int _targetPlayerId, const QString &_targetZone, int _x, int _y, bool _faceDown, bool _tapped) - : GameCommand("move_card", _gameId) -{ - insertItem(new SerializableItem_String("start_zone", _startZone)); - insertItem(new SerializableItem_Int("card_id", _cardId)); - insertItem(new SerializableItem_Int("target_player_id", _targetPlayerId)); - insertItem(new SerializableItem_String("target_zone", _targetZone)); - insertItem(new SerializableItem_Int("x", _x)); - insertItem(new SerializableItem_Int("y", _y)); - insertItem(new SerializableItem_Bool("face_down", _faceDown)); - insertItem(new SerializableItem_Bool("tapped", _tapped)); -} Command_FlipCard::Command_FlipCard(int _gameId, const QString &_zone, int _cardId, bool _faceDown) : GameCommand("flip_card", _gameId) { @@ -461,7 +449,6 @@ void ProtocolItem::initializeHashAuto() itemNameHash.insert("cmdmulligan", Command_Mulligan::newItem); itemNameHash.insert("cmdroll_die", Command_RollDie::newItem); itemNameHash.insert("cmddraw_cards", Command_DrawCards::newItem); - itemNameHash.insert("cmdmove_card", Command_MoveCard::newItem); itemNameHash.insert("cmdflip_card", Command_FlipCard::newItem); itemNameHash.insert("cmdattach_card", Command_AttachCard::newItem); itemNameHash.insert("cmdcreate_token", Command_CreateToken::newItem); diff --git a/common/protocol_items.dat b/common/protocol_items.dat index 2819ddec..4941d115 100644 --- a/common/protocol_items.dat +++ b/common/protocol_items.dat @@ -20,7 +20,6 @@ 2:mulligan 2:roll_die:i,sides 2:draw_cards:i,number -2:move_card:s,start_zone:i,card_id:i,target_player_id:s,target_zone:i,x:i,y:b,face_down:b,tapped 2:flip_card:s,zone:i,card_id:b,face_down 2:attach_card:s,start_zone:i,card_id:i,target_player_id:s,target_zone:i,target_card_id 2:create_token:s,zone:s,card_name:s,color:s,pt:s,annotation:b,destroy:i,x:i,y diff --git a/common/protocol_items.h b/common/protocol_items.h index 8a32ace1..245d255f 100644 --- a/common/protocol_items.h +++ b/common/protocol_items.h @@ -182,21 +182,6 @@ public: static SerializableItem *newItem() { return new Command_DrawCards; } int getItemId() const { return ItemId_Command_DrawCards; } }; -class Command_MoveCard : public GameCommand { - Q_OBJECT -public: - Command_MoveCard(int _gameId = -1, const QString &_startZone = QString(), int _cardId = -1, int _targetPlayerId = -1, const QString &_targetZone = QString(), int _x = -1, int _y = -1, bool _faceDown = false, bool _tapped = false); - QString getStartZone() const { return static_cast(itemMap.value("start_zone"))->getData(); }; - int getCardId() const { return static_cast(itemMap.value("card_id"))->getData(); }; - int getTargetPlayerId() const { return static_cast(itemMap.value("target_player_id"))->getData(); }; - QString getTargetZone() const { return static_cast(itemMap.value("target_zone"))->getData(); }; - int getX() const { return static_cast(itemMap.value("x"))->getData(); }; - int getY() const { return static_cast(itemMap.value("y"))->getData(); }; - bool getFaceDown() const { return static_cast(itemMap.value("face_down"))->getData(); }; - bool getTapped() const { return static_cast(itemMap.value("tapped"))->getData(); }; - static SerializableItem *newItem() { return new Command_MoveCard; } - int getItemId() const { return ItemId_Command_MoveCard; } -}; class Command_FlipCard : public GameCommand { Q_OBJECT public: diff --git a/common/server_cardzone.cpp b/common/server_cardzone.cpp index a2ca1a99..2d417390 100644 --- a/common/server_cardzone.cpp +++ b/common/server_cardzone.cpp @@ -21,6 +21,8 @@ #include "server_card.h" #include "server_player.h" #include "rng_abstract.h" +#include +#include Server_CardZone::Server_CardZone(Server_Player *_player, const QString &_name, bool _has_coords, ZoneType _type) : player(_player), name(_name), has_coords(_has_coords), type(_type), cardsBeingLookedAt(0) @@ -29,7 +31,7 @@ Server_CardZone::Server_CardZone(Server_Player *_player, const QString &_name, b Server_CardZone::~Server_CardZone() { - qDebug(QString("Server_CardZone destructor: %1").arg(name).toLatin1()); + qDebug() << "Server_CardZone destructor:" << name; clear(); } @@ -41,6 +43,13 @@ void Server_CardZone::shuffle() cards = temp; } +int Server_CardZone::removeCard(Server_Card *card) +{ + int index = cards.indexOf(card); + cards.removeAt(index); + return index; +} + Server_Card *Server_CardZone::getCard(int id, bool remove, int *position) { if (type != HiddenZone) { @@ -146,29 +155,37 @@ bool Server_CardZone::isColumnEmpty(int x, int y) const void Server_CardZone::moveCard(CommandContainer *cont, QMap &coordMap, Server_Card *card, int x, int y) { coordMap.remove(card->getX()); - player->moveCard(cont, this, card->getId(), this, x, y, card->getFaceDown(), false); + player->moveCard(cont, this, QList() << card->getId(), this, x, y, card->getFaceDown(), false); coordMap.insert(x, card); } -void Server_CardZone::fixFreeSpaces(CommandContainer *cont, int x, int y) +void Server_CardZone::fixFreeSpaces(CommandContainer *cont) { QMap coordMap; - for (int i = 0; i < cards.size(); ++i) - if (cards[i]->getY() == y) - coordMap.insert(cards[i]->getX(), cards[i]); - - int baseX = (x / 3) * 3; - if (!coordMap.contains(baseX)) { - if (coordMap.contains(baseX + 1)) - moveCard(cont, coordMap, coordMap.value(baseX + 1), baseX, y); - else if (coordMap.contains(baseX + 2)) { - moveCard(cont, coordMap, coordMap.value(baseX + 2), baseX, y); - return; - } else - return; + QSet placesToLook; + for (int i = 0; i < cards.size(); ++i) { + coordMap.insert(cards[i]->getY() * 10000 + cards[i]->getX(), cards[i]); + placesToLook.insert(cards[i]->getY() * 10000 + (cards[i]->getX() / 3) * 3); + } + + QSetIterator placeIterator(placesToLook); + while (placeIterator.hasNext()) { + int foo = placeIterator.next(); + int y = foo / 10000; + int baseX = foo - y * 10000; + + if (!coordMap.contains(y * 10000 + baseX)) { + if (coordMap.contains(y * 10000 + baseX + 1)) + moveCard(cont, coordMap, coordMap.value(y * 10000 + baseX + 1), baseX, y); + else if (coordMap.contains(baseX + 2)) { + moveCard(cont, coordMap, coordMap.value(y * 10000 + baseX + 2), baseX, y); + return; + } else + return; + } + if (!coordMap.contains(y * 10000 + baseX + 1) && coordMap.contains(y * 10000 + baseX + 2)) + moveCard(cont, coordMap, coordMap.value(y * 10000 + baseX + 2), baseX + 1, y); } - if (!coordMap.contains(baseX + 1) && coordMap.contains(baseX + 2)) - moveCard(cont, coordMap, coordMap.value(baseX + 2), baseX + 1, y); } void Server_CardZone::insertCard(Server_Card *card, int x, int y) diff --git a/common/server_cardzone.h b/common/server_cardzone.h index c27d907a..62a129a1 100644 --- a/common/server_cardzone.h +++ b/common/server_cardzone.h @@ -40,6 +40,7 @@ public: Server_CardZone(Server_Player *_player, const QString &_name, bool _has_coords, ZoneType _type); ~Server_CardZone(); + int removeCard(Server_Card *card); Server_Card *getCard(int id, bool remove, int *position = NULL); int getCardsBeingLookedAt() const { return cardsBeingLookedAt; } @@ -52,7 +53,7 @@ public: int getFreeGridColumn(int x, int y, const QString &cardName) const; bool isColumnEmpty(int x, int y) const; bool isColumnStacked(int x, int y) const; - void fixFreeSpaces(CommandContainer *cont, int x, int y); + void fixFreeSpaces(CommandContainer *cont); void moveCard(CommandContainer *cont, QMap &coordMap, Server_Card *card, int x, int y); QList cards; void insertCard(Server_Card *card, int x, int y); diff --git a/common/server_player.cpp b/common/server_player.cpp index e7da0d31..a1092d39 100644 --- a/common/server_player.cpp +++ b/common/server_player.cpp @@ -8,6 +8,7 @@ #include "protocol.h" #include "protocol_items.h" #include "decklist.h" +#include Server_Player::Server_Player(Server_Game *_game, int _playerId, ServerInfo_User *_userInfo, bool _spectator, Server_ProtocolHandler *_handler) : game(_game), handler(_handler), userInfo(new ServerInfo_User(_userInfo)), deck(0), playerId(_playerId), spectator(_spectator), nextCardId(0), readyStart(false), conceded(false), deckId(-2) @@ -198,7 +199,7 @@ bool Server_Player::deleteCounter(int counterId) return true; } -ResponseCode Server_Player::moveCard(CommandContainer *cont, const QString &_startZone, int _cardId, int targetPlayerId, const QString &_targetZone, int x, int y, bool faceDown, bool tapped) +ResponseCode Server_Player::moveCard(CommandContainer *cont, const QString &_startZone, const QList &_cardIds, int targetPlayerId, const QString &_targetZone, int x, int y, bool faceDown, bool tapped) { Server_CardZone *startzone = getZones().value(_startZone); Server_Player *targetPlayer = game->getPlayers().value(targetPlayerId); @@ -208,128 +209,168 @@ ResponseCode Server_Player::moveCard(CommandContainer *cont, const QString &_sta if ((!startzone) || (!targetzone)) return RespNameNotFound; - return moveCard(cont, startzone, _cardId, targetzone, x, y, faceDown, tapped); + return moveCard(cont, startzone, _cardIds, targetzone, x, y, faceDown, tapped); } -ResponseCode Server_Player::moveCard(CommandContainer *cont, Server_CardZone *startzone, int _cardId, Server_CardZone *targetzone, int x, int y, bool faceDown, bool tapped) +class Server_Player::MoveCardCompareFunctor { +private: + int x; +public: + MoveCardCompareFunctor(int _x) : x(_x) { } + inline bool operator()(QPair a, QPair b) + { + if (a.second < x) { + if (b.second >= x) + return false; + else + return (a.second > b.second); + } else { + if (b.second < x) + return true; + else + return (a.second < b.second); + } + } +}; + +ResponseCode Server_Player::moveCard(CommandContainer *cont, Server_CardZone *startzone, const QList &_cardIds, Server_CardZone *targetzone, int x, int y, bool faceDown, bool tapped) { // Disallow controller change between different zones. if ((startzone->getName() != targetzone->getName()) && (startzone->getPlayer() != targetzone->getPlayer())) return RespContextError; - int position = -1; - Server_Card *card = startzone->getCard(_cardId, false, &position); - if (!card) - return RespNameNotFound; - if (!card->getAttachedCards().isEmpty() && !targetzone->isColumnEmpty(x, y)) - return RespContextError; - startzone->getCard(_cardId, true); + if (!targetzone->hasCoords() && (x == -1)) + x = targetzone->cards.size(); - int oldX = card->getX(), oldY = card->getY(); - - // Attachment relationships can be retained when moving a card onto the opponent's table - if (startzone->getName() != targetzone->getName()) { - // Delete all attachment relationships - if (card->getParentCard()) - card->setParentCard(0); - - // Make a copy of the list because the original one gets modified during the loop - QList attachedCards = card->getAttachedCards(); - for (int i = 0; i < attachedCards.size(); ++i) - attachedCards[i]->getZone()->getPlayer()->unattachCard(cont, attachedCards[i]); + QList > cardsToMove; + for (int i = 0; i < _cardIds.size(); ++i) { + int position; + Server_Card *card = startzone->getCard(_cardIds[i], false, &position); + if (!card) + return RespNameNotFound; + if (!card->getAttachedCards().isEmpty() && !targetzone->isColumnEmpty(x, y)) + return RespContextError; + cardsToMove.append(QPair(card, position)); } - if (startzone != targetzone) { - // Delete all arrows from and to the card - const QList &players = game->getPlayers().values(); - for (int i = 0; i < players.size(); ++i) { - QList arrowsToDelete; - QMapIterator arrowIterator(players[i]->getArrows()); - while (arrowIterator.hasNext()) { - Server_Arrow *arrow = arrowIterator.next().value(); - if ((arrow->getStartCard() == card) || (arrow->getTargetItem() == card)) - arrowsToDelete.append(arrow->getId()); + MoveCardCompareFunctor cmp(startzone == targetzone ? -1 : x); + qSort(cardsToMove.begin(), cardsToMove.end(), cmp); + + bool secondHalf = false; + int xIndex = -1; + for (int cardIndex = 0; cardIndex < cardsToMove.size(); ++cardIndex) { + Server_Card *card = cardsToMove[cardIndex].first; + int originalPosition = cardsToMove[cardIndex].second; + int position = startzone->removeCard(card); + if ((startzone == targetzone) && !startzone->hasCoords()) { + if (!secondHalf && (originalPosition < x)) { + xIndex = -1; + secondHalf = true; + } else if (secondHalf) + --xIndex; + else + ++xIndex; + } else + ++xIndex; + int newX = x + xIndex; + + // Attachment relationships can be retained when moving a card onto the opponent's table + if (startzone->getName() != targetzone->getName()) { + // Delete all attachment relationships + if (card->getParentCard()) + card->setParentCard(0); + + // Make a copy of the list because the original one gets modified during the loop + QList attachedCards = card->getAttachedCards(); + for (int i = 0; i < attachedCards.size(); ++i) + attachedCards[i]->getZone()->getPlayer()->unattachCard(cont, attachedCards[i]); + } + + if (startzone != targetzone) { + // Delete all arrows from and to the card + const QList &players = game->getPlayers().values(); + for (int i = 0; i < players.size(); ++i) { + QList arrowsToDelete; + QMapIterator arrowIterator(players[i]->getArrows()); + while (arrowIterator.hasNext()) { + Server_Arrow *arrow = arrowIterator.next().value(); + if ((arrow->getStartCard() == card) || (arrow->getTargetItem() == card)) + arrowsToDelete.append(arrow->getId()); + } + for (int j = 0; j < arrowsToDelete.size(); ++j) + players[i]->deleteArrow(arrowsToDelete[j]); } - for (int j = 0; j < arrowsToDelete.size(); ++j) - players[i]->deleteArrow(arrowsToDelete[j]); + } + + if (card->getDestroyOnZoneChange() && (startzone != targetzone)) { + cont->enqueueGameEventPrivate(new Event_DestroyCard(getPlayerId(), startzone->getName(), card->getId()), game->getGameId()); + cont->enqueueGameEventPublic(new Event_DestroyCard(getPlayerId(), startzone->getName(), card->getId()), game->getGameId()); + card->deleteLater(); + } else { + if (!targetzone->hasCoords()) { + y = 0; + card->resetState(); + } else + newX = targetzone->getFreeGridColumn(newX, y, card->getName()); + + targetzone->insertCard(card, newX, y); + + bool targetBeingLookedAt = (targetzone->getType() != HiddenZone) || (targetzone->getCardsBeingLookedAt() > newX) || (targetzone->getCardsBeingLookedAt() == -1); + bool sourceBeingLookedAt = (startzone->getType() != HiddenZone) || (startzone->getCardsBeingLookedAt() > position) || (startzone->getCardsBeingLookedAt() == -1); + + bool targetHiddenToPlayer = faceDown || !targetBeingLookedAt; + bool targetHiddenToOthers = faceDown || (targetzone->getType() != PublicZone); + bool sourceHiddenToPlayer = card->getFaceDown() || !sourceBeingLookedAt; + bool sourceHiddenToOthers = card->getFaceDown() || (startzone->getType() != PublicZone); + + QString privateCardName, publicCardName; + if (!(sourceHiddenToPlayer && targetHiddenToPlayer)) + privateCardName = card->getName(); + if (!(sourceHiddenToOthers && targetHiddenToOthers)) + publicCardName = card->getName(); + + int oldCardId = card->getId(); + if (faceDown) + card->setId(newCardId()); + card->setFaceDown(faceDown); + + // The player does not get to see which card he moved if it moves between two parts of hidden zones which + // are not being looked at. + int privateNewCardId = card->getId(); + int privateOldCardId = oldCardId; + if (!targetBeingLookedAt && !sourceBeingLookedAt) { + privateOldCardId = -1; + privateNewCardId = -1; + privateCardName = QString(); + } + int privatePosition = -1; + if (startzone->getType() == HiddenZone) + privatePosition = position; + cont->enqueueGameEventPrivate(new Event_MoveCard(getPlayerId(), privateOldCardId, privateCardName, startzone->getName(), privatePosition, targetzone->getPlayer()->getPlayerId(), targetzone->getName(), newX, y, privateNewCardId, faceDown), game->getGameId()); + cont->enqueueGameEventOmniscient(new Event_MoveCard(getPlayerId(), privateOldCardId, privateCardName, startzone->getName(), privatePosition, targetzone->getPlayer()->getPlayerId(), targetzone->getName(), newX, y, privateNewCardId, faceDown), game->getGameId()); + + // Other players do not get to see the start and/or target position of the card if the respective + // part of the zone is being looked at. The information is not needed anyway because in hidden zones, + // all cards are equal. + if ( + ((startzone->getType() == HiddenZone) && ((startzone->getCardsBeingLookedAt() > position) || (startzone->getCardsBeingLookedAt() == -1))) + || (startzone->getType() == PublicZone) + ) + position = -1; + if ((targetzone->getType() == HiddenZone) && ((targetzone->getCardsBeingLookedAt() > newX) || (targetzone->getCardsBeingLookedAt() == -1))) + newX = -1; + + if ((startzone->getType() == PublicZone) || (targetzone->getType() == PublicZone)) + cont->enqueueGameEventPublic(new Event_MoveCard(getPlayerId(), oldCardId, publicCardName, startzone->getName(), position, targetzone->getPlayer()->getPlayerId(), targetzone->getName(), newX, y, card->getId(), faceDown), game->getGameId()); + else + cont->enqueueGameEventPublic(new Event_MoveCard(getPlayerId(), -1, QString(), startzone->getName(), position, targetzone->getPlayer()->getPlayerId(), targetzone->getName(), newX, y, -1, false), game->getGameId()); + + if (tapped) + setCardAttrHelper(cont, targetzone->getName(), card->getId(), "tapped", "1"); } } - - if (card->getDestroyOnZoneChange() && (startzone != targetzone)) { - cont->enqueueGameEventPrivate(new Event_DestroyCard(getPlayerId(), startzone->getName(), card->getId()), game->getGameId()); - cont->enqueueGameEventPublic(new Event_DestroyCard(getPlayerId(), startzone->getName(), card->getId()), game->getGameId()); - if (startzone->hasCoords()) - startzone->fixFreeSpaces(cont, oldX, oldY); - card->deleteLater(); - return RespOk; - } - - if (!targetzone->hasCoords()) { - y = 0; - if (x == -1) - x = targetzone->cards.size(); - - card->resetState(); - } else - x = targetzone->getFreeGridColumn(x, y, card->getName()); - - targetzone->insertCard(card, x, y); - - bool targetBeingLookedAt = (targetzone->getType() != HiddenZone) || (targetzone->getCardsBeingLookedAt() > x) || (targetzone->getCardsBeingLookedAt() == -1); - bool sourceBeingLookedAt = (startzone->getType() != HiddenZone) || (startzone->getCardsBeingLookedAt() > position) || (startzone->getCardsBeingLookedAt() == -1); - - bool targetHiddenToPlayer = faceDown || !targetBeingLookedAt; - bool targetHiddenToOthers = faceDown || (targetzone->getType() != PublicZone); - bool sourceHiddenToPlayer = card->getFaceDown() || !sourceBeingLookedAt; - bool sourceHiddenToOthers = card->getFaceDown() || (startzone->getType() != PublicZone); - - QString privateCardName, publicCardName; - if (!(sourceHiddenToPlayer && targetHiddenToPlayer)) - privateCardName = card->getName(); - if (!(sourceHiddenToOthers && targetHiddenToOthers)) - publicCardName = card->getName(); - - int oldCardId = card->getId(); - if (faceDown) - card->setId(newCardId()); - card->setFaceDown(faceDown); - - // The player does not get to see which card he moved if it moves between two parts of hidden zones which - // are not being looked at. - int privateNewCardId = card->getId(); - int privateOldCardId = oldCardId; - if (!targetBeingLookedAt && !sourceBeingLookedAt) { - privateOldCardId = -1; - privateNewCardId = -1; - privateCardName = QString(); - } - int privatePosition = -1; - if (startzone->getType() == HiddenZone) - privatePosition = position; - cont->enqueueGameEventPrivate(new Event_MoveCard(getPlayerId(), privateOldCardId, privateCardName, startzone->getName(), privatePosition, targetzone->getPlayer()->getPlayerId(), targetzone->getName(), x, y, privateNewCardId, faceDown), game->getGameId()); - cont->enqueueGameEventOmniscient(new Event_MoveCard(getPlayerId(), privateOldCardId, privateCardName, startzone->getName(), privatePosition, targetzone->getPlayer()->getPlayerId(), targetzone->getName(), x, y, privateNewCardId, faceDown), game->getGameId()); - - // Other players do not get to see the start and/or target position of the card if the respective - // part of the zone is being looked at. The information is not needed anyway because in hidden zones, - // all cards are equal. - if ( - ((startzone->getType() == HiddenZone) && ((startzone->getCardsBeingLookedAt() > position) || (startzone->getCardsBeingLookedAt() == -1))) - || (startzone->getType() == PublicZone) - ) - position = -1; - if ((targetzone->getType() == HiddenZone) && ((targetzone->getCardsBeingLookedAt() > x) || (targetzone->getCardsBeingLookedAt() == -1))) - x = -1; - - if ((startzone->getType() == PublicZone) || (targetzone->getType() == PublicZone)) - cont->enqueueGameEventPublic(new Event_MoveCard(getPlayerId(), oldCardId, publicCardName, startzone->getName(), position, targetzone->getPlayer()->getPlayerId(), targetzone->getName(), x, y, card->getId(), faceDown), game->getGameId()); - else - cont->enqueueGameEventPublic(new Event_MoveCard(getPlayerId(), -1, QString(), startzone->getName(), position, targetzone->getPlayer()->getPlayerId(), targetzone->getName(), x, y, -1, false), game->getGameId()); - - if (tapped) - setCardAttrHelper(cont, targetzone->getName(), card->getId(), "tapped", "1"); - if (startzone->hasCoords()) - startzone->fixFreeSpaces(cont, oldX, oldY); + startzone->fixFreeSpaces(cont); return RespOk; } @@ -342,7 +383,7 @@ void Server_Player::unattachCard(CommandContainer *cont, Server_Card *card) cont->enqueueGameEventPrivate(new Event_AttachCard(getPlayerId(), zone->getName(), card->getId(), -1, QString(), -1), game->getGameId()); cont->enqueueGameEventPublic(new Event_AttachCard(getPlayerId(), zone->getName(), card->getId(), -1, QString(), -1), game->getGameId()); - moveCard(cont, zone, card->getId(), zone, -1, card->getY(), card->getFaceDown(), card->getTapped()); + moveCard(cont, zone, QList() << card->getId(), zone, -1, card->getY(), card->getFaceDown(), card->getTapped()); } ResponseCode Server_Player::setCardAttrHelper(CommandContainer *cont, const QString &zoneName, int cardId, const QString &attrName, const QString &attrValue) diff --git a/common/server_player.h b/common/server_player.h index 7a3138c3..5bd08d96 100644 --- a/common/server_player.h +++ b/common/server_player.h @@ -22,6 +22,7 @@ class CommandContainer; class Server_Player : public Server_ArrowTarget { Q_OBJECT private: + class MoveCardCompareFunctor; Server_Game *game; Server_ProtocolHandler *handler; ServerInfo_User *userInfo; @@ -74,8 +75,8 @@ public: void clearZones(); void setupZones(); - ResponseCode moveCard(CommandContainer *cont, const QString &_startZone, int _cardId, int _targetPlayer, const QString &_targetZone, int _x, int _y, bool _faceDown, bool _tapped); - ResponseCode moveCard(CommandContainer *cont, Server_CardZone *startzone, int _cardId, Server_CardZone *targetzone, int x, int y, bool faceDown, bool tapped); + ResponseCode moveCard(CommandContainer *cont, const QString &_startZone, const QList &_cardId, int _targetPlayer, const QString &_targetZone, int _x, int _y, bool _faceDown, bool _tapped); + ResponseCode moveCard(CommandContainer *cont, Server_CardZone *startzone, const QList &_cardId, Server_CardZone *targetzone, int x, int y, bool faceDown, bool tapped); void unattachCard(CommandContainer *cont, Server_Card *card); ResponseCode setCardAttrHelper(CommandContainer *cont, const QString &zone, int cardId, const QString &attrName, const QString &attrValue); diff --git a/common/server_protocolhandler.cpp b/common/server_protocolhandler.cpp index 460ed86b..c2546bd9 100644 --- a/common/server_protocolhandler.cpp +++ b/common/server_protocolhandler.cpp @@ -483,7 +483,7 @@ ResponseCode Server_ProtocolHandler::cmdMulligan(Command_Mulligan * /*cmd*/, Com Server_CardZone *deck = player->getZones().value("deck"); while (!hand->cards.isEmpty()) - player->moveCard(cont, hand, hand->cards.first()->getId(), deck, 0, 0, false, false); + player->moveCard(cont, hand, QList() << hand->cards.first()->getId(), deck, 0, 0, false, false); deck->shuffle(); cont->enqueueGameEventPrivate(new Event_Shuffle(player->getPlayerId()), game->getGameId()); @@ -545,8 +545,13 @@ ResponseCode Server_ProtocolHandler::cmdMoveCard(Command_MoveCard *cmd, CommandC if (!game->getGameStarted()) return RespGameNotStarted; - - return player->moveCard(cont, cmd->getStartZone(), cmd->getCardId(), cmd->getTargetPlayerId(), cmd->getTargetZone(), cmd->getX(), cmd->getY(), cmd->getFaceDown(), cmd->getTapped()); + + QList cardIds; + const QList &temp = cmd->getCardIds(); + for (int i = 0; i < temp.size(); ++i) + cardIds.append(temp[i]->getData()); + + return player->moveCard(cont, cmd->getStartZone(), cardIds, cmd->getTargetPlayerId(), cmd->getTargetZone(), cmd->getX(), cmd->getY(), cmd->getFaceDown(), cmd->getTapped()); } ResponseCode Server_ProtocolHandler::cmdFlipCard(Command_FlipCard *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player) @@ -646,7 +651,7 @@ ResponseCode Server_ProtocolHandler::cmdAttachCard(Command_AttachCard *cmd, Comm player->unattachCard(cont, attachedList[i]); if (targetzone->isColumnStacked(targetCard->getX(), targetCard->getY())) - targetPlayer->moveCard(cont, targetzone, targetCard->getId(), targetzone, targetzone->getFreeGridColumn(-2, targetCard->getY(), targetCard->getName()), targetCard->getY(), targetCard->getFaceDown(), false); + targetPlayer->moveCard(cont, targetzone, QList() << targetCard->getId(), targetzone, targetzone->getFreeGridColumn(-2, targetCard->getY(), targetCard->getName()), targetCard->getY(), targetCard->getFaceDown(), false); card->setParentCard(targetCard); card->setCoords(-1, card->getY());