Compare commits

...

4 commits

Author SHA1 Message Date
BruebachL
cbfd286908
[Game][Player] Move dialog creation out of player_actions and into player_dialogs (#6946)
Some checks are pending
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 15 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Docker Image / amd64 & arm64 (push) Waiting to run
* [Game][Player] Split Player into PlayerLogic/PlayerGraphicsItem

Took 4 minutes

Took 48 seconds

Took 2 minutes

* Drop early return.

Took 1 hour 13 minutes


Took 2 minutes

Took 1 minute

Took 24 seconds

* [Game][Player] Split Player into PlayerLogic/PlayerGraphicsItem

Took 4 minutes

Took 58 seconds

* [Game][Menus] Make Menus accept PlayerGraphicsItem instead of PlayerLogic

Took 7 minutes

Took 4 minutes

Took 9 seconds

Took 2 minutes


Took 5 minutes

Took 58 seconds

* [Game][Player] Split Player into PlayerLogic/PlayerGraphicsItem

Took 4 minutes

Took 2 minutes

* [Game][Menus] Make Menus accept PlayerGraphicsItem instead of PlayerLogic

Took 7 minutes


Took 1 minute

Took 57 seconds

* [Game][Player] Move dialog creation out of player_actions and into player_dialogs

Took 3 minutes

Took 1 second

* Fix typo.

Took 5 minutes

* Addressed comments.

Took 16 minutes

Took 11 seconds

* Reintroduce clearCardsToDelete check.

Took 3 minutes

* Capture cards before semaphore.

Took 1 minute

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-06-09 08:22:59 +02:00
BruebachL
487bb84b6f
[Game][Menus] Make Menus accept PlayerGraphicsItem instead of PlayerLogic (#6945)
* [Game][Player] Split Player into PlayerLogic/PlayerGraphicsItem

Took 4 minutes

Took 58 seconds


Took 2 minutes

* [Game][Menus] Make Menus accept PlayerGraphicsItem instead of PlayerLogic

Took 7 minutes

Took 4 minutes

Took 9 seconds

Took 2 minutes


Took 5 minutes

Took 58 seconds

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-06-09 08:07:06 +02:00
BruebachL
9e03f82616
[Game][Player] Split Player into PlayerLogic/PlayerGraphicsItem (#6944)
* [Game][Player] Split Player into PlayerLogic/PlayerGraphicsItem

Took 4 minutes

Took 48 seconds

* Drop early return.

Took 1 hour 13 minutes


Took 2 minutes

Took 1 minute

* Delete player view.

Took 37 seconds

* Restore card counter color in menu.

Took 5 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-06-09 08:05:39 +02:00
Christo
e674a39b87
Fix #6952: prevent deck loss when saving to a full disk (#6978)
* Fix #6952: prevent deck loss when saving to a full disk

DeckLoader::saveToFile() opened the target with QFile in WriteOnly mode,
which truncates the existing file to 0 bytes the moment it is opened. The
serializers (DeckList::saveToFile_Native/_Plain) always return true and the
result of flush() was ignored, so a write that failed part-way -- e.g.
because the disk was full -- left a 0-byte file behind yet was still
reported (and logged) as a successful save. The same truncate-then-write
pattern in updateLastLoadedTimestamp() could destroy a deck on load.

Switch both paths to QSaveFile, which writes to a temporary file and only
atomically replaces the target if commit() succeeds. On any write or flush
failure commit() returns false, the original deck is left untouched, and
the failure is logged instead of being reported as success.

* Use QSaveFile in convertToCockatriceFormat() too

convertToCockatriceFormat() had the same data-loss pattern: QFile WriteOnly
truncated the .cod, saveToFile_Native() always returns true, and the original
file was then removed unconditionally -- so a full disk during conversion wrote
a 0-byte .cod and then deleted the source deck.

Switch to QSaveFile (write + atomic commit), remove the original only after a
successful commit, and move the format check ahead of the file open so an
already-Cockatrice or unsupported deck never truncates or deletes anything.

Raised in review by ZeldaZach.
2026-06-09 07:54:01 +02:00
44 changed files with 1339 additions and 704 deletions

View file

@ -100,6 +100,7 @@ set(cockatrice_SOURCES
src/game/player/menu/utility_menu.cpp
src/game/player/player_actions.cpp
src/game/player/player_area.cpp
src/game/player/player_dialogs.cpp
src/game/player/player_event_handler.cpp
src/game/player/player_graphics_item.cpp
src/game/player/player_info.cpp

View file

@ -44,6 +44,11 @@ signals:
void deleteCardInfoPopup(QString cardName);
void sigPixmapUpdated();
void cardShiftClicked(QString cardName);
void rightClicked(AbstractCardItem *card, QPoint screenPos);
void playSelected(AbstractCardItem *card);
void playSelectedFaceDown(AbstractCardItem *card);
void hideSelected(AbstractCardItem *card);
void selectionChanged(AbstractCardItem *card, bool selected);
public:
enum

View file

@ -40,7 +40,7 @@ void CardItem::prepareDelete()
{
if (owner != nullptr) {
if (owner->getGame()->getActiveCard() == this) {
owner->getPlayerMenu()->updateCardMenu(nullptr);
emit owner->requestCardMenuUpdate(nullptr);
owner->getGame()->setActiveCard(nullptr);
}
owner = nullptr;
@ -399,8 +399,11 @@ void CardItem::playCard(bool faceDown)
emit tz->toggleTapped();
} else {
if (SettingsCache::instance().getClickPlaysAllSelected()) {
faceDown ? state->getZone()->getPlayer()->getPlayerActions()->actPlayFacedown()
: state->getZone()->getPlayer()->getPlayerActions()->actPlay();
if (faceDown) {
emit playSelectedFaceDown(this);
} else {
emit playSelected(this);
}
} else {
state->getZone()->getPlayer()->getPlayerActions()->playCard(this, faceDown);
}
@ -460,7 +463,7 @@ void CardItem::handleClickedToPlay(bool shiftHeld)
{
if (isUnwritableRevealZone(state->getZone())) {
if (SettingsCache::instance().getClickPlaysAllSelected()) {
state->getZone()->getPlayer()->getPlayerActions()->actHide();
emit hideSelected(this);
} else {
state->getZone()->removeCard(this);
}
@ -471,17 +474,12 @@ void CardItem::handleClickedToPlay(bool shiftHeld)
void CardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (event->button() == Qt::RightButton) {
if (owner != nullptr) {
owner->getGame()->setActiveCard(this);
if (QMenu *cardMenu = owner->getPlayerMenu()->updateCardMenu(this)) {
cardMenu->popup(event->screenPos());
return;
}
}
} else if ((event->modifiers() != Qt::AltModifier) && (event->button() == Qt::LeftButton) &&
(!SettingsCache::instance().getDoubleClickToPlay())) {
if (event->button() == Qt::RightButton && owner != nullptr) {
emit rightClicked(this, event->screenPos());
return;
}
if ((event->modifiers() != Qt::AltModifier) && (event->button() == Qt::LeftButton) &&
(!SettingsCache::instance().getDoubleClickToPlay())) {
handleClickedToPlay(event->modifiers().testFlag(Qt::ShiftModifier));
}
@ -531,14 +529,14 @@ bool CardItem::animationEvent()
QVariant CardItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
if ((change == ItemSelectedHasChanged) && owner != nullptr) {
if (value == true) {
owner->getGame()->setActiveCard(this);
owner->getPlayerMenu()->updateCardMenu(this);
} else if (owner->getGameScene()->selectedItems().isEmpty()) {
bool selected = value.toBool();
owner->getGame()->setActiveCard(nullptr);
owner->getPlayerMenu()->updateCardMenu(nullptr);
if (selected) {
owner->getGame()->setActiveCard(this);
}
emit selectionChanged(this, selected);
}
return AbstractCardItem::itemChange(change, value);
}

View file

@ -4,8 +4,10 @@
#include "../game_graphics/zones/select_zone.h"
#include "../game_graphics/zones/view_zone.h"
#include "../game_graphics/zones/view_zone_widget.h"
#include "abstract_game.h"
#include "board/card_item.h"
#include "phases_toolbar.h"
#include "player/player_actions.h"
#include "player/player_graphics_item.h"
#include "player/player_logic.h"
@ -72,6 +74,80 @@ QList<CardItem *> GameScene::selectedCards() const
return selectedCards;
}
void GameScene::onCardSelectionChanged(AbstractCardItem *abstractCard, bool selected)
{
CardItem *card = qobject_cast<CardItem *>(abstractCard);
if (!card || !card->getOwner()) {
return;
}
auto *owner = card->getOwner();
if (selected) {
owner->requestCardMenuUpdate(card);
return;
}
if (selectedItems().isEmpty()) {
owner->getGame()->setActiveCard(nullptr);
owner->requestCardMenuUpdate(nullptr);
}
}
void GameScene::onCardRightClicked(AbstractCardItem *abstractCard, QPoint screenPos)
{
auto *card = qobject_cast<CardItem *>(abstractCard);
if (!card) {
return;
}
if (!card->getOwner()) {
return;
}
auto *view = playerViews.value(card->getOwner()->getPlayerInfo()->getId());
if (!view) {
return;
}
card->getOwner()->getGame()->setActiveCard(card);
if (auto *menu = view->getPlayerMenu()->updateCardMenu(card)) {
menu->popup(screenPos);
}
}
void GameScene::playSelected(AbstractCardItem *card)
{
if (!card) {
return;
}
if (!card->getOwner()) {
return;
}
card->getOwner()->getPlayerActions()->actPlay(selectedCards());
}
void GameScene::playSelectedFaceDown(AbstractCardItem *card)
{
if (!card) {
return;
}
if (!card->getOwner()) {
return;
}
card->getOwner()->getPlayerActions()->actPlayFacedown(selectedCards());
}
void GameScene::hideSelected(AbstractCardItem *card)
{
if (!card) {
return;
}
if (!card->getOwner()) {
return;
}
card->getOwner()->getPlayerActions()->actHide(selectedCards());
}
/**
* @brief Adds a player to the scene and stores their graphics item.
* @param player Player to add.
@ -82,9 +158,11 @@ void GameScene::addPlayer(PlayerLogic *player)
{
qCInfo(GameScenePlayerAdditionRemovalLog) << "GameScene::addPlayer name=" << player->getPlayerInfo()->getName();
playerViews.insert(player->getPlayerInfo()->getId(), player->getGraphicsItem());
addItem(player->getGraphicsItem());
connect(player->getGraphicsItem(), &PlayerGraphicsItem::sizeChanged, this, &GameScene::rearrange);
auto *view = new PlayerGraphicsItem(player);
playerViews.insert(player->getPlayerInfo()->getId(), view);
addItem(view);
connect(view, &PlayerGraphicsItem::sizeChanged, this, &GameScene::rearrange);
connect(player, &PlayerLogic::concededChanged, this, [this](int id, bool conceded) {
if (conceded) {
@ -93,6 +171,8 @@ void GameScene::addPlayer(PlayerLogic *player)
rearrange();
});
connect(player, &PlayerLogic::requestZoneViewToggle, this, &GameScene::toggleZoneView);
connect(player, &PlayerLogic::requestRevealedZoneView, this, &GameScene::addRevealedZoneView);
connect(player, &PlayerLogic::arrowDeleted, this, &GameScene::deleteArrow);
connect(player, &PlayerLogic::arrowCreateRequested, this, &GameScene::addArrow);
connect(player, &PlayerLogic::arrowDeleteRequested, this, &GameScene::requestArrowDeletion);
@ -123,6 +203,7 @@ void GameScene::removePlayer(PlayerLogic *player)
}
auto *view = playerViews.take(player->getPlayerInfo()->getId());
removeItem(view);
view->deleteLater();
rearrange();
}
@ -204,7 +285,7 @@ QList<PlayerLogic *> GameScene::collectActivePlayers(int &firstPlayerIndex) cons
bool firstPlayerFound = false;
for (auto *pgItem : playerViews.values()) {
PlayerLogic *p = pgItem->getPlayer();
PlayerLogic *p = pgItem->getLogic();
if (p && !p->getConceded()) {
activePlayers.append(p);
if (!firstPlayerFound && p->getPlayerInfo()->getLocal()) {
@ -275,12 +356,12 @@ QSizeF GameScene::computeSceneSizeAndPlayerLayout(const QList<PlayerLogic *> &pl
for (int j = 0; j < rowsInColumn; ++j) {
PlayerLogic *player = playersIter.next();
if (col == 0) {
playersByColumn[col].prepend(player->getGraphicsItem());
playersByColumn[col].prepend(playerViews.value(player->getPlayerInfo()->getId()));
} else {
playersByColumn[col].append(player->getGraphicsItem());
playersByColumn[col].append(playerViews.value(player->getPlayerInfo()->getId()));
}
auto *pgItem = player->getGraphicsItem();
auto *pgItem = playerViews.value(player->getPlayerInfo()->getId());
thisColumnHeight += pgItem->boundingRect().height() + playerAreaSpacing;
columnWidth[col] = std::max(columnWidth[col], (int)pgItem->boundingRect().width());
}
@ -375,7 +456,8 @@ void GameScene::addArrow(QSharedPointer<ArrowData> data)
return;
}
auto *startZone = startView->getPlayer()->getZones().value(data->startZone);
PlayerLogic *startLogic = startView->getLogic();
auto *startZone = startLogic->getZones().value(data->startZone);
if (!startZone) {
return;
}
@ -389,7 +471,8 @@ void GameScene::addArrow(QSharedPointer<ArrowData> data)
if (data->isPlayerTargeted()) {
targetItem = targetView->getPlayerTarget();
} else {
if (auto *zone = targetView->getPlayer()->getZones().value(data->targetZone)) {
auto *zone = targetView->getLogic()->getZones().value(data->targetZone);
if (zone) {
targetItem = zone->getCard(data->targetCardId);
}
}

View file

@ -97,6 +97,16 @@ public:
*/
void removePlayer(PlayerLogic *player);
QMap<int, PlayerGraphicsItem *> getPlayers() const
{
return playerViews;
}
PlayerGraphicsItem *viewForPlayer(int playerId)
{
return playerViews.value(playerId);
}
/**
* @brief Adjusts the global rotation offset for player layout.
* @param rotationAdjustment Number of positions to rotate.
@ -182,6 +192,11 @@ public:
void stopRubberBand();
public slots:
void onCardSelectionChanged(AbstractCardItem *card, bool selected);
void onCardRightClicked(AbstractCardItem *card, QPoint screenPos);
void playSelected(AbstractCardItem *card);
void playSelectedFaceDown(AbstractCardItem *card);
void hideSelected(AbstractCardItem *card);
/** @brief Toggles a zone view for a player. */
void toggleZoneView(PlayerLogic *player, const QString &zoneName, int numberCards, bool isReversed = false);

View file

@ -6,6 +6,7 @@
#include "../../zones/view_zone_logic.h"
#include "../card_menu_action_type.h"
#include "../player_actions.h"
#include "../player_graphics_item.h"
#include "../player_logic.h"
#include "move_menu.h"
#include "pt_menu.h"
@ -31,93 +32,92 @@ static QIcon createCircleIcon(const QColor &color)
return QIcon(pixmap);
}
CardMenu::CardMenu(PlayerLogic *_player, const CardItem *_card, bool _shortcutsActive)
template <typename Slot>
static QAction *makeAction(QObject *parent, Slot &&slot, bool checkable = false, bool checked = false)
{
auto *a = new QAction(parent);
a->setCheckable(checkable);
if (checkable) {
a->setChecked(checked);
}
QObject::connect(a, &QAction::triggered, parent, std::forward<Slot>(slot));
return a;
}
CardMenu::CardMenu(PlayerGraphicsItem *_player, const CardItem *_card, bool _shortcutsActive)
: player(_player), card(_card), shortcutsActive(_shortcutsActive)
{
auto playerActions = player->getPlayerActions();
const QList<PlayerLogic *> &players = player->getGame()->getPlayerManager()->getPlayers().values();
const QList<PlayerLogic *> &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
for (auto playerToAdd : players) {
if (playerToAdd == player) {
if (playerToAdd == player->getLogic()) {
continue;
}
playersInfo.append(qMakePair(playerToAdd->getPlayerInfo()->getName(), playerToAdd->getPlayerInfo()->getId()));
}
connect(player->getGame()->getPlayerManager(), &PlayerManager::playerRemoved, this, &CardMenu::removePlayer);
connect(player->getLogic()->getGame()->getPlayerManager(), &PlayerManager::playerRemoved, this,
&CardMenu::removePlayer);
aTap = new QAction(this);
aTap->setData(cmTap);
connect(aTap, &QAction::triggered, playerActions, &PlayerActions::cardMenuAction);
aDoesntUntap = new QAction(this);
aDoesntUntap->setData(cmDoesntUntap);
aDoesntUntap->setCheckable(true);
aDoesntUntap->setChecked(card != nullptr && card->getDoesntUntap());
connect(aDoesntUntap, &QAction::triggered, playerActions, &PlayerActions::cardMenuAction);
auto *actions = player->getLogic()->getPlayerActions();
auto *gameScene = player->getGameScene();
// Single selection resolver used by all lambdas — called at trigger time
auto sel = [gameScene]() { return gameScene->selectedCards(); };
// Unified dispatcher for card menu actions
auto invoke = [actions, sel](CardMenuActionType type) {
return [actions, sel, type]() { actions->cardMenuAction(sel(), type); };
};
// Actions using invoke (type dispatch, need selection)
aTap = makeAction(this, invoke(cmTap));
aDoesntUntap = makeAction(this, invoke(cmDoesntUntap), /*checkable=*/true, card && card->getDoesntUntap());
aFlip = makeAction(this, invoke(cmFlip));
aPeek = makeAction(this, invoke(cmPeek));
aClone = makeAction(this, invoke(cmClone));
// Actions using selection directly
aUnattach = makeAction(this, [actions, sel]() { actions->actUnattach(sel()); });
aSetAnnotation = makeAction(this, [actions, sel]() { actions->actRequestSetAnnotationDialog(sel()); });
aPlay = makeAction(this, [actions, sel]() { actions->actPlay(sel()); });
aPlayFacedown = makeAction(this, [actions, sel]() { actions->actPlayFacedown(sel()); });
aHide = makeAction(this, [actions, sel]() { actions->actHide(sel()); });
aReduceLifeByPower = makeAction(this, [actions, sel]() { actions->actReduceLifeByPower(sel()); });
// Actions that use activeCard, not selection — direct connection
aAttach = new QAction(this);
connect(aAttach, &QAction::triggered, playerActions, &PlayerActions::actAttach);
aUnattach = new QAction(this);
connect(aUnattach, &QAction::triggered, playerActions, &PlayerActions::actUnattach);
aDrawArrow = new QAction(this);
connect(aDrawArrow, &QAction::triggered, playerActions, &PlayerActions::actDrawArrow);
aSetAnnotation = new QAction(this);
connect(aSetAnnotation, &QAction::triggered, playerActions, &PlayerActions::actSetAnnotation);
aFlip = new QAction(this);
aFlip->setData(cmFlip);
connect(aFlip, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction);
aPeek = new QAction(this);
aPeek->setData(cmPeek);
connect(aPeek, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction);
aClone = new QAction(this);
aClone->setData(cmClone);
connect(aClone, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction);
aSelectAll = new QAction(this);
connect(aSelectAll, &QAction::triggered, playerActions, &PlayerActions::actSelectAll);
aSelectRow = new QAction(this);
connect(aSelectRow, &QAction::triggered, playerActions, &PlayerActions::actSelectRow);
aSelectColumn = new QAction(this);
connect(aSelectColumn, &QAction::triggered, playerActions, &PlayerActions::actSelectColumn);
aReduceLifeByPower = new QAction(this);
connect(aReduceLifeByPower, &QAction::triggered, playerActions, &PlayerActions::actReduceLifeByPower);
aPlay = new QAction(this);
connect(aPlay, &QAction::triggered, playerActions, &PlayerActions::actPlay);
aHide = new QAction(this);
connect(aHide, &QAction::triggered, playerActions, &PlayerActions::actHide);
aPlayFacedown = new QAction(this);
connect(aPlayFacedown, &QAction::triggered, playerActions, &PlayerActions::actPlayFacedown);
connect(aAttach, &QAction::triggered, actions, &PlayerActions::actAttach);
connect(aDrawArrow, &QAction::triggered, actions, &PlayerActions::actDrawArrow);
connect(aSelectAll, &QAction::triggered, actions, &PlayerActions::actSelectAll);
connect(aSelectRow, &QAction::triggered, actions, &PlayerActions::actSelectRow);
connect(aSelectColumn, &QAction::triggered, actions, &PlayerActions::actSelectColumn);
aRevealToAll = new QAction(this);
mCardCounters = new QMenu;
// Card counters
for (int i = 0; i < 6; ++i) {
QColor color = SettingsCache::instance().cardCounters().color(i);
QIcon circleIcon = createCircleIcon(color);
auto *tempAddCounter = new QAction(this);
tempAddCounter->setIconVisibleInMenu(true);
tempAddCounter->setIcon(circleIcon);
auto *addAction = makeAction(this, [actions, sel, i]() { actions->actAddCardCounter(sel(), i); });
addAction->setIcon(circleIcon);
aAddCounter.append(addAction);
auto *tempRemoveCounter = new QAction(this);
tempRemoveCounter->setIconVisibleInMenu(true);
tempRemoveCounter->setIcon(circleIcon);
auto *removeAction = makeAction(this, [actions, sel, i]() { actions->actRemoveCardCounter(sel(), i); });
removeAction->setIcon(circleIcon);
aRemoveCounter.append(removeAction);
auto *tempSetCounter = new QAction(this);
tempSetCounter->setIconVisibleInMenu(true);
tempSetCounter->setIcon(circleIcon);
aAddCounter.append(tempAddCounter);
aRemoveCounter.append(tempRemoveCounter);
aSetCounter.append(tempSetCounter);
connect(tempAddCounter, &QAction::triggered, playerActions,
[playerActions, i] { playerActions->actAddCardCounter(i); });
connect(tempRemoveCounter, &QAction::triggered, playerActions,
[playerActions, i] { playerActions->actRemoveCardCounter(i); });
connect(tempSetCounter, &QAction::triggered, playerActions,
[playerActions, i] { playerActions->actSetCardCounter(i); });
auto *setAction = makeAction(this, [actions, sel, i]() { actions->actRequestSetCardCounterDialog(sel(), i); });
setAction->setIcon(circleIcon);
aSetCounter.append(setAction);
}
setShortcutsActive();
@ -129,7 +129,7 @@ CardMenu::CardMenu(PlayerLogic *_player, const CardItem *_card, bool _shortcutsA
}
bool revealedCard = false;
bool writeableCard = player->getPlayerInfo()->getLocalOrJudge();
bool writeableCard = player->getLogic()->getPlayerInfo()->getLocalOrJudge();
if (auto *view = qobject_cast<ZoneViewZoneLogic *>(card->getZone())) {
if (view->getRevealZone()) {
if (view->getWriteableRevealZone()) {
@ -313,7 +313,9 @@ void CardMenu::createHandOrCustomZoneMenu(bool canModifyCard)
initContextualPlayersMenu(revealMenu, aRevealToAll);
connect(revealMenu, &QMenu::triggered, player->getPlayerActions(), &PlayerActions::actReveal);
connect(revealMenu, &QMenu::triggered, this, [this](QAction *action) {
player->getLogic()->getPlayerActions()->actReveal(player->getGameScene()->selectedCards(), action);
});
addSeparator();
addAction(aClone);
@ -398,8 +400,7 @@ void CardMenu::addRelatedCardView()
QAction *viewCard = viewRelatedCards->addAction(relatedCardName);
Q_UNUSED(viewCard);
connect(viewCard, &QAction::triggered, player->getGame(),
[this, cardRef] { player->getGame()->getTab()->viewCardInfo(cardRef); });
connect(viewCard, &QAction::triggered, this, [this, cardRef] { emit cardInfoRequested(cardRef); });
}
}
@ -461,7 +462,8 @@ void CardMenu::addRelatedCardActions()
auto *createRelated = new QAction(text, this);
createRelated->setData(QVariant(index++));
connect(createRelated, &QAction::triggered, player->getPlayerActions(), &PlayerActions::actCreateRelatedCard);
connect(createRelated, &QAction::triggered, player->getLogic()->getPlayerActions(),
&PlayerActions::actCreateRelatedCard);
addAction(createRelated);
}
@ -470,7 +472,7 @@ void CardMenu::addRelatedCardActions()
createRelatedCards->setShortcuts(
SettingsCache::instance().shortcuts().getShortcut("Player/aCreateRelatedTokens"));
}
connect(createRelatedCards, &QAction::triggered, player->getPlayerActions(),
connect(createRelatedCards, &QAction::triggered, player->getLogic()->getPlayerActions(),
&PlayerActions::actCreateAllRelatedCards);
addAction(createRelatedCards);
}

View file

@ -8,15 +8,20 @@
#define COCKATRICE_CARD_MENU_H
#include <QMenu>
#include <libcockatrice/utility/card_ref.h>
class CardItem;
class PlayerGraphicsItem;
class PlayerLogic;
class CardMenu : public QMenu
{
Q_OBJECT
signals:
void cardInfoRequested(const CardRef &cardRef);
public:
explicit CardMenu(PlayerLogic *player, const CardItem *card, bool shortcutsActive);
explicit CardMenu(PlayerGraphicsItem *player, const CardItem *card, bool shortcutsActive);
void removePlayer(PlayerLogic *playerToRemove);
void createTableMenu(bool canModifyCard);
void createStackMenu(bool canModifyCard);
@ -41,7 +46,7 @@ public:
QList<QAction *> aAddCounter, aSetCounter, aRemoveCounter;
private:
PlayerLogic *player;
PlayerGraphicsItem *player;
const CardItem *card;
QList<QPair<QString, int>> playersInfo;
bool shortcutsActive;

View file

@ -2,12 +2,12 @@
#include "../player_logic.h"
CustomZoneMenu::CustomZoneMenu(PlayerLogic *_player) : player(_player)
CustomZoneMenu::CustomZoneMenu(PlayerGraphicsItem *_player) : player(_player)
{
menuAction()->setVisible(false);
connect(player, &PlayerLogic::clearCustomZonesMenu, this, &CustomZoneMenu::clearCustomZonesMenu);
connect(player, &PlayerLogic::addViewCustomZoneActionToCustomZoneMenu, this,
connect(player->getLogic(), &PlayerLogic::clearCustomZonesMenu, this, &CustomZoneMenu::clearCustomZonesMenu);
connect(player->getLogic(), &PlayerLogic::addViewCustomZoneActionToCustomZoneMenu, this,
&CustomZoneMenu::addViewCustomZoneActionToCustomZoneMenu);
retranslateUi();
@ -17,7 +17,7 @@ void CustomZoneMenu::retranslateUi()
{
setTitle(tr("C&ustom Zones"));
if (player->getPlayerInfo()->getLocalOrJudge()) {
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
for (auto aViewZone : actions()) {
aViewZone->setText(tr("View custom zone '%1'").arg(aViewZone->data().toString()));
@ -37,5 +37,5 @@ void CustomZoneMenu::addViewCustomZoneActionToCustomZoneMenu(QString zoneName)
QAction *aViewZone = addAction(tr("View custom zone '%1'").arg(zoneName));
aViewZone->setData(zoneName);
connect(aViewZone, &QAction::triggered, this,
[zoneName, this]() { player->getGameScene()->toggleZoneView(player, zoneName, -1); });
[zoneName, this]() { player->getGameScene()->toggleZoneView(player->getLogic(), zoneName, -1); });
}

View file

@ -11,12 +11,12 @@
#include <QMenu>
class PlayerLogic;
class PlayerGraphicsItem;
class CustomZoneMenu : public QMenu, public AbstractPlayerComponent
{
Q_OBJECT
public:
explicit CustomZoneMenu(PlayerLogic *player);
explicit CustomZoneMenu(PlayerGraphicsItem *player);
void retranslateUi() override;
void setShortcutsActive() override
{
@ -26,7 +26,7 @@ public:
}
private:
PlayerLogic *player;
PlayerGraphicsItem *player;
private slots:
void clearCustomZonesMenu();
void addViewCustomZoneActionToCustomZoneMenu(QString zoneName);

View file

@ -8,14 +8,14 @@
#include <QMenu>
#include <libcockatrice/utility/zone_names.h>
GraveyardMenu::GraveyardMenu(PlayerLogic *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
GraveyardMenu::GraveyardMenu(PlayerGraphicsItem *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
{
createMoveActions();
createViewActions();
addAction(aViewGraveyard);
if (player->getPlayerInfo()->local || player->getPlayerInfo()->judge) {
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
mRevealRandomGraveyardCard = addMenu(QString());
connect(mRevealRandomGraveyardCard, &QMenu::aboutToShow, this,
&GraveyardMenu::populateRevealRandomMenuWithActivePlayers);
@ -36,9 +36,9 @@ GraveyardMenu::GraveyardMenu(PlayerLogic *_player, QWidget *parent) : TearOffMen
void GraveyardMenu::createMoveActions()
{
auto grave = player->getGraveZone();
auto grave = player->getLogic()->getGraveZone();
if (player->getPlayerInfo()->local || player->getPlayerInfo()->judge) {
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
aMoveGraveToTopLibrary = new QAction(this);
aMoveGraveToTopLibrary->setData(QList<QVariant>() << ZoneNames::DECK << 0);
@ -60,7 +60,7 @@ void GraveyardMenu::createMoveActions()
void GraveyardMenu::createViewActions()
{
PlayerActions *playerActions = player->getPlayerActions();
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
aViewGraveyard = new QAction(this);
connect(aViewGraveyard, &QAction::triggered, playerActions, &PlayerActions::actViewGraveyard);
@ -76,9 +76,9 @@ void GraveyardMenu::populateRevealRandomMenuWithActivePlayers()
mRevealRandomGraveyardCard->addSeparator();
const auto &players = player->getGame()->getPlayerManager()->getPlayers().values();
const auto &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) {
if (other == player) {
if (other == player->getLogic()) {
continue;
}
QAction *a = mRevealRandomGraveyardCard->addAction(other->getPlayerInfo()->getName());
@ -90,7 +90,7 @@ void GraveyardMenu::populateRevealRandomMenuWithActivePlayers()
void GraveyardMenu::onRevealRandomTriggered()
{
if (auto *a = qobject_cast<QAction *>(sender())) {
player->getPlayerActions()->actRevealRandomGraveyardCard(a->data().toInt());
player->getLogic()->getPlayerActions()->actRevealRandomGraveyardCard(a->data().toInt());
}
}
@ -100,7 +100,7 @@ void GraveyardMenu::retranslateUi()
aViewGraveyard->setText(tr("&View graveyard"));
if (player->getPlayerInfo()->getLocalOrJudge()) {
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
moveGraveMenu->setTitle(tr("&Move graveyard to..."));
aMoveGraveToTopLibrary->setText(tr("&Top of library"));
aMoveGraveToBottomLibrary->setText(tr("&Bottom of library"));

View file

@ -13,7 +13,7 @@
#include <QAction>
#include <QMenu>
class PlayerLogic;
class PlayerGraphicsItem;
class GraveyardMenu : public TearOffMenu, public AbstractPlayerComponent
{
Q_OBJECT
@ -21,7 +21,7 @@ signals:
void newPlayerActionCreated(QAction *action);
public:
explicit GraveyardMenu(PlayerLogic *player, QWidget *parent = nullptr);
explicit GraveyardMenu(PlayerGraphicsItem *player, QWidget *parent = nullptr);
void createMoveActions();
void createViewActions();
void populateRevealRandomMenuWithActivePlayers();
@ -40,7 +40,7 @@ public:
QAction *aMoveGraveToRfg = nullptr;
private:
PlayerLogic *player;
PlayerGraphicsItem *player;
};
#endif // COCKATRICE_GRAVE_MENU_H

View file

@ -5,16 +5,20 @@
#include "../../../game_graphics/zones/hand_zone.h"
#include "../../abstract_game.h"
#include "../player_actions.h"
#include "../player_graphics_item.h"
#include "../player_logic.h"
#include <QAction>
#include <QMenu>
#include <libcockatrice/utility/zone_names.h>
HandMenu::HandMenu(PlayerLogic *_player, PlayerActions *actions, QWidget *parent) : TearOffMenu(parent), player(_player)
HandMenu::HandMenu(PlayerGraphicsItem *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
{
if (player->getPlayerInfo()->local || player->getPlayerInfo()->judge) {
auto *actions = player->getLogic()->getPlayerActions();
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
aViewHand = new QAction(this);
connect(aViewHand, &QAction::triggered, actions, &PlayerActions::actViewHand);
addAction(aViewHand);
@ -58,7 +62,7 @@ HandMenu::HandMenu(PlayerLogic *_player, PlayerActions *actions, QWidget *parent
addSeparator();
aMulligan = new QAction(this);
connect(aMulligan, &QAction::triggered, actions, &PlayerActions::actMulligan);
connect(aMulligan, &QAction::triggered, actions, &PlayerActions::actRequestMulliganDialog);
addAction(aMulligan);
// Mulligan same size
@ -75,7 +79,7 @@ HandMenu::HandMenu(PlayerLogic *_player, PlayerActions *actions, QWidget *parent
mMoveHandMenu = addTearOffMenu(QString());
if (player->getPlayerInfo()->local || player->getPlayerInfo()->judge) {
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
aMoveHandToTopLibrary = new QAction(this);
aMoveHandToTopLibrary->setData(QList<QVariant>() << ZoneNames::DECK << 0);
aMoveHandToBottomLibrary = new QAction(this);
@ -85,7 +89,7 @@ HandMenu::HandMenu(PlayerLogic *_player, PlayerActions *actions, QWidget *parent
aMoveHandToRfg = new QAction(this);
aMoveHandToRfg->setData(QList<QVariant>() << ZoneNames::EXILE << 0);
auto hand = player->getHandZone();
auto hand = player->getLogic()->getHandZone();
connect(aMoveHandToTopLibrary, &QAction::triggered, hand, &HandZoneLogic::moveAllToZone);
connect(aMoveHandToBottomLibrary, &QAction::triggered, hand, &HandZoneLogic::moveAllToZone);
@ -107,7 +111,7 @@ void HandMenu::retranslateUi()
{
setTitle(tr("&Hand"));
if (player->getPlayerInfo()->getLocalOrJudge()) {
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
aViewHand->setText(tr("&View hand"));
mSortHand->setTitle(tr("Sort hand by..."));
@ -166,9 +170,9 @@ void HandMenu::populateRevealHandMenuWithActivePlayers()
mRevealHand->addSeparator();
const auto &players = player->getGame()->getPlayerManager()->getPlayers().values();
const auto &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) {
if (other == player) {
if (other == player->getLogic()) {
continue;
}
QAction *a = mRevealHand->addAction(other->getPlayerInfo()->getName());
@ -185,9 +189,9 @@ void HandMenu::populateRevealRandomHandCardMenuWithActivePlayers()
mRevealRandomHandCard->addSeparator();
const auto &players = player->getGame()->getPlayerManager()->getPlayers().values();
const auto &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) {
if (other == player) {
if (other == player->getLogic()) {
continue;
}
QAction *a = mRevealRandomHandCard->addAction(other->getPlayerInfo()->getName());
@ -204,7 +208,7 @@ void HandMenu::onRevealHandTriggered()
}
const int targetId = action->data().toInt();
player->getPlayerActions()->actRevealHand(targetId);
player->getLogic()->getPlayerActions()->actRevealHand(targetId);
}
void HandMenu::onRevealRandomHandCardTriggered()
@ -215,5 +219,5 @@ void HandMenu::onRevealRandomHandCardTriggered()
}
const int targetId = action->data().toInt();
player->getPlayerActions()->actRevealRandomHandCard(targetId);
player->getLogic()->getPlayerActions()->actRevealRandomHandCard(targetId);
}

View file

@ -13,7 +13,7 @@
#include <QAction>
#include <QMenu>
class PlayerLogic;
class PlayerGraphicsItem;
class PlayerActions;
class HandMenu : public TearOffMenu, public AbstractPlayerComponent
@ -21,7 +21,7 @@ class HandMenu : public TearOffMenu, public AbstractPlayerComponent
Q_OBJECT
public:
HandMenu(PlayerLogic *player, PlayerActions *actions, QWidget *parent = nullptr);
HandMenu(PlayerGraphicsItem *player, QWidget *parent = nullptr);
QMenu *revealHandMenu() const
{
@ -43,7 +43,7 @@ private slots:
void onRevealRandomHandCardTriggered();
private:
PlayerLogic *player;
PlayerGraphicsItem *player;
QAction *aViewHand = nullptr;
QAction *aMulligan = nullptr;

View file

@ -8,9 +8,10 @@
#include "../player_logic.h"
#include <QAction>
#include <QGraphicsView>
#include <QMenu>
LibraryMenu::LibraryMenu(PlayerLogic *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
LibraryMenu::LibraryMenu(PlayerGraphicsItem *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
{
createDrawActions();
createShuffleActions();
@ -75,8 +76,8 @@ LibraryMenu::LibraryMenu(PlayerLogic *_player, QWidget *parent) : TearOffMenu(pa
bottomLibraryMenu->addSeparator();
bottomLibraryMenu->addAction(aShuffleBottomCards);
connect(player, &PlayerLogic::resetTopCardMenuActions, this, &LibraryMenu::resetTopCardMenuActions);
connect(player, &PlayerLogic::deckChanged, this, &LibraryMenu::enableOpenInDeckEditorAction);
connect(player->getLogic(), &PlayerLogic::resetTopCardMenuActions, this, &LibraryMenu::resetTopCardMenuActions);
connect(player->getLogic(), &PlayerLogic::deckChanged, this, &LibraryMenu::enableOpenInDeckEditorAction);
retranslateUi();
}
@ -94,41 +95,41 @@ void LibraryMenu::resetTopCardMenuActions()
void LibraryMenu::createDrawActions()
{
PlayerActions *playerActions = player->getPlayerActions();
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
if (player->getPlayerInfo()->local || player->getPlayerInfo()->judge) {
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
aDrawCard = new QAction(this);
connect(aDrawCard, &QAction::triggered, playerActions, &PlayerActions::actDrawCard);
aDrawCards = new QAction(this);
connect(aDrawCards, &QAction::triggered, playerActions, &PlayerActions::actDrawCards);
connect(aDrawCards, &QAction::triggered, playerActions, &PlayerActions::actRequestDrawCardsDialog);
aUndoDraw = new QAction(this);
connect(aUndoDraw, &QAction::triggered, playerActions, &PlayerActions::actUndoDraw);
aDrawBottomCard = new QAction(this);
connect(aDrawBottomCard, &QAction::triggered, playerActions, &PlayerActions::actDrawBottomCard);
aDrawBottomCards = new QAction(this);
connect(aDrawBottomCards, &QAction::triggered, playerActions, &PlayerActions::actDrawBottomCards);
connect(aDrawBottomCards, &QAction::triggered, playerActions, &PlayerActions::actRequestDrawBottomCardsDialog);
}
}
void LibraryMenu::createShuffleActions()
{
PlayerActions *playerActions = player->getPlayerActions();
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
if (player->getPlayerInfo()->local || player->getPlayerInfo()->judge) {
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
aShuffle = new QAction(this);
connect(aShuffle, &QAction::triggered, playerActions, &PlayerActions::actShuffle);
aShuffleTopCards = new QAction(this);
connect(aShuffleTopCards, &QAction::triggered, playerActions, &PlayerActions::actShuffleTop);
connect(aShuffleTopCards, &QAction::triggered, playerActions, &PlayerActions::actRequestShuffleTopDialog);
aShuffleBottomCards = new QAction(this);
connect(aShuffleBottomCards, &QAction::triggered, playerActions, &PlayerActions::actShuffleBottom);
connect(aShuffleBottomCards, &QAction::triggered, playerActions, &PlayerActions::actRequestShuffleBottomDialog);
}
}
void LibraryMenu::createMoveActions()
{
PlayerActions *playerActions = player->getPlayerActions();
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
if (player->getPlayerInfo()->local || player->getPlayerInfo()->judge) {
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
aMoveTopToPlay = new QAction(this);
connect(aMoveTopToPlay, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardToPlay);
aMoveTopToPlayFaceDown = new QAction(this);
@ -149,7 +150,8 @@ void LibraryMenu::createMoveActions()
connect(aMoveTopCardsToExileFaceDown, &QAction::triggered, playerActions,
&PlayerActions::actMoveTopCardsToExileFaceDown);
aMoveTopCardsUntil = new QAction(this);
connect(aMoveTopCardsUntil, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardsUntil);
connect(aMoveTopCardsUntil, &QAction::triggered, playerActions,
&PlayerActions::actRequestMoveTopCardsUntilDialog);
aMoveTopCardToBottom = new QAction(this);
connect(aMoveTopCardToBottom, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardToBottom);
@ -181,16 +183,16 @@ void LibraryMenu::createMoveActions()
void LibraryMenu::createViewActions()
{
PlayerActions *playerActions = player->getPlayerActions();
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
if (player->getPlayerInfo()->local || player->getPlayerInfo()->judge) {
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
aViewLibrary = new QAction(this);
connect(aViewLibrary, &QAction::triggered, playerActions, &PlayerActions::actViewLibrary);
aViewTopCards = new QAction(this);
connect(aViewTopCards, &QAction::triggered, playerActions, &PlayerActions::actViewTopCards);
connect(aViewTopCards, &QAction::triggered, playerActions, &PlayerActions::actRequestViewTopCardsDialog);
aViewBottomCards = new QAction(this);
connect(aViewBottomCards, &QAction::triggered, playerActions, &PlayerActions::actViewBottomCards);
connect(aViewBottomCards, &QAction::triggered, playerActions, &PlayerActions::actRequestViewBottomCardsDialog);
aAlwaysRevealTopCard = new QAction(this);
aAlwaysRevealTopCard->setCheckable(true);
connect(aAlwaysRevealTopCard, &QAction::triggered, playerActions, &PlayerActions::actAlwaysRevealTopCard);
@ -207,7 +209,7 @@ void LibraryMenu::retranslateUi()
{
setTitle(tr("&Library"));
if (player->getPlayerInfo()->getLocalOrJudge()) {
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
aViewLibrary->setText(tr("&View library"));
aViewTopCards->setText(tr("View &top cards of library..."));
aViewBottomCards->setText(tr("View bottom cards of library..."));
@ -263,9 +265,9 @@ void LibraryMenu::populateRevealLibraryMenuWithActivePlayers()
mRevealLibrary->addSeparator();
const auto &players = player->getGame()->getPlayerManager()->getPlayers().values();
const auto &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) {
if (other == player) {
if (other == player->getLogic()) {
continue;
}
QAction *a = mRevealLibrary->addAction(other->getPlayerInfo()->getName());
@ -278,9 +280,9 @@ void LibraryMenu::populateLendLibraryMenuWithActivePlayers()
{
mLendLibrary->clear();
const auto &players = player->getGame()->getPlayerManager()->getPlayers().values();
const auto &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) {
if (other == player) {
if (other == player->getLogic()) {
continue;
}
QAction *a = mLendLibrary->addAction(other->getPlayerInfo()->getName());
@ -299,9 +301,9 @@ void LibraryMenu::populateRevealTopCardMenuWithActivePlayers()
mRevealTopCard->addSeparator();
const auto &players = player->getGame()->getPlayerManager()->getPlayers().values();
const auto &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) {
if (other == player) {
if (other == player->getLogic()) {
continue;
}
QAction *a = mRevealTopCard->addAction(other->getPlayerInfo()->getName());
@ -313,27 +315,33 @@ void LibraryMenu::populateRevealTopCardMenuWithActivePlayers()
void LibraryMenu::onRevealLibraryTriggered()
{
if (auto *a = qobject_cast<QAction *>(sender())) {
player->getPlayerActions()->actRevealLibrary(a->data().toInt());
player->getLogic()->getPlayerActions()->actRevealLibrary(a->data().toInt());
}
}
void LibraryMenu::onLendLibraryTriggered()
{
if (auto *a = qobject_cast<QAction *>(sender())) {
player->getPlayerActions()->actLendLibrary(a->data().toInt());
player->getLogic()->getPlayerActions()->actLendLibrary(a->data().toInt());
}
}
void LibraryMenu::onRevealTopCardTriggered()
{
QWidget *parent = nullptr;
if (auto *view = player->scene() ? player->scene()->views().value(0) : nullptr) {
parent = view->window();
}
if (auto *a = qobject_cast<QAction *>(sender())) {
int deckSize = player->getDeckZone()->getCards().size();
bool ok;
int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Reveal top cards of library"),
int deckSize = player->getLogic()->getDeckZone()->getCards().size();
bool ok = true;
int number = QInputDialog::getInt(parent, tr("Reveal top cards of library"),
tr("Number of cards: (max. %1)").arg(deckSize), defaultNumberTopCards, 1,
deckSize, 1, &ok);
if (ok) {
player->getPlayerActions()->actRevealTopCards(a->data().toInt(), number);
player->getLogic()->getPlayerActions()->actRevealTopCards(a->data().toInt(), number);
defaultNumberTopCards = number;
}
}

View file

@ -13,6 +13,7 @@
#include <QAction>
#include <QMenu>
class PlayerGraphicsItem;
class PlayerLogic;
class PlayerActions;
@ -24,7 +25,7 @@ public slots:
void resetTopCardMenuActions();
public:
LibraryMenu(PlayerLogic *player, QWidget *parent = nullptr);
LibraryMenu(PlayerGraphicsItem *player, QWidget *parent = nullptr);
void createDrawActions();
void createShuffleActions();
void createMoveActions();
@ -111,7 +112,7 @@ public:
int defaultNumberTopCards = 1;
private:
PlayerLogic *player;
PlayerGraphicsItem *player;
};
#endif // COCKATRICE_LIBRARY_MENU_H

View file

@ -4,7 +4,7 @@
#include "../player_actions.h"
#include "../player_logic.h"
MoveMenu::MoveMenu(PlayerLogic *player) : QMenu(tr("Move to"))
MoveMenu::MoveMenu(PlayerGraphicsItem *player) : QMenu(tr("Move to"))
{
aMoveToTopLibrary = new QAction(this);
aMoveToTopLibrary->setData(cmMoveToTopLibrary);
@ -20,14 +20,22 @@ MoveMenu::MoveMenu(PlayerLogic *player) : QMenu(tr("Move to"))
aMoveToExile = new QAction(this);
aMoveToExile->setData(cmMoveToExile);
connect(aMoveToTopLibrary, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction);
connect(aMoveToBottomLibrary, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction);
connect(aMoveToXfromTopOfLibrary, &QAction::triggered, player->getPlayerActions(),
&PlayerActions::actMoveCardXCardsFromTop);
connect(aMoveToTable, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction);
connect(aMoveToHand, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction);
connect(aMoveToGraveyard, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction);
connect(aMoveToExile, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction);
auto *actions = player->getLogic()->getPlayerActions();
auto invoke = [player](CardMenuActionType type) {
return [type, player]() {
player->getLogic()->getPlayerActions()->cardMenuAction(player->getGameScene()->selectedCards(), type);
};
};
connect(aMoveToTopLibrary, &QAction::triggered, actions, invoke(cmMoveToTopLibrary));
connect(aMoveToBottomLibrary, &QAction::triggered, actions, invoke(cmMoveToBottomLibrary));
connect(aMoveToXfromTopOfLibrary, &QAction::triggered, actions,
&PlayerActions::actRequestMoveCardXCardsFromTopDialog);
connect(aMoveToTable, &QAction::triggered, actions, invoke(cmMoveToTable));
connect(aMoveToHand, &QAction::triggered, actions, invoke(cmMoveToHand));
connect(aMoveToGraveyard, &QAction::triggered, actions, invoke(cmMoveToGraveyard));
connect(aMoveToExile, &QAction::triggered, actions, invoke(cmMoveToExile));
addAction(aMoveToTopLibrary);
addAction(aMoveToXfromTopOfLibrary);

View file

@ -8,13 +8,13 @@
#define COCKATRICE_MOVE_MENU_H
#include <QMenu>
class PlayerLogic;
class PlayerGraphicsItem;
class MoveMenu : public QMenu
{
Q_OBJECT
public:
explicit MoveMenu(PlayerLogic *player);
explicit MoveMenu(PlayerGraphicsItem *player);
void setShortcutsActive();
void retranslateUi();

View file

@ -10,12 +10,15 @@
#include <libcockatrice/protocol/pb/command_reveal_cards.pb.h>
PlayerMenu::PlayerMenu(PlayerLogic *_player) : QObject(_player), player(_player)
PlayerMenu::PlayerMenu(PlayerGraphicsItem *_player) : QObject(_player), player(_player)
{
connect(player->getLogic(), &PlayerLogic::requestCardMenuUpdate, this, &PlayerMenu::updateCardMenu);
connect(this, &PlayerMenu::cardInfoRequested, player, &PlayerGraphicsItem::cardInfoRequested);
playerMenu = new TearOffMenu();
if (player->getPlayerInfo()->getLocalOrJudge()) {
handMenu = addManagedMenu<HandMenu>(player, player->getPlayerActions(), playerMenu);
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
handMenu = addManagedMenu<HandMenu>(player, playerMenu);
libraryMenu = addManagedMenu<LibraryMenu>(player, playerMenu);
} else {
handMenu = nullptr;
@ -25,7 +28,7 @@ PlayerMenu::PlayerMenu(PlayerLogic *_player) : QObject(_player), player(_player)
graveMenu = addManagedMenu<GraveyardMenu>(player, playerMenu);
rfgMenu = addManagedMenu<RfgMenu>(player, playerMenu);
if (player->getPlayerInfo()->getLocalOrJudge()) {
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
sideboardMenu = addManagedMenu<SideboardMenu>(player, playerMenu);
customZonesMenu = addManagedMenu<CustomZoneMenu>(player);
playerMenu->addSeparator();
@ -40,7 +43,7 @@ PlayerMenu::PlayerMenu(PlayerLogic *_player) : QObject(_player), player(_player)
utilityMenu = nullptr;
}
if (player->getPlayerInfo()->getLocal()) {
if (player->getLogic()->getPlayerInfo()->getLocal()) {
sayMenu = addManagedMenu<SayMenu>(player);
} else {
sayMenu = nullptr;
@ -55,13 +58,13 @@ PlayerMenu::PlayerMenu(PlayerLogic *_player) : QObject(_player), player(_player)
void PlayerMenu::setMenusForGraphicItems()
{
player->getGraphicsItem()->getTableZoneGraphicsItem()->setMenu(playerMenu);
player->getGraphicsItem()->getGraveyardZoneGraphicsItem()->setMenu(graveMenu, graveMenu->aViewGraveyard);
player->getGraphicsItem()->getRfgZoneGraphicsItem()->setMenu(rfgMenu, rfgMenu->aViewRfg);
if (player->getPlayerInfo()->getLocalOrJudge()) {
player->getGraphicsItem()->getHandZoneGraphicsItem()->setMenu(handMenu);
player->getGraphicsItem()->getDeckZoneGraphicsItem()->setMenu(libraryMenu, libraryMenu->aDrawCard);
player->getGraphicsItem()->getSideboardZoneGraphicsItem()->setMenu(sideboardMenu);
player->getTableZoneGraphicsItem()->setMenu(playerMenu);
player->getGraveyardZoneGraphicsItem()->setMenu(graveMenu, graveMenu->aViewGraveyard);
player->getRfgZoneGraphicsItem()->setMenu(rfgMenu, rfgMenu->aViewRfg);
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
player->getHandZoneGraphicsItem()->setMenu(handMenu);
player->getDeckZoneGraphicsItem()->setMenu(libraryMenu, libraryMenu->aDrawCard);
player->getSideboardZoneGraphicsItem()->setMenu(sideboardMenu);
}
}
@ -74,12 +77,14 @@ QMenu *PlayerMenu::updateCardMenu(const CardItem *card)
// If is spectator (as spectators don't need card menus), return
// only update the menu if the card is actually selected
if ((player->getGame()->getPlayerManager()->isSpectator() && !player->getGame()->getPlayerManager()->isJudge()) ||
player->getGame()->getActiveCard() != card) {
if ((player->getLogic()->getGame()->getPlayerManager()->isSpectator() &&
!player->getLogic()->getGame()->getPlayerManager()->isJudge()) ||
player->getLogic()->getGame()->getActiveCard() != card) {
return nullptr;
}
QMenu *menu = new CardMenu(player, card, shortcutsActive);
CardMenu *menu = new CardMenu(player, card, shortcutsActive);
connect(menu, &CardMenu::cardInfoRequested, this, &PlayerMenu::cardInfoRequested);
emit cardMenuUpdated(menu);
return menu;
@ -87,7 +92,7 @@ QMenu *PlayerMenu::updateCardMenu(const CardItem *card)
void PlayerMenu::retranslateUi()
{
playerMenu->setTitle(tr("Player \"%1\"").arg(player->getPlayerInfo()->getName()));
playerMenu->setTitle(tr("Player \"%1\"").arg(player->getLogic()->getPlayerInfo()->getName()));
for (auto *component : managedComponents) {
component->retranslateUi();
@ -104,7 +109,8 @@ void PlayerMenu::refreshShortcuts()
{
if (shortcutsActive) {
// Judges get access to every player's menus but only want shortcuts to be set for their own.
if (player->getPlayerInfo()->getLocalOrJudge() && !player->getPlayerInfo()->getLocal()) {
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge() &&
!player->getLogic()->getPlayerInfo()->getLocal()) {
setShortcutsInactive();
} else {
setShortcutsActive();

View file

@ -8,7 +8,6 @@
#define COCKATRICE_PLAYER_MENU_H
#include "../../../interface/widgets/menus/tearoff_menu.h"
#include "../player_logic.h"
#include "custom_zone_menu.h"
#include "grave_menu.h"
#include "hand_menu.h"
@ -23,29 +22,31 @@
#include <QObject>
class CardItem;
class CardMenu;
class PlayerGraphicsItem;
class PlayerMenu : public QObject
{
Q_OBJECT
signals:
void cardMenuUpdated(QMenu *cardMenu);
void cardMenuUpdated(CardMenu *cardMenu);
void cardInfoRequested(const CardRef &cardRef);
void shortcutsActivated();
void shortcutsDeactivated();
void retranslateRequested();
public slots:
void setMenusForGraphicItems();
QMenu *updateCardMenu(const CardItem *card);
private slots:
void refreshShortcuts();
public:
explicit PlayerMenu(PlayerLogic *player);
explicit PlayerMenu(PlayerGraphicsItem *player);
/** @brief Retranslate all user-visible strings. Called on language change. */
void retranslateUi();
QMenu *updateCardMenu(const CardItem *card);
[[nodiscard]] QMenu *getPlayerMenu() const
{
return playerMenu;
@ -77,7 +78,7 @@ public:
void setShortcutsInactive();
private:
PlayerLogic *player;
PlayerGraphicsItem *player;
TearOffMenu *playerMenu;
QMenu *countersMenu;
HandMenu *handMenu;

View file

@ -3,30 +3,40 @@
#include "../player_actions.h"
#include "../player_logic.h"
PtMenu::PtMenu(PlayerLogic *player) : QMenu(tr("Power / toughness"))
PtMenu::PtMenu(PlayerGraphicsItem *player) : QMenu(tr("Power / toughness"))
{
PlayerActions *playerActions = player->getPlayerActions();
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
aIncP = new QAction(this);
connect(aIncP, &QAction::triggered, playerActions, &PlayerActions::actIncP);
connect(aIncP, &QAction::triggered, playerActions,
[player, playerActions] { playerActions->actIncP(player->getGameScene()->selectedCards()); });
aDecP = new QAction(this);
connect(aDecP, &QAction::triggered, playerActions, &PlayerActions::actDecP);
connect(aDecP, &QAction::triggered, playerActions,
[player, playerActions] { playerActions->actDecP(player->getGameScene()->selectedCards()); });
aIncT = new QAction(this);
connect(aIncT, &QAction::triggered, playerActions, &PlayerActions::actIncT);
connect(aIncT, &QAction::triggered, playerActions,
[player, playerActions] { playerActions->actIncT(player->getGameScene()->selectedCards()); });
aDecT = new QAction(this);
connect(aDecT, &QAction::triggered, playerActions, &PlayerActions::actDecT);
connect(aDecT, &QAction::triggered, playerActions,
[player, playerActions] { playerActions->actDecT(player->getGameScene()->selectedCards()); });
aIncPT = new QAction(this);
connect(aIncPT, &QAction::triggered, playerActions, [playerActions] { playerActions->actIncPT(); });
connect(aIncPT, &QAction::triggered, playerActions,
[player, playerActions] { playerActions->actIncPT(player->getGameScene()->selectedCards()); });
aDecPT = new QAction(this);
connect(aDecPT, &QAction::triggered, playerActions, &PlayerActions::actDecPT);
connect(aDecPT, &QAction::triggered, playerActions,
[player, playerActions] { playerActions->actDecPT(player->getGameScene()->selectedCards()); });
aFlowP = new QAction(this);
connect(aFlowP, &QAction::triggered, playerActions, &PlayerActions::actFlowP);
connect(aFlowP, &QAction::triggered, playerActions,
[player, playerActions] { playerActions->actFlowP(player->getGameScene()->selectedCards()); });
aFlowT = new QAction(this);
connect(aFlowT, &QAction::triggered, playerActions, &PlayerActions::actFlowT);
connect(aFlowT, &QAction::triggered, playerActions,
[player, playerActions] { playerActions->actFlowT(player->getGameScene()->selectedCards()); });
aSetPT = new QAction(this);
connect(aSetPT, &QAction::triggered, playerActions, &PlayerActions::actSetPT);
connect(aSetPT, &QAction::triggered, playerActions,
[player, playerActions] { playerActions->actRequestSetPTDialog(player->getGameScene()->selectedCards()); });
aResetPT = new QAction(this);
connect(aResetPT, &QAction::triggered, playerActions, &PlayerActions::actResetPT);
connect(aResetPT, &QAction::triggered, playerActions,
[player, playerActions] { playerActions->actResetPT(player->getGameScene()->selectedCards()); });
addAction(aIncP);
addAction(aDecP);

View file

@ -8,14 +8,14 @@
#define COCKATRICE_PT_MENU_H
#include <QMenu>
class PlayerLogic;
class PlayerGraphicsItem;
class PtMenu : public QMenu
{
Q_OBJECT
public:
explicit PtMenu(PlayerLogic *player);
explicit PtMenu(PlayerGraphicsItem *player);
void retranslateUi();
void setShortcutsActive();

View file

@ -5,14 +5,14 @@
#include <libcockatrice/utility/zone_names.h>
RfgMenu::RfgMenu(PlayerLogic *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
RfgMenu::RfgMenu(PlayerGraphicsItem *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
{
createMoveActions();
createViewActions();
addAction(aViewRfg);
if (player->getPlayerInfo()->getLocalOrJudge()) {
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
addSeparator();
moveRfgMenu = addTearOffMenu(QString());
moveRfgMenu->addAction(aMoveRfgToTopLibrary);
@ -28,8 +28,8 @@ RfgMenu::RfgMenu(PlayerLogic *_player, QWidget *parent) : TearOffMenu(parent), p
void RfgMenu::createMoveActions()
{
if (player->getPlayerInfo()->getLocalOrJudge()) {
auto rfg = player->getRfgZone();
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
auto rfg = player->getLogic()->getRfgZone();
aMoveRfgToTopLibrary = new QAction(this);
aMoveRfgToTopLibrary->setData(QList<QVariant>() << ZoneNames::DECK << 0);
@ -49,7 +49,7 @@ void RfgMenu::createMoveActions()
void RfgMenu::createViewActions()
{
PlayerActions *playerActions = player->getPlayerActions();
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
aViewRfg = new QAction(this);
connect(aViewRfg, &QAction::triggered, playerActions, &PlayerActions::actViewRfg);
@ -61,7 +61,7 @@ void RfgMenu::retranslateUi()
aViewRfg->setText(tr("&View exile"));
if (player->getPlayerInfo()->getLocalOrJudge()) {
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
moveRfgMenu->setTitle(tr("&Move exile to..."));
aMoveRfgToTopLibrary->setText(tr("&Top of library"));
aMoveRfgToBottomLibrary->setText(tr("&Bottom of library"));

View file

@ -13,12 +13,12 @@
#include <QAction>
#include <QMenu>
class PlayerLogic;
class PlayerGraphicsItem;
class RfgMenu : public TearOffMenu, public AbstractPlayerComponent
{
Q_OBJECT
public:
explicit RfgMenu(PlayerLogic *player, QWidget *parent = nullptr);
explicit RfgMenu(PlayerGraphicsItem *player, QWidget *parent = nullptr);
void createMoveActions();
void createViewActions();
void retranslateUi() override;
@ -38,7 +38,7 @@ public:
QAction *aMoveRfgToGrave = nullptr;
private:
PlayerLogic *player;
PlayerGraphicsItem *player;
};
#endif // COCKATRICE_RFG_MENU_H

View file

@ -4,7 +4,7 @@
#include "../player_actions.h"
#include "../player_logic.h"
SayMenu::SayMenu(PlayerLogic *_player) : player(_player)
SayMenu::SayMenu(PlayerGraphicsItem *_player) : player(_player)
{
connect(&SettingsCache::instance().messages(), &MessageSettings::messageMacrosChanged, this, &SayMenu::initSayMenu);
initSayMenu();
@ -44,7 +44,7 @@ void SayMenu::initSayMenu()
for (int i = 0; i < count; ++i) {
auto *newAction = new QAction(SettingsCache::instance().messages().getMessageAt(i), this);
connect(newAction, &QAction::triggered, player->getPlayerActions(), &PlayerActions::actSayMessage);
connect(newAction, &QAction::triggered, player->getLogic()->getPlayerActions(), &PlayerActions::actSayMessage);
addAction(newAction);
}

View file

@ -11,12 +11,12 @@
#include <QMenu>
class PlayerLogic;
class PlayerGraphicsItem;
class SayMenu : public QMenu, public AbstractPlayerComponent
{
Q_OBJECT
public:
explicit SayMenu(PlayerLogic *player);
explicit SayMenu(PlayerGraphicsItem *player);
void retranslateUi() override;
void setShortcutsActive() override;
@ -26,7 +26,7 @@ private slots:
void initSayMenu();
private:
PlayerLogic *player;
PlayerGraphicsItem *player;
bool shortcutsActive = false;
};

View file

@ -3,12 +3,13 @@
#include "../player_actions.h"
#include "../player_logic.h"
SideboardMenu::SideboardMenu(PlayerLogic *player, QMenu *playerMenu) : QMenu(playerMenu)
SideboardMenu::SideboardMenu(PlayerGraphicsItem *player, QMenu *playerMenu) : QMenu(playerMenu)
{
aViewSideboard = new QAction(this);
connect(aViewSideboard, &QAction::triggered, player->getPlayerActions(), &PlayerActions::actViewSideboard);
connect(aViewSideboard, &QAction::triggered, player->getLogic()->getPlayerActions(),
&PlayerActions::actViewSideboard);
if (player->getPlayerInfo()->getLocalOrJudge()) {
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
addAction(aViewSideboard);
}

View file

@ -11,19 +11,19 @@
#include <QMenu>
class PlayerLogic;
class PlayerGraphicsItem;
class SideboardMenu : public QMenu, public AbstractPlayerComponent
{
Q_OBJECT
public:
explicit SideboardMenu(PlayerLogic *player, QMenu *playerMenu);
explicit SideboardMenu(PlayerGraphicsItem *player, QMenu *playerMenu);
void retranslateUi() override;
void setShortcutsActive() override;
void setShortcutsInactive() override;
private:
PlayerLogic *player;
PlayerGraphicsItem *player;
QAction *aViewSideboard;
};

View file

@ -8,34 +8,41 @@
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
#include <libcockatrice/deck_list/tree/inner_deck_list_node.h>
UtilityMenu::UtilityMenu(PlayerLogic *_player, QMenu *playerMenu) : QMenu(playerMenu), player(_player)
UtilityMenu::UtilityMenu(PlayerGraphicsItem *_player, QMenu *playerMenu) : QMenu(playerMenu), player(_player)
{
PlayerActions *playerActions = player->getPlayerActions();
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
connect(playerActions, &PlayerActions::requestEnableAndSetCreateAnotherTokenAction, this,
&UtilityMenu::setAndEnableCreateAnotherTokenAction);
connect(playerActions, &PlayerActions::requestSetLastToken, this, &UtilityMenu::setLastToken);
if (player->getPlayerInfo()->getLocalOrJudge()) {
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
aUntapAll = new QAction(this);
connect(aUntapAll, &QAction::triggered, playerActions, &PlayerActions::actUntapAll);
aRollDie = new QAction(this);
connect(aRollDie, &QAction::triggered, playerActions, &PlayerActions::actRollDie);
connect(aRollDie, &QAction::triggered, playerActions, &PlayerActions::actRequestRollDieDialog);
aFlipCoin = new QAction(this);
connect(aFlipCoin, &QAction::triggered, playerActions, &PlayerActions::actFlipCoin);
aCreateToken = new QAction(this);
connect(aCreateToken, &QAction::triggered, playerActions, &PlayerActions::actCreateToken);
connect(aCreateToken, &QAction::triggered, playerActions, [this]() {
player->getLogic()->getPlayerActions()->actRequestCreateTokenDialog(getPredefinedTokens());
});
aCreateAnotherToken = new QAction(this);
connect(aCreateAnotherToken, &QAction::triggered, playerActions, &PlayerActions::actCreateAnotherToken);
aCreateAnotherToken->setEnabled(false);
aIncrementAllCardCounters = new QAction(this);
connect(aIncrementAllCardCounters, &QAction::triggered, playerActions,
&PlayerActions::actIncrementAllCardCounters);
connect(aIncrementAllCardCounters, &QAction::triggered, playerActions, [this]() {
player->getLogic()->getPlayerActions()->actIncrementAllCardCounters(
player->getGameScene()->selectedCards());
});
createPredefinedTokenMenu = new QMenu(QString());
createPredefinedTokenMenu->setEnabled(false);
connect(player, &PlayerLogic::deckChanged, this, &UtilityMenu::populatePredefinedTokensMenu);
connect(player->getLogic(), &PlayerLogic::deckChanged, this, &UtilityMenu::populatePredefinedTokensMenu);
playerMenu->addAction(aIncrementAllCardCounters);
playerMenu->addSeparator();
@ -66,7 +73,7 @@ void UtilityMenu::populatePredefinedTokensMenu()
clear();
setEnabled(false);
predefinedTokens.clear();
const DeckList &deckList = player->getDeck();
const DeckList &deckList = player->getLogic()->getDeck();
if (deckList.isEmpty()) {
return;
@ -84,14 +91,24 @@ void UtilityMenu::populatePredefinedTokensMenu()
if (i < 10) {
a->setShortcut(QKeySequence("Alt+" + QString::number((i + 1) % 10)));
}
connect(a, &QAction::triggered, player->getPlayerActions(), &PlayerActions::actCreatePredefinedToken);
connect(a, &QAction::triggered, player->getLogic()->getPlayerActions(),
&PlayerActions::actCreatePredefinedToken);
}
}
}
void UtilityMenu::setLastToken(CardInfoPtr lastToken)
{
if (!createAnotherTokenActionExists()) {
return;
}
player->getLogic()->getPlayerActions()->setLastTokenInfo(lastToken);
}
void UtilityMenu::retranslateUi()
{
if (player->getPlayerInfo()->getLocalOrJudge()) {
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
aIncrementAllCardCounters->setText(tr("Increment all card counters"));
aUntapAll->setText(tr("&Untap all permanents"));
aRollDie->setText(tr("R&oll die..."));
@ -106,7 +123,7 @@ void UtilityMenu::setShortcutsActive()
{
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
if (player->getPlayerInfo()->getLocalOrJudge()) {
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
aIncrementAllCardCounters->setShortcuts(shortcuts.getShortcut("Player/aIncrementAllCardCounters"));
aUntapAll->setShortcuts(shortcuts.getShortcut("Player/aUntapAll"));
aRollDie->setShortcuts(shortcuts.getShortcut("Player/aRollDie"));
@ -118,7 +135,7 @@ void UtilityMenu::setShortcutsActive()
void UtilityMenu::setShortcutsInactive()
{
if (player->getPlayerInfo()->getLocalOrJudge()) {
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
aUntapAll->setShortcut(QKeySequence());
aRollDie->setShortcut(QKeySequence());
aFlipCoin->setShortcut(QKeySequence());

View file

@ -10,19 +10,21 @@
#include "abstract_player_component.h"
#include <QMenu>
#include <libcockatrice/card/card_info.h>
class PlayerLogic;
class PlayerGraphicsItem;
class UtilityMenu : public QMenu, public AbstractPlayerComponent
{
Q_OBJECT
public slots:
void populatePredefinedTokensMenu();
void setLastToken(CardInfoPtr lastToken);
void retranslateUi() override;
void setShortcutsActive() override;
void setShortcutsInactive() override;
public:
explicit UtilityMenu(PlayerLogic *player, QMenu *playerMenu);
explicit UtilityMenu(PlayerGraphicsItem *player, QMenu *playerMenu);
[[nodiscard]] bool createAnotherTokenActionExists() const
{
@ -31,7 +33,7 @@ public:
void setAndEnableCreateAnotherTokenAction(QString text)
{
aCreateAnotherToken->setText(text);
aCreateAnotherToken->setText(tr("C&reate another %1 token").arg(text));
aCreateAnotherToken->setEnabled(true);
}
@ -41,7 +43,7 @@ public:
}
private:
PlayerLogic *player;
PlayerGraphicsItem *player;
QStringList predefinedTokens;
QMenu *createPredefinedTokenMenu;

File diff suppressed because it is too large Load diff

View file

@ -9,6 +9,7 @@
#define COCKATRICE_PLAYER_ACTIONS_H
#include "../dialogs/dlg_create_token.h"
#include "../dialogs/dlg_move_top_cards_until.h"
#include "card_menu_action_type.h"
#include "event_processing_options.h"
#include "player_logic.h"
@ -56,30 +57,75 @@ public:
return movingCardsUntil;
}
signals:
void requestViewTopCardsDialog(int defaultNumberTopCards, int deckSize);
void requestViewBottomCardsDialog(int defaultNumberBottomCards, int deckSize);
void requestShuffleTopDialog(int defaultNumberTopCards, int maxCards);
void requestShuffleBottomDialog(int defaultNumberBottomCards, int maxCards);
void requestMulliganDialog(int startSize, int handSize, int deckSize);
void requestDrawCardsDialog(int defaultNumberTopCards, int deckSize);
void requestMoveTopCardsToDialog(int defaultNumberTopCards,
int maxCards,
const QString &targetZone,
const QString &zoneDisplayName,
bool faceDown);
void requestMoveTopCardsUntilDialog(MoveTopCardsUntilOptions options);
void requestMoveBottomCardsToDialog(int defaultNumberBottomCards,
int maxCards,
const QString &targetZone,
const QString &zoneDisplayName,
bool faceDown);
void requestDrawBottomCardsDialog(int defaultNumberBottomCards, int maxCards);
void requestRollDieDialog();
void requestCreateTokenDialog(const QStringList &predefinedTokens);
void requestCreateRelatedFromRelationDialog(const CardItem *sourceCard, const CardRelation *cardRelation);
void requestMoveCardXCardsFromTopDialog(int defaultNumberTopCardsToPlaceBelow, int deckSize);
void requestSetPTDialog(const QString &oldPT);
void requestSetAnnotationDialog(const QString &oldAnnotation);
void requestSetCardCounterDialog(int counterId, const QString &oldValueForDlg);
void requestZoneViewToggle(const QString &zoneName, int numberCards, bool isReversed = false);
void requestSortHand(const QList<CardList::SortOption> &options);
void requestEnableAndSetCreateAnotherTokenAction(const QString &lastTokenName);
void requestSetLastToken(CardInfoPtr lastToken);
public slots:
void setLastToken(CardInfoPtr cardInfo);
void setLastTokenInfo(CardInfoPtr cardInfo);
void playCard(CardItem *c, bool faceDown);
void playCardToTable(const CardItem *c, bool faceDown);
void actUntapAll();
void actRollDie();
void actRequestRollDieDialog();
void actRollDie(int sides, int count);
void actFlipCoin();
void actCreateToken();
void actRequestCreateTokenDialog(const QStringList &predefinedTokens);
void actCreateToken(TokenInfo tokenToCreate);
void actCreateAnotherToken();
void actRequestCreateRelatedFromRelationDialog(const CardItem *sourceCard, const CardRelation *cardRelation);
bool createRelatedFromRelation(const CardItem *sourceCard, const CardRelation *cardRelation, int variableCount);
void onRelatedCardCreated(const CardItem *sourceCard, const CardRelation *cardRelation);
void setLastRelatedCreationSucceeded(bool succeeded)
{
lastRelatedCreationSucceeded = succeeded;
}
void actShuffle();
void actShuffleTop();
void actShuffleBottom();
void actRequestShuffleTopDialog();
void actShuffleTop(int number);
void actRequestShuffleBottomDialog();
void actShuffleBottom(int number);
void actDrawCard();
void actDrawCards();
void actRequestDrawCardsDialog();
void actDrawCards(int number);
void actUndoDraw();
void actMulligan();
void actRequestMulliganDialog();
void actMulligan(int number);
void actMulliganSameSize();
void actMulliganMinusOne();
void doMulligan(int number);
void actPlay();
void actPlayFacedown();
void actHide();
void actPlay(QList<CardItem *> selectedCards);
void actPlayFacedown(QList<CardItem *> selectedCards);
void actHide(QList<CardItem *> selectedCards);
void actMoveTopCardToPlay();
void actMoveTopCardToPlayFaceDown();
@ -89,10 +135,14 @@ public slots:
void actMoveTopCardsToGraveFaceDown();
void actMoveTopCardsToExile();
void actMoveTopCardsToExileFaceDown();
void actMoveTopCardsUntil();
void actRequestMoveTopCardsUntilDialog();
void moveTopCardsUntil(const QString &expr, MoveTopCardsUntilOptions options);
void actMoveTopCardToBottom();
void actRequestMoveTopCardsToDialog(const QString &targetZone, const QString &zoneDisplayName, bool faceDown);
void moveTopCardsTo(int number, const QString &targetZone, bool faceDown);
void actDrawBottomCard();
void actDrawBottomCards();
void actRequestDrawBottomCardsDialog();
void actDrawBottomCards(int number);
void actMoveBottomCardToPlay();
void actMoveBottomCardToPlayFaceDown();
void actMoveBottomCardToGrave();
@ -102,6 +152,8 @@ public slots:
void actMoveBottomCardsToExile();
void actMoveBottomCardsToExileFaceDown();
void actMoveBottomCardToTop();
void actRequestMoveBottomCardsToDialog(const QString &targetZone, const QString &zoneDisplayName, bool faceDown);
void moveBottomCardsTo(int number, const QString &targetZone, bool faceDown);
void actSelectAll();
void actSelectRow();
@ -109,10 +161,12 @@ public slots:
void actViewLibrary();
void actViewHand();
void actViewTopCards();
void actViewBottomCards();
void actAlwaysRevealTopCard();
void actAlwaysLookAtTopCard();
void actRequestViewTopCardsDialog();
void actViewTopCards(int number);
void actRequestViewBottomCardsDialog();
void actViewBottomCards(int number);
void actAlwaysRevealTopCard(bool alwaysRevealTopCard);
void actAlwaysLookAtTopCard(bool alwaysRevealTopCard);
void actViewGraveyard();
void actLendLibrary(int lendToPlayerId);
void actRevealTopCards(int revealToPlayerId, int amount);
@ -127,37 +181,41 @@ public slots:
void actCreateRelatedCard();
void actCreateAllRelatedCards();
void actMoveCardXCardsFromTop();
void actRemoveCardCounter(int counterId);
void actAddCardCounter(int counterId);
void actSetCardCounter(int counterId);
void actIncrementAllCardCounters();
void actRequestMoveCardXCardsFromTopDialog();
void actMoveCardXCardsFromTop(QList<CardItem *> selectedCards, int number);
void actRemoveCardCounter(QList<CardItem *> selectedCards, int counterId);
void actAddCardCounter(QList<CardItem *> selectedCards, int counterId);
void actRequestSetCardCounterDialog(QList<CardItem *> selectedCards, int counterId);
void actSetCardCounter(QList<CardItem *> selectedCards, int counterId, const QString &counterValue);
void actIncrementAllCardCounters(QList<CardItem *> cardsToUpdate);
void actAttach();
void actUnattach();
void actUnattach(QList<CardItem *> selectedCards);
void actDrawArrow();
void actIncPT(int deltaP, int deltaT);
void actResetPT();
void actSetPT();
void actIncP();
void actDecP();
void actIncT();
void actDecT();
void actIncPT();
void actDecPT();
void actFlowP();
void actFlowT();
void actIncPT(QList<CardItem *> selectedCards, int deltaP, int deltaT);
void actResetPT(QList<CardItem *> selectedCards);
void actRequestSetPTDialog(QList<CardItem *> selectedCards);
void actSetPT(QList<CardItem *> selectedCards, const QString &pt);
void actIncP(QList<CardItem *> selectedCards);
void actDecP(QList<CardItem *> selectedCards);
void actIncT(QList<CardItem *> selectedCards);
void actDecT(QList<CardItem *> selectedCards);
void actIncPT(QList<CardItem *> selectedCards);
void actDecPT(QList<CardItem *> selectedCards);
void actFlowP(QList<CardItem *> selectedCards);
void actFlowT(QList<CardItem *> selectedCards);
void actReduceLifeByPower();
void actReduceLifeByPower(QList<CardItem *> selectedCards);
void actSetAnnotation();
void actReveal(QAction *action);
void actRequestSetAnnotationDialog(QList<CardItem *> selectedCards);
void actSetAnnotation(QList<CardItem *> selectedCards, const QString &annotation);
void actReveal(QList<CardItem *> selectedCards, QAction *action);
void actRevealHand(int revealToPlayerId);
void actRevealRandomHandCard(int revealToPlayerId);
void actRevealLibrary(int revealToPlayerId);
void actSortHand();
void cardMenuAction();
void cardMenuAction(QList<CardItem *> selectedCards, CardMenuActionType type);
private:
PlayerLogic *player;
@ -176,21 +234,19 @@ private:
int movingCardsUntilCounter = 0;
MoveTopCardsUntilOptions movingCardsUntilOptions;
void moveTopCardsTo(const QString &targetZone, const QString &zoneDisplayName, bool faceDown);
void moveBottomCardsTo(const QString &targetZone, const QString &zoneDisplayName, bool faceDown);
bool lastRelatedCreationSucceeded = false;
void createCard(const CardItem *sourceCard,
const QString &dbCardName,
CardRelationType attach = CardRelationType::DoesNotAttach,
bool persistent = false);
bool createRelatedFromRelation(const CardItem *sourceCard, const CardRelation *cardRelation);
void playSelectedCards(bool faceDown = false);
void playSelectedCards(QList<CardItem *> selectedCards, bool faceDown = false);
void cmdSetTopCard(Command_MoveCard &cmd);
void cmdSetBottomCard(Command_MoveCard &cmd);
void offsetCardCounter(int counterId, int offset);
void offsetCardCounter(QList<CardItem *> selectedCards, int counterId, int offset);
};
#endif // COCKATRICE_PLAYER_ACTIONS_H

View file

@ -0,0 +1,298 @@
#include "player_dialogs.h"
#include "../../client/settings/card_counter_settings.h"
#include "../../interface/widgets/utility/get_text_with_max.h"
#include "../board/card_item.h"
#include "../dialogs/dlg_roll_dice.h"
#include "../player/player_graphics_item.h"
#include <QInputDialog>
#include <libcockatrice/card/relation/card_relation.h>
PlayerDialogs::PlayerDialogs(PlayerGraphicsItem *_player, PlayerActions *_playerActions)
: QObject(_player), player(_player), playerActions(_playerActions)
{
connect(playerActions, &PlayerActions::requestViewTopCardsDialog, this,
&PlayerDialogs::onViewTopCardsDialogRequested);
connect(playerActions, &PlayerActions::requestViewBottomCardsDialog, this,
&PlayerDialogs::onViewBottomCardsDialogRequested);
connect(playerActions, &PlayerActions::requestShuffleTopDialog, this, &PlayerDialogs::onShuffleTopDialogRequested);
connect(playerActions, &PlayerActions::requestShuffleBottomDialog, this,
&PlayerDialogs::onShuffleBottomDialogRequested);
connect(playerActions, &PlayerActions::requestMulliganDialog, this, &PlayerDialogs::onMulliganDialogRequested);
connect(playerActions, &PlayerActions::requestDrawCardsDialog, this, &PlayerDialogs::onDrawCardsDialogRequested);
connect(playerActions, &PlayerActions::requestMoveTopCardsToDialog, this,
&PlayerDialogs::onMoveTopCardsToDialogRequested);
connect(playerActions, &PlayerActions::requestMoveTopCardsUntilDialog, this,
&PlayerDialogs::onMoveTopCardsUntilDialogRequested);
connect(playerActions, &PlayerActions::requestMoveBottomCardsToDialog, this,
&PlayerDialogs::onMoveBottomCardsToDialogRequested);
connect(playerActions, &PlayerActions::requestDrawBottomCardsDialog, this,
&PlayerDialogs::onDrawBottomCardsDialogRequested);
connect(playerActions, &PlayerActions::requestRollDieDialog, this, &PlayerDialogs::onRollDieDialogRequested);
connect(playerActions, &PlayerActions::requestCreateTokenDialog, this,
&PlayerDialogs::onCreateTokenDialogRequested);
connect(playerActions, &PlayerActions::requestCreateRelatedFromRelationDialog, this,
&PlayerDialogs::onCreateRelatedFromRelationDialogRequested);
connect(playerActions, &PlayerActions::requestMoveCardXCardsFromTopDialog, this,
&PlayerDialogs::onMoveCardXCardsFromTopDialogRequested);
connect(playerActions, &PlayerActions::requestSetPTDialog, this, &PlayerDialogs::onSetPTDialogRequested);
connect(playerActions, &PlayerActions::requestSetAnnotationDialog, this,
&PlayerDialogs::onSetAnnotationDialogRequested);
connect(playerActions, &PlayerActions::requestSetCardCounterDialog, this,
&PlayerDialogs::onSetCardCounterDialogRequested);
}
void PlayerDialogs::onViewTopCardsDialogRequested(int defaultNumberTopCards, int deckSize)
{
bool ok;
int number = QInputDialog::getInt(dialogParent(), tr("View top cards of library"),
tr("Number of cards: (max. %1)").arg(deckSize), defaultNumberTopCards, 1,
deckSize, 1, &ok);
if (ok) {
playerActions->actViewTopCards(number);
}
}
void PlayerDialogs::onViewBottomCardsDialogRequested(int defaultNumberBottomCards, int deckSize)
{
bool ok;
int number = QInputDialog::getInt(dialogParent(), tr("View bottom cards of library"),
tr("Number of cards: (max. %1)").arg(deckSize), defaultNumberBottomCards, 1,
deckSize, 1, &ok);
if (ok) {
playerActions->actViewBottomCards(number);
}
}
void PlayerDialogs::onShuffleTopDialogRequested(int defaultNumberTopCards, int maxCards)
{
bool ok;
int number = QInputDialog::getInt(dialogParent(), tr("Shuffle top cards of library"),
tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberTopCards, 1,
maxCards, 1, &ok);
if (ok) {
playerActions->actShuffleTop(number);
}
}
void PlayerDialogs::onShuffleBottomDialogRequested(int defaultNumberBottomCards, int maxCards)
{
bool ok;
int number = QInputDialog::getInt(dialogParent(), tr("Shuffle bottom cards of library"),
tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberBottomCards, 1,
maxCards, 1, &ok);
if (ok) {
playerActions->actShuffleBottom(number);
}
}
void PlayerDialogs::onMulliganDialogRequested(int startSize, int handSize, int deckSize)
{
bool ok;
int number = QInputDialog::getInt(dialogParent(), tr("Draw hand"),
tr("Number of cards: (max. %1)").arg(deckSize) + '\n' +
tr("0 and lower are in comparison to current hand size"),
startSize, -handSize, deckSize, 1, &ok);
if (ok) {
playerActions->actMulligan(number);
}
}
void PlayerDialogs::onDrawCardsDialogRequested(int defaultNumberTopCards, int deckSize)
{
bool ok;
int number = QInputDialog::getInt(dialogParent(), tr("Draw cards"), tr("Number of cards: (max. %1)").arg(deckSize),
defaultNumberTopCards, 1, deckSize, 1, &ok);
if (ok) {
playerActions->actDrawCards(number);
}
}
void PlayerDialogs::onMoveTopCardsToDialogRequested(int defaultNumberTopCards,
int maxCards,
const QString &targetZone,
const QString &zoneDisplayName,
bool faceDown)
{
bool ok;
int number = QInputDialog::getInt(dialogParent(), tr("Move top cards to %1").arg(zoneDisplayName),
tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberTopCards, 1,
maxCards, 1, &ok);
if (ok) {
playerActions->moveTopCardsTo(number, targetZone, faceDown);
}
}
void PlayerDialogs::onMoveTopCardsUntilDialogRequested(MoveTopCardsUntilOptions options)
{
DlgMoveTopCardsUntil dlg(dialogParent(), options);
if (!dlg.exec()) {
return;
}
playerActions->moveTopCardsUntil(dlg.getExpr(), dlg.getOptions());
}
void PlayerDialogs::onMoveBottomCardsToDialogRequested(int defaultNumberBottomCards,
int maxCards,
const QString &targetZone,
const QString &zoneDisplayName,
bool faceDown)
{
bool ok;
int number = QInputDialog::getInt(dialogParent(), tr("Move bottom cards to %1").arg(zoneDisplayName),
tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberBottomCards, 1,
maxCards, 1, &ok);
if (ok) {
playerActions->moveBottomCardsTo(number, targetZone, faceDown);
}
}
void PlayerDialogs::onDrawBottomCardsDialogRequested(int defaultNumberBottomCards, int maxCards)
{
bool ok;
int number =
QInputDialog::getInt(dialogParent(), tr("Draw bottom cards"), tr("Number of cards: (max. %1)").arg(maxCards),
defaultNumberBottomCards, 1, maxCards, 1, &ok);
if (ok) {
playerActions->actDrawBottomCards(number);
}
}
void PlayerDialogs::onRollDieDialogRequested()
{
DlgRollDice dlg(dialogParent());
if (!dlg.exec()) {
return;
}
playerActions->actRollDie(dlg.getDieSideCount(), dlg.getDiceToRollCount());
}
void PlayerDialogs::onCreateRelatedFromRelationDialogRequested(const CardItem *sourceCard,
const CardRelation *cardRelation)
{
if (sourceCard == nullptr || cardRelation == nullptr) {
playerActions->setLastRelatedCreationSucceeded(false);
return;
}
int variableCount = cardRelation->getDefaultCount();
if (cardRelation->getIsVariable()) {
bool ok;
emit requestDialogSemaphore(true);
variableCount = QInputDialog::getInt(dialogParent(), tr("Create tokens"), tr("Number:"),
cardRelation->getDefaultCount(), 1, MAX_TOKENS_PER_DIALOG, 1, &ok);
emit requestDialogSemaphore(false);
if (!ok) {
playerActions->setLastRelatedCreationSucceeded(false); // cancelled
return;
}
}
const bool succeeded = playerActions->createRelatedFromRelation(sourceCard, cardRelation, variableCount);
playerActions->setLastRelatedCreationSucceeded(succeeded);
if (succeeded) {
playerActions->onRelatedCardCreated(sourceCard, cardRelation); // only on confirmed success
}
}
void PlayerDialogs::onCreateTokenDialogRequested(const QStringList &predefinedTokens)
{
DlgCreateToken dlg(predefinedTokens, dialogParent());
if (!dlg.exec()) {
return;
}
playerActions->actCreateToken(dlg.getTokenInfo());
}
void PlayerDialogs::onMoveCardXCardsFromTopDialogRequested(int defaultNumberTopCardsToPlaceBelow, int deckSize)
{
bool ok;
int number =
QInputDialog::getInt(dialogParent(), tr("Place card X cards from top of library"),
tr("Which position should this card be placed:") + "\n" + tr("(max. %1)").arg(deckSize),
defaultNumberTopCardsToPlaceBelow, 1, deckSize, 1, &ok);
number -= 1; // indexes start at 0
if (ok) {
playerActions->actMoveCardXCardsFromTop(player->getGameScene()->selectedCards(), number);
}
}
void PlayerDialogs::onSetPTDialogRequested(const QString &oldPT)
{
bool ok;
auto cards = player->getGameScene()->selectedCards();
emit requestDialogSemaphore(true);
QString pt = getTextWithMax(dialogParent(), tr("Change power/toughness"), tr("Change stats to:"), QLineEdit::Normal,
oldPT, &ok);
emit requestDialogSemaphore(false);
if (!ok || player->getLogic()->clearCardsToDelete()) {
return;
}
playerActions->actSetPT(cards, pt);
}
void PlayerDialogs::onSetAnnotationDialogRequested(const QString &oldAnnotation)
{
auto cards = player->getGameScene()->selectedCards();
emit requestDialogSemaphore(true);
AnnotationDialog *dialog = new AnnotationDialog(dialogParent());
dialog->setOptions(QInputDialog::UsePlainTextEditForTextInput);
dialog->setWindowTitle(tr("Set annotation"));
dialog->setLabelText(tr("Please enter the new annotation:"));
dialog->setTextValue(oldAnnotation);
bool ok = dialog->exec();
emit requestDialogSemaphore(false);
if (!ok || player->getLogic()->clearCardsToDelete()) {
return;
}
QString annotation = dialog->textValue().left(MAX_NAME_LENGTH);
playerActions->actSetAnnotation(cards, annotation);
}
void PlayerDialogs::onSetCardCounterDialogRequested(int counterId, const QString &oldValueForDlg)
{
auto cards = player->getGameScene()->selectedCards();
emit requestDialogSemaphore(true);
auto &cardCounterSettings = SettingsCache::instance().cardCounters();
QString counterName = cardCounterSettings.displayName(counterId);
AbstractCounterDialog dialog(counterName, oldValueForDlg, dialogParent());
int ok = dialog.exec();
emit requestDialogSemaphore(false);
if (!ok || player->getLogic()->clearCardsToDelete()) {
return;
}
playerActions->actSetCardCounter(cards, counterId, dialog.textValue());
}

View file

@ -0,0 +1,62 @@
#ifndef COCKATRICE_PLAYER_DIALOGS_H
#define COCKATRICE_PLAYER_DIALOGS_H
#include "player_actions.h"
#include <QGraphicsView>
#include <QObject>
class PlayerGraphicsItem;
class PlayerDialogs : public QObject
{
Q_OBJECT
public:
explicit PlayerDialogs(PlayerGraphicsItem *player, PlayerActions *playerActions);
signals:
void requestDialogSemaphore(bool active);
public slots:
void onViewTopCardsDialogRequested(int defaultNumberTopCards, int deckSize);
void onViewBottomCardsDialogRequested(int defaultNumberBottomCards, int deckSize);
void onShuffleTopDialogRequested(int defaultNumberTopCards, int maxCards);
void onShuffleBottomDialogRequested(int defaultNumberBottomCards, int maxCards);
void onMulliganDialogRequested(int startSize, int handSize, int deckSize);
void onDrawCardsDialogRequested(int defaultNumberTopCards, int deckSize);
void onMoveTopCardsToDialogRequested(int defaultNumberTopCards,
int maxCards,
const QString &targetZone,
const QString &zoneDisplayName,
bool faceDown);
void onMoveTopCardsUntilDialogRequested(MoveTopCardsUntilOptions options);
void onMoveBottomCardsToDialogRequested(int defaultNumberBottomCards,
int maxCards,
const QString &targetZone,
const QString &zoneDisplayName,
bool faceDown);
void onDrawBottomCardsDialogRequested(int defaultNumberBottomCards, int maxCards);
void onRollDieDialogRequested();
void onCreateRelatedFromRelationDialogRequested(const CardItem *sourceCard, const CardRelation *cardRelation);
void onCreateTokenDialogRequested(const QStringList &predefinedTokens);
void onMoveCardXCardsFromTopDialogRequested(int defaultNumberTopCardsToPlaceBelow, int deckSize);
void onSetPTDialogRequested(const QString &oldPT);
void onSetAnnotationDialogRequested(const QString &oldAnnotation);
void onSetCardCounterDialogRequested(int counterId, const QString &oldValueForDlg);
private:
PlayerGraphicsItem *player;
PlayerActions *playerActions;
QWidget *dialogParent() const
{
if (auto *s = player->scene()) {
if (auto *v = s->views().value(0)) {
return v->window();
}
}
return nullptr;
}
};
#endif // COCKATRICE_PLAYER_DIALOGS_H

View file

@ -6,7 +6,6 @@
#include "../board/arrow_item.h"
#include "../board/card_item.h"
#include "../board/card_list.h"
#include "libcockatrice/utility/color.h"
#include "player_actions.h"
#include "player_logic.h"
@ -33,10 +32,12 @@
#include <libcockatrice/protocol/pb/event_set_card_counter.pb.h>
#include <libcockatrice/protocol/pb/event_set_counter.pb.h>
#include <libcockatrice/protocol/pb/event_shuffle.pb.h>
#include <libcockatrice/utility/color.h>
#include <libcockatrice/utility/zone_names.h>
PlayerEventHandler::PlayerEventHandler(PlayerLogic *_player) : QObject(_player), player(_player)
{
connect(this, &PlayerEventHandler::requestCardMenuUpdate, player, &PlayerLogic::requestCardMenuUpdate);
}
void PlayerEventHandler::eventGameSay(const Event_GameSay &event)
@ -252,7 +253,7 @@ void PlayerEventHandler::eventSetCardCounter(const Event_SetCardCounter &event)
int oldValue = card->getCounters().value(event.counter_id(), 0);
card->setCounter(event.counter_id(), event.counter_value());
player->getPlayerMenu()->updateCardMenu(card);
emit requestCardMenuUpdate(card);
emit logSetCardCounter(player, card->getName(), event.counter_id(), event.counter_value(), oldValue);
}
@ -370,7 +371,7 @@ void PlayerEventHandler::eventMoveCard(const Event_MoveCard &event, const GameEv
targetZone->addCard(card, true, x, y);
emit cardZoneChanged(card, startZone == targetZone);
player->getPlayerMenu()->updateCardMenu(card);
emit requestCardMenuUpdate(card);
if (player->getPlayerActions()->isMovingCardsUntil() && startZoneString == ZoneNames::DECK &&
targetZone->getName() == ZoneNames::STACK) {
@ -397,7 +398,7 @@ void PlayerEventHandler::eventFlipCard(const Event_FlipCard &event)
emit logFlipCard(player, card->getName(), event.face_down());
card->setFaceDown(event.face_down());
player->getPlayerMenu()->updateCardMenu(card);
emit requestCardMenuUpdate(card);
}
void PlayerEventHandler::eventDestroyCard(const Event_DestroyCard &event)
@ -466,7 +467,7 @@ void PlayerEventHandler::eventAttachCard(const Event_AttachCard &event)
} else {
emit logUnattachCard(player, startCard->getName());
}
player->getPlayerMenu()->updateCardMenu(startCard);
emit requestCardMenuUpdate(startCard);
}
void PlayerEventHandler::eventDrawCards(const Event_DrawCards &event)
@ -552,7 +553,7 @@ void PlayerEventHandler::eventRevealCards(const Event_RevealCards &event, EventP
}
if (!options.testFlag(SKIP_REVEAL_WINDOW) && showZoneView && !cardList.isEmpty()) {
player->getGameScene()->addRevealedZoneView(player, zone, cardList, event.grant_write_access());
emit player->requestRevealedZoneView(player, zone, cardList, event.grant_write_access());
}
emit logRevealCards(player, zone, cardId, cardName, otherPlayer, false,

View file

@ -83,6 +83,7 @@ signals:
void logAlwaysRevealTopCard(PlayerLogic *player, CardZoneLogic *zone, bool reveal);
void logAlwaysLookAtTopCard(PlayerLogic *player, CardZoneLogic *zone, bool reveal);
void cardZoneChanged(CardItem *card, bool sameZone);
void requestCardMenuUpdate(const CardItem *card);
public:
PlayerEventHandler(PlayerLogic *player);

View file

@ -8,6 +8,10 @@
#include "../board/abstract_card_item.h"
#include "../board/counter_general.h"
#include "../hand_counter.h"
#include "player_actions.h"
#include "player_dialogs.h"
#include <QGraphicsView>
PlayerGraphicsItem::PlayerGraphicsItem(PlayerLogic *_player) : player(_player)
{
@ -16,28 +20,35 @@ PlayerGraphicsItem::PlayerGraphicsItem(PlayerLogic *_player) : player(_player)
connect(&SettingsCache::instance(), &SettingsCache::handJustificationChanged, this,
&PlayerGraphicsItem::rearrangeZones);
connect(player, &PlayerLogic::rearrangeCounters, this, &PlayerGraphicsItem::rearrangeCounters);
connect(player, &PlayerLogic::activeChanged, this, &PlayerGraphicsItem::onPlayerActiveChanged);
connect(player, &PlayerLogic::concededChanged, this, [this](int, bool c) { setVisible(!c); });
connect(player, &PlayerLogic::zoneIdChanged, this, [this](int id) { playerArea->setPlayerZoneId(id); });
connect(player, &PlayerLogic::counterAdded, this, &PlayerGraphicsItem::onCounterAdded);
connect(player, &PlayerLogic::counterRemoved, this, &PlayerGraphicsItem::onCounterRemoved);
connect(player->getPlayerMenu(), &PlayerMenu::shortcutsActivated, this, [this]() {
playerMenu = new PlayerMenu(this);
connect(playerMenu, &PlayerMenu::shortcutsActivated, this, [this]() {
for (auto *ctr : counterWidgets) {
ctr->setShortcutsActive();
}
});
connect(player->getPlayerMenu(), &PlayerMenu::shortcutsDeactivated, this, [this]() {
connect(playerMenu, &PlayerMenu::shortcutsDeactivated, this, [this]() {
for (auto *ctr : counterWidgets) {
ctr->setShortcutsInactive();
}
});
connect(player->getPlayerMenu(), &PlayerMenu::retranslateRequested, this, [this]() {
connect(playerMenu, &PlayerMenu::retranslateRequested, this, [this]() {
for (auto *ctr : counterWidgets) {
ctr->retranslateUi();
}
});
playerDialogs = new PlayerDialogs(this, player->getPlayerActions());
connect(playerDialogs, &PlayerDialogs::requestDialogSemaphore, player, &PlayerLogic::setDialogSemaphore);
playerArea = new PlayerArea(this);
playerTarget = new PlayerTarget(player, playerArea);
@ -47,6 +58,8 @@ PlayerGraphicsItem::PlayerGraphicsItem(PlayerLogic *_player) : player(_player)
initializeZones();
playerMenu->setMenusForGraphicItems();
connect(tableZoneGraphicsItem, &TableZone::sizeChanged, this, &PlayerGraphicsItem::updateBoundingRect);
updateBoundingRect();
@ -57,7 +70,7 @@ PlayerGraphicsItem::PlayerGraphicsItem(PlayerLogic *_player) : player(_player)
void PlayerGraphicsItem::retranslateUi()
{
player->getPlayerMenu()->retranslateUi();
playerMenu->retranslateUi();
QMapIterator<QString, CardZoneLogic *> zoneIterator(player->getZones());
while (zoneIterator.hasNext()) {
@ -93,14 +106,16 @@ void PlayerGraphicsItem::initializeZones()
rfgZoneGraphicsItem = new PileZone(player->getRfgZone(), this);
rfgZoneGraphicsItem->setPos(base + QPointF(0, 2 * h + h2 + 10));
tableZoneGraphicsItem = new TableZone(player->getTableZone(), this);
tableZoneGraphicsItem = new TableZone(player->getTableZone(), mirrored, this);
connect(tableZoneGraphicsItem, &TableZone::sizeChanged, this, &PlayerGraphicsItem::updateBoundingRect);
connect(this, &PlayerGraphicsItem::mirroredChanged, tableZoneGraphicsItem, &TableZone::setMirrored);
stackZoneGraphicsItem =
new StackZone(player->getStackZone(), static_cast<int>(tableZoneGraphicsItem->boundingRect().height()), this);
handZoneGraphicsItem =
new HandZone(player->getHandZone(), static_cast<int>(tableZoneGraphicsItem->boundingRect().height()), this);
connect(player->getPlayerActions(), &PlayerActions::requestSortHand, handZoneGraphicsItem, &HandZone::sortHand);
connect(handZoneGraphicsItem->getLogic(), &HandZoneLogic::cardCountChanged, handCounter,
&HandCounter::updateNumber);
@ -145,6 +160,7 @@ void PlayerGraphicsItem::setMirrored(bool _mirrored)
{
if (mirrored != _mirrored) {
mirrored = _mirrored;
emit mirroredChanged(mirrored);
rearrangeZones();
}
}
@ -159,11 +175,11 @@ void PlayerGraphicsItem::onCounterAdded(CounterState *state)
}
counterWidgets.insert(state->getId(), widget);
if (player->getPlayerMenu()->getCountersMenu() && widget->getMenu()) {
player->getPlayerMenu()->getCountersMenu()->addMenu(widget->getMenu());
if (playerMenu->getCountersMenu() && widget->getMenu()) {
playerMenu->getCountersMenu()->addMenu(widget->getMenu());
}
if (player->getPlayerMenu()->getShortcutsActive()) {
if (playerMenu->getShortcutsActive()) {
widget->setShortcutsActive();
}
@ -176,8 +192,8 @@ void PlayerGraphicsItem::onCounterRemoved(int counterId)
if (!widget) {
return;
}
if (player->getPlayerMenu()->getCountersMenu() && widget->getMenu()) {
player->getPlayerMenu()->getCountersMenu()->removeAction(widget->getMenu()->menuAction());
if (playerMenu->getCountersMenu() && widget->getMenu()) {
playerMenu->getCountersMenu()->removeAction(widget->getMenu()->menuAction());
}
widget->delCounter();
rearrangeCounters();

View file

@ -14,6 +14,7 @@
class HandZone;
class PileZone;
class PlayerDialogs;
class PlayerTarget;
class StackZone;
class TableZone;
@ -55,11 +56,16 @@ public:
return static_cast<GameScene *>(scene());
}
PlayerLogic *getPlayer() const
PlayerLogic *getLogic() const
{
return player;
}
[[nodiscard]] PlayerMenu *getPlayerMenu() const
{
return playerMenu;
}
PlayerArea *getPlayerArea() const
{
return playerArea;
@ -111,9 +117,13 @@ public slots:
signals:
void sizeChanged();
void playerCountChanged();
void mirroredChanged(bool isMirrored);
void cardInfoRequested(const CardRef &cardRef);
private:
PlayerLogic *player;
PlayerMenu *playerMenu;
PlayerDialogs *playerDialogs;
PlayerArea *playerArea;
PlayerTarget *playerTarget;
QMap<int, AbstractCounter *> counterWidgets;

View file

@ -35,14 +35,6 @@ PlayerLogic::PlayerLogic(const ServerInfo_User &info, int _id, bool _local, bool
conceded(false), zoneId(0), dialogSemaphore(false)
{
initializeZones();
playerMenu = new PlayerMenu(this);
graphicsItem = new PlayerGraphicsItem(this);
playerMenu->setMenusForGraphicItems();
connect(this, &PlayerLogic::activeChanged, graphicsItem, &PlayerGraphicsItem::onPlayerActiveChanged);
connect(this, &PlayerLogic::openDeckEditor, game->getTab(), &TabGame::openDeckEditor);
}
void PlayerLogic::initializeZones()
@ -68,7 +60,6 @@ PlayerLogic::~PlayerLogic()
}
zones.clear();
delete playerMenu;
delete getPlayerInfo()->userInfo;
}
@ -326,22 +317,16 @@ void PlayerLogic::setActive(bool _active)
active = _active;
emit activeChanged(active);
}
void PlayerLogic::onRequestZoneViewToggle(const QString &zoneName, int numberCards, bool isReversed)
{
emit requestZoneViewToggle(this, zoneName, numberCards, isReversed);
}
void PlayerLogic::updateZones()
{
getTableZone()->reorganizeCards();
}
PlayerGraphicsItem *PlayerLogic::getGraphicsItem()
{
return graphicsItem;
}
GameScene *PlayerLogic::getGameScene()
{
return getGraphicsItem()->getGameScene();
}
void PlayerLogic::setGameStarted()
{
if (playerInfo->local) {

View file

@ -67,8 +67,14 @@ class PlayerLogic : public QObject
signals:
void openDeckEditor(const LoadedDeck &deck);
void requestZoneViewToggle(PlayerLogic *player, const QString &zoneName, int numberCards, bool isReversed);
void requestRevealedZoneView(PlayerLogic *player,
CardZoneLogic *zone,
const QList<const ServerInfo_Card *> &cardList,
bool withWritePermission);
void deckChanged();
void newCardAdded(AbstractCardItem *card);
void requestCardMenuUpdate(const CardItem *card);
void counterAdded(CounterState *state);
void counterRemoved(int counterId);
void rearrangeCounters();
@ -85,6 +91,7 @@ signals:
public slots:
void setActive(bool _active);
void onRequestZoneViewToggle(const QString &zoneName, int numberCards, bool isReversed);
public:
PlayerLogic(const ServerInfo_User &info, int _id, bool _local, bool _judge, AbstractGame *_parent);
@ -112,10 +119,6 @@ public:
return game;
}
GameScene *getGameScene();
[[nodiscard]] PlayerGraphicsItem *getGraphicsItem();
[[nodiscard]] PlayerActions *getPlayerActions() const
{
return playerActions;
@ -131,11 +134,6 @@ public:
return playerInfo;
}
[[nodiscard]] PlayerMenu *getPlayerMenu() const
{
return playerMenu;
}
void setDeck(const DeckList &_deck);
[[nodiscard]] const DeckList &getDeck() const
@ -234,8 +232,6 @@ private:
PlayerInfo *playerInfo;
PlayerEventHandler *playerEventHandler;
PlayerActions *playerActions;
PlayerMenu *playerMenu;
PlayerGraphicsItem *graphicsItem;
bool active;
bool conceded;

View file

@ -22,7 +22,8 @@ const QColor TableZone::FADE_MASK = QColor(0, 0, 0, 80);
const QColor TableZone::GRADIENT_COLOR = QColor(255, 255, 255, 150);
const QColor TableZone::GRADIENT_COLORLESS = QColor(255, 255, 255, 0);
TableZone::TableZone(TableZoneLogic *_logic, QGraphicsItem *parent) : SelectZone(_logic, parent), active(false)
TableZone::TableZone(TableZoneLogic *_logic, bool _mirrored, QGraphicsItem *parent)
: SelectZone(_logic, parent), active(false), mirrored(_mirrored)
{
connect(_logic, &TableZoneLogic::contentSizeChanged, this, &TableZone::resizeToContents);
connect(_logic, &TableZoneLogic::toggleTapped, this, &TableZone::toggleTapped);
@ -50,12 +51,16 @@ QRectF TableZone::boundingRect() const
return QRectF(0, 0, width, height);
}
void TableZone::setMirrored(bool isMirrored)
{
mirrored = isMirrored;
update();
}
bool TableZone::isInverted() const
{
return ((getLogic()->getPlayer()->getGraphicsItem()->getMirrored() &&
!SettingsCache::instance().getInvertVerticalCoordinate()) ||
(!getLogic()->getPlayer()->getGraphicsItem()->getMirrored() &&
SettingsCache::instance().getInvertVerticalCoordinate()));
return ((mirrored && !SettingsCache::instance().getInvertVerticalCoordinate()) ||
(!mirrored && SettingsCache::instance().getInvertVerticalCoordinate()));
}
void TableZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)

View file

@ -82,6 +82,7 @@ private:
If this TableZone is currently active
*/
bool active = false;
bool mirrored = false;
[[nodiscard]] bool isInverted() const;
@ -96,6 +97,7 @@ public slots:
Reorganizes CardItems in the TableZone
*/
void reorganizeCards() override;
void setMirrored(bool isMirrored);
public:
/**
@ -104,7 +106,7 @@ public:
@param _p the Player
@param parent defaults to null
*/
explicit TableZone(TableZoneLogic *_logic, QGraphicsItem *parent = nullptr);
explicit TableZone(TableZoneLogic *_logic, bool mirrored, QGraphicsItem *parent = nullptr);
/**
@return a QRectF of the TableZone bounding box.

View file

@ -9,6 +9,7 @@
#include <QFutureWatcher>
#include <QPrinter>
#include <QRegularExpression>
#include <QSaveFile>
#include <QStringList>
#include <QTextCursor>
#include <QTextDocument>
@ -129,7 +130,10 @@ std::optional<LoadedDeck> DeckLoader::loadFromRemote(const QString &nativeString
std::optional<LoadedDeck::LoadInfo>
DeckLoader::saveToFile(const DeckList &deck, const QString &fileName, DeckFileFormat::Format fmt)
{
QFile file(fileName);
// Use QSaveFile so that a failed write (e.g. a full disk) leaves the existing deck untouched
// instead of truncating it to a 0-byte file. The target is only replaced once every byte has
// been flushed successfully in commit().
QSaveFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qCWarning(DeckLoaderLog) << "Could not create or open file:" << fileName;
return std::nullopt;
@ -145,15 +149,19 @@ DeckLoader::saveToFile(const DeckList &deck, const QString &fileName, DeckFileFo
break;
}
file.flush();
file.close();
qCInfo(DeckLoaderLog) << "Saved deck to " << fileName << "with format" << fmt << "-" << success;
if (!success) {
file.cancelWriting();
qCWarning(DeckLoaderLog) << "Failed to serialize deck for file:" << fileName;
return std::nullopt;
}
if (!file.commit()) {
qCWarning(DeckLoaderLog) << "Failed to save deck to " << fileName << ":" << file.errorString();
return std::nullopt;
}
qCInfo(DeckLoaderLog) << "Saved deck to " << fileName << "with format" << fmt;
LoadedDeck::LoadInfo lastLoadInfo = {fileName, fmt};
return lastLoadInfo;
}
@ -196,38 +204,44 @@ bool DeckLoader::updateLastLoadedTimestamp(LoadedDeck &deck)
QDateTime originalTimestamp = fileInfo.lastModified();
// Open the file for writing
QFile file(fileName);
// Use QSaveFile so that a failed write (e.g. a full disk) cannot truncate an existing deck to a
// 0-byte file while merely bumping its timestamp.
QSaveFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qCWarning(DeckLoaderLog) << "Failed to open file for writing:" << fileName;
return false;
}
bool result = false;
// Perform file modifications
deck.deckList.setLastLoadedTimestamp(QDateTime::currentDateTime().toString());
result = deck.deckList.saveToFile_Native(&file);
file.close(); // Close the file to ensure changes are flushed
if (result) {
// Re-open the file and set the original timestamp
if (!file.open(QIODevice::ReadWrite)) {
qCWarning(DeckLoaderLog) << "Failed to re-open file to set timestamp:" << fileName;
return false;
}
if (!file.setFileTime(originalTimestamp, QFileDevice::FileModificationTime)) {
qCWarning(DeckLoaderLog) << "Failed to set modification time for file:" << fileName;
file.close();
return false;
}
file.close();
if (!deck.deckList.saveToFile_Native(&file)) {
file.cancelWriting();
qCWarning(DeckLoaderLog) << "Failed to serialize deck for file:" << fileName;
return false;
}
return result;
if (!file.commit()) {
qCWarning(DeckLoaderLog) << "Failed to update timestamp for file:" << fileName << ":" << file.errorString();
return false;
}
// Re-open the file and restore the original timestamp, so that updating the lastLoadedTimestamp
// does not change the file's modification time.
QFile timestampFile(fileName);
if (!timestampFile.open(QIODevice::ReadWrite)) {
qCWarning(DeckLoaderLog) << "Failed to re-open file to set timestamp:" << fileName;
return false;
}
if (!timestampFile.setFileTime(originalTimestamp, QFileDevice::FileModificationTime)) {
qCWarning(DeckLoaderLog) << "Failed to set modification time for file:" << fileName;
timestampFile.close();
return false;
}
timestampFile.close();
return true;
}
static QString getDomainForWebsite(DeckLoader::DecklistWebsite website)
@ -444,51 +458,54 @@ bool DeckLoader::convertToCockatriceFormat(LoadedDeck &deck)
return false;
}
// Determine the format before touching any file, so an already-converted or
// unsupported deck never truncates or deletes anything.
switch (DeckFileFormat::getFormatFromName(fileName)) {
case DeckFileFormat::PlainText:
break;
case DeckFileFormat::Cockatrice:
qCInfo(DeckLoaderLog) << "File is already in Cockatrice format. No conversion needed.";
return true;
default:
qCWarning(DeckLoaderLog) << "Unsupported file format for conversion:" << fileName;
return false;
}
// Change the file extension to .cod
QFileInfo fileInfo(fileName);
QString newFileName = QDir::toNativeSeparators(fileInfo.path() + "/" + fileInfo.completeBaseName() + ".cod");
// Open the new file for writing
QFile file(newFileName);
// Use QSaveFile so a failed write (e.g. a full disk) cannot leave a 0-byte .cod
// behind and then delete the original deck.
QSaveFile file(newFileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qCWarning(DeckLoaderLog) << "Failed to open file for writing:" << newFileName;
return false;
}
bool result = false;
// Perform file modifications based on the detected format
switch (DeckFileFormat::getFormatFromName(fileName)) {
case DeckFileFormat::PlainText:
// Save in Cockatrice's native format
result = deck.deckList.saveToFile_Native(&file);
break;
case DeckFileFormat::Cockatrice:
qCInfo(DeckLoaderLog) << "File is already in Cockatrice format. No conversion needed.";
result = true;
break;
default:
qCWarning(DeckLoaderLog) << "Unsupported file format for conversion:" << fileName;
result = false;
break;
if (!deck.deckList.saveToFile_Native(&file)) {
file.cancelWriting();
qCWarning(DeckLoaderLog) << "Failed to serialize deck for file:" << newFileName;
return false;
}
file.close();
// Delete the old file if conversion was successful
if (result) {
if (!QFile::remove(fileName)) {
qCWarning(DeckLoaderLog) << "Failed to delete original file:" << fileName;
} else {
qCInfo(DeckLoaderLog) << "Original file deleted successfully:" << fileName;
}
deck.lastLoadInfo = {
.fileName = newFileName,
.fileFormat = DeckFileFormat::Cockatrice,
};
if (!file.commit()) {
qCWarning(DeckLoaderLog) << "Failed to convert deck to " << newFileName << ":" << file.errorString();
return false;
}
return result;
// Conversion succeeded: delete the original file.
if (!QFile::remove(fileName)) {
qCWarning(DeckLoaderLog) << "Failed to delete original file:" << fileName;
} else {
qCInfo(DeckLoaderLog) << "Original file deleted successfully:" << fileName;
}
deck.lastLoadInfo = {
.fileName = newFileName,
.fileFormat = DeckFileFormat::Cockatrice,
};
return true;
}
void DeckLoader::printDeckListNode(QTextCursor *cursor, const InnerDecklistNode *node)

View file

@ -1,6 +1,7 @@
#include "tab_game.h"
#include "../../../client/settings/cache_settings.h"
#include "../../../game/player/menu/card_menu.h"
#include "../game/board/arrow_item.h"
#include "../game/board/card_item.h"
#include "../game/deckview/deck_view_container.h"
@ -363,11 +364,10 @@ void TabGame::retranslateUi()
cardInfoFrameWidget->retranslateUi();
QMapIterator<int, PlayerLogic *> i(game->getPlayerManager()->getPlayers());
while (i.hasNext()) {
i.next().value()->getGraphicsItem()->retranslateUi();
for (auto playerView : scene->getPlayers().values()) {
playerView->retranslateUi();
}
QMapIterator<int, TabbedDeckViewContainer *> j(deckViewContainers);
while (j.hasNext()) {
j.next().value()->playerDeckView->retranslateUi();
@ -654,8 +654,12 @@ PlayerLogic *TabGame::addPlayer(PlayerLogic *newPlayer)
scene->addPlayer(newPlayer);
auto *view = scene->viewForPlayer(newPlayer->getPlayerInfo()->getId());
connect(newPlayer, &PlayerLogic::newCardAdded, this, &TabGame::newCardAdded);
connect(newPlayer->getPlayerMenu(), &PlayerMenu::cardMenuUpdated, this, &TabGame::setCardMenu);
connect(newPlayer, &PlayerLogic::openDeckEditor, this, &TabGame::openDeckEditor);
connect(view->getPlayerMenu(), &PlayerMenu::cardMenuUpdated, this, &TabGame::setCardMenu);
connect(view, &PlayerGraphicsItem::cardInfoRequested, this, &TabGame::viewCardInfo);
messageLog->connectToPlayerEventHandler(newPlayer->getPlayerEventHandler());
@ -668,7 +672,7 @@ PlayerLogic *TabGame::addPlayer(PlayerLogic *newPlayer)
addLocalPlayer(newPlayer, newPlayer->getPlayerInfo()->getId());
}
gameMenu->insertMenu(playersSeparator, newPlayer->getPlayerMenu()->getPlayerMenu());
gameMenu->insertMenu(playersSeparator, view->getPlayerMenu()->getPlayerMenu());
createZoneForPlayer(newPlayer, newPlayer->getPlayerInfo()->getId());
@ -678,7 +682,7 @@ PlayerLogic *TabGame::addPlayer(PlayerLogic *newPlayer)
void TabGame::addLocalPlayer(PlayerLogic *newPlayer, int playerId)
{
if (game->getGameState()->getClients().size() == 1) {
newPlayer->getPlayerMenu()->setShortcutsActive();
scene->viewForPlayer(playerId)->getPlayerMenu()->setShortcutsActive();
}
auto *deckView = new TabbedDeckViewContainer(playerId, this);
@ -698,27 +702,24 @@ void TabGame::addLocalPlayer(PlayerLogic *newPlayer, int playerId)
void TabGame::processPlayerLeave(PlayerLogic *leavingPlayer)
{
QString playerName = "@" + leavingPlayer->getPlayerInfo()->getName();
removePlayerFromAutoCompleteList(playerName);
scene->removePlayer(leavingPlayer);
removePlayerFromAutoCompleteList("@" + leavingPlayer->getPlayerInfo()->getName());
// When we inserted the playerMenu into the gameMenu earlier, Qt wrapped the playerMenu into a QAction*, which lives
// independently and does not get cleaned up when the source menu gets destroyed. We have to manually clean here.
if (leavingPlayer->getPlayerMenu()) {
QMenu *menu = leavingPlayer->getPlayerMenu()->getPlayerMenu();
if (menu) {
// Find and remove the QAction pointing to this menu
QList<QAction *> actions = gameMenu->actions();
for (QAction *act : actions) {
if (act->menu() == menu) {
gameMenu->removeAction(act);
delete act; // deletes the QAction wrapper around the submenu
break;
}
auto *view = scene->viewForPlayer(leavingPlayer->getPlayerInfo()->getId());
if (view) {
// Find and remove the QAction pointing to this menu
QMenu *menu = view->getPlayerMenu()->getPlayerMenu();
for (QAction *act : gameMenu->actions()) {
if (act->menu() == menu) {
gameMenu->removeAction(act);
delete act;
break;
}
}
}
scene->removePlayer(leavingPlayer);
}
void TabGame::processRemotePlayerDeckSelect(QString deckList, int playerId, QString playerName)
@ -869,12 +870,12 @@ PlayerLogic *TabGame::setActivePlayer(int id)
if (i.value() == player) {
i.value()->setActive(true);
if (game->getGameState()->getClients().size() > 1) {
i.value()->getPlayerMenu()->setShortcutsActive();
scene->viewForPlayer(i.value()->getPlayerInfo()->getId())->getPlayerMenu()->setShortcutsActive();
}
} else {
i.value()->setActive(false);
if (game->getGameState()->getClients().size() > 1) {
i.value()->getPlayerMenu()->setShortcutsInactive();
scene->viewForPlayer(i.value()->getPlayerInfo()->getId())->getPlayerMenu()->setShortcutsInactive();
}
}
}
@ -890,8 +891,13 @@ void TabGame::setActivePhase(int phase)
void TabGame::newCardAdded(AbstractCardItem *card)
{
connect(card, &AbstractCardItem::rightClicked, scene, &GameScene::onCardRightClicked);
connect(card, &AbstractCardItem::playSelected, scene, &GameScene::playSelected);
connect(card, &AbstractCardItem::playSelectedFaceDown, scene, &GameScene::playSelectedFaceDown);
connect(card, &AbstractCardItem::hideSelected, scene, &GameScene::hideSelected);
connect(card, &AbstractCardItem::hovered, cardInfoFrameWidget,
qOverload<AbstractCardItem *>(&CardInfoFrameWidget::setCard));
connect(card, &AbstractCardItem::selectionChanged, scene, &GameScene::onCardSelectionChanged);
connect(card, &AbstractCardItem::showCardInfoPopup, this, &TabGame::showCardInfoPopup);
connect(card, SIGNAL(deleteCardInfoPopup(QString)), this, SLOT(deleteCardInfoPopup(QString)));
connect(card, &AbstractCardItem::cardShiftClicked, this, &TabGame::linkCardToChat);
@ -935,7 +941,7 @@ QString TabGame::getTabText() const
/**
* @param menu The menu to set. Pass in nullptr to set the menu to empty.
*/
void TabGame::setCardMenu(QMenu *menu)
void TabGame::setCardMenu(CardMenu *menu)
{
if (!aCardMenu) {
return;

View file

@ -141,7 +141,7 @@ signals:
private slots:
void adminLockChanged(bool lock);
void newCardAdded(AbstractCardItem *card);
void setCardMenu(QMenu *menu);
void setCardMenu(CardMenu *menu);
void actGameInfo();
void actConcede();