mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2025-12-28 13:46:00 -08:00
* Sort *every* file into a doxygen group. Took 7 hours 9 minutes Took 18 seconds Took 2 minutes * Lint some ingroup definitions. Took 10 minutes Took 2 seconds * Just include the groups in the Doxyfile in this commit. Took 3 minutes * Update some group comments so they link! Took 14 minutes --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
321 lines
9.7 KiB
C++
321 lines
9.7 KiB
C++
/**
|
|
* @file decklist.h
|
|
* @brief Defines the DeckList class and supporting types for managing a full
|
|
* deck structure including cards, zones, sideboard plans, and
|
|
* serialization to/from multiple formats. This is a logic class which
|
|
* does not care about Qt or user facing views.
|
|
* See @c DeckListModel for the actual Qt Model to be used for views
|
|
*/
|
|
|
|
#ifndef DECKLIST_H
|
|
#define DECKLIST_H
|
|
|
|
#include "card_ref.h"
|
|
#include "inner_deck_list_node.h"
|
|
|
|
#include <QMap>
|
|
#include <QVector>
|
|
#include <QtCore/QXmlStreamReader>
|
|
#include <QtCore/QXmlStreamWriter>
|
|
#include <common/pb/move_card_to_zone.pb.h>
|
|
|
|
class AbstractDecklistNode;
|
|
class DecklistCardNode;
|
|
class CardDatabase;
|
|
class QIODevice;
|
|
class QTextStream;
|
|
class InnerDecklistNode;
|
|
|
|
/**
|
|
* @class SideboardPlan
|
|
* @ingroup Decks
|
|
* @brief Represents a predefined sideboarding strategy for a deck.
|
|
*
|
|
* Sideboard plans store a named list of card movements that should be applied
|
|
* between the mainboard and sideboard for a specific matchup. Each movement
|
|
* is expressed using a `MoveCard_ToZone` protobuf message.
|
|
*
|
|
* ### Responsibilities:
|
|
* - Store the plan name and list of moves.
|
|
* - Support XML serialization/deserialization.
|
|
*
|
|
* ### Typical usage:
|
|
* A deck can contain multiple sideboard plans (e.g., "vs Aggro", "vs Control"),
|
|
* each describing how to transform the main deck into its intended configuration.
|
|
*/
|
|
class SideboardPlan
|
|
{
|
|
private:
|
|
QString name; ///< Human-readable name of this plan.
|
|
QList<MoveCard_ToZone> moveList; ///< List of move instructions for this plan.
|
|
|
|
public:
|
|
/**
|
|
* @brief Construct a new SideboardPlan.
|
|
* @param _name The plan name.
|
|
* @param _moveList Initial list of card move instructions.
|
|
*/
|
|
explicit SideboardPlan(const QString &_name = QString(),
|
|
const QList<MoveCard_ToZone> &_moveList = QList<MoveCard_ToZone>());
|
|
|
|
/**
|
|
* @brief Read a SideboardPlan from an XML stream.
|
|
* @param xml XML reader positioned at the plan element.
|
|
* @return true if parsing succeeded.
|
|
*/
|
|
bool readElement(QXmlStreamReader *xml);
|
|
|
|
/**
|
|
* @brief Write this SideboardPlan to XML.
|
|
* @param xml Stream to append the serialized element to.
|
|
*/
|
|
void write(QXmlStreamWriter *xml);
|
|
|
|
/// @return The plan name.
|
|
QString getName() const
|
|
{
|
|
return name;
|
|
}
|
|
|
|
/// @return Const reference to the move list.
|
|
const QList<MoveCard_ToZone> &getMoveList() const
|
|
{
|
|
return moveList;
|
|
}
|
|
|
|
/// @brief Replace the move list with a new one.
|
|
void setMoveList(const QList<MoveCard_ToZone> &_moveList);
|
|
};
|
|
|
|
/**
|
|
* @class DeckList
|
|
* @ingroup Decks
|
|
* @brief Represents a complete deck, including metadata, zones, cards,
|
|
* and sideboard plans.
|
|
*
|
|
* A DeckList is a QObject wrapper around an `InnerDecklistNode` tree,
|
|
* enriched with metadata like deck name, comments, tags, banner card,
|
|
* and multiple sideboard plans.
|
|
*
|
|
* ### Core responsibilities:
|
|
* - Store and manage the root node tree (zones → groups → cards).
|
|
* - Provide deck-level metadata (name, comments, tags, banner).
|
|
* - Support multiple sideboard plans (meta-game strategies).
|
|
* - Provide import/export in multiple formats:
|
|
* - Cockatrice native XML format.
|
|
* - Plain-text list format.
|
|
* - Provide hashing for deck identity (deck hash).
|
|
*
|
|
* ### Ownership:
|
|
* - Owns the root `InnerDecklistNode` tree.
|
|
* - Owns `SideboardPlan` instances stored in `sideboardPlans`.
|
|
*
|
|
* ### Signals:
|
|
* - @c deckHashChanged() — emitted when the deck contents change.
|
|
* - @c deckTagsChanged() — emitted when tags are added/removed.
|
|
*
|
|
* ### Example workflow:
|
|
* ```
|
|
* DeckList deck;
|
|
* deck.setName("Mono Red Aggro");
|
|
* deck.addCard("Lightning Bolt", "main", -1);
|
|
* deck.addTag("Aggro");
|
|
* deck.saveToFile_Native(device);
|
|
* ```
|
|
*/
|
|
class DeckList : public QObject
|
|
{
|
|
Q_OBJECT
|
|
private:
|
|
QString name; ///< User-defined deck name.
|
|
QString comments; ///< Free-form comments or notes.
|
|
CardRef bannerCard; ///< Optional representative card for the deck.
|
|
QString lastLoadedTimestamp; ///< Timestamp string of last load.
|
|
QStringList tags; ///< User-defined tags for deck classification.
|
|
QMap<QString, SideboardPlan *> sideboardPlans; ///< Named sideboard plans.
|
|
InnerDecklistNode *root; ///< Root of the deck tree (zones + cards).
|
|
|
|
/**
|
|
* @brief Cached deck hash, recalculated lazily.
|
|
* An empty string indicates the cache is invalid.
|
|
*/
|
|
mutable QString cachedDeckHash;
|
|
|
|
// Helpers for traversing the tree
|
|
static void getCardListHelper(InnerDecklistNode *node, QSet<QString> &result);
|
|
static void getCardRefListHelper(InnerDecklistNode *item, QList<CardRef> &result);
|
|
InnerDecklistNode *getZoneObjFromName(const QString &zoneName);
|
|
|
|
protected:
|
|
/**
|
|
* @brief Map a card name to its zone.
|
|
* Override in subclasses for format-specific logic.
|
|
* @param cardName Card being placed.
|
|
* @param currentZoneName Zone candidate.
|
|
* @return Zone name to use.
|
|
*/
|
|
virtual QString getCardZoneFromName(const QString /*cardName*/, QString currentZoneName)
|
|
{
|
|
return currentZoneName;
|
|
};
|
|
|
|
/**
|
|
* @brief Produce the complete display name of a card.
|
|
* Override in subclasses to add set suffixes or annotations.
|
|
* @param cardName Base name.
|
|
* @return Full display name.
|
|
*/
|
|
virtual QString getCompleteCardName(const QString &cardName) const
|
|
{
|
|
return cardName;
|
|
};
|
|
|
|
signals:
|
|
/// Emitted when the deck hash changes.
|
|
void deckHashChanged();
|
|
/// Emitted when the deck tags are modified.
|
|
void deckTagsChanged();
|
|
|
|
public slots:
|
|
/// @name Metadata setters
|
|
///@{
|
|
void setName(const QString &_name = QString())
|
|
{
|
|
name = _name;
|
|
}
|
|
void setComments(const QString &_comments = QString())
|
|
{
|
|
comments = _comments;
|
|
}
|
|
void setTags(const QStringList &_tags = QStringList())
|
|
{
|
|
tags = _tags;
|
|
emit deckTagsChanged();
|
|
}
|
|
void addTag(const QString &_tag)
|
|
{
|
|
tags.append(_tag);
|
|
emit deckTagsChanged();
|
|
}
|
|
void clearTags()
|
|
{
|
|
tags.clear();
|
|
emit deckTagsChanged();
|
|
}
|
|
void setBannerCard(const CardRef &_bannerCard = {})
|
|
{
|
|
bannerCard = _bannerCard;
|
|
}
|
|
void setLastLoadedTimestamp(const QString &_lastLoadedTimestamp = QString())
|
|
{
|
|
lastLoadedTimestamp = _lastLoadedTimestamp;
|
|
}
|
|
///@}
|
|
|
|
public:
|
|
/// @brief Construct an empty deck.
|
|
explicit DeckList();
|
|
/// @brief Deep-copy constructor.
|
|
DeckList(const DeckList &other);
|
|
/// @brief Construct from a serialized native-format string.
|
|
explicit DeckList(const QString &nativeString);
|
|
~DeckList() override;
|
|
|
|
/// @name Metadata getters
|
|
///@{
|
|
QString getName() const
|
|
{
|
|
return name;
|
|
}
|
|
QString getComments() const
|
|
{
|
|
return comments;
|
|
}
|
|
QStringList getTags() const
|
|
{
|
|
return tags;
|
|
}
|
|
CardRef getBannerCard() const
|
|
{
|
|
return bannerCard;
|
|
}
|
|
QString getLastLoadedTimestamp() const
|
|
{
|
|
return lastLoadedTimestamp;
|
|
}
|
|
///@}
|
|
|
|
bool isBlankDeck() const
|
|
{
|
|
return name.isEmpty() && comments.isEmpty() && getCardList().isEmpty();
|
|
}
|
|
|
|
/// @name Sideboard plans
|
|
///@{
|
|
QList<MoveCard_ToZone> getCurrentSideboardPlan();
|
|
void setCurrentSideboardPlan(const QList<MoveCard_ToZone> &plan);
|
|
const QMap<QString, SideboardPlan *> &getSideboardPlans() const
|
|
{
|
|
return sideboardPlans;
|
|
}
|
|
///@}
|
|
|
|
/// @name Serialization (XML)
|
|
///@{
|
|
bool readElement(QXmlStreamReader *xml);
|
|
void write(QXmlStreamWriter *xml) const;
|
|
bool loadFromXml(QXmlStreamReader *xml);
|
|
bool loadFromString_Native(const QString &nativeString);
|
|
QString writeToString_Native() const;
|
|
bool loadFromFile_Native(QIODevice *device);
|
|
bool saveToFile_Native(QIODevice *device);
|
|
///@}
|
|
|
|
/// @name Serialization (Plain text)
|
|
///@{
|
|
bool loadFromStream_Plain(QTextStream &stream, bool preserveMetadata);
|
|
bool loadFromFile_Plain(QIODevice *device);
|
|
bool saveToStream_Plain(QTextStream &stream, bool prefixSideboardCards, bool slashTappedOutSplitCards);
|
|
bool saveToFile_Plain(QIODevice *device, bool prefixSideboardCards = true, bool slashTappedOutSplitCards = false);
|
|
QString writeToString_Plain(bool prefixSideboardCards = true, bool slashTappedOutSplitCards = false);
|
|
///@}
|
|
|
|
/// @name Deck manipulation
|
|
///@{
|
|
void cleanList(bool preserveMetadata = false);
|
|
bool isEmpty() const
|
|
{
|
|
return root->isEmpty() && name.isEmpty() && comments.isEmpty() && sideboardPlans.isEmpty();
|
|
}
|
|
QStringList getCardList() const;
|
|
QList<CardRef> getCardRefList() const;
|
|
int getSideboardSize() const;
|
|
InnerDecklistNode *getRoot() const
|
|
{
|
|
return root;
|
|
}
|
|
DecklistCardNode *addCard(const QString &cardName,
|
|
const QString &zoneName,
|
|
int position,
|
|
const QString &cardSetName = QString(),
|
|
const QString &cardSetCollectorNumber = QString(),
|
|
const QString &cardProviderId = QString());
|
|
bool deleteNode(AbstractDecklistNode *node, InnerDecklistNode *rootNode = nullptr);
|
|
///@}
|
|
|
|
/// @name Deck identity
|
|
///@{
|
|
QString getDeckHash() const;
|
|
void refreshDeckHash();
|
|
///@}
|
|
|
|
/**
|
|
* @brief Apply a function to every card in the deck tree.
|
|
*
|
|
* @param func Function taking (zone node, card node).
|
|
*/
|
|
void forEachCard(const std::function<void(InnerDecklistNode *, DecklistCardNode *)> &func);
|
|
};
|
|
|
|
#endif
|