mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-13 21:40:00 -08:00
[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.
This commit is contained in:
parent
d2d65836ab
commit
17a1f8cf78
15 changed files with 312 additions and 1 deletions
|
|
@ -56,6 +56,7 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/dialogs/dlg_settings.cpp
|
src/interface/widgets/dialogs/dlg_settings.cpp
|
||||||
src/interface/widgets/dialogs/dlg_startup_card_check.cpp
|
src/interface/widgets/dialogs/dlg_startup_card_check.cpp
|
||||||
src/interface/widgets/dialogs/dlg_tip_of_the_day.cpp
|
src/interface/widgets/dialogs/dlg_tip_of_the_day.cpp
|
||||||
|
src/interface/widgets/dialogs/dlg_turn_order.cpp
|
||||||
src/interface/widgets/dialogs/dlg_update.cpp
|
src/interface/widgets/dialogs/dlg_update.cpp
|
||||||
src/interface/widgets/dialogs/dlg_view_log.cpp
|
src/interface/widgets/dialogs/dlg_view_log.cpp
|
||||||
src/interface/widgets/dialogs/override_printing_warning.cpp
|
src/interface/widgets/dialogs/override_printing_warning.cpp
|
||||||
|
|
|
||||||
|
|
@ -605,6 +605,20 @@ void MessageLogWidget::logReverseTurn(PlayerLogic *player, bool reversed)
|
||||||
.arg(reversed ? tr("reversed") : tr("normal")));
|
.arg(reversed ? tr("reversed") : tr("normal")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MessageLogWidget::logTurnOrderChanged(QStringList playerNames, bool randomized)
|
||||||
|
{
|
||||||
|
QStringList sanitizedNames;
|
||||||
|
for (const QString &name : playerNames) {
|
||||||
|
sanitizedNames.append(sanitizeHtml(name));
|
||||||
|
}
|
||||||
|
const QString order = sanitizedNames.join(" -> ");
|
||||||
|
if (randomized) {
|
||||||
|
appendHtmlServerMessage(tr("Randomized turn order: %1.").arg(order));
|
||||||
|
} else {
|
||||||
|
appendHtmlServerMessage(tr("New turn order set: %1.").arg(order));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MessageLogWidget::logRollDie(PlayerLogic *player, int sides, const QList<uint> &rolls)
|
void MessageLogWidget::logRollDie(PlayerLogic *player, int sides, const QList<uint> &rolls)
|
||||||
{
|
{
|
||||||
if (rolls.length() == 1) {
|
if (rolls.length() == 1) {
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,7 @@ public slots:
|
||||||
int amount,
|
int amount,
|
||||||
bool isLentToAnotherPlayer);
|
bool isLentToAnotherPlayer);
|
||||||
void logReverseTurn(PlayerLogic *player, bool reversed);
|
void logReverseTurn(PlayerLogic *player, bool reversed);
|
||||||
|
void logTurnOrderChanged(QStringList playerNames, bool randomized);
|
||||||
void logRollDie(PlayerLogic *player, int sides, const QList<uint> &rolls);
|
void logRollDie(PlayerLogic *player, int sides, const QList<uint> &rolls);
|
||||||
void logSay(PlayerLogic *player, QString message);
|
void logSay(PlayerLogic *player, QString message);
|
||||||
void logSetActivePhase(int phase);
|
void logSetActivePhase(int phase);
|
||||||
|
|
|
||||||
|
|
@ -116,12 +116,15 @@ void DlgCreateGame::sharedCtor()
|
||||||
|
|
||||||
shareDecklistsOnLoadCheckBox = new QCheckBox(tr("Open decklists in lobby"));
|
shareDecklistsOnLoadCheckBox = new QCheckBox(tr("Open decklists in lobby"));
|
||||||
|
|
||||||
|
shufflePlayersCheckBox = new QCheckBox(tr("Shuffle players at start"));
|
||||||
|
|
||||||
createGameAsJudgeCheckBox = new QCheckBox(tr("Create game as judge"));
|
createGameAsJudgeCheckBox = new QCheckBox(tr("Create game as judge"));
|
||||||
|
|
||||||
auto *gameSetupOptionsLayout = new QGridLayout;
|
auto *gameSetupOptionsLayout = new QGridLayout;
|
||||||
gameSetupOptionsLayout->addWidget(startingLifeTotalLabel, 0, 0);
|
gameSetupOptionsLayout->addWidget(startingLifeTotalLabel, 0, 0);
|
||||||
gameSetupOptionsLayout->addWidget(startingLifeTotalEdit, 0, 1);
|
gameSetupOptionsLayout->addWidget(startingLifeTotalEdit, 0, 1);
|
||||||
gameSetupOptionsLayout->addWidget(shareDecklistsOnLoadCheckBox, 1, 0);
|
gameSetupOptionsLayout->addWidget(shareDecklistsOnLoadCheckBox, 1, 0);
|
||||||
|
gameSetupOptionsLayout->addWidget(shufflePlayersCheckBox, 1, 1);
|
||||||
if (room && room->getUserInfo()->user_level() & ServerInfo_User::IsJudge) {
|
if (room && room->getUserInfo()->user_level() & ServerInfo_User::IsJudge) {
|
||||||
gameSetupOptionsLayout->addWidget(createGameAsJudgeCheckBox, 2, 0);
|
gameSetupOptionsLayout->addWidget(createGameAsJudgeCheckBox, 2, 0);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -184,6 +187,7 @@ DlgCreateGame::DlgCreateGame(TabRoom *_room, const QMap<int, QString> &_gameType
|
||||||
createGameAsSpectatorCheckBox->setChecked(SettingsCache::instance().game().getCreateGameAsSpectator());
|
createGameAsSpectatorCheckBox->setChecked(SettingsCache::instance().game().getCreateGameAsSpectator());
|
||||||
startingLifeTotalEdit->setValue(SettingsCache::instance().game().getDefaultStartingLifeTotal());
|
startingLifeTotalEdit->setValue(SettingsCache::instance().game().getDefaultStartingLifeTotal());
|
||||||
shareDecklistsOnLoadCheckBox->setChecked(SettingsCache::instance().game().getShareDecklistsOnLoad());
|
shareDecklistsOnLoadCheckBox->setChecked(SettingsCache::instance().game().getShareDecklistsOnLoad());
|
||||||
|
shufflePlayersCheckBox->setChecked(SettingsCache::instance().game().getShufflePlayers());
|
||||||
|
|
||||||
if (!rememberGameSettings->isChecked()) {
|
if (!rememberGameSettings->isChecked()) {
|
||||||
actReset();
|
actReset();
|
||||||
|
|
@ -217,6 +221,7 @@ DlgCreateGame::DlgCreateGame(const ServerInfo_Game &gameInfo, const QMap<int, QS
|
||||||
createGameAsSpectatorCheckBox->setEnabled(false);
|
createGameAsSpectatorCheckBox->setEnabled(false);
|
||||||
startingLifeTotalEdit->setEnabled(false);
|
startingLifeTotalEdit->setEnabled(false);
|
||||||
shareDecklistsOnLoadCheckBox->setEnabled(false);
|
shareDecklistsOnLoadCheckBox->setEnabled(false);
|
||||||
|
shufflePlayersCheckBox->setEnabled(false);
|
||||||
|
|
||||||
descriptionEdit->setText(QString::fromStdString(gameInfo.description()));
|
descriptionEdit->setText(QString::fromStdString(gameInfo.description()));
|
||||||
maxPlayersEdit->setValue(gameInfo.max_players());
|
maxPlayersEdit->setValue(gameInfo.max_players());
|
||||||
|
|
@ -227,6 +232,7 @@ DlgCreateGame::DlgCreateGame(const ServerInfo_Game &gameInfo, const QMap<int, QS
|
||||||
spectatorsCanTalkCheckBox->setChecked(gameInfo.spectators_can_chat());
|
spectatorsCanTalkCheckBox->setChecked(gameInfo.spectators_can_chat());
|
||||||
spectatorsSeeEverythingCheckBox->setChecked(gameInfo.spectators_omniscient());
|
spectatorsSeeEverythingCheckBox->setChecked(gameInfo.spectators_omniscient());
|
||||||
shareDecklistsOnLoadCheckBox->setChecked(gameInfo.share_decklists_on_load());
|
shareDecklistsOnLoadCheckBox->setChecked(gameInfo.share_decklists_on_load());
|
||||||
|
shufflePlayersCheckBox->setChecked(gameInfo.shuffle_players());
|
||||||
|
|
||||||
QSet<int> types;
|
QSet<int> types;
|
||||||
for (int i = 0; i < gameInfo.game_types_size(); ++i) {
|
for (int i = 0; i < gameInfo.game_types_size(); ++i) {
|
||||||
|
|
@ -264,6 +270,7 @@ void DlgCreateGame::actReset()
|
||||||
|
|
||||||
startingLifeTotalEdit->setValue(20);
|
startingLifeTotalEdit->setValue(20);
|
||||||
shareDecklistsOnLoadCheckBox->setChecked(false);
|
shareDecklistsOnLoadCheckBox->setChecked(false);
|
||||||
|
shufflePlayersCheckBox->setChecked(false);
|
||||||
createGameAsJudgeCheckBox->setChecked(false);
|
createGameAsJudgeCheckBox->setChecked(false);
|
||||||
|
|
||||||
QMapIterator<int, QRadioButton *> gameTypeCheckBoxIterator(gameTypeCheckBoxes);
|
QMapIterator<int, QRadioButton *> gameTypeCheckBoxIterator(gameTypeCheckBoxes);
|
||||||
|
|
@ -294,6 +301,7 @@ void DlgCreateGame::actOK()
|
||||||
cmd.set_join_as_spectator(createGameAsSpectatorCheckBox->isChecked());
|
cmd.set_join_as_spectator(createGameAsSpectatorCheckBox->isChecked());
|
||||||
cmd.set_starting_life_total(startingLifeTotalEdit->value());
|
cmd.set_starting_life_total(startingLifeTotalEdit->value());
|
||||||
cmd.set_share_decklists_on_load(shareDecklistsOnLoadCheckBox->isChecked());
|
cmd.set_share_decklists_on_load(shareDecklistsOnLoadCheckBox->isChecked());
|
||||||
|
cmd.set_shuffle_players(shufflePlayersCheckBox->isChecked());
|
||||||
|
|
||||||
auto _gameTypes = QString();
|
auto _gameTypes = QString();
|
||||||
QMapIterator<int, QRadioButton *> gameTypeCheckBoxIterator(gameTypeCheckBoxes);
|
QMapIterator<int, QRadioButton *> gameTypeCheckBoxIterator(gameTypeCheckBoxes);
|
||||||
|
|
@ -318,6 +326,7 @@ void DlgCreateGame::actOK()
|
||||||
SettingsCache::instance().game().setCreateGameAsSpectator(createGameAsSpectatorCheckBox->isChecked());
|
SettingsCache::instance().game().setCreateGameAsSpectator(createGameAsSpectatorCheckBox->isChecked());
|
||||||
SettingsCache::instance().game().setDefaultStartingLifeTotal(startingLifeTotalEdit->value());
|
SettingsCache::instance().game().setDefaultStartingLifeTotal(startingLifeTotalEdit->value());
|
||||||
SettingsCache::instance().game().setShareDecklistsOnLoad(shareDecklistsOnLoadCheckBox->isChecked());
|
SettingsCache::instance().game().setShareDecklistsOnLoad(shareDecklistsOnLoadCheckBox->isChecked());
|
||||||
|
SettingsCache::instance().game().setShufflePlayers(shufflePlayersCheckBox->isChecked());
|
||||||
SettingsCache::instance().game().setGameTypes(_gameTypes);
|
SettingsCache::instance().game().setGameTypes(_gameTypes);
|
||||||
}
|
}
|
||||||
PendingCommand *pend = room->prepareRoomCommand(cmd);
|
PendingCommand *pend = room->prepareRoomCommand(cmd);
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ private:
|
||||||
QCheckBox *spectatorsAllowedCheckBox, *spectatorsNeedPasswordCheckBox, *spectatorsCanTalkCheckBox,
|
QCheckBox *spectatorsAllowedCheckBox, *spectatorsNeedPasswordCheckBox, *spectatorsCanTalkCheckBox,
|
||||||
*spectatorsSeeEverythingCheckBox, *createGameAsJudgeCheckBox, *createGameAsSpectatorCheckBox;
|
*spectatorsSeeEverythingCheckBox, *createGameAsJudgeCheckBox, *createGameAsSpectatorCheckBox;
|
||||||
QCheckBox *shareDecklistsOnLoadCheckBox;
|
QCheckBox *shareDecklistsOnLoadCheckBox;
|
||||||
|
QCheckBox *shufflePlayersCheckBox;
|
||||||
QDialogButtonBox *buttonBox;
|
QDialogButtonBox *buttonBox;
|
||||||
QPushButton *clearButton;
|
QPushButton *clearButton;
|
||||||
QCheckBox *rememberGameSettings;
|
QCheckBox *rememberGameSettings;
|
||||||
|
|
|
||||||
114
cockatrice/src/interface/widgets/dialogs/dlg_turn_order.cpp
Normal file
114
cockatrice/src/interface/widgets/dialogs/dlg_turn_order.cpp
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
#include "dlg_turn_order.h"
|
||||||
|
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QListWidget>
|
||||||
|
#include <QListWidgetItem>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QRandomGenerator>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
DlgTurnOrder::DlgTurnOrder(const QStringList &_playerNames, QWidget *parent)
|
||||||
|
: QDialog(parent), randomizeRequested(false)
|
||||||
|
{
|
||||||
|
listWidget = new QListWidget(this);
|
||||||
|
listWidget->addItems(_playerNames);
|
||||||
|
listWidget->setCurrentRow(0);
|
||||||
|
connect(listWidget, &QListWidget::currentRowChanged, this, &DlgTurnOrder::selectionChanged);
|
||||||
|
|
||||||
|
moveUpButton = new QPushButton(tr("Move up"), this);
|
||||||
|
connect(moveUpButton, &QPushButton::clicked, this, &DlgTurnOrder::actMoveUp);
|
||||||
|
moveDownButton = new QPushButton(tr("Move down"), this);
|
||||||
|
connect(moveDownButton, &QPushButton::clicked, this, &DlgTurnOrder::actMoveDown);
|
||||||
|
randomizeButton = new QPushButton(tr("Randomize"), this);
|
||||||
|
connect(randomizeButton, &QPushButton::clicked, this, &DlgTurnOrder::actRandomize);
|
||||||
|
|
||||||
|
auto *buttonColumn = new QVBoxLayout;
|
||||||
|
buttonColumn->addWidget(moveUpButton);
|
||||||
|
buttonColumn->addWidget(moveDownButton);
|
||||||
|
buttonColumn->addWidget(randomizeButton);
|
||||||
|
buttonColumn->addStretch();
|
||||||
|
|
||||||
|
auto *listLayout = new QHBoxLayout;
|
||||||
|
listLayout->addWidget(listWidget);
|
||||||
|
listLayout->addLayout(buttonColumn);
|
||||||
|
|
||||||
|
auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
|
connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgTurnOrder::actOk);
|
||||||
|
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgTurnOrder::reject);
|
||||||
|
|
||||||
|
auto *mainLayout = new QVBoxLayout;
|
||||||
|
mainLayout->addLayout(listLayout);
|
||||||
|
mainLayout->addWidget(buttonBox);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
updateButtons();
|
||||||
|
setWindowTitle(tr("Set turn order"));
|
||||||
|
setMinimumWidth(300);
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList DlgTurnOrder::order() const
|
||||||
|
{
|
||||||
|
QStringList playerNames;
|
||||||
|
for (int i = 0; i < listWidget->count(); ++i) {
|
||||||
|
playerNames.append(listWidget->item(i)->text());
|
||||||
|
}
|
||||||
|
return playerNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DlgTurnOrder::moveSelected(int delta)
|
||||||
|
{
|
||||||
|
const int row = listWidget->currentRow();
|
||||||
|
const int newRow = row + delta;
|
||||||
|
if (row < 0 || newRow < 0 || newRow >= listWidget->count()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QListWidgetItem *item = listWidget->takeItem(row);
|
||||||
|
listWidget->insertItem(newRow, item);
|
||||||
|
listWidget->setCurrentRow(newRow);
|
||||||
|
randomizeRequested = false;
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DlgTurnOrder::updateButtons()
|
||||||
|
{
|
||||||
|
const int row = listWidget->currentRow();
|
||||||
|
const int count = listWidget->count();
|
||||||
|
moveUpButton->setEnabled(row > 0);
|
||||||
|
moveDownButton->setEnabled(row >= 0 && row < count - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DlgTurnOrder::actMoveUp()
|
||||||
|
{
|
||||||
|
moveSelected(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DlgTurnOrder::actMoveDown()
|
||||||
|
{
|
||||||
|
moveSelected(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DlgTurnOrder::actRandomize()
|
||||||
|
{
|
||||||
|
QList<QListWidgetItem *> items;
|
||||||
|
while (listWidget->count() > 0) {
|
||||||
|
items.append(listWidget->takeItem(0));
|
||||||
|
}
|
||||||
|
while (!items.isEmpty()) {
|
||||||
|
const int index = QRandomGenerator::global()->bounded(items.size());
|
||||||
|
listWidget->addItem(items.takeAt(index));
|
||||||
|
}
|
||||||
|
randomizeRequested = true;
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DlgTurnOrder::actOk()
|
||||||
|
{
|
||||||
|
accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DlgTurnOrder::selectionChanged()
|
||||||
|
{
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
46
cockatrice/src/interface/widgets/dialogs/dlg_turn_order.h
Normal file
46
cockatrice/src/interface/widgets/dialogs/dlg_turn_order.h
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
/**
|
||||||
|
* @file dlg_turn_order.h
|
||||||
|
* @ingroup GameDialogs
|
||||||
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
|
#ifndef DLG_TURN_ORDER_H
|
||||||
|
#define DLG_TURN_ORDER_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
class QListWidget;
|
||||||
|
class QPushButton;
|
||||||
|
|
||||||
|
class DlgTurnOrder : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
QListWidget *listWidget;
|
||||||
|
QPushButton *moveUpButton;
|
||||||
|
QPushButton *moveDownButton;
|
||||||
|
QPushButton *randomizeButton;
|
||||||
|
bool randomizeRequested;
|
||||||
|
|
||||||
|
void moveSelected(int delta);
|
||||||
|
void updateButtons();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void actMoveUp();
|
||||||
|
void actMoveDown();
|
||||||
|
void actRandomize();
|
||||||
|
void actOk();
|
||||||
|
void selectionChanged();
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DlgTurnOrder(const QStringList &_playerNames, QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
[[nodiscard]] bool randomize() const
|
||||||
|
{
|
||||||
|
return randomizeRequested;
|
||||||
|
}
|
||||||
|
[[nodiscard]] QStringList order() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#include "../interface/widgets/cards/card_info_frame_widget.h"
|
#include "../interface/widgets/cards/card_info_frame_widget.h"
|
||||||
#include "../interface/widgets/dialogs/dlg_create_game.h"
|
#include "../interface/widgets/dialogs/dlg_create_game.h"
|
||||||
#include "../interface/widgets/dialogs/dlg_invite_to_game.h"
|
#include "../interface/widgets/dialogs/dlg_invite_to_game.h"
|
||||||
|
#include "../interface/widgets/dialogs/dlg_turn_order.h"
|
||||||
#include "../interface/widgets/server/game_link.h"
|
#include "../interface/widgets/server/game_link.h"
|
||||||
#include "../interface/widgets/server/user/user_list_manager.h"
|
#include "../interface/widgets/server/user/user_list_manager.h"
|
||||||
#include "../interface/widgets/utility/completer_utils.h"
|
#include "../interface/widgets/utility/completer_utils.h"
|
||||||
|
|
@ -259,6 +260,8 @@ void TabGame::connectMessageLogToGameEventHandler()
|
||||||
|
|
||||||
connect(game->getGameEventHandler(), &GameEventHandler::logTurnReversed, messageLog,
|
connect(game->getGameEventHandler(), &GameEventHandler::logTurnReversed, messageLog,
|
||||||
&MessageLogWidget::logReverseTurn);
|
&MessageLogWidget::logReverseTurn);
|
||||||
|
connect(game->getGameEventHandler(), &GameEventHandler::logTurnOrderChanged, messageLog,
|
||||||
|
&MessageLogWidget::logTurnOrderChanged);
|
||||||
|
|
||||||
connect(game->getGameEventHandler(), &GameEventHandler::logConcede, messageLog, &MessageLogWidget::logConcede);
|
connect(game->getGameEventHandler(), &GameEventHandler::logConcede, messageLog, &MessageLogWidget::logConcede);
|
||||||
connect(game->getGameEventHandler(), &GameEventHandler::logUnconcede, messageLog, &MessageLogWidget::logUnconcede);
|
connect(game->getGameEventHandler(), &GameEventHandler::logUnconcede, messageLog, &MessageLogWidget::logUnconcede);
|
||||||
|
|
@ -369,6 +372,9 @@ void TabGame::retranslateUi()
|
||||||
if (aReverseTurn) {
|
if (aReverseTurn) {
|
||||||
aReverseTurn->setText(tr("Reverse turn order"));
|
aReverseTurn->setText(tr("Reverse turn order"));
|
||||||
}
|
}
|
||||||
|
if (aTurnOrder) {
|
||||||
|
aTurnOrder->setText(tr("&Set turn order..."));
|
||||||
|
}
|
||||||
if (aRemoveLocalArrows) {
|
if (aRemoveLocalArrows) {
|
||||||
aRemoveLocalArrows->setText(tr("&Remove all local arrows"));
|
aRemoveLocalArrows->setText(tr("&Remove all local arrows"));
|
||||||
}
|
}
|
||||||
|
|
@ -625,6 +631,25 @@ void TabGame::actConcede()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TabGame::actTurnOrder()
|
||||||
|
{
|
||||||
|
if (!game->isHost() || game->getGameMetaInfo()->started()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList playerNames;
|
||||||
|
for (PlayerLogic *player : game->getPlayerManager()->getPlayers()) {
|
||||||
|
playerNames.append(player->getPlayerInfo()->getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
DlgTurnOrder dlg(playerNames, this);
|
||||||
|
if (dlg.exec() != QDialog::Accepted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
game->getGameEventHandler()->handleSetPlayerOrder(dlg.order(), dlg.randomize());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Confirms the leave game and sends the leave game command, if applicable.
|
* Confirms the leave game and sends the leave game command, if applicable.
|
||||||
*
|
*
|
||||||
|
|
@ -836,6 +861,15 @@ void TabGame::processPlayerLeave(PlayerLogic *leavingPlayer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A shuffled local player has their seat changed, so the deck view container
|
||||||
|
// keyed by their previous id must be cleaned up alongside the leaving player.
|
||||||
|
int leavingPlayerId = leavingPlayer->getPlayerInfo()->getId();
|
||||||
|
if (deckViewContainers.contains(leavingPlayerId)) {
|
||||||
|
TabbedDeckViewContainer *deckView = deckViewContainers.take(leavingPlayerId);
|
||||||
|
deckViewContainerLayout->removeWidget(deckView);
|
||||||
|
deckView->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
scene->removePlayer(leavingPlayer);
|
scene->removePlayer(leavingPlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1090,6 +1124,11 @@ void TabGame::createMenuItems()
|
||||||
connect(aNextTurn, &QAction::triggered, game->getGameEventHandler(), &GameEventHandler::handleNextTurn);
|
connect(aNextTurn, &QAction::triggered, game->getGameEventHandler(), &GameEventHandler::handleNextTurn);
|
||||||
aReverseTurn = new QAction(this);
|
aReverseTurn = new QAction(this);
|
||||||
connect(aReverseTurn, &QAction::triggered, game->getGameEventHandler(), &GameEventHandler::handleReverseTurn);
|
connect(aReverseTurn, &QAction::triggered, game->getGameEventHandler(), &GameEventHandler::handleReverseTurn);
|
||||||
|
aTurnOrder = new QAction(this);
|
||||||
|
connect(aTurnOrder, &QAction::triggered, this, &TabGame::actTurnOrder);
|
||||||
|
if (!game->isHost() || game->getGameMetaInfo()->started()) {
|
||||||
|
aTurnOrder->setVisible(false);
|
||||||
|
}
|
||||||
aRemoveLocalArrows = new QAction(this);
|
aRemoveLocalArrows = new QAction(this);
|
||||||
connect(aRemoveLocalArrows, &QAction::triggered, this, &TabGame::actRemoveLocalArrows);
|
connect(aRemoveLocalArrows, &QAction::triggered, this, &TabGame::actRemoveLocalArrows);
|
||||||
aRotateViewCW = new QAction(this);
|
aRotateViewCW = new QAction(this);
|
||||||
|
|
@ -1135,6 +1174,7 @@ void TabGame::createMenuItems()
|
||||||
gameMenu->addMenu(phasesMenu);
|
gameMenu->addMenu(phasesMenu);
|
||||||
gameMenu->addAction(aNextTurn);
|
gameMenu->addAction(aNextTurn);
|
||||||
gameMenu->addAction(aReverseTurn);
|
gameMenu->addAction(aReverseTurn);
|
||||||
|
gameMenu->addAction(aTurnOrder);
|
||||||
gameMenu->addSeparator();
|
gameMenu->addSeparator();
|
||||||
gameMenu->addAction(aRemoveLocalArrows);
|
gameMenu->addAction(aRemoveLocalArrows);
|
||||||
gameMenu->addAction(aRotateViewCW);
|
gameMenu->addAction(aRotateViewCW);
|
||||||
|
|
@ -1163,6 +1203,7 @@ void TabGame::createReplayMenuItems()
|
||||||
aNextPhaseAction = nullptr;
|
aNextPhaseAction = nullptr;
|
||||||
aNextTurn = nullptr;
|
aNextTurn = nullptr;
|
||||||
aReverseTurn = nullptr;
|
aReverseTurn = nullptr;
|
||||||
|
aTurnOrder = nullptr;
|
||||||
aRemoveLocalArrows = nullptr;
|
aRemoveLocalArrows = nullptr;
|
||||||
aRotateViewCW = nullptr;
|
aRotateViewCW = nullptr;
|
||||||
aRotateViewCCW = nullptr;
|
aRotateViewCCW = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,8 @@ private:
|
||||||
QMenu *gameMenu, *viewMenu;
|
QMenu *gameMenu, *viewMenu;
|
||||||
TearOffMenu *phasesMenu;
|
TearOffMenu *phasesMenu;
|
||||||
QAction *aGameInfo, *aConcede, *aCopyGameLink, *aLeaveGame, *aNextPhase, *aNextPhaseAction, *aNextTurn,
|
QAction *aGameInfo, *aConcede, *aCopyGameLink, *aLeaveGame, *aNextPhase, *aNextPhaseAction, *aNextTurn,
|
||||||
*aReverseTurn, *aRemoveLocalArrows, *aRotateViewCW, *aRotateViewCCW, *aResetLayout, *aResetReplayLayout;
|
*aReverseTurn, *aTurnOrder, *aRemoveLocalArrows, *aRotateViewCW, *aRotateViewCCW, *aResetLayout,
|
||||||
|
*aResetReplayLayout;
|
||||||
QAction *aFocusChat;
|
QAction *aFocusChat;
|
||||||
QAction *aInviteToGame = nullptr;
|
QAction *aInviteToGame = nullptr;
|
||||||
QList<QAction *> phaseActions;
|
QList<QAction *> phaseActions;
|
||||||
|
|
@ -162,6 +163,7 @@ private slots:
|
||||||
void actInviteToGame();
|
void actInviteToGame();
|
||||||
void actConcede();
|
void actConcede();
|
||||||
void actCopyGameLink();
|
void actCopyGameLink();
|
||||||
|
void actTurnOrder();
|
||||||
void actRemoveLocalArrows();
|
void actRemoveLocalArrows();
|
||||||
void actRotateViewCW();
|
void actRotateViewCW();
|
||||||
void actRotateViewCCW();
|
void actRotateViewCCW();
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QMapIterator>
|
#include <QMapIterator>
|
||||||
#include <QMessageLogger>
|
#include <QMessageLogger>
|
||||||
|
#include <QSet>
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <google/protobuf/descriptor.h>
|
#include <google/protobuf/descriptor.h>
|
||||||
#include <google/protobuf/message.h>
|
#include <google/protobuf/message.h>
|
||||||
|
|
@ -38,6 +39,7 @@
|
||||||
#include <libcockatrice/protocol/pb/command_reverse_turn.pb.h>
|
#include <libcockatrice/protocol/pb/command_reverse_turn.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_card_attr.pb.h>
|
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>
|
||||||
|
#include <libcockatrice/protocol/pb/command_set_player_order.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_set_playmat.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>
|
||||||
|
|
@ -50,6 +52,7 @@
|
||||||
#include <libcockatrice/protocol/pb/event_join.pb.h>
|
#include <libcockatrice/protocol/pb/event_join.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/event_kicked.pb.h>
|
#include <libcockatrice/protocol/pb/event_kicked.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/event_leave.pb.h>
|
#include <libcockatrice/protocol/pb/event_leave.pb.h>
|
||||||
|
#include <libcockatrice/protocol/pb/event_player_order_changed.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/event_player_properties_changed.pb.h>
|
#include <libcockatrice/protocol/pb/event_player_properties_changed.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/event_reverse_turn.pb.h>
|
#include <libcockatrice/protocol/pb/event_reverse_turn.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/event_set_active_phase.pb.h>
|
#include <libcockatrice/protocol/pb/event_set_active_phase.pb.h>
|
||||||
|
|
@ -189,6 +192,9 @@ void GameEventHandler::processGameEventContainer(const GameEventContainer &cont,
|
||||||
case GameEvent::REVERSE_TURN:
|
case GameEvent::REVERSE_TURN:
|
||||||
eventReverseTurn(event.GetExtension(Event_ReverseTurn::ext), playerId, context);
|
eventReverseTurn(event.GetExtension(Event_ReverseTurn::ext), playerId, context);
|
||||||
break;
|
break;
|
||||||
|
case GameEvent::PLAYER_ORDER_CHANGED:
|
||||||
|
eventPlayerOrderChanged(event.GetExtension(Event_PlayerOrderChanged::ext), playerId, context);
|
||||||
|
break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
PlayerLogic *player = game->getPlayerManager()->getPlayers().value(playerId, 0);
|
PlayerLogic *player = game->getPlayerManager()->getPlayers().value(playerId, 0);
|
||||||
|
|
@ -215,6 +221,16 @@ void GameEventHandler::handleReverseTurn()
|
||||||
sendGameCommand(Command_ReverseTurn());
|
sendGameCommand(Command_ReverseTurn());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameEventHandler::handleSetPlayerOrder(const QList<QString> &playerNames, bool randomize)
|
||||||
|
{
|
||||||
|
Command_SetPlayerOrder command;
|
||||||
|
command.set_randomize(randomize);
|
||||||
|
for (const QString &name : playerNames) {
|
||||||
|
command.add_player_names(name.toStdString());
|
||||||
|
}
|
||||||
|
sendGameCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
void GameEventHandler::handleActiveLocalPlayerConceded()
|
void GameEventHandler::handleActiveLocalPlayerConceded()
|
||||||
{
|
{
|
||||||
sendGameCommand(Command_Concede());
|
sendGameCommand(Command_Concede());
|
||||||
|
|
@ -377,6 +393,27 @@ void GameEventHandler::eventGameStateChanged(const Event_GameStateChanged &event
|
||||||
{
|
{
|
||||||
const int playerListSize = event.player_list_size();
|
const int playerListSize = event.player_list_size();
|
||||||
|
|
||||||
|
if (event.has_local_player_id()) {
|
||||||
|
game->getPlayerManager()->setLocalPlayerId(event.local_player_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
QSet<int> authoritativePlayerIds;
|
||||||
|
for (int i = 0; i < playerListSize; ++i) {
|
||||||
|
const ServerInfo_PlayerProperties &prop = event.player_list(i).properties();
|
||||||
|
if (!prop.spectator()) {
|
||||||
|
authoritativePlayerIds.insert(prop.player_id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Players whose seats were shuffled away from the previous game are no longer
|
||||||
|
// part of the authoritative list and must be removed.
|
||||||
|
for (int stalePlayerId : game->getPlayerManager()->getPlayers().keys()) {
|
||||||
|
if (!authoritativePlayerIds.contains(stalePlayerId)) {
|
||||||
|
game->getPlayerManager()->removePlayer(stalePlayerId);
|
||||||
|
emit playerLeft(stalePlayerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QVector<QPair<int, QPair<QString, QString>>> opponentDecksToDisplay;
|
QVector<QPair<int, QPair<QString, QString>>> opponentDecksToDisplay;
|
||||||
|
|
||||||
for (int i = 0; i < playerListSize; ++i) {
|
for (int i = 0; i < playerListSize; ++i) {
|
||||||
|
|
@ -625,6 +662,17 @@ void GameEventHandler::eventReverseTurn(const Event_ReverseTurn &event,
|
||||||
emit logTurnReversed(player, event.reversed());
|
emit logTurnReversed(player, event.reversed());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameEventHandler::eventPlayerOrderChanged(const Event_PlayerOrderChanged &event,
|
||||||
|
int /*eventPlayerId*/,
|
||||||
|
const GameEventContext & /*context*/)
|
||||||
|
{
|
||||||
|
QStringList playerNames;
|
||||||
|
for (const auto &name : event.player_names()) {
|
||||||
|
playerNames.append(QString::fromStdString(name));
|
||||||
|
}
|
||||||
|
emit logTurnOrderChanged(playerNames, event.randomized());
|
||||||
|
}
|
||||||
|
|
||||||
void GameEventHandler::eventGameHostChanged(const Event_GameHostChanged & /*event*/,
|
void GameEventHandler::eventGameHostChanged(const Event_GameHostChanged & /*event*/,
|
||||||
int eventPlayerId,
|
int eventPlayerId,
|
||||||
const GameEventContext & /*context*/)
|
const GameEventContext & /*context*/)
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ class Event_GameSay;
|
||||||
class Event_Kicked;
|
class Event_Kicked;
|
||||||
class Event_ReverseTurn;
|
class Event_ReverseTurn;
|
||||||
class Event_Ping;
|
class Event_Ping;
|
||||||
|
class Event_PlayerOrderChanged;
|
||||||
class ServerInfo_PlayerProperties;
|
class ServerInfo_PlayerProperties;
|
||||||
namespace google
|
namespace google
|
||||||
{
|
{
|
||||||
|
|
@ -113,6 +114,16 @@ public:
|
||||||
/** @brief Request reversing the current turn order. */
|
/** @brief Request reversing the current turn order. */
|
||||||
void handleReverseTurn();
|
void handleReverseTurn();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Request a new seating / turn order.
|
||||||
|
*
|
||||||
|
* Only the game host (or a moderator) may do this before the game starts.
|
||||||
|
*
|
||||||
|
* @param playerNames Ordered list of player names. Ignored when randomize is true.
|
||||||
|
* @param randomize Ask the server to shuffle the seats instead.
|
||||||
|
*/
|
||||||
|
void handleSetPlayerOrder(const QList<QString> &playerNames, bool randomize);
|
||||||
|
|
||||||
/** @brief Concede the game for the currently active local player. */
|
/** @brief Concede the game for the currently active local player. */
|
||||||
void handleActiveLocalPlayerConceded();
|
void handleActiveLocalPlayerConceded();
|
||||||
|
|
||||||
|
|
@ -316,6 +327,10 @@ public:
|
||||||
/** @brief Handle a turn reversal event. */
|
/** @brief Handle a turn reversal event. */
|
||||||
void eventReverseTurn(const Event_ReverseTurn &event, int eventPlayerId, const GameEventContext &context);
|
void eventReverseTurn(const Event_ReverseTurn &event, int eventPlayerId, const GameEventContext &context);
|
||||||
|
|
||||||
|
/** @brief Handle a change of the seating / turn order. */
|
||||||
|
void
|
||||||
|
eventPlayerOrderChanged(const Event_PlayerOrderChanged &event, int eventPlayerId, const GameEventContext &context);
|
||||||
|
|
||||||
/** @brief Handle ping / latency updates. */
|
/** @brief Handle ping / latency updates. */
|
||||||
void eventPing(const Event_Ping &event, int eventPlayerId, const GameEventContext &context);
|
void eventPing(const Event_Ping &event, int eventPlayerId, const GameEventContext &context);
|
||||||
|
|
||||||
|
|
@ -443,6 +458,7 @@ signals:
|
||||||
void logLeave(PlayerLogic *player, QString reason);
|
void logLeave(PlayerLogic *player, QString reason);
|
||||||
void logKicked();
|
void logKicked();
|
||||||
void logTurnReversed(PlayerLogic *player, bool reversed);
|
void logTurnReversed(PlayerLogic *player, bool reversed);
|
||||||
|
void logTurnOrderChanged(QStringList playerNames, bool randomized);
|
||||||
void logGameClosed();
|
void logGameClosed();
|
||||||
void logActivePlayer(PlayerLogic *activePlayer);
|
void logActivePlayer(PlayerLogic *activePlayer);
|
||||||
void logActivePhaseChanged(int activePhase);
|
void logActivePhaseChanged(int activePhase);
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,11 @@ public:
|
||||||
return localPlayerId;
|
return localPlayerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setLocalPlayerId(int _localPlayerId)
|
||||||
|
{
|
||||||
|
localPlayerId = _localPlayerId;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] const QMap<int, PlayerLogic *> &getPlayers() const
|
[[nodiscard]] const QMap<int, PlayerLogic *> &getPlayers() const
|
||||||
{
|
{
|
||||||
return players;
|
return players;
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ public:
|
||||||
[[nodiscard]] virtual bool getCreateGameAsSpectator() const = 0;
|
[[nodiscard]] virtual bool getCreateGameAsSpectator() const = 0;
|
||||||
[[nodiscard]] virtual int getDefaultStartingLifeTotal() const = 0;
|
[[nodiscard]] virtual int getDefaultStartingLifeTotal() const = 0;
|
||||||
[[nodiscard]] virtual bool getShareDecklistsOnLoad() const = 0;
|
[[nodiscard]] virtual bool getShareDecklistsOnLoad() const = 0;
|
||||||
|
[[nodiscard]] virtual bool getShufflePlayers() const = 0;
|
||||||
[[nodiscard]] virtual bool getRememberGameSettings() const = 0;
|
[[nodiscard]] virtual bool getRememberGameSettings() const = 0;
|
||||||
[[nodiscard]] virtual bool getLocalGameRememberSettings() const = 0;
|
[[nodiscard]] virtual bool getLocalGameRememberSettings() const = 0;
|
||||||
[[nodiscard]] virtual int getLocalGameMaxPlayers() const = 0;
|
[[nodiscard]] virtual int getLocalGameMaxPlayers() const = 0;
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,11 @@ bool GameSettings::getShareDecklistsOnLoad() const
|
||||||
return getValue("shareDecklistsOnLoad", "game").toBool();
|
return getValue("shareDecklistsOnLoad", "game").toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GameSettings::getShufflePlayers() const
|
||||||
|
{
|
||||||
|
return getValue("shuffleplayers", "game").toBool();
|
||||||
|
}
|
||||||
|
|
||||||
bool GameSettings::getRememberGameSettings() const
|
bool GameSettings::getRememberGameSettings() const
|
||||||
{
|
{
|
||||||
return getValue("rememberGameSettings", "game", QString(), true).toBool();
|
return getValue("rememberGameSettings", "game", QString(), true).toBool();
|
||||||
|
|
@ -151,6 +156,11 @@ void GameSettings::setShareDecklistsOnLoad(bool _shareDecklistsOnLoad)
|
||||||
setValue(_shareDecklistsOnLoad, "shareDecklistsOnLoad", "game");
|
setValue(_shareDecklistsOnLoad, "shareDecklistsOnLoad", "game");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameSettings::setShufflePlayers(bool _shufflePlayers)
|
||||||
|
{
|
||||||
|
setValue(_shufflePlayers, "shuffleplayers", "game");
|
||||||
|
}
|
||||||
|
|
||||||
void GameSettings::setRememberGameSettings(bool _rememberGameSettings)
|
void GameSettings::setRememberGameSettings(bool _rememberGameSettings)
|
||||||
{
|
{
|
||||||
setValue(_rememberGameSettings, "rememberGameSettings", "game");
|
setValue(_rememberGameSettings, "rememberGameSettings", "game");
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ public:
|
||||||
[[nodiscard]] bool getCreateGameAsSpectator() const override;
|
[[nodiscard]] bool getCreateGameAsSpectator() const override;
|
||||||
[[nodiscard]] int getDefaultStartingLifeTotal() const override;
|
[[nodiscard]] int getDefaultStartingLifeTotal() const override;
|
||||||
[[nodiscard]] bool getShareDecklistsOnLoad() const override;
|
[[nodiscard]] bool getShareDecklistsOnLoad() const override;
|
||||||
|
[[nodiscard]] bool getShufflePlayers() const override;
|
||||||
[[nodiscard]] bool getRememberGameSettings() const override;
|
[[nodiscard]] bool getRememberGameSettings() const override;
|
||||||
[[nodiscard]] bool getLocalGameRememberSettings() const override;
|
[[nodiscard]] bool getLocalGameRememberSettings() const override;
|
||||||
[[nodiscard]] int getLocalGameMaxPlayers() const override;
|
[[nodiscard]] int getLocalGameMaxPlayers() const override;
|
||||||
|
|
@ -44,6 +45,7 @@ public:
|
||||||
void setCreateGameAsSpectator(bool _createGameAsSpectator);
|
void setCreateGameAsSpectator(bool _createGameAsSpectator);
|
||||||
void setDefaultStartingLifeTotal(int _defaultStartingLifeTotal);
|
void setDefaultStartingLifeTotal(int _defaultStartingLifeTotal);
|
||||||
void setShareDecklistsOnLoad(bool _shareDecklistsOnLoad);
|
void setShareDecklistsOnLoad(bool _shareDecklistsOnLoad);
|
||||||
|
void setShufflePlayers(bool _shufflePlayers);
|
||||||
void setRememberGameSettings(bool _rememberGameSettings);
|
void setRememberGameSettings(bool _rememberGameSettings);
|
||||||
void setLocalGameRememberSettings(bool value);
|
void setLocalGameRememberSettings(bool value);
|
||||||
void setLocalGameMaxPlayers(int value);
|
void setLocalGameMaxPlayers(int value);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue