diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml
index 3c8e915a8..aeed5da81 100644
--- a/.github/workflows/desktop-build.yml
+++ b/.github/workflows/desktop-build.yml
@@ -46,7 +46,7 @@ concurrency:
jobs:
configure:
name: Configure
- runs-on: ubuntu-slim
+ runs-on: ubuntu-latest
outputs:
tag: ${{steps.configure.outputs.tag}}
sha: ${{steps.configure.outputs.sha}}
diff --git a/.github/workflows/desktop-lint.yml b/.github/workflows/desktop-lint.yml
index fe7be0287..433f302a5 100644
--- a/.github/workflows/desktop-lint.yml
+++ b/.github/workflows/desktop-lint.yml
@@ -20,13 +20,13 @@ on:
jobs:
format:
- runs-on: ubuntu-slim
+ runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v6
with:
- fetch-depth: 20 # should be enough to find merge base
+ fetch-depth: 20 # should be enough to find merge base
- name: Install dependencies
shell: bash
diff --git a/.github/workflows/translations-pull.yml b/.github/workflows/translations-pull.yml
index ca9069192..ed61e3b19 100644
--- a/.github/workflows/translations-pull.yml
+++ b/.github/workflows/translations-pull.yml
@@ -16,7 +16,7 @@ jobs:
if: github.event_name != 'schedule' || github.repository_owner == 'Cockatrice'
name: Pull languages
- runs-on: ubuntu-slim
+ runs-on: ubuntu-latest
steps:
- name: Checkout repo
diff --git a/.github/workflows/translations-push.yml b/.github/workflows/translations-push.yml
index e926a58ed..777e9e6ac 100644
--- a/.github/workflows/translations-push.yml
+++ b/.github/workflows/translations-push.yml
@@ -16,7 +16,7 @@ jobs:
if: github.event_name != 'schedule' || github.repository_owner == 'Cockatrice'
name: Push strings
- runs-on: ubuntu-slim
+ runs-on: ubuntu-latest
steps:
- name: Checkout repo
@@ -46,7 +46,7 @@ jobs:
- name: Render template
id: template
- uses: chuhlomin/render-template/binary@v1
+ uses: chuhlomin/render-template@v1
with:
template: .ci/update_translation_source_strings_template.md
vars: |
diff --git a/.github/workflows/web-lint.yml b/.github/workflows/web-lint.yml
index ecc6d14d1..8a90325e7 100644
--- a/.github/workflows/web-lint.yml
+++ b/.github/workflows/web-lint.yml
@@ -10,7 +10,7 @@ on:
jobs:
ESLint:
- runs-on: ubuntu-slim
+ runs-on: ubuntu-latest
defaults:
run:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4a5e944c4..fe808a652 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -74,11 +74,11 @@ endif()
# A project name is needed for CPack
# Version can be overriden by git tags, see cmake/getversion.cmake
-project("Cockatrice" VERSION 3.0.0)
+project("Cockatrice" VERSION 2.11.0)
# Set release name if not provided via env/cmake var
if(NOT DEFINED GIT_TAG_RELEASENAME)
- set(GIT_TAG_RELEASENAME "Graduation Day")
+ set(GIT_TAG_RELEASENAME "Omenpath")
endif()
# Use c++20 for all targets
diff --git a/cmake/NSIS.template.in b/cmake/NSIS.template.in
index 7b52b7bcc..2fdc61fb9 100644
--- a/cmake/NSIS.template.in
+++ b/cmake/NSIS.template.in
@@ -11,7 +11,6 @@ SetCompressor LZMA
Var NormalDestDir
Var PortableDestDir
Var PortableMode
-Var ReinstallMode
!include LogicLib.nsh
!include FileFunc.nsh
@@ -29,23 +28,13 @@ Var ReinstallMode
!define MUI_FINISHPAGE_RUN_TEXT "Run 'Cockatrice' now"
!define MUI_ICON "${NSIS_SOURCE_PATH}\cockatrice\resources\appicon.ico"
-!define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfReinstall
!insertmacro MUI_PAGE_WELCOME
-
-!define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfReinstall
!insertmacro MUI_PAGE_LICENSE "${NSIS_SOURCE_PATH}\LICENSE"
-
Page Custom PortableModePageCreate PortableModePageLeave
!define MUI_PAGE_CUSTOMFUNCTION_PRE componentsPagePre
!insertmacro MUI_PAGE_COMPONENTS
-
-!define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfReinstall
!insertmacro MUI_PAGE_DIRECTORY
-
-!define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfReinstall
!insertmacro MUI_PAGE_INSTFILES
-
-!define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfReinstall
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_UNPAGE_CONFIRM
@@ -84,7 +73,6 @@ ${IfNot} ${Errors}
MessageBox MB_ICONINFORMATION|MB_SETFOREGROUND "\
/PORTABLE : Install in portable mode$\n\
/S : Silent install$\n\
- /R : Silent upgrade$\n\
/D=%directory% : Specify destination directory$\n"
Quit
${EndIf}
@@ -102,16 +90,6 @@ ${Else}
${EndIf}
${EndIf}
-ClearErrors
-${GetOptions} $9 "/R" $8
-${IfNot} ${Errors}
- StrCpy $ReinstallMode 1
- SetSilent silent
- SetAutoClose true
-${Else}
- StrCpy $ReinstallMode 0
-${EndIf}
-
${If} $InstDir == ""
; User did not use /D to specify a directory,
; we need to set a default based on the install mode
@@ -119,22 +97,6 @@ ${If} $InstDir == ""
${EndIf}
Call SetModeDestinationFromInstdir
-; --- Detect portable install when using /R ---
-${If} $ReinstallMode = 1
- IfFileExists "$InstDir\portable.dat" 0 not_portable
- StrCpy $PortableMode 1
- Goto portable_done
-
- not_portable:
- StrCpy $PortableMode 0
-
- portable_done:
-${EndIf}
-
-${If} $ReinstallMode = 1
- Call AutoUninstallIfNeeded
-${EndIf}
-
FunctionEnd
Function un.onInit
@@ -164,46 +126,8 @@ ${Else}
${EndIf}
FunctionEnd
-Function SkipIfReinstall
-${If} $ReinstallMode = 1
- Abort
-${EndIf}
-FunctionEnd
-
-Function AutoUninstallIfNeeded
-
-SetShellVarContext all
-
-; --- 32-bit uninstall ---
-SetRegView 32
-ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "QuietUninstallString"
-
-StrCmp $R0 "" done32
-DetailPrint "Removing previous version (32-bit)..."
-ExecWait '$R0'
-
-done32:
-
-; --- 64-bit uninstall ---
-${If} ${RunningX64}
- SetRegView 64
- ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "QuietUninstallString"
-
- StrCmp $R0 "" done64
- DetailPrint "Removing previous version (64-bit)..."
- ExecWait '$R0'
-
- done64:
-${EndIf}
-
-FunctionEnd
Function PortableModePageCreate
-
-${If} $ReinstallMode = 1
- Abort
-${EndIf}
-
Call SetModeDestinationFromInstdir ; If the user clicks BACK on the directory page we will remember their mode specific directory
!insertmacro MUI_HEADER_TEXT "Install Mode" "Choose how you want to install Cockatrice."
nsDialogs::Create 1018
@@ -235,11 +159,6 @@ ${EndIf}
FunctionEnd
Function componentsPagePre
-
-${If} $ReinstallMode = 1
- Return
-${EndIf}
-
${If} $PortableMode = 0
SetShellVarContext all
@@ -249,12 +168,8 @@ ${If} $PortableMode = 0
ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "UninstallString"
StrCmp $R0 "" done32
- ${If} $ReinstallMode = 0
- MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION "A previous version of Cockatrice must be uninstalled before installing the new one." IDOK uninst32
- Abort
- ${Else}
- Goto uninst32
- ${EndIf}
+ MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION "A previous version of Cockatrice must be uninstalled before installing the new one." IDOK uninst32
+ Abort
uninst32:
ClearErrors
@@ -269,12 +184,8 @@ ${If} $PortableMode = 0
ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "UninstallString"
StrCmp $R0 "" done64
- ${If} $ReinstallMode = 0
- MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION "A previous version of Cockatrice must be uninstalled before installing the new one." IDOK uninst64
- Abort
- ${Else}
- Goto uninst64
- ${EndIf}
+ MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION "A previous version of Cockatrice must be uninstalled before installing the new one." IDOK uninst64
+ Abort
uninst64:
ClearErrors
@@ -366,12 +277,6 @@ ${Else}
FileWrite $0 "PORTABLE"
FileClose $0
${EndIf}
-
-${If} $ReinstallMode = 1
- IfFileExists "$INSTDIR\cockatrice.exe" 0 +2
- Exec '"$INSTDIR\cockatrice.exe"'
-${EndIf}
-
SectionEnd
Section "Start menu item" SecStartMenu
diff --git a/cockatrice/src/client/network/interfaces/tapped_out_interface.cpp b/cockatrice/src/client/network/interfaces/tapped_out_interface.cpp
index af377d176..a30a7f531 100644
--- a/cockatrice/src/client/network/interfaces/tapped_out_interface.cpp
+++ b/cockatrice/src/client/network/interfaces/tapped_out_interface.cpp
@@ -89,8 +89,6 @@ void TappedOutInterface::analyzeDeck(const DeckList &deck)
QNetworkRequest request(QUrl("https://tappedout.net/mtg-decks/paste/"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
request.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING));
- // we interpret the redirect and open it in the browser instead, do not follow redirects
- request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::ManualRedirectPolicy);
manager->post(request, data);
}
diff --git a/cockatrice/src/game/log/message_log_widget.cpp b/cockatrice/src/game/log/message_log_widget.cpp
index 09f6e656b..c38e433eb 100644
--- a/cockatrice/src/game/log/message_log_widget.cpp
+++ b/cockatrice/src/game/log/message_log_widget.cpp
@@ -54,7 +54,7 @@ MessageLogWidget::getFromStr(CardZoneLogic *zone, QString cardName, int position
fromStr = tr(" from the top of their library");
}
}
- } else if (position == zone->getCards().size()) {
+ } else if (position >= zone->getCards().size() - 1) {
if (cardName.isEmpty()) {
if (ownerChange) {
cardName = tr("the bottom card of %1's library").arg(zone->getPlayer()->getPlayerInfo()->getName());
diff --git a/cockatrice/src/interface/widgets/cards/card_info_text_widget.cpp b/cockatrice/src/interface/widgets/cards/card_info_text_widget.cpp
index f5f343807..456e1533a 100644
--- a/cockatrice/src/interface/widgets/cards/card_info_text_widget.cpp
+++ b/cockatrice/src/interface/widgets/cards/card_info_text_widget.cpp
@@ -62,7 +62,7 @@ void CardInfoTextWidget::setCard(const ExactCard &exactCard)
text += QString("
| %1 | | %2 |
")
.arg(tr("Name:"), card->getName().toHtmlEscaped());
- if (!exactCard.getPrinting().isEmpty()) {
+ if (exactCard.getPrinting() != PrintingInfo()) {
QString setShort = exactCard.getPrinting().getSet()->getShortName().toHtmlEscaped();
QString cardNum = exactCard.getPrinting().getProperty("num").toHtmlEscaped();
diff --git a/cockatrice/src/interface/widgets/deck_analytics/deck_analytics_widget.cpp b/cockatrice/src/interface/widgets/deck_analytics/deck_analytics_widget.cpp
index 147675e21..ea61302f0 100644
--- a/cockatrice/src/interface/widgets/deck_analytics/deck_analytics_widget.cpp
+++ b/cockatrice/src/interface/widgets/deck_analytics/deck_analytics_widget.cpp
@@ -29,14 +29,10 @@ DeckAnalyticsWidget::DeckAnalyticsWidget(QWidget *parent, DeckListStatisticsAnal
removeButton = new QPushButton(this);
saveButton = new QPushButton(this);
loadButton = new QPushButton(this);
- includeSideboardCheckBox = new QCheckBox(this);
- includeSideboardCheckBox->setChecked(false);
-
controlLayout->addWidget(addButton);
controlLayout->addWidget(removeButton);
controlLayout->addWidget(saveButton);
controlLayout->addWidget(loadButton);
- controlLayout->addWidget(includeSideboardCheckBox);
layout->addWidget(controlContainer);
@@ -44,7 +40,6 @@ DeckAnalyticsWidget::DeckAnalyticsWidget(QWidget *parent, DeckListStatisticsAnal
connect(removeButton, &QPushButton::clicked, this, &DeckAnalyticsWidget::onRemoveSelected);
connect(saveButton, &QPushButton::clicked, this, &DeckAnalyticsWidget::saveLayout);
connect(loadButton, &QPushButton::clicked, this, &DeckAnalyticsWidget::loadLayout);
- connect(includeSideboardCheckBox, &QCheckBox::clicked, this, &DeckAnalyticsWidget::includeSideboardChanged);
// Scroll area and container
scrollArea = new QScrollArea(this);
@@ -71,13 +66,6 @@ void DeckAnalyticsWidget::retranslateUi()
removeButton->setText(tr("Remove Panel"));
saveButton->setText(tr("Save Layout"));
loadButton->setText(tr("Load Layout"));
- includeSideboardCheckBox->setText(tr("Include Sideboard"));
-}
-
-void DeckAnalyticsWidget::includeSideboardChanged(bool checked)
-{
- statsAnalyzer->getConfig().includeSideboard = checked;
- updateDisplays();
}
void DeckAnalyticsWidget::updateDisplays()
diff --git a/cockatrice/src/interface/widgets/deck_analytics/deck_analytics_widget.h b/cockatrice/src/interface/widgets/deck_analytics/deck_analytics_widget.h
index 09618c3f8..31ee36fbb 100644
--- a/cockatrice/src/interface/widgets/deck_analytics/deck_analytics_widget.h
+++ b/cockatrice/src/interface/widgets/deck_analytics/deck_analytics_widget.h
@@ -11,7 +11,6 @@
#include "deck_list_statistics_analyzer.h"
#include "resizable_panel.h"
-#include
#include
#include
#include
@@ -30,7 +29,6 @@ public slots:
public:
explicit DeckAnalyticsWidget(QWidget *parent, DeckListStatisticsAnalyzer *analyzer);
void retranslateUi();
- void includeSideboardChanged(bool checked);
private slots:
void onAddPanel();
@@ -59,8 +57,6 @@ private:
QPushButton *saveButton;
QPushButton *loadButton;
- QCheckBox *includeSideboardCheckBox;
-
QScrollArea *scrollArea;
QWidget *panelContainer;
QVBoxLayout *panelLayout;
diff --git a/cockatrice/src/interface/widgets/deck_analytics/deck_list_statistics_analyzer.cpp b/cockatrice/src/interface/widgets/deck_analytics/deck_list_statistics_analyzer.cpp
index 073b6d25c..ad8afb766 100644
--- a/cockatrice/src/interface/widgets/deck_analytics/deck_list_statistics_analyzer.cpp
+++ b/cockatrice/src/interface/widgets/deck_analytics/deck_list_statistics_analyzer.cpp
@@ -19,13 +19,7 @@ void DeckListStatisticsAnalyzer::analyze()
{
clearData();
- QList nodes;
-
- if (config.includeSideboard) {
- nodes = model->getCardNodes();
- } else {
- nodes = model->getCardNodesForZone(DECK_ZONE_MAIN);
- }
+ QList nodes = model->getCardNodes();
for (auto node : nodes) {
CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(node->getName());
diff --git a/cockatrice/src/interface/widgets/deck_analytics/deck_list_statistics_analyzer.h b/cockatrice/src/interface/widgets/deck_analytics/deck_list_statistics_analyzer.h
index 52ae751bf..946bb0117 100644
--- a/cockatrice/src/interface/widgets/deck_analytics/deck_list_statistics_analyzer.h
+++ b/cockatrice/src/interface/widgets/deck_analytics/deck_list_statistics_analyzer.h
@@ -17,7 +17,6 @@ struct DeckListStatisticsAnalyzerConfig
bool computeCategories = true;
bool computeCurveBreakdowns = true;
bool computeProbabilities = true;
- bool includeSideboard = false;
};
class DeckListStatisticsAnalyzer : public QObject
@@ -134,11 +133,6 @@ public:
return model;
}
- DeckListStatisticsAnalyzerConfig &getConfig()
- {
- return config;
- }
-
signals:
void statsUpdated();
diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_update.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_update.cpp
index c9adeb270..0a9244dec 100644
--- a/cockatrice/src/interface/widgets/dialogs/dlg_update.cpp
+++ b/cockatrice/src/interface/widgets/dialogs/dlg_update.cpp
@@ -219,9 +219,7 @@ void DlgUpdate::downloadSuccessful(const QUrl &filepath)
{
setLabel(tr("Installing..."));
// Try to open the installer. If it opens, quit Cockatrice
- if (QProcess::startDetached(filepath.toLocalFile(),
- QStringList()
- << "/R" << QString("/D=%1").arg(QCoreApplication::applicationDirPath()))) {
+ if (QDesktopServices::openUrl(filepath)) {
QMetaObject::invokeMethod(static_cast(parent()), "close", Qt::QueuedConnection);
qCInfo(DlgUpdateLog) << "Opened downloaded update file successfully - closing Cockatrice";
close();
diff --git a/cockatrice/src/interface/widgets/server/game_selector.cpp b/cockatrice/src/interface/widgets/server/game_selector.cpp
index 0ff2a5542..f14cc6d82 100644
--- a/cockatrice/src/interface/widgets/server/game_selector.cpp
+++ b/cockatrice/src/interface/widgets/server/game_selector.cpp
@@ -91,7 +91,6 @@ GameSelector::GameSelector(AbstractClient *_client,
bool filtersSetToDefault = showFilters && gameListProxyModel->areFilterParametersSetToDefaults();
clearFilterButton->setEnabled(!filtersSetToDefault);
connect(clearFilterButton, &QPushButton::clicked, this, &GameSelector::actClearFilter);
- connect(gameListProxyModel, &GamesProxyModel::filtersChanged, this, &GameSelector::checkClearFilterButtonState);
if (room) {
createButton = new QPushButton;
@@ -189,16 +188,15 @@ void GameSelector::actSetFilter()
dlg.getShowOnlyIfSpectatorsCanChat(), dlg.getShowOnlyIfSpectatorsCanSeeHands());
gameListProxyModel->saveFilterParameters(gameTypeMap);
- updateTitle();
-}
-
-void GameSelector::checkClearFilterButtonState()
-{
clearFilterButton->setEnabled(!gameListProxyModel->areFilterParametersSetToDefaults());
+
+ updateTitle();
}
void GameSelector::actClearFilter()
{
+ clearFilterButton->setEnabled(false);
+
gameListProxyModel->resetFilterParameters();
gameListProxyModel->saveFilterParameters(gameTypeMap);
diff --git a/cockatrice/src/interface/widgets/server/game_selector.h b/cockatrice/src/interface/widgets/server/game_selector.h
index fa91e5f96..ea0a4feb0 100644
--- a/cockatrice/src/interface/widgets/server/game_selector.h
+++ b/cockatrice/src/interface/widgets/server/game_selector.h
@@ -40,7 +40,6 @@ private slots:
* Updates the proxy model with selected filter parameters and refreshes the displayed game list.
*/
void actSetFilter();
- void checkClearFilterButtonState();
/**
* @brief Clears all filters applied to the game list.
diff --git a/cockatrice/src/interface/widgets/server/game_selector_quick_filter_toolbar.cpp b/cockatrice/src/interface/widgets/server/game_selector_quick_filter_toolbar.cpp
index f7eacd636..daab4d6eb 100644
--- a/cockatrice/src/interface/widgets/server/game_selector_quick_filter_toolbar.cpp
+++ b/cockatrice/src/interface/widgets/server/game_selector_quick_filter_toolbar.cpp
@@ -19,46 +19,32 @@ GameSelectorQuickFilterToolBar::GameSelectorQuickFilterToolBar(QWidget *parent,
mainLayout->setSpacing(5);
searchBar = new QLineEdit(this);
- searchBar->setText(model->getGameNameFilter());
- connect(searchBar, &QLineEdit::textChanged, this, [this](const QString &text) {
- applyFilters([&](auto &, auto &, auto &, auto &, auto &, auto &, auto &, QString &gameNameFilter, auto &,
- auto &, auto &, auto &, auto &, auto &, auto &, auto &, auto &) { gameNameFilter = text; });
- });
+ searchBar->setText(model->getCreatorNameFilters().join(", "));
+ connect(searchBar, &QLineEdit::textChanged, this, [this](const QString &text) { model->setGameNameFilter(text); });
hideGamesNotCreatedByBuddiesCheckBox = new QCheckBox(this);
- hideGamesNotCreatedByBuddiesCheckBox->setChecked(model->getHideNotBuddyCreatedGames());
+ hideGamesNotCreatedByBuddiesCheckBox->setChecked(model->getHideBuddiesOnlyGames());
connect(hideGamesNotCreatedByBuddiesCheckBox, &QCheckBox::toggled, this, [this](bool checked) {
- applyFilters([&](auto &, auto &, auto &, auto &, auto &, bool &hideNotBuddyCreatedGames, auto &, auto &,
- QStringList &creatorNameFilters, auto &, auto &, auto &, auto &, auto &, auto &, auto &,
- auto &) {
- hideNotBuddyCreatedGames = checked;
-
- if (checked) {
- QStringList buddyNames;
- for (auto buddy : tabSupervisor->getUserListManager()->getBuddyList().values()) {
- buddyNames << QString::fromStdString(buddy.name());
- }
- creatorNameFilters = buddyNames;
- } else {
- creatorNameFilters.clear();
+ if (checked) {
+ QStringList buddyNames;
+ for (auto buddy : tabSupervisor->getUserListManager()->getBuddyList().values()) {
+ buddyNames << QString::fromStdString(buddy.name());
}
- });
+ model->setCreatorNameFilters(buddyNames);
+ } else {
+ model->setCreatorNameFilters({});
+ }
});
hideFullGamesCheckBox = new QCheckBox(this);
hideFullGamesCheckBox->setChecked(model->getHideFullGames());
- connect(hideFullGamesCheckBox, &QCheckBox::toggled, this, [this](bool checked) {
- applyFilters([&](auto &, auto &, bool &hideFullGames, auto &, auto &, auto &, auto &, auto &, auto &, auto &,
- auto &, auto &, auto &, auto &, auto &, auto &, auto &) { hideFullGames = checked; });
- });
+ connect(hideFullGamesCheckBox, &QCheckBox::toggled, this,
+ [this](bool checked) { model->setHideFullGames(checked); });
hideStartedGamesCheckBox = new QCheckBox(this);
hideStartedGamesCheckBox->setChecked(model->getHideGamesThatStarted());
- connect(hideStartedGamesCheckBox, &QCheckBox::toggled, this, [this](bool checked) {
- applyFilters([&](auto &, auto &, auto &, bool &hideGamesThatStarted, auto &, auto &, auto &, auto &, auto &,
- auto &, auto &, auto &, auto &, auto &, auto &, auto &,
- auto &) { hideGamesThatStarted = checked; });
- });
+ connect(hideStartedGamesCheckBox, &QCheckBox::toggled, this,
+ [this](bool checked) { model->setHideGamesThatStarted(checked); });
filterToFormatComboBox = new QComboBox(this);
@@ -83,15 +69,13 @@ GameSelectorQuickFilterToolBar::GameSelectorQuickFilterToolBar(QWidget *parent,
// Update proxy model on selection change
connect(filterToFormatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [this](int index) {
- applyFilters([&](auto &, auto &, auto &, auto &, auto &, auto &, auto &, auto &, auto &,
- QSet &gameTypeFilter, auto &, auto &, auto &, auto &, auto &, auto &, auto &) {
- QVariant data = filterToFormatComboBox->itemData(index);
- if (!data.isValid()) {
- gameTypeFilter.clear();
- } else {
- gameTypeFilter = {data.toInt()};
- }
- });
+ QVariant data = filterToFormatComboBox->itemData(index);
+ if (!data.isValid()) {
+ model->setGameTypeFilter({}); // empty = no filter
+ } else {
+ int typeId = data.toInt();
+ model->setGameTypeFilter({typeId});
+ }
});
hideGamesNotCreatedByBuddiesCheckBox->setMinimumSize(20, 20);
@@ -112,87 +96,9 @@ GameSelectorQuickFilterToolBar::GameSelectorQuickFilterToolBar(QWidget *parent,
setLayout(mainLayout);
- syncFromModel();
-
- connect(model, &GamesProxyModel::filtersChanged, this, &GameSelectorQuickFilterToolBar::syncFromModel);
-
retranslateUi();
}
-void GameSelectorQuickFilterToolBar::syncFromModel()
-{
- QSignalBlocker b1(searchBar);
- QSignalBlocker b2(filterToFormatComboBox);
- QSignalBlocker b3(hideGamesNotCreatedByBuddiesCheckBox);
- QSignalBlocker b4(hideFullGamesCheckBox);
- QSignalBlocker b5(hideStartedGamesCheckBox);
-
- searchBar->setText(model->getGameNameFilter());
-
- hideGamesNotCreatedByBuddiesCheckBox->setChecked(model->getHideNotBuddyCreatedGames());
- hideFullGamesCheckBox->setChecked(model->getHideFullGames());
- hideStartedGamesCheckBox->setChecked(model->getHideGamesThatStarted());
-
- QSet types = model->getGameTypeFilter();
- if (types.size() == 1) {
- int idx = filterToFormatComboBox->findData(*types.begin());
- filterToFormatComboBox->setCurrentIndex(idx >= 0 ? idx : 0);
- } else {
- filterToFormatComboBox->setCurrentIndex(0);
- }
-}
-
-void GameSelectorQuickFilterToolBar::applyFilters(std::function &,
- int &,
- int &,
- QTime &,
- bool &,
- bool &,
- bool &,
- bool &)> mutator)
-{
- bool hideBuddiesOnlyGames = model->getHideBuddiesOnlyGames();
- bool hideIgnoredUserGames = model->getHideIgnoredUserGames();
- bool hideFullGames = model->getHideFullGames();
- bool hideGamesThatStarted = model->getHideGamesThatStarted();
- bool hidePasswordProtectedGames = model->getHidePasswordProtectedGames();
- bool hideNotBuddyCreatedGames = model->getHideNotBuddyCreatedGames();
- bool hideOpenDecklistGames = model->getHideOpenDecklistGames();
-
- QString gameNameFilter = model->getGameNameFilter();
- QStringList creatorNameFilters = model->getCreatorNameFilters();
- QSet gameTypeFilter = model->getGameTypeFilter();
-
- int minPlayers = model->getMaxPlayersFilterMin();
- int maxPlayers = model->getMaxPlayersFilterMax();
- QTime maxGameAge = model->getMaxGameAge();
-
- bool showOnlyIfSpectatorsCanWatch = model->getShowOnlyIfSpectatorsCanWatch();
- bool showSpectatorPasswordProtected = model->getShowSpectatorPasswordProtected();
- bool showOnlyIfSpectatorsCanChat = model->getShowOnlyIfSpectatorsCanChat();
- bool showOnlyIfSpectatorsCanSeeHands = model->getShowOnlyIfSpectatorsCanSeeHands();
-
- mutator(hideBuddiesOnlyGames, hideIgnoredUserGames, hideFullGames, hideGamesThatStarted, hidePasswordProtectedGames,
- hideNotBuddyCreatedGames, hideOpenDecklistGames, gameNameFilter, creatorNameFilters, gameTypeFilter,
- minPlayers, maxPlayers, maxGameAge, showOnlyIfSpectatorsCanWatch, showSpectatorPasswordProtected,
- showOnlyIfSpectatorsCanChat, showOnlyIfSpectatorsCanSeeHands);
-
- model->setGameFilters(hideBuddiesOnlyGames, hideIgnoredUserGames, hideFullGames, hideGamesThatStarted,
- hidePasswordProtectedGames, hideNotBuddyCreatedGames, hideOpenDecklistGames, gameNameFilter,
- creatorNameFilters, gameTypeFilter, minPlayers, maxPlayers, maxGameAge,
- showOnlyIfSpectatorsCanWatch, showSpectatorPasswordProtected, showOnlyIfSpectatorsCanChat,
- showOnlyIfSpectatorsCanSeeHands);
-}
-
void GameSelectorQuickFilterToolBar::retranslateUi()
{
searchBar->setPlaceholderText(tr("Filter by game name..."));
diff --git a/cockatrice/src/interface/widgets/server/game_selector_quick_filter_toolbar.h b/cockatrice/src/interface/widgets/server/game_selector_quick_filter_toolbar.h
index c658418f9..642fdd1c4 100644
--- a/cockatrice/src/interface/widgets/server/game_selector_quick_filter_toolbar.h
+++ b/cockatrice/src/interface/widgets/server/game_selector_quick_filter_toolbar.h
@@ -18,24 +18,6 @@ public:
TabSupervisor *tabSupervisor,
GamesProxyModel *model,
const QMap &allGameTypes);
- void syncFromModel();
- void applyFilters(std::function &,
- int &,
- int &,
- QTime &,
- bool &,
- bool &,
- bool &,
- bool &)> mutator);
void retranslateUi();
private:
diff --git a/cockatrice/src/interface/widgets/server/games_model.cpp b/cockatrice/src/interface/widgets/server/games_model.cpp
index 1f05308b8..05d363fee 100644
--- a/cockatrice/src/interface/widgets/server/games_model.cpp
+++ b/cockatrice/src/interface/widgets/server/games_model.cpp
@@ -326,7 +326,6 @@ void GamesProxyModel::setGameFilters(bool _hideBuddiesOnlyGames,
#else
invalidateFilter();
#endif
- emit filtersChanged();
}
int GamesProxyModel::getNumFilteredGames() const
diff --git a/cockatrice/src/interface/widgets/server/games_model.h b/cockatrice/src/interface/widgets/server/games_model.h
index c6884093d..56c806fb6 100644
--- a/cockatrice/src/interface/widgets/server/games_model.h
+++ b/cockatrice/src/interface/widgets/server/games_model.h
@@ -138,9 +138,6 @@ private:
bool showOnlyIfSpectatorsCanChat;
bool showOnlyIfSpectatorsCanSeeHands;
-signals:
- void filtersChanged();
-
public:
/**
* @brief Constructs a GamesProxyModel.
diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.cpp b/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.cpp
index f51d0f3e7..7a424de8b 100644
--- a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.cpp
+++ b/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.cpp
@@ -4,29 +4,10 @@ void ArchidektApiResponseCardEntry::fromJson(const QJsonObject &json)
{
id = json.value("id").toInt();
- categories.clear();
-
auto categoriesJson = json.value("categories").toArray();
- for (const auto &categoryValue : categoriesJson) {
- Category cat;
-
- if (categoryValue.isObject()) {
- QJsonObject obj = categoryValue.toObject();
-
- cat.id = obj.value("id").toInt();
- cat.name = obj.value("name").toString();
- cat.isPremier = obj.value("isPremier").toBool();
- cat.includedInDeck = obj.value("includedInDeck").toBool();
- cat.includedInPrice = obj.value("includedInPrice").toBool();
- } else if (categoryValue.isString()) {
- cat.name = categoryValue.toString();
-
- // assume mainboard unless known otherwise
- cat.includedInDeck = true;
- }
-
- categories.append(cat);
+ for (auto category : categoriesJson) {
+ categories.append(category.toString());
}
companion = json.value("companion").toBool();
@@ -46,13 +27,7 @@ void ArchidektApiResponseCardEntry::fromJson(const QJsonObject &json)
void ArchidektApiResponseCardEntry::debugPrint() const
{
qDebug() << "Id:" << id;
- for (auto category : categories) {
- qDebug() << "Category ID:" << category.id;
- qDebug() << "Category Name:" << category.name;
- qDebug() << "Category Premier:" << category.isPremier;
- qDebug() << "Category Included in Deck:" << category.includedInDeck;
- qDebug() << "Category Included in Price:" << category.includedInPrice;
- }
+ qDebug() << "Categories:" << categories;
qDebug() << "Companion:" << companion;
qDebug() << "FlippedDefault:" << flippedDefault;
qDebug() << "Label:" << label;
diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.h b/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.h
index f3961dc6f..f7f86e9ed 100644
--- a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.h
+++ b/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.h
@@ -9,15 +9,6 @@
#include
#include
-struct Category
-{
- int id;
- QString name;
- bool isPremier;
- bool includedInDeck;
- bool includedInPrice;
-};
-
class ArchidektApiResponseCardEntry
{
public:
@@ -35,7 +26,7 @@ public:
return card;
};
- QList getCategories() const
+ QStringList getCategories() const
{
return categories;
}
@@ -47,7 +38,7 @@ public:
private:
int id;
- QList categories;
+ QStringList categories;
bool companion;
bool flippedDefault;
QString label;
diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp b/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp
index 66b68d823..8b17cd49e 100644
--- a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp
+++ b/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp
@@ -63,60 +63,16 @@ ArchidektApiResponseDeckDisplayWidget::ArchidektApiResponseDeckDisplayWidget(QWi
QString tempDeck;
QTextStream deckStream(&tempDeck);
- QString mainboardText;
- QString sideboardText;
-
- QTextStream mainStream(&mainboardText);
- QTextStream sideStream(&sideboardText);
-
- for (const auto &card : response.getCards()) {
+ for (auto card : response.getCards()) {
QString fullName = card.getCard().getOracleCard().value("name").toString();
// We don't really care about the second card, the card database already has it as a relation
QString cleanName = fullName.split("//").first().trimmed();
- QString line = QString("%1 %2 (%3) %4\n")
- .arg(card.getQuantity())
- .arg(cleanName)
- .arg(card.getCard().getEdition().getEditionCode().toUpper())
- .arg(card.getCard().getCollectorNumber());
-
- bool isCommander = false;
- bool isSideboardCategory = false;
- bool includedInDeck = false;
-
- for (const auto &cat : card.getCategories()) {
-
- if (cat.name.compare("Commander", Qt::CaseInsensitive) == 0) {
- isCommander = true;
- }
-
- if (cat.name.compare("Sideboard", Qt::CaseInsensitive) == 0 ||
- cat.name.compare("Maybeboard", Qt::CaseInsensitive) == 0) {
- isSideboardCategory = true;
- }
-
- if (cat.includedInDeck) {
- includedInDeck = true;
- }
- }
-
- QString target;
-
- if (isCommander || isSideboardCategory) {
- sideStream << line;
- } else if (includedInDeck) {
- mainStream << line;
- } else {
- sideStream << line;
- }
- }
-
- // Combine with blank line separator
- tempDeck = mainboardText;
-
- if (!sideboardText.isEmpty()) {
- tempDeck += "\n";
- tempDeck += sideboardText;
+ tempDeck += QString("%1 %2 (%3) %4\n")
+ .arg(card.getQuantity())
+ .arg(cleanName)
+ .arg(card.getCard().getEdition().getEditionCode().toUpper())
+ .arg(card.getCard().getCollectorNumber());
}
model = new DeckListModel(this);
diff --git a/cockatrice/src/interface/widgets/tabs/tab_game.cpp b/cockatrice/src/interface/widgets/tabs/tab_game.cpp
index 161829b35..cf8269069 100644
--- a/cockatrice/src/interface/widgets/tabs/tab_game.cpp
+++ b/cockatrice/src/interface/widgets/tabs/tab_game.cpp
@@ -259,9 +259,6 @@ TabGame::~TabGame()
if (replayManager) {
delete replayManager->replay;
}
- for (auto &player : game->getPlayerManager()->getPlayers()) {
- player->clear();
- }
}
void TabGame::updatePlayerListDockTitle()
diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_button.h b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_button.h
deleted file mode 100644
index 5d9f7f944..000000000
--- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_button.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef COCKATRICE_VISUAL_DATABASE_DISPLAY_FILTER_BUTTON_H
-#define COCKATRICE_VISUAL_DATABASE_DISPLAY_FILTER_BUTTON_H
-
-#include
-
-const QString visualDatabaseDisplayFilterButtonStyle = QString(R"(
- QPushButton {
- background-color: palette(button);
- color: palette(button-text);
- padding: 5px 10px;
- border-radius: 4px;
- border: 1px solid palette(dark);
- }
- QPushButton:checked {
- background-color: palette(highlight);
- color: palette(highlighted-text);
- border: 1px solid palette(shadow);
- }
-)");
-
-#endif // COCKATRICE_VISUAL_DATABASE_DISPLAY_FILTER_BUTTON_H
diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_format_legality_filter_widget.cpp b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_format_legality_filter_widget.cpp
index 633f07af7..0df948016 100644
--- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_format_legality_filter_widget.cpp
+++ b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_format_legality_filter_widget.cpp
@@ -1,7 +1,6 @@
#include "visual_database_display_format_legality_filter_widget.h"
#include "../../../filters/filter_tree_model.h"
-#include "visual_database_display_filter_button.h"
#include
#include
@@ -81,7 +80,8 @@ void VisualDatabaseDisplayFormatLegalityFilterWidget::createFormatButtons()
for (auto it = allFormatsWithCount.begin(); it != allFormatsWithCount.end(); ++it) {
auto *button = new QPushButton(it.key(), flowWidget);
button->setCheckable(true);
- button->setStyleSheet(visualDatabaseDisplayFilterButtonStyle);
+ button->setStyleSheet("QPushButton { background-color: lightgray; border: 1px solid gray; padding: 5px; }"
+ "QPushButton:checked { background-color: green; color: white; }");
flowWidget->addWidget(button);
formatButtons[it.key()] = button;
diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp
index c44489c1b..bc8e914bd 100644
--- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp
+++ b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp
@@ -1,7 +1,6 @@
#include "visual_database_display_main_type_filter_widget.h"
#include "../../../filters/filter_tree_model.h"
-#include "visual_database_display_filter_button.h"
#include
#include
@@ -76,8 +75,8 @@ void VisualDatabaseDisplayMainTypeFilterWidget::createMainTypeButtons()
for (auto it = allMainCardTypesWithCount.begin(); it != allMainCardTypesWithCount.end(); ++it) {
auto *button = new QPushButton(it.key(), flowWidget);
button->setCheckable(true);
-
- button->setStyleSheet(visualDatabaseDisplayFilterButtonStyle);
+ button->setStyleSheet("QPushButton { background-color: lightgray; border: 1px solid gray; padding: 5px; }"
+ "QPushButton:checked { background-color: green; color: white; }");
flowWidget->addWidget(button);
typeButtons[it.key()] = button;
diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp
index 2751ee971..5098696dd 100644
--- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp
+++ b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp
@@ -3,7 +3,6 @@
#include "../../../interface/widgets/dialogs/dlg_load_deck_from_clipboard.h"
#include "../../../interface/widgets/tabs/abstract_tab_deck_editor.h"
#include "../deck_editor/deck_state_manager.h"
-#include "visual_database_display_filter_button.h"
#include
@@ -96,8 +95,8 @@ void VisualDatabaseDisplayNameFilterWidget::createNameFilter(const QString &name
// Create a button for the filter
auto *button = new QPushButton(name, flowWidget);
-
- button->setStyleSheet(visualDatabaseDisplayFilterButtonStyle);
+ button->setStyleSheet("QPushButton { background-color: lightgray; border: 1px solid gray; padding: 5px; }"
+ "QPushButton:hover { background-color: red; color: white; }");
connect(button, &QPushButton::clicked, this, [this, name]() {
removeNameFilter(name);
diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp
index b72116461..3339bc561 100644
--- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp
+++ b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp
@@ -2,7 +2,6 @@
#include "../../../client/settings/cache_settings.h"
#include "../../../filters/filter_tree_model.h"
-#include "visual_database_display_filter_button.h"
#include
#include
@@ -102,8 +101,8 @@ void VisualDatabaseDisplaySetFilterWidget::createSetButtons()
auto *button = new QPushButton(longName + " (" + shortName + ")", flowWidget);
button->setCheckable(true);
-
- button->setStyleSheet(visualDatabaseDisplayFilterButtonStyle);
+ button->setStyleSheet("QPushButton { background-color: lightgray; border: 1px solid gray; padding: 5px; }"
+ "QPushButton:checked { background-color: green; color: white; }");
flowWidget->addWidget(button);
setButtons[shortName] = button;
diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp
index 6d4bcb58e..57559d12c 100644
--- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp
+++ b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp
@@ -1,7 +1,6 @@
#include "visual_database_display_sub_type_filter_widget.h"
#include "../../../filters/filter_tree_model.h"
-#include "visual_database_display_filter_button.h"
#include
#include
@@ -81,8 +80,8 @@ void VisualDatabaseDisplaySubTypeFilterWidget::createSubTypeButtons()
for (auto it = allSubCardTypesWithCount.begin(); it != allSubCardTypesWithCount.end(); ++it) {
auto *button = new QPushButton(it.key(), flowWidget);
button->setCheckable(true);
-
- button->setStyleSheet(visualDatabaseDisplayFilterButtonStyle);
+ button->setStyleSheet("QPushButton { background-color: lightgray; border: 1px solid gray; padding: 5px; }"
+ "QPushButton:checked { background-color: green; color: white; }");
flowWidget->addWidget(button);
typeButtons[it.key()] = button;
diff --git a/libcockatrice_card/libcockatrice/card/database/card_database_querier.cpp b/libcockatrice_card/libcockatrice/card/database/card_database_querier.cpp
index 021e8d12d..26e515a2d 100644
--- a/libcockatrice_card/libcockatrice/card/database/card_database_querier.cpp
+++ b/libcockatrice_card/libcockatrice/card/database/card_database_querier.cpp
@@ -133,7 +133,7 @@ ExactCard CardDatabaseQuerier::getRandomCard() const
ExactCard CardDatabaseQuerier::getCardFromSameSet(const QString &cardName, const PrintingInfo &otherPrinting) const
{
// The source card does not have a printing defined, which means we can't get a card from the same set.
- if (otherPrinting.isEmpty()) {
+ if (otherPrinting == PrintingInfo()) {
return getCard({cardName});
}
@@ -360,4 +360,4 @@ QMap CardDatabaseQuerier::getAllFormatsWithCount() const
}
return formatCounts;
-}
+}
\ No newline at end of file
diff --git a/libcockatrice_card/libcockatrice/card/printing/printing_info.h b/libcockatrice_card/libcockatrice/card/printing/printing_info.h
index ad7b33654..43d82a9cb 100644
--- a/libcockatrice_card/libcockatrice/card/printing/printing_info.h
+++ b/libcockatrice_card/libcockatrice/card/printing/printing_info.h
@@ -54,16 +54,6 @@ public:
return this->set == other.set && this->properties == other.properties;
}
- /**
- * @brief check if the info is empty, as if default constructed.
- *
- * @return True if both set and properties are empty, otherwise false.
- */
- bool isEmpty() const
- {
- return set == nullptr && properties.isEmpty();
- }
-
private:
CardSetPtr set; ///< The set this variation belongs to.
QVariantHash properties; ///< Key-value store for variation-specific attributes.
diff --git a/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.cpp b/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.cpp
index 7c0437bf0..f04bcc849 100644
--- a/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.cpp
+++ b/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.cpp
@@ -49,7 +49,6 @@
#include
#include
#include
-#include
Server_AbstractPlayer::Server_AbstractPlayer(Server_Game *_game,
int _playerId,
@@ -229,37 +228,6 @@ shouldBeFaceDown(const MoveCardStruct &cardStruct, const Server_CardZone *startZ
return false;
}
-/**
- * @brief Determines whether a set of moved cards is from the bottom of the deck
- */
-static bool shouldBeFromTheBottom(const Server_CardZone *startZone, const std::set &cardsToMove)
-{
- if (!startZone) {
- return false;
- }
-
- if (startZone->getName() != ZoneNames::DECK) {
- return false;
- }
-
- int movedCount = static_cast(cardsToMove.size());
- int tailStart = startZone->getCards().size() - movedCount;
- if (tailStart <= 0) { // if the entire deck is moved it should not be considered from the bottom
- return false;
- }
-
- // check if the move is a contiguous block at the end of the deck, fail fast when not
- int expectedPosition = tailStart;
- for (const auto &card : cardsToMove) {
- if (card.position != expectedPosition) {
- return false;
- }
- ++expectedPosition;
- }
-
- return true;
-}
-
Response::ResponseCode Server_AbstractPlayer::moveCard(GameEventStorage &ges,
Server_CardZone *startzone,
const QList &_cards,
@@ -276,11 +244,8 @@ Response::ResponseCode Server_AbstractPlayer::moveCard(GameEventStorage &ges,
return Response::RespContextError;
}
- if (!targetzone->hasCoords()) {
- yCoord = 0;
- if (xCoord <= -1) {
- xCoord = targetzone->getCards().size();
- }
+ if (!targetzone->hasCoords() && (xCoord <= -1)) {
+ xCoord = targetzone->getCards().size();
}
std::set cardsToMove;
@@ -320,21 +285,164 @@ Response::ResponseCode Server_AbstractPlayer::moveCard(GameEventStorage &ges,
bool revealTopStart = false;
bool revealTopTarget = false;
- bool isFromBottom = shouldBeFromTheBottom(startzone, cardsToMove);
+ for (auto cardStruct : cardsToMove) {
+ Server_Card *card = cardStruct.card;
+ int originalPosition = cardStruct.position;
- if (isFromBottom) {
- std::ranges::reverse_view reversedCardsToMove{cardsToMove};
- for (auto card : reversedCardsToMove) {
- processMoveCard(ges, startzone, targetzone, card, xCoord, yCoord, xIndex, revealTopStart, revealTopTarget,
- isReversed, undoingDraw);
+ bool sourceBeingLookedAt;
+ int position = startzone->removeCard(card, sourceBeingLookedAt);
+
+ // Attachment relationships can be retained when moving a card onto the opponent's table
+ if (startzone->getName() != targetzone->getName()) {
+ // Delete all attachment relationships
+ if (card->getParentCard()) {
+ card->setParentCard(nullptr);
+ }
+
+ // Make a copy of the list because the original one gets modified during the loop
+ QList attachedCards = card->getAttachedCards();
+ for (auto &attachedCard : attachedCards) {
+ attachedCard->getZone()->getPlayer()->unattachCard(ges, attachedCard);
+ }
}
- } else {
- for (auto card : cardsToMove) {
- processMoveCard(ges, startzone, targetzone, card, xCoord, yCoord, xIndex, revealTopStart, revealTopTarget,
- isReversed, undoingDraw);
+
+ if (startzone != targetzone) {
+ // Delete all arrows from and to the card
+ for (auto *player : game->getPlayers().values()) {
+ QList arrowsToDelete;
+ for (Server_Arrow *arrow : player->getArrows()) {
+ if ((arrow->getStartCard() == card) || (arrow->getTargetItem() == card))
+ arrowsToDelete.append(arrow->getId());
+ }
+ for (int j : arrowsToDelete) {
+ player->deleteArrow(j);
+ }
+ }
+ }
+
+ if (shouldDestroyOnMove(card, startzone, targetzone)) {
+ Event_DestroyCard event;
+ event.set_zone_name(startzone->getName().toStdString());
+ event.set_card_id(static_cast(card->getId()));
+ ges.enqueueGameEvent(event, playerId);
+
+ if (Server_Card *stashedCard = card->takeStashedCard()) {
+ stashedCard->setId(newCardId());
+ ges.enqueueGameEvent(makeCreateTokenEvent(startzone, stashedCard, card->getX(), card->getY()),
+ playerId);
+ card->deleteLater();
+ card = stashedCard;
+ } else {
+ card->deleteLater();
+ card = nullptr;
+ }
+ }
+
+ if (card) {
+ ++xIndex;
+ int newX = isReversed ? targetzone->getCards().size() - xCoord + xIndex : xCoord + xIndex;
+
+ bool faceDown = shouldBeFaceDown(cardStruct, startzone, targetzone);
+
+ if (targetzone->hasCoords()) {
+ newX = targetzone->getFreeGridColumn(newX, yCoord, card->getName(), faceDown);
+ } else {
+ yCoord = 0;
+ card->resetState(targetzone->getName() == ZoneNames::STACK);
+ }
+
+ targetzone->insertCard(card, newX, yCoord);
+ int targetLookedCards = targetzone->getCardsBeingLookedAt();
+ bool sourceKnownToPlayer = isReversed || (sourceBeingLookedAt && !card->getFaceDown());
+ if (targetzone->getType() == ServerInfo_Zone::HiddenZone && targetLookedCards >= newX) {
+ if (sourceKnownToPlayer) {
+ targetLookedCards += 1;
+ } else {
+ targetLookedCards = newX;
+ }
+ targetzone->setCardsBeingLookedAt(targetLookedCards);
+ }
+
+ bool targetHiddenToOthers = faceDown || (targetzone->getType() != ServerInfo_Zone::PublicZone);
+ bool sourceHiddenToOthers = card->getFaceDown() || (startzone->getType() != ServerInfo_Zone::PublicZone);
+
+ int oldCardId = card->getId();
+ if ((faceDown && (startzone != targetzone)) || (targetzone->getPlayer() != startzone->getPlayer())) {
+ card->setId(targetzone->getPlayer()->newCardId());
+ }
+ card->setFaceDown(faceDown);
+
+ Event_MoveCard eventOthers;
+ eventOthers.set_start_player_id(startzone->getPlayer()->getPlayerId());
+ eventOthers.set_start_zone(startzone->getName().toStdString());
+ eventOthers.set_target_player_id(targetzone->getPlayer()->getPlayerId());
+ if (startzone != targetzone) {
+ eventOthers.set_target_zone(targetzone->getName().toStdString());
+ }
+ eventOthers.set_y(yCoord);
+ eventOthers.set_face_down(faceDown);
+
+ Event_MoveCard eventPrivate(eventOthers);
+ if (sourceBeingLookedAt || targetzone->getType() != ServerInfo_Zone::HiddenZone ||
+ startzone->getType() != ServerInfo_Zone::HiddenZone) {
+ eventPrivate.set_card_id(oldCardId);
+ eventPrivate.set_new_card_id(card->getId());
+ } else {
+ eventPrivate.set_card_id(-1);
+ eventPrivate.set_new_card_id(-1);
+ }
+ if (sourceKnownToPlayer || !(faceDown || targetzone->getType() == ServerInfo_Zone::HiddenZone)) {
+ QString privateCardName = card->getName();
+ eventPrivate.set_card_name(privateCardName.toStdString());
+ eventPrivate.set_new_card_provider_id(card->getProviderId().toStdString());
+ }
+ if (startzone->getType() == ServerInfo_Zone::HiddenZone) {
+ eventPrivate.set_position(position);
+ } else {
+ eventPrivate.set_position(-1);
+ }
+
+ eventPrivate.set_x(newX);
+
+ if (
+ // cards from public zones have their id known, their previous position is already known, the event does
+ // not accomodate for previous locations in zones with coordinates (which are always public)
+ (startzone->getType() != ServerInfo_Zone::PublicZone) &&
+ // other players are not allowed to be able to track which card is which in private zones like the hand
+ (startzone->getType() != ServerInfo_Zone::PrivateZone)) {
+ eventOthers.set_position(position);
+ }
+ if (
+ // other players are not allowed to be able to track which card is which in private zones like the hand
+ (targetzone->getType() != ServerInfo_Zone::PrivateZone)) {
+ eventOthers.set_x(newX);
+ }
+
+ if ((startzone->getType() == ServerInfo_Zone::PublicZone) ||
+ (targetzone->getType() == ServerInfo_Zone::PublicZone)) {
+ eventOthers.set_card_id(oldCardId);
+ if (!(sourceHiddenToOthers && targetHiddenToOthers)) {
+ QString publicCardName = card->getName();
+ eventOthers.set_card_name(publicCardName.toStdString());
+ eventOthers.set_new_card_provider_id(card->getProviderId().toStdString());
+ }
+ eventOthers.set_new_card_id(card->getId());
+ }
+
+ ges.enqueueGameEvent(eventPrivate, playerId, GameEventStorageItem::SendToPrivate, playerId);
+ ges.enqueueGameEvent(eventOthers, playerId, GameEventStorageItem::SendToOthers);
+
+ if (originalPosition == 0) {
+ revealTopStart = true;
+ }
+ if (newX == 0) {
+ revealTopTarget = true;
+ }
+
+ // handle side effects for this card
+ onCardBeingMoved(ges, cardStruct, startzone, targetzone, undoingDraw);
}
}
-
if (revealTopStart) {
revealTopCardIfNeeded(startzone, ges);
}
@@ -354,174 +462,6 @@ Response::ResponseCode Server_AbstractPlayer::moveCard(GameEventStorage &ges,
return Response::RespOk;
}
-void Server_AbstractPlayer::processMoveCard(GameEventStorage &ges,
- Server_CardZone *startzone,
- Server_CardZone *targetzone,
- MoveCardStruct cardStruct,
- int xCoord,
- int yCoord,
- int &xIndex,
- bool &revealTopStart,
- bool &revealTopTarget,
- bool isReversed,
- bool undoingDraw)
-{
- Server_Card *card = cardStruct.card;
- int originalPosition = cardStruct.position;
-
- bool sourceBeingLookedAt;
- int position = startzone->removeCard(card, sourceBeingLookedAt);
-
- // Attachment relationships can be retained when moving a card onto the opponent's table
- if (startzone->getName() != targetzone->getName()) {
- // Delete all attachment relationships
- if (card->getParentCard()) {
- card->setParentCard(nullptr);
- }
-
- // Make a copy of the list because the original one gets modified during the loop
- QList attachedCards = card->getAttachedCards();
- for (auto &attachedCard : attachedCards) {
- attachedCard->getZone()->getPlayer()->unattachCard(ges, attachedCard);
- }
- }
-
- if (startzone != targetzone) {
- // Delete all arrows from and to the card
- for (auto *player : game->getPlayers().values()) {
- QList arrowsToDelete;
- for (Server_Arrow *arrow : player->getArrows()) {
- if ((arrow->getStartCard() == card) || (arrow->getTargetItem() == card))
- arrowsToDelete.append(arrow->getId());
- }
- for (int j : arrowsToDelete) {
- player->deleteArrow(j);
- }
- }
- }
-
- if (shouldDestroyOnMove(card, startzone, targetzone)) {
- Event_DestroyCard event;
- event.set_zone_name(startzone->getName().toStdString());
- event.set_card_id(static_cast(card->getId()));
- ges.enqueueGameEvent(event, playerId);
-
- if (Server_Card *stashedCard = card->takeStashedCard()) {
- stashedCard->setId(newCardId());
- ges.enqueueGameEvent(makeCreateTokenEvent(startzone, stashedCard, card->getX(), card->getY()), playerId);
- card->deleteLater();
- card = stashedCard;
- } else {
- card->deleteLater();
- card = nullptr;
- }
- }
-
- if (card) {
- ++xIndex;
- int newX = isReversed ? targetzone->getCards().size() - xCoord + xIndex : xCoord + xIndex;
-
- bool faceDown = shouldBeFaceDown(cardStruct, startzone, targetzone);
-
- if (targetzone->hasCoords()) {
- newX = targetzone->getFreeGridColumn(newX, yCoord, card->getName(), faceDown);
- } else {
- card->resetState(targetzone->getName() == ZoneNames::STACK);
- }
-
- targetzone->insertCard(card, newX, yCoord);
- int targetLookedCards = targetzone->getCardsBeingLookedAt();
- bool sourceKnownToPlayer = isReversed || (sourceBeingLookedAt && !card->getFaceDown());
- if (targetzone->getType() == ServerInfo_Zone::HiddenZone && targetLookedCards >= newX) {
- if (sourceKnownToPlayer) {
- targetLookedCards += 1;
- } else {
- targetLookedCards = newX;
- }
- targetzone->setCardsBeingLookedAt(targetLookedCards);
- }
-
- bool targetHiddenToOthers = faceDown || (targetzone->getType() != ServerInfo_Zone::PublicZone);
- bool sourceHiddenToOthers = card->getFaceDown() || (startzone->getType() != ServerInfo_Zone::PublicZone);
-
- int oldCardId = card->getId();
- if ((faceDown && (startzone != targetzone)) || (targetzone->getPlayer() != startzone->getPlayer())) {
- card->setId(targetzone->getPlayer()->newCardId());
- }
- card->setFaceDown(faceDown);
-
- Event_MoveCard eventOthers;
- eventOthers.set_start_player_id(startzone->getPlayer()->getPlayerId());
- eventOthers.set_start_zone(startzone->getName().toStdString());
- eventOthers.set_target_player_id(targetzone->getPlayer()->getPlayerId());
- if (startzone != targetzone) {
- eventOthers.set_target_zone(targetzone->getName().toStdString());
- }
- eventOthers.set_y(yCoord);
- eventOthers.set_face_down(faceDown);
-
- Event_MoveCard eventPrivate(eventOthers);
- if (sourceBeingLookedAt || targetzone->getType() != ServerInfo_Zone::HiddenZone ||
- startzone->getType() != ServerInfo_Zone::HiddenZone) {
- eventPrivate.set_card_id(oldCardId);
- eventPrivate.set_new_card_id(card->getId());
- } else {
- eventPrivate.set_card_id(-1);
- eventPrivate.set_new_card_id(-1);
- }
- if (sourceKnownToPlayer || !(faceDown || targetzone->getType() == ServerInfo_Zone::HiddenZone)) {
- QString privateCardName = card->getName();
- eventPrivate.set_card_name(privateCardName.toStdString());
- eventPrivate.set_new_card_provider_id(card->getProviderId().toStdString());
- }
- if (startzone->getType() == ServerInfo_Zone::HiddenZone) {
- eventPrivate.set_position(position);
- } else {
- eventPrivate.set_position(-1);
- }
-
- eventPrivate.set_x(newX);
-
- if (
- // cards from public zones have their id known, their previous position is already known, the event does
- // not accomodate for previous locations in zones with coordinates (which are always public)
- (startzone->getType() != ServerInfo_Zone::PublicZone) &&
- // other players are not allowed to be able to track which card is which in private zones like the hand
- (startzone->getType() != ServerInfo_Zone::PrivateZone)) {
- eventOthers.set_position(position);
- }
- if (
- // other players are not allowed to be able to track which card is which in private zones like the hand
- (targetzone->getType() != ServerInfo_Zone::PrivateZone)) {
- eventOthers.set_x(newX);
- }
-
- if ((startzone->getType() == ServerInfo_Zone::PublicZone) ||
- (targetzone->getType() == ServerInfo_Zone::PublicZone)) {
- eventOthers.set_card_id(oldCardId);
- if (!(sourceHiddenToOthers && targetHiddenToOthers)) {
- QString publicCardName = card->getName();
- eventOthers.set_card_name(publicCardName.toStdString());
- eventOthers.set_new_card_provider_id(card->getProviderId().toStdString());
- }
- eventOthers.set_new_card_id(card->getId());
- }
-
- ges.enqueueGameEvent(eventPrivate, playerId, GameEventStorageItem::SendToPrivate, playerId);
- ges.enqueueGameEvent(eventOthers, playerId, GameEventStorageItem::SendToOthers);
-
- if (originalPosition == 0) {
- revealTopStart = true;
- }
- if (newX == 0) {
- revealTopTarget = true;
- }
-
- // handle side effects for this card
- onCardBeingMoved(ges, cardStruct, startzone, targetzone, undoingDraw);
- }
-}
-
void Server_AbstractPlayer::onCardBeingMoved(GameEventStorage &ges,
const MoveCardStruct &cardStruct,
Server_CardZone *startzone,
diff --git a/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.h b/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.h
index 9d9809298..40fe84aa1 100644
--- a/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.h
+++ b/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.h
@@ -93,19 +93,6 @@ public:
bool fixFreeSpaces = true,
bool undoingDraw = false,
bool isReversed = false);
-
- void processMoveCard(GameEventStorage &ges,
- Server_CardZone *startzone,
- Server_CardZone *targetzone,
- MoveCardStruct cardStruct,
- int xCoord,
- int yCoord,
- int &xIndex,
- bool &revealTopStart,
- bool &revealTopTarget,
- bool isReversed,
- bool undoingDraw);
-
virtual void onCardBeingMoved(GameEventStorage &ges,
const MoveCardStruct &cardStruct,
Server_CardZone *startzone,
diff --git a/oracle/src/oracleimporter.cpp b/oracle/src/oracleimporter.cpp
index 578afd98d..b5d7b9856 100644
--- a/oracle/src/oracleimporter.cpp
+++ b/oracle/src/oracleimporter.cpp
@@ -366,6 +366,8 @@ int OracleImporter::importCardsFromSet(const CardSetPtr ¤tSet, const QList
auto found_iter = splitCards.find(name + numProperty);
if (found_iter == splitCards.end()) {
splitCards.insert(name + numProperty, {{split}, name});
+ } else if (layout == "adventure" || layout == "prepare") {
+ found_iter->first.insert(0, split);
} else {
found_iter->first.append(split);
}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index fffaf1bda..c5346e59f 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -65,5 +65,4 @@ target_link_libraries(
add_subdirectory(card_zone_algorithms)
add_subdirectory(carddatabase)
add_subdirectory(loading_from_clipboard)
-add_subdirectory(movecard_tests)
add_subdirectory(oracle)
diff --git a/tests/movecard_tests/CMakeLists.txt b/tests/movecard_tests/CMakeLists.txt
deleted file mode 100755
index 769047148..000000000
--- a/tests/movecard_tests/CMakeLists.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-add_executable(reverse_card_move_test reverse_card_move_test.cpp)
-
-if(NOT GTEST_FOUND)
- add_dependencies(reverse_card_move_test gtest)
-endif()
-
-target_link_libraries(
- reverse_card_move_test
- PRIVATE libcockatrice_network_server_remote
- PRIVATE libcockatrice_rng
- PRIVATE Threads::Threads
- PRIVATE ${GTEST_BOTH_LIBRARIES}
- PRIVATE ${TEST_QT_MODULES}
-)
-
-add_test(NAME reverse_card_move_test COMMAND reverse_card_move_test)
diff --git a/tests/movecard_tests/reverse_card_move_test.cpp b/tests/movecard_tests/reverse_card_move_test.cpp
deleted file mode 100644
index 2231a7e3b..000000000
--- a/tests/movecard_tests/reverse_card_move_test.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-#include "game/server_abstract_player.h"
-#include "game/server_card.h"
-#include "game/server_cardzone.h"
-#include "game/server_game.h"
-#include "server_response_containers.h"
-#include "server_room.h"
-#include "server_test_helpers.h"
-
-#include
-#include
-#include
-#include
-#include
-
-RNG_Abstract *rng = nullptr; // this needs to be defined due to other functions in server
-
-TEST(ReverseCardMoveTest, MoveCardFromBottomTest)
-{
- ServerInfo_User user;
- user.set_name("test-user");
-
- // instantiate a fake server instance
- FakeServer server;
- Server_Room room(0, 0, "", "", "", "", false, "", {}, &server);
- Server_Game game(user, 1, "", "", 2, QList(), false, false, false, false, false, false, 20, false, &room);
- Server_AbstractPlayer player(&game, 1, user, false, nullptr);
- Server_CardZone deckZone(&player, ZoneNames::DECK, true, ServerInfo_Zone::PublicZone);
- Server_CardZone exileZone(&player, ZoneNames::EXILE, true, ServerInfo_Zone::PublicZone);
-
- // setup the deck with 20 useless cards
- for (int i = 0; i < 20; i++) {
- auto *cardUseless = new Server_Card({"Card Useless", "card-Useless"}, player.newCardId(), i, 0);
- deckZone.insertCard(cardUseless, i, 0);
- }
-
- // add 4 cards to the end of it
- auto *cardA = new Server_Card({"Card A", "card-a"}, player.newCardId(), 20, 0);
- auto *cardB = new Server_Card({"Card B", "card-b"}, player.newCardId(), 21, 0);
- auto *cardC = new Server_Card({"Card C", "card-c"}, player.newCardId(), 22, 0);
- auto *cardD = new Server_Card({"Card D", "card-d"}, player.newCardId(), 23, 0);
-
- deckZone.insertCard(cardA, 20, 0);
- deckZone.insertCard(cardB, 21, 0);
- deckZone.insertCard(cardC, 22, 0);
- deckZone.insertCard(cardD, 23, 0);
-
- // try to move them, with the expected client given order (n-3, n-2, n-1, n)
- CardToMove moveA;
- moveA.set_card_id(cardA->getId());
- CardToMove moveB;
- moveB.set_card_id(cardB->getId());
- CardToMove moveC;
- moveC.set_card_id(cardC->getId());
- CardToMove moveD;
- moveD.set_card_id(cardD->getId());
-
- QList cardsToMove = {&moveA, &moveB, &moveC, &moveD};
- GameEventStorage ges;
-
- const auto response = player.moveCard(ges, &deckZone, cardsToMove, &exileZone, 0, 0, false, false, false);
-
- EXPECT_EQ(response, Response::RespOk);
-
- int positionA;
- int positionB;
- int positionC;
- int positionD;
- // find the cards in the destination zone and check they are the right card
- EXPECT_EQ(exileZone.getCard(cardA->getId(), &positionA), cardA);
- EXPECT_EQ(exileZone.getCard(cardB->getId(), &positionB), cardB);
- EXPECT_EQ(exileZone.getCard(cardC->getId(), &positionC), cardC);
- EXPECT_EQ(exileZone.getCard(cardD->getId(), &positionD), cardD);
-
- // check that they are at the expected index
- EXPECT_EQ(cardA->getX(), 3);
- EXPECT_EQ(cardB->getX(), 2);
- EXPECT_EQ(cardC->getX(), 1);
- EXPECT_EQ(cardD->getX(), 0);
-
- // also check if the given positions are correct
- EXPECT_EQ(positionA, 3);
- EXPECT_EQ(positionB, 2);
- EXPECT_EQ(positionC, 1);
- EXPECT_EQ(positionD, 0);
-}
-
-int main(int argc, char **argv)
-{
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
diff --git a/tests/movecard_tests/server_test_helpers.h b/tests/movecard_tests/server_test_helpers.h
deleted file mode 100644
index fd2ed6c17..000000000
--- a/tests/movecard_tests/server_test_helpers.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#include "server.h"
-#include "server_database_interface.h"
-
-class MockDatabaseInterface : public Server_DatabaseInterface
-{
-public:
- AuthenticationResult checkUserPassword(Server_ProtocolHandler *,
- const QString &,
- const QString &,
- const QString &,
- QString &,
- int &,
- bool) override
- {
- return NotLoggedIn;
- }
- ServerInfo_User getUserData(const QString &, bool) override
- {
- return ServerInfo_User();
- }
- int getNextGameId() override
- {
- return 1;
- }
- int getNextReplayId() override
- {
- return 1;
- }
- int getActiveUserCount(QString) override
- {
- return 1;
- }
-};
-
-class FakeServer : public Server
-{
-public:
- FakeServer()
- {
- setDatabaseInterface(new MockDatabaseInterface());
- }
-};