mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-05 01:23:24 -08:00
[Refactor] Move card item creation out of game logic (#7436)
* [Refactor] Move card item creation out of game logic * [Game] Rename signal to createCardRequested per review * [Game] Move attachment bookkeeping onto CardState CardState::setAttachedTo now maintains the attachedCards graph, resets the grid point and emits the zone events itself, so game logic no longer needs to reach into the CardItem graphics item. CardItem::setAttachedTo delegates to the state and keeps only the view teardown (deleteLater). --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
7ca23430cd
commit
78964779c6
20 changed files with 159 additions and 137 deletions
|
|
@ -11,7 +11,6 @@
|
|||
#include <QString>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
class CardItem;
|
||||
class AbstractClient;
|
||||
class CardState;
|
||||
class GameEventHandler;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "card_state.h"
|
||||
|
||||
#include "../zones/card_zone_logic.h"
|
||||
|
||||
#include <QSharedPointer>
|
||||
#include <libcockatrice/card/card_info.h>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
|
|
@ -206,7 +208,33 @@ void CardState::setAttachedTo(CardState *_attachedTo)
|
|||
if (attachedTo == _attachedTo) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (attachedTo != nullptr) {
|
||||
attachedTo->removeAttachedCard(this);
|
||||
}
|
||||
|
||||
setGridPoint(QPoint(-1, getGridPoint().y()));
|
||||
attachedTo = _attachedTo;
|
||||
emit attachedToChanged(_attachedTo);
|
||||
emit stateChanged();
|
||||
|
||||
if (attachedTo != nullptr) {
|
||||
// If the zone is being torn down, it might already be null by the time a card tries to un-attach all its
|
||||
// attached cards. The graphics item that owns this state handles the teardown in that case.
|
||||
CardZoneLogic *parentZone = attachedTo->getZone();
|
||||
if (parentZone == nullptr) {
|
||||
return;
|
||||
}
|
||||
emit parentZone->cardAdded(this);
|
||||
attachedTo->addAttachedCard(this);
|
||||
if (getZone() != parentZone) {
|
||||
parentZone->reorganizeCards();
|
||||
}
|
||||
} else if (getZone() != nullptr) {
|
||||
emit getZone() -> cardAdded(this);
|
||||
}
|
||||
|
||||
if (getZone() != nullptr) {
|
||||
getZone()->reorganizeCards();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@
|
|||
#include <qtmetamacros.h>
|
||||
|
||||
class CardZoneLogic;
|
||||
class CardItem;
|
||||
|
||||
class CardState : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
@ -35,7 +33,7 @@ private:
|
|||
QString color;
|
||||
|
||||
CardState *attachedTo = nullptr;
|
||||
QList<CardItem *> attachedCards;
|
||||
QList<CardState *> attachedCards;
|
||||
CardZoneLogic *zone = nullptr;
|
||||
|
||||
signals:
|
||||
|
|
@ -226,17 +224,17 @@ public:
|
|||
|
||||
void setAttachedTo(CardState *_attachedTo);
|
||||
|
||||
void addAttachedCard(CardItem *card)
|
||||
void addAttachedCard(CardState *card)
|
||||
{
|
||||
attachedCards.append(card);
|
||||
}
|
||||
|
||||
void removeAttachedCard(CardItem *card)
|
||||
void removeAttachedCard(CardState *card)
|
||||
{
|
||||
attachedCards.removeOne(card);
|
||||
}
|
||||
|
||||
const QList<CardItem *> &getAttachedCards() const
|
||||
const QList<CardState *> &getAttachedCards() const
|
||||
{
|
||||
return attachedCards;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#include "player_actions.h"
|
||||
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
#include "../../game_graphics/dialogs/dlg_create_token.h"
|
||||
#include "../abstract_game.h"
|
||||
#include "../board/arrow_data.h"
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#include "player_event_handler.h"
|
||||
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
#include "../abstract_game.h"
|
||||
#include "../board/arrow_data.h"
|
||||
#include "../board/card_list.h"
|
||||
#include "../board/card_state.h"
|
||||
#include "../board/counter_state.h"
|
||||
#include "../zones/card_zone_logic.h"
|
||||
#include "../zones/hand_zone_logic.h"
|
||||
|
|
@ -27,6 +27,9 @@
|
|||
#include <QSharedPointer>
|
||||
#include <QtGlobal>
|
||||
#include <algorithm>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
#include <libcockatrice/card/database/card_database_querier.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>
|
||||
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
|
||||
#include <libcockatrice/protocol/pb/context_undo_draw.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_attach_card.pb.h>
|
||||
|
|
@ -49,15 +52,11 @@
|
|||
#include <libcockatrice/protocol/pb/event_set_card_counter.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_set_counter.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_shuffle.pb.h>
|
||||
#include <libcockatrice/utility/color.h>
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
#include <qlogging.h>
|
||||
#include <string>
|
||||
|
||||
static CardItem *toCardItem(CardState *card)
|
||||
{
|
||||
return card == nullptr ? nullptr : qobject_cast<CardItem *>(card->parent());
|
||||
}
|
||||
|
||||
PlayerEventHandler::PlayerEventHandler(PlayerLogic *_player) : QObject(_player), player(_player)
|
||||
{
|
||||
connect(this, &PlayerEventHandler::requestCardMenuUpdate, player, &PlayerLogic::requestCardMenuUpdate);
|
||||
|
|
@ -160,23 +159,29 @@ void PlayerEventHandler::eventCreateToken(const Event_CreateToken &event)
|
|||
}
|
||||
|
||||
CardRef cardRef = {QString::fromStdString(event.card_name()), QString::fromStdString(event.card_provider_id())};
|
||||
CardItem *card = new CardItem(player, nullptr, cardRef, event.card_id());
|
||||
// use db PT if not provided in event and not face-down
|
||||
if (!QString::fromStdString(event.pt()).isEmpty()) {
|
||||
card->setPT(QString::fromStdString(event.pt()));
|
||||
} else if (!event.face_down()) {
|
||||
ExactCard dbCard = card->getCard();
|
||||
QString pt = QString::fromStdString(event.pt());
|
||||
if (pt.isEmpty() && !event.face_down()) {
|
||||
ExactCard dbCard = CardDatabaseManager::query()->getCard(cardRef);
|
||||
if (dbCard) {
|
||||
card->setPT(dbCard.getInfo().getPowTough());
|
||||
pt = dbCard.getInfo().getPowTough();
|
||||
}
|
||||
}
|
||||
card->setColor(QString::fromStdString(event.color()));
|
||||
card->setAnnotation(QString::fromStdString(event.annotation()));
|
||||
card->setDestroyOnZoneChange(event.destroy_on_zone_change());
|
||||
card->setFaceDown(event.face_down());
|
||||
|
||||
emit logCreateToken(player, card->getName(), card->getPT(), card->getFaceDown());
|
||||
zone->addCard(card->getState(), true, event.x(), event.y());
|
||||
emit logCreateToken(player, cardRef.name, pt, event.face_down());
|
||||
|
||||
ServerInfo_Card cardInfo;
|
||||
cardInfo.set_id(event.card_id());
|
||||
cardInfo.set_name(event.card_name());
|
||||
cardInfo.set_provider_id(event.card_provider_id());
|
||||
cardInfo.set_pt(pt.toStdString());
|
||||
cardInfo.set_color(event.color());
|
||||
cardInfo.set_annotation(event.annotation());
|
||||
cardInfo.set_destroy_on_zone_change(event.destroy_on_zone_change());
|
||||
cardInfo.set_face_down(event.face_down());
|
||||
cardInfo.set_x(event.x());
|
||||
cardInfo.set_y(event.y());
|
||||
emit zone->createCardRequested(cardInfo, true);
|
||||
}
|
||||
|
||||
void PlayerEventHandler::eventSetCardAttr(const Event_SetCardAttr &event,
|
||||
|
|
@ -276,7 +281,7 @@ void PlayerEventHandler::eventSetCardCounter(const Event_SetCardCounter &event)
|
|||
|
||||
int oldValue = card->getCounters().value(event.counter_id(), 0);
|
||||
card->setCounter(event.counter_id(), event.counter_value());
|
||||
emit requestCardMenuUpdate(toCardItem(card));
|
||||
emit requestCardMenuUpdate(card);
|
||||
emit logSetCardCounter(player, card->getName(), event.counter_id(), event.counter_value(), oldValue);
|
||||
}
|
||||
|
||||
|
|
@ -362,22 +367,17 @@ void PlayerEventHandler::eventMoveCard(const Event_MoveCard &event, const GameEv
|
|||
|
||||
if (card->getAttachedTo() && (startZone != targetZone)) {
|
||||
CardState *parentCard = card->getAttachedTo();
|
||||
// Route through CardItem so the old parent's attachedCards list is cleaned up: CardState::setAttachedTo
|
||||
// only repoints the pointer, leaving a dangling entry that reorganizeCards/prepareDelete would dereference.
|
||||
if (CardItem *item = toCardItem(card)) {
|
||||
item->setAttachedTo(nullptr);
|
||||
} else {
|
||||
card->setAttachedTo(nullptr);
|
||||
}
|
||||
// CardState::setAttachedTo removes the card from the old parent's attachedCards list and emits the zone events.
|
||||
card->setAttachedTo(nullptr);
|
||||
parentCard->getZone()->reorganizeCards();
|
||||
}
|
||||
|
||||
card->setId(event.new_card_id());
|
||||
card->setFaceDown(event.face_down());
|
||||
if (startZone != targetZone) {
|
||||
const QList<CardItem *> &attachedCards = card->getAttachedCards();
|
||||
const QList<CardState *> &attachedCards = card->getAttachedCards();
|
||||
for (auto attachedCard : attachedCards) {
|
||||
emit targetZone->cardAdded(attachedCard->getState());
|
||||
emit targetZone->cardAdded(attachedCard);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -391,8 +391,8 @@ void PlayerEventHandler::eventMoveCard(const Event_MoveCard &event, const GameEv
|
|||
|
||||
targetZone->addCard(card, true, x, y);
|
||||
|
||||
emit cardZoneChanged(toCardItem(card), startZone == targetZone);
|
||||
emit requestCardMenuUpdate(toCardItem(card));
|
||||
emit cardZoneChanged(card, startZone == targetZone);
|
||||
emit requestCardMenuUpdate(card);
|
||||
|
||||
if (player->getPlayerActions()->isMovingCardsUntil() && startZoneString == ZoneNames::DECK &&
|
||||
targetZone->getName() == ZoneNames::STACK) {
|
||||
|
|
@ -419,7 +419,7 @@ void PlayerEventHandler::eventFlipCard(const Event_FlipCard &event)
|
|||
|
||||
emit logFlipCard(player, card->getName(), event.face_down());
|
||||
card->setFaceDown(event.face_down());
|
||||
emit requestCardMenuUpdate(toCardItem(card));
|
||||
emit requestCardMenuUpdate(card);
|
||||
}
|
||||
|
||||
void PlayerEventHandler::eventDestroyCard(const Event_DestroyCard &event)
|
||||
|
|
@ -434,10 +434,18 @@ void PlayerEventHandler::eventDestroyCard(const Event_DestroyCard &event)
|
|||
return;
|
||||
}
|
||||
|
||||
QList<CardItem *> attachedCards = card->getAttachedCards();
|
||||
QList<CardState *> attachedCards = card->getAttachedCards();
|
||||
// This list is always empty except for buggy server implementations.
|
||||
for (auto &attachedCard : attachedCards) {
|
||||
card->removeAttachedCard(attachedCard);
|
||||
attachedCard->setGridPoint(QPoint(-1, attachedCard->getGridPoint().y()));
|
||||
attachedCard->setAttachedTo(nullptr);
|
||||
if (attachedCard->getZone() == nullptr) {
|
||||
attachedCard->deleteView();
|
||||
} else {
|
||||
emit attachedCard->getZone()->cardAdded(attachedCard);
|
||||
attachedCard->getZone()->reorganizeCards();
|
||||
}
|
||||
}
|
||||
|
||||
emit logDestroyCard(player, card->getName());
|
||||
|
|
@ -473,14 +481,7 @@ void PlayerEventHandler::eventAttachCard(const Event_AttachCard &event)
|
|||
|
||||
CardState *oldParent = startCard->getAttachedTo();
|
||||
|
||||
// Route through CardItem::setAttachedTo to keep the attachedCards graph, grid-x reset and zone emits intact:
|
||||
// CardState::setAttachedTo alone only repoints the pointer, so the target would never list the card and the old
|
||||
// parent would keep a dangling pointer.
|
||||
if (CardItem *startItem = toCardItem(startCard)) {
|
||||
startItem->setAttachedTo(toCardItem(targetCard));
|
||||
} else {
|
||||
startCard->setAttachedTo(targetCard);
|
||||
}
|
||||
startCard->setAttachedTo(targetCard);
|
||||
|
||||
startZone->reorganizeCards();
|
||||
if ((startZone != targetZone) && targetZone) {
|
||||
|
|
@ -495,7 +496,7 @@ void PlayerEventHandler::eventAttachCard(const Event_AttachCard &event)
|
|||
} else {
|
||||
emit logUnattachCard(player, startCard->getName());
|
||||
}
|
||||
emit requestCardMenuUpdate(toCardItem(startCard));
|
||||
emit requestCardMenuUpdate(startCard);
|
||||
}
|
||||
|
||||
void PlayerEventHandler::eventDrawCards(const Event_DrawCards &event)
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@
|
|||
#include <qtmetamacros.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
class CardItem;
|
||||
class CardState;
|
||||
class CardZoneLogic;
|
||||
class PlayerLogic;
|
||||
|
|
@ -62,7 +61,7 @@ template <typename T> class QList;
|
|||
* Design notes:
|
||||
* - All event handlers assume events are authoritative and already validated
|
||||
* by the server.
|
||||
* - Most handlers mutate both logical state (CardItem, CardZoneLogic, counters)
|
||||
* - Most handlers mutate both logical state (CardState, CardZoneLogic, counters)
|
||||
* and visual/UI state (views, arrows, menus).
|
||||
* - Logging signals are emitted *after* or *during* state mutation, depending
|
||||
* on whether later mutations would invalidate log data.
|
||||
|
|
@ -267,8 +266,8 @@ signals:
|
|||
void logAlwaysLookAtTopCard(PlayerLogic *player, CardZoneLogic *zone, bool reveal);
|
||||
/** @} */
|
||||
|
||||
void cardZoneChanged(CardItem *card, bool sameZone);
|
||||
void requestCardMenuUpdate(CardItem *card);
|
||||
void cardZoneChanged(CardState *card, bool sameZone);
|
||||
void requestCardMenuUpdate(CardState *card);
|
||||
/**
|
||||
* @brief A card was just moved by the server and its view needs refreshing.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
#include "player_logic.h"
|
||||
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
#include "../abstract_game.h"
|
||||
#include "../board/arrow_data.h"
|
||||
#include "../board/card_list.h"
|
||||
#include "../board/card_state.h"
|
||||
#include "../board/counter_state.h"
|
||||
#include "../game_meta_info.h"
|
||||
#include "../zones/hand_zone_logic.h"
|
||||
|
|
@ -33,11 +34,6 @@
|
|||
#include <qalgorithms.h>
|
||||
#include <string>
|
||||
|
||||
static CardItem *toCardItem(CardState *card)
|
||||
{
|
||||
return card == nullptr ? nullptr : qobject_cast<CardItem *>(card->parent());
|
||||
}
|
||||
|
||||
PlayerLogic::PlayerLogic(const ServerInfo_User &info, int _id, bool _local, bool _judge, AbstractGame *_parent)
|
||||
: QObject(_parent), game(_parent), playerInfo(new PlayerInfo(info, _id, _local, _judge)),
|
||||
playerEventHandler(new PlayerEventHandler(this)), playerActions(new PlayerActions(this)), active(false),
|
||||
|
|
@ -177,22 +173,20 @@ void PlayerLogic::processPlayerInfo(const ServerInfo_Player &info)
|
|||
const int cardListSize = zoneInfo.card_list_size();
|
||||
if (!cardListSize) {
|
||||
for (int j = 0; j < zoneInfo.card_count(); ++j) {
|
||||
zone->addCard((new CardItem(this))->getState(), false, -1);
|
||||
emit zone->createCardRequested(ServerInfo_Card(), false);
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < cardListSize; ++j) {
|
||||
const ServerInfo_Card &cardInfo = zoneInfo.card_list(j);
|
||||
auto *card = new CardItem(this);
|
||||
card->processCardInfo(cardInfo);
|
||||
ServerInfo_Card cardInfo = zoneInfo.card_list(j);
|
||||
// Zones without coordinates (hand, piles, stack) preserve the order
|
||||
// they arrive in on the server in the positions of their cards list.
|
||||
// The x coordinate of such cards is always 0, so inserting at it
|
||||
// would reverse the list on reconnect. Append instead.
|
||||
if (zoneInfo.with_coords()) {
|
||||
zone->addCard(card->getState(), false, cardInfo.x(), cardInfo.y());
|
||||
} else {
|
||||
zone->addCard(card->getState(), false, -1);
|
||||
if (!zoneInfo.with_coords()) {
|
||||
cardInfo.set_x(-1);
|
||||
cardInfo.set_y(-1);
|
||||
}
|
||||
emit zone->createCardRequested(cardInfo, false);
|
||||
}
|
||||
}
|
||||
if (zoneInfo.has_always_reveal_top_card()) {
|
||||
|
|
@ -232,13 +226,7 @@ void PlayerLogic::processCardAttachment(const ServerInfo_Player &info)
|
|||
continue;
|
||||
}
|
||||
|
||||
// Route through CardItem::setAttachedTo to maintain the attachedCards graph and reparenting;
|
||||
// CardState::setAttachedTo alone only repoints the pointer.
|
||||
if (CardItem *startItem = toCardItem(startCard)) {
|
||||
startItem->setAttachedTo(toCardItem(targetCard));
|
||||
} else {
|
||||
startCard->setAttachedTo(targetCard);
|
||||
}
|
||||
startCard->setAttachedTo(targetCard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -250,7 +238,7 @@ void PlayerLogic::processCardAttachment(const ServerInfo_Player &info)
|
|||
}
|
||||
}
|
||||
|
||||
void PlayerLogic::addCard(CardItem *card)
|
||||
void PlayerLogic::addCard(AbstractCardItem *card)
|
||||
{
|
||||
emit newCardAdded(card);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ signals:
|
|||
/** @brief Emitted when the remote playmat (card/params) is updated from player properties. */
|
||||
void playmatChanged();
|
||||
void newCardAdded(AbstractCardItem *card);
|
||||
void requestCardMenuUpdate(CardItem *card);
|
||||
void requestCardMenuUpdate(CardState *card);
|
||||
void counterAdded(CounterState *state);
|
||||
void counterRemoved(int counterId);
|
||||
void rearrangeCounters();
|
||||
|
|
@ -103,7 +103,7 @@ public:
|
|||
void processPlayerInfo(const ServerInfo_Player &info);
|
||||
void processCardAttachment(const ServerInfo_Player &info);
|
||||
|
||||
void addCard(CardItem *c);
|
||||
void addCard(AbstractCardItem *c);
|
||||
void deleteCard(CardState *c);
|
||||
|
||||
bool clearCardsToDelete();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
#include "card_zone_logic.h"
|
||||
|
||||
#include "../../client/translation.h"
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
#include "../../game_graphics/zones/card_zone.h"
|
||||
#include "../board/card_list.h"
|
||||
#include "../board/card_state.h"
|
||||
#include "../player/player_actions.h"
|
||||
#include "../player/player_info.h"
|
||||
#include "../player/player_logic.h"
|
||||
|
|
@ -50,10 +52,15 @@ void CardZoneLogic::addCard(CardState *card, const bool reorganize, const int x,
|
|||
|
||||
for (auto *viewLogic : views) {
|
||||
if (viewLogic->prepareAddCard(x)) {
|
||||
auto copy = new CardItem(player, nullptr, card->getCardRef(), card->getId());
|
||||
copy->setFaceDown(card->getFaceDown());
|
||||
|
||||
viewLogic->addCard(copy->getState(), reorganize, x, y);
|
||||
ServerInfo_Card cardInfo;
|
||||
const CardRef &cardRef = card->getCardRef();
|
||||
cardInfo.set_name(cardRef.name.toStdString());
|
||||
cardInfo.set_provider_id(cardRef.providerId.toStdString());
|
||||
cardInfo.set_id(card->getId());
|
||||
cardInfo.set_face_down(card->getFaceDown());
|
||||
cardInfo.set_x(x);
|
||||
cardInfo.set_y(y);
|
||||
emit viewLogic->createCardRequested(cardInfo, reorganize);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -168,9 +175,9 @@ void CardZoneLogic::clearContents()
|
|||
for (CardState *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->getState());
|
||||
const QList<CardState *> &attachedCards = card->getAttachedCards();
|
||||
for (CardState *attachedCard : attachedCards) {
|
||||
emit attachedCard->getZone()->cardAdded(attachedCard);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,10 +14,9 @@
|
|||
#include <QLoggingCategory>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <libcockatrice/protocol/pb/serverinfo_card.pb.h>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
class CardItem;
|
||||
|
||||
inline Q_LOGGING_CATEGORY(CardZoneLogicLog, "card_zone_logic");
|
||||
|
||||
class PlayerLogic;
|
||||
|
|
@ -33,6 +32,8 @@ class CardZoneLogic : public QObject
|
|||
|
||||
signals:
|
||||
void cardAdded(CardState *addedCard);
|
||||
/** @brief Asks the graphics side to build the card item for @p cardInfo and add it to this zone. */
|
||||
void createCardRequested(const ServerInfo_Card &cardInfo, bool reorganize);
|
||||
void cardCountChanged();
|
||||
void reorganizeCards();
|
||||
void updateGraphics();
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ ZoneViewZoneLogic::ZoneViewZoneLogic(PlayerLogic *_player,
|
|||
* 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
|
||||
* Make sure to call this method once before calling addCard(), so that you skip creating the card and calling
|
||||
* addCard() if it's not required.
|
||||
*
|
||||
* @param x The position to insert the card at.
|
||||
|
|
|
|||
|
|
@ -89,14 +89,18 @@ void CardItem::prepareDelete()
|
|||
owner = nullptr;
|
||||
}
|
||||
|
||||
const QList<CardItem *> &attachedCards = state->getAttachedCards();
|
||||
while (!attachedCards.isEmpty()) {
|
||||
attachedCards.first()->setZone(nullptr); // so that it won't try to call reorganizeCards()
|
||||
attachedCards.first()->setAttachedTo(nullptr);
|
||||
const QList<CardState *> &attachedStates = state->getAttachedCards();
|
||||
while (!attachedStates.isEmpty()) {
|
||||
auto *attachedItem = qobject_cast<CardItem *>(attachedStates.first()->parent());
|
||||
if (attachedItem == nullptr) {
|
||||
break;
|
||||
}
|
||||
attachedItem->setZone(nullptr); // so that it won't try to call reorganizeCards()
|
||||
attachedItem->setAttachedTo(nullptr);
|
||||
}
|
||||
|
||||
if (state->getAttachedTo() != nullptr) {
|
||||
state->getAttachedTo()->removeAttachedCard(this);
|
||||
state->getAttachedTo()->removeAttachedCard(state);
|
||||
state->setAttachedTo(nullptr);
|
||||
}
|
||||
}
|
||||
|
|
@ -225,36 +229,13 @@ void CardItem::setPT(const QString &_pt)
|
|||
|
||||
void CardItem::setAttachedTo(CardItem *_attachedTo)
|
||||
{
|
||||
if (state->getAttachedTo() != nullptr) {
|
||||
state->getAttachedTo()->removeAttachedCard(this);
|
||||
}
|
||||
CardState *newParent = _attachedTo == nullptr ? nullptr : _attachedTo->getState();
|
||||
state->setAttachedTo(newParent);
|
||||
|
||||
state->setGridPoint(QPoint(-1, state->getGridPoint().y()));
|
||||
state->setAttachedTo(_attachedTo == nullptr ? nullptr : _attachedTo->getState());
|
||||
if (state->getAttachedTo() != nullptr) {
|
||||
// If the zone is being torn down, it might already be null by the time a card tries to un-attach all its
|
||||
// attached cards
|
||||
if (state->getAttachedTo()->getZone() == nullptr) {
|
||||
deleteLater();
|
||||
} else {
|
||||
emit state->getAttachedTo()->getZone()->cardAdded(state);
|
||||
state->getAttachedTo()->addAttachedCard(this);
|
||||
if (state->getZone() != state->getAttachedTo()->getZone()) {
|
||||
state->getAttachedTo()->getZone()->reorganizeCards();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If the zone is being torn down, it might already be null by the time a card tries to un-attach all its
|
||||
// attached cards
|
||||
if (state->getZone() == nullptr) {
|
||||
deleteLater();
|
||||
} else {
|
||||
emit state->getZone()->cardAdded(state);
|
||||
}
|
||||
}
|
||||
|
||||
if (state->getZone() != nullptr) {
|
||||
state->getZone()->reorganizeCards();
|
||||
// If the zone is being torn down, it might already be null by the time a card tries to un-attach all its attached
|
||||
// cards
|
||||
if (newParent != nullptr ? newParent->getZone() == nullptr : state->getZone() == nullptr) {
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -120,15 +120,15 @@ public:
|
|||
return state->getAttachedTo();
|
||||
}
|
||||
void setAttachedTo(CardItem *_attachedTo);
|
||||
void addAttachedCard(CardItem *card)
|
||||
void addAttachedCard(CardState *card)
|
||||
{
|
||||
state->addAttachedCard(card);
|
||||
}
|
||||
void removeAttachedCard(CardItem *card)
|
||||
void removeAttachedCard(CardState *card)
|
||||
{
|
||||
state->removeAttachedCard(card);
|
||||
}
|
||||
[[nodiscard]] const QList<CardItem *> &getAttachedCards() const
|
||||
[[nodiscard]] const QList<CardState *> &getAttachedCards() const
|
||||
{
|
||||
return state->getAttachedCards();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ void GameScene::onCardSelectionChanged(AbstractCardItem *abstractCard, bool sele
|
|||
auto *owner = card->getOwner();
|
||||
|
||||
if (selected) {
|
||||
owner->requestCardMenuUpdate(card);
|
||||
owner->requestCardMenuUpdate(card->getState());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -231,7 +231,7 @@ void GameScene::onCardRightClicked(AbstractCardItem *abstractCard, QPoint screen
|
|||
|
||||
setActiveCard(card);
|
||||
|
||||
if (auto *menu = view->getPlayerMenu()->updateCardMenu(card)) {
|
||||
if (auto *menu = view->getPlayerMenu()->updateCardMenu(card->getState())) {
|
||||
menu->popup(screenPos);
|
||||
}
|
||||
}
|
||||
|
|
@ -650,11 +650,15 @@ void GameScene::requestArrowDeletion(int playerId, int arrowId)
|
|||
}
|
||||
}
|
||||
|
||||
void GameScene::onCardZoneChanged(CardItem *card, bool sameZone)
|
||||
void GameScene::onCardZoneChanged(CardState *card, bool sameZone)
|
||||
{
|
||||
auto *item = qobject_cast<CardItem *>(card->parent());
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
QList<ArrowItem *> toDelete;
|
||||
for (auto *arrow : arrowRegistry.all()) {
|
||||
if (arrow->getStartItem() == card || arrow->getTargetItem() == card) {
|
||||
if (arrow->getStartItem() == item || arrow->getTargetItem() == item) {
|
||||
if (sameZone) {
|
||||
arrow->updatePath();
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ public slots:
|
|||
/// Queues up arrow deletion but doesn't directly modify the scene
|
||||
void requestArrowDeletion(int playerId, int arrowId);
|
||||
|
||||
void onCardZoneChanged(CardItem *card, bool sameZone);
|
||||
void onCardZoneChanged(CardState *card, bool sameZone);
|
||||
/**
|
||||
* @brief Refreshes the view of a card that the server just moved.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -87,22 +87,24 @@ void PlayerMenu::setMenusForGraphicItems()
|
|||
}
|
||||
}
|
||||
|
||||
QMenu *PlayerMenu::updateCardMenu(CardItem *card)
|
||||
QMenu *PlayerMenu::updateCardMenu(CardState *card)
|
||||
{
|
||||
if (!card) {
|
||||
emit cardMenuUpdated(nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto *cardItem = qobject_cast<CardItem *>(card->parent());
|
||||
|
||||
// If is spectator (as spectators don't need card menus), return
|
||||
// only update the menu if the card is actually selected
|
||||
if ((player->getLogic()->getGame()->getPlayerManager()->isSpectator() &&
|
||||
!player->getLogic()->getGame()->getPlayerManager()->isJudge()) ||
|
||||
player->getGameScene()->getActiveCard() != card) {
|
||||
cardItem == nullptr || player->getGameScene()->getActiveCard() != cardItem) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CardMenu *menu = new CardMenu(player, card, shortcutsActive);
|
||||
CardMenu *menu = new CardMenu(player, cardItem, shortcutsActive);
|
||||
connect(menu, &CardMenu::cardInfoRequested, this, &PlayerMenu::cardInfoRequested);
|
||||
emit cardMenuUpdated(menu);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
#include <qtmetamacros.h>
|
||||
#include <utility>
|
||||
|
||||
class CardItem;
|
||||
class CardState;
|
||||
class CardMenu;
|
||||
class PlayerGraphicsItem;
|
||||
class AbstractPlayerComponent;
|
||||
|
|
@ -43,7 +43,7 @@ signals:
|
|||
|
||||
public slots:
|
||||
void setMenusForGraphicItems();
|
||||
QMenu *updateCardMenu(CardItem *card);
|
||||
QMenu *updateCardMenu(CardState *card);
|
||||
|
||||
private slots:
|
||||
void refreshShortcuts();
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ CardZone::CardZone(CardZoneLogic *_logic, QGraphicsItem *parent)
|
|||
connect(logic, &CardZoneLogic::cardCountChanged, this, &CardZone::invalidateItems);
|
||||
connect(logic, &CardZoneLogic::reorganizeCards, this, &CardZone::invalidateItems);
|
||||
connect(logic, &CardZoneLogic::cardAdded, this, &CardZone::onCardAdded);
|
||||
connect(logic, &CardZoneLogic::createCardRequested, this, &CardZone::onCreateCardRequested);
|
||||
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);
|
||||
|
|
@ -59,6 +60,14 @@ void CardZone::onCardAdded(CardState *addedCard)
|
|||
addedItem->update();
|
||||
}
|
||||
|
||||
void CardZone::onCreateCardRequested(const ServerInfo_Card &cardInfo, bool reorganize)
|
||||
{
|
||||
CardRef cardRef = {QString::fromStdString(cardInfo.name()), QString::fromStdString(cardInfo.provider_id())};
|
||||
auto *card = new CardItem(getLogic()->getPlayer(), nullptr, cardRef, cardInfo.id());
|
||||
card->processCardInfo(cardInfo);
|
||||
getLogic()->addCard(card->getState(), reorganize, cardInfo.x(), cardInfo.y());
|
||||
}
|
||||
|
||||
void CardZone::retranslateUi()
|
||||
{
|
||||
for (auto *card : cardItems()) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ class QAction;
|
|||
class QGraphicsItem;
|
||||
class QMenu;
|
||||
class QPoint;
|
||||
class ServerInfo_Card;
|
||||
template <typename T> class QList;
|
||||
|
||||
class CardItem;
|
||||
|
|
@ -59,6 +60,8 @@ public slots:
|
|||
* connection in CardZone's constructor dispatches through the vtable.
|
||||
*/
|
||||
virtual void onCardAdded(CardState *addedCard);
|
||||
/** @brief Builds the card item for @p cardInfo and hands it to this zone's logic. */
|
||||
void onCreateCardRequested(const ServerInfo_Card &cardInfo, bool reorganize);
|
||||
|
||||
public:
|
||||
enum
|
||||
|
|
|
|||
|
|
@ -248,11 +248,14 @@ void TableZone::reorganizeCards()
|
|||
cardItems()[i]->setPos(actualX, actualY);
|
||||
cardItems()[i]->setRealZValue(ZValues::tableCardZValue(actualX, actualY));
|
||||
|
||||
QListIterator<CardItem *> attachedCardIterator(cardItems()[i]->getAttachedCards());
|
||||
QListIterator<CardState *> attachedCardIterator(cardItems()[i]->getAttachedCards());
|
||||
int j = 0;
|
||||
while (attachedCardIterator.hasNext()) {
|
||||
++j;
|
||||
CardItem *attachedCard = attachedCardIterator.next();
|
||||
CardItem *attachedCard = qobject_cast<CardItem *>(attachedCardIterator.next()->parent());
|
||||
if (attachedCard == nullptr) {
|
||||
continue;
|
||||
}
|
||||
qreal childX = actualX - j * STACKED_CARD_OFFSET_X;
|
||||
qreal childY = y + 5;
|
||||
attachedCard->setPos(childX, childY);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue