Player refactor (#6112)

* Player refactor.

Took 1 hour 43 minutes

Took 1 minute


Took 23 seconds

* Tiny lint.

Took 3 minutes

* Hook up tap logic again.

Took 13 minutes

* Fix an include.

Took 3 minutes

* Stuff.

Took 6 minutes

* Fix typo.

Took 7 minutes

* Include.

Took 1 minute

* Reorganize method/variable definitions, remove unused ones.

Took 1 hour 8 minutes


Took 24 seconds

* Clean up some unused imports.

Took 6 minutes

* Player holds the deck, emits deckChanged(), other elements player->getDeck() to respond to changes.

Took 37 minutes

* Connect player->openDeckEditor signal directly in the player constructor

Took 6 minutes

* Emit openDeckEditor signal in player_actions again.

Took 3 minutes

* Do to-do's

Took 3 hours 32 minutes

* Lint.

Took 3 minutes

* Lint again.

Took 2 minutes

* Fix include.

Took 32 minutes

* The stack should ensure card visibility.

Took 21 minutes

* Fine, the game can remember the tab.

Took 10 minutes

Took 21 seconds

Took 9 seconds

* zoneId is a dynamic gameplay property and thus belongs in player.cpp

Took 11 minutes

Took 19 seconds

* Signal view removal, addition.

Took 5 minutes

* Ensure all players are considered local in local game.

Took 10 minutes

* ENSURE they are.

Took 8 minutes

* Bounds check data sent by QAction()

Took 54 minutes

* Move comment.

Took 20 seconds

* Reimplement logging category for game_event_handler.cpp, remove linebreaks.

Took 36 seconds

* PlayerGraphicsItem is responsible for retranslateUi, not Player.


Took 14 seconds

* Set menu for sideboard again, translate some menu titles, reimplement actIncPT action

Took 54 seconds

* Comment spacing.

Took 43 seconds

* Change message_log_widget.cpp slots to take CardZoneLogic parameters as emitted by PlayerEventHandler.

Took 7 minutes

Took 14 seconds

* Remove unused player_logger.cpp

Took 2 minutes

* Query local game state correctly from tab_supervisor again

Took 3 minutes

* Revert Deck legality checker.

Took 3 minutes

* Instantiate menu before graphics item.

Took 1 hour 5 minutes

Took 55 minutes

* Differentiate games and replays.


Took 9 seconds

* Lint.

Took 10 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
BruebachL 2025-09-11 00:49:33 +02:00 committed by GitHub
parent b8e545bfa4
commit 9601a1fa4e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
92 changed files with 7104 additions and 5827 deletions

View file

@ -1,102 +1,31 @@
#include "card_zone.h"
#include "../board/card_item.h"
#include "../cards/card_database_manager.h"
#include "../player/player.h"
#include "pb/command_move_card.pb.h"
#include "pb/serverinfo_user.pb.h"
#include "pile_zone.h"
#include "view_zone.h"
#include <QAction>
#include <QDebug>
#include <QGraphicsSceneMouseEvent>
#include <QMenu>
/**
* @param _p the player that the zone belongs to
* @param _name internal name of the zone
* @param _isShufflable whether it makes sense to shuffle this zone by default after viewing it
* @param _contentsKnown whether the cards in the zone are known to the client
* @param parent the parent graphics object.
*/
CardZone::CardZone(Player *_p,
const QString &_name,
bool _hasCardAttr,
bool _isShufflable,
bool _contentsKnown,
QGraphicsItem *parent)
: AbstractGraphicsItem(parent), player(_p), name(_name), cards(_contentsKnown), views{}, menu(nullptr),
doubleClickAction(0), hasCardAttr(_hasCardAttr), isShufflable(_isShufflable)
CardZone::CardZone(CardZoneLogic *_logic, QGraphicsItem *parent)
: AbstractGraphicsItem(parent), menu(nullptr), doubleClickAction(0), logic(_logic)
{
// If we join a game before the card db finishes loading, the cards might have the wrong printings.
// Force refresh all cards in the zone when db finishes loading to fix that.
connect(CardDatabaseManager::getInstance(), &CardDatabase::cardDatabaseLoadingFinished, this,
&CardZone::refreshCardInfos);
connect(logic, &CardZoneLogic::retranslateUi, this, &CardZone::retranslateUi);
connect(logic, &CardZoneLogic::cardAdded, this, &CardZone::onCardAdded);
connect(logic, &CardZoneLogic::setGraphicsVisibility, this, [this](bool v) { this->setVisible(v); });
connect(logic, &CardZoneLogic::updateGraphics, this, [this]() { update(); });
connect(logic, &CardZoneLogic::reorganizeCards, this, &CardZone::reorganizeCards);
}
void CardZone::onCardAdded(CardItem *addedCard)
{
addedCard->setParentItem(this);
addedCard->update();
}
void CardZone::retranslateUi()
{
for (int i = 0; i < cards.size(); ++i)
cards[i]->retranslateUi();
}
void CardZone::clearContents()
{
for (int i = 0; i < cards.size(); i++) {
// If an incorrectly implemented server doesn't return attached cards to whom they belong before dropping a
// player, we have to return them to avoid a crash.
const QList<CardItem *> &attachedCards = cards[i]->getAttachedCards();
for (auto attachedCard : attachedCards)
attachedCard->setParentItem(attachedCard->getZone());
player->deleteCard(cards.at(i));
}
cards.clear();
emit cardCountChanged();
}
QString CardZone::getTranslatedName(bool theirOwn, GrammaticalCase gc) const
{
QString ownerName = player->getName();
if (name == "hand")
return (theirOwn ? tr("their hand", "nominative") : tr("%1's hand", "nominative").arg(ownerName));
else if (name == "deck")
switch (gc) {
case CaseLookAtZone:
return (theirOwn ? tr("their library", "look at zone")
: tr("%1's library", "look at zone").arg(ownerName));
case CaseTopCardsOfZone:
return (theirOwn ? tr("of their library", "top cards of zone,")
: tr("of %1's library", "top cards of zone").arg(ownerName));
case CaseRevealZone:
return (theirOwn ? tr("their library", "reveal zone")
: tr("%1's library", "reveal zone").arg(ownerName));
case CaseShuffleZone:
return (theirOwn ? tr("their library", "shuffle") : tr("%1's library", "shuffle").arg(ownerName));
default:
return (theirOwn ? tr("their library", "nominative") : tr("%1's library", "nominative").arg(ownerName));
}
else if (name == "grave")
return (theirOwn ? tr("their graveyard", "nominative") : tr("%1's graveyard", "nominative").arg(ownerName));
else if (name == "rfg")
return (theirOwn ? tr("their exile", "nominative") : tr("%1's exile", "nominative").arg(ownerName));
else if (name == "sb")
switch (gc) {
case CaseLookAtZone:
return (theirOwn ? tr("their sideboard", "look at zone")
: tr("%1's sideboard", "look at zone").arg(ownerName));
case CaseNominative:
return (theirOwn ? tr("their sideboard", "nominative")
: tr("%1's sideboard", "nominative").arg(ownerName));
default:
break;
}
else {
return (theirOwn ? tr("their custom zone '%1'", "nominative").arg(name)
: tr("%1's custom zone '%2'", "nominative").arg(ownerName).arg(name));
}
return QString();
for (int i = 0; i < getLogic()->getCards().size(); ++i)
getLogic()->getCards()[i]->retranslateUi();
}
void CardZone::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * /*event*/)
@ -114,13 +43,6 @@ bool CardZone::showContextMenu(const QPoint &screenPos)
return false;
}
void CardZone::refreshCardInfos()
{
for (const auto &cardItem : cards) {
cardItem->refreshCardInfo();
}
}
void CardZone::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (event->button() == Qt::RightButton) {
@ -132,104 +54,6 @@ void CardZone::mousePressEvent(QGraphicsSceneMouseEvent *event)
event->ignore();
}
void CardZone::addCard(CardItem *card, const bool reorganize, const int x, const int y)
{
if (!card) {
qCWarning(CardZoneLog) << "CardZone::addCard() card is null; this shouldn't normally happen";
return;
}
for (auto *view : views) {
if (view->prepareAddCard(x)) {
view->addCard(new CardItem(player, nullptr, card->getCardRef(), card->getId()), reorganize, x, y);
}
}
card->setZone(this);
addCardImpl(card, x, y);
if (reorganize)
reorganizeCards();
emit cardCountChanged();
}
CardItem *CardZone::getCard(int cardId)
{
CardItem *c = cards.findCard(cardId);
if (!c) {
qCWarning(CardZoneLog) << "CardZone::getCard: card id=" << cardId << "not found";
return nullptr;
}
// If the card's id is -1, this zone is invisible,
// so we need to give the card an id as it comes out.
// It can be assumed that in an invisible zone, all cards are equal.
if (c->getId() == -1) {
c->setId(cardId);
}
return c;
}
CardItem *CardZone::takeCard(int position, int cardId, bool toNewZone)
{
if (position == -1) {
// position == -1 means either that the zone is indexed by card id
// or that it doesn't matter which card you take.
for (int i = 0; i < cards.size(); ++i)
if (cards[i]->getId() == cardId) {
position = i;
break;
}
if (position == -1)
position = 0;
}
if (position >= cards.size())
return nullptr;
for (auto *view : views) {
view->removeCard(position, toNewZone);
}
CardItem *c = cards.takeAt(position);
c->setId(cardId);
reorganizeCards();
emit cardCountChanged();
return c;
}
void CardZone::removeCard(CardItem *card)
{
if (!card) {
qCWarning(CardZoneLog) << "CardZone::removeCard: card is null, this shouldn't normally happen";
return;
}
cards.removeOne(card);
reorganizeCards();
emit cardCountChanged();
player->deleteCard(card);
}
void CardZone::moveAllToZone()
{
QList<QVariant> data = static_cast<QAction *>(sender())->data().toList();
QString targetZone = data[0].toString();
int targetX = data[1].toInt();
Command_MoveCard cmd;
cmd.set_start_zone(getName().toStdString());
cmd.set_target_player_id(player->getId());
cmd.set_target_zone(targetZone.toStdString());
cmd.set_x(targetX);
for (int i = 0; i < cards.size(); ++i)
cmd.mutable_cards_to_move()->add_card()->set_card_id(cards[i]->getId());
player->sendGameCommand(cmd);
}
QPointF CardZone::closestGridPoint(const QPointF &point)
{
return point;

View file

@ -1,22 +1,15 @@
#ifndef CARDZONE_H
#define CARDZONE_H
#include "../../client/translation.h"
#include "../board/abstract_graphics_item.h"
#include "../board/card_list.h"
#include "../board/graphics_item_type.h"
#include "logic/card_zone_logic.h"
#include <QLoggingCategory>
#include <QString>
inline Q_LOGGING_CATEGORY(CardZoneLog, "card_zone");
class Player;
class ZoneViewZone;
class QMenu;
class QAction;
class QPainter;
class CardDragItem;
/**
* A zone in the game that can contain cards.
* This class contains methods to get and modify the cards that are contained inside this zone.
@ -27,26 +20,21 @@ class CardZone : public AbstractGraphicsItem
{
Q_OBJECT
protected:
Player *player;
QString name;
CardList cards;
QList<ZoneViewZone *> views;
QMenu *menu;
QAction *doubleClickAction;
bool hasCardAttr;
bool isShufflable;
bool alwaysRevealTopCard;
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override;
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
virtual void addCardImpl(CardItem *card, int x, int y) = 0;
signals:
void cardCountChanged();
public slots:
void moveAllToZone();
bool showContextMenu(const QPoint &screenPos);
virtual void reorganizeCards() = 0;
virtual QPointF closestGridPoint(const QPointF &point);
private slots:
void refreshCardInfos();
QMenu *getMenu() const
{
return menu;
}
public slots:
bool showContextMenu(const QPoint &screenPos);
void onCardAdded(CardItem *addedCard);
public:
enum
@ -58,69 +46,23 @@ public:
return Type;
}
virtual void
handleDropEvent(const QList<CardDragItem *> &dragItem, CardZone *startZone, const QPoint &dropPoint) = 0;
CardZone(Player *_player,
const QString &_name,
bool _hasCardAttr,
bool _isShufflable,
bool _contentsKnown,
QGraphicsItem *parent = nullptr);
handleDropEvent(const QList<CardDragItem *> &dragItem, CardZoneLogic *startZone, const QPoint &dropPoint) = 0;
CardZone(CardZoneLogic *logic, QGraphicsItem *parent = nullptr);
void retranslateUi();
void clearContents();
bool getHasCardAttr() const
CardZoneLogic *getLogic() const
{
return hasCardAttr;
}
bool getIsShufflable() const
{
return isShufflable;
}
QMenu *getMenu() const
{
return menu;
return logic;
}
void setMenu(QMenu *_menu, QAction *_doubleClickAction = 0)
{
menu = _menu;
doubleClickAction = _doubleClickAction;
}
QString getName() const
{
return name;
}
QString getTranslatedName(bool theirOwn, GrammaticalCase gc) const;
Player *getPlayer() const
{
return player;
}
bool contentsKnown() const
{
return cards.getContentsKnown();
}
const CardList &getCards() const
{
return cards;
}
void addCard(CardItem *card, bool reorganize, int x, int y = -1);
// getCard() finds a card by id.
CardItem *getCard(int cardId);
// 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);
QList<ZoneViewZone *> &getViews()
{
return views;
}
virtual void reorganizeCards() = 0;
virtual QPointF closestGridPoint(const QPointF &point);
bool getAlwaysRevealTopCard() const
{
return alwaysRevealTopCard;
}
void setAlwaysRevealTopCard(bool _alwaysRevealTopCard)
{
alwaysRevealTopCard = _alwaysRevealTopCard;
}
private:
CardZoneLogic *logic;
};
#endif

View file

@ -9,8 +9,8 @@
#include <QPainter>
HandZone::HandZone(Player *_p, bool _contentsKnown, int _zoneHeight, QGraphicsItem *parent)
: SelectZone(_p, "hand", false, false, _contentsKnown, parent), zoneHeight(_zoneHeight)
HandZone::HandZone(HandZoneLogic *_logic, int _zoneHeight, QGraphicsItem *parent)
: SelectZone(_logic, parent), zoneHeight(_zoneHeight)
{
connect(themeManager, &ThemeManager::themeChanged, this, &HandZone::updateBg);
updateBg();
@ -22,50 +22,34 @@ void HandZone::updateBg()
update();
}
void HandZone::addCardImpl(CardItem *card, int x, int /*y*/)
{
// if x is negative set it to add at end
if (x < 0 || x >= cards.size()) {
x = cards.size();
}
cards.insert(x, card);
if (!cards.getContentsKnown()) {
card->setId(-1);
card->setCardRef({});
}
card->setParentItem(this);
card->resetState();
card->setVisible(true);
card->update();
}
void HandZone::handleDropEvent(const QList<CardDragItem *> &dragItems, CardZone *startZone, const QPoint &dropPoint)
void HandZone::handleDropEvent(const QList<CardDragItem *> &dragItems,
CardZoneLogic *startZone,
const QPoint &dropPoint)
{
QPoint point = dropPoint + scenePos().toPoint();
int x = -1;
if (SettingsCache::instance().getHorizontalHand()) {
for (x = 0; x < cards.size(); x++)
if (point.x() < static_cast<CardItem *>(cards.at(x))->scenePos().x())
for (x = 0; x < getLogic()->getCards().size(); x++)
if (point.x() < static_cast<CardItem *>(getLogic()->getCards().at(x))->scenePos().x())
break;
} else {
for (x = 0; x < cards.size(); x++)
if (point.y() < static_cast<CardItem *>(cards.at(x))->scenePos().y())
for (x = 0; x < getLogic()->getCards().size(); x++)
if (point.y() < static_cast<CardItem *>(getLogic()->getCards().at(x))->scenePos().y())
break;
}
Command_MoveCard cmd;
cmd.set_start_player_id(startZone->getPlayer()->getId());
cmd.set_start_player_id(startZone->getPlayer()->getPlayerInfo()->getId());
cmd.set_start_zone(startZone->getName().toStdString());
cmd.set_target_player_id(player->getId());
cmd.set_target_zone(getName().toStdString());
cmd.set_target_player_id(getLogic()->getPlayer()->getPlayerInfo()->getId());
cmd.set_target_zone(getLogic()->getName().toStdString());
cmd.set_x(x);
cmd.set_y(-1);
for (int i = 0; i < dragItems.size(); ++i)
cmd.mutable_cards_to_move()->add_card()->set_card_id(dragItems[i]->getId());
player->sendGameCommand(cmd);
getLogic()->getPlayer()->getPlayerActions()->sendGameCommand(cmd);
}
QRectF HandZone::boundingRect() const
@ -78,23 +62,23 @@ QRectF HandZone::boundingRect() const
void HandZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
QBrush brush = themeManager->getExtraBgBrush(ThemeManager::Hand, player->getZoneId());
QBrush brush = themeManager->getExtraBgBrush(ThemeManager::Hand, getLogic()->getPlayer()->getZoneId());
painter->fillRect(boundingRect(), brush);
}
void HandZone::reorganizeCards()
{
if (!cards.isEmpty()) {
const int cardCount = cards.size();
if (!getLogic()->getCards().isEmpty()) {
const int cardCount = getLogic()->getCards().size();
if (SettingsCache::instance().getHorizontalHand()) {
bool leftJustified = SettingsCache::instance().getLeftJustified();
qreal cardWidth = cards.at(0)->boundingRect().width();
qreal cardWidth = getLogic()->getCards().at(0)->boundingRect().width();
const int xPadding = leftJustified ? cardWidth * 1.4 : 5;
qreal totalWidth =
leftJustified ? boundingRect().width() - (1 * xPadding) - 5 : boundingRect().width() - 2 * xPadding;
for (int i = 0; i < cardCount; i++) {
CardItem *c = cards.at(i);
CardItem *c = getLogic()->getCards().at(i);
// If the total width of the cards is smaller than the available width,
// the cards do not need to overlap and are displayed in the center of the area.
if (cardWidth * cardCount > totalWidth)
@ -109,16 +93,16 @@ void HandZone::reorganizeCards()
}
} else {
qreal totalWidth = boundingRect().width();
qreal cardWidth = cards.at(0)->boundingRect().width();
qreal cardWidth = getLogic()->getCards().at(0)->boundingRect().width();
qreal xspace = 5;
qreal x1 = xspace;
qreal x2 = totalWidth - xspace - cardWidth;
for (int i = 0; i < cardCount; i++) {
CardItem *card = cards.at(i);
CardItem *card = getLogic()->getCards().at(i);
qreal x = (i % 2) ? x2 : x1;
qreal y =
divideCardSpaceInZone(i, cardCount, boundingRect().height(), cards.at(0)->boundingRect().height());
qreal y = divideCardSpaceInZone(i, cardCount, boundingRect().height(),
getLogic()->getCards().at(0)->boundingRect().height());
card->setPos(x, y);
card->setRealZValue(i);
}
@ -129,10 +113,10 @@ void HandZone::reorganizeCards()
void HandZone::sortHand()
{
if (cards.isEmpty()) {
if (getLogic()->getCards().isEmpty()) {
return;
}
cards.sortBy({CardList::SortByMainType, CardList::SortByManaValue, CardList::SortByColorGrouping});
getLogic()->sortCards({CardList::SortByMainType, CardList::SortByManaValue, CardList::SortByColorGrouping});
reorganizeCards();
}

View file

@ -1,6 +1,7 @@
#ifndef HANDZONE_H
#define HANDZONE_H
#include "logic/hand_zone_logic.h"
#include "select_zone.h"
class HandZone : public SelectZone
@ -14,16 +15,14 @@ public slots:
void updateOrientation();
public:
HandZone(Player *_p, bool _contentsKnown, int _zoneHeight, QGraphicsItem *parent = nullptr);
void handleDropEvent(const QList<CardDragItem *> &dragItems, CardZone *startZone, const QPoint &dropPoint) override;
HandZone(HandZoneLogic *_logic, int _zoneHeight, QGraphicsItem *parent = nullptr);
void
handleDropEvent(const QList<CardDragItem *> &dragItems, CardZoneLogic *startZone, const QPoint &dropPoint) override;
QRectF boundingRect() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
void reorganizeCards() override;
void sortHand();
void setWidth(qreal _width);
protected:
void addCardImpl(CardItem *card, int x, int y) override;
};
#endif

View file

@ -0,0 +1,206 @@
#include "card_zone_logic.h"
#include "../../board/card_item.h"
#include "../../cards/card_database_manager.h"
#include "../../player/player.h"
#include "../pile_zone.h"
#include "../view_zone.h"
#include "pb/command_move_card.pb.h"
#include "pb/serverinfo_user.pb.h"
#include "view_zone_logic.h"
#include <QAction>
#include <QDebug>
/**
* @param _player the player that the zone belongs to
* @param _name internal name of the zone
* @param _isShufflable whether it makes sense to shuffle this zone by default after viewing it
* @param _contentsKnown whether the cards in the zone are known to the client
* @param parent the parent QObject.
*/
CardZoneLogic::CardZoneLogic(Player *_player,
const QString &_name,
bool _hasCardAttr,
bool _isShufflable,
bool _contentsKnown,
QObject *parent)
: QObject(parent), player(_player), name(_name), cards(_contentsKnown), views{}, hasCardAttr(_hasCardAttr),
isShufflable(_isShufflable)
{
// If we join a game before the card db finishes loading, the cards might have the wrong printings.
// Force refresh all cards in the zone when db finishes loading to fix that.
connect(CardDatabaseManager::getInstance(), &CardDatabase::cardDatabaseLoadingFinished, this,
&CardZoneLogic::refreshCardInfos);
}
void CardZoneLogic::addCard(CardItem *card, const bool reorganize, const int x, const int y)
{
if (!card) {
qCWarning(CardZoneLog) << "CardZoneLogic::addCard() card is null; this shouldn't normally happen";
return;
}
for (auto *view : views) {
if (qobject_cast<ZoneViewZoneLogic *>(view->getLogic())->prepareAddCard(x)) {
view->getLogic()->addCard(new CardItem(player, nullptr, card->getCardRef(), card->getId()), reorganize, x,
y);
}
}
card->setZone(this);
emit cardAdded(card);
addCardImpl(card, x, y);
if (reorganize)
emit reorganizeCards();
emit cardCountChanged();
}
CardItem *CardZoneLogic::takeCard(int position, int cardId, bool toNewZone)
{
if (position == -1) {
// position == -1 means either that the zone is indexed by card id
// or that it doesn't matter which card you take.
for (int i = 0; i < cards.size(); ++i)
if (cards[i]->getId() == cardId) {
position = i;
break;
}
if (position == -1)
position = 0;
}
if (position >= cards.size())
return nullptr;
for (auto *view : views) {
qobject_cast<ZoneViewZoneLogic *>(view->getLogic())->removeCard(position, toNewZone);
}
CardItem *c = cards.takeAt(position);
c->setId(cardId);
emit reorganizeCards();
emit cardCountChanged();
return c;
}
CardItem *CardZoneLogic::getCard(int cardId)
{
CardItem *c = cards.findCard(cardId);
if (!c) {
qCWarning(CardZoneLog) << "CardZoneLogic::getCard: card id=" << cardId << "not found";
return nullptr;
}
// If the card's id is -1, this zone is invisible,
// so we need to give the card an id as it comes out.
// It can be assumed that in an invisible zone, all cards are equal.
if (c->getId() == -1) {
c->setId(cardId);
}
return c;
}
void CardZoneLogic::removeCard(CardItem *card)
{
if (!card) {
qCWarning(CardZoneLog) << "CardZoneLogic::removeCard: card is null, this shouldn't normally happen";
return;
}
cards.removeOne(card);
emit reorganizeCards();
emit cardCountChanged();
player->deleteCard(card);
}
void CardZoneLogic::refreshCardInfos()
{
for (const auto &cardItem : cards) {
cardItem->refreshCardInfo();
}
}
void CardZoneLogic::moveAllToZone()
{
QList<QVariant> data = static_cast<QAction *>(sender())->data().toList();
if (data.length() < 2) {
return;
}
QString targetZone = data[0].toString();
int targetX = data[1].toInt();
Command_MoveCard cmd;
cmd.set_start_zone(getName().toStdString());
cmd.set_target_player_id(player->getPlayerInfo()->getId());
cmd.set_target_zone(targetZone.toStdString());
cmd.set_x(targetX);
for (int i = 0; i < cards.size(); ++i)
cmd.mutable_cards_to_move()->add_card()->set_card_id(cards[i]->getId());
player->getPlayerActions()->sendGameCommand(cmd);
}
void CardZoneLogic::clearContents()
{
for (int i = 0; i < cards.size(); i++) {
// If an incorrectly implemented server doesn't return attached cards to whom they belong before dropping a
// player, we have to return them to avoid a crash.
const QList<CardItem *> &attachedCards = cards[i]->getAttachedCards();
for (auto attachedCard : attachedCards) {
emit attachedCard->getZone()->cardAdded(attachedCard);
}
player->deleteCard(cards.at(i));
}
cards.clear();
emit cardCountChanged();
}
QString CardZoneLogic::getTranslatedName(bool theirOwn, GrammaticalCase gc) const
{
QString ownerName = player->getPlayerInfo()->getName();
if (name == "hand")
return (theirOwn ? tr("their hand", "nominative") : tr("%1's hand", "nominative").arg(ownerName));
else if (name == "deck")
switch (gc) {
case CaseLookAtZone:
return (theirOwn ? tr("their library", "look at zone")
: tr("%1's library", "look at zone").arg(ownerName));
case CaseTopCardsOfZone:
return (theirOwn ? tr("of their library", "top cards of zone,")
: tr("of %1's library", "top cards of zone").arg(ownerName));
case CaseRevealZone:
return (theirOwn ? tr("their library", "reveal zone")
: tr("%1's library", "reveal zone").arg(ownerName));
case CaseShuffleZone:
return (theirOwn ? tr("their library", "shuffle") : tr("%1's library", "shuffle").arg(ownerName));
default:
return (theirOwn ? tr("their library", "nominative") : tr("%1's library", "nominative").arg(ownerName));
}
else if (name == "grave")
return (theirOwn ? tr("their graveyard", "nominative") : tr("%1's graveyard", "nominative").arg(ownerName));
else if (name == "rfg")
return (theirOwn ? tr("their exile", "nominative") : tr("%1's exile", "nominative").arg(ownerName));
else if (name == "sb")
switch (gc) {
case CaseLookAtZone:
return (theirOwn ? tr("their sideboard", "look at zone")
: tr("%1's sideboard", "look at zone").arg(ownerName));
case CaseNominative:
return (theirOwn ? tr("their sideboard", "nominative")
: tr("%1's sideboard", "nominative").arg(ownerName));
default:
break;
}
else {
return (theirOwn ? tr("their custom zone '%1'", "nominative").arg(name)
: tr("%1's custom zone '%2'", "nominative").arg(ownerName).arg(name));
}
return QString();
}

View file

@ -0,0 +1,113 @@
#ifndef COCKATRICE_CARD_ZONE_LOGIC_H
#define COCKATRICE_CARD_ZONE_LOGIC_H
#include "../../../client/translation.h"
#include "../../board/card_list.h"
#include <QLoggingCategory>
#include <QObject>
inline Q_LOGGING_CATEGORY(CardZoneLogicLog, "card_zone_logic");
class Player;
class ZoneViewZone;
class QMenu;
class QAction;
class QPainter;
class CardDragItem;
class CardZoneLogic : public QObject
{
Q_OBJECT
signals:
void cardAdded(CardItem *addedCard);
void cardCountChanged();
void reorganizeCards();
void updateGraphics();
void setGraphicsVisibility(bool visible);
void retranslateUi();
public:
explicit CardZoneLogic(Player *_player,
const QString &_name,
bool _hasCardAttr,
bool _isShufflable,
bool _contentsKnown,
QObject *parent = nullptr);
void addCard(CardItem *card, bool reorganize, int x, int y = -1);
// getCard() finds a card by id.
CardItem *getCard(int cardId);
void removeCard(CardItem *card);
// 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 rawInsertCard(CardItem *card, int index)
{
cards.insert(index, card);
};
[[nodiscard]] const CardList &getCards() const
{
return cards;
}
void sortCards(const QList<CardList::SortOption> &options)
{
cards.sortBy(options);
}
QString getName() const
{
return name;
}
QString getTranslatedName(bool theirOwn, GrammaticalCase gc) const;
Player *getPlayer() const
{
return player;
}
bool contentsKnown() const
{
return cards.getContentsKnown();
}
QList<ZoneViewZone *> &getViews()
{
return views;
}
void setAlwaysRevealTopCard(bool _alwaysRevealTopCard)
{
alwaysRevealTopCard = _alwaysRevealTopCard;
}
bool getAlwaysRevealTopCard() const
{
return alwaysRevealTopCard;
}
bool getHasCardAttr() const
{
return hasCardAttr;
}
bool getIsShufflable() const
{
return isShufflable;
}
void clearContents();
public slots:
void moveAllToZone();
private slots:
void refreshCardInfos();
protected:
Player *player;
QString name;
CardList cards;
QList<ZoneViewZone *> views;
bool hasCardAttr;
bool isShufflable;
bool alwaysRevealTopCard;
virtual void addCardImpl(CardItem *card, int x, int y) = 0;
};
#endif // COCKATRICE_CARD_ZONE_LOGIC_H

View file

@ -0,0 +1,29 @@
#include "hand_zone_logic.h"
#include "../../board/card_item.h"
HandZoneLogic::HandZoneLogic(Player *_player,
const QString &_name,
bool _hasCardAttr,
bool _isShufflable,
bool _contentsKnown,
QObject *parent)
: CardZoneLogic(_player, _name, _hasCardAttr, _isShufflable, _contentsKnown, parent)
{
}
void HandZoneLogic::addCardImpl(CardItem *card, int x, int /*y*/)
{
// if x is negative set it to add at end
if (x < 0 || x >= cards.size()) {
x = cards.size();
}
cards.insert(x, card);
if (!cards.getContentsKnown()) {
card->setId(-1);
card->setCardRef({});
}
card->resetState();
card->setVisible(true);
}

View file

@ -0,0 +1,20 @@
#ifndef COCKATRICE_HAND_ZONE_LOGIC_H
#define COCKATRICE_HAND_ZONE_LOGIC_H
#include "card_zone_logic.h"
class HandZoneLogic : public CardZoneLogic
{
Q_OBJECT
public:
HandZoneLogic(Player *_player,
const QString &_name,
bool _hasCardAttr,
bool _isShufflable,
bool _contentsKnown,
QObject *parent = nullptr);
protected:
void addCardImpl(CardItem *card, int x, int y) override;
};
#endif // COCKATRICE_HAND_ZONE_LOGIC_H

View file

@ -0,0 +1,33 @@
#include "pile_zone_logic.h"
#include "../../board/card_item.h"
PileZoneLogic::PileZoneLogic(Player *_player,
const QString &_name,
bool _hasCardAttr,
bool _isShufflable,
bool _contentsKnown,
QObject *parent)
: CardZoneLogic(_player, _name, _hasCardAttr, _isShufflable, _contentsKnown, parent)
{
}
void PileZoneLogic::addCardImpl(CardItem *card, int x, int /*y*/)
{
connect(card, &CardItem::sigPixmapUpdated, this, &PileZoneLogic::callUpdate);
// if x is negative set it to add at end
if (x < 0 || x >= cards.size()) {
x = cards.size();
}
cards.insert(x, card);
card->setPos(0, 0);
if (!contentsKnown()) {
card->setCardRef({});
card->setId(-1);
// If we obscure a previously revealed card, its name has to be forgotten
if (cards.size() > x + 1)
cards.at(x + 1)->setCardRef({});
}
card->setVisible(false);
card->resetState();
}

View file

@ -0,0 +1,25 @@
#ifndef COCKATRICE_PILE_ZONE_LOGIC_H
#define COCKATRICE_PILE_ZONE_LOGIC_H
#include "card_zone_logic.h"
class PileZoneLogic : public CardZoneLogic
{
Q_OBJECT
signals:
void callUpdate();
public:
PileZoneLogic(Player *_player,
const QString &_name,
bool _hasCardAttr,
bool _isShufflable,
bool _contentsKnown,
QObject *parent = nullptr);
protected:
void addCardImpl(CardItem *card, int x, int y) override;
};
#endif // COCKATRICE_PILE_ZONE_LOGIC_H

View file

@ -0,0 +1,29 @@
#include "stack_zone_logic.h"
#include "../../board/card_item.h"
StackZoneLogic::StackZoneLogic(Player *_player,
const QString &_name,
bool _hasCardAttr,
bool _isShufflable,
bool _contentsKnown,
QObject *parent)
: CardZoneLogic(_player, _name, _hasCardAttr, _isShufflable, _contentsKnown, parent)
{
}
void StackZoneLogic::addCardImpl(CardItem *card, int x, int /*y*/)
{
// if x is negative set it to add at end
if (x < 0 || x >= cards.size()) {
x = static_cast<int>(cards.size());
}
cards.insert(x, card);
if (!cards.getContentsKnown()) {
card->setId(-1);
card->setCardRef({});
}
card->resetState(true);
card->setVisible(true);
}

View file

@ -0,0 +1,20 @@
#ifndef COCKATRICE_STACK_ZONE_LOGIC_H
#define COCKATRICE_STACK_ZONE_LOGIC_H
#include "card_zone_logic.h"
class StackZoneLogic : public CardZoneLogic
{
Q_OBJECT
public:
StackZoneLogic(Player *_player,
const QString &_name,
bool _hasCardAttr,
bool _isShufflable,
bool _contentsKnown,
QObject *parent = nullptr);
protected:
void addCardImpl(CardItem *card, int x, int y) override;
};
#endif // COCKATRICE_STACK_ZONE_LOGIC_H

View file

@ -0,0 +1,29 @@
#include "table_zone_logic.h"
#include "../../board/card_item.h"
TableZoneLogic::TableZoneLogic(Player *_player,
const QString &_name,
bool _hasCardAttr,
bool _isShufflable,
bool _contentsKnown,
QObject *parent)
: CardZoneLogic(_player, _name, _hasCardAttr, _isShufflable, _contentsKnown, parent)
{
}
void TableZoneLogic::addCardImpl(CardItem *card, int _x, int _y)
{
cards.append(card);
card->setGridPoint(QPoint(_x, _y));
card->setVisible(true);
}
CardItem *TableZoneLogic::takeCard(int position, int cardId, bool toNewZone)
{
CardItem *result = CardZoneLogic::takeCard(position, cardId);
if (toNewZone)
emit contentSizeChanged();
return result;
}

View file

@ -0,0 +1,34 @@
#ifndef COCKATRICE_TABLE_ZONE_LOGIC_H
#define COCKATRICE_TABLE_ZONE_LOGIC_H
#include "card_zone_logic.h"
class TableZoneLogic : public CardZoneLogic
{
Q_OBJECT
signals:
void contentSizeChanged();
void toggleTapped();
public:
TableZoneLogic(Player *_player,
const QString &_name,
bool _hasCardAttr,
bool _isShufflable,
bool _contentsKnown,
QObject *parent = nullptr);
protected:
void addCardImpl(CardItem *card, int x, int y) override;
/**
* @brief Removes a card from view.
*
* @param position card position
* @param cardId id of card to take
* @param toNewZone Whether the destination of the card is not the same as the starting zone. Defaults to true
* @return CardItem that has been removed
*/
CardItem *takeCard(int position, int cardId, bool toNewZone = true) override;
};
#endif // COCKATRICE_TABLE_ZONE_LOGIC_H

View file

@ -0,0 +1,159 @@
#include "view_zone_logic.h"
#include "../../../settings/cache_settings.h"
#include "../../board/card_item.h"
ZoneViewZoneLogic::ZoneViewZoneLogic(Player *_player,
CardZoneLogic *_origZone,
int _numberCards,
bool _revealZone,
bool _writeableRevealZone,
bool _isReversed,
QObject *parent)
: CardZoneLogic(_player, _origZone->getName(), false, false, true, parent), origZone(_origZone),
numberCards(_numberCards), revealZone(_revealZone), writeableRevealZone(_writeableRevealZone),
isReversed(_isReversed)
{
}
/**
* Checks if inserting a card at the given position requires an actual new card to be created and added to the view.
* Also does any cardId updates that would be required if a card is inserted in that position.
*
* Note that this method can end up modifying the cardIds despite returning false.
* (for example, if the card is inserted into a hidden portion of the deck while the view is reversed)
*
* Make sure to call this method once before calling addCard(), so that you skip creating a new CardItem and calling
* addCard() if it's not required.
*
* @param x The position to insert the card at.
* @return Whether to proceed with calling addCard.
*/
bool ZoneViewZoneLogic::prepareAddCard(int x)
{
bool doInsert = false;
if (!isReversed) {
if (x <= cards.size() || cards.size() == -1) {
doInsert = true;
}
} else {
// map x (which is in origZone indexes) to this viewZone's cardList index
int firstId = cards.isEmpty() ? origZone->getCards().size() : cards.front()->getId();
int insertionIndex = x - firstId;
if (insertionIndex >= 0) {
// card was put into a portion of the deck that's in the view
doInsert = true;
} else {
// card was put into a portion of the deck that's not in the view; update ids but don't insert card
updateCardIds(ADD_CARD);
}
}
// autoclose check is done both here and in removeCard
if (cards.isEmpty() && !doInsert && SettingsCache::instance().getCloseEmptyCardView()) {
emit closeView();
}
return doInsert;
}
/**
* Make sure prepareAddCard() was called before calling addCard().
* This method assumes we already checked that the card is being inserted into the visible portion
*/
void ZoneViewZoneLogic::addCardImpl(CardItem *card, int x, int /*y*/)
{
if (!isReversed) {
// if x is negative set it to add at end
// if x is out-of-bounds then also set it to add at the end
if (x < 0 || x >= cards.size()) {
x = cards.size();
}
cards.insert(x, card);
} else {
// map x (which is in origZone indexes) to this viewZone's cardList index
int firstId = cards.isEmpty() ? origZone->getCards().size() : cards.front()->getId();
int insertionIndex = x - firstId;
// qMin to prevent out-of-bounds error when bottoming a card that is already in the view
cards.insert(qMin(insertionIndex, cards.size()), card);
}
updateCardIds(ADD_CARD);
reorganizeCards();
}
void ZoneViewZoneLogic::updateCardIds(CardAction action)
{
if (origZone->contentsKnown()) {
return;
}
if (cards.isEmpty()) {
return;
}
int cardCount = cards.size();
auto startId = 0;
if (isReversed) {
// the card has not been added to origZone's cardList at this point
startId = origZone->getCards().size() - cardCount;
switch (action) {
case INITIALIZE:
break;
case ADD_CARD:
startId += 1;
break;
case REMOVE_CARD:
startId -= 1;
break;
}
}
for (int i = 0; i < cardCount; ++i) {
cards[i]->setId(i + startId);
}
}
void ZoneViewZoneLogic::removeCard(int position, bool toNewZone)
{
if (isReversed) {
position -= cards.first()->getId();
if (position < 0 || position >= cards.size()) {
updateCardIds(REMOVE_CARD);
return;
}
}
if (position >= cards.size()) {
return;
}
CardItem *card = cards.takeAt(position);
card->deleteLater();
// The toNewZone check is to prevent the view from auto-closing if the view contains only a single card and that
// card gets dragged within the view.
// Another autoclose check is done in prepareAddCard so that the view autocloses if the last card was moved to an
// unrevealed portion of the same zone.
if (cards.isEmpty() && SettingsCache::instance().getCloseEmptyCardView() && toNewZone) {
emit closeView();
return;
}
updateCardIds(REMOVE_CARD);
reorganizeCards();
}
void ZoneViewZoneLogic::setWriteableRevealZone(bool _writeableRevealZone)
{
if (writeableRevealZone && !_writeableRevealZone) {
emit addToViews();
} else if (!writeableRevealZone && _writeableRevealZone) {
emit removeFromViews();
}
writeableRevealZone = _writeableRevealZone;
}

View file

@ -0,0 +1,65 @@
#ifndef COCKATRICE_VIEW_ZONE_LOGIC_H
#define COCKATRICE_VIEW_ZONE_LOGIC_H
#include "card_zone_logic.h"
class ZoneViewZoneLogic : public CardZoneLogic
{
Q_OBJECT
signals:
void addToViews();
void removeFromViews();
void closeView();
private:
CardZoneLogic *origZone;
int numberCards;
bool revealZone, writeableRevealZone;
bool isReversed;
public:
enum CardAction
{
INITIALIZE,
ADD_CARD,
REMOVE_CARD
};
ZoneViewZoneLogic(Player *_player,
CardZoneLogic *_origZone,
int _numberCards,
bool _revealZone,
bool _writeableRevealZone,
bool _isReversed,
QObject *parent = nullptr);
bool prepareAddCard(int x);
void removeCard(int position, bool toNewZone);
void updateCardIds(CardAction action);
int getNumberCards() const
{
return numberCards;
}
bool getRevealZone() const
{
return revealZone;
}
bool getWriteableRevealZone() const
{
return writeableRevealZone;
}
void setWriteableRevealZone(bool _writeableRevealZone);
bool getIsReversed() const
{
return isReversed;
}
CardZoneLogic *getOriginalZone() const
{
return origZone;
}
protected:
void addCardImpl(CardItem *card, int x, int y) override;
};
#endif // COCKATRICE_VIEW_ZONE_LOGIC_H

View file

@ -3,6 +3,7 @@
#include "../board/card_drag_item.h"
#include "../board/card_item.h"
#include "../player/player.h"
#include "logic/pile_zone_logic.h"
#include "pb/command_move_card.pb.h"
#include "view_zone.h"
@ -10,8 +11,7 @@
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
PileZone::PileZone(Player *_p, const QString &_name, bool _isShufflable, bool _contentsKnown, QGraphicsItem *parent)
: CardZone(_p, _name, false, _isShufflable, _contentsKnown, parent)
PileZone::PileZone(PileZoneLogic *_logic, QGraphicsItem *parent) : CardZone(_logic, parent)
{
setCacheMode(DeviceCoordinateCache); // Do not move this line to the parent constructor!
setAcceptHoverEvents(true);
@ -47,52 +47,30 @@ void PileZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*optio
{
painter->drawPath(shape());
if (!cards.isEmpty())
cards.at(0)->paintPicture(painter, cards.at(0)->getTranslatedSize(painter), 90);
if (!getLogic()->getCards().isEmpty())
getLogic()->getCards().at(0)->paintPicture(painter, getLogic()->getCards().at(0)->getTranslatedSize(painter),
90);
painter->translate((float)CARD_WIDTH / 2, (float)CARD_HEIGHT / 2);
painter->rotate(-90);
painter->translate((float)-CARD_WIDTH / 2, (float)-CARD_HEIGHT / 2);
paintNumberEllipse(cards.size(), 28, Qt::white, -1, -1, painter);
paintNumberEllipse(getLogic()->getCards().size(), 28, Qt::white, -1, -1, painter);
}
void PileZone::addCardImpl(CardItem *card, int x, int /*y*/)
{
connect(card, &CardItem::sigPixmapUpdated, this, &PileZone::callUpdate);
// if x is negative set it to add at end
if (x < 0 || x >= cards.size()) {
x = cards.size();
}
cards.insert(x, card);
card->setPos(0, 0);
if (!contentsKnown()) {
card->setCardRef({});
card->setId(-1);
// If we obscure a previously revealed card, its name has to be forgotten
if (cards.size() > x + 1)
cards.at(x + 1)->setCardRef({});
}
card->setVisible(false);
card->resetState();
card->setParentItem(this);
}
void PileZone::handleDropEvent(const QList<CardDragItem *> &dragItems,
CardZone *startZone,
const QPoint & /*dropPoint*/)
void PileZone::handleDropEvent(const QList<CardDragItem *> &dragItems, CardZoneLogic *startZone, const QPoint &)
{
Command_MoveCard cmd;
cmd.set_start_player_id(startZone->getPlayer()->getId());
cmd.set_start_player_id(startZone->getPlayer()->getPlayerInfo()->getId());
cmd.set_start_zone(startZone->getName().toStdString());
cmd.set_target_player_id(player->getId());
cmd.set_target_zone(getName().toStdString());
cmd.set_target_player_id(getLogic()->getPlayer()->getPlayerInfo()->getId());
cmd.set_target_zone(getLogic()->getName().toStdString());
cmd.set_x(0);
cmd.set_y(0);
for (int i = 0; i < dragItems.size(); ++i)
cmd.mutable_cards_to_move()->add_card()->set_card_id(dragItems[i]->getId());
player->sendGameCommand(cmd);
getLogic()->getPlayer()->getPlayerActions()->sendGameCommand(cmd);
}
void PileZone::reorganizeCards()
@ -119,13 +97,14 @@ void PileZone::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
QApplication::startDragDistance())
return;
if (cards.isEmpty())
if (getLogic()->getCards().isEmpty())
return;
bool faceDown = event->modifiers().testFlag(Qt::ShiftModifier);
bool bottomCard = event->modifiers().testFlag(Qt::ControlModifier);
CardItem *card = bottomCard ? cards.last() : cards.first();
const int cardid = contentsKnown() ? card->getId() : (bottomCard ? cards.size() - 1 : 0);
CardItem *card = bottomCard ? getLogic()->getCards().last() : getLogic()->getCards().first();
const int cardid =
getLogic()->contentsKnown() ? card->getId() : (bottomCard ? getLogic()->getCards().size() - 1 : 0);
CardDragItem *drag = card->createDragItem(cardid, event->pos(), event->scenePos(), faceDown);
drag->grabMouse();
setCursor(Qt::OpenHandCursor);
@ -138,7 +117,7 @@ void PileZone::mouseReleaseEvent(QGraphicsSceneMouseEvent * /*event*/)
void PileZone::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
if (!cards.isEmpty())
cards[0]->processHoverEvent();
if (!getLogic()->getCards().isEmpty())
getLogic()->getCards()[0]->processHoverEvent();
QGraphicsItem::hoverEnterEvent(event);
}

View file

@ -2,6 +2,7 @@
#define PILEZONE_H
#include "card_zone.h"
#include "logic/pile_zone_logic.h"
/**
* A CardZone where the cards are in a single pile instead of being laid out.
@ -17,23 +18,19 @@ private slots:
}
public:
PileZone(Player *_p,
const QString &_name,
bool _isShufflable,
bool _contentsKnown,
QGraphicsItem *parent = nullptr);
QRectF boundingRect() const override;
QPainterPath shape() const override;
PileZone(PileZoneLogic *_logic, QGraphicsItem *parent);
[[nodiscard]] QRectF boundingRect() const override;
[[nodiscard]] QPainterPath shape() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
void reorganizeCards() override;
void handleDropEvent(const QList<CardDragItem *> &dragItems, CardZone *startZone, const QPoint &dropPoint) override;
void
handleDropEvent(const QList<CardDragItem *> &dragItems, CardZoneLogic *startZone, const QPoint &dropPoint) override;
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
void addCardImpl(CardItem *card, int x, int y) override;
};
#endif

View file

@ -32,13 +32,7 @@ qreal divideCardSpaceInZone(qreal index, int cardCount, qreal totalHeight, qreal
return y;
}
SelectZone::SelectZone(Player *_player,
const QString &_name,
bool _hasCardAttr,
bool _isShufflable,
bool _contentsKnown,
QGraphicsItem *parent)
: CardZone(_player, _name, _hasCardAttr, _isShufflable, _contentsKnown, parent)
SelectZone::SelectZone(CardZoneLogic *_logic, QGraphicsItem *parent) : CardZone(_logic, parent)
{
}
@ -57,8 +51,8 @@ void SelectZone::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
pos.setY(br.height());
QRectF selectionRect = QRectF(selectionOrigin, pos).normalized();
for (auto card : cards) {
if (card->getAttachedTo() && card->getAttachedTo()->getZone() != this) {
for (auto card : getLogic()->getCards()) {
if (card->getAttachedTo() && card->getAttachedTo()->getZone() != getLogic()) {
continue;
}

View file

@ -21,12 +21,7 @@ protected:
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
public:
SelectZone(Player *_player,
const QString &_name,
bool _hasCardAttr,
bool _isShufflable,
bool _contentsKnown,
QGraphicsItem *parent = nullptr);
SelectZone(CardZoneLogic *logic, QGraphicsItem *parent = nullptr);
};
qreal divideCardSpaceInZone(qreal index, int cardCount, qreal totalHeight, qreal cardHeight, bool reverse = false);

View file

@ -6,13 +6,14 @@
#include "../board/card_drag_item.h"
#include "../board/card_item.h"
#include "../player/player.h"
#include "logic/stack_zone_logic.h"
#include "pb/command_move_card.pb.h"
#include <QPainter>
#include <QSet>
StackZone::StackZone(Player *_p, int _zoneHeight, QGraphicsItem *parent)
: SelectZone(_p, "stack", false, false, true, parent), zoneHeight(_zoneHeight)
StackZone::StackZone(StackZoneLogic *_logic, int _zoneHeight, QGraphicsItem *parent)
: SelectZone(_logic, parent), zoneHeight(_zoneHeight)
{
connect(themeManager, &ThemeManager::themeChanged, this, &StackZone::updateBg);
updateBg();
@ -24,24 +25,6 @@ void StackZone::updateBg()
update();
}
void StackZone::addCardImpl(CardItem *card, int x, int /*y*/)
{
// if x is negative set it to add at end
if (x < 0 || x >= cards.size()) {
x = static_cast<int>(cards.size());
}
cards.insert(x, card);
if (!cards.getContentsKnown()) {
card->setId(-1);
card->setCardRef({});
}
card->setParentItem(this);
card->resetState(true);
card->setVisible(true);
card->update();
}
QRectF StackZone::boundingRect() const
{
return {0, 0, 100, zoneHeight};
@ -49,27 +32,29 @@ QRectF StackZone::boundingRect() const
void StackZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
QBrush brush = themeManager->getExtraBgBrush(ThemeManager::Stack, player->getZoneId());
QBrush brush = themeManager->getExtraBgBrush(ThemeManager::Stack, getLogic()->getPlayer()->getZoneId());
painter->fillRect(boundingRect(), brush);
}
void StackZone::handleDropEvent(const QList<CardDragItem *> &dragItems, CardZone *startZone, const QPoint &dropPoint)
void StackZone::handleDropEvent(const QList<CardDragItem *> &dragItems,
CardZoneLogic *startZone,
const QPoint &dropPoint)
{
if (startZone == nullptr || startZone->getPlayer() == nullptr) {
return;
}
Command_MoveCard cmd;
cmd.set_start_player_id(startZone->getPlayer()->getId());
cmd.set_start_player_id(startZone->getPlayer()->getPlayerInfo()->getId());
cmd.set_start_zone(startZone->getName().toStdString());
cmd.set_target_player_id(player->getId());
cmd.set_target_zone(getName().toStdString());
cmd.set_target_player_id(getLogic()->getPlayer()->getPlayerInfo()->getId());
cmd.set_target_zone(getLogic()->getName().toStdString());
int index = 0;
if (!cards.isEmpty()) {
const auto cardCount = static_cast<int>(cards.size());
const auto &card = cards.at(0);
if (!getLogic()->getCards().isEmpty()) {
const auto cardCount = static_cast<int>(getLogic()->getCards().size());
const auto &card = getLogic()->getCards().at(0);
index = qRound(divideCardSpaceInZone(dropPoint.y(), cardCount, boundingRect().height(),
card->boundingRect().height(), true));
@ -78,9 +63,9 @@ void StackZone::handleDropEvent(const QList<CardDragItem *> &dragItems, CardZone
// currently, so clamp it to avoid crashes.
index = qBound(0, index, cardCount - 1);
if (startZone == this) {
if (startZone == getLogic()) {
const auto &dragItem = dragItems.at(0);
const auto &card = cards.at(index);
const auto &card = getLogic()->getCards().at(index);
if (card->getId() == dragItem->getId()) {
return;
@ -97,24 +82,24 @@ void StackZone::handleDropEvent(const QList<CardDragItem *> &dragItems, CardZone
}
}
player->sendGameCommand(cmd);
getLogic()->getPlayer()->getPlayerActions()->sendGameCommand(cmd);
}
void StackZone::reorganizeCards()
{
if (!cards.isEmpty()) {
const auto cardCount = static_cast<int>(cards.size());
if (!getLogic()->getCards().isEmpty()) {
const auto cardCount = static_cast<int>(getLogic()->getCards().size());
qreal totalWidth = boundingRect().width();
qreal cardWidth = cards.at(0)->boundingRect().width();
qreal cardWidth = getLogic()->getCards().at(0)->boundingRect().width();
qreal xspace = 5;
qreal x1 = xspace;
qreal x2 = totalWidth - xspace - cardWidth;
for (int i = 0; i < cardCount; i++) {
CardItem *card = cards.at(i);
CardItem *card = getLogic()->getCards().at(i);
qreal x = (i % 2) ? x2 : x1;
qreal y =
divideCardSpaceInZone(i, cardCount, boundingRect().height(), cards.at(0)->boundingRect().height());
qreal y = divideCardSpaceInZone(i, cardCount, boundingRect().height(),
getLogic()->getCards().at(0)->boundingRect().height());
card->setPos(x, y);
card->setRealZValue(i);
}

View file

@ -1,6 +1,7 @@
#ifndef STACKZONE_H
#define STACKZONE_H
#include "logic/stack_zone_logic.h"
#include "select_zone.h"
class StackZone : public SelectZone
@ -12,14 +13,12 @@ private slots:
void updateBg();
public:
StackZone(Player *_p, int _zoneHeight, QGraphicsItem *parent = nullptr);
void handleDropEvent(const QList<CardDragItem *> &dragItems, CardZone *startZone, const QPoint &dropPoint) override;
StackZone(StackZoneLogic *_logic, int _zoneHeight, QGraphicsItem *parent);
void
handleDropEvent(const QList<CardDragItem *> &dragItems, CardZoneLogic *startZone, const QPoint &dropPoint) override;
QRectF boundingRect() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
void reorganizeCards() override;
protected:
void addCardImpl(CardItem *card, int x, int y) override;
};
#endif

View file

@ -7,6 +7,7 @@
#include "../board/card_item.h"
#include "../cards/card_info.h"
#include "../player/player.h"
#include "logic/table_zone_logic.h"
#include "pb/command_move_card.pb.h"
#include "pb/command_set_card_attr.pb.h"
@ -19,9 +20,10 @@ const QColor TableZone::FADE_MASK = QColor(0, 0, 0, 80);
const QColor TableZone::GRADIENT_COLOR = QColor(255, 255, 255, 150);
const QColor TableZone::GRADIENT_COLORLESS = QColor(255, 255, 255, 0);
TableZone::TableZone(Player *_p, const QString &name, QGraphicsItem *parent)
: SelectZone(_p, name, true, false, true, parent), active(false)
TableZone::TableZone(TableZoneLogic *_logic, QGraphicsItem *parent) : SelectZone(_logic, parent), active(false)
{
connect(_logic, &TableZoneLogic::contentSizeChanged, this, &TableZone::resizeToContents);
connect(_logic, &TableZoneLogic::toggleTapped, this, &TableZone::toggleTapped);
connect(themeManager, &ThemeManager::themeChanged, this, &TableZone::updateBg);
connect(&SettingsCache::instance(), &SettingsCache::invertVerticalCoordinateChanged, this,
&TableZone::reorganizeCards);
@ -48,13 +50,15 @@ QRectF TableZone::boundingRect() const
bool TableZone::isInverted() const
{
return ((player->getMirrored() && !SettingsCache::instance().getInvertVerticalCoordinate()) ||
(!player->getMirrored() && SettingsCache::instance().getInvertVerticalCoordinate()));
return ((getLogic()->getPlayer()->getGraphicsItem()->getMirrored() &&
!SettingsCache::instance().getInvertVerticalCoordinate()) ||
(!getLogic()->getPlayer()->getGraphicsItem()->getMirrored() &&
SettingsCache::instance().getInvertVerticalCoordinate()));
}
void TableZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
QBrush brush = themeManager->getExtraBgBrush(ThemeManager::Table, player->getZoneId());
QBrush brush = themeManager->getExtraBgBrush(ThemeManager::Table, getLogic()->getPlayer()->getZoneId());
painter->fillRect(boundingRect(), brush);
if (active) {
@ -108,30 +112,22 @@ void TableZone::paintLandDivider(QPainter *painter)
painter->drawLine(QPointF(0, separatorY), QPointF(width, separatorY));
}
void TableZone::addCardImpl(CardItem *card, int _x, int _y)
{
cards.append(card);
card->setGridPoint(QPoint(_x, _y));
card->setParentItem(this);
card->setVisible(true);
card->update();
}
void TableZone::handleDropEvent(const QList<CardDragItem *> &dragItems, CardZone *startZone, const QPoint &dropPoint)
void TableZone::handleDropEvent(const QList<CardDragItem *> &dragItems,
CardZoneLogic *startZone,
const QPoint &dropPoint)
{
handleDropEventByGrid(dragItems, startZone, mapToGrid(dropPoint));
}
void TableZone::handleDropEventByGrid(const QList<CardDragItem *> &dragItems,
CardZone *startZone,
CardZoneLogic *startZone,
const QPoint &gridPoint)
{
Command_MoveCard cmd;
cmd.set_start_player_id(startZone->getPlayer()->getId());
cmd.set_start_player_id(startZone->getPlayer()->getPlayerInfo()->getId());
cmd.set_start_zone(startZone->getName().toStdString());
cmd.set_target_player_id(player->getId());
cmd.set_target_zone(getName().toStdString());
cmd.set_target_player_id(getLogic()->getPlayer()->getPlayerInfo()->getId());
cmd.set_target_zone(getLogic()->getName().toStdString());
cmd.set_x(gridPoint.x());
cmd.set_y(gridPoint.y());
@ -139,7 +135,7 @@ void TableZone::handleDropEventByGrid(const QList<CardDragItem *> &dragItems,
CardToMove *ctm = cmd.mutable_cards_to_move()->add_card();
ctm->set_card_id(item->getId());
ctm->set_face_down(item->getFaceDown());
if (startZone->getName() != name && !item->getFaceDown()) {
if (startZone->getName() != getLogic()->getName() && !item->getFaceDown()) {
const auto &card = item->getItem()->getCard();
if (card) {
ctm->set_pt(card.getInfo().getPowTough().toStdString());
@ -147,7 +143,7 @@ void TableZone::handleDropEventByGrid(const QList<CardDragItem *> &dragItems,
}
}
startZone->getPlayer()->sendGameCommand(cmd);
startZone->getPlayer()->getPlayerActions()->sendGameCommand(cmd);
}
void TableZone::reorganizeCards()
@ -155,8 +151,8 @@ void TableZone::reorganizeCards()
// Calculate card stack widths so mapping functions work properly
computeCardStackWidths();
for (int i = 0; i < cards.size(); ++i) {
QPoint gridPoint = cards[i]->getGridPos();
for (int i = 0; i < getLogic()->getCards().size(); ++i) {
QPoint gridPoint = getLogic()->getCards()[i]->getGridPos();
if (gridPoint.x() == -1)
continue;
@ -164,16 +160,16 @@ void TableZone::reorganizeCards()
qreal x = mapPoint.x();
qreal y = mapPoint.y();
int numberAttachedCards = cards[i]->getAttachedCards().size();
int numberAttachedCards = getLogic()->getCards()[i]->getAttachedCards().size();
qreal actualX = x + numberAttachedCards * STACKED_CARD_OFFSET_X;
qreal actualY = y;
if (numberAttachedCards)
actualY += 15;
cards[i]->setPos(actualX, actualY);
cards[i]->setRealZValue((actualY + CARD_HEIGHT) * 100000 + (actualX + 1) * 100);
getLogic()->getCards()[i]->setPos(actualX, actualY);
getLogic()->getCards()[i]->setRealZValue((actualY + CARD_HEIGHT) * 100000 + (actualX + 1) * 100);
QListIterator<CardItem *> attachedCardIterator(cards[i]->getAttachedCards());
QListIterator<CardItem *> attachedCardIterator(getLogic()->getCards()[i]->getAttachedCards());
int j = 0;
while (attachedCardIterator.hasNext()) {
++j;
@ -211,22 +207,15 @@ void TableZone::toggleTapped()
CardItem *temp = qgraphicsitem_cast<CardItem *>(selectedItem);
if (temp->getTapped() != tapAll) {
Command_SetCardAttr *cmd = new Command_SetCardAttr;
cmd->set_zone(name.toStdString());
cmd->set_zone(getLogic()->getName().toStdString());
cmd->set_card_id(temp->getId());
cmd->set_attribute(AttrTapped);
cmd->set_attr_value(tapAll ? "1" : "0");
cmdList.append(cmd);
}
}
player->sendGameCommand(player->prepareGameCommand(cmdList));
}
CardItem *TableZone::takeCard(int position, int cardId, bool toNewZone)
{
CardItem *result = CardZone::takeCard(position, cardId);
if (toNewZone)
resizeToContents();
return result;
getLogic()->getPlayer()->getPlayerActions()->sendGameCommand(
getLogic()->getPlayer()->getPlayerActions()->prepareGameCommand(cmdList));
}
void TableZone::resizeToContents()
@ -234,9 +223,9 @@ void TableZone::resizeToContents()
int xMax = 0;
// Find rightmost card position, which includes the left margin amount.
for (int i = 0; i < cards.size(); ++i)
if (cards[i]->pos().x() > xMax)
xMax = (int)cards[i]->pos().x();
for (int i = 0; i < getLogic()->getCards().size(); ++i)
if (getLogic()->getCards()[i]->pos().x() > xMax)
xMax = (int)getLogic()->getCards()[i]->pos().x();
// Minimum width is the rightmost card position plus enough room for
// another card with padding, then margin.
@ -254,9 +243,9 @@ void TableZone::resizeToContents()
CardItem *TableZone::getCardFromGrid(const QPoint &gridPoint) const
{
for (int i = 0; i < cards.size(); i++)
if (cards.at(i)->getGridPoint() == gridPoint)
return cards.at(i);
for (int i = 0; i < getLogic()->getCards().size(); i++)
if (getLogic()->getCards().at(i)->getGridPoint() == gridPoint)
return getLogic()->getCards().at(i);
return 0;
}
@ -271,8 +260,8 @@ void TableZone::computeCardStackWidths()
// Each card stack is three grid points worth of card locations.
// First pass: compute the number of cards at each card stack.
QMap<int, int> cardStackCount;
for (int i = 0; i < cards.size(); ++i) {
const QPoint &gridPoint = cards[i]->getGridPos();
for (int i = 0; i < getLogic()->getCards().size(); ++i) {
const QPoint &gridPoint = getLogic()->getCards()[i]->getGridPos();
if (gridPoint.x() == -1)
continue;
@ -282,15 +271,16 @@ void TableZone::computeCardStackWidths()
// Second pass: compute the width at each card stack.
cardStackWidth.clear();
for (int i = 0; i < cards.size(); ++i) {
const QPoint &gridPoint = cards[i]->getGridPos();
for (int i = 0; i < getLogic()->getCards().size(); ++i) {
const QPoint &gridPoint = getLogic()->getCards()[i]->getGridPos();
if (gridPoint.x() == -1)
continue;
const int key = getCardStackMapKey(gridPoint.x() / 3, gridPoint.y());
const int stackCount = cardStackCount.value(key, 0);
if (stackCount == 1)
cardStackWidth.insert(key, CARD_WIDTH + cards[i]->getAttachedCards().size() * STACKED_CARD_OFFSET_X);
cardStackWidth.insert(key, CARD_WIDTH + getLogic()->getCards()[i]->getAttachedCards().size() *
STACKED_CARD_OFFSET_X);
else
cardStackWidth.insert(key, CARD_WIDTH + (stackCount - 1) * STACKED_CARD_OFFSET_X);
}

View file

@ -2,6 +2,7 @@
#define TABLEZONE_H
#include "../board/abstract_card_item.h"
#include "logic/table_zone_logic.h"
#include "select_zone.h"
/*
@ -75,7 +76,7 @@ private:
/*
If this TableZone is currently active
*/
bool active;
bool active = false;
bool isInverted() const;
@ -98,7 +99,7 @@ public:
@param _p the Player
@param parent defaults to null
*/
explicit TableZone(Player *_p, const QString &name, QGraphicsItem *parent = nullptr);
explicit TableZone(TableZoneLogic *_logic, QGraphicsItem *parent = nullptr);
/**
@return a QRectF of the TableZone bounding box.
@ -121,12 +122,14 @@ public:
/**
See HandleDropEventByGrid
*/
void handleDropEvent(const QList<CardDragItem *> &dragItems, CardZone *startZone, const QPoint &dropPoint) override;
void
handleDropEvent(const QList<CardDragItem *> &dragItems, CardZoneLogic *startZone, const QPoint &dropPoint) override;
/**
Handles the placement of cards
*/
void handleDropEventByGrid(const QList<CardDragItem *> &dragItems, CardZone *startZone, const QPoint &gridPoint);
void
handleDropEventByGrid(const QList<CardDragItem *> &dragItems, CardZoneLogic *startZone, const QPoint &gridPoint);
/**
@return CardItem from grid location
@ -142,16 +145,6 @@ public:
static int clampValidTableRow(const int row);
/**
Removes a card from view.
@param position card position
@param cardId id of card to take
@param toNewZone Whether the destination of the card is not the same as the starting zone. Defaults to true
@return CardItem that has been removed
*/
CardItem *takeCard(int position, int cardId, bool toNewZone = true) override;
/**
Resizes the TableZone in case CardItems are within or
outside of the TableZone constraints.
@ -177,9 +170,6 @@ public:
update();
}
protected:
void addCardImpl(CardItem *card, int x, int y) override;
private:
void paintZoneOutline(QPainter *painter);
void paintLandDivider(QPainter *painter);

View file

@ -5,6 +5,7 @@
#include "../board/card_item.h"
#include "../cards/card_info.h"
#include "../player/player.h"
#include "logic/view_zone_logic.h"
#include "pb/command_dump_zone.pb.h"
#include "pb/command_move_card.pb.h"
#include "pb/response_dump_zone.pb.h"
@ -23,21 +24,24 @@
* @param _writeableRevealZone whether the player can interact with the revealed cards.
* @param parent the parent QGraphicsWidget containing the reveal zone
*/
ZoneViewZone::ZoneViewZone(Player *_p,
CardZone *_origZone,
int _numberCards,
bool _revealZone,
bool _writeableRevealZone,
QGraphicsItem *parent,
bool _isReversed)
: SelectZone(_p, _origZone->getName(), false, false, true, parent), bRect(QRectF()), minRows(0),
numberCards(_numberCards), origZone(_origZone), revealZone(_revealZone),
writeableRevealZone(_writeableRevealZone), groupBy(CardList::NoSort), sortBy(CardList::NoSort),
isReversed(_isReversed)
ZoneViewZone::ZoneViewZone(ZoneViewZoneLogic *_logic, QGraphicsItem *parent)
: SelectZone(_logic, parent), bRect(QRectF()), minRows(0), groupBy(CardList::NoSort), sortBy(CardList::NoSort)
{
if (!(revealZone && !writeableRevealZone)) {
origZone->getViews().append(this);
if (!(qobject_cast<ZoneViewZoneLogic *>(getLogic())->getRevealZone() &&
!qobject_cast<ZoneViewZoneLogic *>(getLogic())->getWriteableRevealZone())) {
qobject_cast<ZoneViewZoneLogic *>(getLogic())->getOriginalZone()->getViews().append(this);
}
connect(_logic, &ZoneViewZoneLogic::closeView, this, &ZoneViewZone::close);
}
void ZoneViewZone::addToViews()
{
qobject_cast<ZoneViewZoneLogic *>(getLogic())->getOriginalZone()->getViews().append(this);
}
void ZoneViewZone::removeFromViews()
{
qobject_cast<ZoneViewZoneLogic *>(getLogic())->getOriginalZone()->getViews().removeOne(this);
}
/**
@ -47,8 +51,9 @@ ZoneViewZone::ZoneViewZone(Player *_p,
void ZoneViewZone::close()
{
emit closed();
if (!(revealZone && !writeableRevealZone)) {
origZone->getViews().removeOne(this);
if (!(qobject_cast<ZoneViewZoneLogic *>(getLogic())->getRevealZone() &&
!qobject_cast<ZoneViewZoneLogic *>(getLogic())->getWriteableRevealZone())) {
qobject_cast<ZoneViewZoneLogic *>(getLogic())->getOriginalZone()->getViews().removeOne(this);
}
deleteLater();
}
@ -67,29 +72,31 @@ void ZoneViewZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*o
void ZoneViewZone::initializeCards(const QList<const ServerInfo_Card *> &cardList)
{
int numberCards = qobject_cast<ZoneViewZoneLogic *>(getLogic())->getNumberCards();
if (!cardList.isEmpty()) {
for (int i = 0; i < cardList.size(); ++i) {
auto card = cardList[i];
CardRef cardRef = {QString::fromStdString(card->name()), QString::fromStdString(card->provider_id())};
addCard(new CardItem(player, this, cardRef, card->id()), false, i);
getLogic()->addCard(new CardItem(getLogic()->getPlayer(), this, cardRef, card->id()), false, i);
}
reorganizeCards();
} else if (!origZone->contentsKnown()) {
} else if (!qobject_cast<ZoneViewZoneLogic *>(getLogic())->getOriginalZone()->contentsKnown()) {
Command_DumpZone cmd;
cmd.set_player_id(player->getId());
cmd.set_zone_name(name.toStdString());
cmd.set_player_id(getLogic()->getPlayer()->getPlayerInfo()->getId());
cmd.set_zone_name(getLogic()->getName().toStdString());
cmd.set_number_cards(numberCards);
cmd.set_is_reversed(isReversed);
cmd.set_is_reversed(qobject_cast<ZoneViewZoneLogic *>(getLogic())->getIsReversed());
PendingCommand *pend = player->prepareGameCommand(cmd);
PendingCommand *pend = getLogic()->getPlayer()->getPlayerActions()->prepareGameCommand(cmd);
connect(pend, &PendingCommand::finished, this, &ZoneViewZone::zoneDumpReceived);
player->sendGameCommand(pend);
getLogic()->getPlayer()->getPlayerActions()->sendGameCommand(pend);
} else {
const CardList &c = origZone->getCards();
const CardList &c = qobject_cast<ZoneViewZoneLogic *>(getLogic())->getOriginalZone()->getCards();
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, this, card->getCardRef(), card->getId()), false, i);
getLogic()->addCard(new CardItem(getLogic()->getPlayer(), this, card->getCardRef(), card->getId()), false,
i);
}
reorganizeCards();
}
@ -103,55 +110,21 @@ void ZoneViewZone::zoneDumpReceived(const Response &r)
const ServerInfo_Card &cardInfo = resp.zone_info().card_list(i);
auto cardName = QString::fromStdString(cardInfo.name());
auto cardProviderId = QString::fromStdString(cardInfo.provider_id());
auto *card = new CardItem(player, this, {cardName, cardProviderId}, cardInfo.id(), this);
cards.insert(i, card);
auto card = new CardItem(getLogic()->getPlayer(), this, {cardName, cardProviderId}, cardInfo.id(), getLogic());
getLogic()->rawInsertCard(card, i);
}
updateCardIds(INITIALIZE);
qobject_cast<ZoneViewZoneLogic *>(getLogic())->updateCardIds(ZoneViewZoneLogic::INITIALIZE);
reorganizeCards();
emit cardCountChanged();
}
void ZoneViewZone::updateCardIds(CardAction action)
{
if (origZone->contentsKnown()) {
return;
}
if (cards.isEmpty()) {
return;
}
int cardCount = cards.size();
auto startId = 0;
if (isReversed) {
// the card has not been added to origZone's cardList at this point
startId = origZone->getCards().size() - cardCount;
switch (action) {
case INITIALIZE:
break;
case ADD_CARD:
startId += 1;
break;
case REMOVE_CARD:
startId -= 1;
break;
}
}
for (int i = 0; i < cardCount; ++i) {
cards[i]->setId(i + startId);
}
emit getLogic()->cardCountChanged();
}
// Because of boundingRect(), this function must not be called before the zone was added to a scene.
void ZoneViewZone::reorganizeCards()
{
// filter cards
CardList cardsToDisplay = CardList(cards.getContentsKnown());
for (auto card : cards) {
CardList cardsToDisplay = CardList(getLogic()->getCards().getContentsKnown());
for (auto card : getLogic()->getCards()) {
if (filterString.check(card->getCard().getCardPtr())) {
card->show();
cardsToDisplay.append(card);
@ -297,122 +270,23 @@ void ZoneViewZone::setPileView(int _pileView)
reorganizeCards();
}
/**
* Checks if inserting a card at the given position requires an actual new card to be created and added to the view.
* Also does any cardId updates that would be required if a card is inserted in that position.
*
* Note that this method can end up modifying the cardIds despite returning false.
* (for example, if the card is inserted into a hidden portion of the deck while the view is reversed)
*
* Make sure to call this method once before calling addCard(), so that you skip creating a new CardItem and calling
* addCard() if it's not required.
*
* @param x The position to insert the card at.
* @return Whether to proceed with calling addCard.
*/
bool ZoneViewZone::prepareAddCard(int x)
{
bool doInsert = false;
if (!isReversed) {
if (x <= cards.size() || cards.size() == -1) {
doInsert = true;
}
} else {
// map x (which is in origZone indexes) to this viewZone's cardList index
int firstId = cards.isEmpty() ? origZone->getCards().size() : cards.front()->getId();
int insertionIndex = x - firstId;
if (insertionIndex >= 0) {
// card was put into a portion of the deck that's in the view
doInsert = true;
} else {
// card was put into a portion of the deck that's not in the view; update ids but don't insert card
updateCardIds(ADD_CARD);
}
}
// autoclose check is done both here and in removeCard
if (cards.isEmpty() && !doInsert && SettingsCache::instance().getCloseEmptyCardView()) {
close();
}
return doInsert;
}
/**
* Make sure prepareAddCard() was called before calling addCard().
* This method assumes we already checked that the card is being inserted into the visible portion
*/
void ZoneViewZone::addCardImpl(CardItem *card, int x, int /*y*/)
{
if (!isReversed) {
// if x is negative set it to add at end
// if x is out-of-bounds then also set it to add at the end
if (x < 0 || x >= cards.size()) {
x = cards.size();
}
cards.insert(x, card);
} else {
// map x (which is in origZone indexes) to this viewZone's cardList index
int firstId = cards.isEmpty() ? origZone->getCards().size() : cards.front()->getId();
int insertionIndex = x - firstId;
// qMin to prevent out-of-bounds error when bottoming a card that is already in the view
cards.insert(qMin(insertionIndex, cards.size()), card);
}
card->setParentItem(this);
card->update();
updateCardIds(ADD_CARD);
reorganizeCards();
}
void ZoneViewZone::handleDropEvent(const QList<CardDragItem *> &dragItems,
CardZone *startZone,
CardZoneLogic *startZone,
const QPoint & /*dropPoint*/)
{
Command_MoveCard cmd;
cmd.set_start_player_id(startZone->getPlayer()->getId());
cmd.set_start_player_id(startZone->getPlayer()->getPlayerInfo()->getId());
cmd.set_start_zone(startZone->getName().toStdString());
cmd.set_target_player_id(player->getId());
cmd.set_target_zone(getName().toStdString());
cmd.set_target_player_id(getLogic()->getPlayer()->getPlayerInfo()->getId());
cmd.set_target_zone(getLogic()->getName().toStdString());
cmd.set_x(0);
cmd.set_y(0);
cmd.set_is_reversed(isReversed);
cmd.set_is_reversed(qobject_cast<ZoneViewZoneLogic *>(getLogic())->getIsReversed());
for (int i = 0; i < dragItems.size(); ++i)
cmd.mutable_cards_to_move()->add_card()->set_card_id(dragItems[i]->getId());
player->sendGameCommand(cmd);
}
void ZoneViewZone::removeCard(int position, bool toNewZone)
{
if (isReversed) {
position -= cards.first()->getId();
if (position < 0 || position >= cards.size()) {
updateCardIds(REMOVE_CARD);
return;
}
}
if (position >= cards.size()) {
return;
}
CardItem *card = cards.takeAt(position);
card->deleteLater();
// The toNewZone check is to prevent the view from auto-closing if the view contains only a single card and that
// card gets dragged within the view.
// Another autoclose check is done in prepareAddCard so that the view autocloses if the last card was moved to an
// unrevealed portion of the same zone.
if (cards.isEmpty() && SettingsCache::instance().getCloseEmptyCardView() && toNewZone) {
close();
return;
}
updateCardIds(REMOVE_CARD);
reorganizeCards();
getLogic()->getPlayer()->getPlayerActions()->sendGameCommand(cmd);
}
void ZoneViewZone::setGeometry(const QRectF &rect)
@ -427,16 +301,6 @@ QSizeF ZoneViewZone::sizeHint(Qt::SizeHint /*which*/, const QSizeF & /*constrain
return optimumRect.size();
}
void ZoneViewZone::setWriteableRevealZone(bool _writeableRevealZone)
{
if (writeableRevealZone && !_writeableRevealZone) {
origZone->getViews().append(this);
} else if (!writeableRevealZone && _writeableRevealZone) {
origZone->getViews().removeOne(this);
}
writeableRevealZone = _writeableRevealZone;
}
void ZoneViewZone::wheelEvent(QGraphicsSceneWheelEvent *event)
{
emit wheelEventReceived(event);

View file

@ -2,6 +2,7 @@
#define ZONEVIEWERZONE_H
#include "../filters/filter_string.h"
#include "logic/view_zone_logic.h"
#include "select_zone.h"
#include <QGraphicsLayoutItem>
@ -33,22 +34,10 @@ private:
static constexpr int VERTICAL_PADDING = 5;
QRectF bRect, optimumRect;
int minRows, numberCards;
CardZone *origZone;
bool revealZone, writeableRevealZone;
int minRows;
FilterString filterString = FilterString("");
CardList::SortOption groupBy, sortBy;
bool pileView;
bool isReversed;
enum CardAction
{
INITIALIZE,
ADD_CARD,
REMOVE_CARD
};
void updateCardIds(CardAction action);
struct GridSize
{
@ -58,45 +47,23 @@ private:
GridSize positionCardsForDisplay(CardList &cards, CardList::SortOption pileOption = CardList::NoSort);
void handleDropEvent(const QList<CardDragItem *> &dragItems, CardZone *startZone, const QPoint &dropPoint) override;
void
handleDropEvent(const QList<CardDragItem *> &dragItems, CardZoneLogic *startZone, const QPoint &dropPoint) override;
public:
ZoneViewZone(Player *_p,
CardZone *_origZone,
int _numberCards = -1,
bool _revealZone = false,
bool _writeableRevealZone = false,
QGraphicsItem *parent = nullptr,
bool _isReversed = false);
ZoneViewZone(ZoneViewZoneLogic *_logic, QGraphicsItem *parent);
QRectF boundingRect() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
void reorganizeCards() override;
void initializeCards(const QList<const ServerInfo_Card *> &cardList = QList<const ServerInfo_Card *>());
bool prepareAddCard(int x);
void removeCard(int position, bool toNewZone);
int getNumberCards() const
{
return numberCards;
}
void setGeometry(const QRectF &rect) override;
QRectF getOptimumRect() const
{
return optimumRect;
}
bool getRevealZone() const
{
return revealZone;
}
bool getWriteableRevealZone() const
{
return writeableRevealZone;
}
void setWriteableRevealZone(bool _writeableRevealZone);
bool getIsReversed() const
{
return isReversed;
}
public slots:
void addToViews();
void removeFromViews();
void close();
void setFilterString(const QString &_filterString);
void setGroupBy(CardList::SortOption _groupBy);
@ -110,7 +77,6 @@ signals:
void wheelEventReceived(QGraphicsSceneWheelEvent *event);
protected:
void addCardImpl(CardItem *card, int x, int y) override;
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const override;
void wheelEvent(QGraphicsSceneWheelEvent *event) override;
};

View file

@ -29,7 +29,7 @@
* @param _writeableRevealZone whether the player can interact with the revealed cards.
*/
ZoneViewWidget::ZoneViewWidget(Player *_player,
CardZone *_origZone,
CardZoneLogic *_origZone,
int numberCards,
bool _revealZone,
bool _writeableRevealZone,
@ -130,8 +130,9 @@ ZoneViewWidget::ZoneViewWidget(Player *_player,
vbox->addItem(zoneHBox);
zone =
new ZoneViewZone(player, _origZone, numberCards, _revealZone, _writeableRevealZone, zoneContainer, _isReversed);
zone = new ZoneViewZone(new ZoneViewZoneLogic(player, _origZone, numberCards, _revealZone, _writeableRevealZone,
_isReversed, zoneContainer),
zoneContainer);
connect(zone, &ZoneViewZone::wheelEventReceived, scrollBarProxy, &ScrollableGraphicsProxyWidget::recieveWheelEvent);
retranslateUi();
@ -211,7 +212,7 @@ void ZoneViewWidget::processSetPileView(QT_STATE_CHANGED_T value)
void ZoneViewWidget::retranslateUi()
{
setWindowTitle(zone->getTranslatedName(false, CaseNominative));
setWindowTitle(zone->getLogic()->getTranslatedName(false, CaseNominative));
{ // We can't change the strings after they're put into the QComboBox, so this is our workaround
int oldIndex = groupBySelector.currentIndex();
@ -353,7 +354,7 @@ void ZoneViewWidget::closeEvent(QCloseEvent *event)
// manually call zone->close in order to remove it from the origZones views
zone->close();
if (shuffleCheckBox.isChecked())
player->sendGameCommand(Command_Shuffle());
player->getPlayerActions()->sendGameCommand(Command_Shuffle());
zoneDeleted();
event->accept();
}

View file

@ -2,6 +2,7 @@
#define ZONEVIEWWIDGET_H
#include "../../utility/macros.h"
#include "logic/card_zone_logic.h"
#include <QCheckBox>
#include <QComboBox>
@ -75,7 +76,7 @@ private slots:
public:
ZoneViewWidget(Player *_player,
CardZone *_origZone,
CardZoneLogic *_origZone,
int numberCards = 0,
bool _revealZone = false,
bool _writeableRevealZone = false,