Cockatrice/libcockatrice_settings/libcockatrice/settings/game_settings.cpp
BruebachL 5ea16c805f
[Server/Client/Protocol] Shuffle or reorder player seats before a game starts (#7398)
* [Protocol] Add shuffle players option and player order command/event

Adds a 'Shuffle players at start' option to game creation plus a local
player id on the game state so clients can reconcile seat changes, and a
SET_PLAYER_ORDER command (1206) with a PLAYER_ORDER_CHANGED event (2023)
so the game host can set or randomize the seating order.

Took 6 minutes

* [Server] Shuffle and reorder player seats before a game starts

Auto-shuffles the seats at game start when enabled (now for games with
two or more players instead of three or more) and handles the new
SET_PLAYER_ORDER command so the game host or a moderator can reorder or
randomize the seats before the game starts. Re-seating re-keys the
player ids while keeping the per-user game/seat routing and persistent
player records in sync, then broadcasts the new order to everyone.

* [Client] Add shuffle players option and turn order dialog

Adds the 'Shuffle players at start' checkbox to game creation and a
host-only 'Set turn order...' action that opens a dialog to reorder or
randomize the seats before the game starts. Seating changes are shown in
the game's message log.

* [Client] Move the turn order dialog strings into retranslateUi

Follows the DlgInviteToGame convention so the dialog can be retranslated
instead of freezing its strings at construction time.

* [Server] Keep player ids stable across seat shuffles

* [Client] Lay out table and turn order dialog in seat order

* [Server] Send game-joined player list in seat order

* [Client] Reword the shuffle option to match its behaviour

* [Client] Address the seat-order review comments

- Give the game setup checkboxes a row of their own so they no longer
  collide in the create-game dialog
- Rename DlgTurnOrder::randomize() to isRandomizeRequested()
- Document what the ids in GameState::seatOrder mean
- Keep "Set turn order..." in sync with the game: hidden for non-hosts
  and once the game has started, re-shown when the game ends or hosting
  moves to the local player (new GameState::hostChanged signal)

* [Client] Do not preview a randomized turn order

Randomizing is a request to the server, not a local shuffle. Shuffling the
list locally meant the dialog showed an order the server then discarded, and
let the host re-open it until a favourable order appeared. The dialog now
switches to a mode that says the server will randomize and toggles back to the
manual list on request.

* [Client] Let moderators set the turn order

The server accepts SET_PLAYER_ORDER from the host or a moderator, but the
client hid the action from everyone except the host, making the moderator
branch unreachable. Visibility and the handler now share canSetTurnOrder().

* [Server] Rely on the player order event instead of a full state resend

cmdSetPlayerOrder re-sent the whole game state after reseating, so every
client reloaded its deck view mid-lobby for no reason. The new seating reaches
clients through the Event_PlayerOrderChanged that reseatPlayers broadcasts.

* [Client] Show random turn order in the game selector

The restrictions column listed "open decklists" but not the new seating
option, so a joining player had no way to see that seats will be randomized
each game. Game info already shows the disabled checkbox.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-11-04 15:44:50 +01:00

182 lines
4.5 KiB
C++

#include "game_settings.h"
#include "libcockatrice/settings/settings_manager.h"
#include <QVariant>
class QObject;
GameSettings::GameSettings(const QString &settingPath, QObject *parent)
: SettingsManager(settingPath + "game.ini", QString(), QString(), parent)
{
}
QString GameSettings::getGameDescription() const
{
return getValue("gameDescription", "game").toString();
}
int GameSettings::getMaxPlayers() const
{
return getValue("maxPlayers", "game", QString(), 2).toInt();
}
QString GameSettings::getGameTypes() const
{
return getValue("gameTypes", "game").toString();
}
bool GameSettings::getOnlyBuddies() const
{
return getValue("onlyBuddies", "game").toBool();
}
bool GameSettings::getOnlyRegistered() const
{
return getValue("onlyRegistered", "game").toBool();
}
bool GameSettings::getSpectatorsAllowed() const
{
return getValue("spectatorsAllowed", "game").toBool();
}
bool GameSettings::getSpectatorsNeedPassword() const
{
return getValue("spectatorsNeedPassword", "game").toBool();
}
bool GameSettings::getSpectatorsCanTalk() const
{
return getValue("spectatorsCanTalk", "game").toBool();
}
bool GameSettings::getSpectatorsCanSeeEverything() const
{
return getValue("spectatorsCanSeeEverything", "game").toBool();
}
bool GameSettings::getCreateGameAsSpectator() const
{
return getValue("createGameAsSpectator", "game").toBool();
}
int GameSettings::getDefaultStartingLifeTotal() const
{
return getValue("defaultStartingLifeTotal", "game", QString(), 20).toInt();
}
bool GameSettings::getShareDecklistsOnLoad() const
{
return getValue("shareDecklistsOnLoad", "game").toBool();
}
bool GameSettings::getShufflePlayers() const
{
return getValue("shuffleplayers", "game").toBool();
}
bool GameSettings::getRememberGameSettings() const
{
return getValue("rememberGameSettings", "game", QString(), true).toBool();
}
bool GameSettings::getLocalGameRememberSettings() const
{
return getValue("rememberSettings", "localgameoptions").toBool();
}
int GameSettings::getLocalGameMaxPlayers() const
{
return getValue("maxPlayers", "localgameoptions", QString(), 1).toInt();
}
int GameSettings::getLocalGameStartingLifeTotal() const
{
return getValue("startingLifeTotal", "localgameoptions", QString(), 20).toInt();
}
void GameSettings::setGameDescription(const QString &_gameDescription)
{
setValue(_gameDescription, "gameDescription", "game");
}
void GameSettings::setMaxPlayers(int _maxPlayers)
{
setValue(_maxPlayers, "maxPlayers", "game");
}
void GameSettings::setGameTypes(const QString &_gameTypes)
{
setValue(_gameTypes, "gameTypes", "game");
}
void GameSettings::setOnlyBuddies(bool _onlyBuddies)
{
setValue(_onlyBuddies, "onlyBuddies", "game");
}
void GameSettings::setOnlyRegistered(bool _onlyRegistered)
{
setValue(_onlyRegistered, "onlyRegistered", "game");
}
void GameSettings::setSpectatorsAllowed(bool _spectatorsAllowed)
{
setValue(_spectatorsAllowed, "spectatorsAllowed", "game");
}
void GameSettings::setSpectatorsNeedPassword(bool _spectatorsNeedPassword)
{
setValue(_spectatorsNeedPassword, "spectatorsNeedPassword", "game");
}
void GameSettings::setSpectatorsCanTalk(bool _spectatorsCanTalk)
{
setValue(_spectatorsCanTalk, "spectatorsCanTalk", "game");
}
void GameSettings::setSpectatorsCanSeeEverything(bool _spectatorsCanSeeEverything)
{
setValue(_spectatorsCanSeeEverything, "spectatorsCanSeeEverything", "game");
}
void GameSettings::setCreateGameAsSpectator(bool _createGameAsSpectator)
{
setValue(_createGameAsSpectator, "createGameAsSpectator", "game");
}
void GameSettings::setDefaultStartingLifeTotal(int _defaultStartingLifeTotal)
{
setValue(_defaultStartingLifeTotal, "defaultStartingLifeTotal", "game");
}
void GameSettings::setShareDecklistsOnLoad(bool _shareDecklistsOnLoad)
{
setValue(_shareDecklistsOnLoad, "shareDecklistsOnLoad", "game");
}
void GameSettings::setShufflePlayers(bool _shufflePlayers)
{
setValue(_shufflePlayers, "shuffleplayers", "game");
}
void GameSettings::setRememberGameSettings(bool _rememberGameSettings)
{
setValue(_rememberGameSettings, "rememberGameSettings", "game");
}
void GameSettings::setLocalGameRememberSettings(bool value)
{
setValue(value, "rememberSettings", "localgameoptions");
}
void GameSettings::setLocalGameMaxPlayers(int value)
{
setValue(value, "maxPlayers", "localgameoptions");
}
void GameSettings::setLocalGameStartingLifeTotal(int value)
{
setValue(value, "startingLifeTotal", "localgameoptions");
}