mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-29 09:22:18 -07:00
Refactor tax counters into cast counts with separate ID space and user activated create/delete
This commit is contained in:
parent
4354191918
commit
f5e49a571e
50 changed files with 900 additions and 828 deletions
|
|
@ -67,7 +67,7 @@ set(cockatrice_SOURCES
|
|||
src/game_graphics/board/card_item.cpp
|
||||
src/game/board/card_list.cpp
|
||||
src/game/board/card_state.cpp
|
||||
src/game_graphics/board/commander_tax_counter.cpp
|
||||
src/game_graphics/board/cast_count_widget.cpp
|
||||
src/game_graphics/board/counter_general.cpp
|
||||
src/game/board/counter_state.cpp
|
||||
src/game_graphics/board/translate_counter_name.cpp
|
||||
|
|
|
|||
|
|
@ -597,18 +597,18 @@ 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 1st Tax"),
|
||||
parseSequenceString(""),
|
||||
ShortcutGroup::Player_Counters)},
|
||||
{"Player/aRemoveCommanderTax", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Decrease 1st Tax"),
|
||||
parseSequenceString(""),
|
||||
ShortcutGroup::Player_Counters)},
|
||||
{"Player/aAddPartnerTax", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Increase 2nd Tax"),
|
||||
parseSequenceString(""),
|
||||
ShortcutGroup::Player_Counters)},
|
||||
{"Player/aRemovePartnerTax", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Decrease 2nd Tax"),
|
||||
parseSequenceString(""),
|
||||
ShortcutGroup::Player_Counters)},
|
||||
{"Player/aIncrease1stCastCount", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Increase 1st Cast Count"),
|
||||
parseSequenceString(""),
|
||||
ShortcutGroup::Player_Counters)},
|
||||
{"Player/aDecrease1stCastCount", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Decrease 1st Cast Count"),
|
||||
parseSequenceString(""),
|
||||
ShortcutGroup::Player_Counters)},
|
||||
{"Player/aIncrease2ndCastCount", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Increase 2nd Cast Count"),
|
||||
parseSequenceString(""),
|
||||
ShortcutGroup::Player_Counters)},
|
||||
{"Player/aDecrease2ndCastCount", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Decrease 2nd Cast Count"),
|
||||
parseSequenceString(""),
|
||||
ShortcutGroup::Player_Counters)},
|
||||
{"Player/aCloseMostRecentZoneView", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Close Recent View"),
|
||||
parseSequenceString("Esc"),
|
||||
ShortcutGroup::View)},
|
||||
|
|
|
|||
|
|
@ -14,10 +14,13 @@
|
|||
#include <libcockatrice/card/relation/card_relation.h>
|
||||
#include <libcockatrice/protocol/pb/command_attach_card.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_change_zone_properties.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_create_cast_count.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_create_token.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_delete_cast_count.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_draw_cards.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_flip_card.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_game_say.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_inc_cast_count.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_inc_counter.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_move_card.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_mulligan.pb.h>
|
||||
|
|
@ -25,7 +28,6 @@
|
|||
#include <libcockatrice/protocol/pb/command_roll_die.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_card_counter.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_counter_active.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_shuffle.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_undo_draw.pb.h>
|
||||
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
|
||||
|
|
@ -1674,32 +1676,34 @@ void PlayerActions::playSelectedCardsImpl(
|
|||
}
|
||||
}
|
||||
|
||||
void PlayerActions::actPlayAndIncrease1stTax(QList<CardItem *> selectedCards)
|
||||
void PlayerActions::actPlayAndIncrease1stCastCount(QList<CardItem *> selectedCards)
|
||||
{
|
||||
playAndIncreaseTax(selectedCards, CounterIds::TaxCounter1);
|
||||
playAndIncreaseCastCount(selectedCards, 1);
|
||||
}
|
||||
|
||||
void PlayerActions::actPlayAndIncrease2ndTax(QList<CardItem *> selectedCards)
|
||||
void PlayerActions::actPlayAndIncrease2ndCastCount(QList<CardItem *> selectedCards)
|
||||
{
|
||||
playAndIncreaseTax(selectedCards, CounterIds::TaxCounter2);
|
||||
playAndIncreaseCastCount(selectedCards, 2);
|
||||
}
|
||||
|
||||
void PlayerActions::playAndIncreaseTax(QList<CardItem *> selectedCards, int counterId)
|
||||
void PlayerActions::playAndIncreaseCastCount(QList<CardItem *> selectedCards, int index)
|
||||
{
|
||||
playSelectedCardsImpl(selectedCards, false, [this, counterId](PendingCommand *pend, const QString &originalZone) {
|
||||
playSelectedCardsImpl(selectedCards, false, [this, index](PendingCommand *pend, const QString &originalZone) {
|
||||
if (originalZone != ZoneNames::COMMAND || pend == nullptr) {
|
||||
return;
|
||||
}
|
||||
// Gate the tax increment on the server accepting the move, so a rejected move
|
||||
// (the card couldn't legally leave the command zone) never inflates the tax.
|
||||
// Gate the increment on the server accepting the move
|
||||
connect(pend, &PendingCommand::finished, this,
|
||||
[this, counterId](const Response &response, const CommandContainer &, const QVariant &) {
|
||||
[this, index](const Response &response, const CommandContainer &, const QVariant &) {
|
||||
if (response.response_code() != Response::RespOk) {
|
||||
return;
|
||||
}
|
||||
CounterState *state = player->getCounters().value(counterId, nullptr);
|
||||
if (state && state->isActive()) {
|
||||
sendIncCounter(counterId, 1);
|
||||
CounterState *state = player->getCastCount(index);
|
||||
if (state) {
|
||||
Command_IncCastCount cmd;
|
||||
cmd.set_index(index);
|
||||
cmd.set_delta(1);
|
||||
sendGameCommand(cmd);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -1713,29 +1717,40 @@ void PlayerActions::sendIncCounter(int counterId, int delta)
|
|||
sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
void PlayerActions::actModifyTaxCounter(int counterId, int delta)
|
||||
void PlayerActions::actModifyCastCount(int index, int delta)
|
||||
{
|
||||
CounterState *state = player->getCounters().value(counterId, nullptr);
|
||||
if (!state || !state->isActive() || !CounterIds::isTaxCounter(counterId)) {
|
||||
if (!CastCountIds::isValidIndex(index)) {
|
||||
return;
|
||||
}
|
||||
sendIncCounter(counterId, delta);
|
||||
CounterState *state = player->getCastCount(index);
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
Command_IncCastCount cmd;
|
||||
cmd.set_index(index);
|
||||
cmd.set_delta(delta);
|
||||
sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
void PlayerActions::actToggleTaxCounter(int counterId)
|
||||
void PlayerActions::actToggleCastCount(int index)
|
||||
{
|
||||
CounterState *state = player->getCounters().value(counterId, nullptr);
|
||||
if (!state || !CounterIds::isTaxCounter(counterId)) {
|
||||
if (!CastCountIds::isValidIndex(index)) {
|
||||
return;
|
||||
}
|
||||
// Prevent disabling a counter with tax accumulated; player must reset to 0 first
|
||||
if (state->isActive() && state->getValue() != 0) {
|
||||
return;
|
||||
CounterState *state = player->getCastCount(index);
|
||||
if (state) {
|
||||
// Delete only allowed when value is 0
|
||||
if (state->getValue() != 0) {
|
||||
return;
|
||||
}
|
||||
Command_DeleteCastCount cmd;
|
||||
cmd.set_index(index);
|
||||
sendGameCommand(cmd);
|
||||
} else {
|
||||
Command_CreateCastCount cmd;
|
||||
cmd.set_index(index);
|
||||
sendGameCommand(cmd);
|
||||
}
|
||||
Command_SetCounterActive cmd;
|
||||
cmd.set_counter_id(counterId);
|
||||
cmd.set_active(!state->isActive());
|
||||
sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
void PlayerActions::actPlay(QList<CardItem *> selectedCards)
|
||||
|
|
|
|||
|
|
@ -127,14 +127,14 @@ public slots:
|
|||
|
||||
void actPlay(QList<CardItem *> selectedCards);
|
||||
void actPlayFacedown(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). */
|
||||
void actToggleTaxCounter(int counterId);
|
||||
/** @brief Plays the selected card and increments the 1st cast count. */
|
||||
void actPlayAndIncrease1stCastCount(QList<CardItem *> selectedCards);
|
||||
/** @brief Plays the selected card and increments the 2nd cast count. */
|
||||
void actPlayAndIncrease2ndCastCount(QList<CardItem *> selectedCards);
|
||||
/** @brief Modifies a cast count by delta. */
|
||||
void actModifyCastCount(int index, int delta);
|
||||
/** @brief Toggles a cast count's existence (create if missing, delete if value is 0). */
|
||||
void actToggleCastCount(int index);
|
||||
void actHide(QList<CardItem *> selectedCards);
|
||||
|
||||
void actMoveTopCardToPlay();
|
||||
|
|
@ -280,11 +280,11 @@ 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.
|
||||
* the server accepts, increments the given cast count by one.
|
||||
* @param selectedCards Cards to play
|
||||
* @param counterId The tax counter to increment (CounterIds::TaxCounter1 through TaxCounter5)
|
||||
* @param index The cast count index (1-5)
|
||||
*/
|
||||
void playAndIncreaseTax(QList<CardItem *> selectedCards, int counterId);
|
||||
void playAndIncreaseCastCount(QList<CardItem *> selectedCards, int index);
|
||||
|
||||
void cmdSetTopCard(Command_MoveCard &cmd);
|
||||
void cmdSetBottomCard(Command_MoveCard &cmd);
|
||||
|
|
|
|||
|
|
@ -15,10 +15,12 @@
|
|||
#include <libcockatrice/protocol/pb/event_attach_card.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_change_zone_properties.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_create_arrow.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_create_cast_count.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_create_counter.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_create_token.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_del_counter.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_delete_arrow.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_delete_cast_count.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_destroy_card.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_draw_cards.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_dump_zone.pb.h>
|
||||
|
|
@ -30,8 +32,8 @@
|
|||
#include <libcockatrice/protocol/pb/event_roll_die.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_set_card_attr.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_set_card_counter.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_set_cast_count.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_set_counter.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_set_counter_active.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_shuffle.pb.h>
|
||||
#include <libcockatrice/utility/color.h>
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
|
|
@ -277,20 +279,26 @@ void PlayerEventHandler::eventSetCounter(const Event_SetCounter &event)
|
|||
}
|
||||
}
|
||||
|
||||
void PlayerEventHandler::eventSetCounterActive(const Event_SetCounterActive &event)
|
||||
{
|
||||
CounterState *state = player->getCounters().value(event.counter_id(), nullptr);
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
state->setActive(event.active());
|
||||
}
|
||||
|
||||
void PlayerEventHandler::eventDelCounter(const Event_DelCounter &event)
|
||||
{
|
||||
player->delCounter(event.counter_id());
|
||||
}
|
||||
|
||||
void PlayerEventHandler::eventCreateCastCount(const Event_CreateCastCount &event)
|
||||
{
|
||||
player->addCastCount(event.index());
|
||||
}
|
||||
|
||||
void PlayerEventHandler::eventDeleteCastCount(const Event_DeleteCastCount &event)
|
||||
{
|
||||
player->delCastCount(event.index());
|
||||
}
|
||||
|
||||
void PlayerEventHandler::eventSetCastCount(const Event_SetCastCount &event)
|
||||
{
|
||||
player->setCastCountValue(event.index(), event.value());
|
||||
}
|
||||
|
||||
void PlayerEventHandler::eventDumpZone(const Event_DumpZone &event)
|
||||
{
|
||||
PlayerLogic *zoneOwner = player->getGame()->getPlayerManager()->getPlayers().value(event.zone_owner_id(), 0);
|
||||
|
|
@ -640,12 +648,18 @@ void PlayerEventHandler::processGameEvent(GameEvent::GameEventType type,
|
|||
case GameEvent::SET_COUNTER:
|
||||
eventSetCounter(event.GetExtension(Event_SetCounter::ext));
|
||||
break;
|
||||
case GameEvent::SET_COUNTER_ACTIVE:
|
||||
eventSetCounterActive(event.GetExtension(Event_SetCounterActive::ext));
|
||||
break;
|
||||
case GameEvent::DEL_COUNTER:
|
||||
eventDelCounter(event.GetExtension(Event_DelCounter::ext));
|
||||
break;
|
||||
case GameEvent::CREATE_CAST_COUNT:
|
||||
eventCreateCastCount(event.GetExtension(Event_CreateCastCount::ext));
|
||||
break;
|
||||
case GameEvent::DELETE_CAST_COUNT:
|
||||
eventDeleteCastCount(event.GetExtension(Event_DeleteCastCount::ext));
|
||||
break;
|
||||
case GameEvent::SET_CAST_COUNT:
|
||||
eventSetCastCount(event.GetExtension(Event_SetCastCount::ext));
|
||||
break;
|
||||
case GameEvent::DUMP_ZONE:
|
||||
eventDumpZone(event.GetExtension(Event_DumpZone::ext));
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -48,7 +48,9 @@ class Event_RollDie;
|
|||
class Event_SetCardAttr;
|
||||
class Event_SetCardCounter;
|
||||
class Event_SetCounter;
|
||||
class Event_SetCounterActive;
|
||||
class Event_CreateCastCount;
|
||||
class Event_DeleteCastCount;
|
||||
class Event_SetCastCount;
|
||||
class Event_Shuffle;
|
||||
class Event_GameLogNotice;
|
||||
|
||||
|
|
@ -156,12 +158,18 @@ public:
|
|||
/// Set a player-level counter value.
|
||||
void eventSetCounter(const Event_SetCounter &event);
|
||||
|
||||
/** @brief Show or hide a player-level counter without deleting it. */
|
||||
void eventSetCounterActive(const Event_SetCounterActive &event);
|
||||
|
||||
/// Delete a player-level counter.
|
||||
void eventDelCounter(const Event_DelCounter &event);
|
||||
|
||||
/// Create a cast count.
|
||||
void eventCreateCastCount(const Event_CreateCastCount &event);
|
||||
|
||||
/// Delete a cast count.
|
||||
void eventDeleteCastCount(const Event_DeleteCastCount &event);
|
||||
|
||||
/// Set a cast count value.
|
||||
void eventSetCastCount(const Event_SetCastCount &event);
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @name Zone-level operations
|
||||
|
|
|
|||
|
|
@ -292,6 +292,49 @@ void PlayerLogic::clearCounters()
|
|||
}
|
||||
qDeleteAll(counters);
|
||||
counters.clear();
|
||||
|
||||
for (int index : castCounts.keys()) {
|
||||
emit castCountRemoved(index);
|
||||
}
|
||||
qDeleteAll(castCounts);
|
||||
castCounts.clear();
|
||||
}
|
||||
|
||||
CounterState *PlayerLogic::addCastCount(int index)
|
||||
{
|
||||
if (castCounts.contains(index)) {
|
||||
return nullptr;
|
||||
}
|
||||
QString name = CastCountIds::nameForIndex(index);
|
||||
auto *state = new CounterState(index, name, QColor(128, 128, 128), 20, 0, true, this);
|
||||
castCounts.insert(index, state);
|
||||
emit castCountAdded(index, state);
|
||||
return state;
|
||||
}
|
||||
|
||||
void PlayerLogic::delCastCount(int index)
|
||||
{
|
||||
auto *state = castCounts.take(index);
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
emit castCountRemoved(index);
|
||||
state->deleteLater();
|
||||
}
|
||||
|
||||
void PlayerLogic::setCastCountValue(int index, int value)
|
||||
{
|
||||
auto *state = castCounts.value(index, nullptr);
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
state->setValue(value);
|
||||
emit castCountValueChanged(index, value);
|
||||
}
|
||||
|
||||
CounterState *PlayerLogic::getCastCount(int index) const
|
||||
{
|
||||
return castCounts.value(index, nullptr);
|
||||
}
|
||||
|
||||
CounterState *PlayerLogic::getLifeCounter() const
|
||||
|
|
|
|||
|
|
@ -79,6 +79,9 @@ signals:
|
|||
void counterAdded(CounterState *state);
|
||||
void counterRemoved(int counterId);
|
||||
void rearrangeCounters();
|
||||
void castCountAdded(int index, CounterState *state);
|
||||
void castCountRemoved(int index);
|
||||
void castCountValueChanged(int index, int value);
|
||||
void activeChanged(bool active);
|
||||
void zoneIdChanged(int zoneId);
|
||||
void concededChanged(int playerId, bool conceded);
|
||||
|
|
@ -225,6 +228,16 @@ public:
|
|||
*/
|
||||
CounterState *getLifeCounter() const;
|
||||
|
||||
// Cast count management
|
||||
CounterState *addCastCount(int index);
|
||||
void delCastCount(int index);
|
||||
void setCastCountValue(int index, int value);
|
||||
CounterState *getCastCount(int index) const;
|
||||
const QMap<int, CounterState *> &getCastCounts() const
|
||||
{
|
||||
return castCounts;
|
||||
}
|
||||
|
||||
void setConceded(bool _conceded);
|
||||
bool getConceded() const
|
||||
{
|
||||
|
|
@ -259,6 +272,7 @@ private:
|
|||
int zoneId;
|
||||
QMap<QString, CardZoneLogic *> zones;
|
||||
QMap<int, CounterState *> counters;
|
||||
QMap<int, CounterState *> castCounts; // index (1-5) -> state
|
||||
|
||||
bool dialogSemaphore;
|
||||
QList<CardItem *> cardsToDelete;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ AbstractCounter::AbstractCounter(CounterState *state,
|
|||
setAcceptHoverEvents(true);
|
||||
|
||||
// Route through the (possibly overridden) virtual setValue so subclasses such as
|
||||
// CommanderTaxCounter can clamp and refresh their tooltip on every value change.
|
||||
// CastCountWidget can clamp and refresh their tooltip on every value change.
|
||||
connect(state, &CounterState::valueChanged, this, [this](int, int newValue) { setValue(newValue); });
|
||||
|
||||
connect(state, &CounterState::activeChanged, this, [this](bool newActive) {
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ public:
|
|||
/**
|
||||
* @brief Sets the counter value and triggers a visual update.
|
||||
*
|
||||
* Virtual to allow subclass display customization (e.g., CommanderTaxCounter tooltip updates).
|
||||
* Virtual to allow subclass display customization (e.g., CastCountWidget tooltip updates).
|
||||
* Overflow protection is handled server-side, not in client counter classes.
|
||||
*
|
||||
* @param _value The new counter value
|
||||
|
|
@ -122,9 +122,9 @@ public:
|
|||
/**
|
||||
* @brief Shows or hides the counter and enables or disables its menu.
|
||||
*
|
||||
* Sole owner of both, so container layout code only positions counters and may read
|
||||
* isActive(). Qt AND-s visibility with the parent item's, so an active counter nested in a
|
||||
* hidden zone (e.g. a tax counter in the command zone) still does not render.
|
||||
* Sole owner of both visibility and menu state, so container layout code only positions
|
||||
* counters and may read isActive(). Note that Qt AND-s visibility with the parent item's,
|
||||
* so an active counter nested in a hidden parent still does not render.
|
||||
*
|
||||
* @param _active True to show and enable the counter, false to hide and disable it
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,32 +1,30 @@
|
|||
#include "commander_tax_counter.h"
|
||||
#include "cast_count_widget.h"
|
||||
|
||||
#include "../../game/board/counter_state.h"
|
||||
#include "translate_counter_name.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QFontDatabase>
|
||||
#include <QPainter>
|
||||
|
||||
static constexpr qreal CORNER_RADIUS = 4.0;
|
||||
static constexpr qreal FONT_SIZE_RATIO = 0.6;
|
||||
|
||||
CommanderTaxCounter::CommanderTaxCounter(CounterState *state, PlayerLogic *player, QGraphicsItem *parent)
|
||||
CastCountWidget::CastCountWidget(CounterState *state, PlayerLogic *player, QGraphicsItem *parent)
|
||||
: AbstractCounter(state, player, false, false, parent), size(state->getRadius())
|
||||
{
|
||||
setCacheMode(DeviceCoordinateCache);
|
||||
setAcceptHoverEvents(true);
|
||||
|
||||
setToolTip(tr("%1: %2").arg(TranslateCounterName::getDisplayName(getName())).arg(getValue()));
|
||||
}
|
||||
|
||||
QRectF CommanderTaxCounter::boundingRect() const
|
||||
QRectF CastCountWidget::boundingRect() const
|
||||
{
|
||||
return QRectF(0, 0, size, size);
|
||||
}
|
||||
|
||||
void CommanderTaxCounter::paint(QPainter *painter,
|
||||
[[maybe_unused]] const QStyleOptionGraphicsItem *option,
|
||||
[[maybe_unused]] QWidget *widget)
|
||||
void CastCountWidget::paint(QPainter *painter,
|
||||
[[maybe_unused]] const QStyleOptionGraphicsItem *option,
|
||||
[[maybe_unused]] QWidget *widget)
|
||||
{
|
||||
painter->save();
|
||||
|
||||
|
|
@ -46,7 +44,7 @@ void CommanderTaxCounter::paint(QPainter *painter,
|
|||
painter->restore();
|
||||
}
|
||||
|
||||
void CommanderTaxCounter::setValue(int _value)
|
||||
void CastCountWidget::setValue(int _value)
|
||||
{
|
||||
int clampedValue = qMax(0, _value);
|
||||
AbstractCounter::setValue(clampedValue);
|
||||
35
cockatrice/src/game_graphics/board/cast_count_widget.h
Normal file
35
cockatrice/src/game_graphics/board/cast_count_widget.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* @file cast_count_widget.h
|
||||
* @ingroup GameGraphicsBoard
|
||||
* @brief Displays a single cast count overlay counter in the command zone.
|
||||
*/
|
||||
|
||||
#ifndef COCKATRICE_CAST_COUNT_WIDGET_H
|
||||
#define COCKATRICE_CAST_COUNT_WIDGET_H
|
||||
|
||||
#include "abstract_counter.h"
|
||||
|
||||
namespace CastCountSizes
|
||||
{
|
||||
constexpr int MARGIN = 2;
|
||||
} // namespace CastCountSizes
|
||||
|
||||
/**
|
||||
* @class CastCountWidget
|
||||
* @brief A compact counter widget for tracking cast counts in the command zone.
|
||||
*/
|
||||
class CastCountWidget : public AbstractCounter
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
int size;
|
||||
|
||||
public:
|
||||
CastCountWidget(CounterState *state, PlayerLogic *player, QGraphicsItem *parent = nullptr);
|
||||
|
||||
[[nodiscard]] QRectF boundingRect() const override;
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
void setValue(int _value) override;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_CAST_COUNT_WIDGET_H
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
/**
|
||||
* @file commander_tax_counter.h
|
||||
* @ingroup GameGraphicsPlayers
|
||||
* @brief Square counter for commander tax, clamped to non-negative values.
|
||||
*/
|
||||
|
||||
#ifndef COCKATRICE_COMMANDER_TAX_COUNTER_H
|
||||
#define COCKATRICE_COMMANDER_TAX_COUNTER_H
|
||||
|
||||
#include "abstract_counter.h"
|
||||
|
||||
/**
|
||||
* @namespace TaxCounterSizes
|
||||
* @brief Layout constants for commander tax counters.
|
||||
*/
|
||||
namespace TaxCounterSizes
|
||||
{
|
||||
|
||||
/** @brief Margin around and between tax counter icons */
|
||||
constexpr int TAX_COUNTER_MARGIN = 2;
|
||||
|
||||
} // namespace TaxCounterSizes
|
||||
|
||||
/**
|
||||
* @class CommanderTaxCounter
|
||||
* @brief Counter for tracking commander tax in Commander format.
|
||||
*
|
||||
* Displays the number of times the commander has been cast from the command
|
||||
* zone. Can be adjusted manually via +1/-1 menu actions, or automatically
|
||||
* incremented when using "Play and Increase Tax" on an accepted cast from
|
||||
* the command zone. Values are clamped to >= 0.
|
||||
*
|
||||
* Appearance: square with rounded corners, semi-transparent background,
|
||||
* positioned at top-left of command zone.
|
||||
*
|
||||
* Two instances per player: CounterIds::CommanderTax and CounterIds::PartnerTax.
|
||||
* Each counter supports an active/inactive state (inherited from AbstractCounter):
|
||||
* commander tax starts active; partner tax starts inactive until explicitly
|
||||
* enabled by the player via the context menu.
|
||||
*
|
||||
* @see AbstractCounter
|
||||
* @see AbstractCounter::setActive()
|
||||
* @see CounterIds
|
||||
*/
|
||||
class CommanderTaxCounter : public AbstractCounter
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
int size; ///< Width and height of the counter in pixels
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a CommanderTaxCounter.
|
||||
* @param state Counter state containing id, name, value, etc.
|
||||
* @param player The player who owns this counter
|
||||
* @param parent Parent graphics item (typically the command zone)
|
||||
*/
|
||||
CommanderTaxCounter(CounterState *state, PlayerLogic *player, QGraphicsItem *parent = nullptr);
|
||||
|
||||
[[nodiscard]] QRectF boundingRect() const override;
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
|
||||
/**
|
||||
* @brief Overrides AbstractCounter::setValue to clamp values to >= 0 and update the tooltip.
|
||||
* @param _value New value (clamped if negative)
|
||||
*/
|
||||
void setValue(int _value) override;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_COMMANDER_TAX_COUNTER_H
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
#include "translate_counter_name.h"
|
||||
|
||||
#include <libcockatrice/utility/counter_ids.h>
|
||||
|
||||
const QMap<QString, QString> TranslateCounterName::translated = {
|
||||
{"life", QT_TRANSLATE_NOOP("TranslateCounterName", "Life")},
|
||||
{"w", QT_TRANSLATE_NOOP("TranslateCounterName", "White")},
|
||||
|
|
@ -11,8 +9,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::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")}};
|
||||
{"cast_count_1", QT_TRANSLATE_NOOP("TranslateCounterName", "1st Cast Count")},
|
||||
{"cast_count_2", QT_TRANSLATE_NOOP("TranslateCounterName", "2nd Cast Count")},
|
||||
{"cast_count_3", QT_TRANSLATE_NOOP("TranslateCounterName", "3rd Cast Count")},
|
||||
{"cast_count_4", QT_TRANSLATE_NOOP("TranslateCounterName", "4th Cast Count")},
|
||||
{"cast_count_5", QT_TRANSLATE_NOOP("TranslateCounterName", "5th Cast Count")}};
|
||||
|
|
|
|||
|
|
@ -672,27 +672,11 @@ void MessageLogWidget::logSetCardCounter(PlayerLogic *player, QString cardName,
|
|||
|
||||
void MessageLogWidget::logSetCounter(PlayerLogic *player, int counterId, QString counterName, int value, int oldValue)
|
||||
{
|
||||
Q_UNUSED(counterId);
|
||||
if (counterName == "life") {
|
||||
soundEngine->playSound("life_change");
|
||||
}
|
||||
|
||||
if (CounterIds::isTaxCounter(counterId)) {
|
||||
QString playerName = sanitizeHtml(player->getPlayerInfo()->getName());
|
||||
QString valueStr = QString("<font class=\"blue\">%1</font>").arg(value);
|
||||
int delta = value - oldValue;
|
||||
QString deltaStr = QString::number(delta);
|
||||
QString counterDisplayName = TranslateCounterName::getDisplayName(counterName);
|
||||
QString taxLabel = QString("<font class=\"blue\">%1</font>").arg(sanitizeHtml(counterDisplayName));
|
||||
if (value > oldValue) {
|
||||
// delta > 0 here; the format string supplies the leading '+'
|
||||
appendHtmlServerMessage(tr("%1 increases %2 to %3 (+%4).").arg(playerName, taxLabel, valueStr, deltaStr));
|
||||
} else {
|
||||
// delta < 0 here; deltaStr already carries the '-' sign
|
||||
appendHtmlServerMessage(tr("%1 decreases %2 to %3 (%4).").arg(playerName, taxLabel, valueStr, deltaStr));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
QString counterDisplayName = TranslateCounterName::getDisplayName(counterName);
|
||||
appendHtmlServerMessage(tr("%1 sets counter %2 to %3 (%4%5).")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
|
|
|
|||
|
|
@ -84,8 +84,10 @@ 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()); });
|
||||
aPlayAndIncrease1stTax = makeAction(this, [actions, sel]() { actions->actPlayAndIncrease1stTax(sel()); });
|
||||
aPlayAndIncrease2ndTax = makeAction(this, [actions, sel]() { actions->actPlayAndIncrease2ndTax(sel()); });
|
||||
aPlayAndIncrease1stCastCount =
|
||||
makeAction(this, [actions, sel]() { actions->actPlayAndIncrease1stCastCount(sel()); });
|
||||
aPlayAndIncrease2ndCastCount =
|
||||
makeAction(this, [actions, sel]() { actions->actPlayAndIncrease2ndCastCount(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()); });
|
||||
|
|
@ -166,16 +168,15 @@ CardMenu::CardMenu(PlayerGraphicsItem *_player, const CardItem *_card, bool _sho
|
|||
if (writeableCard) {
|
||||
addAction(aPlay);
|
||||
|
||||
// Only offer for single selection: a multi-select would over-count casts by
|
||||
// bumping one commander's tax counter once per command-zone card.
|
||||
// Only offer for single selection: a multi-select would over-count casts
|
||||
const bool singleSelection = gameScene->selectedCards().size() <= 1;
|
||||
|
||||
if (singleSelection && player->getTaxCounterIfActive(CounterIds::TaxCounter1)) {
|
||||
addAction(aPlayAndIncrease1stTax);
|
||||
if (singleSelection && player->getCastCountWidget(1)) {
|
||||
addAction(aPlayAndIncrease1stCastCount);
|
||||
}
|
||||
|
||||
if (singleSelection && player->getTaxCounterIfActive(CounterIds::TaxCounter2)) {
|
||||
addAction(aPlayAndIncrease2ndTax);
|
||||
if (singleSelection && player->getCastCountWidget(2)) {
|
||||
addAction(aPlayAndIncrease2ndCastCount);
|
||||
}
|
||||
|
||||
// No reveal submenu - command zone is public
|
||||
|
|
@ -524,8 +525,8 @@ void CardMenu::retranslateUi()
|
|||
aPlay->setText(tr("&Play"));
|
||||
aHide->setText(tr("&Hide"));
|
||||
aPlayFacedown->setText(tr("Play &Face Down"));
|
||||
aPlayAndIncrease1stTax->setText(tr("Play and &Increase 1st Tax"));
|
||||
aPlayAndIncrease2ndTax->setText(tr("Play and Increase &2nd Tax"));
|
||||
aPlayAndIncrease1stCastCount->setText(tr("Play and &Increase 1st Cast Count"));
|
||||
aPlayAndIncrease2ndCastCount->setText(tr("Play and Increase &2nd Cast Count"));
|
||||
aRevealToAll->setText(tr("&All players"));
|
||||
//: Turn sideways or back again
|
||||
aTap->setText(tr("&Tap / Untap"));
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ public:
|
|||
QMenu *mCardCounters;
|
||||
|
||||
QAction *aPlay, *aPlayFacedown;
|
||||
/** @brief Play actions that also increment the corresponding tax counter. */
|
||||
QAction *aPlayAndIncrease1stTax, *aPlayAndIncrease2ndTax;
|
||||
/** @brief Play actions that also increment the corresponding cast count. */
|
||||
QAction *aPlayAndIncrease1stCastCount, *aPlayAndIncrease2ndCastCount;
|
||||
QAction *aRevealToAll;
|
||||
QAction *aHide;
|
||||
QAction *aClone;
|
||||
|
|
|
|||
|
|
@ -14,42 +14,41 @@
|
|||
|
||||
CommandZoneMenu::CommandZoneMenu(PlayerGraphicsItem *_player, QMenu *playerMenu) : QMenu(playerMenu), player(_player)
|
||||
{
|
||||
// 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");
|
||||
inc1ShortcutKey = QStringLiteral("Player/aIncrease1stCastCount");
|
||||
dec1ShortcutKey = QStringLiteral("Player/aDecrease1stCastCount");
|
||||
inc2ShortcutKey = QStringLiteral("Player/aIncrease2ndCastCount");
|
||||
dec2ShortcutKey = QStringLiteral("Player/aDecrease2ndCastCount");
|
||||
|
||||
PlayerLogic *logic = player->getLogic();
|
||||
if (logic && logic->getPlayerInfo()->getLocalOrJudge()) {
|
||||
for (int i = 0; i < TaxCounterCount; ++i) {
|
||||
int counterId = CounterIds::taxCounterIdFromIndex(i);
|
||||
for (int i = 0; i < CastCountCount; ++i) {
|
||||
int index = i + 1; // 1-based index
|
||||
|
||||
aIncreaseTax[i] = new QAction(this);
|
||||
connect(aIncreaseTax[i], &QAction::triggered, this, [this, counterId]() {
|
||||
aIncrease[i] = new QAction(this);
|
||||
connect(aIncrease[i], &QAction::triggered, this, [this, index]() {
|
||||
if (auto *l = player->getLogic()) {
|
||||
l->getPlayerActions()->actModifyTaxCounter(counterId, 1);
|
||||
l->getPlayerActions()->actModifyCastCount(index, 1);
|
||||
}
|
||||
});
|
||||
addAction(aIncreaseTax[i]);
|
||||
addAction(aIncrease[i]);
|
||||
|
||||
aDecreaseTax[i] = new QAction(this);
|
||||
connect(aDecreaseTax[i], &QAction::triggered, this, [this, counterId]() {
|
||||
aDecrease[i] = new QAction(this);
|
||||
connect(aDecrease[i], &QAction::triggered, this, [this, index]() {
|
||||
if (auto *l = player->getLogic()) {
|
||||
l->getPlayerActions()->actModifyTaxCounter(counterId, -1);
|
||||
l->getPlayerActions()->actModifyCastCount(index, -1);
|
||||
}
|
||||
});
|
||||
addAction(aDecreaseTax[i]);
|
||||
addAction(aDecrease[i]);
|
||||
|
||||
addSeparator();
|
||||
|
||||
aToggleTax[i] = new QAction(this);
|
||||
connect(aToggleTax[i], &QAction::triggered, this, [this, counterId]() {
|
||||
aToggle[i] = new QAction(this);
|
||||
connect(aToggle[i], &QAction::triggered, this, [this, index]() {
|
||||
if (auto *l = player->getLogic()) {
|
||||
l->getPlayerActions()->actToggleTaxCounter(counterId);
|
||||
l->getPlayerActions()->actToggleCastCount(index);
|
||||
}
|
||||
});
|
||||
addAction(aToggleTax[i]);
|
||||
addAction(aToggle[i]);
|
||||
|
||||
addSeparator();
|
||||
}
|
||||
|
|
@ -58,7 +57,7 @@ CommandZoneMenu::CommandZoneMenu(PlayerGraphicsItem *_player, QMenu *playerMenu)
|
|||
connect(aToggleMinimized, &QAction::triggered, this, &CommandZoneMenu::actToggleMinimized);
|
||||
addAction(aToggleMinimized);
|
||||
|
||||
connect(this, &QMenu::aboutToShow, this, &CommandZoneMenu::updateTaxCounterActionStates);
|
||||
connect(this, &QMenu::aboutToShow, this, &CommandZoneMenu::updateCastCountActionStates);
|
||||
}
|
||||
|
||||
retranslateUi();
|
||||
|
|
@ -70,14 +69,13 @@ void CommandZoneMenu::retranslateUi()
|
|||
|
||||
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]));
|
||||
for (int i = 0; i < CastCountCount; ++i) {
|
||||
if (aIncrease[i]) {
|
||||
aIncrease[i]->setText(tr("&Increase %1 Cast Count (+1)").arg(ordinals[i]));
|
||||
}
|
||||
if (aDecreaseTax[i]) {
|
||||
aDecreaseTax[i]->setText(tr("&Decrease %1 Tax (-1)").arg(ordinals[i]));
|
||||
if (aDecrease[i]) {
|
||||
aDecrease[i]->setText(tr("&Decrease %1 Cast Count (-1)").arg(ordinals[i]));
|
||||
}
|
||||
// Toggle action labels are derived dynamically in updateTaxCounterActionStates()
|
||||
}
|
||||
|
||||
if (aToggleMinimized) {
|
||||
|
|
@ -93,44 +91,39 @@ void CommandZoneMenu::actToggleMinimized()
|
|||
}
|
||||
}
|
||||
|
||||
void CommandZoneMenu::updateTaxCounterActionStates()
|
||||
void CommandZoneMenu::updateCastCountActionStates()
|
||||
{
|
||||
static const char *ordinals[] = {"1st", "2nd", "3rd", "4th", "5th"};
|
||||
|
||||
// Collect all tax counter states
|
||||
std::array<AbstractCounter *, TaxCounterCount> taxCounters{};
|
||||
for (int i = 0; i < TaxCounterCount; ++i) {
|
||||
taxCounters[i] = player->getTaxCounterIfActive(CounterIds::taxCounterIdFromIndex(i));
|
||||
std::array<AbstractCounter *, CastCountCount> castCounts{};
|
||||
for (int i = 0; i < CastCountCount; ++i) {
|
||||
castCounts[i] = player->getCastCountWidget(i + 1);
|
||||
}
|
||||
|
||||
// Find highest active tax counter index
|
||||
int highestActive = -1;
|
||||
for (int i = TaxCounterCount - 1; i >= 0; --i) {
|
||||
if (taxCounters[i]) {
|
||||
for (int i = CastCountCount - 1; i >= 0; --i) {
|
||||
if (castCounts[i]) {
|
||||
highestActive = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < TaxCounterCount; ++i) {
|
||||
AbstractCounter *counter = taxCounters[i];
|
||||
for (int i = 0; i < CastCountCount; ++i) {
|
||||
AbstractCounter *counter = castCounts[i];
|
||||
|
||||
if (aIncreaseTax[i]) {
|
||||
aIncreaseTax[i]->setVisible(counter && counter->getValue() < MAX_COUNTER_VALUE);
|
||||
if (aIncrease[i]) {
|
||||
aIncrease[i]->setVisible(counter && counter->getValue() < MAX_COUNTER_VALUE);
|
||||
}
|
||||
if (aDecreaseTax[i]) {
|
||||
aDecreaseTax[i]->setVisible(counter && counter->getValue() > 0);
|
||||
if (aDecrease[i]) {
|
||||
aDecrease[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]));
|
||||
if (aToggle[i]) {
|
||||
aToggle[i]->setText(counter ? tr("&Remove %1 Cast Count").arg(ordinals[i])
|
||||
: tr("&Add %1 Cast Count").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 canAdd = !counter && (i == 0 || castCounts[i - 1]);
|
||||
bool canRemove = counter && counter->getValue() == 0 && i == highestActive;
|
||||
aToggleTax[i]->setVisible(canAdd || canRemove);
|
||||
aToggle[i]->setVisible(canAdd || canRemove);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -144,34 +137,32 @@ void CommandZoneMenu::setShortcutsActive()
|
|||
{
|
||||
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
|
||||
|
||||
// Only first two tax counters have shortcuts
|
||||
if (aIncreaseTax[0]) {
|
||||
aIncreaseTax[0]->setShortcuts(shortcuts.getShortcut(incTax1ShortcutKey));
|
||||
if (aIncrease[0]) {
|
||||
aIncrease[0]->setShortcuts(shortcuts.getShortcut(inc1ShortcutKey));
|
||||
}
|
||||
if (aDecreaseTax[0]) {
|
||||
aDecreaseTax[0]->setShortcuts(shortcuts.getShortcut(decTax1ShortcutKey));
|
||||
if (aDecrease[0]) {
|
||||
aDecrease[0]->setShortcuts(shortcuts.getShortcut(dec1ShortcutKey));
|
||||
}
|
||||
if (aIncreaseTax[1]) {
|
||||
aIncreaseTax[1]->setShortcuts(shortcuts.getShortcut(incTax2ShortcutKey));
|
||||
if (aIncrease[1]) {
|
||||
aIncrease[1]->setShortcuts(shortcuts.getShortcut(inc2ShortcutKey));
|
||||
}
|
||||
if (aDecreaseTax[1]) {
|
||||
aDecreaseTax[1]->setShortcuts(shortcuts.getShortcut(decTax2ShortcutKey));
|
||||
if (aDecrease[1]) {
|
||||
aDecrease[1]->setShortcuts(shortcuts.getShortcut(dec2ShortcutKey));
|
||||
}
|
||||
}
|
||||
|
||||
void CommandZoneMenu::setShortcutsInactive()
|
||||
{
|
||||
// Only first two tax counters have shortcuts
|
||||
if (aIncreaseTax[0]) {
|
||||
aIncreaseTax[0]->setShortcut(QKeySequence());
|
||||
if (aIncrease[0]) {
|
||||
aIncrease[0]->setShortcut(QKeySequence());
|
||||
}
|
||||
if (aDecreaseTax[0]) {
|
||||
aDecreaseTax[0]->setShortcut(QKeySequence());
|
||||
if (aDecrease[0]) {
|
||||
aDecrease[0]->setShortcut(QKeySequence());
|
||||
}
|
||||
if (aIncreaseTax[1]) {
|
||||
aIncreaseTax[1]->setShortcut(QKeySequence());
|
||||
if (aIncrease[1]) {
|
||||
aIncrease[1]->setShortcut(QKeySequence());
|
||||
}
|
||||
if (aDecreaseTax[1]) {
|
||||
aDecreaseTax[1]->setShortcut(QKeySequence());
|
||||
if (aDecrease[1]) {
|
||||
aDecrease[1]->setShortcut(QKeySequence());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* @file command_zone_menu.h
|
||||
* @ingroup GameMenusZones
|
||||
* @brief Context menu for command zone right-click actions.
|
||||
* @ingroup GameGraphicsPlayers
|
||||
* @brief Submenu for command zone actions (cast counts, minimize/restore).
|
||||
*/
|
||||
|
||||
#ifndef COCKATRICE_COMMAND_ZONE_MENU_H
|
||||
|
|
@ -17,10 +17,10 @@ class PlayerGraphicsItem;
|
|||
|
||||
/**
|
||||
* @class CommandZoneMenu
|
||||
* @brief Context menu for the command zone.
|
||||
* @brief Player submenu for managing cast counts and command zone display.
|
||||
*
|
||||
* Appears when right-clicking on the command zone. Provides actions for
|
||||
* adjusting tax counters (up to 5) and toggling minimized state.
|
||||
* Provides actions to increment/decrement each cast count, toggle cast counts
|
||||
* on/off, and minimize/restore the command zone display.
|
||||
*
|
||||
* @see PlayerMenu
|
||||
* @see CommandZone
|
||||
|
|
@ -36,15 +36,15 @@ public:
|
|||
void setShortcutsInactive() override;
|
||||
|
||||
private:
|
||||
static constexpr int TaxCounterCount = CounterIds::TaxCounterCount;
|
||||
static constexpr int CastCountCount = CastCountIds::Count;
|
||||
|
||||
std::array<QAction *, TaxCounterCount> aIncreaseTax{};
|
||||
std::array<QAction *, TaxCounterCount> aDecreaseTax{};
|
||||
std::array<QAction *, TaxCounterCount> aToggleTax{};
|
||||
std::array<QAction *, CastCountCount> aIncrease{};
|
||||
std::array<QAction *, CastCountCount> aDecrease{};
|
||||
std::array<QAction *, CastCountCount> aToggle{};
|
||||
QAction *aToggleMinimized = nullptr;
|
||||
|
||||
public slots:
|
||||
void updateTaxCounterActionStates();
|
||||
void updateCastCountActionStates();
|
||||
|
||||
private slots:
|
||||
void actToggleMinimized();
|
||||
|
|
@ -52,11 +52,10 @@ private slots:
|
|||
private:
|
||||
PlayerGraphicsItem *player;
|
||||
|
||||
// Shortcuts only for first two tax counters
|
||||
QString incTax1ShortcutKey;
|
||||
QString decTax1ShortcutKey;
|
||||
QString incTax2ShortcutKey;
|
||||
QString decTax2ShortcutKey;
|
||||
QString inc1ShortcutKey;
|
||||
QString dec1ShortcutKey;
|
||||
QString inc2ShortcutKey;
|
||||
QString dec2ShortcutKey;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_COMMAND_ZONE_MENU_H
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include "../../game/player/player_actions.h"
|
||||
#include "../../interface/widgets/tabs/tab_game.h"
|
||||
#include "../board/abstract_card_item.h"
|
||||
#include "../board/commander_tax_counter.h"
|
||||
#include "../board/cast_count_widget.h"
|
||||
#include "../board/counter_general.h"
|
||||
#include "../hand_counter.h"
|
||||
#include "../z_values.h"
|
||||
|
|
@ -32,6 +32,8 @@ PlayerGraphicsItem::PlayerGraphicsItem(PlayerLogic *_player) : player(_player)
|
|||
|
||||
connect(player, &PlayerLogic::counterAdded, this, &PlayerGraphicsItem::onCounterAdded);
|
||||
connect(player, &PlayerLogic::counterRemoved, this, &PlayerGraphicsItem::onCounterRemoved);
|
||||
connect(player, &PlayerLogic::castCountAdded, this, &PlayerGraphicsItem::onCastCountAdded);
|
||||
connect(player, &PlayerLogic::castCountRemoved, this, &PlayerGraphicsItem::onCastCountRemoved);
|
||||
|
||||
playerMenu = new PlayerMenu(this);
|
||||
|
||||
|
|
@ -231,34 +233,12 @@ void PlayerGraphicsItem::onCounterAdded(CounterState *state)
|
|||
AbstractCounter *widget;
|
||||
if (state->getName() == "life") {
|
||||
widget = playerTarget->addCounter(state);
|
||||
} else if (CounterIds::isTaxCounter(state->getId())) {
|
||||
if (!commandZoneGraphicsItem) {
|
||||
qWarning() << "Cannot create tax counter" << state->getName() << "- command zone not available";
|
||||
return;
|
||||
}
|
||||
// Qt parent (commandZoneGraphicsItem) owns widget; counterWidgets map holds reference
|
||||
// for lookup; CommandZone::registerTaxCounter connects QObject::destroyed for cleanup
|
||||
widget = new CommanderTaxCounter(state, player, commandZoneGraphicsItem);
|
||||
widget->setActive(state->isActive());
|
||||
commandZoneGraphicsItem->registerTaxCounter(widget);
|
||||
|
||||
if (auto *menu = playerMenu->getCommandZoneMenu()) {
|
||||
connect(state, &CounterState::activeChanged, menu, &CommandZoneMenu::updateTaxCounterActionStates);
|
||||
connect(state, &CounterState::valueChanged, menu, &CommandZoneMenu::updateTaxCounterActionStates);
|
||||
}
|
||||
} else {
|
||||
widget = new GeneralCounter(state, player, true, this);
|
||||
}
|
||||
counterWidgets.insert(state->getId(), widget);
|
||||
|
||||
// A counter's submenu follows its isActive() state: while inactive the counter is hidden and
|
||||
// the server rejects every modification. Only tax counters go inactive today.
|
||||
setCounterMenuRegistered(widget, state->isActive());
|
||||
connect(state, &CounterState::activeChanged, this, [this, counterId = state->getId()](bool newActive) {
|
||||
if (AbstractCounter *counter = getCounterWidget(counterId)) {
|
||||
setCounterMenuRegistered(counter, newActive);
|
||||
}
|
||||
});
|
||||
|
||||
if (playerMenu->getShortcutsActive()) {
|
||||
widget->setShortcutsActive();
|
||||
|
|
@ -267,6 +247,25 @@ void PlayerGraphicsItem::onCounterAdded(CounterState *state)
|
|||
rearrangeCounters();
|
||||
}
|
||||
|
||||
void PlayerGraphicsItem::onCastCountAdded(int index, CounterState *state)
|
||||
{
|
||||
if (!commandZoneGraphicsItem) {
|
||||
qWarning() << "Cannot create cast count" << index << "- command zone not available";
|
||||
return;
|
||||
}
|
||||
|
||||
auto *widget = new CastCountWidget(state, player, commandZoneGraphicsItem);
|
||||
commandZoneGraphicsItem->registerCastCount(widget);
|
||||
castCountWidgets.insert(index, widget);
|
||||
|
||||
if (auto *menu = playerMenu->getCommandZoneMenu()) {
|
||||
menu->updateCastCountActionStates();
|
||||
connect(state, &CounterState::valueChanged, menu, &CommandZoneMenu::updateCastCountActionStates);
|
||||
}
|
||||
|
||||
rearrangeCounters();
|
||||
}
|
||||
|
||||
void PlayerGraphicsItem::onCounterRemoved(int counterId)
|
||||
{
|
||||
auto *widget = counterWidgets.take(counterId);
|
||||
|
|
@ -274,25 +273,37 @@ void PlayerGraphicsItem::onCounterRemoved(int counterId)
|
|||
return;
|
||||
}
|
||||
setCounterMenuRegistered(widget, false);
|
||||
if (commandZoneGraphicsItem && CounterIds::isTaxCounter(widget->getId())) {
|
||||
commandZoneGraphicsItem->unregisterTaxCounter(widget);
|
||||
widget->delCounter();
|
||||
rearrangeCounters();
|
||||
}
|
||||
|
||||
void PlayerGraphicsItem::onCastCountRemoved(int index)
|
||||
{
|
||||
auto *widget = castCountWidgets.take(index);
|
||||
if (!widget) {
|
||||
return;
|
||||
}
|
||||
if (commandZoneGraphicsItem) {
|
||||
commandZoneGraphicsItem->unregisterCastCount(widget);
|
||||
}
|
||||
widget->delCounter();
|
||||
|
||||
if (auto *menu = playerMenu->getCommandZoneMenu()) {
|
||||
menu->updateCastCountActionStates();
|
||||
}
|
||||
|
||||
rearrangeCounters();
|
||||
}
|
||||
|
||||
void PlayerGraphicsItem::rearrangeCounters()
|
||||
{
|
||||
if (commandZoneGraphicsItem) {
|
||||
commandZoneGraphicsItem->rearrangeTaxCounters();
|
||||
commandZoneGraphicsItem->rearrangeCastCounts();
|
||||
}
|
||||
|
||||
qreal ySize = boundingRect().y() + 80;
|
||||
constexpr qreal padding = 5;
|
||||
for (auto *ctr : counterWidgets.values()) {
|
||||
if (CounterIds::isTaxCounter(ctr->getId())) {
|
||||
continue;
|
||||
}
|
||||
if (!ctr->getShownInCounterArea()) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -302,10 +313,9 @@ void PlayerGraphicsItem::rearrangeCounters()
|
|||
}
|
||||
}
|
||||
|
||||
AbstractCounter *PlayerGraphicsItem::getTaxCounterIfActive(int counterId) const
|
||||
AbstractCounter *PlayerGraphicsItem::getCastCountWidget(int index) const
|
||||
{
|
||||
AbstractCounter *counter = getCounterWidget(counterId);
|
||||
return (counter && counter->isActive()) ? counter : nullptr;
|
||||
return castCountWidgets.value(index, nullptr);
|
||||
}
|
||||
|
||||
void PlayerGraphicsItem::rearrangeZones()
|
||||
|
|
|
|||
|
|
@ -123,14 +123,16 @@ public:
|
|||
{
|
||||
return counterWidgets.value(counterId, nullptr);
|
||||
}
|
||||
/** @brief Returns the tax counter if it exists and is active, or nullptr otherwise. */
|
||||
[[nodiscard]] AbstractCounter *getTaxCounterIfActive(int counterId) const;
|
||||
/** @brief Returns the cast count widget for the given index (1-5), or nullptr if not found. */
|
||||
[[nodiscard]] AbstractCounter *getCastCountWidget(int index) const;
|
||||
|
||||
public slots:
|
||||
void onPlayerActiveChanged(bool _active);
|
||||
void onCustomZoneAdded(QString customZoneName);
|
||||
void onCounterAdded(CounterState *state);
|
||||
void onCounterRemoved(int counterId);
|
||||
void onCastCountAdded(int index, CounterState *state);
|
||||
void onCastCountRemoved(int index);
|
||||
void rearrangeCounters();
|
||||
void retranslateUi();
|
||||
|
||||
|
|
@ -147,6 +149,7 @@ private:
|
|||
PlayerArea *playerArea;
|
||||
PlayerTarget *playerTarget;
|
||||
QMap<int, AbstractCounter *> counterWidgets;
|
||||
QMap<int, AbstractCounter *> castCountWidgets;
|
||||
QMap<QString, CardZone *> zoneGraphicsItems;
|
||||
PileZone *deckZoneGraphicsItem;
|
||||
PileZone *sideboardGraphicsItem;
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ constexpr qreal OVERLAY_BASE = ZValueLayerManager::OVERLAY_BASE;
|
|||
|
||||
// Overlay layer Z-values for items that should appear above normal cards
|
||||
constexpr qreal HOVERED_CARD = ZValueLayerManager::overlayZValue(1.0);
|
||||
/** @brief Commander tax counter overlay */
|
||||
constexpr qreal TAX_COUNTERS = ZValueLayerManager::overlayZValue(2.0);
|
||||
/** @brief Cast count overlay */
|
||||
constexpr qreal CAST_COUNTS = ZValueLayerManager::overlayZValue(2.0);
|
||||
constexpr qreal ARROWS = ZValueLayerManager::overlayZValue(3.0);
|
||||
constexpr qreal ZONE_VIEW_WIDGET = ZValueLayerManager::overlayZValue(4.0);
|
||||
constexpr qreal DRAG_ITEM = ZValueLayerManager::overlayZValue(5.0);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#include "../board/abstract_counter.h"
|
||||
#include "../board/card_drag_item.h"
|
||||
#include "../board/card_item.h"
|
||||
#include "../board/commander_tax_counter.h"
|
||||
#include "../board/cast_count_widget.h"
|
||||
#include "../z_values.h"
|
||||
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
|
|
@ -26,7 +26,7 @@ CommandZone::CommandZone(CommandZoneLogic *_logic, int _zoneHeight, QGraphicsIte
|
|||
|
||||
CommandZone::~CommandZone()
|
||||
{
|
||||
for (AbstractCounter *ctr : taxCounters) {
|
||||
for (AbstractCounter *ctr : castCounts) {
|
||||
disconnect(ctr, &QObject::destroyed, this, nullptr);
|
||||
}
|
||||
}
|
||||
|
|
@ -52,7 +52,7 @@ void CommandZone::setMinimumHeight(int height)
|
|||
return;
|
||||
}
|
||||
// The floor only affects height while minimized; skip relayout if the displayed
|
||||
// height is unchanged (e.g. a tax counter toggled while expanded).
|
||||
// height is unchanged (e.g. a cast count toggled while expanded).
|
||||
const qreal oldEffectiveHeight = currentHeight();
|
||||
minimumHeight = height;
|
||||
if (qFuzzyCompare(1.0 + currentHeight(), 1.0 + oldEffectiveHeight)) {
|
||||
|
|
@ -145,38 +145,32 @@ void CommandZone::reorganizeCards()
|
|||
update();
|
||||
}
|
||||
|
||||
void CommandZone::registerTaxCounter(AbstractCounter *counter)
|
||||
void CommandZone::registerCastCount(AbstractCounter *counter)
|
||||
{
|
||||
if (!counter || taxCounters.contains(counter)) {
|
||||
if (!counter || castCounts.contains(counter)) {
|
||||
return;
|
||||
}
|
||||
taxCounters.append(counter);
|
||||
connect(counter, &QObject::destroyed, this, [this, counter]() { taxCounters.removeOne(counter); });
|
||||
castCounts.append(counter);
|
||||
connect(counter, &QObject::destroyed, this, [this, counter]() { castCounts.removeOne(counter); });
|
||||
}
|
||||
|
||||
void CommandZone::unregisterTaxCounter(AbstractCounter *counter)
|
||||
void CommandZone::unregisterCastCount(AbstractCounter *counter)
|
||||
{
|
||||
if (!counter) {
|
||||
return;
|
||||
}
|
||||
disconnect(counter, &QObject::destroyed, this, nullptr);
|
||||
taxCounters.removeOne(counter);
|
||||
castCounts.removeOne(counter);
|
||||
}
|
||||
|
||||
void CommandZone::rearrangeTaxCounters()
|
||||
void CommandZone::rearrangeCastCounts()
|
||||
{
|
||||
qreal y = TaxCounterSizes::TAX_COUNTER_MARGIN;
|
||||
qreal y = CastCountSizes::MARGIN;
|
||||
|
||||
for (AbstractCounter *ctr : taxCounters) {
|
||||
ctr->setPos(TaxCounterSizes::TAX_COUNTER_MARGIN, y);
|
||||
ctr->setZValue(ZValues::TAX_COUNTERS);
|
||||
// Visibility is owned solely by AbstractCounter::setActive() (the counter's own flag),
|
||||
// which Qt AND-s with this CommandZone's visibility via child-visibility propagation
|
||||
// (tax counters are graphics children of the zone). This function only handles layout,
|
||||
// so it stacks and measures by isActive() alone.
|
||||
if (ctr->isActive()) {
|
||||
y += ctr->getRadius() + TaxCounterSizes::TAX_COUNTER_MARGIN;
|
||||
}
|
||||
for (AbstractCounter *ctr : castCounts) {
|
||||
ctr->setPos(CastCountSizes::MARGIN, y);
|
||||
ctr->setZValue(ZValues::CAST_COUNTS);
|
||||
y += ctr->getRadius() + CastCountSizes::MARGIN;
|
||||
}
|
||||
|
||||
setMinimumHeight(static_cast<int>(y));
|
||||
|
|
|
|||
|
|
@ -38,21 +38,21 @@ constexpr qreal COMMAND_ZONE_WIDTH = CardDimensions::WIDTH_F * 1.5;
|
|||
*
|
||||
* Always visible when enabled. Uses the generic vertical stacking layout
|
||||
* with bottom overflow enabled. Can be minimized via double-click (25% height,
|
||||
* or the tax-counter floor if higher).
|
||||
* or the cast count floor if higher).
|
||||
*
|
||||
* @see SelectZone::layoutCardsVertically for the stacking algorithm
|
||||
* @see CommandZoneLogic for card data management
|
||||
* @see CommanderTaxCounter for the tax counter overlay
|
||||
* @see CastCountWidget for the cast count overlay
|
||||
*/
|
||||
class CommandZone : public SelectZone
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
static constexpr double MINIMIZED_HEIGHT_RATIO = 0.25;
|
||||
int zoneHeight; ///< Full height in pixels when expanded
|
||||
bool minimized = false; ///< Whether zone is collapsed (25% height, or the tax-counter floor)
|
||||
int minimumHeight = 0; ///< Floor for minimized height (e.g. to fit tax counters)
|
||||
QList<AbstractCounter *> taxCounters; ///< Registered tax counter widgets
|
||||
int zoneHeight; ///< Full height in pixels when expanded
|
||||
bool minimized = false; ///< Whether zone is collapsed (25% height, or the cast count floor)
|
||||
int minimumHeight = 0; ///< Floor for minimized height (e.g. to fit cast counts)
|
||||
QList<AbstractCounter *> castCounts; ///< Registered cast count widgets
|
||||
|
||||
public:
|
||||
/**
|
||||
|
|
@ -86,24 +86,24 @@ public:
|
|||
[[nodiscard]] bool isMinimized() const;
|
||||
/** @brief Returns the current display height (full or minimized). */
|
||||
[[nodiscard]] qreal currentHeight() const;
|
||||
/** @brief Sets the minimum height floor, e.g. to ensure tax counters remain visible. */
|
||||
/** @brief Sets the minimum height floor, e.g. to ensure cast counts remain visible. */
|
||||
void setMinimumHeight(int height);
|
||||
/** @brief Registers a tax counter widget for layout management. */
|
||||
void registerTaxCounter(AbstractCounter *counter);
|
||||
/** @brief Registers a cast count widget for layout management. */
|
||||
void registerCastCount(AbstractCounter *counter);
|
||||
/**
|
||||
* @brief Unregisters a tax counter widget from layout management.
|
||||
* @brief Unregisters a cast count widget from layout management.
|
||||
*
|
||||
* Call on removal: the widget outlives it via deleteLater(), so unregister synchronously
|
||||
* to keep it out of the next layout pass.
|
||||
*/
|
||||
void unregisterTaxCounter(AbstractCounter *counter);
|
||||
/** @brief Lays out visible tax counters vertically in the top-left corner of the command zone. */
|
||||
void rearrangeTaxCounters();
|
||||
void unregisterCastCount(AbstractCounter *counter);
|
||||
/** @brief Lays out visible cast counts vertically in the top-left corner of the command zone. */
|
||||
void rearrangeCastCounts();
|
||||
|
||||
signals:
|
||||
/** @brief Emitted when the zone's minimized state changes. */
|
||||
void minimizedChanged(bool isMinimized);
|
||||
/** @brief Emitted when display height changes without a minimized-state change (e.g. tax counter toggled while
|
||||
/** @brief Emitted when display height changes without a minimized-state change (e.g. cast count toggled while
|
||||
* minimized). */
|
||||
void effectiveHeightChanged();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue