diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt index d675b809d..1ca3c77c2 100644 --- a/cockatrice/CMakeLists.txt +++ b/cockatrice/CMakeLists.txt @@ -39,6 +39,7 @@ set(cockatrice_SOURCES src/interface/widgets/dialogs/dlg_load_deck_from_clipboard.cpp src/interface/widgets/dialogs/dlg_load_deck_from_website.cpp src/interface/widgets/dialogs/dlg_load_remote_deck.cpp + src/interface/widgets/dialogs/dlg_local_game_options.cpp src/interface/widgets/dialogs/dlg_manage_sets.cpp src/interface/widgets/dialogs/dlg_register.cpp src/interface/widgets/dialogs/dlg_select_set_for_cards.cpp diff --git a/cockatrice/src/client/settings/cache_settings.cpp b/cockatrice/src/client/settings/cache_settings.cpp index e7a5d114e..1d8121b19 100644 --- a/cockatrice/src/client/settings/cache_settings.cpp +++ b/cockatrice/src/client/settings/cache_settings.cpp @@ -385,6 +385,13 @@ SettingsCache::SettingsCache() defaultStartingLifeTotal = settings->value("game/defaultstartinglifetotal", 20).toInt(); shareDecklistsOnLoad = settings->value("game/sharedecklistsonload", false).toBool(); rememberGameSettings = settings->value("game/remembergamesettings", true).toBool(); + + // Local game settings use "localgameoptions/" prefix to keep them separate + // from server game settings which use "game/" prefix + localGameRememberSettings = settings->value("localgameoptions/remembersettings", false).toBool(); + localGameMaxPlayers = settings->value("localgameoptions/maxplayers", 1).toInt(); + localGameStartingLifeTotal = settings->value("localgameoptions/startinglifetotal", 20).toInt(); + clientID = settings->value("personal/clientid", CLIENT_INFO_NOT_SET).toString(); clientVersion = settings->value("personal/clientversion", CLIENT_INFO_NOT_SET).toString(); } @@ -1242,6 +1249,24 @@ void SettingsCache::setRememberGameSettings(const bool _rememberGameSettings) settings->setValue("game/remembergamesettings", rememberGameSettings); } +void SettingsCache::setLocalGameRememberSettings(bool value) +{ + localGameRememberSettings = value; + settings->setValue("localgameoptions/remembersettings", value); +} + +void SettingsCache::setLocalGameMaxPlayers(int value) +{ + localGameMaxPlayers = value; + settings->setValue("localgameoptions/maxplayers", value); +} + +void SettingsCache::setLocalGameStartingLifeTotal(int value) +{ + localGameStartingLifeTotal = value; + settings->setValue("localgameoptions/startinglifetotal", value); +} + void SettingsCache::setNotifyAboutUpdate(QT_STATE_CHANGED_T _notifyaboutupdate) { notifyAboutUpdates = static_cast(_notifyaboutupdate); diff --git a/cockatrice/src/client/settings/cache_settings.h b/cockatrice/src/client/settings/cache_settings.h index 5c5054105..2bbf85352 100644 --- a/cockatrice/src/client/settings/cache_settings.h +++ b/cockatrice/src/client/settings/cache_settings.h @@ -330,6 +330,12 @@ private: [[nodiscard]] QString getSafeConfigFilePath(QString configEntry, QString defaultPath) const; void loadPaths(); bool rememberGameSettings; + + // Local game settings (separate from server game settings in game/*) + bool localGameRememberSettings; + int localGameMaxPlayers; + int localGameStartingLifeTotal; + QList releaseChannels; bool isPortableBuild; bool roundCardCorners; @@ -862,6 +868,18 @@ public: { return rememberGameSettings; } + [[nodiscard]] bool getLocalGameRememberSettings() const + { + return localGameRememberSettings; + } + [[nodiscard]] int getLocalGameMaxPlayers() const + { + return localGameMaxPlayers; + } + [[nodiscard]] int getLocalGameStartingLifeTotal() const + { + return localGameStartingLifeTotal; + } [[nodiscard]] int getKeepAlive() const override { return keepalive; @@ -1089,6 +1107,9 @@ public slots: void setDefaultStartingLifeTotal(const int _defaultStartingLifeTotal); void setShareDecklistsOnLoad(const bool _shareDecklistsOnLoad); void setRememberGameSettings(const bool _rememberGameSettings); + void setLocalGameRememberSettings(bool value); + void setLocalGameMaxPlayers(int value); + void setLocalGameStartingLifeTotal(int value); void setCheckUpdatesOnStartup(QT_STATE_CHANGED_T value); void setStartupCardUpdateCheckPromptForUpdate(bool value); void setStartupCardUpdateCheckAlwaysUpdate(bool value); diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_local_game_options.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_local_game_options.cpp new file mode 100644 index 000000000..52466ff10 --- /dev/null +++ b/cockatrice/src/interface/widgets/dialogs/dlg_local_game_options.cpp @@ -0,0 +1,83 @@ +#include "dlg_local_game_options.h" + +#include "../../../client/settings/cache_settings.h" + +#include +#include +#include +#include +#include +#include +#include + +DlgLocalGameOptions::DlgLocalGameOptions(QWidget *parent) : QDialog(parent) +{ + numberPlayersLabel = new QLabel(tr("Players:"), this); + numberPlayersEdit = new QSpinBox(this); + numberPlayersEdit->setMinimum(1); + numberPlayersEdit->setMaximum(8); + numberPlayersEdit->setValue(1); + numberPlayersLabel->setBuddy(numberPlayersEdit); + + auto *generalGrid = new QGridLayout; + generalGrid->addWidget(numberPlayersLabel, 0, 0); + generalGrid->addWidget(numberPlayersEdit, 0, 1); + generalGroupBox = new QGroupBox(tr("General"), this); + generalGroupBox->setLayout(generalGrid); + + startingLifeTotalLabel = new QLabel(tr("Starting life total:"), this); + startingLifeTotalEdit = new QSpinBox(this); + startingLifeTotalEdit->setMinimum(1); + startingLifeTotalEdit->setMaximum(99999); + startingLifeTotalEdit->setValue(20); + startingLifeTotalLabel->setBuddy(startingLifeTotalEdit); + + auto *gameSetupGrid = new QGridLayout; + gameSetupGrid->addWidget(startingLifeTotalLabel, 0, 0); + gameSetupGrid->addWidget(startingLifeTotalEdit, 0, 1); + gameSetupOptionsGroupBox = new QGroupBox(tr("Game setup options"), this); + gameSetupOptionsGroupBox->setLayout(gameSetupGrid); + + rememberSettingsCheckBox = new QCheckBox(tr("Remember settings"), this); + + buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); + connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgLocalGameOptions::actOK); + connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgLocalGameOptions::reject); + + auto *mainLayout = new QVBoxLayout; + mainLayout->addWidget(generalGroupBox); + mainLayout->addWidget(gameSetupOptionsGroupBox); + mainLayout->addWidget(rememberSettingsCheckBox); + mainLayout->addWidget(buttonBox); + setLayout(mainLayout); + + rememberSettingsCheckBox->setChecked(SettingsCache::instance().getLocalGameRememberSettings()); + if (rememberSettingsCheckBox->isChecked()) { + numberPlayersEdit->setValue(SettingsCache::instance().getLocalGameMaxPlayers()); + startingLifeTotalEdit->setValue(SettingsCache::instance().getLocalGameStartingLifeTotal()); + } + + setWindowTitle(tr("Local game options")); + setFixedHeight(sizeHint().height()); + + numberPlayersEdit->setFocus(); +} + +void DlgLocalGameOptions::actOK() +{ + SettingsCache::instance().setLocalGameRememberSettings(rememberSettingsCheckBox->isChecked()); + if (rememberSettingsCheckBox->isChecked()) { + SettingsCache::instance().setLocalGameMaxPlayers(numberPlayersEdit->value()); + SettingsCache::instance().setLocalGameStartingLifeTotal(startingLifeTotalEdit->value()); + } + + accept(); +} + +LocalGameOptions DlgLocalGameOptions::getOptions() const +{ + return LocalGameOptions{ + .numberPlayers = numberPlayersEdit->value(), + .startingLifeTotal = startingLifeTotalEdit->value(), + }; +} diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_local_game_options.h b/cockatrice/src/interface/widgets/dialogs/dlg_local_game_options.h new file mode 100644 index 000000000..4307581a4 --- /dev/null +++ b/cockatrice/src/interface/widgets/dialogs/dlg_local_game_options.h @@ -0,0 +1,53 @@ +/** + * @file dlg_local_game_options.h + * @ingroup RoomDialogs + * @brief Dialog for configuring local game options. + * + * Provides a user interface for setting up local games with configurable + * number of players and starting life total. + */ + +#ifndef DLG_LOCAL_GAME_OPTIONS_H +#define DLG_LOCAL_GAME_OPTIONS_H + +#include + +struct LocalGameOptions +{ + int numberPlayers = 1; + int startingLifeTotal = 20; +}; + +class QCheckBox; +class QDialogButtonBox; +class QGroupBox; +class QLabel; +class QSpinBox; + +class DlgLocalGameOptions : public QDialog +{ + Q_OBJECT +public: + explicit DlgLocalGameOptions(QWidget *parent = nullptr); + + [[nodiscard]] LocalGameOptions getOptions() const; + +private slots: + void actOK(); + +private: + QGroupBox *generalGroupBox; + QGroupBox *gameSetupOptionsGroupBox; + + QLabel *numberPlayersLabel; + QSpinBox *numberPlayersEdit; + + QLabel *startingLifeTotalLabel; + QSpinBox *startingLifeTotalEdit; + + QCheckBox *rememberSettingsCheckBox; + + QDialogButtonBox *buttonBox; +}; + +#endif // DLG_LOCAL_GAME_OPTIONS_H diff --git a/cockatrice/src/interface/window_main.cpp b/cockatrice/src/interface/window_main.cpp index 3724ff29d..fbba6c3f5 100644 --- a/cockatrice/src/interface/window_main.cpp +++ b/cockatrice/src/interface/window_main.cpp @@ -27,6 +27,7 @@ #include "../interface/widgets/dialogs/dlg_forgot_password_challenge.h" #include "../interface/widgets/dialogs/dlg_forgot_password_request.h" #include "../interface/widgets/dialogs/dlg_forgot_password_reset.h" +#include "../interface/widgets/dialogs/dlg_local_game_options.h" #include "../interface/widgets/dialogs/dlg_manage_sets.h" #include "../interface/widgets/dialogs/dlg_register.h" #include "../interface/widgets/dialogs/dlg_settings.h" @@ -49,7 +50,6 @@ #include #include #include -#include #include #include #include @@ -225,16 +225,15 @@ void MainWindow::actDisconnect() void MainWindow::actSinglePlayer() { - bool ok; - int numberPlayers = - QInputDialog::getInt(this, tr("Number of players"), tr("Please enter the number of players."), 1, 1, 8, 1, &ok); - if (!ok) + DlgLocalGameOptions dlg(this); + if (dlg.exec() != QDialog::Accepted) { return; + } - startLocalGame(numberPlayers); + startLocalGame(dlg.getOptions()); } -void MainWindow::startLocalGame(int numberPlayers) +void MainWindow::startLocalGame(const LocalGameOptions &options) { aConnect->setEnabled(false); aRegister->setEnabled(false); @@ -248,7 +247,7 @@ void MainWindow::startLocalGame(int numberPlayers) QList localClients; localClients.append(mainClient); - for (int i = 0; i < numberPlayers - 1; ++i) { + for (int i = 0; i < options.numberPlayers - 1; ++i) { LocalServerInterface *slaveLsi = localServer->newConnection(); LocalClient *slaveClient = new LocalClient(slaveLsi, tr("Player %1").arg(i + 2), SettingsCache::instance().getClientID(), this); @@ -257,7 +256,8 @@ void MainWindow::startLocalGame(int numberPlayers) tabSupervisor->startLocal(localClients); Command_CreateGame createCommand; - createCommand.set_max_players(static_cast(numberPlayers)); + createCommand.set_max_players(static_cast(options.numberPlayers)); + createCommand.set_starting_life_total(options.startingLifeTotal); mainClient->sendCommand(LocalClient::prepareRoomCommand(createCommand, 0)); } @@ -913,7 +913,9 @@ MainWindow::MainWindow(QWidget *parent) void MainWindow::startupConfigCheck() { if (SettingsCache::instance().debug().getLocalGameOnStartup()) { - startLocalGame(SettingsCache::instance().debug().getLocalGamePlayerCount()); + LocalGameOptions options; + options.numberPlayers = SettingsCache::instance().debug().getLocalGamePlayerCount(); + startLocalGame(options); } if (SettingsCache::instance().getCheckUpdatesOnStartup()) { diff --git a/cockatrice/src/interface/window_main.h b/cockatrice/src/interface/window_main.h index 75b0f5062..ed6de5b0d 100644 --- a/cockatrice/src/interface/window_main.h +++ b/cockatrice/src/interface/window_main.h @@ -25,6 +25,8 @@ #ifndef WINDOW_H #define WINDOW_H +#include "widgets/dialogs/dlg_local_game_options.h" + #include #include #include @@ -137,7 +139,7 @@ private: void createCardUpdateProcess(bool background = false); void exitCardDatabaseUpdate(); - void startLocalGame(int numberPlayers); + void startLocalGame(const LocalGameOptions &options); QList tabMenus; QMenu *cockatriceMenu, *dbMenu, *tabsMenu, *helpMenu, *trayIconMenu; diff --git a/doc/doxygen/extra-pages/user_documentation/index.md b/doc/doxygen/extra-pages/user_documentation/index.md index 3f10a0ac6..d7e9d529d 100644 --- a/doc/doxygen/extra-pages/user_documentation/index.md +++ b/doc/doxygen/extra-pages/user_documentation/index.md @@ -1,5 +1,5 @@ @page user_reference User Reference - + ## Deck Management - @subpage creating_decks