mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-06-12 17:14:52 -07:00
* style: Add braces to all control flow statements Standardize code style by adding explicit braces to all single-statement control flow blocks (if, else, for, while) across the entire codebase. Also documents the InsertBraces clang-format option (requires v15+) for future automated enforcement. * InsertBraces-check-enabled
221 lines
No EOL
7.7 KiB
C++
221 lines
No EOL
7.7 KiB
C++
#include "card_zone_logic.h"
|
|
|
|
#include "../../board/card_item.h"
|
|
#include "../../player/player.h"
|
|
#include "../../player/player_actions.h"
|
|
#include "../view_zone.h"
|
|
#include "view_zone_logic.h"
|
|
|
|
#include <QAction>
|
|
#include <QDebug>
|
|
#include <libcockatrice/card/database/card_database_manager.h>
|
|
#include <libcockatrice/protocol/pb/command_move_card.pb.h>
|
|
#include <libcockatrice/utility/zone_names.h>
|
|
|
|
/**
|
|
* @param _player the player that the zone belongs to
|
|
* @param _name internal name of the zone
|
|
* @param _hasCardAttr whether cards in the zone can have attributes set on them
|
|
* @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)) {
|
|
auto copy = new CardItem(player, nullptr, card->getCardRef(), card->getId());
|
|
copy->setFaceDown(card->getFaceDown());
|
|
|
|
view->getLogic()->addCard(copy, 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()
|
|
{
|
|
// First gather the cards into a safe temporary list.
|
|
const CardList toClear = cards;
|
|
|
|
// Detach and notify attached cards and zones *before* deleting anything.
|
|
for (CardItem *card : toClear) {
|
|
// 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 = card->getAttachedCards();
|
|
for (CardItem *attachedCard : attachedCards) {
|
|
emit attachedCard->getZone()->cardAdded(attachedCard);
|
|
}
|
|
}
|
|
|
|
// Now request deletions after all manipulations are done.
|
|
for (CardItem *card : toClear) {
|
|
player->deleteCard(card);
|
|
}
|
|
|
|
cards.clear();
|
|
emit cardCountChanged();
|
|
}
|
|
|
|
QString CardZoneLogic::getTranslatedName(bool theirOwn, GrammaticalCase gc) const
|
|
{
|
|
QString ownerName = player->getPlayerInfo()->getName();
|
|
if (name == ZoneNames::HAND) {
|
|
return (theirOwn ? tr("their hand", "nominative") : tr("%1's hand", "nominative").arg(ownerName));
|
|
} else if (name == ZoneNames::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 == ZoneNames::GRAVE) {
|
|
return (theirOwn ? tr("their graveyard", "nominative") : tr("%1's graveyard", "nominative").arg(ownerName));
|
|
} else if (name == ZoneNames::EXILE) {
|
|
return (theirOwn ? tr("their exile", "nominative") : tr("%1's exile", "nominative").arg(ownerName));
|
|
} else if (name == ZoneNames::SIDEBOARD) {
|
|
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();
|
|
} |