mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-29 09:22:18 -07:00
Change things about resolution, address comments.
Took 45 minutes Took 12 minutes
This commit is contained in:
parent
cb8fe8305e
commit
80d44da729
36 changed files with 393 additions and 413 deletions
|
|
@ -244,8 +244,6 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/playmat/playmat_collection_dialog.h
|
src/interface/widgets/playmat/playmat_collection_dialog.h
|
||||||
src/interface/widgets/playmat/playmat_preview_widget.cpp
|
src/interface/widgets/playmat/playmat_preview_widget.cpp
|
||||||
src/interface/widgets/playmat/playmat_settings_dialog.cpp
|
src/interface/widgets/playmat/playmat_settings_dialog.cpp
|
||||||
src/interface/widgets/playmat/playmat_settings_utils.cpp
|
|
||||||
src/interface/widgets/playmat/playmat_settings_utils.h
|
|
||||||
src/interface/widgets/quick_settings/settings_button_widget.cpp
|
src/interface/widgets/quick_settings/settings_button_widget.cpp
|
||||||
src/interface/widgets/quick_settings/settings_popup_widget.cpp
|
src/interface/widgets/quick_settings/settings_popup_widget.cpp
|
||||||
src/interface/widgets/replay/replay_manager.cpp
|
src/interface/widgets/replay/replay_manager.cpp
|
||||||
|
|
|
||||||
|
|
@ -286,7 +286,7 @@ void GameEventHandler::eventGameStateChanged(const Event_GameStateChanged &event
|
||||||
}
|
}
|
||||||
player->processPlayerInfo(playerInfo);
|
player->processPlayerInfo(playerInfo);
|
||||||
// Extract playmat from player properties for opponent display
|
// Extract playmat from player properties for opponent display
|
||||||
if (prop.has_playmat_card_name()) {
|
if (prop.has_playmat_params()) {
|
||||||
player->setPlaymatFromProperties(prop);
|
player->setPlaymatFromProperties(prop);
|
||||||
}
|
}
|
||||||
if (player->getPlayerInfo()->getLocal()) {
|
if (player->getPlayerInfo()->getLocal()) {
|
||||||
|
|
@ -356,7 +356,7 @@ void GameEventHandler::eventPlayerPropertiesChanged(const Event_PlayerProperties
|
||||||
emit playerPropertiesChanged(prop, eventPlayerId);
|
emit playerPropertiesChanged(prop, eventPlayerId);
|
||||||
|
|
||||||
// Update playmat from player properties
|
// Update playmat from player properties
|
||||||
if (prop.has_playmat_card_name()) {
|
if (prop.has_playmat_params()) {
|
||||||
player->setPlaymatFromProperties(prop);
|
player->setPlaymatFromProperties(prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -252,12 +252,11 @@ void PlayerLogic::setDeck(const DeckList &_deck)
|
||||||
|
|
||||||
void PlayerLogic::setPlaymatFromProperties(const ServerInfo_PlayerProperties &props)
|
void PlayerLogic::setPlaymatFromProperties(const ServerInfo_PlayerProperties &props)
|
||||||
{
|
{
|
||||||
if (props.has_playmat_card_name() && !props.playmat_card_name().empty()) {
|
if (props.has_playmat_params() && !props.playmat_params().card_name().empty()) {
|
||||||
remotePlaymatCard = {QString::fromStdString(props.playmat_card_name()),
|
const auto &pp = props.playmat_params();
|
||||||
QString::fromStdString(props.playmat_card_provider_id())};
|
remotePlaymatCard = {QString::fromStdString(pp.card_name()), QString::fromStdString(pp.card_provider_id())};
|
||||||
remotePlaymatParams = {
|
remotePlaymatParams = {qBound(0.0, pp.margin_pct_l(), 0.95), qBound(0.0, pp.margin_pct_r(), 0.95),
|
||||||
qBound(0.0, props.playmat_margin_pct_l(), 0.95), qBound(0.0, props.playmat_margin_pct_r(), 0.95),
|
qBound(0.0, pp.vertical_offset(), 1.0), qBound(0.1, pp.zoom(), 4.0)};
|
||||||
qBound(0.0, props.playmat_vertical_offset(), 1.0), qBound(0.1, props.playmat_zoom(), 4.0)};
|
|
||||||
hasRemotePlaymat = true;
|
hasRemotePlaymat = true;
|
||||||
} else {
|
} else {
|
||||||
remotePlaymatCard = CardRef{};
|
remotePlaymatCard = CardRef{};
|
||||||
|
|
|
||||||
|
|
@ -8,19 +8,21 @@
|
||||||
#include "../../interface/widgets/dialogs/dlg_load_deck_from_clipboard.h"
|
#include "../../interface/widgets/dialogs/dlg_load_deck_from_clipboard.h"
|
||||||
#include "../../interface/widgets/dialogs/dlg_load_deck_from_website.h"
|
#include "../../interface/widgets/dialogs/dlg_load_deck_from_website.h"
|
||||||
#include "../../interface/widgets/dialogs/dlg_load_remote_deck.h"
|
#include "../../interface/widgets/dialogs/dlg_load_remote_deck.h"
|
||||||
#include "../../interface/widgets/playmat/playmat_settings_utils.h"
|
|
||||||
#include "../../interface/widgets/tabs/tab_game.h"
|
#include "../../interface/widgets/tabs/tab_game.h"
|
||||||
#include "deck_view.h"
|
#include "deck_view.h"
|
||||||
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <libcockatrice/card/database/card_database.h>
|
#include <libcockatrice/card/database/card_database.h>
|
||||||
#include <libcockatrice/card/database/card_database_manager.h>
|
#include <libcockatrice/card/database/card_database_manager.h>
|
||||||
|
#include <libcockatrice/deck_list/playmat_resolver.h>
|
||||||
#include <libcockatrice/protocol/pb/command_deck_select.pb.h>
|
#include <libcockatrice/protocol/pb/command_deck_select.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_ready_start.pb.h>
|
#include <libcockatrice/protocol/pb/command_ready_start.pb.h>
|
||||||
|
#include <libcockatrice/protocol/pb/command_set_playmat.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_set_sideboard_lock.pb.h>
|
#include <libcockatrice/protocol/pb/command_set_sideboard_lock.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_set_sideboard_plan.pb.h>
|
#include <libcockatrice/protocol/pb/command_set_sideboard_plan.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/response_deck_download.pb.h>
|
#include <libcockatrice/protocol/pb/response_deck_download.pb.h>
|
||||||
#include <libcockatrice/protocol/pending_command.h>
|
#include <libcockatrice/protocol/pending_command.h>
|
||||||
|
#include <libcockatrice/settings/interface_settings.h>
|
||||||
#include <libcockatrice/settings/visual_deck_storage_settings.h>
|
#include <libcockatrice/settings/visual_deck_storage_settings.h>
|
||||||
#include <libcockatrice/utility/string_limits.h>
|
#include <libcockatrice/utility/string_limits.h>
|
||||||
|
|
||||||
|
|
@ -101,6 +103,9 @@ DeckViewContainer::DeckViewContainer(int _playerId, TabGame *parent)
|
||||||
connect(&SettingsCache::instance().visualDeckStorage(), &VisualDeckStorageSettings::visualDeckStorageInGameChanged,
|
connect(&SettingsCache::instance().visualDeckStorage(), &VisualDeckStorageSettings::visualDeckStorageInGameChanged,
|
||||||
this, &DeckViewContainer::setVisualDeckStorageExists);
|
this, &DeckViewContainer::setVisualDeckStorageExists);
|
||||||
|
|
||||||
|
connect(&SettingsCache::instance().userInterface(), &InterfaceSettings::playmatSettingsChanged, this,
|
||||||
|
&DeckViewContainer::onPlaymatSettingsChanged);
|
||||||
|
|
||||||
switchToDeckSelectView();
|
switchToDeckSelectView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -278,11 +283,9 @@ void DeckViewContainer::loadDeckFromFile(const QString &filePath)
|
||||||
|
|
||||||
void DeckViewContainer::loadDeckFromDeckList(const DeckList &deck)
|
void DeckViewContainer::loadDeckFromDeckList(const DeckList &deck)
|
||||||
{
|
{
|
||||||
// Bake the user-level playmat resolution (override > deck > fallback list)
|
currentDeck = deck;
|
||||||
// into the uploaded deck so the server, local and remote players, and
|
|
||||||
// replays all derive the same effective playmat.
|
QString deckString = deck.writeToString_Native();
|
||||||
const DeckList effectiveDeck = applyUserPlaymatSettings(deck, SettingsCache::instance().userInterface());
|
|
||||||
QString deckString = effectiveDeck.writeToString_Native();
|
|
||||||
|
|
||||||
if (deckString.length() > MAX_FILE_LENGTH) {
|
if (deckString.length() > MAX_FILE_LENGTH) {
|
||||||
QMessageBox::critical(this, tr("Error"), tr("Deck is greater than maximum file size."));
|
QMessageBox::critical(this, tr("Error"), tr("Deck is greater than maximum file size."));
|
||||||
|
|
@ -294,6 +297,65 @@ void DeckViewContainer::loadDeckFromDeckList(const DeckList &deck)
|
||||||
PendingCommand *pend = parentGame->getGame()->getGameEventHandler()->prepareGameCommand(cmd);
|
PendingCommand *pend = parentGame->getGame()->getGameEventHandler()->prepareGameCommand(cmd);
|
||||||
connect(pend, &PendingCommand::finished, this, &DeckViewContainer::deckSelectFinished);
|
connect(pend, &PendingCommand::finished, this, &DeckViewContainer::deckSelectFinished);
|
||||||
parentGame->getGame()->getGameEventHandler()->sendGameCommand(pend, playerId);
|
parentGame->getGame()->getGameEventHandler()->sendGameCommand(pend, playerId);
|
||||||
|
|
||||||
|
resolveAndSendPlaymat();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckViewContainer::resolveAndSendPlaymat()
|
||||||
|
{
|
||||||
|
if (currentDeck.getCardRefList().isEmpty() && currentDeck.getPlaymat().card.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &settings = SettingsCache::instance().userInterface();
|
||||||
|
const auto fallbackBehavior = static_cast<PlaymatFallbackMode>(settings.getPlaymatFallbackBehavior());
|
||||||
|
|
||||||
|
PlaymatResolution resolved;
|
||||||
|
QList<PlaymatResolution> fallbackList = settings.getPlaymatFallbackList();
|
||||||
|
|
||||||
|
// In random mode with 2+ entries, remove the last-resolved mat to avoid repeats.
|
||||||
|
if (fallbackBehavior == PlaymatFallbackMode::Random && fallbackList.size() > 1) {
|
||||||
|
fallbackList.removeAll(lastResolvedPlaymat);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (settings.getPlaymatMode()) {
|
||||||
|
case 0: { // Override deck playmat — always use collection
|
||||||
|
DeckList emptyDeck;
|
||||||
|
resolved = resolveEffectivePlaymat(emptyDeck, {}, fallbackList, fallbackBehavior, playmatRotationIndex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1: // Fallback if deck has none — deck > collection > none
|
||||||
|
resolved = resolveEffectivePlaymat(currentDeck, {}, fallbackList, fallbackBehavior, playmatRotationIndex);
|
||||||
|
break;
|
||||||
|
case 2: // Deck only, ignore collection
|
||||||
|
resolved = currentDeck.getPlaymat();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastResolvedPlaymat = resolved;
|
||||||
|
|
||||||
|
Command_SetPlaymat playmatCmd;
|
||||||
|
auto *pp = playmatCmd.mutable_playmat_params();
|
||||||
|
pp->set_card_name(resolved.card.name.toStdString());
|
||||||
|
pp->set_card_provider_id(resolved.card.providerId.toStdString());
|
||||||
|
pp->set_margin_pct_l(resolved.params.marginPctL);
|
||||||
|
pp->set_margin_pct_r(resolved.params.marginPctR);
|
||||||
|
pp->set_vertical_offset(resolved.params.verticalOffset);
|
||||||
|
pp->set_zoom(resolved.params.zoom);
|
||||||
|
PendingCommand *playmatPend = parentGame->getGame()->getGameEventHandler()->prepareGameCommand(playmatCmd);
|
||||||
|
parentGame->getGame()->getGameEventHandler()->sendGameCommand(playmatPend, playerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckViewContainer::onPlaymatSettingsChanged()
|
||||||
|
{
|
||||||
|
resolveAndSendPlaymat();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckViewContainer::advancePlaymatRotation()
|
||||||
|
{
|
||||||
|
playmatRotationIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckViewContainer::loadRemoteDeck()
|
void DeckViewContainer::loadRemoteDeck()
|
||||||
|
|
@ -384,6 +446,10 @@ void DeckViewContainer::sideboardPlanChanged()
|
||||||
*/
|
*/
|
||||||
void DeckViewContainer::sendReadyStartCommand(bool ready)
|
void DeckViewContainer::sendReadyStartCommand(bool ready)
|
||||||
{
|
{
|
||||||
|
if (ready) {
|
||||||
|
resolveAndSendPlaymat();
|
||||||
|
}
|
||||||
|
|
||||||
Command_ReadyStart cmd;
|
Command_ReadyStart cmd;
|
||||||
cmd.set_ready(ready);
|
cmd.set_ready(ready);
|
||||||
parentGame->getGame()->getGameEventHandler()->sendGameCommand(cmd, playerId);
|
parentGame->getGame()->getGameEventHandler()->sendGameCommand(cmd, playerId);
|
||||||
|
|
@ -421,6 +487,7 @@ void DeckViewContainer::setSideboardLocked(bool locked)
|
||||||
|
|
||||||
void DeckViewContainer::setDeck(const DeckList &deck)
|
void DeckViewContainer::setDeck(const DeckList &deck)
|
||||||
{
|
{
|
||||||
|
currentDeck = deck;
|
||||||
deckView->setDeck(deck);
|
deckView->setDeck(deck);
|
||||||
switchToDeckLoadedView();
|
switchToDeckLoadedView();
|
||||||
}
|
}
|
||||||
|
|
@ -57,6 +57,9 @@ private:
|
||||||
VisualDeckStorageWidget *visualDeckStorageWidget;
|
VisualDeckStorageWidget *visualDeckStorageWidget;
|
||||||
TabGame *parentGame;
|
TabGame *parentGame;
|
||||||
int playerId;
|
int playerId;
|
||||||
|
int playmatRotationIndex = 0; ///< Per-match cursor for round-robin playmat mode.
|
||||||
|
DeckList currentDeck; ///< Cached deck for live settings re-resolution.
|
||||||
|
PlaymatResolution lastResolvedPlaymat; ///< Tracks last sent playmat to avoid repeats in random mode.
|
||||||
|
|
||||||
void tryCreateVisualDeckStorageWidget();
|
void tryCreateVisualDeckStorageWidget();
|
||||||
void sendReadyStartCommand(bool ready);
|
void sendReadyStartCommand(bool ready);
|
||||||
|
|
@ -75,6 +78,7 @@ private slots:
|
||||||
void sideboardLockButtonClicked();
|
void sideboardLockButtonClicked();
|
||||||
void updateSideboardLockButtonText();
|
void updateSideboardLockButtonText();
|
||||||
void refreshShortcuts();
|
void refreshShortcuts();
|
||||||
|
void onPlaymatSettingsChanged();
|
||||||
signals:
|
signals:
|
||||||
void newCardAdded(AbstractCardItem *card);
|
void newCardAdded(AbstractCardItem *card);
|
||||||
void notIdle();
|
void notIdle();
|
||||||
|
|
@ -87,6 +91,8 @@ public:
|
||||||
void setSideboardLocked(bool locked);
|
void setSideboardLocked(bool locked);
|
||||||
void setDeck(const DeckList &deck);
|
void setDeck(const DeckList &deck);
|
||||||
void setVisualDeckStorageExists(bool exists);
|
void setVisualDeckStorageExists(bool exists);
|
||||||
|
void advancePlaymatRotation();
|
||||||
|
void resolveAndSendPlaymat();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void loadDeckFromFile(const QString &filePath);
|
void loadDeckFromFile(const QString &filePath);
|
||||||
|
|
|
||||||
|
|
@ -379,15 +379,18 @@ void PlayerGraphicsItem::updatePlaymat()
|
||||||
CardRef playmatCard;
|
CardRef playmatCard;
|
||||||
PlaymatParams params;
|
PlaymatParams params;
|
||||||
|
|
||||||
// Check local deck first (for local player)
|
if (player->getHasRemotePlaymat()) {
|
||||||
const DeckList &deck = player->getDeck();
|
// Prefer the server-confirmed playmat (updated by Command_SetPlaymat).
|
||||||
if (!deck.getPlaymatCard().isEmpty()) {
|
|
||||||
playmatCard = deck.getPlaymatCard();
|
|
||||||
params = deck.getPlaymatParams();
|
|
||||||
} else if (visibility == 2 && player->getHasRemotePlaymat()) {
|
|
||||||
// "Show all" — also show remote playmats from opponents
|
|
||||||
playmatCard = player->getRemotePlaymatCard();
|
playmatCard = player->getRemotePlaymatCard();
|
||||||
params = player->getRemotePlaymatParams();
|
params = player->getRemotePlaymatParams();
|
||||||
|
} else {
|
||||||
|
// Fall back to the locally baked-in deck playmat.
|
||||||
|
const DeckList &deck = player->getDeck();
|
||||||
|
const PlaymatResolution &deckPlaymat = deck.getPlaymat();
|
||||||
|
if (!deckPlaymat.card.isEmpty()) {
|
||||||
|
playmatCard = deckPlaymat.card;
|
||||||
|
params = deckPlaymat.params;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (playmatCard.isEmpty()) {
|
if (playmatCard.isEmpty()) {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
#include "../../../client/settings/cache_settings.h"
|
#include "../../../client/settings/cache_settings.h"
|
||||||
#include "../../../client/settings/shortcuts_settings.h"
|
#include "../../../client/settings/shortcuts_settings.h"
|
||||||
#include "../playmat/playmat_settings_dialog.h"
|
#include "../playmat/playmat_settings_dialog.h"
|
||||||
#include "../playmat/playmat_settings_utils.h"
|
|
||||||
#include "../settings_page/user_interface_settings_page.h"
|
#include "../settings_page/user_interface_settings_page.h"
|
||||||
#include "../tabs/api/commander_spellbook/commander_bracket_widget.h"
|
#include "../tabs/api/commander_spellbook/commander_bracket_widget.h"
|
||||||
#include "deck_list_style_proxy.h"
|
#include "deck_list_style_proxy.h"
|
||||||
|
|
@ -454,29 +453,25 @@ void DeckEditorDeckDockWidget::writeBannerCard(int index)
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::openPlaymatSettings()
|
void DeckEditorDeckDockWidget::openPlaymatSettings()
|
||||||
{
|
{
|
||||||
CardRef currentCard = deckStateManager->getMetadata().playmatCard;
|
PlaymatResolution current = deckStateManager->getMetadata().playmat;
|
||||||
PlaymatParams currentParams = deckStateManager->getMetadata().playmatParams;
|
|
||||||
|
|
||||||
PlaymatSettingsDialog dialog(currentCard, currentParams, this);
|
PlaymatSettingsDialog dialog(current.card, current.params, this);
|
||||||
if (dialog.exec() == QDialog::Accepted) {
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
CardRef newCard = dialog.card();
|
CardRef newCard = dialog.card();
|
||||||
PlaymatParams newParams = dialog.params();
|
PlaymatParams newParams = dialog.params();
|
||||||
|
|
||||||
if (newCard.isEmpty()) {
|
if (newCard.isEmpty()) {
|
||||||
// User clicked "Remove Playmat"
|
deckStateManager->setPlaymat(PlaymatResolution{});
|
||||||
deckStateManager->setPlaymatCard(CardRef{});
|
|
||||||
deckStateManager->setPlaymatParams(PlaymatParams{});
|
|
||||||
} else {
|
} else {
|
||||||
deckStateManager->setPlaymatCard(newCard);
|
deckStateManager->setPlaymat({newCard, newParams});
|
||||||
deckStateManager->setPlaymatParams(newParams);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// "Also set as my default playmat": make this the fixed user-level
|
// "Also set as my default playmat": make this the fixed user-level
|
||||||
// fallback, so decks without a playmat of their own use it.
|
// fallback, so decks without a playmat of their own use it.
|
||||||
if (dialog.useAsDefault() && !newCard.isEmpty()) {
|
if (dialog.useAsDefault() && !newCard.isEmpty()) {
|
||||||
auto &interfaceSettings = SettingsCache::instance().userInterface();
|
auto &interfaceSettings = SettingsCache::instance().userInterface();
|
||||||
interfaceSettings.setPlaymatFallbackList({storedFromResolution({newCard, newParams})});
|
interfaceSettings.setPlaymatFallbackList({{newCard, newParams}});
|
||||||
interfaceSettings.setPlaymatFallbackMode(0); // PlaymatFallbackMode::Fixed
|
interfaceSettings.setPlaymatFallbackBehavior(0); // PlaymatFallbackMode::Fixed
|
||||||
}
|
}
|
||||||
updatePlaymatLabel();
|
updatePlaymatLabel();
|
||||||
}
|
}
|
||||||
|
|
@ -484,7 +479,7 @@ void DeckEditorDeckDockWidget::openPlaymatSettings()
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::updatePlaymatLabel()
|
void DeckEditorDeckDockWidget::updatePlaymatLabel()
|
||||||
{
|
{
|
||||||
CardRef playmat = deckStateManager->getMetadata().playmatCard;
|
CardRef playmat = deckStateManager->getMetadata().playmat.card;
|
||||||
if (playmat.isEmpty()) {
|
if (playmat.isEmpty()) {
|
||||||
playmatSettingsButton->setText(tr("Edit Playmat..."));
|
playmatSettingsButton->setText(tr("Edit Playmat..."));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -142,28 +142,15 @@ void DeckStateManager::setBannerCard(const CardRef &bannerCard)
|
||||||
doMetadataModified();
|
doMetadataModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckStateManager::setPlaymatCard(const CardRef &playmatCard)
|
void DeckStateManager::setPlaymat(const PlaymatResolution &playmat)
|
||||||
{
|
{
|
||||||
CardRef previous = deckList->getPlaymatCard();
|
PlaymatResolution previous = deckList->getPlaymat();
|
||||||
if (previous == playmatCard) {
|
if (previous == playmat) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
requestHistorySave(tr("Set playmat card to %1 (%2)").arg(playmatCard.name).arg(playmatCard.providerId));
|
requestHistorySave(tr("Set playmat to %1").arg(playmat.card.name));
|
||||||
deckList->setPlaymatCard(playmatCard);
|
deckList->setPlaymat(playmat);
|
||||||
|
|
||||||
doMetadataModified();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeckStateManager::setPlaymatParams(const PlaymatParams &playmatParams)
|
|
||||||
{
|
|
||||||
PlaymatParams previous = deckList->getPlaymatParams();
|
|
||||||
if (previous == playmatParams) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
requestHistorySave(tr("Updated playmat positioning"));
|
|
||||||
deckList->setPlaymatParams(playmatParams);
|
|
||||||
|
|
||||||
doMetadataModified();
|
doMetadataModified();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -171,8 +171,7 @@ public:
|
||||||
void setName(const QString &name);
|
void setName(const QString &name);
|
||||||
void setComments(const QString &comments);
|
void setComments(const QString &comments);
|
||||||
void setBannerCard(const CardRef &bannerCard);
|
void setBannerCard(const CardRef &bannerCard);
|
||||||
void setPlaymatCard(const CardRef &playmatCard);
|
void setPlaymat(const PlaymatResolution &playmat);
|
||||||
void setPlaymatParams(const PlaymatParams &playmatParams);
|
|
||||||
void setTags(const QStringList &tags);
|
void setTags(const QStringList &tags);
|
||||||
void setFormat(const QString &format);
|
void setFormat(const QString &format);
|
||||||
///@}
|
///@}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#include "../../../client/settings/cache_settings.h"
|
#include "../../../client/settings/cache_settings.h"
|
||||||
#include "playmat_settings_dialog.h"
|
#include "playmat_settings_dialog.h"
|
||||||
#include "playmat_settings_utils.h"
|
|
||||||
|
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
|
|
@ -24,7 +23,7 @@ void PlaymatCollectionDialog::accept()
|
||||||
{
|
{
|
||||||
auto &interfaceSettings = SettingsCache::instance().userInterface();
|
auto &interfaceSettings = SettingsCache::instance().userInterface();
|
||||||
interfaceSettings.setPlaymatFallbackList(playmats);
|
interfaceSettings.setPlaymatFallbackList(playmats);
|
||||||
interfaceSettings.setPlaymatFallbackMode(modeCombo->currentData().toInt());
|
interfaceSettings.setPlaymatFallbackBehavior(modeCombo->currentData().toInt());
|
||||||
QDialog::accept();
|
QDialog::accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -39,8 +38,8 @@ void PlaymatCollectionDialog::setupUi()
|
||||||
playmats = interfaceSettings.getPlaymatFallbackList();
|
playmats = interfaceSettings.getPlaymatFallbackList();
|
||||||
|
|
||||||
playmatList = new QListWidget;
|
playmatList = new QListWidget;
|
||||||
for (const StoredPlaymat &entry : playmats) {
|
for (const PlaymatResolution &entry : playmats) {
|
||||||
playmatList->addItem(entry.name);
|
playmatList->addItem(entry.card.name);
|
||||||
}
|
}
|
||||||
connect(playmatList, &QListWidget::itemSelectionChanged, this, &PlaymatCollectionDialog::selectionChanged);
|
connect(playmatList, &QListWidget::itemSelectionChanged, this, &PlaymatCollectionDialog::selectionChanged);
|
||||||
connect(playmatList, &QListWidget::itemDoubleClicked, this, [this](QListWidgetItem *) { editPlaymat(); });
|
connect(playmatList, &QListWidget::itemDoubleClicked, this, [this](QListWidgetItem *) { editPlaymat(); });
|
||||||
|
|
@ -73,7 +72,7 @@ void PlaymatCollectionDialog::setupUi()
|
||||||
modeCombo->addItem(QString(), 0);
|
modeCombo->addItem(QString(), 0);
|
||||||
modeCombo->addItem(QString(), 1);
|
modeCombo->addItem(QString(), 1);
|
||||||
modeCombo->addItem(QString(), 2);
|
modeCombo->addItem(QString(), 2);
|
||||||
const int modeIndex = modeCombo->findData(interfaceSettings.getPlaymatFallbackMode());
|
const int modeIndex = modeCombo->findData(interfaceSettings.getPlaymatFallbackBehavior());
|
||||||
if (modeIndex >= 0) {
|
if (modeIndex >= 0) {
|
||||||
modeCombo->setCurrentIndex(modeIndex);
|
modeCombo->setCurrentIndex(modeIndex);
|
||||||
}
|
}
|
||||||
|
|
@ -106,20 +105,16 @@ void PlaymatCollectionDialog::selectionChanged()
|
||||||
moveDownButton->setEnabled(hasSelection && playmatList->currentRow() < playmatList->count() - 1);
|
moveDownButton->setEnabled(hasSelection && playmatList->currentRow() < playmatList->count() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaymatCollectionDialog::appendEntry(const StoredPlaymat &entry)
|
|
||||||
{
|
|
||||||
playmats.append(entry);
|
|
||||||
playmatList->addItem(entry.name);
|
|
||||||
playmatList->setCurrentRow(playmatList->count() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlaymatCollectionDialog::addPlaymat()
|
void PlaymatCollectionDialog::addPlaymat()
|
||||||
{
|
{
|
||||||
PlaymatSettingsDialog dialog(CardRef{}, PlaymatParams{}, this);
|
PlaymatSettingsDialog dialog(CardRef{}, PlaymatParams{}, this);
|
||||||
if (dialog.exec() == QDialog::Accepted) {
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
const CardRef card = dialog.card();
|
const CardRef card = dialog.card();
|
||||||
if (!card.isEmpty()) {
|
if (!card.isEmpty()) {
|
||||||
appendEntry(storedFromResolution({card, dialog.params()}));
|
PlaymatResolution res = {card, dialog.params()};
|
||||||
|
playmats.append(res);
|
||||||
|
playmatList->addItem(res.card.name);
|
||||||
|
playmatList->setCurrentRow(playmatList->count() - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -131,14 +126,14 @@ void PlaymatCollectionDialog::editPlaymat()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PlaymatResolution current = resolutionFromStoredPlaymat(playmats.at(row));
|
const PlaymatResolution ¤t = playmats.at(row);
|
||||||
PlaymatSettingsDialog dialog(current.card, current.params, this);
|
PlaymatSettingsDialog dialog(current.card, current.params, this);
|
||||||
if (dialog.exec() == QDialog::Accepted) {
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
const CardRef card = dialog.card();
|
const CardRef card = dialog.card();
|
||||||
if (card.isEmpty()) {
|
if (card.isEmpty()) {
|
||||||
return; // Removal is handled by the Remove button
|
return; // Removal is handled by the Remove button
|
||||||
}
|
}
|
||||||
playmats[row] = storedFromResolution({card, dialog.params()});
|
playmats[row] = {card, dialog.params()};
|
||||||
playmatList->item(row)->setText(card.name);
|
playmatList->item(row)->setText(card.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -186,8 +181,8 @@ void PlaymatCollectionDialog::retranslateUi()
|
||||||
removeButton->setText(tr("Remove"));
|
removeButton->setText(tr("Remove"));
|
||||||
moveUpButton->setText(tr("Move Up"));
|
moveUpButton->setText(tr("Move Up"));
|
||||||
moveDownButton->setText(tr("Move Down"));
|
moveDownButton->setText(tr("Move Down"));
|
||||||
modeLabel->setText(tr("When a deck has no playmat:"));
|
modeLabel->setText(tr("List mode:"));
|
||||||
modeCombo->setItemText(0, tr("Always use the first playmat"));
|
modeCombo->setItemText(0, tr("Fixed (always the first entry)"));
|
||||||
modeCombo->setItemText(1, tr("Cycle through playmats (one per game)"));
|
modeCombo->setItemText(1, tr("Round-robin (cycle through entries)"));
|
||||||
modeCombo->setItemText(2, tr("Pick a random playmat per game"));
|
modeCombo->setItemText(2, tr("Random (pick one per game)"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#define COCKATRICE_PLAYMAT_COLLECTION_DIALOG_H
|
#define COCKATRICE_PLAYMAT_COLLECTION_DIALOG_H
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <libcockatrice/interfaces/interface_interface_settings_provider.h>
|
#include <libcockatrice/utility/playmat_params.h>
|
||||||
|
|
||||||
class QComboBox;
|
class QComboBox;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
|
|
@ -39,9 +39,8 @@ private:
|
||||||
void setupUi();
|
void setupUi();
|
||||||
void retranslateUi();
|
void retranslateUi();
|
||||||
int currentRow() const;
|
int currentRow() const;
|
||||||
void appendEntry(const StoredPlaymat &entry);
|
|
||||||
|
|
||||||
QList<StoredPlaymat> playmats; ///< Working copy edited by the dialog.
|
QList<PlaymatResolution> playmats; ///< Working copy edited by the dialog.
|
||||||
QListWidget *playmatList;
|
QListWidget *playmatList;
|
||||||
QComboBox *modeCombo;
|
QComboBox *modeCombo;
|
||||||
QLabel *modeLabel;
|
QLabel *modeLabel;
|
||||||
|
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
#include "playmat_settings_utils.h"
|
|
||||||
|
|
||||||
#include <libcockatrice/interfaces/interface_interface_settings_provider.h>
|
|
||||||
#include <libcockatrice/settings/interface_settings.h>
|
|
||||||
|
|
||||||
PlaymatResolution resolutionFromStoredPlaymat(const StoredPlaymat &stored)
|
|
||||||
{
|
|
||||||
PlaymatResolution resolution;
|
|
||||||
resolution.card = {stored.name, stored.providerId};
|
|
||||||
resolution.params = {qBound(0.0, stored.marginPctL, 0.95), qBound(0.0, stored.marginPctR, 0.95),
|
|
||||||
qBound(0.0, stored.verticalOffset, 1.0), qBound(0.1, stored.zoom, 4.0)};
|
|
||||||
return resolution;
|
|
||||||
}
|
|
||||||
|
|
||||||
StoredPlaymat storedFromResolution(const PlaymatResolution &resolution)
|
|
||||||
{
|
|
||||||
StoredPlaymat stored;
|
|
||||||
stored.name = resolution.card.name;
|
|
||||||
stored.providerId = resolution.card.providerId;
|
|
||||||
stored.marginPctL = resolution.params.marginPctL;
|
|
||||||
stored.marginPctR = resolution.params.marginPctR;
|
|
||||||
stored.verticalOffset = resolution.params.verticalOffset;
|
|
||||||
stored.zoom = resolution.params.zoom;
|
|
||||||
return stored;
|
|
||||||
}
|
|
||||||
|
|
||||||
DeckList applyUserPlaymatSettings(const DeckList &deck, const InterfaceSettings &settings)
|
|
||||||
{
|
|
||||||
// Per-session cursor for the round-robin mode; advancing per resolution
|
|
||||||
// (per deck upload, i.e. roughly per game) cycles deterministically.
|
|
||||||
static int rotationIndex = 0;
|
|
||||||
|
|
||||||
QList<PlaymatResolution> fallbackList;
|
|
||||||
const QList<StoredPlaymat> storedList = settings.getPlaymatFallbackList();
|
|
||||||
fallbackList.reserve(storedList.size());
|
|
||||||
for (const StoredPlaymat &stored : storedList) {
|
|
||||||
fallbackList.append(resolutionFromStoredPlaymat(stored));
|
|
||||||
}
|
|
||||||
|
|
||||||
const PlaymatResolution resolved =
|
|
||||||
resolveEffectivePlaymat(deck, resolutionFromStoredPlaymat(settings.getPlaymatOverride()), fallbackList,
|
|
||||||
static_cast<PlaymatFallbackMode>(settings.getPlaymatFallbackMode()), rotationIndex);
|
|
||||||
|
|
||||||
DeckList effectiveDeck = deck;
|
|
||||||
effectiveDeck.setPlaymatCard(resolved.card);
|
|
||||||
effectiveDeck.setPlaymatParams(resolved.params);
|
|
||||||
return effectiveDeck;
|
|
||||||
}
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
#ifndef COCKATRICE_PLAYMAT_SETTINGS_UTILS_H
|
|
||||||
#define COCKATRICE_PLAYMAT_SETTINGS_UTILS_H
|
|
||||||
|
|
||||||
#include <libcockatrice/deck_list/deck_list.h>
|
|
||||||
#include <libcockatrice/deck_list/playmat_resolver.h>
|
|
||||||
#include <libcockatrice/interfaces/interface_interface_settings_provider.h>
|
|
||||||
|
|
||||||
class InterfaceSettings;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Converts a stored (settings-level) playmat entry into resolver types,
|
|
||||||
* clamping the positioning parameters to their valid ranges.
|
|
||||||
*/
|
|
||||||
PlaymatResolution resolutionFromStoredPlaymat(const StoredPlaymat &stored);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Converts a resolved playmat into a stored (settings-level) entry.
|
|
||||||
*/
|
|
||||||
StoredPlaymat storedFromResolution(const PlaymatResolution &resolution);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Applies the user-level playmat settings (override, fallback list and
|
|
||||||
* mode) to a copy of the deck, returning the deck with the effective
|
|
||||||
* playmat baked into its metadata.
|
|
||||||
*
|
|
||||||
* The resolution chain is: override > deck-configured playmat > fallback list.
|
|
||||||
* The deck passed in is never modified; the returned copy is intended for
|
|
||||||
* upload to the server so local and remote players see the same effective mat.
|
|
||||||
*/
|
|
||||||
DeckList applyUserPlaymatSettings(const DeckList &deck, const InterfaceSettings &settings);
|
|
||||||
|
|
||||||
#endif // COCKATRICE_PLAYMAT_SETTINGS_UTILS_H
|
|
||||||
|
|
@ -9,7 +9,6 @@
|
||||||
#include "../interface/widgets/general/background_sources.h"
|
#include "../interface/widgets/general/background_sources.h"
|
||||||
#include "../playmat/playmat_collection_dialog.h"
|
#include "../playmat/playmat_collection_dialog.h"
|
||||||
#include "../playmat/playmat_settings_dialog.h"
|
#include "../playmat/playmat_settings_dialog.h"
|
||||||
#include "../playmat/playmat_settings_utils.h"
|
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QColorDialog>
|
#include <QColorDialog>
|
||||||
|
|
@ -342,22 +341,28 @@ AppearanceSettingsPage::AppearanceSettingsPage()
|
||||||
});
|
});
|
||||||
playmatVisibilityLabel.setBuddy(&playmatVisibilityCombo);
|
playmatVisibilityLabel.setBuddy(&playmatVisibilityCombo);
|
||||||
|
|
||||||
// User-level playmat settings: override (force all decks) and fallback collection.
|
// Playmat mode: Override / Fallback / Deck-only
|
||||||
connect(&playmatOverrideEditButton, &QPushButton::clicked, this,
|
playmatModeCombo.addItem(tr("Override deck playmat"), 0);
|
||||||
&AppearanceSettingsPage::openOverridePlaymatSettings);
|
playmatModeCombo.addItem(tr("Fallback if deck has none"), 1);
|
||||||
connect(&playmatOverrideClearButton, &QPushButton::clicked, this, &AppearanceSettingsPage::clearOverridePlaymat);
|
playmatModeCombo.addItem(tr("Deck only, ignore collection"), 2);
|
||||||
|
int modeIdx = playmatModeCombo.findData(settings.userInterface().getPlaymatMode());
|
||||||
|
if (modeIdx >= 0) {
|
||||||
|
playmatModeCombo.setCurrentIndex(modeIdx);
|
||||||
|
}
|
||||||
|
connect(&playmatModeCombo, qOverload<int>(&QComboBox::currentIndexChanged), this, [this](int index) {
|
||||||
|
SettingsCache::instance().userInterface().setPlaymatMode(playmatModeCombo.itemData(index).toInt());
|
||||||
|
});
|
||||||
|
playmatModeLabel.setBuddy(&playmatModeCombo);
|
||||||
|
|
||||||
|
// User-level playmat settings: fallback collection.
|
||||||
connect(&playmatDefaultEditButton, &QPushButton::clicked, this,
|
connect(&playmatDefaultEditButton, &QPushButton::clicked, this,
|
||||||
&AppearanceSettingsPage::openPlaymatCollectionDialog);
|
&AppearanceSettingsPage::openPlaymatCollectionDialog);
|
||||||
|
|
||||||
auto *overrideButtons = new QHBoxLayout;
|
|
||||||
overrideButtons->addWidget(&playmatOverrideEditButton);
|
|
||||||
overrideButtons->addWidget(&playmatOverrideClearButton);
|
|
||||||
|
|
||||||
auto *playmatGrid = new QGridLayout;
|
auto *playmatGrid = new QGridLayout;
|
||||||
playmatGrid->addWidget(&playmatVisibilityLabel, 0, 0, 1, 1);
|
playmatGrid->addWidget(&playmatVisibilityLabel, 0, 0, 1, 1);
|
||||||
playmatGrid->addWidget(&playmatVisibilityCombo, 0, 1, 1, 1);
|
playmatGrid->addWidget(&playmatVisibilityCombo, 0, 1, 1, 1);
|
||||||
playmatGrid->addWidget(&playmatOverrideLabel, 1, 0, 1, 1);
|
playmatGrid->addWidget(&playmatModeLabel, 1, 0, 1, 1);
|
||||||
playmatGrid->addLayout(overrideButtons, 1, 1, 1, 1);
|
playmatGrid->addWidget(&playmatModeCombo, 1, 1, 1, 1);
|
||||||
playmatGrid->addWidget(&playmatDefaultLabel, 2, 0, 1, 1);
|
playmatGrid->addWidget(&playmatDefaultLabel, 2, 0, 1, 1);
|
||||||
playmatGrid->addWidget(&playmatDefaultEditButton, 2, 1, 1, 1);
|
playmatGrid->addWidget(&playmatDefaultEditButton, 2, 1, 1, 1);
|
||||||
|
|
||||||
|
|
@ -471,40 +476,10 @@ void AppearanceSettingsPage::cardViewExpandedRowsMaxChanged(int value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppearanceSettingsPage::openOverridePlaymatSettings()
|
|
||||||
{
|
|
||||||
auto &interfaceSettings = SettingsCache::instance().userInterface();
|
|
||||||
const PlaymatResolution current = resolutionFromStoredPlaymat(interfaceSettings.getPlaymatOverride());
|
|
||||||
PlaymatSettingsDialog dialog(current.card, current.params, this);
|
|
||||||
if (dialog.exec() == QDialog::Accepted) {
|
|
||||||
const CardRef card = dialog.card();
|
|
||||||
if (card.isEmpty()) {
|
|
||||||
interfaceSettings.setPlaymatOverride(StoredPlaymat{});
|
|
||||||
} else {
|
|
||||||
interfaceSettings.setPlaymatOverride(storedFromResolution({card, dialog.params()}));
|
|
||||||
}
|
|
||||||
updatePlaymatSummary();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppearanceSettingsPage::clearOverridePlaymat()
|
|
||||||
{
|
|
||||||
SettingsCache::instance().userInterface().setPlaymatOverride(StoredPlaymat{});
|
|
||||||
updatePlaymatSummary();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppearanceSettingsPage::openPlaymatCollectionDialog()
|
void AppearanceSettingsPage::openPlaymatCollectionDialog()
|
||||||
{
|
{
|
||||||
PlaymatCollectionDialog dialog(this);
|
PlaymatCollectionDialog dialog(this);
|
||||||
dialog.exec();
|
dialog.exec();
|
||||||
updatePlaymatSummary();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppearanceSettingsPage::updatePlaymatSummary()
|
|
||||||
{
|
|
||||||
const StoredPlaymat overridePlaymat = SettingsCache::instance().userInterface().getPlaymatOverride();
|
|
||||||
playmatOverrideEditButton.setText(overridePlaymat.isEmpty() ? tr("Set...")
|
|
||||||
: tr("Change (%1)").arg(overridePlaymat.name));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppearanceSettingsPage::retranslateUi()
|
void AppearanceSettingsPage::retranslateUi()
|
||||||
|
|
@ -567,9 +542,7 @@ void AppearanceSettingsPage::retranslateUi()
|
||||||
minPlayersForMultiColumnLayoutLabel.setText(tr("Minimum player count for multi-column layout:"));
|
minPlayersForMultiColumnLayoutLabel.setText(tr("Minimum player count for multi-column layout:"));
|
||||||
playmatGroupBox->setTitle(tr("Playmat settings"));
|
playmatGroupBox->setTitle(tr("Playmat settings"));
|
||||||
playmatVisibilityLabel.setText(tr("Playmat visibility:"));
|
playmatVisibilityLabel.setText(tr("Playmat visibility:"));
|
||||||
playmatOverrideLabel.setText(tr("Force playmat for all decks:"));
|
playmatModeLabel.setText(tr("Default collection behavior:"));
|
||||||
playmatOverrideClearButton.setText(tr("Clear"));
|
playmatDefaultLabel.setText(tr("Default playmat collection:"));
|
||||||
playmatDefaultLabel.setText(tr("Default playmats (when a deck has none):"));
|
|
||||||
playmatDefaultEditButton.setText(tr("Edit..."));
|
playmatDefaultEditButton.setText(tr("Edit..."));
|
||||||
updatePlaymatSummary();
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,7 @@ private slots:
|
||||||
|
|
||||||
void cardViewInitialRowsMaxChanged(int value);
|
void cardViewInitialRowsMaxChanged(int value);
|
||||||
void cardViewExpandedRowsMaxChanged(int value);
|
void cardViewExpandedRowsMaxChanged(int value);
|
||||||
void openOverridePlaymatSettings();
|
|
||||||
void clearOverridePlaymat();
|
|
||||||
void openPlaymatCollectionDialog();
|
void openPlaymatCollectionDialog();
|
||||||
void updatePlaymatSummary();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QLabel themeLabel;
|
QLabel themeLabel;
|
||||||
|
|
@ -65,9 +62,8 @@ private:
|
||||||
QCheckBox invertVerticalCoordinateCheckBox;
|
QCheckBox invertVerticalCoordinateCheckBox;
|
||||||
QLabel playmatVisibilityLabel;
|
QLabel playmatVisibilityLabel;
|
||||||
QComboBox playmatVisibilityCombo;
|
QComboBox playmatVisibilityCombo;
|
||||||
QLabel playmatOverrideLabel;
|
QLabel playmatModeLabel;
|
||||||
QPushButton playmatOverrideEditButton;
|
QComboBox playmatModeCombo;
|
||||||
QPushButton playmatOverrideClearButton;
|
|
||||||
QLabel playmatDefaultLabel;
|
QLabel playmatDefaultLabel;
|
||||||
QPushButton playmatDefaultEditButton;
|
QPushButton playmatDefaultEditButton;
|
||||||
QGroupBox *themeGroupBox;
|
QGroupBox *themeGroupBox;
|
||||||
|
|
|
||||||
|
|
@ -911,6 +911,7 @@ void TabGame::stopGame()
|
||||||
QMapIterator<int, TabbedDeckViewContainer *> i(deckViewContainers);
|
QMapIterator<int, TabbedDeckViewContainer *> i(deckViewContainers);
|
||||||
while (i.hasNext()) {
|
while (i.hasNext()) {
|
||||||
i.next();
|
i.next();
|
||||||
|
i.value()->playerDeckView->advancePlaymatRotation();
|
||||||
i.value()->show();
|
i.value()->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ static const QString CURRENT_SIDEBOARD_PLAN_KEY = "";
|
||||||
|
|
||||||
bool DeckList::Metadata::isEmpty() const
|
bool DeckList::Metadata::isEmpty() const
|
||||||
{
|
{
|
||||||
return name.isEmpty() && comments.isEmpty() && bannerCard.isEmpty() && tags.isEmpty() && playmatCard.isEmpty();
|
return name.isEmpty() && comments.isEmpty() && bannerCard.isEmpty() && tags.isEmpty() && playmat.card.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
DeckList::DeckList()
|
DeckList::DeckList()
|
||||||
|
|
@ -82,28 +82,28 @@ bool DeckList::readElement(QXmlStreamReader *xml)
|
||||||
QString vOffStr = xml->attributes().value("verticalOffset").toString();
|
QString vOffStr = xml->attributes().value("verticalOffset").toString();
|
||||||
QString zoomStr = xml->attributes().value("zoom").toString();
|
QString zoomStr = xml->attributes().value("zoom").toString();
|
||||||
QString cardName = xml->readElementText();
|
QString cardName = xml->readElementText();
|
||||||
metadata.playmatCard = {cardName, providerId};
|
PlaymatResolution playmat;
|
||||||
PlaymatParams params;
|
playmat.card = {cardName, providerId};
|
||||||
// Clamp to the same ranges as the settings dialog and the remote
|
// Clamp to the same ranges as the settings dialog and the remote
|
||||||
// player-properties path so malformed deck files cannot produce
|
// player-properties path so malformed deck files cannot produce
|
||||||
// degenerate art rectangles (e.g. a zoom of 0 dividing by zero).
|
// degenerate art rectangles (e.g. a zoom of 0 dividing by zero).
|
||||||
params.marginPctL = qBound(0.0, marginLStr.toDouble(&ok), 0.95);
|
playmat.params.marginPctL = qBound(0.0, marginLStr.toDouble(&ok), 0.95);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
params.marginPctL = 0.07;
|
playmat.params.marginPctL = 0.07;
|
||||||
}
|
}
|
||||||
params.marginPctR = qBound(0.0, marginRStr.toDouble(&ok), 0.95);
|
playmat.params.marginPctR = qBound(0.0, marginRStr.toDouble(&ok), 0.95);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
params.marginPctR = 0.07;
|
playmat.params.marginPctR = 0.07;
|
||||||
}
|
}
|
||||||
params.verticalOffset = qBound(0.0, vOffStr.toDouble(&ok), 1.0);
|
playmat.params.verticalOffset = qBound(0.0, vOffStr.toDouble(&ok), 1.0);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
params.verticalOffset = 0.33;
|
playmat.params.verticalOffset = 0.33;
|
||||||
}
|
}
|
||||||
params.zoom = qBound(0.1, zoomStr.toDouble(&ok), 4.0);
|
playmat.params.zoom = qBound(0.1, zoomStr.toDouble(&ok), 4.0);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
params.zoom = 1.0;
|
playmat.params.zoom = 1.0;
|
||||||
}
|
}
|
||||||
metadata.playmatParams = params;
|
metadata.playmat = playmat;
|
||||||
} else if (childName == "tags") {
|
} else if (childName == "tags") {
|
||||||
metadata.tags.clear(); // Clear existing tags
|
metadata.tags.clear(); // Clear existing tags
|
||||||
while (xml->readNextStartElement()) {
|
while (xml->readNextStartElement()) {
|
||||||
|
|
@ -134,14 +134,14 @@ static void writeMetadata(QXmlStreamWriter *xml, const DeckList::Metadata &metad
|
||||||
xml->writeAttribute("providerId", metadata.bannerCard.providerId);
|
xml->writeAttribute("providerId", metadata.bannerCard.providerId);
|
||||||
xml->writeCharacters(metadata.bannerCard.name);
|
xml->writeCharacters(metadata.bannerCard.name);
|
||||||
xml->writeEndElement();
|
xml->writeEndElement();
|
||||||
if (!metadata.playmatCard.isEmpty()) {
|
if (!metadata.playmat.card.isEmpty()) {
|
||||||
xml->writeStartElement("playmatCard");
|
xml->writeStartElement("playmatCard");
|
||||||
xml->writeAttribute("providerId", metadata.playmatCard.providerId);
|
xml->writeAttribute("providerId", metadata.playmat.card.providerId);
|
||||||
xml->writeAttribute("marginPctL", QString::number(metadata.playmatParams.marginPctL, 'f', 4));
|
xml->writeAttribute("marginPctL", QString::number(metadata.playmat.params.marginPctL, 'f', 4));
|
||||||
xml->writeAttribute("marginPctR", QString::number(metadata.playmatParams.marginPctR, 'f', 4));
|
xml->writeAttribute("marginPctR", QString::number(metadata.playmat.params.marginPctR, 'f', 4));
|
||||||
xml->writeAttribute("verticalOffset", QString::number(metadata.playmatParams.verticalOffset, 'f', 4));
|
xml->writeAttribute("verticalOffset", QString::number(metadata.playmat.params.verticalOffset, 'f', 4));
|
||||||
xml->writeAttribute("zoom", QString::number(metadata.playmatParams.zoom, 'f', 4));
|
xml->writeAttribute("zoom", QString::number(metadata.playmat.params.zoom, 'f', 4));
|
||||||
xml->writeCharacters(metadata.playmatCard.name);
|
xml->writeCharacters(metadata.playmat.card.name);
|
||||||
xml->writeEndElement();
|
xml->writeEndElement();
|
||||||
}
|
}
|
||||||
xml->writeTextElement("comments", metadata.comments);
|
xml->writeTextElement("comments", metadata.comments);
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QtCore/QXmlStreamReader>
|
#include <QtCore/QXmlStreamReader>
|
||||||
#include <libcockatrice/utility/card_ref.h>
|
#include <libcockatrice/utility/playmat_params.h>
|
||||||
|
|
||||||
class AbstractDecklistNode;
|
class AbstractDecklistNode;
|
||||||
class DecklistCardNode;
|
class DecklistCardNode;
|
||||||
|
|
@ -27,34 +27,6 @@ class QIODevice;
|
||||||
class QTextStream;
|
class QTextStream;
|
||||||
class InnerDecklistNode;
|
class InnerDecklistNode;
|
||||||
|
|
||||||
/**
|
|
||||||
* @struct PlaymatParams
|
|
||||||
* @ingroup Decks
|
|
||||||
* @brief Positioning parameters for a playmat card image.
|
|
||||||
*
|
|
||||||
* Controls how the cropped card art is positioned within the
|
|
||||||
* combined table+stack play area. The coordinate system is
|
|
||||||
* relative to the cropped art source image.
|
|
||||||
*/
|
|
||||||
struct PlaymatParams
|
|
||||||
{
|
|
||||||
double marginPctL = 0.07; ///< Left margin as fraction of card width (0.0–0.95).
|
|
||||||
double marginPctR = 0.07; ///< Right margin as fraction of card width (0.0–0.95).
|
|
||||||
double verticalOffset = 0.33; ///< Vertical position within card (0.0=top, 1.0=bottom).
|
|
||||||
double zoom = 1.0; ///< Scale factor (0.1–4.0).
|
|
||||||
|
|
||||||
bool operator==(const PlaymatParams &other) const
|
|
||||||
{
|
|
||||||
return qFuzzyCompare(marginPctL, other.marginPctL) && qFuzzyCompare(marginPctR, other.marginPctR) &&
|
|
||||||
qFuzzyCompare(verticalOffset, other.verticalOffset) && qFuzzyCompare(zoom, other.zoom);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const PlaymatParams &other) const
|
|
||||||
{
|
|
||||||
return !(*this == other);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class DeckList
|
* @class DeckList
|
||||||
* @ingroup Decks
|
* @ingroup Decks
|
||||||
|
|
@ -98,8 +70,7 @@ public:
|
||||||
CardRef bannerCard; ///< Optional representative card for the deck.
|
CardRef bannerCard; ///< Optional representative card for the deck.
|
||||||
QStringList tags; ///< User-defined tags for deck classification.
|
QStringList tags; ///< User-defined tags for deck classification.
|
||||||
QString lastLoadedTimestamp; ///< Timestamp string of last load.
|
QString lastLoadedTimestamp; ///< Timestamp string of last load.
|
||||||
CardRef playmatCard; ///< Optional card used as playmat background for table+stack zones.
|
PlaymatResolution playmat; ///< Optional playmat background for table+stack zones.
|
||||||
PlaymatParams playmatParams; ///< Positioning parameters for the playmat card image.
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Checks if all values (except for lastLoadedTimestamp) in the metadata is empty.
|
* @brief Checks if all values (except for lastLoadedTimestamp) in the metadata is empty.
|
||||||
|
|
@ -145,13 +116,9 @@ public:
|
||||||
{
|
{
|
||||||
metadata.bannerCard = _bannerCard;
|
metadata.bannerCard = _bannerCard;
|
||||||
}
|
}
|
||||||
void setPlaymatCard(const CardRef &_playmatCard = {})
|
void setPlaymat(const PlaymatResolution &_playmat = {})
|
||||||
{
|
{
|
||||||
metadata.playmatCard = _playmatCard;
|
metadata.playmat = _playmat;
|
||||||
}
|
|
||||||
void setPlaymatParams(const PlaymatParams &_playmatParams = {})
|
|
||||||
{
|
|
||||||
metadata.playmatParams = _playmatParams;
|
|
||||||
}
|
}
|
||||||
void setLastLoadedTimestamp(const QString &_lastLoadedTimestamp = QString())
|
void setLastLoadedTimestamp(const QString &_lastLoadedTimestamp = QString())
|
||||||
{
|
{
|
||||||
|
|
@ -208,13 +175,9 @@ public:
|
||||||
{
|
{
|
||||||
return metadata.bannerCard;
|
return metadata.bannerCard;
|
||||||
}
|
}
|
||||||
CardRef getPlaymatCard() const
|
PlaymatResolution getPlaymat() const
|
||||||
{
|
{
|
||||||
return metadata.playmatCard;
|
return metadata.playmat;
|
||||||
}
|
|
||||||
PlaymatParams getPlaymatParams() const
|
|
||||||
{
|
|
||||||
return metadata.playmatParams;
|
|
||||||
}
|
}
|
||||||
QString getLastLoadedTimestamp() const
|
QString getLastLoadedTimestamp() const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,15 @@ PlaymatResolution resolveEffectivePlaymat(const DeckList &deck,
|
||||||
const PlaymatResolution &force,
|
const PlaymatResolution &force,
|
||||||
const QList<PlaymatResolution> &fallbackList,
|
const QList<PlaymatResolution> &fallbackList,
|
||||||
PlaymatFallbackMode fallbackMode,
|
PlaymatFallbackMode fallbackMode,
|
||||||
int &rotationIndex)
|
int rotationIndex)
|
||||||
{
|
{
|
||||||
if (!force.card.isEmpty()) {
|
if (!force.card.isEmpty()) {
|
||||||
return force;
|
return force;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!deck.getPlaymatCard().isEmpty()) {
|
const PlaymatResolution &deckPlaymat = deck.getPlaymat();
|
||||||
return {deck.getPlaymatCard(), deck.getPlaymatParams()};
|
if (!deckPlaymat.card.isEmpty()) {
|
||||||
|
return deckPlaymat;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fallbackList.isEmpty()) {
|
if (fallbackList.isEmpty()) {
|
||||||
|
|
@ -24,7 +25,7 @@ PlaymatResolution resolveEffectivePlaymat(const DeckList &deck,
|
||||||
case PlaymatFallbackMode::Fixed:
|
case PlaymatFallbackMode::Fixed:
|
||||||
return fallbackList.first();
|
return fallbackList.first();
|
||||||
case PlaymatFallbackMode::RoundRobin:
|
case PlaymatFallbackMode::RoundRobin:
|
||||||
return fallbackList.at(rotationIndex++ % fallbackList.size());
|
return fallbackList.at(rotationIndex % fallbackList.size());
|
||||||
case PlaymatFallbackMode::Random:
|
case PlaymatFallbackMode::Random:
|
||||||
return fallbackList.at(QRandomGenerator::global()->bounded(fallbackList.size()));
|
return fallbackList.at(QRandomGenerator::global()->bounded(fallbackList.size()));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,22 +14,6 @@ enum class PlaymatFallbackMode
|
||||||
Random = 2 ///< Pick a random entry per resolution.
|
Random = 2 ///< Pick a random entry per resolution.
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @struct PlaymatResolution
|
|
||||||
* @ingroup Decks
|
|
||||||
* @brief A resolved playmat (card + positioning parameters).
|
|
||||||
*/
|
|
||||||
struct PlaymatResolution
|
|
||||||
{
|
|
||||||
CardRef card; ///< The card whose art is used as playmat.
|
|
||||||
PlaymatParams params; ///< Positioning parameters for the playmat card image.
|
|
||||||
|
|
||||||
bool operator==(const PlaymatResolution &other) const
|
|
||||||
{
|
|
||||||
return card == other.card && params == other.params;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Resolves the effective playmat for a deck per the resolution chain:
|
* @brief Resolves the effective playmat for a deck per the resolution chain:
|
||||||
* force override > deck-configured playmat > fallback list > none.
|
* force override > deck-configured playmat > fallback list > none.
|
||||||
|
|
@ -49,6 +33,6 @@ PlaymatResolution resolveEffectivePlaymat(const DeckList &deck,
|
||||||
const PlaymatResolution &force,
|
const PlaymatResolution &force,
|
||||||
const QList<PlaymatResolution> &fallbackList,
|
const QList<PlaymatResolution> &fallbackList,
|
||||||
PlaymatFallbackMode fallbackMode,
|
PlaymatFallbackMode fallbackMode,
|
||||||
int &rotationIndex);
|
int rotationIndex);
|
||||||
|
|
||||||
#endif // COCKATRICE_PLAYMAT_RESOLVER_H
|
#endif // COCKATRICE_PLAYMAT_RESOLVER_H
|
||||||
|
|
|
||||||
|
|
@ -30,4 +30,4 @@ add_library(libcockatrice_interfaces STATIC ${MOC_SOURCES})
|
||||||
|
|
||||||
target_include_directories(libcockatrice_interfaces PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(libcockatrice_interfaces PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
target_link_libraries(libcockatrice_interfaces PUBLIC ${QT_CORE_MODULE})
|
target_link_libraries(libcockatrice_interfaces PUBLIC libcockatrice_utility ${QT_CORE_MODULE})
|
||||||
|
|
|
||||||
|
|
@ -4,26 +4,7 @@
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
#include <libcockatrice/utility/playmat_params.h>
|
||||||
/**
|
|
||||||
* @struct StoredPlaymat
|
|
||||||
* @brief A user-level playmat entry as stored in the settings, independent of
|
|
||||||
* any deck. Mirrors a deck-configured playmat (card + parameters).
|
|
||||||
*/
|
|
||||||
struct StoredPlaymat
|
|
||||||
{
|
|
||||||
QString name; ///< Card name whose art is used as playmat.
|
|
||||||
QString providerId; ///< Printing provider id (uuid); may be empty.
|
|
||||||
double marginPctL = 0.07; ///< Left margin as fraction of card width (0.0-0.95).
|
|
||||||
double marginPctR = 0.07; ///< Right margin as fraction of card width (0.0-0.95).
|
|
||||||
double verticalOffset = 0.33; ///< Vertical position within card (0.0=top, 1.0=bottom).
|
|
||||||
double zoom = 1.0; ///< Scale factor (0.1-4.0).
|
|
||||||
|
|
||||||
bool isEmpty() const
|
|
||||||
{
|
|
||||||
return name.isEmpty();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class IInterfaceSettingsProvider
|
class IInterfaceSettingsProvider
|
||||||
{
|
{
|
||||||
|
|
@ -66,14 +47,16 @@ public:
|
||||||
[[nodiscard]] virtual QStringList getUserListExpandedSections() const = 0;
|
[[nodiscard]] virtual QStringList getUserListExpandedSections() const = 0;
|
||||||
[[nodiscard]] virtual int getPlaymatVisibility() const = 0;
|
[[nodiscard]] virtual int getPlaymatVisibility() const = 0;
|
||||||
|
|
||||||
/** @brief User-level fallback playmats, used when a deck has none configured. */
|
/** @brief User-level playmat collection. Used either as a forced playmat
|
||||||
[[nodiscard]] virtual QList<StoredPlaymat> getPlaymatFallbackList() const = 0;
|
* (mode == Always) or as a fallback when a deck has none (mode == Fallback). */
|
||||||
|
[[nodiscard]] virtual QList<PlaymatResolution> getPlaymatFallbackList() const = 0;
|
||||||
|
|
||||||
/** @brief User-level override playmat applied to all decks, or empty to disable. */
|
/** @brief How the fallback list is applied: Always (0), Fallback (1), Never (2). */
|
||||||
[[nodiscard]] virtual StoredPlaymat getPlaymatOverride() const = 0;
|
[[nodiscard]] virtual int getPlaymatMode() const = 0;
|
||||||
|
|
||||||
/** @brief How the fallback list is consulted (0 Fixed, 1 Round-robin, 2 Random). */
|
/** @brief How the fallback list is picked from when mode is Fallback
|
||||||
[[nodiscard]] virtual int getPlaymatFallbackMode() const = 0;
|
* (0 Fixed, 1 Round-robin, 2 Random). */
|
||||||
|
[[nodiscard]] virtual int getPlaymatFallbackBehavior() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // COCKATRICE_INTERFACE_INTERFACE_SETTINGS_PROVIDER_H
|
#endif // COCKATRICE_INTERFACE_INTERFACE_SETTINGS_PROVIDER_H
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@
|
||||||
#include <libcockatrice/protocol/pb/command_set_card_attr.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_card_counter.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_set_counter.pb.h>
|
#include <libcockatrice/protocol/pb/command_set_counter.pb.h>
|
||||||
|
#include <libcockatrice/protocol/pb/command_set_playmat.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_set_sideboard_lock.pb.h>
|
#include <libcockatrice/protocol/pb/command_set_sideboard_lock.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_set_sideboard_plan.pb.h>
|
#include <libcockatrice/protocol/pb/command_set_sideboard_plan.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_shuffle.pb.h>
|
#include <libcockatrice/protocol/pb/command_shuffle.pb.h>
|
||||||
|
|
@ -144,6 +145,13 @@ Response::ResponseCode Server_AbstractParticipant::cmdSetSideboardLock(const Com
|
||||||
return Response::RespFunctionNotAllowed;
|
return Response::RespFunctionNotAllowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Response::ResponseCode Server_AbstractParticipant::cmdSetPlaymat(const Command_SetPlaymat & /*cmd*/,
|
||||||
|
ResponseContainer & /*rc*/,
|
||||||
|
GameEventStorage & /*ges*/)
|
||||||
|
{
|
||||||
|
return Response::RespFunctionNotAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
Response::ResponseCode Server_AbstractParticipant::cmdConcede(const Command_Concede & /*cmd*/,
|
Response::ResponseCode Server_AbstractParticipant::cmdConcede(const Command_Concede & /*cmd*/,
|
||||||
ResponseContainer & /*rc*/,
|
ResponseContainer & /*rc*/,
|
||||||
GameEventStorage & /*ges*/)
|
GameEventStorage & /*ges*/)
|
||||||
|
|
@ -525,6 +533,9 @@ Server_AbstractParticipant::processGameCommand(const GameCommand &command, Respo
|
||||||
case GameCommand::REVERSE_TURN:
|
case GameCommand::REVERSE_TURN:
|
||||||
return cmdReverseTurn(command.GetExtension(Command_ReverseTurn::ext), rc, ges);
|
return cmdReverseTurn(command.GetExtension(Command_ReverseTurn::ext), rc, ges);
|
||||||
break;
|
break;
|
||||||
|
case GameCommand::SET_PLAYMAT:
|
||||||
|
return cmdSetPlaymat(command.GetExtension(Command_SetPlaymat::ext), rc, ges);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return Response::RespInvalidCommand;
|
return Response::RespInvalidCommand;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ class Command_SetSideboardPlan;
|
||||||
class Command_DeckSelect;
|
class Command_DeckSelect;
|
||||||
class Command_SetSideboardLock;
|
class Command_SetSideboardLock;
|
||||||
class Command_ChangeZoneProperties;
|
class Command_ChangeZoneProperties;
|
||||||
|
class Command_SetPlaymat;
|
||||||
|
|
||||||
class Server_AbstractParticipant : public Server_ArrowTarget, public ServerInfo_User_Container
|
class Server_AbstractParticipant : public Server_ArrowTarget, public ServerInfo_User_Container
|
||||||
{
|
{
|
||||||
|
|
@ -124,6 +125,8 @@ public:
|
||||||
cmdSetSideboardPlan(const Command_SetSideboardPlan &cmd, ResponseContainer &rc, GameEventStorage &ges);
|
cmdSetSideboardPlan(const Command_SetSideboardPlan &cmd, ResponseContainer &rc, GameEventStorage &ges);
|
||||||
virtual Response::ResponseCode
|
virtual Response::ResponseCode
|
||||||
cmdSetSideboardLock(const Command_SetSideboardLock &cmd, ResponseContainer &rc, GameEventStorage &ges);
|
cmdSetSideboardLock(const Command_SetSideboardLock &cmd, ResponseContainer &rc, GameEventStorage &ges);
|
||||||
|
virtual Response::ResponseCode
|
||||||
|
cmdSetPlaymat(const Command_SetPlaymat &cmd, ResponseContainer &rc, GameEventStorage &ges);
|
||||||
virtual Response::ResponseCode cmdGameSay(const Command_GameSay &cmd, ResponseContainer &rc, GameEventStorage &ges);
|
virtual Response::ResponseCode cmdGameSay(const Command_GameSay &cmd, ResponseContainer &rc, GameEventStorage &ges);
|
||||||
virtual Response::ResponseCode cmdShuffle(const Command_Shuffle &cmd, ResponseContainer &rc, GameEventStorage &ges);
|
virtual Response::ResponseCode cmdShuffle(const Command_Shuffle &cmd, ResponseContainer &rc, GameEventStorage &ges);
|
||||||
virtual Response::ResponseCode
|
virtual Response::ResponseCode
|
||||||
|
|
|
||||||
|
|
@ -1653,13 +1653,13 @@ void Server_AbstractPlayer::getPlayerProperties(ServerInfo_PlayerProperties &res
|
||||||
result.set_ready_start(readyStart);
|
result.set_ready_start(readyStart);
|
||||||
if (deck) {
|
if (deck) {
|
||||||
result.set_deck_hash(deck->getDeckHash().toStdString());
|
result.set_deck_hash(deck->getDeckHash().toStdString());
|
||||||
const auto &playmatCard = deck->getPlaymatCard();
|
const auto &playmat = deck->getPlaymat();
|
||||||
const auto ¶ms = deck->getPlaymatParams();
|
auto *playmatParams = result.mutable_playmat_params();
|
||||||
result.set_playmat_card_name(playmatCard.name.toStdString());
|
playmatParams->set_card_name(playmat.card.name.toStdString());
|
||||||
result.set_playmat_card_provider_id(playmatCard.providerId.toStdString());
|
playmatParams->set_card_provider_id(playmat.card.providerId.toStdString());
|
||||||
result.set_playmat_margin_pct_l(params.marginPctL);
|
playmatParams->set_margin_pct_l(playmat.params.marginPctL);
|
||||||
result.set_playmat_margin_pct_r(params.marginPctR);
|
playmatParams->set_margin_pct_r(playmat.params.marginPctR);
|
||||||
result.set_playmat_vertical_offset(params.verticalOffset);
|
playmatParams->set_vertical_offset(playmat.params.verticalOffset);
|
||||||
result.set_playmat_zoom(params.zoom);
|
playmatParams->set_zoom(playmat.params.zoom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include <libcockatrice/protocol/pb/command_mulligan.pb.h>
|
#include <libcockatrice/protocol/pb/command_mulligan.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_set_active_phase.pb.h>
|
#include <libcockatrice/protocol/pb/command_set_active_phase.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_set_counter.pb.h>
|
#include <libcockatrice/protocol/pb/command_set_counter.pb.h>
|
||||||
|
#include <libcockatrice/protocol/pb/command_set_playmat.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_set_sideboard_lock.pb.h>
|
#include <libcockatrice/protocol/pb/command_set_sideboard_lock.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_set_sideboard_plan.pb.h>
|
#include <libcockatrice/protocol/pb/command_set_sideboard_plan.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_shuffle.pb.h>
|
#include <libcockatrice/protocol/pb/command_shuffle.pb.h>
|
||||||
|
|
@ -250,14 +251,14 @@ Server_Player::cmdDeckSelect(const Command_DeckSelect &cmd, ResponseContainer &r
|
||||||
Event_PlayerPropertiesChanged event;
|
Event_PlayerPropertiesChanged event;
|
||||||
event.mutable_player_properties()->set_sideboard_locked(true);
|
event.mutable_player_properties()->set_sideboard_locked(true);
|
||||||
event.mutable_player_properties()->set_deck_hash(deck->getDeckHash().toStdString());
|
event.mutable_player_properties()->set_deck_hash(deck->getDeckHash().toStdString());
|
||||||
const auto &playmatCard = deck->getPlaymatCard();
|
const auto &playmat = deck->getPlaymat();
|
||||||
const auto ¶ms = deck->getPlaymatParams();
|
auto *playmatParams = event.mutable_player_properties()->mutable_playmat_params();
|
||||||
event.mutable_player_properties()->set_playmat_card_name(playmatCard.name.toStdString());
|
playmatParams->set_card_name(playmat.card.name.toStdString());
|
||||||
event.mutable_player_properties()->set_playmat_card_provider_id(playmatCard.providerId.toStdString());
|
playmatParams->set_card_provider_id(playmat.card.providerId.toStdString());
|
||||||
event.mutable_player_properties()->set_playmat_margin_pct_l(params.marginPctL);
|
playmatParams->set_margin_pct_l(playmat.params.marginPctL);
|
||||||
event.mutable_player_properties()->set_playmat_margin_pct_r(params.marginPctR);
|
playmatParams->set_margin_pct_r(playmat.params.marginPctR);
|
||||||
event.mutable_player_properties()->set_playmat_vertical_offset(params.verticalOffset);
|
playmatParams->set_vertical_offset(playmat.params.verticalOffset);
|
||||||
event.mutable_player_properties()->set_playmat_zoom(params.zoom);
|
playmatParams->set_zoom(playmat.params.zoom);
|
||||||
ges.enqueueGameEvent(event, playerId);
|
ges.enqueueGameEvent(event, playerId);
|
||||||
|
|
||||||
Context_DeckSelect context;
|
Context_DeckSelect context;
|
||||||
|
|
@ -602,6 +603,41 @@ Server_Player::cmdReverseTurn(const Command_ReverseTurn &cmd, ResponseContainer
|
||||||
return Server_AbstractParticipant::cmdReverseTurn(cmd, rc, ges);
|
return Server_AbstractParticipant::cmdReverseTurn(cmd, rc, ges);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Response::ResponseCode
|
||||||
|
Server_Player::cmdSetPlaymat(const Command_SetPlaymat &cmd, ResponseContainer &rc, GameEventStorage &ges)
|
||||||
|
{
|
||||||
|
Q_UNUSED(rc);
|
||||||
|
|
||||||
|
if (!deck) {
|
||||||
|
return Response::RespContextError;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &pp = cmd.playmat_params();
|
||||||
|
PlaymatResolution playmat;
|
||||||
|
playmat.card.name = QString::fromStdString(pp.card_name());
|
||||||
|
playmat.card.providerId = QString::fromStdString(pp.card_provider_id());
|
||||||
|
playmat.params.marginPctL = qBound(0.0, pp.margin_pct_l(), 0.95);
|
||||||
|
playmat.params.marginPctR = qBound(0.0, pp.margin_pct_r(), 0.95);
|
||||||
|
playmat.params.verticalOffset = qBound(0.0, pp.vertical_offset(), 1.0);
|
||||||
|
playmat.params.zoom = qBound(0.1, pp.zoom(), 4.0);
|
||||||
|
deck->setPlaymat(playmat);
|
||||||
|
|
||||||
|
Event_PlayerPropertiesChanged event;
|
||||||
|
auto *props = event.mutable_player_properties();
|
||||||
|
props->set_sideboard_locked(sideboardLocked);
|
||||||
|
props->set_deck_hash(deck->getDeckHash().toStdString());
|
||||||
|
auto *playmatParams = props->mutable_playmat_params();
|
||||||
|
playmatParams->set_card_name(playmat.card.name.toStdString());
|
||||||
|
playmatParams->set_card_provider_id(playmat.card.providerId.toStdString());
|
||||||
|
playmatParams->set_margin_pct_l(playmat.params.marginPctL);
|
||||||
|
playmatParams->set_margin_pct_r(playmat.params.marginPctR);
|
||||||
|
playmatParams->set_vertical_offset(playmat.params.verticalOffset);
|
||||||
|
playmatParams->set_zoom(playmat.params.zoom);
|
||||||
|
ges.enqueueGameEvent(event, playerId);
|
||||||
|
|
||||||
|
return Response::RespOk;
|
||||||
|
}
|
||||||
|
|
||||||
void Server_Player::getInfo(ServerInfo_Player *info,
|
void Server_Player::getInfo(ServerInfo_Player *info,
|
||||||
Server_AbstractParticipant *recipient,
|
Server_AbstractParticipant *recipient,
|
||||||
bool omniscient,
|
bool omniscient,
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,8 @@ public:
|
||||||
cmdSetActivePhase(const Command_SetActivePhase &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
|
cmdSetActivePhase(const Command_SetActivePhase &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
|
||||||
Response::ResponseCode
|
Response::ResponseCode
|
||||||
cmdReverseTurn(const Command_ReverseTurn & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage &ges) override;
|
cmdReverseTurn(const Command_ReverseTurn & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage &ges) override;
|
||||||
|
Response::ResponseCode
|
||||||
|
cmdSetPlaymat(const Command_SetPlaymat &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
|
||||||
Response::ResponseCode cmdChangeZoneProperties(const Command_ChangeZoneProperties &cmd,
|
Response::ResponseCode cmdChangeZoneProperties(const Command_ChangeZoneProperties &cmd,
|
||||||
ResponseContainer &rc,
|
ResponseContainer &rc,
|
||||||
GameEventStorage &ges) override;
|
GameEventStorage &ges) override;
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ set(PROTO_FILES
|
||||||
command_set_card_attr.proto
|
command_set_card_attr.proto
|
||||||
command_set_card_counter.proto
|
command_set_card_counter.proto
|
||||||
command_set_counter.proto
|
command_set_counter.proto
|
||||||
|
command_set_playmat.proto
|
||||||
command_set_sideboard_lock.proto
|
command_set_sideboard_lock.proto
|
||||||
command_set_sideboard_plan.proto
|
command_set_sideboard_plan.proto
|
||||||
command_shuffle.proto
|
command_shuffle.proto
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
syntax = "proto2";
|
||||||
|
import "game_commands.proto";
|
||||||
|
import "serverinfo_playerproperties.proto";
|
||||||
|
message Command_SetPlaymat {
|
||||||
|
extend GameCommand {
|
||||||
|
optional Command_SetPlaymat ext = 1035;
|
||||||
|
}
|
||||||
|
optional ServerInfo_PlayerProperties.PlaymatParams playmat_params = 1;
|
||||||
|
}
|
||||||
|
|
@ -175,6 +175,11 @@ message GameCommand {
|
||||||
/// Server: Server_Player::cmdReverseTurn
|
/// Server: Server_Player::cmdReverseTurn
|
||||||
/// Client: reflected via subsequent turn events
|
/// Client: reflected via subsequent turn events
|
||||||
REVERSE_TURN = 1034;
|
REVERSE_TURN = 1034;
|
||||||
|
|
||||||
|
/// Set the player's playmat independently of the deck.
|
||||||
|
/// Server: Server_Player::cmdSetPlaymat
|
||||||
|
/// Client: reflected via player properties changed event
|
||||||
|
SET_PLAYMAT = 1035;
|
||||||
}
|
}
|
||||||
|
|
||||||
extensions 100 to max;
|
extensions 100 to max;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,15 @@ syntax = "proto2";
|
||||||
import "serverinfo_user.proto";
|
import "serverinfo_user.proto";
|
||||||
|
|
||||||
message ServerInfo_PlayerProperties {
|
message ServerInfo_PlayerProperties {
|
||||||
|
message PlaymatParams {
|
||||||
|
optional string card_name = 1;
|
||||||
|
optional string card_provider_id = 2;
|
||||||
|
optional double margin_pct_l = 3 [default = 0.07];
|
||||||
|
optional double margin_pct_r = 4 [default = 0.07];
|
||||||
|
optional double vertical_offset = 5 [default = 0.33];
|
||||||
|
optional double zoom = 6 [default = 1.0];
|
||||||
|
}
|
||||||
|
|
||||||
optional sint32 player_id = 1;
|
optional sint32 player_id = 1;
|
||||||
optional ServerInfo_User user_info = 2;
|
optional ServerInfo_User user_info = 2;
|
||||||
optional bool spectator = 3;
|
optional bool spectator = 3;
|
||||||
|
|
@ -11,10 +20,5 @@ message ServerInfo_PlayerProperties {
|
||||||
optional sint32 ping_seconds = 7;
|
optional sint32 ping_seconds = 7;
|
||||||
optional bool sideboard_locked = 8;
|
optional bool sideboard_locked = 8;
|
||||||
optional bool judge = 9;
|
optional bool judge = 9;
|
||||||
optional string playmat_card_name = 10;
|
optional PlaymatParams playmat_params = 10;
|
||||||
optional string playmat_card_provider_id = 11;
|
|
||||||
optional double playmat_margin_pct_l = 12 [default = 0.07];
|
|
||||||
optional double playmat_margin_pct_r = 13 [default = 0.07];
|
|
||||||
optional double playmat_vertical_offset = 14 [default = 0.33];
|
|
||||||
optional double playmat_zoom = 15 [default = 1.0];
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,30 +2,31 @@
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
const QChar PLAYMAT_FIELD_SEP = QChar(0x1F); ///< Separator between StoredPlaymat fields.
|
const QChar PLAYMAT_FIELD_SEP = QChar(0x1F); ///< Separator between PlaymatResolution fields.
|
||||||
|
|
||||||
QString encodeStoredPlaymat(const StoredPlaymat &stored)
|
QString encodePlaymatResolution(const PlaymatResolution &res)
|
||||||
{
|
{
|
||||||
return stored.name + PLAYMAT_FIELD_SEP + stored.providerId + PLAYMAT_FIELD_SEP +
|
return res.card.name + PLAYMAT_FIELD_SEP + res.card.providerId + PLAYMAT_FIELD_SEP +
|
||||||
QString::number(stored.marginPctL, 'f', 4) + PLAYMAT_FIELD_SEP + QString::number(stored.marginPctR, 'f', 4) +
|
QString::number(res.params.marginPctL, 'f', 4) + PLAYMAT_FIELD_SEP +
|
||||||
PLAYMAT_FIELD_SEP + QString::number(stored.verticalOffset, 'f', 4) + PLAYMAT_FIELD_SEP +
|
QString::number(res.params.marginPctR, 'f', 4) + PLAYMAT_FIELD_SEP +
|
||||||
QString::number(stored.zoom, 'f', 4);
|
QString::number(res.params.verticalOffset, 'f', 4) + PLAYMAT_FIELD_SEP +
|
||||||
|
QString::number(res.params.zoom, 'f', 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
StoredPlaymat decodeStoredPlaymat(const QString &encoded)
|
PlaymatResolution decodePlaymatResolution(const QString &encoded)
|
||||||
{
|
{
|
||||||
const QStringList fields = encoded.split(PLAYMAT_FIELD_SEP);
|
const QStringList fields = encoded.split(PLAYMAT_FIELD_SEP);
|
||||||
if (fields.size() != 6) {
|
if (fields.size() != 6) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
StoredPlaymat stored;
|
PlaymatResolution res;
|
||||||
stored.name = fields.at(0);
|
res.card.name = fields.at(0);
|
||||||
stored.providerId = fields.at(1);
|
res.card.providerId = fields.at(1);
|
||||||
stored.marginPctL = fields.at(2).toDouble();
|
res.params.marginPctL = fields.at(2).toDouble();
|
||||||
stored.marginPctR = fields.at(3).toDouble();
|
res.params.marginPctR = fields.at(3).toDouble();
|
||||||
stored.verticalOffset = fields.at(4).toDouble();
|
res.params.verticalOffset = fields.at(4).toDouble();
|
||||||
stored.zoom = fields.at(5).toDouble();
|
res.params.zoom = fields.at(5).toDouble();
|
||||||
return stored;
|
return res;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
@ -194,28 +195,28 @@ int InterfaceSettings::getPlaymatVisibility() const
|
||||||
return getValue("playmatvisibility", QString(), QString(), 2).toInt();
|
return getValue("playmatvisibility", QString(), QString(), 2).toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<StoredPlaymat> InterfaceSettings::getPlaymatFallbackList() const
|
QList<PlaymatResolution> InterfaceSettings::getPlaymatFallbackList() const
|
||||||
{
|
{
|
||||||
const QStringList entries = getValue("playmatFallbackList", QString(), QString(), QStringList()).toStringList();
|
const QStringList entries = getValue("playmatFallbackList", QString(), QString(), QStringList()).toStringList();
|
||||||
QList<StoredPlaymat> result;
|
QList<PlaymatResolution> result;
|
||||||
result.reserve(entries.size());
|
result.reserve(entries.size());
|
||||||
for (const QString &entry : entries) {
|
for (const QString &entry : entries) {
|
||||||
const StoredPlaymat stored = decodeStoredPlaymat(entry);
|
const PlaymatResolution res = decodePlaymatResolution(entry);
|
||||||
if (!stored.isEmpty()) {
|
if (!res.card.isEmpty()) {
|
||||||
result.append(stored);
|
result.append(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
StoredPlaymat InterfaceSettings::getPlaymatOverride() const
|
int InterfaceSettings::getPlaymatMode() const
|
||||||
{
|
{
|
||||||
return decodeStoredPlaymat(getValue("playmatOverride", QString(), QString(), QString()).toString());
|
return qBound(0, getValue("playmatMode", QString(), QString(), 1).toInt(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
int InterfaceSettings::getPlaymatFallbackMode() const
|
int InterfaceSettings::getPlaymatFallbackBehavior() const
|
||||||
{
|
{
|
||||||
return qBound(0, getValue("playmatFallbackMode", QString(), QString(), 1).toInt(), 2);
|
return qBound(0, getValue("playmatFallbackBehavior", QString(), QString(), 0).toInt(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InterfaceSettings::getLifeCounterAnimationsEnabled() const
|
bool InterfaceSettings::getLifeCounterAnimationsEnabled() const
|
||||||
|
|
@ -410,30 +411,34 @@ void InterfaceSettings::setPlaymatVisibility(int _visibility)
|
||||||
emit playmatVisibilityChanged(_visibility);
|
emit playmatVisibilityChanged(_visibility);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InterfaceSettings::setPlaymatFallbackList(const QList<StoredPlaymat> &_fallbackList)
|
void InterfaceSettings::setPlaymatFallbackList(const QList<PlaymatResolution> &_fallbackList)
|
||||||
{
|
{
|
||||||
QStringList entries;
|
QStringList entries;
|
||||||
entries.reserve(_fallbackList.size());
|
entries.reserve(_fallbackList.size());
|
||||||
for (const StoredPlaymat &stored : _fallbackList) {
|
for (const PlaymatResolution &res : _fallbackList) {
|
||||||
entries.append(encodeStoredPlaymat(stored));
|
entries.append(encodePlaymatResolution(res));
|
||||||
}
|
}
|
||||||
setValue(entries, "playmatFallbackList");
|
setValue(entries, "playmatFallbackList");
|
||||||
emit playmatSettingsChanged();
|
emit playmatSettingsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InterfaceSettings::setPlaymatOverride(const StoredPlaymat &_override)
|
void InterfaceSettings::setPlaymatMode(int _mode)
|
||||||
{
|
{
|
||||||
setValue(_override.isEmpty() ? QString() : encodeStoredPlaymat(_override), "playmatOverride");
|
const int mode = qBound(0, _mode, 2);
|
||||||
|
if (getPlaymatMode() == mode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setValue(mode, "playmatMode");
|
||||||
emit playmatSettingsChanged();
|
emit playmatSettingsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InterfaceSettings::setPlaymatFallbackMode(int _fallbackMode)
|
void InterfaceSettings::setPlaymatFallbackBehavior(int _behavior)
|
||||||
{
|
{
|
||||||
const int mode = qBound(0, _fallbackMode, 2);
|
const int behavior = qBound(0, _behavior, 2);
|
||||||
if (getPlaymatFallbackMode() == mode) {
|
if (getPlaymatFallbackBehavior() == behavior) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setValue(mode, "playmatFallbackMode");
|
setValue(behavior, "playmatFallbackBehavior");
|
||||||
emit playmatSettingsChanged();
|
emit playmatSettingsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,9 +43,9 @@ public:
|
||||||
[[nodiscard]] bool getShowShortcuts() const override;
|
[[nodiscard]] bool getShowShortcuts() const override;
|
||||||
[[nodiscard]] bool getShowGameSelectorFilterToolbar() const override;
|
[[nodiscard]] bool getShowGameSelectorFilterToolbar() const override;
|
||||||
[[nodiscard]] int getPlaymatVisibility() const override;
|
[[nodiscard]] int getPlaymatVisibility() const override;
|
||||||
[[nodiscard]] QList<StoredPlaymat> getPlaymatFallbackList() const override;
|
[[nodiscard]] QList<PlaymatResolution> getPlaymatFallbackList() const override;
|
||||||
[[nodiscard]] StoredPlaymat getPlaymatOverride() const override;
|
[[nodiscard]] int getPlaymatMode() const override;
|
||||||
[[nodiscard]] int getPlaymatFallbackMode() const override;
|
[[nodiscard]] int getPlaymatFallbackBehavior() const override;
|
||||||
[[nodiscard]] bool getLifeCounterAnimationsEnabled() const override;
|
[[nodiscard]] bool getLifeCounterAnimationsEnabled() const override;
|
||||||
[[nodiscard]] bool getBattlefieldFlashEnabled() const override;
|
[[nodiscard]] bool getBattlefieldFlashEnabled() const override;
|
||||||
[[nodiscard]] QStringList getUserListExpandedSections() const override;
|
[[nodiscard]] QStringList getUserListExpandedSections() const override;
|
||||||
|
|
@ -82,9 +82,9 @@ public:
|
||||||
void setShowShortcuts(bool _showShortcuts);
|
void setShowShortcuts(bool _showShortcuts);
|
||||||
void setShowGameSelectorFilterToolbar(bool _showGameSelectorFilterToolbar);
|
void setShowGameSelectorFilterToolbar(bool _showGameSelectorFilterToolbar);
|
||||||
void setPlaymatVisibility(int _visibility);
|
void setPlaymatVisibility(int _visibility);
|
||||||
void setPlaymatFallbackList(const QList<StoredPlaymat> &_fallbackList);
|
void setPlaymatFallbackList(const QList<PlaymatResolution> &_fallbackList);
|
||||||
void setPlaymatOverride(const StoredPlaymat &_override);
|
void setPlaymatMode(int _mode);
|
||||||
void setPlaymatFallbackMode(int _fallbackMode);
|
void setPlaymatFallbackBehavior(int _behavior);
|
||||||
void setLifeCounterAnimationsEnabled(bool _lifeCounterAnimationsEnabled);
|
void setLifeCounterAnimationsEnabled(bool _lifeCounterAnimationsEnabled);
|
||||||
void setBattlefieldFlashEnabled(bool _battlefieldFlashEnabled);
|
void setBattlefieldFlashEnabled(bool _battlefieldFlashEnabled);
|
||||||
void setUserListExpandedSections(const QStringList §ions);
|
void setUserListExpandedSections(const QStringList §ions);
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,13 @@ set(UTILITY_SOURCES libcockatrice/utility/expression.cpp libcockatrice/utility/l
|
||||||
)
|
)
|
||||||
|
|
||||||
set(UTILITY_HEADERS
|
set(UTILITY_HEADERS
|
||||||
|
libcockatrice/utility/card_ref.h
|
||||||
libcockatrice/utility/color.h
|
libcockatrice/utility/color.h
|
||||||
libcockatrice/utility/expression.h
|
libcockatrice/utility/expression.h
|
||||||
libcockatrice/utility/levenshtein.h
|
libcockatrice/utility/levenshtein.h
|
||||||
libcockatrice/utility/macros.h
|
libcockatrice/utility/macros.h
|
||||||
libcockatrice/utility/passwordhasher.h
|
libcockatrice/utility/passwordhasher.h
|
||||||
|
libcockatrice/utility/playmat_params.h
|
||||||
libcockatrice/utility/string_limits.h
|
libcockatrice/utility/string_limits.h
|
||||||
libcockatrice/utility/dice_limits.h
|
libcockatrice/utility/dice_limits.h
|
||||||
libcockatrice/utility/counter_limits.h
|
libcockatrice/utility/counter_limits.h
|
||||||
|
|
|
||||||
52
libcockatrice_utility/libcockatrice/utility/playmat_params.h
Normal file
52
libcockatrice_utility/libcockatrice/utility/playmat_params.h
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
#ifndef COCKATRICE_PLAYMAT_PARAMS_H
|
||||||
|
#define COCKATRICE_PLAYMAT_PARAMS_H
|
||||||
|
|
||||||
|
#include "card_ref.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct PlaymatParams
|
||||||
|
* @ingroup Decks
|
||||||
|
* @brief Positioning parameters for a playmat card image.
|
||||||
|
*
|
||||||
|
* Controls how the cropped card art is positioned within the
|
||||||
|
* combined table+stack play area. The coordinate system is
|
||||||
|
* relative to the cropped art source image.
|
||||||
|
*/
|
||||||
|
struct PlaymatParams
|
||||||
|
{
|
||||||
|
double marginPctL = 0.07; ///< Left margin as fraction of card width (0.0–0.95).
|
||||||
|
double marginPctR = 0.07; ///< Right margin as fraction of card width (0.0–0.95).
|
||||||
|
double verticalOffset = 0.33; ///< Vertical position within card (0.0=top, 1.0=bottom).
|
||||||
|
double zoom = 1.0; ///< Scale factor (0.1–4.0).
|
||||||
|
|
||||||
|
bool operator==(const PlaymatParams &other) const
|
||||||
|
{
|
||||||
|
return qFuzzyCompare(marginPctL, other.marginPctL) && qFuzzyCompare(marginPctR, other.marginPctR) &&
|
||||||
|
qFuzzyCompare(verticalOffset, other.verticalOffset) && qFuzzyCompare(zoom, other.zoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const PlaymatParams &other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct PlaymatResolution
|
||||||
|
* @ingroup Decks
|
||||||
|
* @brief A resolved playmat (card + positioning parameters).
|
||||||
|
*/
|
||||||
|
struct PlaymatResolution
|
||||||
|
{
|
||||||
|
CardRef card; ///< The card whose art is used as playmat.
|
||||||
|
PlaymatParams params; ///< Positioning parameters for the playmat card image.
|
||||||
|
|
||||||
|
bool operator==(const PlaymatResolution &other) const
|
||||||
|
{
|
||||||
|
return card == other.card && params == other.params;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COCKATRICE_PLAYMAT_PARAMS_H
|
||||||
|
|
@ -17,22 +17,19 @@ PlaymatResolution makeResolution(const QString &name, const QString &providerId
|
||||||
TEST(PlaymatResolverTest, EmptyChainReturnsEmpty)
|
TEST(PlaymatResolverTest, EmptyChainReturnsEmpty)
|
||||||
{
|
{
|
||||||
DeckList deck;
|
DeckList deck;
|
||||||
int rotationIndex = 0;
|
const PlaymatResolution resolved = resolveEffectivePlaymat(deck, {}, {}, PlaymatFallbackMode::Fixed, 0);
|
||||||
const PlaymatResolution resolved = resolveEffectivePlaymat(deck, {}, {}, PlaymatFallbackMode::Fixed, rotationIndex);
|
|
||||||
EXPECT_TRUE(resolved.card.isEmpty());
|
EXPECT_TRUE(resolved.card.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PlaymatResolverTest, OverrideWinsOverDeckAndFallback)
|
TEST(PlaymatResolverTest, OverrideWinsOverDeckAndFallback)
|
||||||
{
|
{
|
||||||
DeckList deck;
|
DeckList deck;
|
||||||
deck.setPlaymatCard({QStringLiteral("Deck Mat"), QStringLiteral("deck-provider")});
|
deck.setPlaymat({{QStringLiteral("Deck Mat"), QStringLiteral("deck-provider")}, {}});
|
||||||
|
|
||||||
const PlaymatResolution force = makeResolution(QStringLiteral("Force Mat"), QStringLiteral("force-provider"));
|
const PlaymatResolution force = makeResolution(QStringLiteral("Force Mat"), QStringLiteral("force-provider"));
|
||||||
const QList<PlaymatResolution> fallback = {makeResolution(QStringLiteral("Fallback Mat"))};
|
const QList<PlaymatResolution> fallback = {makeResolution(QStringLiteral("Fallback Mat"))};
|
||||||
|
|
||||||
int rotationIndex = 0;
|
const PlaymatResolution resolved = resolveEffectivePlaymat(deck, force, fallback, PlaymatFallbackMode::Fixed, 0);
|
||||||
const PlaymatResolution resolved =
|
|
||||||
resolveEffectivePlaymat(deck, force, fallback, PlaymatFallbackMode::Fixed, rotationIndex);
|
|
||||||
EXPECT_EQ(resolved.card.name, QStringLiteral("Force Mat"));
|
EXPECT_EQ(resolved.card.name, QStringLiteral("Force Mat"));
|
||||||
EXPECT_EQ(resolved.card.providerId, QStringLiteral("force-provider"));
|
EXPECT_EQ(resolved.card.providerId, QStringLiteral("force-provider"));
|
||||||
}
|
}
|
||||||
|
|
@ -40,14 +37,11 @@ TEST(PlaymatResolverTest, OverrideWinsOverDeckAndFallback)
|
||||||
TEST(PlaymatResolverTest, DeckWinsOverFallback)
|
TEST(PlaymatResolverTest, DeckWinsOverFallback)
|
||||||
{
|
{
|
||||||
DeckList deck;
|
DeckList deck;
|
||||||
deck.setPlaymatCard({QStringLiteral("Deck Mat"), QStringLiteral("deck-provider")});
|
deck.setPlaymat({{QStringLiteral("Deck Mat"), QStringLiteral("deck-provider")}, {0.1, 0.2, 0.3, 1.5}});
|
||||||
deck.setPlaymatParams({0.1, 0.2, 0.3, 1.5});
|
|
||||||
|
|
||||||
const QList<PlaymatResolution> fallback = {makeResolution(QStringLiteral("Fallback Mat"))};
|
const QList<PlaymatResolution> fallback = {makeResolution(QStringLiteral("Fallback Mat"))};
|
||||||
|
|
||||||
int rotationIndex = 0;
|
const PlaymatResolution resolved = resolveEffectivePlaymat(deck, {}, fallback, PlaymatFallbackMode::Fixed, 0);
|
||||||
const PlaymatResolution resolved =
|
|
||||||
resolveEffectivePlaymat(deck, {}, fallback, PlaymatFallbackMode::Fixed, rotationIndex);
|
|
||||||
EXPECT_EQ(resolved.card.name, QStringLiteral("Deck Mat"));
|
EXPECT_EQ(resolved.card.name, QStringLiteral("Deck Mat"));
|
||||||
EXPECT_EQ(resolved.card.providerId, QStringLiteral("deck-provider"));
|
EXPECT_EQ(resolved.card.providerId, QStringLiteral("deck-provider"));
|
||||||
EXPECT_DOUBLE_EQ(resolved.params.marginPctL, 0.1);
|
EXPECT_DOUBLE_EQ(resolved.params.marginPctL, 0.1);
|
||||||
|
|
@ -59,9 +53,7 @@ TEST(PlaymatResolverTest, FallbackUsedWhenDeckHasNone)
|
||||||
DeckList deck;
|
DeckList deck;
|
||||||
const QList<PlaymatResolution> fallback = {makeResolution(QStringLiteral("Fallback Mat"))};
|
const QList<PlaymatResolution> fallback = {makeResolution(QStringLiteral("Fallback Mat"))};
|
||||||
|
|
||||||
int rotationIndex = 0;
|
const PlaymatResolution resolved = resolveEffectivePlaymat(deck, {}, fallback, PlaymatFallbackMode::Fixed, 0);
|
||||||
const PlaymatResolution resolved =
|
|
||||||
resolveEffectivePlaymat(deck, {}, fallback, PlaymatFallbackMode::Fixed, rotationIndex);
|
|
||||||
EXPECT_EQ(resolved.card.name, QStringLiteral("Fallback Mat"));
|
EXPECT_EQ(resolved.card.name, QStringLiteral("Fallback Mat"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,10 +63,8 @@ TEST(PlaymatResolverTest, FixedAlwaysUsesFirst)
|
||||||
const QList<PlaymatResolution> fallback = {makeResolution(QStringLiteral("First")),
|
const QList<PlaymatResolution> fallback = {makeResolution(QStringLiteral("First")),
|
||||||
makeResolution(QStringLiteral("Second"))};
|
makeResolution(QStringLiteral("Second"))};
|
||||||
|
|
||||||
int rotationIndex = 3; // ignored in Fixed mode
|
|
||||||
for (int i = 0; i < 5; ++i) {
|
for (int i = 0; i < 5; ++i) {
|
||||||
const PlaymatResolution resolved =
|
const PlaymatResolution resolved = resolveEffectivePlaymat(deck, {}, fallback, PlaymatFallbackMode::Fixed, i);
|
||||||
resolveEffectivePlaymat(deck, {}, fallback, PlaymatFallbackMode::Fixed, rotationIndex);
|
|
||||||
EXPECT_EQ(resolved.card.name, QStringLiteral("First"));
|
EXPECT_EQ(resolved.card.name, QStringLiteral("First"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -86,28 +76,23 @@ TEST(PlaymatResolverTest, RoundRobinCyclesAndWraps)
|
||||||
makeResolution(QStringLiteral("Second")),
|
makeResolution(QStringLiteral("Second")),
|
||||||
makeResolution(QStringLiteral("Third"))};
|
makeResolution(QStringLiteral("Third"))};
|
||||||
|
|
||||||
int rotationIndex = 0;
|
|
||||||
const QStringList expected = {QStringLiteral("First"), QStringLiteral("Second"), QStringLiteral("Third"),
|
const QStringList expected = {QStringLiteral("First"), QStringLiteral("Second"), QStringLiteral("Third"),
|
||||||
QStringLiteral("First"), QStringLiteral("Second"), QStringLiteral("Third")};
|
QStringLiteral("First"), QStringLiteral("Second"), QStringLiteral("Third")};
|
||||||
for (const QString &name : expected) {
|
for (int i = 0; i < expected.size(); ++i) {
|
||||||
const PlaymatResolution resolved =
|
const PlaymatResolution resolved =
|
||||||
resolveEffectivePlaymat(deck, {}, fallback, PlaymatFallbackMode::RoundRobin, rotationIndex);
|
resolveEffectivePlaymat(deck, {}, fallback, PlaymatFallbackMode::RoundRobin, i);
|
||||||
EXPECT_EQ(resolved.card.name, name);
|
EXPECT_EQ(resolved.card.name, expected.at(i));
|
||||||
}
|
}
|
||||||
EXPECT_EQ(rotationIndex, expected.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PlaymatResolverTest, RoundRobinRespectsExistingCursor)
|
TEST(PlaymatResolverTest, RoundRobinRespectsCursor)
|
||||||
{
|
{
|
||||||
DeckList deck;
|
DeckList deck;
|
||||||
const QList<PlaymatResolution> fallback = {makeResolution(QStringLiteral("First")),
|
const QList<PlaymatResolution> fallback = {makeResolution(QStringLiteral("First")),
|
||||||
makeResolution(QStringLiteral("Second"))};
|
makeResolution(QStringLiteral("Second"))};
|
||||||
|
|
||||||
int rotationIndex = 5;
|
const PlaymatResolution resolved = resolveEffectivePlaymat(deck, {}, fallback, PlaymatFallbackMode::RoundRobin, 5);
|
||||||
const PlaymatResolution resolved =
|
|
||||||
resolveEffectivePlaymat(deck, {}, fallback, PlaymatFallbackMode::RoundRobin, rotationIndex);
|
|
||||||
EXPECT_EQ(resolved.card.name, QStringLiteral("Second")); // 5 % 2 == 1
|
EXPECT_EQ(resolved.card.name, QStringLiteral("Second")); // 5 % 2 == 1
|
||||||
EXPECT_EQ(rotationIndex, 6);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PlaymatResolverTest, RandomStaysWithinList)
|
TEST(PlaymatResolverTest, RandomStaysWithinList)
|
||||||
|
|
@ -117,10 +102,8 @@ TEST(PlaymatResolverTest, RandomStaysWithinList)
|
||||||
makeResolution(QStringLiteral("Second")),
|
makeResolution(QStringLiteral("Second")),
|
||||||
makeResolution(QStringLiteral("Third"))};
|
makeResolution(QStringLiteral("Third"))};
|
||||||
|
|
||||||
int rotationIndex = 0;
|
|
||||||
for (int i = 0; i < 50; ++i) {
|
for (int i = 0; i < 50; ++i) {
|
||||||
const PlaymatResolution resolved =
|
const PlaymatResolution resolved = resolveEffectivePlaymat(deck, {}, fallback, PlaymatFallbackMode::Random, i);
|
||||||
resolveEffectivePlaymat(deck, {}, fallback, PlaymatFallbackMode::Random, rotationIndex);
|
|
||||||
ASSERT_FALSE(resolved.card.name.isEmpty());
|
ASSERT_FALSE(resolved.card.name.isEmpty());
|
||||||
EXPECT_TRUE(fallback.contains(resolved));
|
EXPECT_TRUE(fallback.contains(resolved));
|
||||||
}
|
}
|
||||||
|
|
@ -129,13 +112,11 @@ TEST(PlaymatResolverTest, RandomStaysWithinList)
|
||||||
TEST(PlaymatResolverTest, ForceWithEmptyCardIgnoresFallbackParamsButNotFallback)
|
TEST(PlaymatResolverTest, ForceWithEmptyCardIgnoresFallbackParamsButNotFallback)
|
||||||
{
|
{
|
||||||
DeckList deck;
|
DeckList deck;
|
||||||
deck.setPlaymatCard({QStringLiteral("Deck Mat")});
|
deck.setPlaymat({{QStringLiteral("Deck Mat")}, {}});
|
||||||
|
|
||||||
// An empty force entry must not mask the deck-configured playmat.
|
// An empty force entry must not mask the deck-configured playmat.
|
||||||
const PlaymatResolution emptyForce;
|
const PlaymatResolution emptyForce;
|
||||||
int rotationIndex = 0;
|
const PlaymatResolution resolved = resolveEffectivePlaymat(deck, emptyForce, {}, PlaymatFallbackMode::Fixed, 0);
|
||||||
const PlaymatResolution resolved =
|
|
||||||
resolveEffectivePlaymat(deck, emptyForce, {}, PlaymatFallbackMode::Fixed, rotationIndex);
|
|
||||||
EXPECT_EQ(resolved.card.name, QStringLiteral("Deck Mat"));
|
EXPECT_EQ(resolved.card.name, QStringLiteral("Deck Mat"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue