diff --git a/cockatrice/src/client/settings/shortcuts_settings.h b/cockatrice/src/client/settings/shortcuts_settings.h index 47332b8c4..9c64b0d6c 100644 --- a/cockatrice/src/client/settings/shortcuts_settings.h +++ b/cockatrice/src/client/settings/shortcuts_settings.h @@ -562,10 +562,10 @@ private: ShortcutGroup::Move_selected)}, {"Player/aPlayFacedown", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Battlefield, Face Down"), parseSequenceString(""), - ShortcutGroup::Move_selected)}, - {"Player/aPlay", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Battlefield"), - parseSequenceString(""), - ShortcutGroup::Move_selected)}, + ShortcutGroup::Playing_Area)}, + {"Player/aMoveToTable", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Battlefield"), + parseSequenceString(""), + ShortcutGroup::Move_selected)}, {"Player/aViewHand", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Hand"), parseSequenceString(""), ShortcutGroup::View)}, {"Player/aViewGraveyard", diff --git a/cockatrice/src/game/player/card_menu_action_type.h b/cockatrice/src/game/player/card_menu_action_type.h index aec6d6397..1b63674fa 100644 --- a/cockatrice/src/game/player/card_menu_action_type.h +++ b/cockatrice/src/game/player/card_menu_action_type.h @@ -9,17 +9,20 @@ enum CardMenuActionType { + // Per-card attribute actions (must be <= cmClone for cardMenuAction() dispatch) cmTap, cmUntap, cmDoesntUntap, cmFlip, cmPeek, cmClone, + // Move actions (must be > cmClone for cardMenuAction() dispatch) cmMoveToTopLibrary, cmMoveToBottomLibrary, cmMoveToHand, cmMoveToGraveyard, - cmMoveToExile + cmMoveToExile, + cmMoveToTable }; #endif // COCKATRICE_CARD_MENU_ACTION_TYPE_H diff --git a/cockatrice/src/game/player/menu/card_menu.cpp b/cockatrice/src/game/player/menu/card_menu.cpp index cd77c2968..7da259a04 100644 --- a/cockatrice/src/game/player/menu/card_menu.cpp +++ b/cockatrice/src/game/player/menu/card_menu.cpp @@ -146,11 +146,10 @@ void CardMenu::createTableMenu(bool canModifyCard) { // Card is on the battlefield if (!canModifyCard) { + addAction(aDrawArrow); + addSeparator(); addRelatedCardView(); addRelatedCardActions(); - - addSeparator(); - addAction(aDrawArrow); addSeparator(); addAction(aClone); addSeparator(); @@ -165,10 +164,9 @@ void CardMenu::createTableMenu(bool canModifyCard) if (card->getFaceDown()) { addAction(aPeek); } - - addRelatedCardView(); - addRelatedCardActions(); - + addSeparator(); + addAction(aClone); + addMenu(new MoveMenu(player)); addSeparator(); addAction(aAttach); if (card->getAttachedTo()) { @@ -179,9 +177,6 @@ void CardMenu::createTableMenu(bool canModifyCard) addMenu(new PtMenu(player)); addAction(aSetAnnotation); addSeparator(); - addAction(aClone); - addMenu(new MoveMenu(player)); - addSeparator(); addAction(aSelectAll); addAction(aSelectRow); @@ -197,27 +192,35 @@ void CardMenu::createTableMenu(bool canModifyCard) } addSeparator(); addMenu(mCardCounters); + addRelatedCardView(); + addRelatedCardActions(); } void CardMenu::createStackMenu(bool canModifyCard) { // Card is on the stack - if (canModifyCard) { - addAction(aAttach); + if (!canModifyCard) { addAction(aDrawArrow); addSeparator(); - addAction(aClone); - addMenu(new MoveMenu(player)); - addSeparator(); - addAction(aSelectAll); - } else { - addAction(aDrawArrow); + addRelatedCardView(); + addRelatedCardActions(); addSeparator(); addAction(aClone); addSeparator(); addAction(aSelectAll); + return; } + addAction(aPlay); + addAction(aPlayFacedown); + addSeparator(); + addAction(aClone); + addMenu(new MoveMenu(player)); + addSeparator(); + addAction(aAttach); + addAction(aDrawArrow); + addSeparator(); + addAction(aSelectAll); addRelatedCardView(); addRelatedCardActions(); } @@ -225,29 +228,30 @@ void CardMenu::createStackMenu(bool canModifyCard) void CardMenu::createGraveyardOrExileMenu(bool canModifyCard) { // Card is in the graveyard or exile - if (canModifyCard) { - addAction(aPlay); - addAction(aPlayFacedown); - - addSeparator(); - addAction(aClone); - addMenu(new MoveMenu(player)); - addSeparator(); - addAction(aSelectAll); - addAction(aSelectColumn); - - addSeparator(); - addAction(aAttach); + if (!canModifyCard) { addAction(aDrawArrow); - } else { + addSeparator(); + addRelatedCardView(); + addRelatedCardActions(); + addSeparator(); addAction(aClone); addSeparator(); addAction(aSelectAll); addAction(aSelectColumn); - addSeparator(); - addAction(aDrawArrow); + return; } + addAction(aPlay); + addAction(aPlayFacedown); + addSeparator(); + addAction(aClone); + addMenu(new MoveMenu(player)); + addSeparator(); + addAction(aAttach); + addAction(aDrawArrow); + addSeparator(); + addAction(aSelectAll); + addAction(aSelectColumn); addRelatedCardView(); addRelatedCardActions(); } diff --git a/cockatrice/src/game/player/menu/move_menu.cpp b/cockatrice/src/game/player/menu/move_menu.cpp index d27e16009..736d2fcc2 100644 --- a/cockatrice/src/game/player/menu/move_menu.cpp +++ b/cockatrice/src/game/player/menu/move_menu.cpp @@ -17,6 +17,8 @@ MoveMenu::MoveMenu(Player *player) : QMenu(tr("Move to")) aMoveToGraveyard->setData(cmMoveToGraveyard); aMoveToExile = new QAction(this); aMoveToExile->setData(cmMoveToExile); + aMoveToTable = new QAction(this); + aMoveToTable->setData(cmMoveToTable); connect(aMoveToTopLibrary, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction); connect(aMoveToBottomLibrary, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction); @@ -25,11 +27,14 @@ MoveMenu::MoveMenu(Player *player) : QMenu(tr("Move to")) connect(aMoveToHand, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction); connect(aMoveToGraveyard, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction); connect(aMoveToExile, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction); + connect(aMoveToTable, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction); addAction(aMoveToTopLibrary); addAction(aMoveToXfromTopOfLibrary); addAction(aMoveToBottomLibrary); addSeparator(); + addAction(aMoveToTable); + addSeparator(); addAction(aMoveToHand); addSeparator(); addAction(aMoveToGraveyard); @@ -50,6 +55,7 @@ void MoveMenu::setShortcutsActive() aMoveToHand->setShortcuts(shortcuts.getShortcut("Player/aMoveToHand")); aMoveToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveToGraveyard")); aMoveToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveToExile")); + aMoveToTable->setShortcuts(shortcuts.getShortcut("Player/aMoveToTable")); } void MoveMenu::retranslateUi() @@ -59,5 +65,6 @@ void MoveMenu::retranslateUi() aMoveToBottomLibrary->setText(tr("&Bottom of library in random order")); aMoveToHand->setText(tr("&Hand")); aMoveToGraveyard->setText(tr("&Graveyard")); + aMoveToTable->setText(tr("T&able")); aMoveToExile->setText(tr("&Exile")); } \ No newline at end of file diff --git a/cockatrice/src/game/player/menu/move_menu.h b/cockatrice/src/game/player/menu/move_menu.h index 5bf657fa4..dc39cb6a5 100644 --- a/cockatrice/src/game/player/menu/move_menu.h +++ b/cockatrice/src/game/player/menu/move_menu.h @@ -23,6 +23,7 @@ public: QAction *aMoveToBottomLibrary = nullptr; QAction *aMoveToHand = nullptr; + QAction *aMoveToTable = nullptr; QAction *aMoveToGraveyard = nullptr; QAction *aMoveToExile = nullptr; }; diff --git a/cockatrice/src/game/player/player_actions.cpp b/cockatrice/src/game/player/player_actions.cpp index 20e526727..2a0061c77 100644 --- a/cockatrice/src/game/player/player_actions.cpp +++ b/cockatrice/src/game/player/player_actions.cpp @@ -75,7 +75,7 @@ void PlayerActions::playCard(CardItem *card, bool faceDown) cmd.set_y(0); } else { tableRow = faceDown ? 2 : info.getUiAttributes().tableRow; - QPoint gridPoint = QPoint(-1, TableZone::clampValidTableRow(2 - tableRow)); + QPoint gridPoint = QPoint(-1, TableZone::tableRowToGridY(tableRow)); cardToMove->set_face_down(faceDown); if (!faceDown) { cardToMove->set_pt(info.getPowTough().toStdString()); @@ -114,12 +114,7 @@ void PlayerActions::playCardToTable(const CardItem *card, bool faceDown) const CardInfo &info = exactCard.getInfo(); int tableRow = faceDown ? 2 : info.getUiAttributes().tableRow; - // default instant/sorcery cards to the noncreatures row - if (tableRow > 2) { - tableRow = 1; - } - - QPoint gridPoint = QPoint(-1, TableZone::clampValidTableRow(2 - tableRow)); + QPoint gridPoint = QPoint(-1, TableZone::tableRowToGridY(tableRow)); cardToMove->set_face_down(faceDown); if (!faceDown) { cardToMove->set_pt(info.getPowTough().toStdString()); @@ -869,7 +864,7 @@ void PlayerActions::actCreateToken() ExactCard correctedCard = CardDatabaseManager::query()->guessCard({lastTokenInfo.name, lastTokenInfo.providerId}); if (correctedCard) { lastTokenInfo.name = correctedCard.getName(); - lastTokenTableRow = TableZone::clampValidTableRow(2 - correctedCard.getInfo().getUiAttributes().tableRow); + lastTokenTableRow = TableZone::tableRowToGridY(correctedCard.getInfo().getUiAttributes().tableRow); if (lastTokenInfo.pt.isEmpty()) { lastTokenInfo.pt = correctedCard.getInfo().getPowTough(); } @@ -920,7 +915,7 @@ void PlayerActions::setLastToken(CardInfoPtr cardInfo) .providerId = SettingsCache::instance().cardOverrides().getCardPreferenceOverride(cardInfo->getName())}; - lastTokenTableRow = TableZone::clampValidTableRow(2 - cardInfo->getUiAttributes().tableRow); + lastTokenTableRow = TableZone::tableRowToGridY(cardInfo->getUiAttributes().tableRow); utilityMenu->setAndEnableCreateAnotherTokenAction(tr("C&reate another %1 token").arg(lastTokenInfo.name)); } @@ -1088,9 +1083,7 @@ void PlayerActions::createCard(const CardItem *sourceCard, return; } - // get the target token's location - // TODO: Define this QPoint into its own function along with the one below - QPoint gridPoint = QPoint(-1, TableZone::clampValidTableRow(2 - cardInfo->getUiAttributes().tableRow)); + QPoint gridPoint = QPoint(-1, TableZone::tableRowToGridY(cardInfo->getUiAttributes().tableRow)); // create the token for the related card Command_CreateToken cmd; @@ -1933,6 +1926,33 @@ void PlayerActions::cardMenuAction() commandList.append(cmd); break; } + case cmMoveToTable: { + for (const auto &card : cardList) { + auto *cmd = new Command_MoveCard; + cmd->set_start_player_id(startPlayerId); + cmd->set_start_zone(startZone.toStdString()); + cmd->set_target_player_id(player->getPlayerInfo()->getId()); + cmd->set_target_zone(ZoneNames::TABLE); + cmd->set_x(-1); + + CardToMove *ctm = cmd->mutable_cards_to_move()->add_card(); + ctm->set_card_id(card->getId()); + ctm->set_face_down(false); + + int tableRow = 0; + ExactCard exactCard = card->getCard(); + if (exactCard) { + const CardInfo &info = exactCard.getInfo(); + tableRow = info.getUiAttributes().tableRow; + ctm->set_pt(info.getPowTough().toStdString()); + ctm->set_tapped(info.getUiAttributes().cipt); + } + + cmd->set_y(TableZone::tableRowToGridY(tableRow)); + commandList.append(cmd); + } + break; + } default: break; } diff --git a/cockatrice/src/game/zones/table_zone.cpp b/cockatrice/src/game/zones/table_zone.cpp index b6ac2150b..2a382fafe 100644 --- a/cockatrice/src/game/zones/table_zone.cpp +++ b/cockatrice/src/game/zones/table_zone.cpp @@ -382,3 +382,11 @@ int TableZone::clampValidTableRow(const int row) return TABLEROWS - 1; return row; } + +int TableZone::tableRowToGridY(int tableRow) +{ + if (tableRow > 2) { + tableRow = 1; + } + return clampValidTableRow(2 - tableRow); +} diff --git a/cockatrice/src/game/zones/table_zone.h b/cockatrice/src/game/zones/table_zone.h index 61eb48d7b..7a53a9eb4 100644 --- a/cockatrice/src/game/zones/table_zone.h +++ b/cockatrice/src/game/zones/table_zone.h @@ -151,6 +151,13 @@ public: static int clampValidTableRow(const int row); + /** + * Converts a card's logical table row (0=creatures, 1=noncreatures, 2=lands) + * to the corresponding grid Y coordinate. Cards with tableRow > 2 (e.g., + * instants/sorceries) default to the noncreatures row. + */ + static int tableRowToGridY(int tableRow); + /** Resizes the TableZone in case CardItems are within or outside of the TableZone constraints.