Deck legality checker.

Took 51 seconds

Took 1 minute

Took 1 minute

Took 5 minutes

Took 3 minutes
This commit is contained in:
Lukas Brübach 2025-09-10 09:40:28 +02:00
parent 2e2682aad4
commit 3f06c848e1
31 changed files with 921 additions and 27 deletions

View file

@ -168,6 +168,10 @@ QVariant DeckListModel::data(const QModelIndex &index, int role) const
return card->depth();
}
case DeckRoles::IsLegalRole: {
return card->getFormatLegality();
}
default: {
return {};
}
@ -268,6 +272,7 @@ bool DeckListModel::setData(const QModelIndex &index, const QVariant &value, con
switch (index.column()) {
case DeckListModelColumns::CARD_AMOUNT:
node->setNumber(value.toInt());
refreshCardFormatLegalities();
break;
case DeckListModelColumns::CARD_NAME:
node->setName(value.toString());
@ -414,8 +419,9 @@ QModelIndex DeckListModel::addCard(const ExactCard &card, const QString &zoneNam
// Determine the correct index
int insertRow = findSortedInsertRow(groupNode, cardInfo);
auto *decklistCard = deckList->addCard(cardInfo->getName(), zoneName, insertRow, cardSetName,
printingInfo.getProperty("num"), printingInfo.getProperty("uuid"));
auto *decklistCard =
deckList->addCard(cardInfo->getName(), zoneName, insertRow, cardSetName, printingInfo.getProperty("num"),
printingInfo.getProperty("uuid"), isCardLegalForCurrentFormat(cardInfo));
beginInsertRows(parentIndex, insertRow, insertRow);
cardNode = new DecklistModelCardNode(decklistCard, groupNode, insertRow);
@ -532,6 +538,13 @@ void DeckListModel::setActiveGroupCriteria(DeckListModelGroupCriteria::Type newC
rebuildTree();
}
void DeckListModel::setActiveFormat(const QString &_format)
{
deckList->setGameFormat(_format);
refreshCardFormatLegalities();
emitBackgroundUpdates(QModelIndex()); // start from root
}
void DeckListModel::cleanList()
{
setDeckList(new DeckList);
@ -595,4 +608,74 @@ QList<QString> DeckListModel::getZones() const
[](auto zoneNode) { return zoneNode->getName(); });
return zones;
}
}
bool DeckListModel::isCardLegalForCurrentFormat(const CardInfoPtr cardInfo)
{
if (!deckList->getGameFormat().isEmpty()) {
if (cardInfo->getProperties().contains("format-" + deckList->getGameFormat())) {
QString formatLegality = cardInfo->getProperty("format-" + deckList->getGameFormat());
return formatLegality == "legal" || formatLegality == "restricted";
}
return false;
}
return true;
}
bool DeckListModel::isCardQuantityLegalForCurrentFormat(const CardInfoPtr cardInfo, int quantity)
{
auto formatRules = CardDatabaseManager::query()->getFormat(deckList->getGameFormat());
if (!formatRules) {
return true;
}
if (cardHasAnyException(*cardInfo.data(), *formatRules.data())) {
return true;
}
if (cardInfo->getProperties().contains("format-" + deckList->getGameFormat())) {
QString formatLegality = cardInfo->getProperty("format-" + deckList->getGameFormat());
if (formatLegality == "legal") {
if (quantity <= formatRules->maxCopies) {
return true;
}
} else if (formatLegality == "restricted") {
if (quantity <= formatRules->maxRestrictedCopies) {
return true;
}
}
}
return false;
}
void DeckListModel::refreshCardFormatLegalities()
{
InnerDecklistNode *listRoot = deckList->getRoot();
for (int i = 0; i < listRoot->size(); i++) {
auto *currentZone = static_cast<InnerDecklistNode *>(listRoot->at(i));
for (int j = 0; j < currentZone->size(); j++) {
auto *currentCard = static_cast<DecklistCardNode *>(currentZone->at(j));
// TODO: better sanity checking
if (currentCard == nullptr) {
continue;
}
ExactCard exactCard = CardDatabaseManager::query()->getCard(currentCard->toCardRef());
if (!exactCard) {
continue;
}
bool legal = isCardLegalForCurrentFormat(exactCard.getCardPtr());
if (legal) {
legal = isCardQuantityLegalForCurrentFormat(exactCard.getCardPtr(), currentCard->getNumber());
}
currentCard->setFormatLegality(legal);
}
}
}

View file

@ -164,6 +164,14 @@ public:
{
dataNode->setCardCollectorNumber(_cardSetNumber);
}
bool getFormatLegality() const override
{
return dataNode->getFormatLegality();
}
void setFormatLegality(const bool _formatLegal) override
{
dataNode->setFormatLegality(_formatLegal);
}
/**
* @brief Returns the underlying data node.
@ -209,6 +217,9 @@ public slots:
*/
void rebuildTree();
public slots:
void setActiveFormat(const QString &_format);
signals:
/**
* @brief Emitted whenever the deck hash changes due to modifications in the model.
@ -301,6 +312,9 @@ public:
[[nodiscard]] QList<ExactCard> getCards() const;
[[nodiscard]] QList<ExactCard> getCardsForZone(const QString &zoneName) const;
[[nodiscard]] QList<QString> getZones() const;
bool isCardLegalForCurrentFormat(CardInfoPtr cardInfo);
bool isCardQuantityLegalForCurrentFormat(CardInfoPtr cardInfo, int quantity);
void refreshCardFormatLegalities();
/**
* @brief Sets the criteria used to group cards in the model.