From 1bcea27a445c912b5d51462e5a35ab732942ded4 Mon Sep 17 00:00:00 2001 From: RickyRister <42636155+RickyRister@users.noreply.github.com> Date: Wed, 4 Mar 2026 18:19:41 -0800 Subject: [PATCH 01/20] [Game] Add face down versions of move cards from library actions (#6661) * implement actions * add new actions to menu * update shortcuts --- .../src/client/settings/shortcuts_settings.h | 16 +++++++ .../src/game/player/menu/library_menu.cpp | 28 ++++++++++++ .../src/game/player/menu/library_menu.h | 4 ++ cockatrice/src/game/player/player_actions.cpp | 44 +++++++++++++++---- cockatrice/src/game/player/player_actions.h | 8 +++- 5 files changed, 90 insertions(+), 10 deletions(-) diff --git a/cockatrice/src/client/settings/shortcuts_settings.h b/cockatrice/src/client/settings/shortcuts_settings.h index 156ee82ea..47332b8c4 100644 --- a/cockatrice/src/client/settings/shortcuts_settings.h +++ b/cockatrice/src/client/settings/shortcuts_settings.h @@ -598,11 +598,19 @@ private: {"Player/aMoveTopCardsToGraveyard", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard (Multiple)"), parseSequenceString("Alt+M"), ShortcutGroup::Move_top)}, + {"Player/aMoveTopCardsToGraveyardFaceDown", + ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard (Multiple), Face Down"), + parseSequenceString(""), + ShortcutGroup::Move_top)}, {"Player/aMoveTopCardToExile", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile"), parseSequenceString(""), ShortcutGroup::Move_top)}, {"Player/aMoveTopCardsToExile", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile (Multiple)"), parseSequenceString(""), ShortcutGroup::Move_top)}, + {"Player/aMoveTopCardsToExileFaceDown", + ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile (Multiple), Face Down"), + parseSequenceString(""), + ShortcutGroup::Move_top)}, {"Player/aMoveTopCardsUntil", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Stack Until Found"), parseSequenceString("Ctrl+Shift+Y"), ShortcutGroup::Move_top)}, @@ -620,11 +628,19 @@ private: {"Player/aMoveBottomCardsToGrave", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard (Multiple)"), parseSequenceString(""), ShortcutGroup::Move_bottom)}, + {"Player/aMoveBottomCardsToGraveFaceDown", + ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard (Multiple), Face Down"), + parseSequenceString(""), + ShortcutGroup::Move_bottom)}, {"Player/aMoveBottomCardToExile", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile"), parseSequenceString(""), ShortcutGroup::Move_bottom)}, {"Player/aMoveBottomCardsToExile", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile (Multiple)"), parseSequenceString(""), ShortcutGroup::Move_bottom)}, + {"Player/aMoveBottomCardsToExileFaceDown", + ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile (Multiple), Face Down"), + parseSequenceString(""), + ShortcutGroup::Move_bottom)}, {"Player/aMoveBottomCardToTop", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Top of Library"), parseSequenceString(""), ShortcutGroup::Move_bottom)}, diff --git a/cockatrice/src/game/player/menu/library_menu.cpp b/cockatrice/src/game/player/menu/library_menu.cpp index 749439558..1bb647d06 100644 --- a/cockatrice/src/game/player/menu/library_menu.cpp +++ b/cockatrice/src/game/player/menu/library_menu.cpp @@ -51,8 +51,10 @@ LibraryMenu::LibraryMenu(Player *_player, QWidget *parent) : TearOffMenu(parent) topLibraryMenu->addSeparator(); topLibraryMenu->addAction(aMoveTopCardToGraveyard); topLibraryMenu->addAction(aMoveTopCardsToGraveyard); + topLibraryMenu->addAction(aMoveTopCardsToGraveyardFaceDown); topLibraryMenu->addAction(aMoveTopCardToExile); topLibraryMenu->addAction(aMoveTopCardsToExile); + topLibraryMenu->addAction(aMoveTopCardsToExileFaceDown); topLibraryMenu->addAction(aMoveTopCardsUntil); topLibraryMenu->addSeparator(); topLibraryMenu->addAction(aShuffleTopCards); @@ -66,8 +68,10 @@ LibraryMenu::LibraryMenu(Player *_player, QWidget *parent) : TearOffMenu(parent) bottomLibraryMenu->addSeparator(); bottomLibraryMenu->addAction(aMoveBottomCardToGraveyard); bottomLibraryMenu->addAction(aMoveBottomCardsToGraveyard); + bottomLibraryMenu->addAction(aMoveBottomCardsToGraveyardFaceDown); bottomLibraryMenu->addAction(aMoveBottomCardToExile); bottomLibraryMenu->addAction(aMoveBottomCardsToExile); + bottomLibraryMenu->addAction(aMoveBottomCardsToExileFaceDown); bottomLibraryMenu->addSeparator(); bottomLibraryMenu->addAction(aShuffleBottomCards); @@ -136,8 +140,14 @@ void LibraryMenu::createMoveActions() connect(aMoveTopCardToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardToExile); aMoveTopCardsToGraveyard = new QAction(this); connect(aMoveTopCardsToGraveyard, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardsToGrave); + aMoveTopCardsToGraveyardFaceDown = new QAction(this); + connect(aMoveTopCardsToGraveyardFaceDown, &QAction::triggered, playerActions, + &PlayerActions::actMoveTopCardsToGraveFaceDown); aMoveTopCardsToExile = new QAction(this); connect(aMoveTopCardsToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardsToExile); + aMoveTopCardsToExileFaceDown = new QAction(this); + connect(aMoveTopCardsToExileFaceDown, &QAction::triggered, playerActions, + &PlayerActions::actMoveTopCardsToExileFaceDown); aMoveTopCardsUntil = new QAction(this); connect(aMoveTopCardsUntil, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardsUntil); aMoveTopCardToBottom = new QAction(this); @@ -156,8 +166,14 @@ void LibraryMenu::createMoveActions() aMoveBottomCardsToGraveyard = new QAction(this); connect(aMoveBottomCardsToGraveyard, &QAction::triggered, playerActions, &PlayerActions::actMoveBottomCardsToGrave); + aMoveBottomCardsToGraveyardFaceDown = new QAction(this); + connect(aMoveBottomCardsToGraveyardFaceDown, &QAction::triggered, playerActions, + &PlayerActions::actMoveBottomCardsToGraveFaceDown); aMoveBottomCardsToExile = new QAction(this); connect(aMoveBottomCardsToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveBottomCardsToExile); + aMoveBottomCardsToExileFaceDown = new QAction(this); + connect(aMoveBottomCardsToExileFaceDown, &QAction::triggered, playerActions, + &PlayerActions::actMoveBottomCardsToExileFaceDown); aMoveBottomCardToTop = new QAction(this); connect(aMoveBottomCardToTop, &QAction::triggered, playerActions, &PlayerActions::actMoveBottomCardToTop); } @@ -216,7 +232,9 @@ void LibraryMenu::retranslateUi() aMoveTopCardToGraveyard->setText(tr("Move top card to grave&yard")); aMoveTopCardToExile->setText(tr("Move top card to e&xile")); aMoveTopCardsToGraveyard->setText(tr("Move top cards to &graveyard...")); + aMoveTopCardsToGraveyardFaceDown->setText(tr("Move top cards to graveyard face down...")); aMoveTopCardsToExile->setText(tr("Move top cards to &exile...")); + aMoveTopCardsToExileFaceDown->setText(tr("Move top cards to exile face down...")); aMoveTopCardsUntil->setText(tr("Put top cards on stack &until...")); aShuffleTopCards->setText(tr("Shuffle top cards...")); @@ -227,7 +245,9 @@ void LibraryMenu::retranslateUi() aMoveBottomCardToGraveyard->setText(tr("Move bottom card to grave&yard")); aMoveBottomCardToExile->setText(tr("Move bottom card to e&xile")); aMoveBottomCardsToGraveyard->setText(tr("Move bottom cards to &graveyard...")); + aMoveBottomCardsToGraveyardFaceDown->setText(tr("Move bottom cards to graveyard face down...")); aMoveBottomCardsToExile->setText(tr("Move bottom cards to &exile...")); + aMoveBottomCardsToExileFaceDown->setText(tr("Move bottom cards to exile face down...")); aMoveBottomCardToTop->setText(tr("Put bottom card on &top")); aShuffleBottomCards->setText(tr("Shuffle bottom cards...")); } @@ -335,8 +355,10 @@ void LibraryMenu::setShortcutsActive() aMoveTopToPlayFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveTopToPlayFaceDown")); aMoveTopCardToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToGraveyard")); aMoveTopCardsToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToGraveyard")); + aMoveTopCardsToGraveyardFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToGraveyardFaceDown")); aMoveTopCardToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToExile")); aMoveTopCardsToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToExile")); + aMoveTopCardsToExileFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToExileFaceDown")); aMoveTopCardsUntil->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsUntil")); aMoveTopCardToBottom->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToBottom")); aDrawBottomCard->setShortcuts(shortcuts.getShortcut("Player/aDrawBottomCard")); @@ -345,8 +367,10 @@ void LibraryMenu::setShortcutsActive() aMoveBottomToPlayFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomToPlayFaceDown")); aMoveBottomCardToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToGrave")); aMoveBottomCardsToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToGrave")); + aMoveBottomCardsToGraveyardFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToGraveFaceDown")); aMoveBottomCardToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToExile")); aMoveBottomCardsToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToExile")); + aMoveBottomCardsToExileFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToExileFaceDown")); aMoveBottomCardToTop->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToTop")); } @@ -367,8 +391,10 @@ void LibraryMenu::setShortcutsInactive() aMoveTopToPlayFaceDown->setShortcut(QKeySequence()); aMoveTopCardToGraveyard->setShortcut(QKeySequence()); aMoveTopCardsToGraveyard->setShortcut(QKeySequence()); + aMoveTopCardsToGraveyardFaceDown->setShortcut(QKeySequence()); aMoveTopCardToExile->setShortcut(QKeySequence()); aMoveTopCardsToExile->setShortcut(QKeySequence()); + aMoveTopCardsToExileFaceDown->setShortcut(QKeySequence()); aMoveTopCardsUntil->setShortcut(QKeySequence()); aDrawBottomCard->setShortcut(QKeySequence()); aDrawBottomCards->setShortcut(QKeySequence()); @@ -376,6 +402,8 @@ void LibraryMenu::setShortcutsInactive() aMoveBottomToPlayFaceDown->setShortcut(QKeySequence()); aMoveBottomCardToGraveyard->setShortcut(QKeySequence()); aMoveBottomCardsToGraveyard->setShortcut(QKeySequence()); + aMoveBottomCardsToGraveyardFaceDown->setShortcut(QKeySequence()); aMoveBottomCardToExile->setShortcut(QKeySequence()); aMoveBottomCardsToExile->setShortcut(QKeySequence()); + aMoveBottomCardsToExileFaceDown->setShortcut(QKeySequence()); } diff --git a/cockatrice/src/game/player/menu/library_menu.h b/cockatrice/src/game/player/menu/library_menu.h index 96d4b82b1..c0883107c 100644 --- a/cockatrice/src/game/player/menu/library_menu.h +++ b/cockatrice/src/game/player/menu/library_menu.h @@ -88,7 +88,9 @@ public: QAction *aMoveTopCardToGraveyard = nullptr; QAction *aMoveTopCardToExile = nullptr; QAction *aMoveTopCardsToGraveyard = nullptr; + QAction *aMoveTopCardsToGraveyardFaceDown = nullptr; QAction *aMoveTopCardsToExile = nullptr; + QAction *aMoveTopCardsToExileFaceDown = nullptr; QAction *aMoveTopCardsUntil = nullptr; QAction *aShuffleTopCards = nullptr; @@ -100,7 +102,9 @@ public: QAction *aMoveBottomCardToGraveyard = nullptr; QAction *aMoveBottomCardToExile = nullptr; QAction *aMoveBottomCardsToGraveyard = nullptr; + QAction *aMoveBottomCardsToGraveyardFaceDown = nullptr; QAction *aMoveBottomCardsToExile = nullptr; + QAction *aMoveBottomCardsToExileFaceDown = nullptr; QAction *aShuffleBottomCards = nullptr; int defaultNumberTopCards = 1; diff --git a/cockatrice/src/game/player/player_actions.cpp b/cockatrice/src/game/player/player_actions.cpp index 1a09836e4..514ac2e67 100644 --- a/cockatrice/src/game/player/player_actions.cpp +++ b/cockatrice/src/game/player/player_actions.cpp @@ -424,15 +424,25 @@ void PlayerActions::actMoveTopCardToExile() void PlayerActions::actMoveTopCardsToGrave() { - moveTopCardsTo("grave", tr("grave")); + moveTopCardsTo("grave", tr("grave"), false); +} + +void PlayerActions::actMoveTopCardsToGraveFaceDown() +{ + moveTopCardsTo("grave", tr("grave"), true); } void PlayerActions::actMoveTopCardsToExile() { - moveTopCardsTo("rfg", tr("exile")); + moveTopCardsTo("rfg", tr("exile"), false); } -void PlayerActions::moveTopCardsTo(const QString &targetZone, const QString &zoneDisplayName) +void PlayerActions::actMoveTopCardsToExileFaceDown() +{ + moveTopCardsTo("rfg", tr("exile"), true); +} + +void PlayerActions::moveTopCardsTo(const QString &targetZone, const QString &zoneDisplayName, bool faceDown) { const int maxCards = player->getDeckZone()->getCards().size(); if (maxCards == 0) { @@ -460,7 +470,11 @@ void PlayerActions::moveTopCardsTo(const QString &targetZone, const QString &zon cmd.set_y(0); for (int i = number - 1; i >= 0; --i) { - cmd.mutable_cards_to_move()->add_card()->set_card_id(i); + auto card = cmd.mutable_cards_to_move()->add_card(); + card->set_card_id(i); + if (faceDown) { + card->set_face_down(true); + } } sendGameCommand(cmd); @@ -608,15 +622,25 @@ void PlayerActions::actMoveBottomCardToExile() void PlayerActions::actMoveBottomCardsToGrave() { - moveBottomCardsTo("grave", tr("grave")); + moveBottomCardsTo("grave", tr("grave"), false); +} + +void PlayerActions::actMoveBottomCardsToGraveFaceDown() +{ + moveBottomCardsTo("grave", tr("grave"), true); } void PlayerActions::actMoveBottomCardsToExile() { - moveBottomCardsTo("rfg", tr("exile")); + moveBottomCardsTo("rfg", tr("exile"), false); } -void PlayerActions::moveBottomCardsTo(const QString &targetZone, const QString &zoneDisplayName) +void PlayerActions::actMoveBottomCardsToExileFaceDown() +{ + moveBottomCardsTo("rfg", tr("exile"), true); +} + +void PlayerActions::moveBottomCardsTo(const QString &targetZone, const QString &zoneDisplayName, bool faceDown) { const int maxCards = player->getDeckZone()->getCards().size(); if (maxCards == 0) { @@ -644,7 +668,11 @@ void PlayerActions::moveBottomCardsTo(const QString &targetZone, const QString & cmd.set_y(0); for (int i = maxCards - number; i < maxCards; ++i) { - cmd.mutable_cards_to_move()->add_card()->set_card_id(i); + auto card = cmd.mutable_cards_to_move()->add_card(); + card->set_card_id(i); + if (faceDown) { + card->set_face_down(true); + } } sendGameCommand(cmd); diff --git a/cockatrice/src/game/player/player_actions.h b/cockatrice/src/game/player/player_actions.h index beed2c241..1d695578d 100644 --- a/cockatrice/src/game/player/player_actions.h +++ b/cockatrice/src/game/player/player_actions.h @@ -98,7 +98,9 @@ public slots: void actMoveTopCardToGrave(); void actMoveTopCardToExile(); void actMoveTopCardsToGrave(); + void actMoveTopCardsToGraveFaceDown(); void actMoveTopCardsToExile(); + void actMoveTopCardsToExileFaceDown(); void actMoveTopCardsUntil(); void actMoveTopCardToBottom(); void actDrawBottomCard(); @@ -108,7 +110,9 @@ public slots: void actMoveBottomCardToGrave(); void actMoveBottomCardToExile(); void actMoveBottomCardsToGrave(); + void actMoveBottomCardsToGraveFaceDown(); void actMoveBottomCardsToExile(); + void actMoveBottomCardsToExileFaceDown(); void actMoveBottomCardToTop(); void actSelectAll(); @@ -180,8 +184,8 @@ private: FilterString movingCardsUntilFilter; int movingCardsUntilCounter = 0; - void moveTopCardsTo(const QString &targetZone, const QString &zoneDisplayName); - void moveBottomCardsTo(const QString &targetZone, const QString &zoneDisplayName); + void moveTopCardsTo(const QString &targetZone, const QString &zoneDisplayName, bool faceDown); + void moveBottomCardsTo(const QString &targetZone, const QString &zoneDisplayName, bool faceDown); void createCard(const CardItem *sourceCard, const QString &dbCardName, From 04f06206b7ae3ff3b4f21d50af3310965adac350 Mon Sep 17 00:00:00 2001 From: DawnFire42 Date: Thu, 5 Mar 2026 14:47:14 -0500 Subject: [PATCH 02/20] Refactor/z value constants (#6651) * feat(z-values): add centralized Z-value constants infrastructure Magic numbers scattered across the codebase make Z-value layering hard to understand and maintain. Centralizing them provides: - Self-documenting layer hierarchy - Validation utilities for development - Single source of truth for Z-value ranges Two-tier header design: - z_value_layer_manager.h: Foundation with constants and validation - z_values.h: User-facing namespace with semantic constants * refactor(z-values): replace magic Z-value numbers with ZValues constants Magic numbers like 2000000007 are impossible to understand without context. Named constants (ZValues::DRAG_ITEM) are self-documenting. This intentionally renumbers overlay Z-values to use a cleaner offset sequence. The relative stacking order is preserved, which is what matters for correct rendering. Each consumer now includes z_values.h and uses semantic constants instead of magic numbers. * refactor(z-values): removed redundant inline with contexpr, Updated doc, magic numbers removed from TableZone. --- .../game/board/abstract_card_drag_item.cpp | 5 +- .../src/game/board/abstract_card_item.cpp | 3 +- cockatrice/src/game/board/arrow_item.cpp | 3 +- cockatrice/src/game/z_value_layer_manager.h | 136 ++++++++++++++++++ cockatrice/src/game/z_values.h | 83 +++++++++++ cockatrice/src/game/zones/table_zone.cpp | 5 +- .../src/game/zones/view_zone_widget.cpp | 9 +- 7 files changed, 234 insertions(+), 10 deletions(-) create mode 100644 cockatrice/src/game/z_value_layer_manager.h create mode 100644 cockatrice/src/game/z_values.h diff --git a/cockatrice/src/game/board/abstract_card_drag_item.cpp b/cockatrice/src/game/board/abstract_card_drag_item.cpp index c961cbcb6..c9a964048 100644 --- a/cockatrice/src/game/board/abstract_card_drag_item.cpp +++ b/cockatrice/src/game/board/abstract_card_drag_item.cpp @@ -1,6 +1,7 @@ #include "abstract_card_drag_item.h" #include "../../client/settings/cache_settings.h" +#include "../z_values.h" #include #include @@ -18,13 +19,13 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item, { if (parentDrag) { parentDrag->addChildDrag(this); - setZValue(2000000007 + hotSpot.x() * 1000000 + hotSpot.y() * 1000 + 1000); + setZValue(ZValues::childDragZValue(hotSpot.x(), hotSpot.y())); connect(parentDrag, &QObject::destroyed, this, &AbstractCardDragItem::deleteLater); } else { hotSpot = QPointF{qBound(0.0, hotSpot.x(), static_cast(CARD_WIDTH - 1)), qBound(0.0, hotSpot.y(), static_cast(CARD_HEIGHT - 1))}; setCursor(Qt::ClosedHandCursor); - setZValue(2000000007); + setZValue(ZValues::DRAG_ITEM); } if (item->getTapped()) setTransform(QTransform() diff --git a/cockatrice/src/game/board/abstract_card_item.cpp b/cockatrice/src/game/board/abstract_card_item.cpp index d5538011d..f8365c3d6 100644 --- a/cockatrice/src/game/board/abstract_card_item.cpp +++ b/cockatrice/src/game/board/abstract_card_item.cpp @@ -3,6 +3,7 @@ #include "../../client/settings/cache_settings.h" #include "../../interface/card_picture_loader/card_picture_loader.h" #include "../game_scene.h" +#include "../z_values.h" #include #include @@ -215,7 +216,7 @@ void AbstractCardItem::setHovered(bool _hovered) if (_hovered) processHoverEvent(); isHovered = _hovered; - setZValue(_hovered ? 2000000004 : realZValue); + setZValue(_hovered ? ZValues::HOVERED_CARD : realZValue); setScale(_hovered && SettingsCache::instance().getScaleCards() ? 1.1 : 1); setTransformOriginPoint(_hovered ? CARD_WIDTH / 2 : 0, _hovered ? CARD_HEIGHT / 2 : 0); update(); diff --git a/cockatrice/src/game/board/arrow_item.cpp b/cockatrice/src/game/board/arrow_item.cpp index 1352b3a05..257d96f8a 100644 --- a/cockatrice/src/game/board/arrow_item.cpp +++ b/cockatrice/src/game/board/arrow_item.cpp @@ -5,6 +5,7 @@ #include "../player/player.h" #include "../player/player_actions.h" #include "../player/player_target.h" +#include "../z_values.h" #include "../zones/card_zone.h" #include "card_item.h" @@ -23,7 +24,7 @@ ArrowItem::ArrowItem(Player *_player, int _id, ArrowTarget *_startItem, ArrowTar : QGraphicsItem(), player(_player), id(_id), startItem(_startItem), targetItem(_targetItem), targetLocked(false), color(_color), fullColor(true) { - setZValue(2000000005); + setZValue(ZValues::ARROWS); if (startItem) startItem->addArrowFrom(this); diff --git a/cockatrice/src/game/z_value_layer_manager.h b/cockatrice/src/game/z_value_layer_manager.h new file mode 100644 index 000000000..303edb8a5 --- /dev/null +++ b/cockatrice/src/game/z_value_layer_manager.h @@ -0,0 +1,136 @@ +/** + * @file z_value_layer_manager.h + * @ingroup GameGraphics + * @brief Semantic Z-value layer management for game scene rendering. + * + * This file provides a structured approach to Z-value allocation in the game scene. + * Z-values in Qt determine stacking order - higher values render on top of lower values. + * + * ## Layer Architecture + * + * The game scene is organized into three conceptual layers: + * + * 1. **Zone Layer (0-999)**: Zone backgrounds, containers, and static elements + * - Zone backgrounds (0.5-1.0) + * - Cards within zones (1.0 base + index) + * + * 2. **Card Layer (1-40,000,000)**: Dynamic card rendering on the table zone + * - Cards use formula: (actualY + CARD_HEIGHT) * 100000 + (actualX + 1) * 100 + * - Maximum card Z-value: ~40,000,000 (with 3 rows, actualY <= ~289) + * + * 3. **Overlay Layer (2,000,000,000+)**: UI elements that must appear above all cards + * - Hovered cards (+1) + * - Arrows (+3) + * - Zone views (+4) + * - Drag items (+5, +6) + * - Top UI elements (+7) + * + * ## Design Rationale + * + * The large gap between card Z-values (max ~40M) and overlay base (2B) provides + * safety margin for future table zone expansions while ensuring overlays always + * render above cards regardless of table position. + * + * ## Usage + * + * Prefer using the semantic constants from ZValues namespace: + * @code + * card->setZValue(ZValues::HOVERED_CARD); + * arrow->setZValue(ZValues::ARROWS); + * @endcode + * + * Use validation functions to verify card Z-values during development: + * @code + * Q_ASSERT(ZValueLayerManager::isValidCardZValue(cardZ)); + * @endcode + */ + +#ifndef Z_VALUE_LAYER_MANAGER_H +#define Z_VALUE_LAYER_MANAGER_H + +#include + +/** + * @namespace ZValueLayerManager + * @brief Utilities for Z-value validation and layer management. + */ +namespace ZValueLayerManager +{ + +/** + * @enum Layer + * @brief Semantic layer identifiers for Z-value allocation. + * + * These represent conceptual rendering layers, not actual Z-values. + * Use the corresponding ZValues constants for actual rendering. + */ +enum class Layer +{ + /// Zone-level elements like backgrounds and containers + Zone, + /// Cards rendered in zones (uses sequential Z-values) + Card, + /// Temporary UI elements like hovered cards and drag items + Overlay +}; + +/** + * @brief Maximum Z-value a card can have on the table zone. + * + * Based on table zone formula: (actualY + CARD_HEIGHT) * 100000 + (actualX + 1) * 100 + * With maximum 3 rows and CARD_HEIGHT ~96, actualY <= ~289. + * Maximum: (289 + 96) * 100000 + 100 * 100 = 38,510,000 + * + * We use 40,000,000 as a safe upper bound with margin. + */ +constexpr qreal CARD_Z_VALUE_MAX = 40000000.0; + +/** + * @brief Base Z-value for overlay elements. + * + * Must exceed CARD_Z_VALUE_MAX to ensure overlays render above all cards. + * The 50x margin (2B vs 40M) provides safety for future expansion. + */ +constexpr qreal OVERLAY_BASE = 2000000000.0; + +/** + * @brief Validates that a Z-value is within the valid card range. + * + * Cards should have Z-values between CARD_BASE (1.0) and CARD_Z_VALUE_MAX. + * Values outside this range may interfere with overlay rendering. + * + * @param zValue The Z-value to validate + * @return true if the Z-value is valid for a card + */ +[[nodiscard]] constexpr bool isValidCardZValue(qreal zValue) +{ + return zValue >= 1.0 && zValue <= CARD_Z_VALUE_MAX; +} + +/** + * @brief Validates that a Z-value is in the overlay layer. + * + * Overlay elements should have Z-values at or above OVERLAY_BASE. + * + * @param zValue The Z-value to validate + * @return true if the Z-value is valid for an overlay element + */ +[[nodiscard]] constexpr bool isOverlayZValue(qreal zValue) +{ + return zValue >= OVERLAY_BASE; +} + +/** + * @brief Returns the Z-value for a specific overlay element. + * + * @param offset Offset from OVERLAY_BASE (0-7 for current elements) + * @return The absolute Z-value for the overlay element + */ +[[nodiscard]] constexpr qreal overlayZValue(qreal offset) +{ + return OVERLAY_BASE + offset; +} + +} // namespace ZValueLayerManager + +#endif // Z_VALUE_LAYER_MANAGER_H diff --git a/cockatrice/src/game/z_values.h b/cockatrice/src/game/z_values.h new file mode 100644 index 000000000..2c7fe9066 --- /dev/null +++ b/cockatrice/src/game/z_values.h @@ -0,0 +1,83 @@ +#ifndef Z_VALUES_H +#define Z_VALUES_H + +#include "z_value_layer_manager.h" + +/** + * @file z_values.h + * @ingroup GameGraphics + * @brief Centralized Z-value constants for rendering layer order. + * + * Z-values in Qt determine stacking order. Higher values render on top. + * These constants define the visual layering hierarchy for the game scene. + * + * ## Layer Architecture + * + * See z_value_layer_manager.h for detailed documentation on the three-layer + * architecture (Zone, Card, Overlay) and the rationale for Z-value choices. + * + * ## Quick Reference + * + * | Layer | Z-Value Range | Purpose | + * |----------|------------------|-----------------------------------| + * | Zone | 0.5 - 1.0 | Zone backgrounds, containers | + * | Card | 1.0 - 40,000,000 | Cards on table (position-based) | + * | Overlay | 2,000,000,000+ | UI elements above all cards | + */ + +namespace ZValues +{ + +// Expose base for callers that need it +constexpr qreal OVERLAY_BASE = ZValueLayerManager::OVERLAY_BASE; + +// Overlay layer Z-values for items that should appear above normal cards +constexpr qreal HOVERED_CARD = ZValueLayerManager::overlayZValue(1.0); +constexpr qreal ARROWS = ZValueLayerManager::overlayZValue(3.0); +constexpr qreal ZONE_VIEW_WIDGET = ZValueLayerManager::overlayZValue(4.0); +constexpr qreal DRAG_ITEM = ZValueLayerManager::overlayZValue(5.0); +constexpr qreal DRAG_ITEM_CHILD = ZValueLayerManager::overlayZValue(6.0); +constexpr qreal TOP_UI = ZValueLayerManager::overlayZValue(7.0); + +/** + * @brief Compute Z-value for child drag items based on hotspot position. + * + * When dragging multiple cards together, each child card needs a unique Z-value + * to prevent Z-fighting (flickering/flashing). The Z-values are derived from + * their position when grabbed to conserve original stacking. The formula encodes + * 2D coordinates into a single value where X has higher weight, ensuring + * deterministic visual stacking. + * + * @param hotSpotX The X coordinate of the grab position + * @param hotSpotY The Y coordinate of the grab position + * @return Unique Z-value for the child drag item + */ +[[nodiscard]] constexpr qreal childDragZValue(qreal hotSpotX, qreal hotSpotY) +{ + return DRAG_ITEM_CHILD + hotSpotX * 1000000 + hotSpotY * 1000 + 1000; +} + +/** + * @brief Compute Z-value for cards on the table zone based on position. + * + * Cards lower on the table (higher Y) render above cards higher up, + * and cards to the right (higher X) render above cards to the left. + * This creates natural visual stacking for overlapping cards. + * + * @param x The X coordinate of the card position + * @param y The Y coordinate of the card position + * @return Z-value for the card's table position + */ +[[nodiscard]] constexpr qreal tableCardZValue(qreal x, qreal y) +{ + constexpr qreal CARD_HEIGHT_FOR_Z = 102.0; + return (y + CARD_HEIGHT_FOR_Z) * 100000.0 + (x + 1) * 100.0; +} + +// Card layering (general architecture, not command-zone specific) +constexpr qreal CARD_BASE = 1.0; +constexpr qreal CARD_MAX = ZValueLayerManager::CARD_Z_VALUE_MAX; + +} // namespace ZValues + +#endif // Z_VALUES_H diff --git a/cockatrice/src/game/zones/table_zone.cpp b/cockatrice/src/game/zones/table_zone.cpp index ca1052d20..33c867c43 100644 --- a/cockatrice/src/game/zones/table_zone.cpp +++ b/cockatrice/src/game/zones/table_zone.cpp @@ -7,6 +7,7 @@ #include "../board/card_item.h" #include "../player/player.h" #include "../player/player_actions.h" +#include "../z_values.h" #include "logic/table_zone_logic.h" #include @@ -169,7 +170,7 @@ void TableZone::reorganizeCards() actualY += 15; getLogic()->getCards()[i]->setPos(actualX, actualY); - getLogic()->getCards()[i]->setRealZValue((actualY + CARD_HEIGHT) * 100000 + (actualX + 1) * 100); + getLogic()->getCards()[i]->setRealZValue(ZValues::tableCardZValue(actualX, actualY)); QListIterator attachedCardIterator(getLogic()->getCards()[i]->getAttachedCards()); int j = 0; @@ -179,7 +180,7 @@ void TableZone::reorganizeCards() qreal childX = actualX - j * STACKED_CARD_OFFSET_X; qreal childY = y + 5; attachedCard->setPos(childX, childY); - attachedCard->setRealZValue((childY + CARD_HEIGHT) * 100000 + (childX + 1) * 100); + attachedCard->setRealZValue(ZValues::tableCardZValue(childX, childY)); } } diff --git a/cockatrice/src/game/zones/view_zone_widget.cpp b/cockatrice/src/game/zones/view_zone_widget.cpp index 3ea4eb119..0ad3b10f1 100644 --- a/cockatrice/src/game/zones/view_zone_widget.cpp +++ b/cockatrice/src/game/zones/view_zone_widget.cpp @@ -7,6 +7,7 @@ #include "../game_scene.h" #include "../player/player.h" #include "../player/player_actions.h" +#include "../z_values.h" #include "view_zone.h" #include @@ -47,7 +48,7 @@ ZoneViewWidget::ZoneViewWidget(Player *_player, { setAcceptHoverEvents(true); setAttribute(Qt::WA_DeleteOnClose); - setZValue(2000000006); + setZValue(ZValues::ZONE_VIEW_WIDGET); setFlag(ItemIgnoresTransformations); QGraphicsLinearLayout *vbox = new QGraphicsLinearLayout(Qt::Vertical); @@ -71,7 +72,7 @@ ZoneViewWidget::ZoneViewWidget(Player *_player, QGraphicsProxyWidget *searchEditProxy = new QGraphicsProxyWidget; searchEditProxy->setWidget(&searchEdit); - searchEditProxy->setZValue(2000000007); + searchEditProxy->setZValue(ZValues::DRAG_ITEM); vbox->addItem(searchEditProxy); // top row @@ -80,13 +81,13 @@ ZoneViewWidget::ZoneViewWidget(Player *_player, // groupBy options QGraphicsProxyWidget *groupBySelectorProxy = new QGraphicsProxyWidget; groupBySelectorProxy->setWidget(&groupBySelector); - groupBySelectorProxy->setZValue(2000000008); + groupBySelectorProxy->setZValue(ZValues::TOP_UI); hTopRow->addItem(groupBySelectorProxy); // sortBy options QGraphicsProxyWidget *sortBySelectorProxy = new QGraphicsProxyWidget; sortBySelectorProxy->setWidget(&sortBySelector); - sortBySelectorProxy->setZValue(2000000007); + sortBySelectorProxy->setZValue(ZValues::DRAG_ITEM); hTopRow->addItem(sortBySelectorProxy); vbox->addItem(hTopRow); From e39bbd2b316753f254be8ae8b60c5c8808160b6b Mon Sep 17 00:00:00 2001 From: ebbit1q Date: Fri, 6 Mar 2026 00:19:10 +0100 Subject: [PATCH 03/20] take default theme name from startup instead of using empty (#6663) --- cockatrice/src/interface/theme_manager.cpp | 4 +++- cockatrice/src/interface/theme_manager.h | 1 + cockatrice/src/interface/widgets/general/home_widget.cpp | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/cockatrice/src/interface/theme_manager.cpp b/cockatrice/src/interface/theme_manager.cpp index abacb2d68..1dc61fdb7 100644 --- a/cockatrice/src/interface/theme_manager.cpp +++ b/cockatrice/src/interface/theme_manager.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -89,6 +90,7 @@ struct PaletteColorInfo ThemeManager::ThemeManager(QObject *parent) : QObject(parent) { + defaultStyleName = qApp->style()->objectName(); ensureThemeDirectoryExists(); #if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &ThemeManager::themeChangedSlot); @@ -346,7 +348,7 @@ void ThemeManager::themeChangedSlot() qApp->setStyle(QStyleFactory::create("Fusion")); qApp->setPalette(createDarkGreenFusionPalette()); } else { - qApp->setStyle(""); + qApp->setStyle(defaultStyleName); // setting the style also sets the palette } if (dirPath.isEmpty()) { diff --git a/cockatrice/src/interface/theme_manager.h b/cockatrice/src/interface/theme_manager.h index 594ede2bf..d942f0fef 100644 --- a/cockatrice/src/interface/theme_manager.h +++ b/cockatrice/src/interface/theme_manager.h @@ -40,6 +40,7 @@ public: }; private: + QString defaultStyleName; std::array brushes; QStringMap availableThemes; /* diff --git a/cockatrice/src/interface/widgets/general/home_widget.cpp b/cockatrice/src/interface/widgets/general/home_widget.cpp index 750ddd000..ea20ef6a0 100644 --- a/cockatrice/src/interface/widgets/general/home_widget.cpp +++ b/cockatrice/src/interface/widgets/general/home_widget.cpp @@ -46,6 +46,8 @@ HomeWidget::HomeWidget(QWidget *parent, TabSupervisor *_tabSupervisor) &HomeWidget::onBackgroundShuffleFrequencyChanged); // Lambda is cleaner to read than overloading this connect(&SettingsCache::instance(), &SettingsCache::homeTabDisplayCardNameChanged, this, [this] { repaint(); }); + connect(&SettingsCache::instance(), &SettingsCache::themeChanged, this, + &HomeWidget::updateButtonsToBackgroundColor); } void HomeWidget::initializeBackgroundFromSource() From 14f1925edc8a47045e771e71746e07290fef3679 Mon Sep 17 00:00:00 2001 From: tooomm Date: Fri, 6 Mar 2026 01:50:15 +0100 Subject: [PATCH 04/20] Add icon to exe (#6655) --- cmake/NSIS.template.in | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/NSIS.template.in b/cmake/NSIS.template.in index a0d51fa2b..2fdc61fb9 100644 --- a/cmake/NSIS.template.in +++ b/cmake/NSIS.template.in @@ -26,6 +26,7 @@ Var PortableMode !define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of Cockatrice.$\r$\n$\r$\nClick Next to continue." !define MUI_FINISHPAGE_RUN "$INSTDIR/cockatrice.exe" !define MUI_FINISHPAGE_RUN_TEXT "Run 'Cockatrice' now" +!define MUI_ICON "${NSIS_SOURCE_PATH}\cockatrice\resources\appicon.ico" !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE "${NSIS_SOURCE_PATH}\LICENSE" From bd5cbb89d47c2cdfac9eb59e550e737d51321775 Mon Sep 17 00:00:00 2001 From: DawnFire42 Date: Thu, 5 Mar 2026 22:13:58 -0500 Subject: [PATCH 05/20] refactor: extract CARD_HEIGHT to shared CardDimensions header (#6668) * refactor: extract CARD_HEIGHT to shared CardDimensions header Move duplicated CARD_WIDTH/CARD_HEIGHT constants to card_dimensions.h. Fixed documentation in z_value_layer_manager.h. * WIDTH_F used directly instead of casting * Improved consistency and added missing newlines at end of files --- .../game/board/abstract_card_drag_item.cpp | 12 ++++---- .../src/game/board/abstract_card_drag_item.h | 2 +- .../src/game/board/abstract_card_item.cpp | 10 +++---- .../src/game/board/abstract_card_item.h | 4 +-- cockatrice/src/game/board/card_item.cpp | 9 +++--- cockatrice/src/game/board/card_item.h | 2 -- cockatrice/src/game/card_dimensions.h | 29 +++++++++++++++++++ cockatrice/src/game/deckview/deck_view.cpp | 22 +++++++------- .../src/game/player/player_graphics_item.cpp | 22 +++++++------- cockatrice/src/game/z_value_layer_manager.h | 8 ++--- cockatrice/src/game/z_values.h | 4 +-- cockatrice/src/game/zones/hand_zone.cpp | 2 +- cockatrice/src/game/zones/pile_zone.cpp | 12 ++++---- cockatrice/src/game/zones/table_zone.cpp | 22 +++++++------- cockatrice/src/game/zones/table_zone.h | 4 +-- cockatrice/src/game/zones/view_zone.cpp | 16 +++++----- .../src/game/zones/view_zone_widget.cpp | 4 +-- .../cards/card_info_display_widget.cpp | 2 +- 18 files changed, 108 insertions(+), 78 deletions(-) create mode 100644 cockatrice/src/game/card_dimensions.h diff --git a/cockatrice/src/game/board/abstract_card_drag_item.cpp b/cockatrice/src/game/board/abstract_card_drag_item.cpp index c9a964048..8e3def4ca 100644 --- a/cockatrice/src/game/board/abstract_card_drag_item.cpp +++ b/cockatrice/src/game/board/abstract_card_drag_item.cpp @@ -8,8 +8,6 @@ #include #include -static const float CARD_WIDTH_HALF = CARD_WIDTH / 2; -static const float CARD_HEIGHT_HALF = CARD_HEIGHT / 2; const QColor GHOST_MASK = QColor(255, 255, 255, 50); AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item, @@ -22,16 +20,16 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item, setZValue(ZValues::childDragZValue(hotSpot.x(), hotSpot.y())); connect(parentDrag, &QObject::destroyed, this, &AbstractCardDragItem::deleteLater); } else { - hotSpot = QPointF{qBound(0.0, hotSpot.x(), static_cast(CARD_WIDTH - 1)), - qBound(0.0, hotSpot.y(), static_cast(CARD_HEIGHT - 1))}; + hotSpot = QPointF{qBound(0.0, hotSpot.x(), CardDimensions::WIDTH_F - 1), + qBound(0.0, hotSpot.y(), CardDimensions::HEIGHT_F - 1)}; setCursor(Qt::ClosedHandCursor); setZValue(ZValues::DRAG_ITEM); } if (item->getTapped()) setTransform(QTransform() - .translate(CARD_WIDTH_HALF, CARD_HEIGHT_HALF) + .translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F) .rotate(90) - .translate(-CARD_WIDTH_HALF, -CARD_HEIGHT_HALF)); + .translate(-CardDimensions::WIDTH_HALF_F, -CardDimensions::HEIGHT_HALF_F)); setCacheMode(DeviceCoordinateCache); @@ -48,7 +46,7 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item, QPainterPath AbstractCardDragItem::shape() const { QPainterPath shape; - qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CARD_WIDTH : 0.0; + qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CardDimensions::WIDTH_F : 0.0; shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius); return shape; } diff --git a/cockatrice/src/game/board/abstract_card_drag_item.h b/cockatrice/src/game/board/abstract_card_drag_item.h index 1d741eded..fe3b87983 100644 --- a/cockatrice/src/game/board/abstract_card_drag_item.h +++ b/cockatrice/src/game/board/abstract_card_drag_item.h @@ -34,7 +34,7 @@ public: AbstractCardDragItem(AbstractCardItem *_item, const QPointF &_hotSpot, AbstractCardDragItem *parentDrag = 0); [[nodiscard]] QRectF boundingRect() const override { - return QRectF(0, 0, CARD_WIDTH, CARD_HEIGHT); + return QRectF(0, 0, CardDimensions::WIDTH_F, CardDimensions::HEIGHT_F); } [[nodiscard]] QPainterPath shape() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; diff --git a/cockatrice/src/game/board/abstract_card_item.cpp b/cockatrice/src/game/board/abstract_card_item.cpp index f8365c3d6..9ec6ada9a 100644 --- a/cockatrice/src/game/board/abstract_card_item.cpp +++ b/cockatrice/src/game/board/abstract_card_item.cpp @@ -39,13 +39,13 @@ AbstractCardItem::~AbstractCardItem() QRectF AbstractCardItem::boundingRect() const { - return QRectF(0, 0, CARD_WIDTH, CARD_HEIGHT); + return QRectF(0, 0, CardDimensions::WIDTH_F, CardDimensions::HEIGHT_F); } QPainterPath AbstractCardItem::shape() const { QPainterPath shape; - qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CARD_WIDTH : 0.0; + qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CardDimensions::WIDTH_F : 0.0; shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius); return shape; } @@ -218,7 +218,7 @@ void AbstractCardItem::setHovered(bool _hovered) isHovered = _hovered; setZValue(_hovered ? ZValues::HOVERED_CARD : realZValue); setScale(_hovered && SettingsCache::instance().getScaleCards() ? 1.1 : 1); - setTransformOriginPoint(_hovered ? CARD_WIDTH / 2 : 0, _hovered ? CARD_HEIGHT / 2 : 0); + setTransformOriginPoint(_hovered ? CardDimensions::WIDTH_HALF_F : 0, _hovered ? CardDimensions::HEIGHT_HALF_F : 0); update(); } @@ -274,9 +274,9 @@ void AbstractCardItem::setTapped(bool _tapped, bool canAnimate) else { tapAngle = tapped ? 90 : 0; setTransform(QTransform() - .translate((float)CARD_WIDTH / 2, (float)CARD_HEIGHT / 2) + .translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F) .rotate(tapAngle) - .translate((float)-CARD_WIDTH / 2, (float)-CARD_HEIGHT / 2)); + .translate(-CardDimensions::WIDTH_HALF_F, -CardDimensions::HEIGHT_HALF_F)); update(); } } diff --git a/cockatrice/src/game/board/abstract_card_item.h b/cockatrice/src/game/board/abstract_card_item.h index dad73dc14..7d2c29cae 100644 --- a/cockatrice/src/game/board/abstract_card_item.h +++ b/cockatrice/src/game/board/abstract_card_item.h @@ -8,6 +8,7 @@ #define ABSTRACTCARDITEM_H #include "../../game_graphics/board/graphics_item_type.h" +#include "../card_dimensions.h" #include "arrow_target.h" #include @@ -15,9 +16,6 @@ class Player; -const int CARD_WIDTH = 72; -const int CARD_HEIGHT = 102; - class AbstractCardItem : public ArrowTarget { Q_OBJECT diff --git a/cockatrice/src/game/board/card_item.cpp b/cockatrice/src/game/board/card_item.cpp index 8b9549f07..62de4a02e 100644 --- a/cockatrice/src/game/board/card_item.cpp +++ b/cockatrice/src/game/board/card_item.cpp @@ -367,8 +367,9 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) if (zone->getHasCardAttr()) childPos = card->pos() - pos(); else - childPos = QPointF(childIndex * CARD_WIDTH / 2, 0); - CardDragItem *drag = new CardDragItem(card, card->getId(), childPos, forceFaceDown, dragItem); + childPos = QPointF(childIndex * CardDimensions::WIDTH_HALF_F, 0); + CardDragItem *drag = + new CardDragItem(card, card->getId(), childPos, card->getFaceDown() || forceFaceDown, dragItem); drag->setPos(dragItem->pos() + childPos); scene()->addItem(drag); } @@ -475,9 +476,9 @@ bool CardItem::animationEvent() } setTransform(QTransform() - .translate(CARD_WIDTH_HALF, CARD_HEIGHT_HALF) + .translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F) .rotate(tapAngle) - .translate(-CARD_WIDTH_HALF, -CARD_HEIGHT_HALF)); + .translate(-CardDimensions::WIDTH_HALF_F, -CardDimensions::HEIGHT_HALF_F)); setHovered(false); update(); diff --git a/cockatrice/src/game/board/card_item.h b/cockatrice/src/game/board/card_item.h index 875c3f4d0..da2097a2c 100644 --- a/cockatrice/src/game/board/card_item.h +++ b/cockatrice/src/game/board/card_item.h @@ -21,8 +21,6 @@ class QAction; class QColor; const int MAX_COUNTERS_ON_CARD = 999; -const float CARD_WIDTH_HALF = CARD_WIDTH / 2; -const float CARD_HEIGHT_HALF = CARD_HEIGHT / 2; const int ROTATION_DEGREES_PER_FRAME = 10; class CardItem : public AbstractCardItem diff --git a/cockatrice/src/game/card_dimensions.h b/cockatrice/src/game/card_dimensions.h new file mode 100644 index 000000000..255d0bc04 --- /dev/null +++ b/cockatrice/src/game/card_dimensions.h @@ -0,0 +1,29 @@ +#ifndef CARD_DIMENSIONS_H +#define CARD_DIMENSIONS_H + +#include + +/** + * @file card_dimensions.h + * @brief Canonical card dimension constants for layout and Z-value calculations. + * + * These values represent the logical pixel dimensions of a standard card graphic. + * They are used throughout the game scene for layout, rendering, and Z-value computation. + */ +namespace CardDimensions +{ +/// Card width in pixels +constexpr int WIDTH = 72; +/// Card height in pixels +constexpr int HEIGHT = 102; + +/// Pre-converted for floating-point contexts (Z-value calculations) +constexpr qreal WIDTH_F = static_cast(WIDTH); +constexpr qreal HEIGHT_F = static_cast(HEIGHT); + +/// Half-dimensions for centering and rotation transforms +constexpr qreal WIDTH_HALF_F = WIDTH_F / 2; +constexpr qreal HEIGHT_HALF_F = HEIGHT_F / 2; +} // namespace CardDimensions + +#endif // CARD_DIMENSIONS_H diff --git a/cockatrice/src/game/deckview/deck_view.cpp b/cockatrice/src/game/deckview/deck_view.cpp index 383545cf3..620dfaa5f 100644 --- a/cockatrice/src/game/deckview/deck_view.cpp +++ b/cockatrice/src/game/deckview/deck_view.cpp @@ -95,8 +95,9 @@ void DeckViewCard::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti pen.setJoinStyle(Qt::MiterJoin); pen.setColor(originZone == DECK_ZONE_MAIN ? Qt::green : Qt::red); painter->setPen(pen); - qreal cardRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * (CARD_WIDTH - 3) : 0.0; - painter->drawRoundedRect(QRectF(1.5, 1.5, CARD_WIDTH - 3., CARD_HEIGHT - 3.), cardRadius, cardRadius); + qreal cardRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * (CardDimensions::WIDTH_F - 3) : 0.0; + painter->drawRoundedRect(QRectF(1.5, 1.5, CardDimensions::WIDTH_F - 3, CardDimensions::HEIGHT_F - 3), cardRadius, + cardRadius); painter->restore(); } @@ -122,7 +123,7 @@ void DeckViewCard::mouseMoveEvent(QGraphicsSceneMouseEvent *event) if (c == this) continue; ++j; - auto childPos = QPointF(j * CARD_WIDTH / 2, 0); + auto childPos = QPointF(j * CardDimensions::WIDTH_HALF_F, 0); auto *drag = new DeckViewCardDragItem(c, childPos, dragItem); drag->setPos(dragItem->pos() + childPos); scene()->addItem(drag); @@ -204,7 +205,7 @@ void DeckViewCardContainer::paint(QPainter *painter, const QStyleOptionGraphicsI painter->setPen(QColor(255, 255, 255, 100)); painter->drawLine(QPointF(0, yUntilNow - paddingY / 2), QPointF(width, yUntilNow - paddingY / 2)); } - qreal thisRowHeight = CARD_HEIGHT * currentRowsAndCols[i].first; + qreal thisRowHeight = CardDimensions::HEIGHT_F * currentRowsAndCols[i].first; QRectF textRect(0, yUntilNow, totalTextWidth, thisRowHeight); yUntilNow += thisRowHeight + paddingY; @@ -260,9 +261,9 @@ QSizeF DeckViewCardContainer::calculateBoundingRect(const QList> // Calculate space needed for cards for (int i = 0; i < rowsAndCols.size(); ++i) { - totalHeight += CARD_HEIGHT * rowsAndCols[i].first + paddingY; - if (CARD_WIDTH * rowsAndCols[i].second > totalWidth) - totalWidth = CARD_WIDTH * rowsAndCols[i].second; + totalHeight += CardDimensions::HEIGHT_F * rowsAndCols[i].first + paddingY; + if (CardDimensions::WIDTH_F * rowsAndCols[i].second > totalWidth) + totalWidth = CardDimensions::WIDTH_F * rowsAndCols[i].second; } return QSizeF(getCardTypeTextWidth() + totalWidth, totalHeight + separatorY + paddingY); @@ -289,9 +290,10 @@ void DeckViewCardContainer::rearrangeItems(const QList> &rowsAnd std::sort(row.begin(), row.end(), DeckViewCardContainer::sortCardsByName); for (int j = 0; j < row.size(); ++j) { DeckViewCard *card = row[j]; - card->setPos(x + (j % tempCols) * CARD_WIDTH, yUntilNow + (j / tempCols) * CARD_HEIGHT); + card->setPos(x + (j % tempCols) * CardDimensions::WIDTH_F, + yUntilNow + (j / tempCols) * CardDimensions::HEIGHT_F); } - yUntilNow += tempRows * CARD_HEIGHT + paddingY; + yUntilNow += tempRows * CardDimensions::HEIGHT_F + paddingY; } prepareGeometryChange(); @@ -392,7 +394,7 @@ void DeckViewScene::applySideboardPlan(const QList &plan) void DeckViewScene::rearrangeItems() { - const int spacing = CARD_HEIGHT / 3; + const int spacing = CardDimensions::HEIGHT / 3; QList contList = cardContainers.values(); // Initialize space requirements diff --git a/cockatrice/src/game/player/player_graphics_item.cpp b/cockatrice/src/game/player/player_graphics_item.cpp index 30648c926..bcc4b7f72 100644 --- a/cockatrice/src/game/player/player_graphics_item.cpp +++ b/cockatrice/src/game/player/player_graphics_item.cpp @@ -19,7 +19,8 @@ PlayerGraphicsItem::PlayerGraphicsItem(Player *_player) : player(_player) playerArea = new PlayerArea(this); playerTarget = new PlayerTarget(player, playerArea); - qreal avatarMargin = (counterAreaWidth + CARD_HEIGHT + 15 - playerTarget->boundingRect().width()) / 2.0; + qreal avatarMargin = + (counterAreaWidth + CardDimensions::HEIGHT_F + 15 - playerTarget->boundingRect().width()) / 2.0; playerTarget->setPos(QPointF(avatarMargin, avatarMargin)); initializeZones(); @@ -55,8 +56,9 @@ void PlayerGraphicsItem::onPlayerActiveChanged(bool _active) void PlayerGraphicsItem::initializeZones() { deckZoneGraphicsItem = new PileZone(player->getDeckZone(), this); - auto base = QPointF(counterAreaWidth + (CARD_HEIGHT - CARD_WIDTH + 15) / 2.0, - 10 + playerTarget->boundingRect().height() + 5 - (CARD_HEIGHT - CARD_WIDTH) / 2.0); + auto base = QPointF(counterAreaWidth + (CardDimensions::HEIGHT_F - CardDimensions::WIDTH_F + 15) / 2.0, + 10 + playerTarget->boundingRect().height() + 5 - + (CardDimensions::HEIGHT_F - CardDimensions::WIDTH_F) / 2.0); deckZoneGraphicsItem->setPos(base); qreal h = deckZoneGraphicsItem->boundingRect().width() + 5; @@ -95,7 +97,7 @@ QRectF PlayerGraphicsItem::boundingRect() const qreal PlayerGraphicsItem::getMinimumWidth() const { - qreal result = tableZoneGraphicsItem->getMinimumWidth() + CARD_HEIGHT + 15 + counterAreaWidth + + qreal result = tableZoneGraphicsItem->getMinimumWidth() + CardDimensions::HEIGHT_F + 15 + counterAreaWidth + stackZoneGraphicsItem->boundingRect().width(); if (!SettingsCache::instance().getHorizontalHand()) { result += handZoneGraphicsItem->boundingRect().width(); @@ -112,8 +114,8 @@ void PlayerGraphicsItem::paint(QPainter * /*painter*/, void PlayerGraphicsItem::processSceneSizeChange(int newPlayerWidth) { // Extend table (and hand, if horizontal) to accommodate the new player width. - qreal tableWidth = - newPlayerWidth - CARD_HEIGHT - 15 - counterAreaWidth - stackZoneGraphicsItem->boundingRect().width(); + qreal tableWidth = newPlayerWidth - CardDimensions::HEIGHT_F - 15 - counterAreaWidth - + stackZoneGraphicsItem->boundingRect().width(); if (!SettingsCache::instance().getHorizontalHand()) { tableWidth -= handZoneGraphicsItem->boundingRect().width(); } @@ -152,7 +154,7 @@ void PlayerGraphicsItem::rearrangeCounters() void PlayerGraphicsItem::rearrangeZones() { - auto base = QPointF(CARD_HEIGHT + counterAreaWidth + 15, 0); + auto base = QPointF(CardDimensions::HEIGHT_F + counterAreaWidth + 15, 0); if (SettingsCache::instance().getHorizontalHand()) { if (mirrored) { if (player->getHandZone()->contentsKnown()) { @@ -203,7 +205,7 @@ void PlayerGraphicsItem::rearrangeZones() void PlayerGraphicsItem::updateBoundingRect() { prepareGeometryChange(); - qreal width = CARD_HEIGHT + 15 + counterAreaWidth + stackZoneGraphicsItem->boundingRect().width(); + qreal width = CardDimensions::HEIGHT_F + 15 + counterAreaWidth + stackZoneGraphicsItem->boundingRect().width(); if (SettingsCache::instance().getHorizontalHand()) { qreal handHeight = player->getPlayerInfo()->getHandVisible() ? handZoneGraphicsItem->boundingRect().height() : 0; @@ -214,7 +216,7 @@ void PlayerGraphicsItem::updateBoundingRect() 0, 0, width + handZoneGraphicsItem->boundingRect().width() + tableZoneGraphicsItem->boundingRect().width(), tableZoneGraphicsItem->boundingRect().height()); } - playerArea->setSize(CARD_HEIGHT + counterAreaWidth + 15, bRect.height()); + playerArea->setSize(CardDimensions::HEIGHT_F + counterAreaWidth + 15, bRect.height()); emit sizeChanged(); -} \ No newline at end of file +} diff --git a/cockatrice/src/game/z_value_layer_manager.h b/cockatrice/src/game/z_value_layer_manager.h index 303edb8a5..4eb864486 100644 --- a/cockatrice/src/game/z_value_layer_manager.h +++ b/cockatrice/src/game/z_value_layer_manager.h @@ -15,7 +15,7 @@ * - Cards within zones (1.0 base + index) * * 2. **Card Layer (1-40,000,000)**: Dynamic card rendering on the table zone - * - Cards use formula: (actualY + CARD_HEIGHT) * 100000 + (actualX + 1) * 100 + * - Cards use formula: (actualY + CardDimensions::HEIGHT) * 100000 + (actualX + 1) * 100 * - Maximum card Z-value: ~40,000,000 (with 3 rows, actualY <= ~289) * * 3. **Overlay Layer (2,000,000,000+)**: UI elements that must appear above all cards @@ -77,9 +77,9 @@ enum class Layer /** * @brief Maximum Z-value a card can have on the table zone. * - * Based on table zone formula: (actualY + CARD_HEIGHT) * 100000 + (actualX + 1) * 100 - * With maximum 3 rows and CARD_HEIGHT ~96, actualY <= ~289. - * Maximum: (289 + 96) * 100000 + 100 * 100 = 38,510,000 + * Based on table zone formula: (actualY + CardDimensions::HEIGHT) * 100000 + (actualX + 1) * 100 + * With maximum 3 rows and CardDimensions::HEIGHT = 102, actualY <= ~289. + * Maximum: (289 + 102) * 100000 + 100 * 100 = 39,110,000 * * We use 40,000,000 as a safe upper bound with margin. */ diff --git a/cockatrice/src/game/z_values.h b/cockatrice/src/game/z_values.h index 2c7fe9066..c6e7f2c8a 100644 --- a/cockatrice/src/game/z_values.h +++ b/cockatrice/src/game/z_values.h @@ -1,6 +1,7 @@ #ifndef Z_VALUES_H #define Z_VALUES_H +#include "card_dimensions.h" #include "z_value_layer_manager.h" /** @@ -70,8 +71,7 @@ constexpr qreal TOP_UI = ZValueLayerManager::overlayZValue(7.0); */ [[nodiscard]] constexpr qreal tableCardZValue(qreal x, qreal y) { - constexpr qreal CARD_HEIGHT_FOR_Z = 102.0; - return (y + CARD_HEIGHT_FOR_Z) * 100000.0 + (x + 1) * 100.0; + return (y + CardDimensions::HEIGHT_F) * 100000.0 + (x + 1) * 100.0; } // Card layering (general architecture, not command-zone specific) diff --git a/cockatrice/src/game/zones/hand_zone.cpp b/cockatrice/src/game/zones/hand_zone.cpp index cc3b44910..7badfcca4 100644 --- a/cockatrice/src/game/zones/hand_zone.cpp +++ b/cockatrice/src/game/zones/hand_zone.cpp @@ -56,7 +56,7 @@ void HandZone::handleDropEvent(const QList &dragItems, QRectF HandZone::boundingRect() const { if (SettingsCache::instance().getHorizontalHand()) - return QRectF(0, 0, width, CARD_HEIGHT + 10); + return QRectF(0, 0, width, CardDimensions::HEIGHT_F + 10); else return QRectF(0, 0, 100, zoneHeight); } diff --git a/cockatrice/src/game/zones/pile_zone.cpp b/cockatrice/src/game/zones/pile_zone.cpp index 87a60fc03..d85b5f4e2 100644 --- a/cockatrice/src/game/zones/pile_zone.cpp +++ b/cockatrice/src/game/zones/pile_zone.cpp @@ -19,9 +19,9 @@ PileZone::PileZone(PileZoneLogic *_logic, QGraphicsItem *parent) : CardZone(_log setCursor(Qt::OpenHandCursor); setTransform(QTransform() - .translate((float)CARD_WIDTH / 2, (float)CARD_HEIGHT / 2) + .translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F) .rotate(90) - .translate((float)-CARD_WIDTH / 2, (float)-CARD_HEIGHT / 2)); + .translate(-CardDimensions::WIDTH_HALF_F, -CardDimensions::HEIGHT_HALF_F)); connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) { Q_UNUSED(_roundCardCorners); @@ -33,13 +33,13 @@ PileZone::PileZone(PileZoneLogic *_logic, QGraphicsItem *parent) : CardZone(_log QRectF PileZone::boundingRect() const { - return QRectF(0, 0, CARD_WIDTH, CARD_HEIGHT); + return QRectF(0, 0, CardDimensions::WIDTH_F, CardDimensions::HEIGHT_F); } QPainterPath PileZone::shape() const { QPainterPath shape; - qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CARD_WIDTH : 0.0; + qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CardDimensions::WIDTH_F : 0.0; shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius); return shape; } @@ -52,9 +52,9 @@ void PileZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*optio getLogic()->getCards().at(0)->paintPicture(painter, getLogic()->getCards().at(0)->getTranslatedSize(painter), 90); - painter->translate((float)CARD_WIDTH / 2, (float)CARD_HEIGHT / 2); + painter->translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F); painter->rotate(-90); - painter->translate((float)-CARD_WIDTH / 2, (float)-CARD_HEIGHT / 2); + painter->translate(-CardDimensions::WIDTH_HALF_F, -CardDimensions::HEIGHT_HALF_F); paintNumberEllipse(getLogic()->getCards().size(), 28, Qt::white, -1, -1, painter); } diff --git a/cockatrice/src/game/zones/table_zone.cpp b/cockatrice/src/game/zones/table_zone.cpp index 33c867c43..a020e4255 100644 --- a/cockatrice/src/game/zones/table_zone.cpp +++ b/cockatrice/src/game/zones/table_zone.cpp @@ -31,7 +31,7 @@ TableZone::TableZone(TableZoneLogic *_logic, QGraphicsItem *parent) : SelectZone updateBg(); - height = MARGIN_TOP + MARGIN_BOTTOM + TABLEROWS * CARD_HEIGHT + (TABLEROWS - 1) * PADDING_Y; + height = MARGIN_TOP + MARGIN_BOTTOM + TABLEROWS * CardDimensions::HEIGHT + (TABLEROWS - 1) * PADDING_Y; width = MIN_WIDTH; currentMinimumWidth = width; @@ -106,7 +106,7 @@ void TableZone::paintLandDivider(QPainter *painter) { // Place the line 2 grid heights down then back it off just enough to allow // some space between a 3-card stack and the land area. - qreal separatorY = MARGIN_TOP + 2 * (CARD_HEIGHT + PADDING_Y) - STACKED_CARD_OFFSET_Y / 2; + qreal separatorY = MARGIN_TOP + 2 * (CardDimensions::HEIGHT + PADDING_Y) - STACKED_CARD_OFFSET_Y / 2; if (isInverted()) separatorY = height - separatorY; painter->setPen(QColor(255, 255, 255, 40)); @@ -232,7 +232,7 @@ void TableZone::resizeToContents() // Minimum width is the rightmost card position plus enough room for // another card with padding, then margin. - currentMinimumWidth = xMax + (2 * CARD_WIDTH) + PADDING_X + MARGIN_RIGHT; + currentMinimumWidth = xMax + (2 * CardDimensions::WIDTH) + PADDING_X + MARGIN_RIGHT; if (currentMinimumWidth < MIN_WIDTH) currentMinimumWidth = MIN_WIDTH; @@ -282,10 +282,10 @@ void TableZone::computeCardStackWidths() const int key = getCardStackMapKey(gridPoint.x() / 3, gridPoint.y()); const int stackCount = cardStackCount.value(key, 0); if (stackCount == 1) - cardStackWidth.insert(key, CARD_WIDTH + getLogic()->getCards()[i]->getAttachedCards().size() * - STACKED_CARD_OFFSET_X); + cardStackWidth.insert(key, CardDimensions::WIDTH + getLogic()->getCards()[i]->getAttachedCards().size() * + STACKED_CARD_OFFSET_X); else - cardStackWidth.insert(key, CARD_WIDTH + (stackCount - 1) * STACKED_CARD_OFFSET_X); + cardStackWidth.insert(key, CardDimensions::WIDTH + (stackCount - 1) * STACKED_CARD_OFFSET_X); } } @@ -299,7 +299,7 @@ QPointF TableZone::mapFromGrid(QPoint gridPoint) const // Add in width of card stack plus padding for each column for (int i = 0; i < gridPoint.x() / 3; ++i) { const int key = getCardStackMapKey(i, gridPoint.y()); - x += cardStackWidth.value(key, CARD_WIDTH) + PADDING_X; + x += cardStackWidth.value(key, CardDimensions::WIDTH) + PADDING_X; } if (isInverted()) @@ -310,7 +310,7 @@ QPointF TableZone::mapFromGrid(QPoint gridPoint) const // Add in card size and padding for each row for (int i = 0; i < gridPoint.y(); ++i) - y += CARD_HEIGHT + PADDING_Y; + y += CardDimensions::HEIGHT + PADDING_Y; return QPointF(x, y); } @@ -324,7 +324,7 @@ QPoint TableZone::mapToGrid(const QPointF &mapPoint) const int y = mapPoint.y() - MARGIN_TOP; // Below calculation effectively rounds to the nearest grid point. - const int gridPointHeight = CARD_HEIGHT + PADDING_Y; + const int gridPointHeight = CardDimensions::HEIGHT + PADDING_Y; int gridPointY = (y + PADDING_Y / 2) / gridPointHeight; gridPointY = clampValidTableRow(gridPointY); @@ -340,7 +340,7 @@ QPoint TableZone::mapToGrid(const QPointF &mapPoint) const // Maximum value is a card width from the right margin, referenced to the // grid area. - const int xMax = width - MARGIN_LEFT - MARGIN_RIGHT - CARD_WIDTH; + const int xMax = width - MARGIN_LEFT - MARGIN_RIGHT - CardDimensions::WIDTH; int xStack = 0; int xNextStack = 0; @@ -348,7 +348,7 @@ QPoint TableZone::mapToGrid(const QPointF &mapPoint) const while ((xNextStack <= x) && (xNextStack <= xMax)) { xStack = xNextStack; const int key = getCardStackMapKey(nextStackCol, gridPointY); - xNextStack += cardStackWidth.value(key, CARD_WIDTH) + PADDING_X; + xNextStack += cardStackWidth.value(key, CardDimensions::WIDTH) + PADDING_X; nextStackCol++; } int stackCol = qMax(nextStackCol - 1, 0); diff --git a/cockatrice/src/game/zones/table_zone.h b/cockatrice/src/game/zones/table_zone.h index 3b353e76c..61eb48d7b 100644 --- a/cockatrice/src/game/zones/table_zone.h +++ b/cockatrice/src/game/zones/table_zone.h @@ -41,12 +41,12 @@ private: /* Minimum width of the table zone including margins. */ - static const int MIN_WIDTH = MARGIN_LEFT + (5 * CARD_WIDTH) + MARGIN_RIGHT; + static const int MIN_WIDTH = MARGIN_LEFT + (5 * CardDimensions::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_X = CardDimensions::WIDTH / 3; static const int STACKED_CARD_OFFSET_Y = PADDING_Y / 3; /* diff --git a/cockatrice/src/game/zones/view_zone.cpp b/cockatrice/src/game/zones/view_zone.cpp index 348ed6e87..d2fd1e971 100644 --- a/cockatrice/src/game/zones/view_zone.cpp +++ b/cockatrice/src/game/zones/view_zone.cpp @@ -118,7 +118,9 @@ void ZoneViewZone::zoneDumpReceived(const Response &r) qobject_cast(getLogic())->updateCardIds(ZoneViewZoneLogic::INITIALIZE); reorganizeCards(); - emit getLogic()->cardCountChanged(); + // clang-format off + emit getLogic()->cardCountChanged(); // emit keyword causes spurious spacing around -> + // clang-format on } // Because of boundingRect(), this function must not be called before the zone was added to a scene. @@ -166,8 +168,8 @@ void ZoneViewZone::reorganizeCards() // determine bounding rect qreal aleft = 0; qreal atop = 0; - qreal awidth = gridSize.cols * CARD_WIDTH + (CARD_WIDTH / 2) + HORIZONTAL_PADDING; - qreal aheight = (gridSize.rows * CARD_HEIGHT) / 3 + CARD_HEIGHT * 1.3; + qreal awidth = gridSize.cols * CardDimensions::WIDTH_F + CardDimensions::WIDTH_HALF_F + HORIZONTAL_PADDING; + qreal aheight = (gridSize.rows * CardDimensions::HEIGHT_F) / 3 + CardDimensions::HEIGHT_F * 1.3; optimumRect = QRectF(aleft, atop, awidth, aheight); updateGeometry(); @@ -210,8 +212,8 @@ ZoneViewZone::GridSize ZoneViewZone::positionCardsForDisplay(CardList &cards, Ca } lastColumnProp = columnProp; - qreal x = col * CARD_WIDTH; - qreal y = row * CARD_HEIGHT / 3; + qreal x = col * CardDimensions::WIDTH_F; + qreal y = row * CardDimensions::HEIGHT_F / 3; c->setPos(HORIZONTAL_PADDING + x, VERTICAL_PADDING + y); c->setRealZValue(i); longestRow = qMax(row, longestRow); @@ -238,8 +240,8 @@ ZoneViewZone::GridSize ZoneViewZone::positionCardsForDisplay(CardList &cards, Ca for (int i = 0; i < cardCount; i++) { CardItem *c = cards.at(i); - qreal x = (i / rows) * CARD_WIDTH; - qreal y = (i % rows) * CARD_HEIGHT / 3; + qreal x = (i / rows) * CardDimensions::WIDTH_F; + qreal y = (i % rows) * CardDimensions::HEIGHT_F / 3; c->setPos(HORIZONTAL_PADDING + x, VERTICAL_PADDING + y); c->setRealZValue(i); } diff --git a/cockatrice/src/game/zones/view_zone_widget.cpp b/cockatrice/src/game/zones/view_zone_widget.cpp index 0ad3b10f1..23d7d6a19 100644 --- a/cockatrice/src/game/zones/view_zone_widget.cpp +++ b/cockatrice/src/game/zones/view_zone_widget.cpp @@ -458,7 +458,7 @@ void ZoneViewWidget::resizeScrollbar(const qreal newZoneHeight) */ static qreal rowsToHeight(int rows) { - const qreal cardsHeight = (rows + 1) * (CARD_HEIGHT / 3); + const qreal cardsHeight = (rows + 1) * (CardDimensions::HEIGHT_F / 3); return cardsHeight + 5; // +5 padding to make the cutoff look nicer } @@ -574,4 +574,4 @@ void ZoneViewWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) if (event->pos().y() <= 0) { expandWindow(); } -} \ No newline at end of file +} diff --git a/cockatrice/src/interface/widgets/cards/card_info_display_widget.cpp b/cockatrice/src/interface/widgets/cards/card_info_display_widget.cpp index f8b581e33..4930fbbfd 100644 --- a/cockatrice/src/interface/widgets/cards/card_info_display_widget.cpp +++ b/cockatrice/src/interface/widgets/cards/card_info_display_widget.cpp @@ -10,7 +10,7 @@ #include CardInfoDisplayWidget::CardInfoDisplayWidget(const CardRef &cardRef, QWidget *parent, Qt::WindowFlags flags) - : QFrame(parent, flags), aspectRatio((qreal)CARD_HEIGHT / (qreal)CARD_WIDTH) + : QFrame(parent, flags), aspectRatio(CardDimensions::HEIGHT_F / CardDimensions::WIDTH_F) { setContentsMargins(3, 3, 3, 3); pic = new CardInfoPictureWidget(); From dead99363909f1b010ce4d468dc311d0a84218a1 Mon Sep 17 00:00:00 2001 From: RickyRister <42636155+RickyRister@users.noreply.github.com> Date: Fri, 6 Mar 2026 10:39:04 -0800 Subject: [PATCH 06/20] [DeckList] Refactor load from plaintext to take normalizer as param (#6664) * [DeckList] Refactor load from plaintext to take normalizer as param * update usages * weaken unit test * weaken unit test more * revert unit test * move CardNameNormalizer to libcockatrice_card * update unit test * formatting --- .../parsers/interface_json_deck_parser.h | 7 +-- .../src/interface/deck_loader/deck_loader.cpp | 5 ++- .../dialogs/dlg_load_deck_from_clipboard.cpp | 3 +- .../dialogs/dlg_load_deck_from_website.cpp | 3 +- .../dialogs/dlg_load_deck_from_website.h | 1 + ...idekt_api_response_deck_display_widget.cpp | 5 +-- .../average_deck/edhrec_deck_api_response.cpp | 5 +-- libcockatrice_card/CMakeLists.txt | 2 + .../card/import/card_name_normalizer.cpp | 45 +++++++++++++++++++ .../card/import/card_name_normalizer.h | 15 +++++++ .../libcockatrice/deck_list/deck_list.cpp | 43 ++++-------------- .../libcockatrice/deck_list/deck_list.h | 6 ++- tests/loading_from_clipboard/CMakeLists.txt | 3 +- .../clipboard_testing.cpp | 3 +- 14 files changed, 94 insertions(+), 52 deletions(-) create mode 100644 libcockatrice_card/libcockatrice/card/import/card_name_normalizer.cpp create mode 100644 libcockatrice_card/libcockatrice/card/import/card_name_normalizer.h diff --git a/cockatrice/src/client/network/parsers/interface_json_deck_parser.h b/cockatrice/src/client/network/parsers/interface_json_deck_parser.h index e19e4f4e4..1818aa35c 100644 --- a/cockatrice/src/client/network/parsers/interface_json_deck_parser.h +++ b/cockatrice/src/client/network/parsers/interface_json_deck_parser.h @@ -8,10 +8,11 @@ #define INTERFACE_JSON_DECK_PARSER_H #include "../../../interface/deck_loader/card_node_function.h" -#include "../../../interface/deck_loader/deck_loader.h" #include #include +#include +#include class IJsonDeckParser { @@ -49,7 +50,7 @@ public: outStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber << '\n'; } - deckList.loadFromStream_Plain(outStream, false); + deckList.loadFromStream_Plain(outStream, false, CardNameNormalizer()); deckList.forEachCard(CardNodeFunction::ResolveProviderId()); return deckList; @@ -96,7 +97,7 @@ public: outStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber << '\n'; } - deckList.loadFromStream_Plain(outStream, false); + deckList.loadFromStream_Plain(outStream, false, CardNameNormalizer()); deckList.forEachCard(CardNodeFunction::ResolveProviderId()); QJsonObject commandersObj = obj.value("commanders").toObject(); diff --git a/cockatrice/src/interface/deck_loader/deck_loader.cpp b/cockatrice/src/interface/deck_loader/deck_loader.cpp index 3481e245b..d71dca24a 100644 --- a/cockatrice/src/interface/deck_loader/deck_loader.cpp +++ b/cockatrice/src/interface/deck_loader/deck_loader.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -42,7 +43,7 @@ DeckLoader::loadFromFile(const QString &fileName, DeckFileFormat::Format fmt, bo DeckList deckList; switch (fmt) { case DeckFileFormat::PlainText: - result = deckList.loadFromFile_Plain(&file); + result = deckList.loadFromFile_Plain(&file, CardNameNormalizer()); break; case DeckFileFormat::Cockatrice: { result = deckList.loadFromFile_Native(&file); @@ -50,7 +51,7 @@ DeckLoader::loadFromFile(const QString &fileName, DeckFileFormat::Format fmt, bo qCInfo(DeckLoaderLog) << "Failed to load " << fileName << "as cockatrice format; retrying as plain format"; file.seek(0); - result = deckList.loadFromFile_Plain(&file); + result = deckList.loadFromFile_Plain(&file, CardNameNormalizer()); fmt = DeckFileFormat::PlainText; } break; diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_load_deck_from_clipboard.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_load_deck_from_clipboard.cpp index b72130c81..9ceb35d78 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_load_deck_from_clipboard.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_load_deck_from_clipboard.cpp @@ -14,6 +14,7 @@ #include #include #include +#include /** * Creates the main layout and connects the signals that are common to all versions of this window @@ -81,7 +82,7 @@ bool AbstractDlgDeckTextEdit::loadIntoDeck(DeckList &deckList) const QTextStream stream(&buffer); - if (deckList.loadFromStream_Plain(stream, true)) { + if (deckList.loadFromStream_Plain(stream, true, CardNameNormalizer())) { if (loadSetNameAndNumberCheckBox->isChecked()) { deckList.forEachCard(CardNodeFunction::ResolveProviderId()); } else { diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_load_deck_from_website.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_load_deck_from_website.cpp index da4135246..ba00873d9 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_load_deck_from_website.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_load_deck_from_website.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include DlgLoadDeckFromWebsite::DlgLoadDeckFromWebsite(QWidget *parent) : QDialog(parent) @@ -99,7 +100,7 @@ void DlgLoadDeckFromWebsite::accept() // Parse the plain text deck here DeckList deckList; QTextStream stream(&deckText); - deckList.loadFromStream_Plain(stream, false); + deckList.loadFromStream_Plain(stream, false, CardNameNormalizer()); deckList.forEachCard(CardNodeFunction::ResolveProviderId()); deck = deckList; diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_load_deck_from_website.h b/cockatrice/src/interface/widgets/dialogs/dlg_load_deck_from_website.h index fe6f0a7e9..1ac98d206 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_load_deck_from_website.h +++ b/cockatrice/src/interface/widgets/dialogs/dlg_load_deck_from_website.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp b/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp index f40b9094f..8b17cd49e 100644 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp +++ b/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp @@ -2,7 +2,6 @@ #include "../../../../../deck_loader/card_node_function.h" #include "../../../../../deck_loader/deck_loader.h" -#include "../../../../cards/card_info_picture_with_text_overlay_widget.h" #include "../../../../cards/card_size_widget.h" #include "../../../../cards/deck_card_zone_display_widget.h" #include "../../../../visual_deck_editor/visual_deck_display_options_widget.h" @@ -10,7 +9,7 @@ #include "../api_response/deck/archidekt_api_response_deck.h" #include -#include +#include ArchidektApiResponseDeckDisplayWidget::ArchidektApiResponseDeckDisplayWidget(QWidget *parent, ArchidektApiResponseDeck _response, @@ -80,7 +79,7 @@ ArchidektApiResponseDeckDisplayWidget::ArchidektApiResponseDeckDisplayWidget(QWi connect(model, &DeckListModel::modelReset, this, &ArchidektApiResponseDeckDisplayWidget::decklistModelReset); auto decklist = QSharedPointer(new DeckList); - decklist->loadFromStream_Plain(deckStream, false); + decklist->loadFromStream_Plain(deckStream, false, CardNameNormalizer()); model->setDeckList(decklist); model->forEachCard(CardNodeFunction::ResolveProviderId()); diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.cpp index a744a9b14..1cb070c30 100644 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.cpp +++ b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.cpp @@ -1,11 +1,10 @@ #include "edhrec_deck_api_response.h" -#include "../../../../../../deck_loader/deck_loader.h" - #include #include #include #include +#include void EdhrecDeckApiResponse::fromJson(const QJsonArray &json) { @@ -15,7 +14,7 @@ void EdhrecDeckApiResponse::fromJson(const QJsonArray &json) } QTextStream stream(&deckList); - deck.loadFromStream_Plain(stream, true); + deck.loadFromStream_Plain(stream, true, CardNameNormalizer()); } void EdhrecDeckApiResponse::debugPrint() const diff --git a/libcockatrice_card/CMakeLists.txt b/libcockatrice_card/CMakeLists.txt index f516cde00..dd3799e33 100644 --- a/libcockatrice_card/CMakeLists.txt +++ b/libcockatrice_card/CMakeLists.txt @@ -12,6 +12,7 @@ set(HEADERS libcockatrice/card/database/parser/card_database_parser.h libcockatrice/card/database/parser/cockatrice_xml_3.h libcockatrice/card/database/parser/cockatrice_xml_4.h + libcockatrice/card/import/card_name_normalizer.h libcockatrice/card/printing/exact_card.h libcockatrice/card/printing/printing_info.h libcockatrice/card/set/card_set.h @@ -36,6 +37,7 @@ add_library( libcockatrice/card/database/parser/card_database_parser.cpp libcockatrice/card/database/parser/cockatrice_xml_3.cpp libcockatrice/card/database/parser/cockatrice_xml_4.cpp + libcockatrice/card/import/card_name_normalizer.cpp libcockatrice/card/printing/exact_card.cpp libcockatrice/card/printing/printing_info.cpp libcockatrice/card/relation/card_relation.cpp diff --git a/libcockatrice_card/libcockatrice/card/import/card_name_normalizer.cpp b/libcockatrice_card/libcockatrice/card/import/card_name_normalizer.cpp new file mode 100644 index 000000000..2349dc3e8 --- /dev/null +++ b/libcockatrice_card/libcockatrice/card/import/card_name_normalizer.cpp @@ -0,0 +1,45 @@ +#include "card_name_normalizer.h" + +#include + +QString CardNameNormalizer::operator()(const QString &cardNameString) const +{ + QString cardName = cardNameString; + + // Regex for advanced card parsing + static const QRegularExpression reSplitCard(R"( ?\/\/ ?)"); + static const QRegularExpression reBrace(R"( ?[\[\{][^\]\}]*[\]\}] ?)"); // not nested + static const QRegularExpression reRoundBrace(R"(^\([^\)]*\) ?)"); // () are only matched at start of string + static const QRegularExpression reDigitBrace(R"( ?\(\d*\) ?)"); // () are matched if containing digits + static const QRegularExpression reBraceDigit( + R"( ?\([\dA-Z]+\) *\d+$)"); // () are matched if containing setcode then a number + static const QRegularExpression reDoubleFacedMarker(R"( ?\(Transform\) ?)"); + + static const QHash differences{{QRegularExpression("’"), "'"}, + {QRegularExpression("Æ"), "Ae"}, + {QRegularExpression("æ"), "ae"}, + {QRegularExpression(" ?[|/]+ ?"), " // "}}; + + // Handle advanced card types + if (cardName.contains(reSplitCard)) { + cardName = cardName.split(reSplitCard).join(" // "); + } + + if (cardName.contains(reDoubleFacedMarker)) { + QStringList faces = cardName.split(reDoubleFacedMarker); + cardName = faces.first().trimmed(); + } + + // Remove unnecessary characters + cardName.remove(reBrace); + cardName.remove(reRoundBrace); // I'll be entirely honest here, these are split to accommodate just three cards + cardName.remove(reDigitBrace); // from un-sets that have a word in between round braces at the end + cardName.remove(reBraceDigit); // very specific format with the set code in () and collectors number after + + // Normalize characters + for (auto diff = differences.constBegin(); diff != differences.constEnd(); ++diff) { + cardName.replace(diff.key(), diff.value()); + } + + return cardName; +} \ No newline at end of file diff --git a/libcockatrice_card/libcockatrice/card/import/card_name_normalizer.h b/libcockatrice_card/libcockatrice/card/import/card_name_normalizer.h new file mode 100644 index 000000000..716e7da80 --- /dev/null +++ b/libcockatrice_card/libcockatrice/card/import/card_name_normalizer.h @@ -0,0 +1,15 @@ +#ifndef COCKATRICE_CARD_NAME_NORMALIZER_H +#define COCKATRICE_CARD_NAME_NORMALIZER_H + +#include + +/** + * Functor that normalizes the raw card name parsed during a plaintext deck import into the card name that Cockatrice + * uses. + */ +struct CardNameNormalizer +{ + QString operator()(const QString &cardNameString) const; +}; + +#endif // COCKATRICE_CARD_NAME_NORMALIZER_H diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.cpp b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.cpp index 3d1070f15..e3e7b41c0 100644 --- a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.cpp +++ b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.cpp @@ -199,9 +199,12 @@ bool DeckList::saveToFile_Native(QIODevice *device) const * * @param in The text to load * @param preserveMetadata If true, don't clear the existing metadata + * @param cardNameNormalizer Function that takes the parsed card name string in the text and * @return False if the input was empty, true otherwise. */ -bool DeckList::loadFromStream_Plain(QTextStream &in, bool preserveMetadata) +bool DeckList::loadFromStream_Plain(QTextStream &in, + bool preserveMetadata, + const std::function &cardNameNormalizer) { const QRegularExpression reCardLine(R"(^\s*[\w\[\(\{].*$)", QRegularExpression::UseUnicodePropertiesOption); const QRegularExpression reEmpty("^\\s*$"); @@ -213,23 +216,11 @@ bool DeckList::loadFromStream_Plain(QTextStream &in, bool preserveMetadata) // Regex for advanced card parsing const QRegularExpression reMultiplier(R"(^[xX\(\[]*(\d+)[xX\*\)\]]* ?(.+))"); - const QRegularExpression reSplitCard(R"( ?\/\/ ?)"); - const QRegularExpression reBrace(R"( ?[\[\{][^\]\}]*[\]\}] ?)"); // not nested - const QRegularExpression reRoundBrace(R"(^\([^\)]*\) ?)"); // () are only matched at start of string - const QRegularExpression reDigitBrace(R"( ?\(\d*\) ?)"); // () are matched if containing digits - const QRegularExpression reBraceDigit( - R"( ?\([\dA-Z]+\) *\d+$)"); // () are matched if containing setcode then a number - const QRegularExpression reDoubleFacedMarker(R"( ?\(Transform\) ?)"); // Regex for extracting set code and collector number with attached symbols const QRegularExpression reHyphenFormat(R"(\((\w{3,})\)\s+(\w{3,})-(\d+[^\w\s]*))"); const QRegularExpression reRegularFormat(R"(\((\w{3,})\)\s+(\d+[^\w\s]*))"); - const QHash differences{{QRegularExpression("’"), QString("'")}, - {QRegularExpression("Æ"), QString("Ae")}, - {QRegularExpression("æ"), QString("ae")}, - {QRegularExpression(" ?[|/]+ ?"), QString(" // ")}}; - cleanList(preserveMetadata); auto inputs = in.readAll().trimmed().split('\n'); @@ -355,26 +346,8 @@ bool DeckList::loadFromStream_Plain(QTextStream &in, bool preserveMetadata) cardName = match.captured(2); } - // Handle advanced card types - if (cardName.contains(reSplitCard)) { - cardName = cardName.split(reSplitCard).join(" // "); - } - - if (cardName.contains(reDoubleFacedMarker)) { - QStringList faces = cardName.split(reDoubleFacedMarker); - cardName = faces.first().trimmed(); - } - - // Remove unnecessary characters - cardName.remove(reBrace); - cardName.remove(reRoundBrace); // I'll be entirely honest here, these are split to accommodate just three cards - cardName.remove(reDigitBrace); // from un-sets that have a word in between round braces at the end - cardName.remove(reBraceDigit); // very specific format with the set code in () and collectors number after - - // Normalize names - for (auto diff = differences.constBegin(); diff != differences.constEnd(); ++diff) { - cardName.replace(diff.key(), diff.value()); - } + // Normalize the card name + cardName = cardNameNormalizer(cardName); // Determine the zone (mainboard/sideboard) QString zoneName = sideboard ? DECK_ZONE_SIDE : DECK_ZONE_MAIN; @@ -387,10 +360,10 @@ bool DeckList::loadFromStream_Plain(QTextStream &in, bool preserveMetadata) return true; } -bool DeckList::loadFromFile_Plain(QIODevice *device) +bool DeckList::loadFromFile_Plain(QIODevice *device, const std::function &cardNameNormalizer) { QTextStream in(device); - return loadFromStream_Plain(in, false); + return loadFromStream_Plain(in, false, cardNameNormalizer); } bool DeckList::saveToStream_Plain(QTextStream &stream, bool prefixSideboardCards, bool slashTappedOutSplitCards) const diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.h b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.h index 91e56fc9f..a96adeb38 100644 --- a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.h +++ b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.h @@ -206,8 +206,10 @@ public: /// @name Serialization (Plain text) ///@{ - bool loadFromStream_Plain(QTextStream &stream, bool preserveMetadata); - bool loadFromFile_Plain(QIODevice *device); + bool loadFromStream_Plain(QTextStream &stream, + bool preserveMetadata, + const std::function &cardNameNormalizer); + bool loadFromFile_Plain(QIODevice *device, const std::function &cardNameNormalizer); bool saveToStream_Plain(QTextStream &stream, bool prefixSideboardCards, bool slashTappedOutSplitCards) const; bool saveToFile_Plain(QIODevice *device, bool prefixSideboardCards = true, bool slashTappedOutSplitCards = false) const; diff --git a/tests/loading_from_clipboard/CMakeLists.txt b/tests/loading_from_clipboard/CMakeLists.txt index 40e85c66e..eecaafcbb 100644 --- a/tests/loading_from_clipboard/CMakeLists.txt +++ b/tests/loading_from_clipboard/CMakeLists.txt @@ -10,6 +10,7 @@ set(TEST_QT_MODULES ${COCKATRICE_QT_VERSION_NAME}::Concurrent ${COCKATRICE_QT_VE ) target_link_libraries( - loading_from_clipboard_test libcockatrice_deck_list Threads::Threads ${GTEST_BOTH_LIBRARIES} ${TEST_QT_MODULES} + loading_from_clipboard_test libcockatrice_deck_list libcockatrice_card Threads::Threads ${GTEST_BOTH_LIBRARIES} + ${TEST_QT_MODULES} ) add_test(NAME loading_from_clipboard_test COMMAND loading_from_clipboard_test) diff --git a/tests/loading_from_clipboard/clipboard_testing.cpp b/tests/loading_from_clipboard/clipboard_testing.cpp index 29535c1dc..a9977b800 100644 --- a/tests/loading_from_clipboard/clipboard_testing.cpp +++ b/tests/loading_from_clipboard/clipboard_testing.cpp @@ -1,6 +1,7 @@ #include "clipboard_testing.h" #include +#include #include DeckList getDeckList(const QString &clipboard) @@ -8,7 +9,7 @@ DeckList getDeckList(const QString &clipboard) DeckList deckList; QString cp(clipboard); QTextStream stream(&cp); // text stream requires local copy - deckList.loadFromStream_Plain(stream, false); + deckList.loadFromStream_Plain(stream, false, CardNameNormalizer()); return deckList; } From 2f10634ca2478521f02a85dc4bc4cfe010940077 Mon Sep 17 00:00:00 2001 From: RickyRister <42636155+RickyRister@users.noreply.github.com> Date: Fri, 6 Mar 2026 11:48:17 -0800 Subject: [PATCH 07/20] [DeckList] Fix double-faced cards not importing correctly (#6665) * [DeckList] Fix double-faced cards not importing correctly * make tests compile --- .../card/import/card_name_normalizer.cpp | 21 +++++++++++++++++++ tests/loading_from_clipboard/CMakeLists.txt | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/libcockatrice_card/libcockatrice/card/import/card_name_normalizer.cpp b/libcockatrice_card/libcockatrice/card/import/card_name_normalizer.cpp index 2349dc3e8..91ebd6647 100644 --- a/libcockatrice_card/libcockatrice/card/import/card_name_normalizer.cpp +++ b/libcockatrice_card/libcockatrice/card/import/card_name_normalizer.cpp @@ -1,7 +1,25 @@ #include "card_name_normalizer.h" +#include "../database/card_database_manager.h" +#include "../printing/exact_card.h" + #include +/** + * @brief Resolves the complete display name of a card. + * @param cardName Base name. + * @return Full display name, or the cardName unchanged if a display name is not found. + */ +static QString getCompleteCardName(const QString &cardName) +{ + ExactCard temp = CardDatabaseManager::query()->guessCard({cardName}); + if (temp) { + return temp.getName(); + } + + return cardName; +} + QString CardNameNormalizer::operator()(const QString &cardNameString) const { QString cardName = cardNameString; @@ -41,5 +59,8 @@ QString CardNameNormalizer::operator()(const QString &cardNameString) const cardName.replace(diff.key(), diff.value()); } + // Resolve complete card name + cardName = getCompleteCardName(cardName); + return cardName; } \ No newline at end of file diff --git a/tests/loading_from_clipboard/CMakeLists.txt b/tests/loading_from_clipboard/CMakeLists.txt index eecaafcbb..85133a8e8 100644 --- a/tests/loading_from_clipboard/CMakeLists.txt +++ b/tests/loading_from_clipboard/CMakeLists.txt @@ -1,5 +1,5 @@ add_definitions("-DCARDDB_DATADIR=\"${CMAKE_CURRENT_SOURCE_DIR}/data/\"") -add_executable(loading_from_clipboard_test clipboard_testing.cpp loading_from_clipboard_test.cpp) +add_executable(loading_from_clipboard_test ${VERSION_STRING_CPP} clipboard_testing.cpp loading_from_clipboard_test.cpp) if(NOT GTEST_FOUND) add_dependencies(loading_from_clipboard_test gtest) From f15b70e4aef3994ab2fa9e371ee4cbbcb9b41a15 Mon Sep 17 00:00:00 2001 From: tooomm Date: Sun, 8 Mar 2026 17:53:16 +0100 Subject: [PATCH 08/20] Use new attest action (#6671) --- .github/workflows/desktop-build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml index e95898097..2cd25fc32 100644 --- a/.github/workflows/desktop-build.yml +++ b/.github/workflows/desktop-build.yml @@ -232,7 +232,7 @@ jobs: - name: Attest binary provenance id: attestation if: steps.upload_release.outcome == 'success' - uses: actions/attest-build-provenance@v4 + uses: actions/attest@v4 with: subject-name: ${{steps.build.outputs.name}} subject-path: ${{steps.build.outputs.path}} @@ -530,7 +530,7 @@ jobs: - name: Attest binary provenance id: attestation if: steps.upload_release.outcome == 'success' - uses: actions/attest-build-provenance@v4 + uses: actions/attest@v4 with: subject-name: ${{steps.build.outputs.name}} subject-path: ${{steps.build.outputs.path}} From c375cdbb1ae84faedc142eadf11ca5a63332bdfe Mon Sep 17 00:00:00 2001 From: tooomm Date: Sun, 8 Mar 2026 18:03:01 +0100 Subject: [PATCH 09/20] CI: Upload artifact files directly (#6654) * Upload artifact files directly * match pdbs name * Update name variable --- .ci/name_build.sh | 10 +++++----- .github/workflows/desktop-build.yml | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.ci/name_build.sh b/.ci/name_build.sh index 060f8a68e..7b964e21c 100755 --- a/.ci/name_build.sh +++ b/.ci/name_build.sh @@ -35,15 +35,15 @@ if ! cd "$path"; then fi # set filename -name="${file%.*}" # remove all after last . -new_name="$name$SUFFIX." +name="${file%.*}" # remove file extension +new_name="$name$SUFFIX" if [[ $MAKE_ZIP ]]; then - filename="${new_name}zip" + filename="${new_name}.zip" echo "creating zip '$filename' from '$file'" zip "$filename" "$file" else extension="${file##*.}" # remove all before last . - filename="$new_name$extension" + filename="$new_name.$extension" echo "renaming '$file' to '$filename'" mv "$file" "$filename" fi @@ -52,4 +52,4 @@ cd "$oldpwd" relative_path="$path/$filename" ls -l "$relative_path" echo "path=$relative_path" >>"$GITHUB_OUTPUT" -echo "name=$filename" >>"$GITHUB_OUTPUT" +echo "name=$new_name" >>"$GITHUB_OUTPUT" diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml index 2cd25fc32..bc49db2da 100644 --- a/.github/workflows/desktop-build.yml +++ b/.github/workflows/desktop-build.yml @@ -214,8 +214,8 @@ jobs: if: matrix.package != 'skip' uses: actions/upload-artifact@v7 with: - name: ${{matrix.distro}}${{matrix.version}}-package path: ${{steps.build.outputs.path}} + archive: false if-no-files-found: error - name: Upload to release @@ -501,15 +501,15 @@ jobs: if: matrix.make_package uses: actions/upload-artifact@v7 with: - name: ${{matrix.artifact_name}} path: ${{steps.build.outputs.path}} + archive: false if-no-files-found: error - name: Upload PDBs (Program Databases) if: matrix.os == 'Windows' uses: actions/upload-artifact@v7 with: - name: Windows${{matrix.target}}-PDBs + name: ${{steps.build.outputs.name}}-PDBs path: | build/cockatrice/Release/*.pdb build/oracle/Release/*.pdb From 4606fcdbd59ed762b8cedb8472cfda771b90642b Mon Sep 17 00:00:00 2001 From: tooomm Date: Sun, 8 Mar 2026 23:27:15 +0100 Subject: [PATCH 10/20] Add description for code docs (#6679) --- .github/ISSUE_TEMPLATE/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index f9abf643d..02bdc148a 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -9,4 +9,4 @@ contact_links: about: For more information and guidance check our Translation FAQ on our wiki! - name: 📖 Code Documentation url: https://cockatrice.github.io/docs/ - about: + about: Helpful source focusing on developers, but there are also references for users! From 852429f24861ae6381dd4b18d6576e74621b980d Mon Sep 17 00:00:00 2001 From: tooomm Date: Sun, 8 Mar 2026 23:48:30 +0100 Subject: [PATCH 11/20] remove unused zip command (#6676) --- .ci/name_build.sh | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/.ci/name_build.sh b/.ci/name_build.sh index 7b964e21c..b111aded6 100755 --- a/.ci/name_build.sh +++ b/.ci/name_build.sh @@ -2,7 +2,6 @@ # used by the ci to rename build artifacts # renames the file to [original name][SUFFIX].[original extension] # where SUFFIX is either available in the environment or as the first arg -# if MAKE_ZIP is set instead a zip is made # expected to be run in the build directory unless BUILD_DIR is set # adds output to GITHUB_OUTPUT builddir="${BUILD_DIR:=.}" @@ -22,8 +21,8 @@ set -e # find file found="$(find "$builddir" -maxdepth 1 -type f -name "$findrx" -print -quit)" -path="${found%/*}" # remove all after last / -file="${found##*/}" # remove all before last / +path="${found%/*}" # remove all including first "/" from right side +file="${found##*/}" # remove all including last "/" from left side if [[ ! $file ]]; then echo "::error file=$0::could not find package" exit 1 @@ -35,18 +34,12 @@ if ! cd "$path"; then fi # set filename -name="${file%.*}" # remove file extension +name="${file%.*}" # remove all including first "." from right side new_name="$name$SUFFIX" -if [[ $MAKE_ZIP ]]; then - filename="${new_name}.zip" - echo "creating zip '$filename' from '$file'" - zip "$filename" "$file" -else - extension="${file##*.}" # remove all before last . - filename="$new_name.$extension" - echo "renaming '$file' to '$filename'" - mv "$file" "$filename" -fi +extension="${file##*.}" # remove all including last "." from left side +filename="$new_name.$extension" +echo "renaming '$file' to '$filename'" +mv "$file" "$filename" cd "$oldpwd" relative_path="$path/$filename" From fd293444c5a1700638fbbdb3b70d9f9677fd1821 Mon Sep 17 00:00:00 2001 From: tooomm Date: Sun, 8 Mar 2026 23:50:33 +0100 Subject: [PATCH 12/20] tweaks (#6674) --- .github/workflows/docker-release.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml index 1846766bf..2fe646374 100644 --- a/.github/workflows/docker-release.yml +++ b/.github/workflows/docker-release.yml @@ -62,5 +62,6 @@ jobs: push: ${{ github.ref_type == 'tag' }} tags: ${{ steps.metadata.outputs.tags }} labels: ${{ steps.metadata.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max + annotations: ${{ steps.metadata.outputs.annotations }} + cache-from: type=gha,scope=servatrice + cache-to: type=gha,mode=max,scope=servatrice From 15a1d5440bc8aa794a2ae157fbd0e9b624ca3de4 Mon Sep 17 00:00:00 2001 From: RickyRister <42636155+RickyRister@users.noreply.github.com> Date: Sun, 8 Mar 2026 15:50:54 -0700 Subject: [PATCH 13/20] [DeckEditor] Fix undo/redo resetting deck sorting (#6673) --- .../src/interface/widgets/deck_editor/deck_state_manager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cockatrice/src/interface/widgets/deck_editor/deck_state_manager.cpp b/cockatrice/src/interface/widgets/deck_editor/deck_state_manager.cpp index 8afbfaaa2..8da27b63c 100644 --- a/cockatrice/src/interface/widgets/deck_editor/deck_state_manager.cpp +++ b/cockatrice/src/interface/widgets/deck_editor/deck_state_manager.cpp @@ -320,6 +320,7 @@ void DeckStateManager::undo(int steps) deckListModel->rebuildTree(); emit deckListModel->layoutChanged(); + emit deckReplaced(); } void DeckStateManager::redo(int steps) @@ -338,6 +339,7 @@ void DeckStateManager::redo(int steps) deckListModel->rebuildTree(); emit deckListModel->layoutChanged(); + emit deckReplaced(); } void DeckStateManager::requestHistorySave(const QString &reason) From e79bbc67b9be76d31f149b04fb7cadeb2ef6c224 Mon Sep 17 00:00:00 2001 From: RickyRister <42636155+RickyRister@users.noreply.github.com> Date: Sun, 8 Mar 2026 15:57:39 -0700 Subject: [PATCH 14/20] [DeckEditor] Fix undo/redo clearing legality (#6675) --- .../libcockatrice/models/deck_list/deck_list_model.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libcockatrice_models/libcockatrice/models/deck_list/deck_list_model.cpp b/libcockatrice_models/libcockatrice/models/deck_list/deck_list_model.cpp index 8cbf23be4..e43c612f0 100644 --- a/libcockatrice_models/libcockatrice/models/deck_list/deck_list_model.cpp +++ b/libcockatrice_models/libcockatrice/models/deck_list/deck_list_model.cpp @@ -85,6 +85,8 @@ void DeckListModel::rebuildTree() } endResetModel(); + + refreshCardFormatLegalities(); } int DeckListModel::rowCount(const QModelIndex &parent) const @@ -649,7 +651,6 @@ void DeckListModel::setDeckList(const QSharedPointer &_deck) deckList = _deck; } rebuildTree(); - refreshCardFormatLegalities(); emit deckReplaced(); } From 413b4b637b8949e2b52c5109d02daed0f8deeab5 Mon Sep 17 00:00:00 2001 From: tooomm Date: Mon, 9 Mar 2026 21:20:38 +0100 Subject: [PATCH 15/20] sign+notarize only releases (#6678) --- .github/workflows/desktop-build.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml index bc49db2da..d627906fd 100644 --- a/.github/workflows/desktop-build.yml +++ b/.github/workflows/desktop-build.yml @@ -220,7 +220,7 @@ jobs: - name: Upload to release id: upload_release - if: needs.configure.outputs.tag != null && matrix.package != 'skip' + if: matrix.package != 'skip' && needs.configure.outputs.tag != null shell: bash env: GH_TOKEN: ${{github.token}} @@ -453,7 +453,8 @@ jobs: key: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}-${{env.BRANCH_NAME}} - name: Sign app bundle - if: matrix.os == 'macOS' && matrix.make_package && (github.ref == 'refs/heads/master' || needs.configure.outputs.tag != null) + if: matrix.os == 'macOS' && matrix.make_package && needs.configure.outputs.tag != null + id: sign_macos env: MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }} MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }} @@ -465,7 +466,7 @@ jobs: fi - name: Notarize app bundle - if: matrix.os == 'macOS' && matrix.make_package && (github.ref == 'refs/heads/master' || needs.configure.outputs.tag != null) + if: steps.sign_macos.outcome == 'success' env: MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }} MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }} @@ -497,8 +498,8 @@ jobs: fi - name: Upload artifact - id: upload_artifact if: matrix.make_package + id: upload_artifact uses: actions/upload-artifact@v7 with: path: ${{steps.build.outputs.path}} @@ -506,7 +507,7 @@ jobs: if-no-files-found: error - name: Upload PDBs (Program Databases) - if: matrix.os == 'Windows' + if: matrix.os == 'Windows' && github.ref_type != 'tag' uses: actions/upload-artifact@v7 with: name: ${{steps.build.outputs.name}}-PDBs @@ -517,8 +518,8 @@ jobs: if-no-files-found: error - name: Upload to release + if: needs.configure.outputs.tag != null && matrix.make_package == '1' id: upload_release - if: needs.configure.outputs.tag != null shell: bash env: GH_TOKEN: ${{github.token}} @@ -528,8 +529,8 @@ jobs: run: gh release upload "$tag_name" "$asset_path#$asset_name" - name: Attest binary provenance - id: attestation if: steps.upload_release.outcome == 'success' + id: attestation uses: actions/attest@v4 with: subject-name: ${{steps.build.outputs.name}} From 8268311fab199a86e000e7b753027afac75996dc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Mar 2026 21:22:26 +0100 Subject: [PATCH 16/20] Bump docker/setup-qemu-action from 3 to 4 (#6683) Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 3 to 4. - [Release notes](https://github.com/docker/setup-qemu-action/releases) - [Commits](https://github.com/docker/setup-qemu-action/compare/v3...v4) --- updated-dependencies: - dependency-name: docker/setup-qemu-action dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml index 2fe646374..02a06e592 100644 --- a/.github/workflows/docker-release.yml +++ b/.github/workflows/docker-release.yml @@ -41,7 +41,7 @@ jobs: org.opencontainers.image.description=Server for Cockatrice, a cross-platform virtual tabletop for multiplayer card games - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v4 - name: Set up Docker buildx uses: docker/setup-buildx-action@v3 From 95d7e027fc8f3f4ed44b3d76b8144a07a1421058 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Mar 2026 21:30:47 +0100 Subject: [PATCH 17/20] Bump docker/setup-buildx-action from 3 to 4 (#6682) Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3 to 4. - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](https://github.com/docker/setup-buildx-action/compare/v3...v4) --- updated-dependencies: - dependency-name: docker/setup-buildx-action dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml index 02a06e592..65ccd1322 100644 --- a/.github/workflows/docker-release.yml +++ b/.github/workflows/docker-release.yml @@ -44,7 +44,7 @@ jobs: uses: docker/setup-qemu-action@v4 - name: Set up Docker buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v4 - name: Login to GitHub Container Registry if: github.ref_type == 'tag' From 42cec1045725a29b72b1278ace7d037c5662f9d4 Mon Sep 17 00:00:00 2001 From: tooomm Date: Mon, 9 Mar 2026 21:32:47 +0100 Subject: [PATCH 18/20] CI: Cleanup (#6677) * Cleanup vcpkg matrix * Add filename with extension as output * fix name -> fullname, cleanup --- .ci/name_build.sh | 1 + .github/workflows/desktop-build.yml | 10 ++-------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/.ci/name_build.sh b/.ci/name_build.sh index b111aded6..85818bbd9 100755 --- a/.ci/name_build.sh +++ b/.ci/name_build.sh @@ -46,3 +46,4 @@ relative_path="$path/$filename" ls -l "$relative_path" echo "path=$relative_path" >>"$GITHUB_OUTPUT" echo "name=$new_name" >>"$GITHUB_OUTPUT" +echo "fullname=$filename" >>"$GITHUB_OUTPUT" diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml index d627906fd..233d9e488 100644 --- a/.github/workflows/desktop-build.yml +++ b/.github/workflows/desktop-build.yml @@ -225,7 +225,7 @@ jobs: env: GH_TOKEN: ${{github.token}} tag_name: ${{needs.configure.outputs.tag}} - asset_name: ${{steps.build.outputs.name}} + asset_name: ${{steps.build.outputs.fullname}} asset_path: ${{steps.build.outputs.path}} run: gh release upload "$tag_name" "$asset_path#$asset_name" @@ -234,7 +234,6 @@ jobs: if: steps.upload_release.outcome == 'success' uses: actions/attest@v4 with: - subject-name: ${{steps.build.outputs.name}} subject-path: ${{steps.build.outputs.path}} show-summary: false @@ -259,7 +258,6 @@ jobs: override_target: 13 make_package: 1 package_suffix: "-macOS13_Intel" - artifact_name: macOS13_Intel-package qt_version: 6.10.* qt_arch: clang_64 qt_modules: qtimageformats qtmultimedia qtwebsockets @@ -274,7 +272,6 @@ jobs: type: Release make_package: 1 package_suffix: "-macOS14" - artifact_name: macOS14-package qt_version: 6.10.* qt_arch: clang_64 qt_modules: qtimageformats qtmultimedia qtwebsockets @@ -289,7 +286,6 @@ jobs: type: Release make_package: 1 package_suffix: "-macOS15" - artifact_name: macOS15-package qt_version: 6.10.* qt_arch: clang_64 qt_modules: qtimageformats qtmultimedia qtwebsockets @@ -314,7 +310,6 @@ jobs: type: Release make_package: 1 package_suffix: "-Win10" - artifact_name: Windows10-installer qt_version: 6.10.* qt_arch: win64_msvc2022_64 qt_modules: qtimageformats qtmultimedia qtwebsockets @@ -524,7 +519,7 @@ jobs: env: GH_TOKEN: ${{github.token}} tag_name: ${{needs.configure.outputs.tag}} - asset_name: ${{steps.build.outputs.name}} + asset_name: ${{steps.build.outputs.fullname}} asset_path: ${{steps.build.outputs.path}} run: gh release upload "$tag_name" "$asset_path#$asset_name" @@ -533,7 +528,6 @@ jobs: id: attestation uses: actions/attest@v4 with: - subject-name: ${{steps.build.outputs.name}} subject-path: ${{steps.build.outputs.path}} show-summary: false From 9e2276a59fa0df05b16bb4e9dbd0a2a377dd572a Mon Sep 17 00:00:00 2001 From: DawnFire42 Date: Wed, 11 Mar 2026 19:34:05 -0400 Subject: [PATCH 19/20] Refactor zone names (#6686) * Add ZoneNames constants for protocol zone identifiers. Introduce a centralized ZoneNames namespace providing constexpr constants for zone identifiers used in the client-server protocol. This establishes a single source of truth for zone names like TABLE, GRAVE, EXILE, HAND, DECK, SIDEBOARD, and STACK. The protocol values remain unchanged (e.g., EXILE maps to rfg for backwards compatibility) while providing meaningful constant names. * refactor(server): use ZoneNames constants in server game logic Replace hardcoded zone name strings with ZoneNames:: constants in: - server_player.cpp: zone setup, draw, shuffle, mulligan operations - server_abstract_player.cpp: card movement and token destruction - server_game.cpp: returning cards when players leave No functional changes - purely mechanical string literal replacement. * refactor(client): use ZoneNames constants in core player/zone logic Update the foundational player and zone classes to use ZoneNames:: constants instead of string literals. Changes include: - player.h/cpp: zone initialization and builtinZones set - card_zone_logic.cpp: zone name translation for UI display - table_zone.cpp: table zone operations No functional changes - purely mechanical string literal replacement. * refactor(client): use ZoneNames constants in player actions and events Replace zone name strings with ZoneNames:: constants in the player action and event handling code. player_actions.cpp contains the most extensive changes (~90+ replacements) covering all card movement commands. No functional changes - purely mechanical string literal replacement. * refactor(client): use ZoneNames constants in zone menu handlers Update all zone-specific menu files to use ZoneNames:: constants for QAction data values and zone targeting. This covers context menus for cards, graveyard, hand, and exile (RFG) zones. No functional changes - purely mechanical string literal replacement. * refactor(client): use ZoneNames constants in game scene components Update remaining game scene components to use ZoneNames:: constants: - arrow_item.cpp: arrow drawing between cards - game_scene.cpp: zone view positioning - message_log_widget.cpp: removes duplicate local static constants that were previously defining zone names redundantly - phases_toolbar.cpp: phase actions (untap all) Notable: message_log_widget.cpp previously had its own local constants (TABLE_ZONE_NAME, GRAVE_ZONE_NAME, etc.) which are now removed in favor of the centralized ZoneNames:: constants. * formatting fix --- cockatrice/src/game/board/arrow_item.cpp | 19 +-- cockatrice/src/game/game_scene.cpp | 5 +- .../src/game/log/message_log_widget.cpp | 43 +++--- cockatrice/src/game/phases_toolbar.cpp | 3 +- cockatrice/src/game/player/menu/card_menu.cpp | 14 +- .../src/game/player/menu/grave_menu.cpp | 9 +- cockatrice/src/game/player/menu/hand_menu.cpp | 9 +- cockatrice/src/game/player/menu/rfg_menu.cpp | 10 +- cockatrice/src/game/player/player.cpp | 22 +-- cockatrice/src/game/player/player.h | 15 +- cockatrice/src/game/player/player_actions.cpp | 137 +++++++++--------- .../src/game/player/player_event_handler.cpp | 5 +- .../src/game/zones/logic/card_zone_logic.cpp | 11 +- cockatrice/src/game/zones/table_zone.cpp | 3 +- .../remote/game/server_abstract_player.cpp | 9 +- .../server/remote/game/server_game.cpp | 5 +- .../server/remote/game/server_player.cpp | 33 +++-- libcockatrice_utility/CMakeLists.txt | 9 +- .../libcockatrice/utility/zone_names.h | 19 +++ 19 files changed, 207 insertions(+), 173 deletions(-) create mode 100644 libcockatrice_utility/libcockatrice/utility/zone_names.h diff --git a/cockatrice/src/game/board/arrow_item.cpp b/cockatrice/src/game/board/arrow_item.cpp index 257d96f8a..60585a774 100644 --- a/cockatrice/src/game/board/arrow_item.cpp +++ b/cockatrice/src/game/board/arrow_item.cpp @@ -19,6 +19,7 @@ #include #include #include +#include ArrowItem::ArrowItem(Player *_player, int _id, ArrowTarget *_startItem, ArrowTarget *_targetItem, const QColor &_color) : QGraphicsItem(), player(_player), id(_id), startItem(_startItem), targetItem(_targetItem), targetLocked(false), @@ -239,16 +240,16 @@ void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) } // if the card is in hand then we will move the card to stack or table as part of drawing the arrow - if (startZone->getName() == "hand") { + if (startZone->getName() == ZoneNames::HAND) { startCard->playCard(false); CardInfoPtr ci = startCard->getCard().getCardPtr(); bool playToStack = SettingsCache::instance().getPlayToStack(); - if (ci && - ((!playToStack && ci->getUiAttributes().tableRow == 3) || - (playToStack && ci->getUiAttributes().tableRow != 0 && startCard->getZone()->getName() != "stack"))) - cmd.set_start_zone("stack"); + if (ci && ((!playToStack && ci->getUiAttributes().tableRow == 3) || + (playToStack && ci->getUiAttributes().tableRow != 0 && + startCard->getZone()->getName() != ZoneNames::STACK))) + cmd.set_start_zone(ZoneNames::STACK); else - cmd.set_start_zone(playToStack ? "stack" : "table"); + cmd.set_start_zone(playToStack ? ZoneNames::STACK : ZoneNames::TABLE); } if (deleteInPhase != 0) { @@ -318,7 +319,7 @@ void ArrowAttachItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) void ArrowAttachItem::attachCards(CardItem *startCard, const CardItem *targetCard) { // do nothing if target is already attached to another card or is not in play - if (targetCard->getAttachedTo() || targetCard->getZone()->getName() != "table") { + if (targetCard->getAttachedTo() || targetCard->getZone()->getName() != ZoneNames::TABLE) { return; } @@ -326,12 +327,12 @@ void ArrowAttachItem::attachCards(CardItem *startCard, const CardItem *targetCar CardZoneLogic *targetZone = targetCard->getZone(); // move card onto table first if attaching from some other zone - if (startZone->getName() != "table") { + if (startZone->getName() != ZoneNames::TABLE) { player->getPlayerActions()->playCardToTable(startCard, false); } Command_AttachCard cmd; - cmd.set_start_zone("table"); + cmd.set_start_zone(ZoneNames::TABLE); cmd.set_card_id(startCard->getId()); cmd.set_target_player_id(targetZone->getPlayer()->getPlayerInfo()->getId()); cmd.set_target_zone(targetZone->getName().toStdString()); diff --git a/cockatrice/src/game/game_scene.cpp b/cockatrice/src/game/game_scene.cpp index 77037cd6e..5dc3b48f7 100644 --- a/cockatrice/src/game/game_scene.cpp +++ b/cockatrice/src/game/game_scene.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include /** @@ -410,9 +411,9 @@ void GameScene::toggleZoneView(Player *player, const QString &zoneName, int numb connect(item, &ZoneViewWidget::closePressed, this, &GameScene::removeZoneView); addItem(item); - if (zoneName == "grave") + if (zoneName == ZoneNames::GRAVE) item->setPos(360, 100); - else if (zoneName == "rfg") + else if (zoneName == ZoneNames::EXILE) item->setPos(380, 120); else item->setPos(340, 80); diff --git a/cockatrice/src/game/log/message_log_widget.cpp b/cockatrice/src/game/log/message_log_widget.cpp index 645974994..c38e433eb 100644 --- a/cockatrice/src/game/log/message_log_widget.cpp +++ b/cockatrice/src/game/log/message_log_widget.cpp @@ -10,16 +10,9 @@ #include <../../client/settings/card_counter_settings.h> #include #include +#include #include -static const QString TABLE_ZONE_NAME = "table"; -static const QString GRAVE_ZONE_NAME = "grave"; -static const QString EXILE_ZONE_NAME = "rfg"; -static const QString HAND_ZONE_NAME = "hand"; -static const QString DECK_ZONE_NAME = "deck"; -static const QString SIDEBOARD_ZONE_NAME = "sb"; -static const QString STACK_ZONE_NAME = "stack"; - static QString sanitizeHtml(QString dirty) { return dirty.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """); @@ -37,15 +30,15 @@ MessageLogWidget::getFromStr(CardZoneLogic *zone, QString cardName, int position QString fromStr; QString zoneName = zone->getName(); - if (zoneName == TABLE_ZONE_NAME) { + if (zoneName == ZoneNames::TABLE) { fromStr = tr(" from play"); - } else if (zoneName == GRAVE_ZONE_NAME) { + } else if (zoneName == ZoneNames::GRAVE) { fromStr = tr(" from their graveyard"); - } else if (zoneName == EXILE_ZONE_NAME) { + } else if (zoneName == ZoneNames::EXILE) { fromStr = tr(" from exile"); - } else if (zoneName == HAND_ZONE_NAME) { + } else if (zoneName == ZoneNames::HAND) { fromStr = tr(" from their hand"); - } else if (zoneName == DECK_ZONE_NAME) { + } else if (zoneName == ZoneNames::DECK) { if (position == 0) { if (cardName.isEmpty()) { if (ownerChange) { @@ -83,9 +76,9 @@ MessageLogWidget::getFromStr(CardZoneLogic *zone, QString cardName, int position fromStr = tr(" from their library"); } } - } else if (zoneName == SIDEBOARD_ZONE_NAME) { + } else if (zoneName == ZoneNames::SIDEBOARD) { fromStr = tr(" from sideboard"); - } else if (zoneName == STACK_ZONE_NAME) { + } else if (zoneName == ZoneNames::STACK) { fromStr = tr(" from the stack"); } else { fromStr = tr(" from custom zone '%1'").arg(zoneName); @@ -275,9 +268,9 @@ void MessageLogWidget::logMoveCard(Player *player, bool ownerChanged = startZone->getPlayer() != targetZone->getPlayer(); // do not log if moved within the same zone - if ((startZoneName == TABLE_ZONE_NAME && targetZoneName == TABLE_ZONE_NAME && !ownerChanged) || - (startZoneName == HAND_ZONE_NAME && targetZoneName == HAND_ZONE_NAME) || - (startZoneName == EXILE_ZONE_NAME && targetZoneName == EXILE_ZONE_NAME)) { + if ((startZoneName == ZoneNames::TABLE && targetZoneName == ZoneNames::TABLE && !ownerChanged) || + (startZoneName == ZoneNames::HAND && targetZoneName == ZoneNames::HAND) || + (startZoneName == ZoneNames::EXILE && targetZoneName == ZoneNames::EXILE)) { return; } @@ -306,28 +299,28 @@ void MessageLogWidget::logMoveCard(Player *player, QString finalStr; std::optional fourthArg; - if (targetZoneName == TABLE_ZONE_NAME) { + if (targetZoneName == ZoneNames::TABLE) { soundEngine->playSound("play_card"); if (card->getFaceDown()) { finalStr = tr("%1 puts %2 into play%3 face down."); } else { finalStr = tr("%1 puts %2 into play%3."); } - } else if (targetZoneName == GRAVE_ZONE_NAME) { + } else if (targetZoneName == ZoneNames::GRAVE) { if (card->getFaceDown()) { finalStr = tr("%1 puts %2%3 into their graveyard face down."); } else { finalStr = tr("%1 puts %2%3 into their graveyard."); } - } else if (targetZoneName == EXILE_ZONE_NAME) { + } else if (targetZoneName == ZoneNames::EXILE) { if (card->getFaceDown()) { finalStr = tr("%1 exiles %2%3 face down."); } else { finalStr = tr("%1 exiles %2%3."); } - } else if (targetZoneName == HAND_ZONE_NAME) { + } else if (targetZoneName == ZoneNames::HAND) { finalStr = tr("%1 moves %2%3 to their hand."); - } else if (targetZoneName == DECK_ZONE_NAME) { + } else if (targetZoneName == ZoneNames::DECK) { if (newX == -1) { finalStr = tr("%1 puts %2%3 into their library."); } else if (newX >= targetZone->getCards().size()) { @@ -339,9 +332,9 @@ void MessageLogWidget::logMoveCard(Player *player, fourthArg = QString::number(newX); finalStr = tr("%1 puts %2%3 into their library %4 cards from the top."); } - } else if (targetZoneName == SIDEBOARD_ZONE_NAME) { + } else if (targetZoneName == ZoneNames::SIDEBOARD) { finalStr = tr("%1 moves %2%3 to sideboard."); - } else if (targetZoneName == STACK_ZONE_NAME) { + } else if (targetZoneName == ZoneNames::STACK) { soundEngine->playSound("play_card"); if (card->getFaceDown()) { finalStr = tr("%1 plays %2%3 face down."); diff --git a/cockatrice/src/game/phases_toolbar.cpp b/cockatrice/src/game/phases_toolbar.cpp index 5106e40de..2341a1d7f 100644 --- a/cockatrice/src/game/phases_toolbar.cpp +++ b/cockatrice/src/game/phases_toolbar.cpp @@ -11,6 +11,7 @@ #include #include #include +#include PhaseButton::PhaseButton(const QString &_name, QGraphicsItem *parent, QAction *_doubleClickAction, bool _highlightable) : QObject(), QGraphicsItem(parent), name(_name), active(false), highlightable(_highlightable), @@ -259,7 +260,7 @@ void PhasesToolbar::actNextTurn() void PhasesToolbar::actUntapAll() { Command_SetCardAttr cmd; - cmd.set_zone("table"); + cmd.set_zone(ZoneNames::TABLE); cmd.set_attribute(AttrTapped); cmd.set_attr_value("0"); diff --git a/cockatrice/src/game/player/menu/card_menu.cpp b/cockatrice/src/game/player/menu/card_menu.cpp index ddf0a55f3..ef95f052e 100644 --- a/cockatrice/src/game/player/menu/card_menu.cpp +++ b/cockatrice/src/game/player/menu/card_menu.cpp @@ -12,6 +12,7 @@ #include #include +#include CardMenu::CardMenu(Player *_player, const CardItem *_card, bool _shortcutsActive) : player(_player), card(_card), shortcutsActive(_shortcutsActive) @@ -115,11 +116,12 @@ CardMenu::CardMenu(Player *_player, const CardItem *_card, bool _shortcutsActive } else if (writeableCard) { if (card->getZone()) { - if (card->getZone()->getName() == "table") { + if (card->getZone()->getName() == ZoneNames::TABLE) { createTableMenu(); - } else if (card->getZone()->getName() == "stack") { + } else if (card->getZone()->getName() == ZoneNames::STACK) { createStackMenu(); - } else if (card->getZone()->getName() == "rfg" || card->getZone()->getName() == "grave") { + } else if (card->getZone()->getName() == ZoneNames::EXILE || + card->getZone()->getName() == ZoneNames::GRAVE) { createGraveyardOrExileMenu(); } else { createHandOrCustomZoneMenu(); @@ -128,7 +130,7 @@ CardMenu::CardMenu(Player *_player, const CardItem *_card, bool _shortcutsActive addMenu(new MoveMenu(player)); } } else { - if (card->getZone() && card->getZone()->getName() != "hand") { + if (card->getZone() && card->getZone()->getName() != ZoneNames::HAND) { addAction(aDrawArrow); addSeparator(); addRelatedCardView(); @@ -285,7 +287,7 @@ void CardMenu::createHandOrCustomZoneMenu() addMenu(new MoveMenu(player)); // actions that are really wonky when done from deck or sideboard - if (card->getZone()->getName() == "hand") { + if (card->getZone()->getName() == ZoneNames::HAND) { addSeparator(); addAction(aAttach); addAction(aDrawArrow); @@ -298,7 +300,7 @@ void CardMenu::createHandOrCustomZoneMenu() } addRelatedCardView(); - if (card->getZone()->getName() == "hand") { + if (card->getZone()->getName() == ZoneNames::HAND) { addRelatedCardActions(); } } diff --git a/cockatrice/src/game/player/menu/grave_menu.cpp b/cockatrice/src/game/player/menu/grave_menu.cpp index d4faca42b..2af62c08a 100644 --- a/cockatrice/src/game/player/menu/grave_menu.cpp +++ b/cockatrice/src/game/player/menu/grave_menu.cpp @@ -6,6 +6,7 @@ #include #include +#include GraveyardMenu::GraveyardMenu(Player *_player, QWidget *parent) : TearOffMenu(parent), player(_player) { @@ -39,16 +40,16 @@ void GraveyardMenu::createMoveActions() if (player->getPlayerInfo()->local || player->getPlayerInfo()->judge) { aMoveGraveToTopLibrary = new QAction(this); - aMoveGraveToTopLibrary->setData(QList() << "deck" << 0); + aMoveGraveToTopLibrary->setData(QList() << ZoneNames::DECK << 0); aMoveGraveToBottomLibrary = new QAction(this); - aMoveGraveToBottomLibrary->setData(QList() << "deck" << -1); + aMoveGraveToBottomLibrary->setData(QList() << ZoneNames::DECK << -1); aMoveGraveToHand = new QAction(this); - aMoveGraveToHand->setData(QList() << "hand" << 0); + aMoveGraveToHand->setData(QList() << ZoneNames::HAND << 0); aMoveGraveToRfg = new QAction(this); - aMoveGraveToRfg->setData(QList() << "rfg" << 0); + aMoveGraveToRfg->setData(QList() << ZoneNames::EXILE << 0); connect(aMoveGraveToTopLibrary, &QAction::triggered, grave, &PileZoneLogic::moveAllToZone); connect(aMoveGraveToBottomLibrary, &QAction::triggered, grave, &PileZoneLogic::moveAllToZone); diff --git a/cockatrice/src/game/player/menu/hand_menu.cpp b/cockatrice/src/game/player/menu/hand_menu.cpp index 019ab925c..d65c136bf 100644 --- a/cockatrice/src/game/player/menu/hand_menu.cpp +++ b/cockatrice/src/game/player/menu/hand_menu.cpp @@ -9,6 +9,7 @@ #include #include +#include HandMenu::HandMenu(Player *_player, PlayerActions *actions, QWidget *parent) : TearOffMenu(parent), player(_player) { @@ -76,13 +77,13 @@ HandMenu::HandMenu(Player *_player, PlayerActions *actions, QWidget *parent) : T if (player->getPlayerInfo()->local || player->getPlayerInfo()->judge) { aMoveHandToTopLibrary = new QAction(this); - aMoveHandToTopLibrary->setData(QList() << "deck" << 0); + aMoveHandToTopLibrary->setData(QList() << ZoneNames::DECK << 0); aMoveHandToBottomLibrary = new QAction(this); - aMoveHandToBottomLibrary->setData(QList() << "deck" << -1); + aMoveHandToBottomLibrary->setData(QList() << ZoneNames::DECK << -1); aMoveHandToGrave = new QAction(this); - aMoveHandToGrave->setData(QList() << "grave" << 0); + aMoveHandToGrave->setData(QList() << ZoneNames::GRAVE << 0); aMoveHandToRfg = new QAction(this); - aMoveHandToRfg->setData(QList() << "rfg" << 0); + aMoveHandToRfg->setData(QList() << ZoneNames::EXILE << 0); auto hand = player->getHandZone(); diff --git a/cockatrice/src/game/player/menu/rfg_menu.cpp b/cockatrice/src/game/player/menu/rfg_menu.cpp index 25e162581..8a101c04c 100644 --- a/cockatrice/src/game/player/menu/rfg_menu.cpp +++ b/cockatrice/src/game/player/menu/rfg_menu.cpp @@ -3,6 +3,8 @@ #include "../player.h" #include "../player_actions.h" +#include + RfgMenu::RfgMenu(Player *_player, QWidget *parent) : TearOffMenu(parent), player(_player) { createMoveActions(); @@ -30,13 +32,13 @@ void RfgMenu::createMoveActions() auto rfg = player->getRfgZone(); aMoveRfgToTopLibrary = new QAction(this); - aMoveRfgToTopLibrary->setData(QList() << "deck" << 0); + aMoveRfgToTopLibrary->setData(QList() << ZoneNames::DECK << 0); aMoveRfgToBottomLibrary = new QAction(this); - aMoveRfgToBottomLibrary->setData(QList() << "deck" << -1); + aMoveRfgToBottomLibrary->setData(QList() << ZoneNames::DECK << -1); aMoveRfgToHand = new QAction(this); - aMoveRfgToHand->setData(QList() << "hand" << 0); + aMoveRfgToHand->setData(QList() << ZoneNames::HAND << 0); aMoveRfgToGrave = new QAction(this); - aMoveRfgToGrave->setData(QList() << "grave" << 0); + aMoveRfgToGrave->setData(QList() << ZoneNames::GRAVE << 0); connect(aMoveRfgToTopLibrary, &QAction::triggered, rfg, &PileZoneLogic::moveAllToZone); connect(aMoveRfgToBottomLibrary, &QAction::triggered, rfg, &PileZoneLogic::moveAllToZone); diff --git a/cockatrice/src/game/player/player.cpp b/cockatrice/src/game/player/player.cpp index 0723ae6bc..ac4149f0e 100644 --- a/cockatrice/src/game/player/player.cpp +++ b/cockatrice/src/game/player/player.cpp @@ -61,15 +61,15 @@ void Player::forwardActionSignalsToEventHandler() void Player::initializeZones() { - addZone(new PileZoneLogic(this, "deck", false, true, false, this)); - addZone(new PileZoneLogic(this, "grave", false, false, true, this)); - addZone(new PileZoneLogic(this, "rfg", false, false, true, this)); - addZone(new PileZoneLogic(this, "sb", false, false, false, this)); - addZone(new TableZoneLogic(this, "table", true, false, true, this)); - addZone(new StackZoneLogic(this, "stack", true, false, true, this)); + addZone(new PileZoneLogic(this, ZoneNames::DECK, false, true, false, this)); + addZone(new PileZoneLogic(this, ZoneNames::GRAVE, false, false, true, this)); + addZone(new PileZoneLogic(this, ZoneNames::EXILE, false, false, true, this)); + addZone(new PileZoneLogic(this, ZoneNames::SIDEBOARD, false, false, false, this)); + addZone(new TableZoneLogic(this, ZoneNames::TABLE, true, false, true, this)); + addZone(new StackZoneLogic(this, ZoneNames::STACK, true, false, true, this)); bool visibleHand = playerInfo->getLocalOrJudge() || (game->getPlayerManager()->isSpectator() && game->getGameMetaInfo()->spectatorsOmniscient()); - addZone(new HandZoneLogic(this, "hand", false, false, visibleHand, this)); + addZone(new HandZoneLogic(this, ZoneNames::HAND, false, false, visibleHand, this)); } Player::~Player() @@ -119,13 +119,13 @@ void Player::setZoneId(int _zoneId) void Player::processPlayerInfo(const ServerInfo_Player &info) { static QSet builtinZones{/* PileZones */ - "deck", "grave", "rfg", "sb", + ZoneNames::DECK, ZoneNames::GRAVE, ZoneNames::EXILE, ZoneNames::SIDEBOARD, /* TableZone */ - "table", + ZoneNames::TABLE, /* StackZone */ - "stack", + ZoneNames::STACK, /* HandZone */ - "hand"}; + ZoneNames::HAND}; clearCounters(); clearArrows(); diff --git a/cockatrice/src/game/player/player.h b/cockatrice/src/game/player/player.h index 0a03b3abe..e9c008821 100644 --- a/cockatrice/src/game/player/player.h +++ b/cockatrice/src/game/player/player.h @@ -27,6 +27,7 @@ #include #include #include +#include inline Q_LOGGING_CATEGORY(PlayerLog, "player"); @@ -155,37 +156,37 @@ public: PileZoneLogic *getDeckZone() { - return qobject_cast(zones.value("deck")); + return qobject_cast(zones.value(ZoneNames::DECK)); } PileZoneLogic *getGraveZone() { - return qobject_cast(zones.value("grave")); + return qobject_cast(zones.value(ZoneNames::GRAVE)); } PileZoneLogic *getRfgZone() { - return qobject_cast(zones.value("rfg")); + return qobject_cast(zones.value(ZoneNames::EXILE)); } PileZoneLogic *getSideboardZone() { - return qobject_cast(zones.value("sb")); + return qobject_cast(zones.value(ZoneNames::SIDEBOARD)); } TableZoneLogic *getTableZone() { - return qobject_cast(zones.value("table")); + return qobject_cast(zones.value(ZoneNames::TABLE)); } StackZoneLogic *getStackZone() { - return qobject_cast(zones.value("stack")); + return qobject_cast(zones.value(ZoneNames::STACK)); } HandZoneLogic *getHandZone() { - return qobject_cast(zones.value("hand")); + return qobject_cast(zones.value(ZoneNames::HAND)); } AbstractCounter *addCounter(const ServerInfo_Counter &counter); diff --git a/cockatrice/src/game/player/player_actions.cpp b/cockatrice/src/game/player/player_actions.cpp index 514ac2e67..20e526727 100644 --- a/cockatrice/src/game/player/player_actions.cpp +++ b/cockatrice/src/game/player/player_actions.cpp @@ -28,6 +28,7 @@ #include #include #include +#include // milliseconds in between triggers of the move top cards until action static constexpr int MOVE_TOP_CARD_UNTIL_INTERVAL = 100; @@ -63,13 +64,13 @@ void PlayerActions::playCard(CardItem *card, bool faceDown) int tableRow = info.getUiAttributes().tableRow; bool playToStack = SettingsCache::instance().getPlayToStack(); QString currentZone = card->getZone()->getName(); - if (currentZone == "stack" && tableRow == 3) { - cmd.set_target_zone("grave"); + if (currentZone == ZoneNames::STACK && tableRow == 3) { + cmd.set_target_zone(ZoneNames::GRAVE); cmd.set_x(0); cmd.set_y(0); - } else if (!faceDown && - ((!playToStack && tableRow == 3) || ((playToStack && tableRow != 0) && currentZone != "stack"))) { - cmd.set_target_zone("stack"); + } else if (!faceDown && ((!playToStack && tableRow == 3) || + ((playToStack && tableRow != 0) && currentZone != ZoneNames::STACK))) { + cmd.set_target_zone(ZoneNames::STACK); cmd.set_x(-1); cmd.set_y(0); } else { @@ -81,7 +82,7 @@ void PlayerActions::playCard(CardItem *card, bool faceDown) } cardToMove->set_tapped(!faceDown && info.getUiAttributes().cipt); if (tableRow != 3) - cmd.set_target_zone("table"); + cmd.set_target_zone(ZoneNames::TABLE); cmd.set_x(gridPoint.x()); cmd.set_y(gridPoint.y()); } @@ -124,7 +125,7 @@ void PlayerActions::playCardToTable(const CardItem *card, bool faceDown) cardToMove->set_pt(info.getPowTough().toStdString()); } cardToMove->set_tapped(!faceDown && info.getUiAttributes().cipt); - cmd.set_target_zone("table"); + cmd.set_target_zone(ZoneNames::TABLE); cmd.set_x(gridPoint.x()); cmd.set_y(gridPoint.y()); sendGameCommand(cmd); @@ -132,12 +133,12 @@ void PlayerActions::playCardToTable(const CardItem *card, bool faceDown) void PlayerActions::actViewLibrary() { - player->getGameScene()->toggleZoneView(player, "deck", -1); + player->getGameScene()->toggleZoneView(player, ZoneNames::DECK, -1); } void PlayerActions::actViewHand() { - player->getGameScene()->toggleZoneView(player, "hand", -1); + player->getGameScene()->toggleZoneView(player, ZoneNames::HAND, -1); } /** @@ -181,7 +182,7 @@ void PlayerActions::actViewTopCards() deckSize, 1, &ok); if (ok) { defaultNumberTopCards = number; - player->getGameScene()->toggleZoneView(player, "deck", number); + player->getGameScene()->toggleZoneView(player, ZoneNames::DECK, number); } } @@ -194,14 +195,14 @@ void PlayerActions::actViewBottomCards() deckSize, 1, &ok); if (ok) { defaultNumberBottomCards = number; - player->getGameScene()->toggleZoneView(player, "deck", number, true); + player->getGameScene()->toggleZoneView(player, ZoneNames::DECK, number, true); } } void PlayerActions::actAlwaysRevealTopCard() { Command_ChangeZoneProperties cmd; - cmd.set_zone_name("deck"); + cmd.set_zone_name(ZoneNames::DECK); cmd.set_always_reveal_top_card(player->getPlayerMenu()->getLibraryMenu()->isAlwaysRevealTopCardChecked()); sendGameCommand(cmd); @@ -210,7 +211,7 @@ void PlayerActions::actAlwaysRevealTopCard() void PlayerActions::actAlwaysLookAtTopCard() { Command_ChangeZoneProperties cmd; - cmd.set_zone_name("deck"); + cmd.set_zone_name(ZoneNames::DECK); cmd.set_always_look_at_top_card(player->getPlayerMenu()->getLibraryMenu()->isAlwaysLookAtTopCardChecked()); sendGameCommand(cmd); @@ -223,17 +224,17 @@ void PlayerActions::actOpenDeckInDeckEditor() void PlayerActions::actViewGraveyard() { - player->getGameScene()->toggleZoneView(player, "grave", -1); + player->getGameScene()->toggleZoneView(player, ZoneNames::GRAVE, -1); } void PlayerActions::actViewRfg() { - player->getGameScene()->toggleZoneView(player, "rfg", -1); + player->getGameScene()->toggleZoneView(player, ZoneNames::EXILE, -1); } void PlayerActions::actViewSideboard() { - player->getGameScene()->toggleZoneView(player, "sb", -1); + player->getGameScene()->toggleZoneView(player, ZoneNames::SIDEBOARD, -1); } void PlayerActions::actShuffle() @@ -263,7 +264,7 @@ void PlayerActions::actShuffleTop() defaultNumberTopCards = number; Command_Shuffle cmd; - cmd.set_zone_name("deck"); + cmd.set_zone_name(ZoneNames::DECK); cmd.set_start(0); cmd.set_end(number - 1); // inclusive, the indexed card at end will be shuffled @@ -292,7 +293,7 @@ void PlayerActions::actShuffleBottom() defaultNumberBottomCards = number; Command_Shuffle cmd; - cmd.set_zone_name("deck"); + cmd.set_zone_name(ZoneNames::DECK); cmd.set_start(-number); cmd.set_end(-1); @@ -376,7 +377,7 @@ void PlayerActions::actUndoDraw() void PlayerActions::cmdSetTopCard(Command_MoveCard &cmd) { - cmd.set_start_zone("deck"); + cmd.set_start_zone(ZoneNames::DECK); auto *cardToMove = cmd.mutable_cards_to_move()->add_card(); cardToMove->set_card_id(0); cmd.set_target_player_id(player->getPlayerInfo()->getId()); @@ -386,7 +387,7 @@ void PlayerActions::cmdSetBottomCard(Command_MoveCard &cmd) { CardZoneLogic *zone = player->getDeckZone(); int lastCard = zone->getCards().size() - 1; - cmd.set_start_zone("deck"); + cmd.set_start_zone(ZoneNames::DECK); auto *cardToMove = cmd.mutable_cards_to_move()->add_card(); cardToMove->set_card_id(lastCard); cmd.set_target_player_id(player->getPlayerInfo()->getId()); @@ -400,7 +401,7 @@ void PlayerActions::actMoveTopCardToGrave() Command_MoveCard cmd; cmdSetTopCard(cmd); - cmd.set_target_zone("grave"); + cmd.set_target_zone(ZoneNames::GRAVE); cmd.set_x(0); cmd.set_y(0); @@ -415,7 +416,7 @@ void PlayerActions::actMoveTopCardToExile() Command_MoveCard cmd; cmdSetTopCard(cmd); - cmd.set_target_zone("rfg"); + cmd.set_target_zone(ZoneNames::EXILE); cmd.set_x(0); cmd.set_y(0); @@ -424,22 +425,22 @@ void PlayerActions::actMoveTopCardToExile() void PlayerActions::actMoveTopCardsToGrave() { - moveTopCardsTo("grave", tr("grave"), false); + moveTopCardsTo(ZoneNames::GRAVE, tr("grave"), false); } void PlayerActions::actMoveTopCardsToGraveFaceDown() { - moveTopCardsTo("grave", tr("grave"), true); + moveTopCardsTo(ZoneNames::GRAVE, tr("grave"), true); } void PlayerActions::actMoveTopCardsToExile() { - moveTopCardsTo("rfg", tr("exile"), false); + moveTopCardsTo(ZoneNames::EXILE, tr("exile"), false); } void PlayerActions::actMoveTopCardsToExileFaceDown() { - moveTopCardsTo("rfg", tr("exile"), true); + moveTopCardsTo(ZoneNames::EXILE, tr("exile"), true); } void PlayerActions::moveTopCardsTo(const QString &targetZone, const QString &zoneDisplayName, bool faceDown) @@ -463,7 +464,7 @@ void PlayerActions::moveTopCardsTo(const QString &targetZone, const QString &zon defaultNumberTopCards = number; Command_MoveCard cmd; - cmd.set_start_zone("deck"); + cmd.set_start_zone(ZoneNames::DECK); cmd.set_target_player_id(player->getPlayerInfo()->getId()); cmd.set_target_zone(targetZone.toStdString()); cmd.set_x(0); @@ -549,7 +550,7 @@ void PlayerActions::actMoveTopCardToBottom() Command_MoveCard cmd; cmdSetTopCard(cmd); - cmd.set_target_zone("deck"); + cmd.set_target_zone(ZoneNames::DECK); cmd.set_x(-1); // bottom of deck cmd.set_y(0); @@ -564,7 +565,7 @@ void PlayerActions::actMoveTopCardToPlay() Command_MoveCard cmd; cmdSetTopCard(cmd); - cmd.set_target_zone("stack"); + cmd.set_target_zone(ZoneNames::STACK); cmd.set_x(-1); cmd.set_y(0); @@ -578,12 +579,12 @@ void PlayerActions::actMoveTopCardToPlayFaceDown() } Command_MoveCard cmd; - cmd.set_start_zone("deck"); + cmd.set_start_zone(ZoneNames::DECK); CardToMove *cardToMove = cmd.mutable_cards_to_move()->add_card(); cardToMove->set_card_id(0); cardToMove->set_face_down(true); cmd.set_target_player_id(player->getPlayerInfo()->getId()); - cmd.set_target_zone("table"); + cmd.set_target_zone(ZoneNames::TABLE); cmd.set_x(-1); cmd.set_y(0); @@ -598,7 +599,7 @@ void PlayerActions::actMoveBottomCardToGrave() Command_MoveCard cmd; cmdSetBottomCard(cmd); - cmd.set_target_zone("grave"); + cmd.set_target_zone(ZoneNames::GRAVE); cmd.set_x(0); cmd.set_y(0); @@ -613,7 +614,7 @@ void PlayerActions::actMoveBottomCardToExile() Command_MoveCard cmd; cmdSetBottomCard(cmd); - cmd.set_target_zone("rfg"); + cmd.set_target_zone(ZoneNames::EXILE); cmd.set_x(0); cmd.set_y(0); @@ -622,22 +623,22 @@ void PlayerActions::actMoveBottomCardToExile() void PlayerActions::actMoveBottomCardsToGrave() { - moveBottomCardsTo("grave", tr("grave"), false); + moveBottomCardsTo(ZoneNames::GRAVE, tr("grave"), false); } void PlayerActions::actMoveBottomCardsToGraveFaceDown() { - moveBottomCardsTo("grave", tr("grave"), true); + moveBottomCardsTo(ZoneNames::GRAVE, tr("grave"), true); } void PlayerActions::actMoveBottomCardsToExile() { - moveBottomCardsTo("rfg", tr("exile"), false); + moveBottomCardsTo(ZoneNames::EXILE, tr("exile"), false); } void PlayerActions::actMoveBottomCardsToExileFaceDown() { - moveBottomCardsTo("rfg", tr("exile"), true); + moveBottomCardsTo(ZoneNames::EXILE, tr("exile"), true); } void PlayerActions::moveBottomCardsTo(const QString &targetZone, const QString &zoneDisplayName, bool faceDown) @@ -661,7 +662,7 @@ void PlayerActions::moveBottomCardsTo(const QString &targetZone, const QString & defaultNumberBottomCards = number; Command_MoveCard cmd; - cmd.set_start_zone("deck"); + cmd.set_start_zone(ZoneNames::DECK); cmd.set_target_player_id(player->getPlayerInfo()->getId()); cmd.set_target_zone(targetZone.toStdString()); cmd.set_x(0); @@ -686,7 +687,7 @@ void PlayerActions::actMoveBottomCardToTop() Command_MoveCard cmd; cmdSetBottomCard(cmd); - cmd.set_target_zone("deck"); + cmd.set_target_zone(ZoneNames::DECK); cmd.set_x(0); // top of deck cmd.set_y(0); @@ -756,7 +757,7 @@ void PlayerActions::actDrawBottomCard() Command_MoveCard cmd; cmdSetBottomCard(cmd); - cmd.set_target_zone("hand"); + cmd.set_target_zone(ZoneNames::HAND); cmd.set_x(0); cmd.set_y(0); @@ -782,9 +783,9 @@ void PlayerActions::actDrawBottomCards() defaultNumberBottomCards = number; Command_MoveCard cmd; - cmd.set_start_zone("deck"); + cmd.set_start_zone(ZoneNames::DECK); cmd.set_target_player_id(player->getPlayerInfo()->getId()); - cmd.set_target_zone("hand"); + cmd.set_target_zone(ZoneNames::HAND); cmd.set_x(0); cmd.set_y(0); @@ -803,7 +804,7 @@ void PlayerActions::actMoveBottomCardToPlay() Command_MoveCard cmd; cmdSetBottomCard(cmd); - cmd.set_target_zone("stack"); + cmd.set_target_zone(ZoneNames::STACK); cmd.set_x(-1); cmd.set_y(0); @@ -820,13 +821,13 @@ void PlayerActions::actMoveBottomCardToPlayFaceDown() int lastCard = zone->getCards().size() - 1; Command_MoveCard cmd; - cmd.set_start_zone("deck"); + cmd.set_start_zone(ZoneNames::DECK); auto *cardToMove = cmd.mutable_cards_to_move()->add_card(); cardToMove->set_card_id(lastCard); cardToMove->set_face_down(true); cmd.set_target_player_id(player->getPlayerInfo()->getId()); - cmd.set_target_zone("table"); + cmd.set_target_zone(ZoneNames::TABLE); cmd.set_x(-1); cmd.set_y(0); @@ -836,7 +837,7 @@ void PlayerActions::actMoveBottomCardToPlayFaceDown() void PlayerActions::actUntapAll() { Command_SetCardAttr cmd; - cmd.set_zone("table"); + cmd.set_zone(ZoneNames::TABLE); cmd.set_attribute(AttrTapped); cmd.set_attr_value("0"); @@ -886,7 +887,7 @@ void PlayerActions::actCreateAnotherToken() } Command_CreateToken cmd; - cmd.set_zone("table"); + cmd.set_zone(ZoneNames::TABLE); cmd.set_card_name(lastTokenInfo.name.toStdString()); cmd.set_card_provider_id(lastTokenInfo.providerId.toStdString()); cmd.set_color(lastTokenInfo.color.toStdString()); @@ -1067,7 +1068,7 @@ bool PlayerActions::createRelatedFromRelation(const CardItem *sourceCard, const // move card onto table first if attaching from some other zone // we only do this for AttachTo because cross-zone TransformInto is already handled server-side - if (attachType == CardRelationType::AttachTo && sourceCard->getZone()->getName() != "table") { + if (attachType == CardRelationType::AttachTo && sourceCard->getZone()->getName() != ZoneNames::TABLE) { playCardToTable(sourceCard, false); } @@ -1093,7 +1094,7 @@ void PlayerActions::createCard(const CardItem *sourceCard, // create the token for the related card Command_CreateToken cmd; - cmd.set_zone("table"); + cmd.set_zone(ZoneNames::TABLE); cmd.set_card_name(cardInfo->getName().toStdString()); switch (cardInfo->getColors().size()) { case 0: @@ -1122,12 +1123,12 @@ void PlayerActions::createCard(const CardItem *sourceCard, switch (attachType) { case CardRelationType::DoesNotAttach: - cmd.set_target_zone("table"); + cmd.set_target_zone(ZoneNames::TABLE); cmd.set_card_provider_id(relatedCard.getPrinting().getUuid().toStdString()); break; case CardRelationType::AttachTo: - cmd.set_target_zone("table"); // We currently only support creating tokens on the table + cmd.set_target_zone(ZoneNames::TABLE); // We currently only support creating tokens on the table cmd.set_card_provider_id(relatedCard.getPrinting().getUuid().toStdString()); cmd.set_target_card_id(sourceCard->getId()); cmd.set_target_mode(Command_CreateToken::ATTACH_TO); @@ -1135,7 +1136,7 @@ void PlayerActions::createCard(const CardItem *sourceCard, case CardRelationType::TransformInto: // allow cards to directly transform on stack - cmd.set_zone(sourceCard->getZone()->getName() == "stack" ? "stack" : "table"); + cmd.set_zone(sourceCard->getZone()->getName() == ZoneNames::STACK ? ZoneNames::STACK : ZoneNames::TABLE); // Transform card zone changes are handled server-side cmd.set_target_zone(sourceCard->getZone()->getName().toStdString()); cmd.set_target_card_id(sourceCard->getId()); @@ -1250,7 +1251,7 @@ void PlayerActions::actMoveCardXCardsFromTop() cmd->set_start_zone(startZone.toStdString()); cmd->mutable_cards_to_move()->CopyFrom(idList); cmd->set_target_player_id(player->getPlayerInfo()->getId()); - cmd->set_target_zone("deck"); + cmd->set_target_zone(ZoneNames::DECK); cmd->set_x(number); cmd->set_y(0); commandList.append(cmd); @@ -1639,7 +1640,7 @@ void PlayerActions::playSelectedCards(const bool faceDown) [](const auto &card1, const auto &card2) { return card1->getId() > card2->getId(); }); for (auto &card : selectedCards) { - if (card && !isUnwritableRevealZone(card->getZone()) && card->getZone()->getName() != "table") { + if (card && !isUnwritableRevealZone(card->getZone()) && card->getZone()->getName() != ZoneNames::TABLE) { playCard(card, faceDown); } } @@ -1692,7 +1693,7 @@ void PlayerActions::actRevealHand(int revealToPlayerId) if (revealToPlayerId != -1) { cmd.set_player_id(revealToPlayerId); } - cmd.set_zone_name("hand"); + cmd.set_zone_name(ZoneNames::HAND); sendGameCommand(cmd); } @@ -1703,7 +1704,7 @@ void PlayerActions::actRevealRandomHandCard(int revealToPlayerId) if (revealToPlayerId != -1) { cmd.set_player_id(revealToPlayerId); } - cmd.set_zone_name("hand"); + cmd.set_zone_name(ZoneNames::HAND); cmd.add_card_id(RANDOM_CARD_FROM_ZONE); sendGameCommand(cmd); @@ -1715,7 +1716,7 @@ void PlayerActions::actRevealLibrary(int revealToPlayerId) if (revealToPlayerId != -1) { cmd.set_player_id(revealToPlayerId); } - cmd.set_zone_name("deck"); + cmd.set_zone_name(ZoneNames::DECK); sendGameCommand(cmd); } @@ -1726,7 +1727,7 @@ void PlayerActions::actLendLibrary(int lendToPlayerId) if (lendToPlayerId != -1) { cmd.set_player_id(lendToPlayerId); } - cmd.set_zone_name("deck"); + cmd.set_zone_name(ZoneNames::DECK); cmd.set_grant_write_access(true); sendGameCommand(cmd); @@ -1739,7 +1740,7 @@ void PlayerActions::actRevealTopCards(int revealToPlayerId, int amount) cmd.set_player_id(revealToPlayerId); } - cmd.set_zone_name("deck"); + cmd.set_zone_name(ZoneNames::DECK); cmd.set_top_cards(amount); // backward compatibility: servers before #1051 only permits to reveal the first card cmd.add_card_id(0); @@ -1753,7 +1754,7 @@ void PlayerActions::actRevealRandomGraveyardCard(int revealToPlayerId) if (revealToPlayerId != -1) { cmd.set_player_id(revealToPlayerId); } - cmd.set_zone_name("grave"); + cmd.set_zone_name(ZoneNames::GRAVE); cmd.add_card_id(RANDOM_CARD_FROM_ZONE); sendGameCommand(cmd); } @@ -1816,7 +1817,7 @@ void PlayerActions::cardMenuAction() } case cmClone: { auto *cmd = new Command_CreateToken; - cmd->set_zone("table"); + cmd->set_zone(ZoneNames::TABLE); cmd->set_card_name(card->getName().toStdString()); cmd->set_card_provider_id(card->getProviderId().toStdString()); cmd->set_color(card->getColor().toStdString()); @@ -1858,13 +1859,13 @@ void PlayerActions::cardMenuAction() cmd->set_start_zone(startZone.toStdString()); cmd->mutable_cards_to_move()->CopyFrom(idList); cmd->set_target_player_id(player->getPlayerInfo()->getId()); - cmd->set_target_zone("deck"); + cmd->set_target_zone(ZoneNames::DECK); cmd->set_x(0); cmd->set_y(0); if (idList.card_size() > 1) { auto *scmd = new Command_Shuffle; - scmd->set_zone_name("deck"); + scmd->set_zone_name(ZoneNames::DECK); scmd->set_start(0); scmd->set_end(idList.card_size() - 1); // inclusive, the indexed card at end will be shuffled // Server process events backwards, so... @@ -1880,13 +1881,13 @@ void PlayerActions::cardMenuAction() cmd->set_start_zone(startZone.toStdString()); cmd->mutable_cards_to_move()->CopyFrom(idList); cmd->set_target_player_id(player->getPlayerInfo()->getId()); - cmd->set_target_zone("deck"); + cmd->set_target_zone(ZoneNames::DECK); cmd->set_x(-1); cmd->set_y(0); if (idList.card_size() > 1) { auto *scmd = new Command_Shuffle; - scmd->set_zone_name("deck"); + scmd->set_zone_name(ZoneNames::DECK); scmd->set_start(-idList.card_size()); scmd->set_end(-1); // Server process events backwards, so... @@ -1902,7 +1903,7 @@ void PlayerActions::cardMenuAction() cmd->set_start_zone(startZone.toStdString()); cmd->mutable_cards_to_move()->CopyFrom(idList); cmd->set_target_player_id(player->getPlayerInfo()->getId()); - cmd->set_target_zone("hand"); + cmd->set_target_zone(ZoneNames::HAND); cmd->set_x(0); cmd->set_y(0); commandList.append(cmd); @@ -1914,7 +1915,7 @@ void PlayerActions::cardMenuAction() cmd->set_start_zone(startZone.toStdString()); cmd->mutable_cards_to_move()->CopyFrom(idList); cmd->set_target_player_id(player->getPlayerInfo()->getId()); - cmd->set_target_zone("grave"); + cmd->set_target_zone(ZoneNames::GRAVE); cmd->set_x(0); cmd->set_y(0); commandList.append(cmd); @@ -1926,7 +1927,7 @@ void PlayerActions::cardMenuAction() cmd->set_start_zone(startZone.toStdString()); cmd->mutable_cards_to_move()->CopyFrom(idList); cmd->set_target_player_id(player->getPlayerInfo()->getId()); - cmd->set_target_zone("rfg"); + cmd->set_target_zone(ZoneNames::EXILE); cmd->set_x(0); cmd->set_y(0); commandList.append(cmd); diff --git a/cockatrice/src/game/player/player_event_handler.cpp b/cockatrice/src/game/player/player_event_handler.cpp index 331605918..f4c3840e0 100644 --- a/cockatrice/src/game/player/player_event_handler.cpp +++ b/cockatrice/src/game/player/player_event_handler.cpp @@ -30,6 +30,7 @@ #include #include #include +#include PlayerEventHandler::PlayerEventHandler(Player *_player) : player(_player) { @@ -321,8 +322,8 @@ void PlayerEventHandler::eventMoveCard(const Event_MoveCard &event, const GameEv } player->getPlayerMenu()->updateCardMenu(card); - if (player->getPlayerActions()->isMovingCardsUntil() && startZoneString == "deck" && - targetZone->getName() == "stack") { + if (player->getPlayerActions()->isMovingCardsUntil() && startZoneString == ZoneNames::DECK && + targetZone->getName() == ZoneNames::STACK) { player->getPlayerActions()->moveOneCardUntil(card); } } diff --git a/cockatrice/src/game/zones/logic/card_zone_logic.cpp b/cockatrice/src/game/zones/logic/card_zone_logic.cpp index 1872ba95e..e917e4ad7 100644 --- a/cockatrice/src/game/zones/logic/card_zone_logic.cpp +++ b/cockatrice/src/game/zones/logic/card_zone_logic.cpp @@ -10,6 +10,7 @@ #include #include #include +#include /** * @param _player the player that the zone belongs to @@ -174,9 +175,9 @@ void CardZoneLogic::clearContents() QString CardZoneLogic::getTranslatedName(bool theirOwn, GrammaticalCase gc) const { QString ownerName = player->getPlayerInfo()->getName(); - if (name == "hand") + if (name == ZoneNames::HAND) return (theirOwn ? tr("their hand", "nominative") : tr("%1's hand", "nominative").arg(ownerName)); - else if (name == "deck") + else if (name == ZoneNames::DECK) switch (gc) { case CaseLookAtZone: return (theirOwn ? tr("their library", "look at zone") @@ -192,11 +193,11 @@ QString CardZoneLogic::getTranslatedName(bool theirOwn, GrammaticalCase gc) cons default: return (theirOwn ? tr("their library", "nominative") : tr("%1's library", "nominative").arg(ownerName)); } - else if (name == "grave") + else if (name == ZoneNames::GRAVE) return (theirOwn ? tr("their graveyard", "nominative") : tr("%1's graveyard", "nominative").arg(ownerName)); - else if (name == "rfg") + else if (name == ZoneNames::EXILE) return (theirOwn ? tr("their exile", "nominative") : tr("%1's exile", "nominative").arg(ownerName)); - else if (name == "sb") + else if (name == ZoneNames::SIDEBOARD) switch (gc) { case CaseLookAtZone: return (theirOwn ? tr("their sideboard", "look at zone") diff --git a/cockatrice/src/game/zones/table_zone.cpp b/cockatrice/src/game/zones/table_zone.cpp index a020e4255..b6ac2150b 100644 --- a/cockatrice/src/game/zones/table_zone.cpp +++ b/cockatrice/src/game/zones/table_zone.cpp @@ -15,6 +15,7 @@ #include #include #include +#include const QColor TableZone::BACKGROUND_COLOR = QColor(100, 100, 100); const QColor TableZone::FADE_MASK = QColor(0, 0, 0, 80); @@ -195,7 +196,7 @@ void TableZone::toggleTapped() auto isCardOnTable = [](const QGraphicsItem *item) { if (auto card = qgraphicsitem_cast(item)) { - return card->getZone()->getName() == "table"; + return card->getZone()->getName() == ZoneNames::TABLE; } return false; }; diff --git a/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.cpp b/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.cpp index 00561bef2..f04bcc849 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.cpp +++ b/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.cpp @@ -48,6 +48,7 @@ #include #include #include +#include Server_AbstractPlayer::Server_AbstractPlayer(Server_Game *_game, int _playerId, @@ -190,8 +191,8 @@ shouldDestroyOnMove(const Server_Card *card, const Server_CardZone *startZone, c } // Allow tokens on the stack - if ((startZone->getName() == "table" || startZone->getName() == "stack") && - (targetZone->getName() == "table" || targetZone->getName() == "stack")) { + if ((startZone->getName() == ZoneNames::TABLE || startZone->getName() == ZoneNames::STACK) && + (targetZone->getName() == ZoneNames::TABLE || targetZone->getName() == ZoneNames::STACK)) { return false; } @@ -264,7 +265,7 @@ Response::ResponseCode Server_AbstractPlayer::moveCard(GameEventStorage &ges, } // do not allow attached cards to move around on the table - if (card->getParentCard() && targetzone->getName() == "table") { + if (card->getParentCard() && targetzone->getName() == ZoneNames::TABLE) { continue; } @@ -347,7 +348,7 @@ Response::ResponseCode Server_AbstractPlayer::moveCard(GameEventStorage &ges, newX = targetzone->getFreeGridColumn(newX, yCoord, card->getName(), faceDown); } else { yCoord = 0; - card->resetState(targetzone->getName() == "stack"); + card->resetState(targetzone->getName() == ZoneNames::STACK); } targetzone->insertCard(card, newX, yCoord); diff --git a/libcockatrice_network/libcockatrice/network/server/remote/game/server_game.cpp b/libcockatrice_network/libcockatrice/network/server/remote/game/server_game.cpp index eae23dacf..2224ddb13 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/game/server_game.cpp +++ b/libcockatrice_network/libcockatrice/network/server/remote/game/server_game.cpp @@ -51,6 +51,7 @@ #include #include #include +#include Server_Game::Server_Game(const ServerInfo_User &_creatorInfo, int _gameId, @@ -832,7 +833,7 @@ void Server_Game::returnCardsFromPlayer(GameEventStorage &ges, Server_AbstractPl QMutexLocker locker(&gameMutex); // Return cards to their rightful owners before conceding the game static const QRegularExpression ownerRegex{"Owner: ?([^\n]+)"}; - const auto &playerTable = player->getZones().value("table"); + const auto &playerTable = player->getZones().value(ZoneNames::TABLE); for (const auto &card : playerTable->getCards()) { if (card == nullptr) { continue; @@ -858,7 +859,7 @@ void Server_Game::returnCardsFromPlayer(GameEventStorage &ges, Server_AbstractPl continue; } - const auto &targetZone = otherPlayer->getZones().value("table"); + const auto &targetZone = otherPlayer->getZones().value(ZoneNames::TABLE); if (playerTable == nullptr || targetZone == nullptr) { continue; diff --git a/libcockatrice_network/libcockatrice/network/server/remote/game/server_player.cpp b/libcockatrice_network/libcockatrice/network/server/remote/game/server_player.cpp index e62f861a9..1175e4b57 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/game/server_player.cpp +++ b/libcockatrice_network/libcockatrice/network/server/remote/game/server_player.cpp @@ -47,6 +47,7 @@ #include #include #include +#include Server_Player::Server_Player(Server_Game *_game, int _playerId, @@ -80,15 +81,15 @@ void Server_Player::setupZones() // ------------------------------------------------------------------ // Create zones - auto *deckZone = new Server_CardZone(this, "deck", false, ServerInfo_Zone::HiddenZone); + auto *deckZone = new Server_CardZone(this, ZoneNames::DECK, false, ServerInfo_Zone::HiddenZone); addZone(deckZone); - auto *sbZone = new Server_CardZone(this, "sb", false, ServerInfo_Zone::HiddenZone); + auto *sbZone = new Server_CardZone(this, ZoneNames::SIDEBOARD, false, ServerInfo_Zone::HiddenZone); addZone(sbZone); - addZone(new Server_CardZone(this, "table", true, ServerInfo_Zone::PublicZone)); - addZone(new Server_CardZone(this, "hand", false, ServerInfo_Zone::PrivateZone)); - addZone(new Server_CardZone(this, "stack", false, ServerInfo_Zone::PublicZone)); - addZone(new Server_CardZone(this, "grave", false, ServerInfo_Zone::PublicZone)); - addZone(new Server_CardZone(this, "rfg", false, ServerInfo_Zone::PublicZone)); + addZone(new Server_CardZone(this, ZoneNames::TABLE, true, ServerInfo_Zone::PublicZone)); + addZone(new Server_CardZone(this, ZoneNames::HAND, false, ServerInfo_Zone::PrivateZone)); + addZone(new Server_CardZone(this, ZoneNames::STACK, false, ServerInfo_Zone::PublicZone)); + addZone(new Server_CardZone(this, ZoneNames::GRAVE, false, ServerInfo_Zone::PublicZone)); + addZone(new Server_CardZone(this, ZoneNames::EXILE, false, ServerInfo_Zone::PublicZone)); addCounter(new Server_Counter(0, "life", makeColor(255, 255, 255), 25, game->getStartingLifeTotal())); addCounter(new Server_Counter(1, "w", makeColor(255, 255, 150), 20, 0)); @@ -164,8 +165,8 @@ void Server_Player::addCounter(Server_Counter *counter) Response::ResponseCode Server_Player::drawCards(GameEventStorage &ges, int number) { - Server_CardZone *deckZone = zones.value("deck"); - Server_CardZone *handZone = zones.value("hand"); + Server_CardZone *deckZone = zones.value(ZoneNames::DECK); + Server_CardZone *handZone = zones.value(ZoneNames::HAND); if (deckZone->getCards().size() < number) { number = deckZone->getCards().size(); } @@ -210,7 +211,7 @@ void Server_Player::onCardBeingMoved(GameEventStorage &ges, // "Undo draw" should only remain valid if the just-drawn card stays within the user's hand (e.g., they only // reorder their hand). If a just-drawn card leaves the hand then remove cards before it from the list // (Ignore the case where the card is currently being un-drawn.) - if (startzone->getName() == "hand" && targetzone->getName() != "hand" && !undoingDraw) { + if (startzone->getName() == ZoneNames::HAND && targetzone->getName() != ZoneNames::HAND && !undoingDraw) { int index = lastDrawList.lastIndexOf(card->getId()); if (index != -1) { lastDrawList.erase(lastDrawList.begin(), lastDrawList.begin() + index); @@ -326,11 +327,11 @@ Server_Player::cmdShuffle(const Command_Shuffle &cmd, ResponseContainer & /*rc*/ return Response::RespContextError; } - if (cmd.has_zone_name() && cmd.zone_name() != "deck") { + if (cmd.has_zone_name() && cmd.zone_name() != ZoneNames::DECK) { return Response::RespFunctionNotAllowed; } - Server_CardZone *zone = zones.value("deck"); + Server_CardZone *zone = zones.value(ZoneNames::DECK); if (!zone) { return Response::RespNameNotFound; } @@ -357,8 +358,8 @@ Server_Player::cmdMulligan(const Command_Mulligan &cmd, ResponseContainer & /*rc return Response::RespContextError; } - Server_CardZone *hand = zones.value("hand"); - Server_CardZone *_deck = zones.value("deck"); + Server_CardZone *hand = zones.value(ZoneNames::HAND); + Server_CardZone *_deck = zones.value(ZoneNames::DECK); int number = cmd.number(); if (!hand->getCards().isEmpty()) { @@ -414,8 +415,8 @@ Server_Player::cmdUndoDraw(const Command_UndoDraw & /*cmd*/, ResponseContainer & Response::ResponseCode retVal; auto *cardToMove = new CardToMove; cardToMove->set_card_id(lastDrawList.takeLast()); - retVal = moveCard(ges, zones.value("hand"), QList() << cardToMove, zones.value("deck"), 0, 0, - false, true); + retVal = moveCard(ges, zones.value(ZoneNames::HAND), QList() << cardToMove, + zones.value(ZoneNames::DECK), 0, 0, false, true); delete cardToMove; return retVal; diff --git a/libcockatrice_utility/CMakeLists.txt b/libcockatrice_utility/CMakeLists.txt index 0575c260f..c0c7d8cc9 100644 --- a/libcockatrice_utility/CMakeLists.txt +++ b/libcockatrice_utility/CMakeLists.txt @@ -10,8 +10,13 @@ set(UTILITY_SOURCES libcockatrice/utility/expression.cpp libcockatrice/utility/l ) set(UTILITY_HEADERS - libcockatrice/utility/color.h libcockatrice/utility/expression.h libcockatrice/utility/levenshtein.h - libcockatrice/utility/macros.h libcockatrice/utility/passwordhasher.h libcockatrice/utility/trice_limits.h + libcockatrice/utility/color.h + libcockatrice/utility/expression.h + libcockatrice/utility/levenshtein.h + libcockatrice/utility/macros.h + libcockatrice/utility/passwordhasher.h + libcockatrice/utility/trice_limits.h + libcockatrice/utility/zone_names.h ) add_library(libcockatrice_utility STATIC ${UTILITY_SOURCES} ${UTILITY_HEADERS}) diff --git a/libcockatrice_utility/libcockatrice/utility/zone_names.h b/libcockatrice_utility/libcockatrice/utility/zone_names.h new file mode 100644 index 000000000..d1463de6a --- /dev/null +++ b/libcockatrice_utility/libcockatrice/utility/zone_names.h @@ -0,0 +1,19 @@ +#ifndef ZONE_NAMES_H +#define ZONE_NAMES_H + +namespace ZoneNames +{ +// Protocol-level zone identifiers shared between client and server. +// These must match exactly across all components. + +constexpr const char *TABLE = "table"; +constexpr const char *GRAVE = "grave"; +constexpr const char *EXILE = "rfg"; // "removed from game" +constexpr const char *HAND = "hand"; +constexpr const char *DECK = "deck"; +constexpr const char *SIDEBOARD = "sb"; +constexpr const char *STACK = "stack"; + +} // namespace ZoneNames + +#endif // ZONE_NAMES_H From 20ad9af989ffd2caace45170fc01af46fd43d818 Mon Sep 17 00:00:00 2001 From: RickyRister <42636155+RickyRister@users.noreply.github.com> Date: Thu, 12 Mar 2026 11:00:32 -0700 Subject: [PATCH 20/20] [CacheSettings] Refactor country list creation (#6687) --- .../src/client/settings/cache_settings.cpp | 266 +----------------- 1 file changed, 15 insertions(+), 251 deletions(-) diff --git a/cockatrice/src/client/settings/cache_settings.cpp b/cockatrice/src/client/settings/cache_settings.cpp index 30093fd52..e7a5d114e 100644 --- a/cockatrice/src/client/settings/cache_settings.cpp +++ b/cockatrice/src/client/settings/cache_settings.cpp @@ -1115,257 +1115,21 @@ void SettingsCache::setClientVersion(const QString &_clientVersion) QStringList SettingsCache::getCountries() const { - static QStringList countries = QStringList() << "ad" - << "ae" - << "af" - << "ag" - << "ai" - << "al" - << "am" - << "ao" - << "aq" - << "ar" - << "as" - << "at" - << "au" - << "aw" - << "ax" - << "az" - << "ba" - << "bb" - << "bd" - << "be" - << "bf" - << "bg" - << "bh" - << "bi" - << "bj" - << "bl" - << "bm" - << "bn" - << "bo" - << "bq" - << "br" - << "bs" - << "bt" - << "bv" - << "bw" - << "by" - << "bz" - << "ca" - << "cc" - << "cd" - << "cf" - << "cg" - << "ch" - << "ci" - << "ck" - << "cl" - << "cm" - << "cn" - << "co" - << "cr" - << "cu" - << "cv" - << "cw" - << "cx" - << "cy" - << "cz" - << "de" - << "dj" - << "dk" - << "dm" - << "do" - << "dz" - << "ec" - << "ee" - << "eg" - << "eh" - << "er" - << "es" - << "et" - << "eu" - << "fi" - << "fj" - << "fk" - << "fm" - << "fo" - << "fr" - << "ga" - << "gb" - << "gd" - << "ge" - << "gf" - << "gg" - << "gh" - << "gi" - << "gl" - << "gm" - << "gn" - << "gp" - << "gq" - << "gr" - << "gs" - << "gt" - << "gu" - << "gw" - << "gy" - << "hk" - << "hm" - << "hn" - << "hr" - << "ht" - << "hu" - << "id" - << "ie" - << "il" - << "im" - << "in" - << "io" - << "iq" - << "ir" - << "is" - << "it" - << "je" - << "jm" - << "jo" - << "jp" - << "ke" - << "kg" - << "kh" - << "ki" - << "km" - << "kn" - << "kp" - << "kr" - << "kw" - << "ky" - << "kz" - << "la" - << "lb" - << "lc" - << "li" - << "lk" - << "lr" - << "ls" - << "lt" - << "lu" - << "lv" - << "ly" - << "ma" - << "mc" - << "md" - << "me" - << "mf" - << "mg" - << "mh" - << "mk" - << "ml" - << "mm" - << "mn" - << "mo" - << "mp" - << "mq" - << "mr" - << "ms" - << "mt" - << "mu" - << "mv" - << "mw" - << "mx" - << "my" - << "mz" - << "na" - << "nc" - << "ne" - << "nf" - << "ng" - << "ni" - << "nl" - << "no" - << "np" - << "nr" - << "nu" - << "nz" - << "om" - << "pa" - << "pe" - << "pf" - << "pg" - << "ph" - << "pk" - << "pl" - << "pm" - << "pn" - << "pr" - << "ps" - << "pt" - << "pw" - << "py" - << "qa" - << "re" - << "ro" - << "rs" - << "ru" - << "rw" - << "sa" - << "sb" - << "sc" - << "sd" - << "se" - << "sg" - << "sh" - << "si" - << "sj" - << "sk" - << "sl" - << "sm" - << "sn" - << "so" - << "sr" - << "ss" - << "st" - << "sv" - << "sx" - << "sy" - << "sz" - << "tc" - << "td" - << "tf" - << "tg" - << "th" - << "tj" - << "tk" - << "tl" - << "tm" - << "tn" - << "to" - << "tr" - << "tt" - << "tv" - << "tw" - << "tz" - << "ua" - << "ug" - << "um" - << "us" - << "uy" - << "uz" - << "va" - << "vc" - << "ve" - << "vg" - << "vi" - << "vn" - << "vu" - << "wf" - << "ws" - << "xk" - << "ye" - << "yt" - << "za" - << "zm" - << "zw"; + static const QStringList countries = { + "ad", "ae", "af", "ag", "ai", "al", "am", "ao", "aq", "ar", "as", "at", "au", "aw", "ax", "az", "ba", "bb", + "bd", "be", "bf", "bg", "bh", "bi", "bj", "bl", "bm", "bn", "bo", "bq", "br", "bs", "bt", "bv", "bw", "by", + "bz", "ca", "cc", "cd", "cf", "cg", "ch", "ci", "ck", "cl", "cm", "cn", "co", "cr", "cu", "cv", "cw", "cx", + "cy", "cz", "de", "dj", "dk", "dm", "do", "dz", "ec", "ee", "eg", "eh", "er", "es", "et", "eu", "fi", "fj", + "fk", "fm", "fo", "fr", "ga", "gb", "gd", "ge", "gf", "gg", "gh", "gi", "gl", "gm", "gn", "gp", "gq", "gr", + "gs", "gt", "gu", "gw", "gy", "hk", "hm", "hn", "hr", "ht", "hu", "id", "ie", "il", "im", "in", "io", "iq", + "ir", "is", "it", "je", "jm", "jo", "jp", "ke", "kg", "kh", "ki", "km", "kn", "kp", "kr", "kw", "ky", "kz", + "la", "lb", "lc", "li", "lk", "lr", "ls", "lt", "lu", "lv", "ly", "ma", "mc", "md", "me", "mf", "mg", "mh", + "mk", "ml", "mm", "mn", "mo", "mp", "mq", "mr", "ms", "mt", "mu", "mv", "mw", "mx", "my", "mz", "na", "nc", + "ne", "nf", "ng", "ni", "nl", "no", "np", "nr", "nu", "nz", "om", "pa", "pe", "pf", "pg", "ph", "pk", "pl", + "pm", "pn", "pr", "ps", "pt", "pw", "py", "qa", "re", "ro", "rs", "ru", "rw", "sa", "sb", "sc", "sd", "se", + "sg", "sh", "si", "sj", "sk", "sl", "sm", "sn", "so", "sr", "ss", "st", "sv", "sx", "sy", "sz", "tc", "td", + "tf", "tg", "th", "tj", "tk", "tl", "tm", "tn", "to", "tr", "tt", "tv", "tw", "tz", "ua", "ug", "um", "us", + "uy", "uz", "va", "vc", "ve", "vg", "vi", "vn", "vu", "wf", "ws", "xk", "ye", "yt", "za", "zm", "zw"}; return countries; }