Generalize tax counters to 5 sequential slots with server-enforced ordering

This commit is contained in:
DawnFire42 2026-08-10 20:04:51 -04:00
parent 876a14758e
commit 4354191918
No known key found for this signature in database
GPG key ID: 24BB855EE2911B33
14 changed files with 352 additions and 251 deletions

View file

@ -597,16 +597,16 @@ private:
{"Player/aViewBottomCards", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Bottom Cards of Library"),
parseSequenceString("Ctrl+Shift+W"),
ShortcutGroup::View)},
{"Player/aAddCommanderTax", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Increase Commander Tax"),
{"Player/aAddCommanderTax", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Increase 1st Tax"),
parseSequenceString(""),
ShortcutGroup::Player_Counters)},
{"Player/aRemoveCommanderTax", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Decrease Commander Tax"),
{"Player/aRemoveCommanderTax", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Decrease 1st Tax"),
parseSequenceString(""),
ShortcutGroup::Player_Counters)},
{"Player/aAddPartnerTax", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Increase Partner Tax"),
{"Player/aAddPartnerTax", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Increase 2nd Tax"),
parseSequenceString(""),
ShortcutGroup::Player_Counters)},
{"Player/aRemovePartnerTax", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Decrease Partner Tax"),
{"Player/aRemovePartnerTax", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Decrease 2nd Tax"),
parseSequenceString(""),
ShortcutGroup::Player_Counters)},
{"Player/aCloseMostRecentZoneView", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Close Recent View"),

View file

@ -1674,14 +1674,14 @@ void PlayerActions::playSelectedCardsImpl(
}
}
void PlayerActions::actPlayAndIncreaseTax(QList<CardItem *> selectedCards)
void PlayerActions::actPlayAndIncrease1stTax(QList<CardItem *> selectedCards)
{
playAndIncreaseTax(selectedCards, CounterIds::CommanderTax);
playAndIncreaseTax(selectedCards, CounterIds::TaxCounter1);
}
void PlayerActions::actPlayAndIncreasePartnerTax(QList<CardItem *> selectedCards)
void PlayerActions::actPlayAndIncrease2ndTax(QList<CardItem *> selectedCards)
{
playAndIncreaseTax(selectedCards, CounterIds::PartnerTax);
playAndIncreaseTax(selectedCards, CounterIds::TaxCounter2);
}
void PlayerActions::playAndIncreaseTax(QList<CardItem *> selectedCards, int counterId)

View file

@ -127,10 +127,10 @@ public slots:
void actPlay(QList<CardItem *> selectedCards);
void actPlayFacedown(QList<CardItem *> selectedCards);
/** @brief Plays the selected card and increments the primary commander tax counter. */
void actPlayAndIncreaseTax(QList<CardItem *> selectedCards);
/** @brief Plays the selected card and increments the partner commander tax counter. */
void actPlayAndIncreasePartnerTax(QList<CardItem *> selectedCards);
/** @brief Plays the selected card and increments the 1st tax counter. */
void actPlayAndIncrease1stTax(QList<CardItem *> selectedCards);
/** @brief Plays the selected card and increments the 2nd tax counter. */
void actPlayAndIncrease2ndTax(QList<CardItem *> selectedCards);
/** @brief Modifies a tax counter by delta if it is active. */
void actModifyTaxCounter(int counterId, int delta);
/** @brief Toggles a tax counter's active state (only if inactive or value is 0). */
@ -282,7 +282,7 @@ private:
* @brief Plays the selected cards and, for each that came from the command zone and whose move
* the server accepts, increments the given (active) tax counter by one.
* @param selectedCards Cards to play
* @param counterId The tax counter to increment (CounterIds::CommanderTax or PartnerTax)
* @param counterId The tax counter to increment (CounterIds::TaxCounter1 through TaxCounter5)
*/
void playAndIncreaseTax(QList<CardItem *> selectedCards, int counterId);

View file

@ -11,5 +11,8 @@ const QMap<QString, QString> TranslateCounterName::translated = {
{"g", QT_TRANSLATE_NOOP("TranslateCounterName", "Green")},
{"x", QT_TRANSLATE_NOOP("TranslateCounterName", "Colorless")},
{"storm", QT_TRANSLATE_NOOP("TranslateCounterName", "Other")},
{CounterNames::CommanderTax, QT_TRANSLATE_NOOP("TranslateCounterName", "Commander Tax")},
{CounterNames::PartnerTax, QT_TRANSLATE_NOOP("TranslateCounterName", "Partner Tax")}};
{CounterNames::TaxCounter1, QT_TRANSLATE_NOOP("TranslateCounterName", "1st Tax")},
{CounterNames::TaxCounter2, QT_TRANSLATE_NOOP("TranslateCounterName", "2nd Tax")},
{CounterNames::TaxCounter3, QT_TRANSLATE_NOOP("TranslateCounterName", "3rd Tax")},
{CounterNames::TaxCounter4, QT_TRANSLATE_NOOP("TranslateCounterName", "4th Tax")},
{CounterNames::TaxCounter5, QT_TRANSLATE_NOOP("TranslateCounterName", "5th Tax")}};

View file

@ -84,8 +84,8 @@ CardMenu::CardMenu(PlayerGraphicsItem *_player, const CardItem *_card, bool _sho
aUnattach = makeAction(this, [actions, sel]() { actions->actUnattach(sel()); });
aSetAnnotation = makeAction(this, [actions, sel]() { actions->actRequestSetAnnotationDialog(sel()); });
aPlay = makeAction(this, [actions, sel]() { actions->actPlay(sel()); });
aPlayAndIncreaseTax = makeAction(this, [actions, sel]() { actions->actPlayAndIncreaseTax(sel()); });
aPlayAndIncreasePartnerTax = makeAction(this, [actions, sel]() { actions->actPlayAndIncreasePartnerTax(sel()); });
aPlayAndIncrease1stTax = makeAction(this, [actions, sel]() { actions->actPlayAndIncrease1stTax(sel()); });
aPlayAndIncrease2ndTax = makeAction(this, [actions, sel]() { actions->actPlayAndIncrease2ndTax(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()); });
@ -170,12 +170,12 @@ CardMenu::CardMenu(PlayerGraphicsItem *_player, const CardItem *_card, bool _sho
// bumping one commander's tax counter once per command-zone card.
const bool singleSelection = gameScene->selectedCards().size() <= 1;
if (singleSelection && player->getTaxCounterIfActive(CounterIds::CommanderTax)) {
addAction(aPlayAndIncreaseTax);
if (singleSelection && player->getTaxCounterIfActive(CounterIds::TaxCounter1)) {
addAction(aPlayAndIncrease1stTax);
}
if (singleSelection && player->getTaxCounterIfActive(CounterIds::PartnerTax)) {
addAction(aPlayAndIncreasePartnerTax);
if (singleSelection && player->getTaxCounterIfActive(CounterIds::TaxCounter2)) {
addAction(aPlayAndIncrease2ndTax);
}
// No reveal submenu - command zone is public
@ -524,8 +524,8 @@ void CardMenu::retranslateUi()
aPlay->setText(tr("&Play"));
aHide->setText(tr("&Hide"));
aPlayFacedown->setText(tr("Play &Face Down"));
aPlayAndIncreaseTax->setText(tr("Play and &Increase Commander Tax"));
aPlayAndIncreasePartnerTax->setText(tr("Play and Increase &Partner Tax"));
aPlayAndIncrease1stTax->setText(tr("Play and &Increase 1st Tax"));
aPlayAndIncrease2ndTax->setText(tr("Play and Increase &2nd Tax"));
aRevealToAll->setText(tr("&All players"));
//: Turn sideways or back again
aTap->setText(tr("&Tap / Untap"));

View file

@ -33,7 +33,7 @@ public:
QAction *aPlay, *aPlayFacedown;
/** @brief Play actions that also increment the corresponding tax counter. */
QAction *aPlayAndIncreaseTax, *aPlayAndIncreasePartnerTax;
QAction *aPlayAndIncrease1stTax, *aPlayAndIncrease2ndTax;
QAction *aRevealToAll;
QAction *aHide;
QAction *aClone;

View file

@ -14,66 +14,45 @@
CommandZoneMenu::CommandZoneMenu(PlayerGraphicsItem *_player, QMenu *playerMenu) : QMenu(playerMenu), player(_player)
{
incTaxShortcutKey = QStringLiteral("Player/aAddCommanderTax");
decTaxShortcutKey = QStringLiteral("Player/aRemoveCommanderTax");
incPartnerTaxShortcutKey = QStringLiteral("Player/aAddPartnerTax");
decPartnerTaxShortcutKey = QStringLiteral("Player/aRemovePartnerTax");
// Shortcuts only for first two tax counters (matching legacy behavior)
incTax1ShortcutKey = QStringLiteral("Player/aAddCommanderTax");
decTax1ShortcutKey = QStringLiteral("Player/aRemoveCommanderTax");
incTax2ShortcutKey = QStringLiteral("Player/aAddPartnerTax");
decTax2ShortcutKey = QStringLiteral("Player/aRemovePartnerTax");
PlayerLogic *logic = player->getLogic();
if (logic && logic->getPlayerInfo()->getLocalOrJudge()) {
aIncreaseCommanderTax = new QAction(this);
connect(aIncreaseCommanderTax, &QAction::triggered, this, [this]() {
if (auto *logic = player->getLogic()) {
logic->getPlayerActions()->actModifyTaxCounter(CounterIds::CommanderTax, 1);
}
});
addAction(aIncreaseCommanderTax);
for (int i = 0; i < TaxCounterCount; ++i) {
int counterId = CounterIds::taxCounterIdFromIndex(i);
aDecreaseCommanderTax = new QAction(this);
connect(aDecreaseCommanderTax, &QAction::triggered, this, [this]() {
if (auto *logic = player->getLogic()) {
logic->getPlayerActions()->actModifyTaxCounter(CounterIds::CommanderTax, -1);
}
});
addAction(aDecreaseCommanderTax);
aIncreaseTax[i] = new QAction(this);
connect(aIncreaseTax[i], &QAction::triggered, this, [this, counterId]() {
if (auto *l = player->getLogic()) {
l->getPlayerActions()->actModifyTaxCounter(counterId, 1);
}
});
addAction(aIncreaseTax[i]);
addSeparator();
aDecreaseTax[i] = new QAction(this);
connect(aDecreaseTax[i], &QAction::triggered, this, [this, counterId]() {
if (auto *l = player->getLogic()) {
l->getPlayerActions()->actModifyTaxCounter(counterId, -1);
}
});
addAction(aDecreaseTax[i]);
aIncreasePartnerTax = new QAction(this);
connect(aIncreasePartnerTax, &QAction::triggered, this, [this]() {
if (auto *logic = player->getLogic()) {
logic->getPlayerActions()->actModifyTaxCounter(CounterIds::PartnerTax, 1);
}
});
addAction(aIncreasePartnerTax);
addSeparator();
aDecreasePartnerTax = new QAction(this);
connect(aDecreasePartnerTax, &QAction::triggered, this, [this]() {
if (auto *logic = player->getLogic()) {
logic->getPlayerActions()->actModifyTaxCounter(CounterIds::PartnerTax, -1);
}
});
addAction(aDecreasePartnerTax);
aToggleTax[i] = new QAction(this);
connect(aToggleTax[i], &QAction::triggered, this, [this, counterId]() {
if (auto *l = player->getLogic()) {
l->getPlayerActions()->actToggleTaxCounter(counterId);
}
});
addAction(aToggleTax[i]);
addSeparator();
aToggleCommanderTaxCounter = new QAction(this);
connect(aToggleCommanderTaxCounter, &QAction::triggered, this, [this]() {
if (auto *logic = player->getLogic()) {
logic->getPlayerActions()->actToggleTaxCounter(CounterIds::CommanderTax);
}
});
addAction(aToggleCommanderTaxCounter);
aTogglePartnerTaxCounter = new QAction(this);
connect(aTogglePartnerTaxCounter, &QAction::triggered, this, [this]() {
if (auto *logic = player->getLogic()) {
logic->getPlayerActions()->actToggleTaxCounter(CounterIds::PartnerTax);
}
});
addAction(aTogglePartnerTaxCounter);
addSeparator();
addSeparator();
}
aToggleMinimized = new QAction(this);
connect(aToggleMinimized, &QAction::triggered, this, &CommandZoneMenu::actToggleMinimized);
@ -88,19 +67,19 @@ CommandZoneMenu::CommandZoneMenu(PlayerGraphicsItem *_player, QMenu *playerMenu)
void CommandZoneMenu::retranslateUi()
{
setTitle(tr("Co&mmander"));
if (aIncreaseCommanderTax) {
aIncreaseCommanderTax->setText(tr("&Increase Commander Tax (+1)"));
static const char *ordinals[] = {"1st", "2nd", "3rd", "4th", "5th"};
for (int i = 0; i < TaxCounterCount; ++i) {
if (aIncreaseTax[i]) {
aIncreaseTax[i]->setText(tr("&Increase %1 Tax (+1)").arg(ordinals[i]));
}
if (aDecreaseTax[i]) {
aDecreaseTax[i]->setText(tr("&Decrease %1 Tax (-1)").arg(ordinals[i]));
}
// Toggle action labels are derived dynamically in updateTaxCounterActionStates()
}
if (aDecreaseCommanderTax) {
aDecreaseCommanderTax->setText(tr("&Decrease Commander Tax (-1)"));
}
if (aIncreasePartnerTax) {
aIncreasePartnerTax->setText(tr("Increase &Partner Tax (+1)"));
}
if (aDecreasePartnerTax) {
aDecreasePartnerTax->setText(tr("Decrease P&artner Tax (-1)"));
}
// Toggle action labels are derived dynamically in updateTaxCounterActionStates()
if (aToggleMinimized) {
aToggleMinimized->setText(tr("&Minimize"));
}
@ -116,29 +95,43 @@ void CommandZoneMenu::actToggleMinimized()
void CommandZoneMenu::updateTaxCounterActionStates()
{
AbstractCounter *cmdTax = player->getTaxCounterIfActive(CounterIds::CommanderTax);
AbstractCounter *partnerTax = player->getTaxCounterIfActive(CounterIds::PartnerTax);
static const char *ordinals[] = {"1st", "2nd", "3rd", "4th", "5th"};
if (aIncreaseCommanderTax) {
aIncreaseCommanderTax->setVisible(cmdTax && cmdTax->getValue() < MAX_COUNTER_VALUE);
}
if (aDecreaseCommanderTax) {
aDecreaseCommanderTax->setVisible(cmdTax && cmdTax->getValue() > 0);
}
if (aToggleCommanderTaxCounter) {
aToggleCommanderTaxCounter->setText(cmdTax ? tr("&Remove Commander Tax") : tr("&Add Commander Tax"));
aToggleCommanderTaxCounter->setVisible(!cmdTax || (cmdTax->getValue() == 0 && !partnerTax));
// Collect all tax counter states
std::array<AbstractCounter *, TaxCounterCount> taxCounters{};
for (int i = 0; i < TaxCounterCount; ++i) {
taxCounters[i] = player->getTaxCounterIfActive(CounterIds::taxCounterIdFromIndex(i));
}
if (aIncreasePartnerTax) {
aIncreasePartnerTax->setVisible(partnerTax && partnerTax->getValue() < MAX_COUNTER_VALUE);
// Find highest active tax counter index
int highestActive = -1;
for (int i = TaxCounterCount - 1; i >= 0; --i) {
if (taxCounters[i]) {
highestActive = i;
break;
}
}
if (aDecreasePartnerTax) {
aDecreasePartnerTax->setVisible(partnerTax && partnerTax->getValue() > 0);
}
if (aTogglePartnerTaxCounter) {
aTogglePartnerTaxCounter->setText(partnerTax ? tr("R&emove Partner Tax") : tr("&Add Partner Tax"));
aTogglePartnerTaxCounter->setVisible(!partnerTax || partnerTax->getValue() == 0);
for (int i = 0; i < TaxCounterCount; ++i) {
AbstractCounter *counter = taxCounters[i];
if (aIncreaseTax[i]) {
aIncreaseTax[i]->setVisible(counter && counter->getValue() < MAX_COUNTER_VALUE);
}
if (aDecreaseTax[i]) {
aDecreaseTax[i]->setVisible(counter && counter->getValue() > 0);
}
if (aToggleTax[i]) {
aToggleTax[i]->setText(counter ? tr("&Remove %1 Tax").arg(ordinals[i])
: tr("&Add %1 Tax").arg(ordinals[i]));
// Toggle visible if:
// - Counter doesn't exist and previous counter is active (can add next in sequence)
// - Counter exists with value 0 and is the highest active (can remove last in sequence)
bool canAdd = !counter && (i == 0 || taxCounters[i - 1]);
bool canRemove = counter && counter->getValue() == 0 && i == highestActive;
aToggleTax[i]->setVisible(canAdd || canRemove);
}
}
if (aToggleMinimized) {
@ -151,32 +144,34 @@ void CommandZoneMenu::setShortcutsActive()
{
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
if (aIncreaseCommanderTax) {
aIncreaseCommanderTax->setShortcuts(shortcuts.getShortcut(incTaxShortcutKey));
// Only first two tax counters have shortcuts
if (aIncreaseTax[0]) {
aIncreaseTax[0]->setShortcuts(shortcuts.getShortcut(incTax1ShortcutKey));
}
if (aDecreaseCommanderTax) {
aDecreaseCommanderTax->setShortcuts(shortcuts.getShortcut(decTaxShortcutKey));
if (aDecreaseTax[0]) {
aDecreaseTax[0]->setShortcuts(shortcuts.getShortcut(decTax1ShortcutKey));
}
if (aIncreasePartnerTax) {
aIncreasePartnerTax->setShortcuts(shortcuts.getShortcut(incPartnerTaxShortcutKey));
if (aIncreaseTax[1]) {
aIncreaseTax[1]->setShortcuts(shortcuts.getShortcut(incTax2ShortcutKey));
}
if (aDecreasePartnerTax) {
aDecreasePartnerTax->setShortcuts(shortcuts.getShortcut(decPartnerTaxShortcutKey));
if (aDecreaseTax[1]) {
aDecreaseTax[1]->setShortcuts(shortcuts.getShortcut(decTax2ShortcutKey));
}
}
void CommandZoneMenu::setShortcutsInactive()
{
if (aIncreaseCommanderTax) {
aIncreaseCommanderTax->setShortcut(QKeySequence());
// Only first two tax counters have shortcuts
if (aIncreaseTax[0]) {
aIncreaseTax[0]->setShortcut(QKeySequence());
}
if (aDecreaseCommanderTax) {
aDecreaseCommanderTax->setShortcut(QKeySequence());
if (aDecreaseTax[0]) {
aDecreaseTax[0]->setShortcut(QKeySequence());
}
if (aIncreasePartnerTax) {
aIncreasePartnerTax->setShortcut(QKeySequence());
if (aIncreaseTax[1]) {
aIncreaseTax[1]->setShortcut(QKeySequence());
}
if (aDecreasePartnerTax) {
aDecreasePartnerTax->setShortcut(QKeySequence());
if (aDecreaseTax[1]) {
aDecreaseTax[1]->setShortcut(QKeySequence());
}
}

View file

@ -10,6 +10,8 @@
#include "abstract_player_component.h"
#include <QMenu>
#include <array>
#include <libcockatrice/utility/counter_ids.h>
class PlayerGraphicsItem;
@ -18,7 +20,7 @@ class PlayerGraphicsItem;
* @brief Context menu for the command zone.
*
* Appears when right-clicking on the command zone. Provides actions for
* adjusting the commander tax counter and toggling minimized state.
* adjusting tax counters (up to 5) and toggling minimized state.
*
* @see PlayerMenu
* @see CommandZone
@ -34,13 +36,12 @@ public:
void setShortcutsInactive() override;
private:
QAction *aIncreaseCommanderTax = nullptr; ///< Increments the primary commander tax counter
QAction *aDecreaseCommanderTax = nullptr; ///< Decrements the primary commander tax counter
QAction *aToggleCommanderTaxCounter = nullptr; ///< Toggles primary commander tax counter visibility
QAction *aIncreasePartnerTax = nullptr; ///< Increments the partner commander tax counter
QAction *aDecreasePartnerTax = nullptr; ///< Decrements the partner commander tax counter
QAction *aTogglePartnerTaxCounter = nullptr; ///< Toggles partner commander tax counter visibility
QAction *aToggleMinimized = nullptr; ///< Toggles command zone minimized state
static constexpr int TaxCounterCount = CounterIds::TaxCounterCount;
std::array<QAction *, TaxCounterCount> aIncreaseTax{};
std::array<QAction *, TaxCounterCount> aDecreaseTax{};
std::array<QAction *, TaxCounterCount> aToggleTax{};
QAction *aToggleMinimized = nullptr;
public slots:
void updateTaxCounterActionStates();
@ -51,10 +52,11 @@ private slots:
private:
PlayerGraphicsItem *player;
QString incTaxShortcutKey;
QString decTaxShortcutKey;
QString incPartnerTaxShortcutKey;
QString decPartnerTaxShortcutKey;
// Shortcuts only for first two tax counters
QString incTax1ShortcutKey;
QString decTax1ShortcutKey;
QString incTax2ShortcutKey;
QString decTax2ShortcutKey;
};
#endif // COCKATRICE_COMMAND_ZONE_MENU_H