Cockatrice/cockatrice/src/game/zones/table_zone.h
Basile Clement 286a7494d3
client: Support arbitrary game zones (#5877)
* Remove `isView` flag from CardZone

This flag is used for two purposes:

 1. It is used as a check for casting to a zone to a `ZoneViewZone`;

 2. Non-view zones are added to the player's zones on construction

This patch removes the `isView` flag and instead:

 1. We directly cast zones to `ZoneViewZone` using a dynamic (qobject)
    cast and use the result of the cast instead of the `isView` flag to
    detect if we are a view zone or not;

 2. The player records its own zones when they are created, simplifying
    control flow.

* Review

* client: Support arbitrary game zones

Currently, the client ignores cards in unknown zones, as there is an
implicit assumption that the set of zones known by the server and the
client are the same.

This patch makes it so that the client accept "custom zones" from the
server (zones outside the builtin deck, graveyard, exile, sideboard,
table, stack and hand zones) using the information from the
ServerInfo_CardZone. Moving cards from/into these zones happens
through a "View custom zone" action in the Game > Player menu and
properly appears in the chat.

Note that this patch intentionally does not introduce any support for
having the server actually create such zones. Instead, this patch aims
to improve backwards compatibility for when we do get to adding this
capability in the future, by making sure that current clients will be
able to interact with future new zones (even if suboptimally).
2025-05-06 21:18:08 -04:00

207 lines
4.9 KiB
C++

#ifndef TABLEZONE_H
#define TABLEZONE_H
#include "../board/abstract_card_item.h"
#include "select_zone.h"
/*
* TableZone is the grid based rect where CardItems may be placed.
* It is the main play zone and can be customized with background images.
*
* TODO: Refactor methods to make more readable, extract some logic to
* private methods (Im looking at you TableZone::reorganizeCards())
*/
class TableZone : public SelectZone
{
Q_OBJECT
signals:
void sizeChanged();
private:
static const int TABLEROWS = 3;
/*
Margins between table edges and cards, paddings between cards
*/
static const int MARGIN_LEFT = 20;
static const int MARGIN_RIGHT = 15;
static const int MARGIN_TOP = 10;
static const int MARGIN_BOTTOM = 30;
static const int PADDING_X = 35;
static const int PADDING_Y = 30;
/*
Minimum width of the table zone including margins.
*/
static const int MIN_WIDTH = MARGIN_LEFT + (5 * CARD_WIDTH) + MARGIN_RIGHT;
/*
Offset sizes when cards are stacked on each other in the grid
*/
static const int STACKED_CARD_OFFSET_X = CARD_WIDTH / 3;
static const int STACKED_CARD_OFFSET_Y = PADDING_Y / 3;
/*
Width of the box line drawn in the margin around the active player's area
*/
static const int BOX_LINE_WIDTH = 10;
/*
Default inactive mask and border gradient
*/
static const QColor BACKGROUND_COLOR;
static const QColor FADE_MASK;
static const QColor GRADIENT_COLOR;
static const QColor GRADIENT_COLORLESS;
/*
Size and shape variables
*/
int width;
int height;
int currentMinimumWidth;
/*
Internal cache for widths of stacks of cards by row and column.
*/
QMap<int, int> cardStackWidth;
/*
Holds any custom background image for the TableZone
*/
QPixmap backgroundPixelMap;
/*
If this TableZone is currently active
*/
bool active;
bool isInverted() const;
private slots:
/**
Loads in any found custom background and updates
*/
void updateBg();
public slots:
/**
Reorganizes CardItems in the TableZone
*/
void reorganizeCards() override;
public:
/**
Constructs TableZone.
@param _p the Player
@param parent defaults to null
*/
explicit TableZone(Player *_p, const QString &name, QGraphicsItem *parent = nullptr);
/**
@return a QRectF of the TableZone bounding box.
*/
QRectF boundingRect() const override;
/**
Render the TableZone
@param painter
@param option
*/
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
/**
Toggles the selected items as tapped.
*/
void toggleTapped();
/**
See HandleDropEventByGrid
*/
void handleDropEvent(const QList<CardDragItem *> &dragItems, CardZone *startZone, const QPoint &dropPoint) override;
/**
Handles the placement of cards
*/
void handleDropEventByGrid(const QList<CardDragItem *> &dragItems, CardZone *startZone, const QPoint &gridPoint);
/**
@return CardItem from grid location
*/
CardItem *getCardFromGrid(const QPoint &gridPoint) const;
/**
@return CardItem from coordinate location
*/
CardItem *getCardFromCoords(const QPointF &point) const;
QPointF closestGridPoint(const QPointF &point) override;
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.
*/
void resizeToContents();
int getMinimumWidth() const
{
return currentMinimumWidth;
}
void setWidth(qreal _width)
{
prepareGeometryChange();
width = _width;
}
qreal getWidth() const
{
return width;
}
void setActive(bool _active)
{
active = _active;
update();
}
protected:
void addCardImpl(CardItem *card, int x, int y) override;
private:
void paintZoneOutline(QPainter *painter);
void paintLandDivider(QPainter *painter);
/*
Calculates card stack widths so mapping functions work properly
*/
void computeCardStackWidths();
/*
Mapping functions for points to/from gridpoints.
*/
QPointF mapFromGrid(QPoint gridPoint) const;
QPoint mapToGrid(const QPointF &mapPoint) const;
/*
Helper function to create a single key from a card stack location.
*/
int getCardStackMapKey(int x, int y) const
{
return x + (y * 1000);
}
};
#endif