Judge mode (#3531)
* Judge mode * Use seperate judge icon * Fix clang init ordering complaint * Create gavel.svg * Add judge level * Adjust judge permissions. * - Tag events caused by judges - Allow judges access to card right click menus. * Allow judges to change phase / turn. * Remove gavel from pawn * Make judge action text black. * Create scales * Rename scales to scales.svg * Use scales * remove gavel * - Address PR feedback - Fix sort order * Zach * add option to servatrice.ini
This commit is contained in:
parent
9d27b36704
commit
ea8201af5c
42 changed files with 375 additions and 105 deletions
|
@ -24,6 +24,7 @@
|
||||||
<file>resources/icons/player.svg</file>
|
<file>resources/icons/player.svg</file>
|
||||||
<file>resources/icons/ready_start.svg</file>
|
<file>resources/icons/ready_start.svg</file>
|
||||||
<file>resources/icons/remove_row.svg</file>
|
<file>resources/icons/remove_row.svg</file>
|
||||||
|
<file>resources/icons/scales.svg</file>
|
||||||
<file>resources/icons/search.svg</file>
|
<file>resources/icons/search.svg</file>
|
||||||
<file>resources/icons/settings.svg</file>
|
<file>resources/icons/settings.svg</file>
|
||||||
<file>resources/icons/spectator.svg</file>
|
<file>resources/icons/spectator.svg</file>
|
||||||
|
|
6
cockatrice/resources/icons/scales.svg
Normal file
6
cockatrice/resources/icons/scales.svg
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="52pt" height="52pt" viewBox="0 0 52 52" version="1.1">
|
||||||
|
<g id="surface1">
|
||||||
|
<path style=" stroke:none;fill-rule:nonzero;fill:#000000;fill-opacity:1;" d="M 25.605469 0.125 C 25.605469 0.125 23.265625 3.140625 23.265625 4.433594 C 23.265625 5.316406 23.765625 6.070313 24.5 6.464844 C 23.898438 6.65625 23.375 6.992188 22.960938 7.449219 C 22.011719 6.640625 20.628906 5.910156 18.710938 5.910156 C 16.640625 5.910156 14.863281 6.753906 13.355469 7.507813 C 12.601563 7.886719 11.925781 8.25 11.324219 8.496094 C 10.964844 8.09375 10.425781 7.878906 9.847656 7.878906 C 8.75 7.878906 7.878906 8.75 7.878906 9.847656 C 7.878906 10.949219 8.75 11.816406 9.847656 11.816406 C 10.757813 11.816406 11.519531 11.234375 11.757813 10.402344 C 12.578125 10.078125 13.386719 9.648438 14.21875 9.234375 C 15.671875 8.507813 17.179688 7.878906 18.710938 7.878906 C 20.496094 7.878906 21.519531 8.679688 22.097656 9.355469 C 22.074219 9.519531 22.035156 9.6875 22.035156 9.847656 C 22.035156 11.816406 23.636719 13.417969 25.605469 13.417969 C 27.574219 13.417969 29.175781 11.816406 29.175781 9.847656 C 29.175781 9.6875 29.136719 9.519531 29.113281 9.355469 C 29.691406 8.679688 30.714844 7.878906 32.5 7.878906 C 34.03125 7.878906 35.539063 8.507813 36.992188 9.234375 C 37.824219 9.648438 38.632813 10.078125 39.457031 10.402344 C 39.695313 11.234375 40.457031 11.816406 41.363281 11.816406 C 42.464844 11.816406 43.332031 10.949219 43.332031 9.847656 C 43.332031 8.75 42.464844 7.878906 41.363281 7.878906 C 40.785156 7.878906 40.246094 8.09375 39.886719 8.496094 C 39.285156 8.25 38.609375 7.886719 37.855469 7.507813 C 36.347656 6.753906 34.570313 5.910156 32.5 5.910156 C 30.585938 5.910156 29.199219 6.640625 28.253906 7.449219 C 27.835938 6.992188 27.3125 6.65625 26.714844 6.464844 C 27.445313 6.070313 27.945313 5.316406 27.945313 4.433594 C 27.945313 3.140625 25.605469 0.125 25.605469 0.125 Z M 9.539063 13.234375 C 9.25 13.332031 9.023438 13.558594 8.925781 13.847656 L 2.277344 31.515625 L 0 31.515625 C 1.445313 35.578125 5.285156 38.53125 9.847656 38.53125 C 14.410156 38.53125 18.25 35.578125 19.695313 31.515625 L 17.417969 31.515625 L 10.773438 13.847656 C 10.601563 13.402344 10.132813 13.140625 9.664063 13.234375 C 9.625 13.234375 9.578125 13.234375 9.539063 13.234375 Z M 41.054688 13.234375 C 40.761719 13.332031 40.539063 13.558594 40.441406 13.847656 L 33.792969 31.515625 L 31.515625 31.515625 C 32.960938 35.578125 36.800781 38.53125 41.363281 38.53125 C 45.925781 38.53125 49.765625 35.578125 51.210938 31.515625 L 48.933594 31.515625 L 42.285156 13.847656 C 42.117188 13.402344 41.648438 13.140625 41.179688 13.234375 C 41.140625 13.234375 41.09375 13.234375 41.054688 13.234375 Z M 21.914063 15.757813 C 21.914063 17.082031 22.589844 18.242188 23.636719 18.898438 L 23.636719 41.980469 C 21.429688 42.773438 19.796875 44.816406 19.695313 47.273438 L 15.757813 47.273438 C 14.671875 47.273438 13.789063 48.15625 13.789063 49.242188 L 13.789063 51.210938 L 37.425781 51.210938 L 37.425781 49.242188 C 37.425781 48.15625 36.539063 47.273438 35.453125 47.273438 L 31.515625 47.273438 C 31.414063 44.816406 29.785156 42.773438 27.574219 41.980469 L 27.574219 18.898438 C 28.621094 18.242188 29.300781 17.082031 29.300781 15.757813 Z M 9.847656 17.050781 L 15.328125 31.515625 L 4.371094 31.515625 Z M 41.363281 17.050781 L 46.84375 31.515625 L 35.886719 31.515625 Z "/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.4 KiB |
|
@ -26,7 +26,7 @@ AbstractCounter::AbstractCounter(Player *_player,
|
||||||
|
|
||||||
shortcutActive = false;
|
shortcutActive = false;
|
||||||
|
|
||||||
if (player->getLocal()) {
|
if (player->getLocalOrJudge()) {
|
||||||
menu = new QMenu(name);
|
menu = new QMenu(name);
|
||||||
aSet = new QAction(this);
|
aSet = new QAction(this);
|
||||||
connect(aSet, SIGNAL(triggered()), this, SLOT(setCounter()));
|
connect(aSet, SIGNAL(triggered()), this, SLOT(setCounter()));
|
||||||
|
@ -115,7 +115,7 @@ void AbstractCounter::setValue(int _value)
|
||||||
|
|
||||||
void AbstractCounter::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
void AbstractCounter::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||||
{
|
{
|
||||||
if (isUnderMouse() && player->getLocal()) {
|
if (isUnderMouse() && player->getLocalOrJudge()) {
|
||||||
if (event->button() == Qt::MidButton || (QApplication::keyboardModifiers() & Qt::ShiftModifier)) {
|
if (event->button() == Qt::MidButton || (QApplication::keyboardModifiers() & Qt::ShiftModifier)) {
|
||||||
if (menu)
|
if (menu)
|
||||||
menu->exec(event->screenPos());
|
menu->exec(event->screenPos());
|
||||||
|
|
|
@ -321,7 +321,7 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||||
const ZoneViewZone *view = static_cast<const ZoneViewZone *>(zone);
|
const ZoneViewZone *view = static_cast<const ZoneViewZone *>(zone);
|
||||||
if (view->getRevealZone() && !view->getWriteableRevealZone())
|
if (view->getRevealZone() && !view->getWriteableRevealZone())
|
||||||
return;
|
return;
|
||||||
} else if (!owner->getLocal())
|
} else if (!owner->getLocalOrJudge())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool forceFaceDown = event->modifiers().testFlag(Qt::ShiftModifier);
|
bool forceFaceDown = event->modifiers().testFlag(Qt::ShiftModifier);
|
||||||
|
@ -352,7 +352,7 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||||
void CardItem::playCard(bool faceDown)
|
void CardItem::playCard(bool faceDown)
|
||||||
{
|
{
|
||||||
// Do nothing if the card belongs to another player
|
// Do nothing if the card belongs to another player
|
||||||
if (!owner->getLocal())
|
if (!owner->getLocalOrJudge())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TableZone *tz = qobject_cast<TableZone *>(zone);
|
TableZone *tz = qobject_cast<TableZone *>(zone);
|
||||||
|
|
|
@ -71,8 +71,9 @@ public:
|
||||||
QWidget *parent = 0);
|
QWidget *parent = 0);
|
||||||
void retranslateUi();
|
void retranslateUi();
|
||||||
void appendHtml(const QString &html);
|
void appendHtml(const QString &html);
|
||||||
void
|
void virtual appendHtmlServerMessage(const QString &html,
|
||||||
appendHtmlServerMessage(const QString &html, bool optionalIsBold = false, QString optionalFontColor = QString());
|
bool optionalIsBold = false,
|
||||||
|
QString optionalFontColor = QString());
|
||||||
void appendMessage(QString message,
|
void appendMessage(QString message,
|
||||||
RoomMessageTypeFlags messageType = 0,
|
RoomMessageTypeFlags messageType = 0,
|
||||||
QString sender = QString(),
|
QString sender = QString(),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "dlg_creategame.h"
|
#include "dlg_creategame.h"
|
||||||
#include "settingscache.h"
|
#include "settingscache.h"
|
||||||
#include "tab_room.h"
|
#include "tab_room.h"
|
||||||
|
#include <QApplication>
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
|
@ -223,6 +224,7 @@ void DlgCreateGame::actOK()
|
||||||
cmd.set_spectators_need_password(spectatorsNeedPasswordCheckBox->isChecked());
|
cmd.set_spectators_need_password(spectatorsNeedPasswordCheckBox->isChecked());
|
||||||
cmd.set_spectators_can_talk(spectatorsCanTalkCheckBox->isChecked());
|
cmd.set_spectators_can_talk(spectatorsCanTalkCheckBox->isChecked());
|
||||||
cmd.set_spectators_see_everything(spectatorsSeeEverythingCheckBox->isChecked());
|
cmd.set_spectators_see_everything(spectatorsSeeEverythingCheckBox->isChecked());
|
||||||
|
cmd.set_join_as_judge(QApplication::keyboardModifiers() & Qt::ShiftModifier);
|
||||||
|
|
||||||
QString gameTypes = QString();
|
QString gameTypes = QString();
|
||||||
QMapIterator<int, QRadioButton *> gameTypeCheckBoxIterator(gameTypeCheckBoxes);
|
QMapIterator<int, QRadioButton *> gameTypeCheckBoxIterator(gameTypeCheckBoxes);
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "pending_command.h"
|
#include "pending_command.h"
|
||||||
#include "tab_room.h"
|
#include "tab_room.h"
|
||||||
#include "tab_supervisor.h"
|
#include "tab_supervisor.h"
|
||||||
|
#include <QApplication>
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
|
@ -205,6 +206,7 @@ void GameSelector::actJoin()
|
||||||
cmd.set_password(password.toStdString());
|
cmd.set_password(password.toStdString());
|
||||||
cmd.set_spectator(spectator);
|
cmd.set_spectator(spectator);
|
||||||
cmd.set_override_restrictions(overrideRestrictions);
|
cmd.set_override_restrictions(overrideRestrictions);
|
||||||
|
cmd.set_join_as_judge((QApplication::keyboardModifiers() & Qt::ShiftModifier) != 0);
|
||||||
|
|
||||||
TabRoom *r = tabSupervisor->getRoomTabs().value(game.room_id());
|
TabRoom *r = tabSupervisor->getRoomTabs().value(game.room_id());
|
||||||
if (!r) {
|
if (!r) {
|
||||||
|
|
|
@ -121,9 +121,11 @@ MessageLogWidget::getFromStr(CardZone *zone, QString cardName, int position, boo
|
||||||
|
|
||||||
void MessageLogWidget::containerProcessingDone()
|
void MessageLogWidget::containerProcessingDone()
|
||||||
{
|
{
|
||||||
|
|
||||||
if (currentContext == MessageContext_MoveCard) {
|
if (currentContext == MessageContext_MoveCard) {
|
||||||
for (auto &i : moveCardQueue)
|
for (auto &i : moveCardQueue)
|
||||||
logDoMoveCard(i);
|
logDoMoveCard(i);
|
||||||
|
|
||||||
moveCardQueue.clear();
|
moveCardQueue.clear();
|
||||||
moveCardTapped.clear();
|
moveCardTapped.clear();
|
||||||
moveCardExtras.clear();
|
moveCardExtras.clear();
|
||||||
|
@ -134,6 +136,7 @@ void MessageLogWidget::containerProcessingDone()
|
||||||
}
|
}
|
||||||
|
|
||||||
currentContext = MessageContext_None;
|
currentContext = MessageContext_None;
|
||||||
|
messageSuffix = messagePrefix = QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageLogWidget::containerProcessingStarted(const GameEventContext &context)
|
void MessageLogWidget::containerProcessingStarted(const GameEventContext &context)
|
||||||
|
@ -815,6 +818,18 @@ void MessageLogWidget::logUndoDraw(Player *player, QString cardName)
|
||||||
.arg(QString("<a href=\"card://%1\">%2</a>").arg(sanitizeHtml(cardName)).arg(sanitizeHtml(cardName))));
|
.arg(QString("<a href=\"card://%1\">%2</a>").arg(sanitizeHtml(cardName)).arg(sanitizeHtml(cardName))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MessageLogWidget::setContextJudgeName(QString name)
|
||||||
|
{
|
||||||
|
messagePrefix = QString("<span style=\"color:black\">");
|
||||||
|
messageSuffix = QString("</span> [<img height=12 src=\"theme:icons/scales\"> %1]").arg(sanitizeHtml(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageLogWidget::appendHtmlServerMessage(const QString &html, bool optionalIsBold, QString optionalFontColor)
|
||||||
|
{
|
||||||
|
|
||||||
|
ChatView::appendHtmlServerMessage(messagePrefix + html + messageSuffix, optionalIsBold, optionalFontColor);
|
||||||
|
}
|
||||||
|
|
||||||
void MessageLogWidget::connectToPlayer(Player *player)
|
void MessageLogWidget::connectToPlayer(Player *player)
|
||||||
{
|
{
|
||||||
connect(player, SIGNAL(logSay(Player *, QString)), this, SLOT(logSay(Player *, QString)));
|
connect(player, SIGNAL(logSay(Player *, QString)), this, SLOT(logSay(Player *, QString)));
|
||||||
|
|
|
@ -38,6 +38,7 @@ private:
|
||||||
QList<LogMoveCard> moveCardQueue;
|
QList<LogMoveCard> moveCardQueue;
|
||||||
QMap<CardItem *, bool> moveCardTapped;
|
QMap<CardItem *, bool> moveCardTapped;
|
||||||
QList<QString> moveCardExtras;
|
QList<QString> moveCardExtras;
|
||||||
|
QString messagePrefix, messageSuffix;
|
||||||
|
|
||||||
const QString tableConstant() const;
|
const QString tableConstant() const;
|
||||||
const QString graveyardConstant() const;
|
const QString graveyardConstant() const;
|
||||||
|
@ -108,6 +109,10 @@ public slots:
|
||||||
void logStopDumpZone(Player *player, CardZone *zone);
|
void logStopDumpZone(Player *player, CardZone *zone);
|
||||||
void logUnattachCard(Player *player, QString cardName);
|
void logUnattachCard(Player *player, QString cardName);
|
||||||
void logUndoDraw(Player *player, QString cardName);
|
void logUndoDraw(Player *player, QString cardName);
|
||||||
|
void setContextJudgeName(QString player);
|
||||||
|
void appendHtmlServerMessage(const QString &html,
|
||||||
|
bool optionalIsBold = false,
|
||||||
|
QString optionalFontColor = QString()) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void connectToPlayer(Player *player);
|
void connectToPlayer(Player *player);
|
||||||
|
|
|
@ -143,6 +143,7 @@ QPixmap UserLevelPixmapGenerator::generatePixmap(int height, UserLevelFlags user
|
||||||
|
|
||||||
QPixmap pixmap = QPixmap("theme:userlevels/" + levelString)
|
QPixmap pixmap = QPixmap("theme:userlevels/" + levelString)
|
||||||
.scaled(height, height, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
.scaled(height, height, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||||
|
|
||||||
pmCache.insert(key, pixmap);
|
pmCache.insert(key, pixmap);
|
||||||
return pixmap;
|
return pixmap;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include "pb/command_attach_card.pb.h"
|
#include "pb/command_attach_card.pb.h"
|
||||||
#include "pb/command_change_zone_properties.pb.h"
|
#include "pb/command_change_zone_properties.pb.h"
|
||||||
|
#include "pb/command_concede.pb.h"
|
||||||
#include "pb/command_create_token.pb.h"
|
#include "pb/command_create_token.pb.h"
|
||||||
#include "pb/command_draw_cards.pb.h"
|
#include "pb/command_draw_cards.pb.h"
|
||||||
#include "pb/command_flip_card.pb.h"
|
#include "pb/command_flip_card.pb.h"
|
||||||
|
@ -91,10 +92,11 @@ void PlayerArea::setSize(qreal width, qreal height)
|
||||||
bRect = QRectF(0, 0, width, height);
|
bRect = QRectF(0, 0, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
Player::Player(const ServerInfo_User &info, int _id, bool _local, TabGame *_parent)
|
Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, TabGame *_parent)
|
||||||
: QObject(_parent), game(_parent), shortcutsActive(false), defaultNumberTopCards(1),
|
: QObject(_parent), game(_parent), shortcutsActive(false), defaultNumberTopCards(1),
|
||||||
defaultNumberTopCardsToPlaceBelow(1), lastTokenDestroy(true), lastTokenTableRow(0), id(_id), active(false),
|
defaultNumberTopCardsToPlaceBelow(1), lastTokenDestroy(true), lastTokenTableRow(0), id(_id), active(false),
|
||||||
local(_local), mirrored(false), handVisible(false), conceded(false), dialogSemaphore(false), deck(nullptr)
|
local(_local), judge(_judge), mirrored(false), handVisible(false), conceded(false), dialogSemaphore(false),
|
||||||
|
deck(nullptr)
|
||||||
{
|
{
|
||||||
userInfo = new ServerInfo_User;
|
userInfo = new ServerInfo_User;
|
||||||
userInfo->CopyFrom(info);
|
userInfo->CopyFrom(info);
|
||||||
|
@ -140,10 +142,12 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, TabGame *_pare
|
||||||
|
|
||||||
updateBoundingRect();
|
updateBoundingRect();
|
||||||
|
|
||||||
if (local) {
|
if (local || judge) {
|
||||||
connect(_parent, SIGNAL(playerAdded(Player *)), this, SLOT(addPlayer(Player *)));
|
connect(_parent, SIGNAL(playerAdded(Player *)), this, SLOT(addPlayer(Player *)));
|
||||||
connect(_parent, SIGNAL(playerRemoved(Player *)), this, SLOT(removePlayer(Player *)));
|
connect(_parent, SIGNAL(playerRemoved(Player *)), this, SLOT(removePlayer(Player *)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (local || judge) {
|
||||||
aMoveHandToTopLibrary = new QAction(this);
|
aMoveHandToTopLibrary = new QAction(this);
|
||||||
aMoveHandToTopLibrary->setData(QList<QVariant>() << "deck" << 0);
|
aMoveHandToTopLibrary->setData(QList<QVariant>() << "deck" << 0);
|
||||||
aMoveHandToBottomLibrary = new QAction(this);
|
aMoveHandToBottomLibrary = new QAction(this);
|
||||||
|
@ -204,7 +208,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, TabGame *_pare
|
||||||
aViewRfg = new QAction(this);
|
aViewRfg = new QAction(this);
|
||||||
connect(aViewRfg, SIGNAL(triggered()), this, SLOT(actViewRfg()));
|
connect(aViewRfg, SIGNAL(triggered()), this, SLOT(actViewRfg()));
|
||||||
|
|
||||||
if (local) {
|
if (local || judge) {
|
||||||
aViewSideboard = new QAction(this);
|
aViewSideboard = new QAction(this);
|
||||||
connect(aViewSideboard, SIGNAL(triggered()), this, SLOT(actViewSideboard()));
|
connect(aViewSideboard, SIGNAL(triggered()), this, SLOT(actViewSideboard()));
|
||||||
|
|
||||||
|
@ -237,7 +241,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, TabGame *_pare
|
||||||
playerMenu = new QMenu(QString());
|
playerMenu = new QMenu(QString());
|
||||||
table->setMenu(playerMenu);
|
table->setMenu(playerMenu);
|
||||||
|
|
||||||
if (local) {
|
if (local || judge) {
|
||||||
handMenu = playerMenu->addMenu(QString());
|
handMenu = playerMenu->addMenu(QString());
|
||||||
playerLists.append(mRevealHand = handMenu->addMenu(QString()));
|
playerLists.append(mRevealHand = handMenu->addMenu(QString()));
|
||||||
playerLists.append(mRevealRandomHandCard = handMenu->addMenu(QString()));
|
playerLists.append(mRevealRandomHandCard = handMenu->addMenu(QString()));
|
||||||
|
@ -286,7 +290,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, TabGame *_pare
|
||||||
graveMenu = playerMenu->addMenu(QString());
|
graveMenu = playerMenu->addMenu(QString());
|
||||||
graveMenu->addAction(aViewGraveyard);
|
graveMenu->addAction(aViewGraveyard);
|
||||||
|
|
||||||
if (local) {
|
if (local || judge) {
|
||||||
mRevealRandomGraveyardCard = graveMenu->addMenu(QString());
|
mRevealRandomGraveyardCard = graveMenu->addMenu(QString());
|
||||||
QAction *newAction = mRevealRandomGraveyardCard->addAction(QString());
|
QAction *newAction = mRevealRandomGraveyardCard->addAction(QString());
|
||||||
newAction->setData(-1);
|
newAction->setData(-1);
|
||||||
|
@ -300,7 +304,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, TabGame *_pare
|
||||||
rfgMenu->addAction(aViewRfg);
|
rfgMenu->addAction(aViewRfg);
|
||||||
rfg->setMenu(rfgMenu, aViewRfg);
|
rfg->setMenu(rfgMenu, aViewRfg);
|
||||||
|
|
||||||
if (local) {
|
if (local || judge) {
|
||||||
graveMenu->addSeparator();
|
graveMenu->addSeparator();
|
||||||
moveGraveMenu = graveMenu->addMenu(QString());
|
moveGraveMenu = graveMenu->addMenu(QString());
|
||||||
moveGraveMenu->addAction(aMoveGraveToTopLibrary);
|
moveGraveMenu->addAction(aMoveGraveToTopLibrary);
|
||||||
|
@ -349,12 +353,22 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, TabGame *_pare
|
||||||
playerMenu->addAction(aCreateAnotherToken);
|
playerMenu->addAction(aCreateAnotherToken);
|
||||||
playerMenu->addMenu(createPredefinedTokenMenu);
|
playerMenu->addMenu(createPredefinedTokenMenu);
|
||||||
playerMenu->addSeparator();
|
playerMenu->addSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (local) {
|
||||||
sayMenu = playerMenu->addMenu(QString());
|
sayMenu = playerMenu->addMenu(QString());
|
||||||
initSayMenu();
|
initSayMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (local || judge) {
|
||||||
aCardMenu = new QAction(this);
|
aCardMenu = new QAction(this);
|
||||||
playerMenu->addSeparator();
|
playerMenu->addSeparator();
|
||||||
playerMenu->addAction(aCardMenu);
|
playerMenu->addAction(aCardMenu);
|
||||||
|
} else {
|
||||||
|
aCardMenu = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (local || judge) {
|
||||||
|
|
||||||
for (auto &playerList : playerLists) {
|
for (auto &playerList : playerLists) {
|
||||||
QAction *newAction = playerList->addAction(QString());
|
QAction *newAction = playerList->addAction(QString());
|
||||||
|
@ -363,12 +377,13 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, TabGame *_pare
|
||||||
allPlayersActions.append(newAction);
|
allPlayersActions.append(newAction);
|
||||||
playerList->addSeparator();
|
playerList->addSeparator();
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
if (!local && !judge) {
|
||||||
countersMenu = nullptr;
|
countersMenu = nullptr;
|
||||||
sbMenu = nullptr;
|
sbMenu = nullptr;
|
||||||
aCreateAnotherToken = nullptr;
|
aCreateAnotherToken = nullptr;
|
||||||
createPredefinedTokenMenu = nullptr;
|
createPredefinedTokenMenu = nullptr;
|
||||||
aCardMenu = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
aTap = new QAction(this);
|
aTap = new QAction(this);
|
||||||
|
@ -632,7 +647,7 @@ void Player::retranslateUi()
|
||||||
graveMenu->setTitle(tr("&Graveyard"));
|
graveMenu->setTitle(tr("&Graveyard"));
|
||||||
rfgMenu->setTitle(tr("&Exile"));
|
rfgMenu->setTitle(tr("&Exile"));
|
||||||
|
|
||||||
if (local) {
|
if (local || judge) {
|
||||||
moveHandMenu->setTitle(tr("&Move hand to..."));
|
moveHandMenu->setTitle(tr("&Move hand to..."));
|
||||||
aMoveHandToTopLibrary->setText(tr("&Top of library"));
|
aMoveHandToTopLibrary->setText(tr("&Top of library"));
|
||||||
aMoveHandToBottomLibrary->setText(tr("&Bottom of library"));
|
aMoveHandToBottomLibrary->setText(tr("&Bottom of library"));
|
||||||
|
@ -684,7 +699,6 @@ void Player::retranslateUi()
|
||||||
aCreateToken->setText(tr("&Create token..."));
|
aCreateToken->setText(tr("&Create token..."));
|
||||||
aCreateAnotherToken->setText(tr("C&reate another token"));
|
aCreateAnotherToken->setText(tr("C&reate another token"));
|
||||||
createPredefinedTokenMenu->setTitle(tr("Cr&eate predefined token"));
|
createPredefinedTokenMenu->setTitle(tr("Cr&eate predefined token"));
|
||||||
sayMenu->setTitle(tr("S&ay"));
|
|
||||||
|
|
||||||
QMapIterator<int, AbstractCounter *> counterIterator(counters);
|
QMapIterator<int, AbstractCounter *> counterIterator(counters);
|
||||||
while (counterIterator.hasNext())
|
while (counterIterator.hasNext())
|
||||||
|
@ -696,6 +710,10 @@ void Player::retranslateUi()
|
||||||
allPlayersAction->setText(tr("&All players"));
|
allPlayersAction->setText(tr("&All players"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (local) {
|
||||||
|
sayMenu->setTitle(tr("S&ay"));
|
||||||
|
}
|
||||||
|
|
||||||
aPlay->setText(tr("&Play"));
|
aPlay->setText(tr("&Play"));
|
||||||
aHide->setText(tr("&Hide"));
|
aHide->setText(tr("&Hide"));
|
||||||
aPlayFacedown->setText(tr("Play &Face Down"));
|
aPlayFacedown->setText(tr("Play &Face Down"));
|
||||||
|
@ -2122,7 +2140,7 @@ AbstractCounter *Player::addCounter(int counterId, const QString &name, QColor c
|
||||||
ctr = new GeneralCounter(this, counterId, name, color, radius, value, true, this);
|
ctr = new GeneralCounter(this, counterId, name, color, radius, value, true, this);
|
||||||
}
|
}
|
||||||
counters.insert(counterId, ctr);
|
counters.insert(counterId, ctr);
|
||||||
if (countersMenu) {
|
if (countersMenu && ctr->getMenu()) {
|
||||||
countersMenu->addMenu(ctr->getMenu());
|
countersMenu->addMenu(ctr->getMenu());
|
||||||
}
|
}
|
||||||
if (shortcutsActive) {
|
if (shortcutsActive) {
|
||||||
|
@ -2254,17 +2272,47 @@ void Player::rearrangeCounters()
|
||||||
|
|
||||||
PendingCommand *Player::prepareGameCommand(const google::protobuf::Message &cmd)
|
PendingCommand *Player::prepareGameCommand(const google::protobuf::Message &cmd)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (judge && !local) {
|
||||||
|
Command_Judge base;
|
||||||
|
GameCommand *c = base.add_game_command();
|
||||||
|
base.set_target_id(id);
|
||||||
|
c->GetReflection()->MutableMessage(c, cmd.GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(cmd);
|
||||||
|
return game->prepareGameCommand(base);
|
||||||
|
} else {
|
||||||
return game->prepareGameCommand(cmd);
|
return game->prepareGameCommand(cmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PendingCommand *Player::prepareGameCommand(const QList<const ::google::protobuf::Message *> &cmdList)
|
PendingCommand *Player::prepareGameCommand(const QList<const ::google::protobuf::Message *> &cmdList)
|
||||||
{
|
{
|
||||||
|
if (judge && !local) {
|
||||||
|
Command_Judge base;
|
||||||
|
base.set_target_id(id);
|
||||||
|
for (int i = 0; i < cmdList.size(); ++i) {
|
||||||
|
GameCommand *c = base.add_game_command();
|
||||||
|
c->GetReflection()
|
||||||
|
->MutableMessage(c, cmdList[i]->GetDescriptor()->FindExtensionByName("ext"))
|
||||||
|
->CopyFrom(*cmdList[i]);
|
||||||
|
delete cmdList[i];
|
||||||
|
}
|
||||||
|
return game->prepareGameCommand(base);
|
||||||
|
} else {
|
||||||
return game->prepareGameCommand(cmdList);
|
return game->prepareGameCommand(cmdList);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::sendGameCommand(const google::protobuf::Message &command)
|
void Player::sendGameCommand(const google::protobuf::Message &command)
|
||||||
{
|
{
|
||||||
|
if (judge && !local) {
|
||||||
|
Command_Judge base;
|
||||||
|
GameCommand *c = base.add_game_command();
|
||||||
|
base.set_target_id(id);
|
||||||
|
c->GetReflection()->MutableMessage(c, command.GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(command);
|
||||||
|
game->sendGameCommand(base, id);
|
||||||
|
} else {
|
||||||
game->sendGameCommand(command, id);
|
game->sendGameCommand(command, id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::sendGameCommand(PendingCommand *pend)
|
void Player::sendGameCommand(PendingCommand *pend)
|
||||||
|
@ -2806,7 +2854,7 @@ void Player::refreshShortcuts()
|
||||||
void Player::updateCardMenu(const CardItem *card)
|
void Player::updateCardMenu(const CardItem *card)
|
||||||
{
|
{
|
||||||
// If bad card OR is a spectator (as spectators don't need card menus), return
|
// If bad card OR is a spectator (as spectators don't need card menus), return
|
||||||
if (card == nullptr || game->isSpectator()) {
|
if (card == nullptr || (game->isSpectator() && !judge)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2817,7 +2865,7 @@ void Player::updateCardMenu(const CardItem *card)
|
||||||
cardMenu->clear();
|
cardMenu->clear();
|
||||||
|
|
||||||
bool revealedCard = false;
|
bool revealedCard = false;
|
||||||
bool writeableCard = getLocal();
|
bool writeableCard = getLocalOrJudge();
|
||||||
if (card->getZone() && card->getZone()->getIsView()) {
|
if (card->getZone() && card->getZone()->getIsView()) {
|
||||||
auto *view = dynamic_cast<ZoneViewZone *>(card->getZone());
|
auto *view = dynamic_cast<ZoneViewZone *>(card->getZone());
|
||||||
if (view->getRevealZone()) {
|
if (view->getRevealZone()) {
|
||||||
|
|
|
@ -228,6 +228,7 @@ private:
|
||||||
int id;
|
int id;
|
||||||
bool active;
|
bool active;
|
||||||
bool local;
|
bool local;
|
||||||
|
bool judge;
|
||||||
bool mirrored;
|
bool mirrored;
|
||||||
bool handVisible;
|
bool handVisible;
|
||||||
bool conceded;
|
bool conceded;
|
||||||
|
@ -339,8 +340,9 @@ public:
|
||||||
return playerTarget;
|
return playerTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player(const ServerInfo_User &info, int _id, bool _local, TabGame *_parent);
|
Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, TabGame *_parent);
|
||||||
~Player() override;
|
~Player() override;
|
||||||
|
|
||||||
void retranslateUi();
|
void retranslateUi();
|
||||||
void clear();
|
void clear();
|
||||||
TabGame *getGame() const
|
TabGame *getGame() const
|
||||||
|
@ -365,6 +367,14 @@ public:
|
||||||
{
|
{
|
||||||
return local;
|
return local;
|
||||||
}
|
}
|
||||||
|
bool getLocalOrJudge() const
|
||||||
|
{
|
||||||
|
return local || judge;
|
||||||
|
}
|
||||||
|
bool getJudge() const
|
||||||
|
{
|
||||||
|
return judge;
|
||||||
|
}
|
||||||
bool getMirrored() const
|
bool getMirrored() const
|
||||||
{
|
{
|
||||||
return mirrored;
|
return mirrored;
|
||||||
|
|
|
@ -58,6 +58,7 @@ PlayerListWidget::PlayerListWidget(TabSupervisor *_tabSupervisor,
|
||||||
notReadyIcon = QPixmap("theme:icons/not_ready_start");
|
notReadyIcon = QPixmap("theme:icons/not_ready_start");
|
||||||
concededIcon = QPixmap("theme:icons/conceded");
|
concededIcon = QPixmap("theme:icons/conceded");
|
||||||
playerIcon = QPixmap("theme:icons/player");
|
playerIcon = QPixmap("theme:icons/player");
|
||||||
|
judgeIcon = QPixmap("theme:icons/scales");
|
||||||
spectatorIcon = QPixmap("theme:icons/spectator");
|
spectatorIcon = QPixmap("theme:icons/spectator");
|
||||||
lockIcon = QPixmap("theme:icons/lock");
|
lockIcon = QPixmap("theme:icons/lock");
|
||||||
|
|
||||||
|
@ -111,8 +112,16 @@ void PlayerListWidget::updatePlayerProperties(const ServerInfo_PlayerProperties
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool isSpectator = prop.has_spectator() && prop.spectator();
|
bool isSpectator = prop.has_spectator() && prop.spectator();
|
||||||
player->setIcon(1, isSpectator ? spectatorIcon : playerIcon);
|
if (prop.has_judge() || prop.has_spectator()) {
|
||||||
|
if (prop.has_judge() && prop.judge()) {
|
||||||
|
player->setIcon(1, judgeIcon);
|
||||||
|
} else if (isSpectator) {
|
||||||
|
player->setIcon(1, spectatorIcon);
|
||||||
|
} else {
|
||||||
|
player->setIcon(1, playerIcon);
|
||||||
|
}
|
||||||
player->setData(1, Qt::UserRole, !isSpectator);
|
player->setData(1, Qt::UserRole, !isSpectator);
|
||||||
|
}
|
||||||
|
|
||||||
if (!isSpectator) {
|
if (!isSpectator) {
|
||||||
if (prop.has_conceded())
|
if (prop.has_conceded())
|
||||||
|
|
|
@ -37,7 +37,7 @@ private:
|
||||||
AbstractClient *client;
|
AbstractClient *client;
|
||||||
TabGame *game;
|
TabGame *game;
|
||||||
UserContextMenu *userContextMenu;
|
UserContextMenu *userContextMenu;
|
||||||
QIcon readyIcon, notReadyIcon, concededIcon, playerIcon, spectatorIcon, lockIcon;
|
QIcon readyIcon, notReadyIcon, concededIcon, playerIcon, judgeIcon, spectatorIcon, lockIcon;
|
||||||
bool gameStarted;
|
bool gameStarted;
|
||||||
signals:
|
signals:
|
||||||
void openMessageDialog(const QString &userName, bool focus);
|
void openMessageDialog(const QString &userName, bool focus);
|
||||||
|
|
|
@ -332,8 +332,8 @@ void DeckViewContainer::setDeck(const DeckLoader &deck)
|
||||||
|
|
||||||
TabGame::TabGame(TabSupervisor *_tabSupervisor, GameReplay *_replay)
|
TabGame::TabGame(TabSupervisor *_tabSupervisor, GameReplay *_replay)
|
||||||
: Tab(_tabSupervisor), secondsElapsed(0), hostId(-1), localPlayerId(-1),
|
: Tab(_tabSupervisor), secondsElapsed(0), hostId(-1), localPlayerId(-1),
|
||||||
isLocalGame(_tabSupervisor->getIsLocalGame()), spectator(true), gameStateKnown(false), resuming(false),
|
isLocalGame(_tabSupervisor->getIsLocalGame()), spectator(true), judge(false), gameStateKnown(false),
|
||||||
currentPhase(-1), activeCard(nullptr), gameClosed(false), replay(_replay), currentReplayStep(0),
|
resuming(false), currentPhase(-1), activeCard(nullptr), gameClosed(false), replay(_replay), currentReplayStep(0),
|
||||||
sayLabel(nullptr), sayEdit(nullptr)
|
sayLabel(nullptr), sayEdit(nullptr)
|
||||||
{
|
{
|
||||||
// THIS CTOR IS USED ON REPLAY
|
// THIS CTOR IS USED ON REPLAY
|
||||||
|
@ -393,8 +393,8 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor,
|
||||||
const QMap<int, QString> &_roomGameTypes)
|
const QMap<int, QString> &_roomGameTypes)
|
||||||
: Tab(_tabSupervisor), clients(_clients), gameInfo(event.game_info()), roomGameTypes(_roomGameTypes),
|
: Tab(_tabSupervisor), clients(_clients), gameInfo(event.game_info()), roomGameTypes(_roomGameTypes),
|
||||||
hostId(event.host_id()), localPlayerId(event.player_id()), isLocalGame(_tabSupervisor->getIsLocalGame()),
|
hostId(event.host_id()), localPlayerId(event.player_id()), isLocalGame(_tabSupervisor->getIsLocalGame()),
|
||||||
spectator(event.spectator()), gameStateKnown(false), resuming(event.resuming()), currentPhase(-1),
|
spectator(event.spectator()), judge(event.judge()), gameStateKnown(false), resuming(event.resuming()),
|
||||||
activeCard(nullptr), gameClosed(false), replay(nullptr), replayDock(nullptr)
|
currentPhase(-1), activeCard(nullptr), gameClosed(false), replay(nullptr), replayDock(nullptr)
|
||||||
{
|
{
|
||||||
// THIS CTOR IS USED ON GAMES
|
// THIS CTOR IS USED ON GAMES
|
||||||
gameInfo.set_started(false);
|
gameInfo.set_started(false);
|
||||||
|
@ -751,7 +751,7 @@ void TabGame::actCompleterChanged()
|
||||||
Player *TabGame::addPlayer(int playerId, const ServerInfo_User &info)
|
Player *TabGame::addPlayer(int playerId, const ServerInfo_User &info)
|
||||||
{
|
{
|
||||||
bool local = ((clients.size() > 1) || (playerId == localPlayerId));
|
bool local = ((clients.size() > 1) || (playerId == localPlayerId));
|
||||||
auto *newPlayer = new Player(info, playerId, local, this);
|
auto *newPlayer = new Player(info, playerId, local, judge, this);
|
||||||
connect(newPlayer, SIGNAL(openDeckEditor(const DeckLoader *)), this, SIGNAL(openDeckEditor(const DeckLoader *)));
|
connect(newPlayer, SIGNAL(openDeckEditor(const DeckLoader *)), this, SIGNAL(openDeckEditor(const DeckLoader *)));
|
||||||
QString newPlayerName = "@" + newPlayer->getName();
|
QString newPlayerName = "@" + newPlayer->getName();
|
||||||
if (sayEdit && !autocompleteUserList.contains(newPlayerName)) {
|
if (sayEdit && !autocompleteUserList.contains(newPlayerName)) {
|
||||||
|
@ -789,6 +789,17 @@ void TabGame::processGameEventContainer(const GameEventContainer &cont, Abstract
|
||||||
const GameEvent &event = cont.event_list(i);
|
const GameEvent &event = cont.event_list(i);
|
||||||
const int playerId = event.player_id();
|
const int playerId = event.player_id();
|
||||||
const auto eventType = static_cast<GameEvent::GameEventType>(getPbExtension(event));
|
const auto eventType = static_cast<GameEvent::GameEventType>(getPbExtension(event));
|
||||||
|
|
||||||
|
if (cont.has_forced_by_judge()) {
|
||||||
|
auto id = cont.forced_by_judge();
|
||||||
|
Player *judgep = players.value(id, nullptr);
|
||||||
|
if (judgep) {
|
||||||
|
messageLog->setContextJudgeName(judgep->getName());
|
||||||
|
} else if (spectators.contains(id)) {
|
||||||
|
messageLog->setContextJudgeName(QString::fromStdString(spectators.value(id).name()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (spectators.contains(playerId)) {
|
if (spectators.contains(playerId)) {
|
||||||
switch (eventType) {
|
switch (eventType) {
|
||||||
case GameEvent::GAME_SAY:
|
case GameEvent::GAME_SAY:
|
||||||
|
|
|
@ -124,6 +124,7 @@ private:
|
||||||
int localPlayerId;
|
int localPlayerId;
|
||||||
const bool isLocalGame;
|
const bool isLocalGame;
|
||||||
bool spectator;
|
bool spectator;
|
||||||
|
bool judge;
|
||||||
QMap<int, Player *> players;
|
QMap<int, Player *> players;
|
||||||
QMap<int, ServerInfo_User> spectators;
|
QMap<int, ServerInfo_User> spectators;
|
||||||
bool gameStateKnown;
|
bool gameStateKnown;
|
||||||
|
|
|
@ -44,6 +44,8 @@ UserContextMenu::UserContextMenu(const TabSupervisor *_tabSupervisor, QWidget *p
|
||||||
aBanHistory = new QAction(QString(), this);
|
aBanHistory = new QAction(QString(), this);
|
||||||
aPromoteToMod = new QAction(QString(), this);
|
aPromoteToMod = new QAction(QString(), this);
|
||||||
aDemoteFromMod = new QAction(QString(), this);
|
aDemoteFromMod = new QAction(QString(), this);
|
||||||
|
aPromoteToJudge = new QAction(QString(), this);
|
||||||
|
aDemoteFromJudge = new QAction(QString(), this);
|
||||||
|
|
||||||
retranslateUi();
|
retranslateUi();
|
||||||
}
|
}
|
||||||
|
@ -64,6 +66,8 @@ void UserContextMenu::retranslateUi()
|
||||||
aBanHistory->setText(tr("View user's &ban history"));
|
aBanHistory->setText(tr("View user's &ban history"));
|
||||||
aPromoteToMod->setText(tr("&Promote user to moderator"));
|
aPromoteToMod->setText(tr("&Promote user to moderator"));
|
||||||
aDemoteFromMod->setText(tr("Dem&ote user from moderator"));
|
aDemoteFromMod->setText(tr("Dem&ote user from moderator"));
|
||||||
|
aPromoteToJudge->setText(tr("Promote user to &juge"));
|
||||||
|
aDemoteFromJudge->setText(tr("Demote user from judge"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserContextMenu::gamesOfUserReceived(const Response &resp, const CommandContainer &commandContainer)
|
void UserContextMenu::gamesOfUserReceived(const Response &resp, const CommandContainer &commandContainer)
|
||||||
|
@ -220,7 +224,7 @@ void UserContextMenu::adjustMod_processUserResponse(const Response &resp, const
|
||||||
const Command_AdjustMod &cmd = commandContainer.admin_command(0).GetExtension(Command_AdjustMod::ext);
|
const Command_AdjustMod &cmd = commandContainer.admin_command(0).GetExtension(Command_AdjustMod::ext);
|
||||||
|
|
||||||
if (resp.response_code() == Response::RespOk) {
|
if (resp.response_code() == Response::RespOk) {
|
||||||
if (cmd.should_be_mod()) {
|
if (cmd.should_be_mod() || cmd.should_be_judge()) {
|
||||||
QMessageBox::information(static_cast<QWidget *>(parent()), tr("Success"),
|
QMessageBox::information(static_cast<QWidget *>(parent()), tr("Success"),
|
||||||
tr("Successfully promoted user."));
|
tr("Successfully promoted user."));
|
||||||
} else {
|
} else {
|
||||||
|
@ -228,7 +232,7 @@ void UserContextMenu::adjustMod_processUserResponse(const Response &resp, const
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (cmd.should_be_mod()) {
|
if (cmd.should_be_mod() || cmd.should_be_judge()) {
|
||||||
QMessageBox::information(static_cast<QWidget *>(parent()), tr("Failed"), tr("Failed to promote user."));
|
QMessageBox::information(static_cast<QWidget *>(parent()), tr("Failed"), tr("Failed to promote user."));
|
||||||
} else {
|
} else {
|
||||||
QMessageBox::information(static_cast<QWidget *>(parent()), tr("Failed"), tr("Failed to demote user."));
|
QMessageBox::information(static_cast<QWidget *>(parent()), tr("Failed"), tr("Failed to demote user."));
|
||||||
|
@ -312,6 +316,15 @@ void UserContextMenu::showContextMenu(const QPoint &pos,
|
||||||
(tabSupervisor->getUserInfo()->user_level() & ServerInfo_User::IsAdmin)) {
|
(tabSupervisor->getUserInfo()->user_level() & ServerInfo_User::IsAdmin)) {
|
||||||
menu->addAction(aPromoteToMod);
|
menu->addAction(aPromoteToMod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (userLevel.testFlag(ServerInfo_User::IsJudge) &&
|
||||||
|
(tabSupervisor->getUserInfo()->user_level() & ServerInfo_User::IsAdmin)) {
|
||||||
|
menu->addAction(aDemoteFromJudge);
|
||||||
|
|
||||||
|
} else if (userLevel.testFlag(ServerInfo_User::IsRegistered) &&
|
||||||
|
(tabSupervisor->getUserInfo()->user_level() & ServerInfo_User::IsAdmin)) {
|
||||||
|
menu->addAction(aPromoteToJudge);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bool anotherUser = userName != tabSupervisor->getOwnUsername();
|
bool anotherUser = userName != tabSupervisor->getOwnUsername();
|
||||||
aDetails->setEnabled(true);
|
aDetails->setEnabled(true);
|
||||||
|
@ -389,6 +402,15 @@ void UserContextMenu::showContextMenu(const QPoint &pos,
|
||||||
cmd.set_user_name(userName.toStdString());
|
cmd.set_user_name(userName.toStdString());
|
||||||
cmd.set_should_be_mod(actionClicked == aPromoteToMod);
|
cmd.set_should_be_mod(actionClicked == aPromoteToMod);
|
||||||
|
|
||||||
|
PendingCommand *pend = client->prepareAdminCommand(cmd);
|
||||||
|
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
|
||||||
|
SLOT(adjustMod_processUserResponse(Response, CommandContainer)));
|
||||||
|
client->sendCommand(pend);
|
||||||
|
} else if (actionClicked == aPromoteToJudge || actionClicked == aDemoteFromJudge) {
|
||||||
|
Command_AdjustMod cmd;
|
||||||
|
cmd.set_user_name(userName.toStdString());
|
||||||
|
cmd.set_should_be_judge(actionClicked == aPromoteToJudge);
|
||||||
|
|
||||||
PendingCommand *pend = client->prepareAdminCommand(cmd);
|
PendingCommand *pend = client->prepareAdminCommand(cmd);
|
||||||
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
|
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
|
||||||
SLOT(adjustMod_processUserResponse(Response, CommandContainer)));
|
SLOT(adjustMod_processUserResponse(Response, CommandContainer)));
|
||||||
|
|
|
@ -30,6 +30,7 @@ private:
|
||||||
QAction *aKick;
|
QAction *aKick;
|
||||||
QAction *aBan, *aBanHistory;
|
QAction *aBan, *aBanHistory;
|
||||||
QAction *aPromoteToMod, *aDemoteFromMod;
|
QAction *aPromoteToMod, *aDemoteFromMod;
|
||||||
|
QAction *aPromoteToJudge, *aDemoteFromJudge;
|
||||||
QAction *aWarnUser, *aWarnHistory;
|
QAction *aWarnUser, *aWarnHistory;
|
||||||
signals:
|
signals:
|
||||||
void openMessageDialog(const QString &userName, bool focus);
|
void openMessageDialog(const QString &userName, bool focus);
|
||||||
|
|
|
@ -109,6 +109,9 @@ void UserInfoBox::updateInfo(const ServerInfo_User &user)
|
||||||
else
|
else
|
||||||
userLevelText = tr("Unregistered user");
|
userLevelText = tr("Unregistered user");
|
||||||
|
|
||||||
|
if (userLevel.testFlag(ServerInfo_User::IsJudge))
|
||||||
|
userLevelText += " | " + tr("Judge");
|
||||||
|
|
||||||
if (user.has_privlevel() && user.privlevel() != "NONE") {
|
if (user.has_privlevel() && user.privlevel() != "NONE") {
|
||||||
userLevelText += " | " + QString("%1").arg(user.privlevel().c_str());
|
userLevelText += " | " + QString("%1").arg(user.privlevel().c_str());
|
||||||
}
|
}
|
||||||
|
|
|
@ -307,7 +307,7 @@ bool UserListTWI::operator<(const QTreeWidgetItem &other) const
|
||||||
|
|
||||||
// Sort by user level
|
// Sort by user level
|
||||||
if (data(0, Qt::UserRole) != other.data(0, Qt::UserRole))
|
if (data(0, Qt::UserRole) != other.data(0, Qt::UserRole))
|
||||||
return data(0, Qt::UserRole).toInt() > other.data(0, Qt::UserRole).toInt();
|
return (data(0, Qt::UserRole).toInt() & 15) > (other.data(0, Qt::UserRole).toInt() & 15);
|
||||||
|
|
||||||
// Sort by name
|
// Sort by name
|
||||||
return QString::localeAwareCompare(data(2, Qt::UserRole).toString(), other.data(2, Qt::UserRole).toString()) < 0;
|
return QString::localeAwareCompare(data(2, Qt::UserRole).toString(), other.data(2, Qt::UserRole).toString()) < 0;
|
||||||
|
|
|
@ -34,6 +34,7 @@ message Command_AdjustMod {
|
||||||
optional Command_AdjustMod ext = 1003;
|
optional Command_AdjustMod ext = 1003;
|
||||||
}
|
}
|
||||||
required string user_name = 1;
|
required string user_name = 1;
|
||||||
required bool should_be_mod = 2;
|
optional bool should_be_mod = 2;
|
||||||
|
optional bool should_be_judge = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,4 +13,5 @@ message Event_GameJoined {
|
||||||
optional sint32 player_id = 4;
|
optional sint32 player_id = 4;
|
||||||
optional bool spectator = 5;
|
optional bool spectator = 5;
|
||||||
optional bool resuming = 6;
|
optional bool resuming = 6;
|
||||||
|
optional bool judge = 7;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,15 @@ message GameCommand {
|
||||||
SET_SIDEBOARD_LOCK = 1030;
|
SET_SIDEBOARD_LOCK = 1030;
|
||||||
CHANGE_ZONE_PROPERTIES = 1031;
|
CHANGE_ZONE_PROPERTIES = 1031;
|
||||||
UNCONCEDE = 1032;
|
UNCONCEDE = 1032;
|
||||||
|
JUDGE = 1033;
|
||||||
}
|
}
|
||||||
extensions 100 to max;
|
extensions 100 to max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message Command_Judge {
|
||||||
|
extend GameCommand {
|
||||||
|
optional Command_Judge ext = 1033;
|
||||||
|
}
|
||||||
|
optional sint32 target_id = 1 [default = -1];
|
||||||
|
repeated GameCommand game_command = 2;
|
||||||
|
}
|
||||||
|
|
|
@ -7,4 +7,5 @@ message GameEventContainer {
|
||||||
repeated GameEvent event_list = 2;
|
repeated GameEvent event_list = 2;
|
||||||
optional GameEventContext context = 3;
|
optional GameEventContext context = 3;
|
||||||
optional uint32 seconds_elapsed = 4;
|
optional uint32 seconds_elapsed = 4;
|
||||||
|
optional uint32 forced_by_judge = 5;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ message Command_CreateGame {
|
||||||
optional bool spectators_can_talk = 8;
|
optional bool spectators_can_talk = 8;
|
||||||
optional bool spectators_see_everything = 9;
|
optional bool spectators_see_everything = 9;
|
||||||
repeated uint32 game_type_ids = 10;
|
repeated uint32 game_type_ids = 10;
|
||||||
|
optional bool join_as_judge = 11;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Command_JoinGame {
|
message Command_JoinGame {
|
||||||
|
@ -46,4 +47,5 @@ message Command_JoinGame {
|
||||||
optional string password = 2;
|
optional string password = 2;
|
||||||
optional bool spectator = 3;
|
optional bool spectator = 3;
|
||||||
optional bool override_restrictions = 4;
|
optional bool override_restrictions = 4;
|
||||||
|
optional bool join_as_judge = 5;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,4 +10,5 @@ message ServerInfo_PlayerProperties {
|
||||||
optional string deck_hash = 6;
|
optional string deck_hash = 6;
|
||||||
optional sint32 ping_seconds = 7;
|
optional sint32 ping_seconds = 7;
|
||||||
optional bool sideboard_locked = 8;
|
optional bool sideboard_locked = 8;
|
||||||
|
optional bool judge = 9;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ message ServerInfo_User {
|
||||||
IsRegistered = 2;
|
IsRegistered = 2;
|
||||||
IsModerator = 4;
|
IsModerator = 4;
|
||||||
IsAdmin = 8;
|
IsAdmin = 8;
|
||||||
|
IsJudge = 16;
|
||||||
};
|
};
|
||||||
enum Gender {
|
enum Gender {
|
||||||
GenderUnknown = -1;
|
GenderUnknown = -1;
|
||||||
|
|
|
@ -172,6 +172,10 @@ public:
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
virtual bool permitCreateGameAsJudge() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Server_DatabaseInterface *getDatabaseInterface() const;
|
Server_DatabaseInterface *getDatabaseInterface() const;
|
||||||
int getNextLocalGameId()
|
int getNextLocalGameId()
|
||||||
|
|
|
@ -390,8 +390,11 @@ void Server_Game::stopGameIfFinished()
|
||||||
emit gameInfoChanged(gameInfo);
|
emit gameInfoChanged(gameInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
Response::ResponseCode
|
Response::ResponseCode Server_Game::checkJoin(ServerInfo_User *user,
|
||||||
Server_Game::checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions)
|
const QString &_password,
|
||||||
|
bool spectator,
|
||||||
|
bool overrideRestrictions,
|
||||||
|
bool asJudge)
|
||||||
{
|
{
|
||||||
Server_DatabaseInterface *databaseInterface = room->getServer()->getDatabaseInterface();
|
Server_DatabaseInterface *databaseInterface = room->getServer()->getDatabaseInterface();
|
||||||
{
|
{
|
||||||
|
@ -400,6 +403,10 @@ Server_Game::checkJoin(ServerInfo_User *user, const QString &_password, bool spe
|
||||||
if (playerIterator.next().value()->getUserInfo()->name() == user->name())
|
if (playerIterator.next().value()->getUserInfo()->name() == user->name())
|
||||||
return Response::RespContextError;
|
return Response::RespContextError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (asJudge && !(user->user_level() & ServerInfo_User::IsJudge)) {
|
||||||
|
return Response::RespUserLevelTooLow;
|
||||||
|
}
|
||||||
if (!(overrideRestrictions && (user->user_level() & ServerInfo_User::IsModerator))) {
|
if (!(overrideRestrictions && (user->user_level() & ServerInfo_User::IsModerator))) {
|
||||||
if ((_password != password) && !(spectator && !spectatorsNeedPassword))
|
if ((_password != password) && !(spectator && !spectatorsNeedPassword))
|
||||||
return Response::RespWrongPassword;
|
return Response::RespWrongPassword;
|
||||||
|
@ -437,12 +444,14 @@ bool Server_Game::containsUser(const QString &userName) const
|
||||||
void Server_Game::addPlayer(Server_AbstractUserInterface *userInterface,
|
void Server_Game::addPlayer(Server_AbstractUserInterface *userInterface,
|
||||||
ResponseContainer &rc,
|
ResponseContainer &rc,
|
||||||
bool spectator,
|
bool spectator,
|
||||||
|
bool judge,
|
||||||
bool broadcastUpdate)
|
bool broadcastUpdate)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&gameMutex);
|
QMutexLocker locker(&gameMutex);
|
||||||
|
|
||||||
Server_Player *newPlayer = new Server_Player(this, nextPlayerId++, userInterface->copyUserInfo(true, true, true),
|
Server_Player *newPlayer = new Server_Player(this, nextPlayerId++, userInterface->copyUserInfo(true, true, true),
|
||||||
spectator, userInterface);
|
spectator, judge, userInterface);
|
||||||
|
|
||||||
newPlayer->moveToThread(thread());
|
newPlayer->moveToThread(thread());
|
||||||
|
|
||||||
Event_Join joinEvent;
|
Event_Join joinEvent;
|
||||||
|
@ -663,6 +672,7 @@ void Server_Game::createGameJoinedEvent(Server_Player *player, ResponseContainer
|
||||||
event1.set_host_id(hostId);
|
event1.set_host_id(hostId);
|
||||||
event1.set_player_id(player->getPlayerId());
|
event1.set_player_id(player->getPlayerId());
|
||||||
event1.set_spectator(player->getSpectator());
|
event1.set_spectator(player->getSpectator());
|
||||||
|
event1.set_judge(player->getJudge());
|
||||||
event1.set_resuming(resuming);
|
event1.set_resuming(resuming);
|
||||||
if (resuming) {
|
if (resuming) {
|
||||||
const QStringList &allGameTypes = room->getGameTypes();
|
const QStringList &allGameTypes = room->getGameTypes();
|
||||||
|
|
|
@ -157,11 +157,12 @@ public:
|
||||||
return spectatorsSeeEverything;
|
return spectatorsSeeEverything;
|
||||||
}
|
}
|
||||||
Response::ResponseCode
|
Response::ResponseCode
|
||||||
checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions);
|
checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions, bool asJudge);
|
||||||
bool containsUser(const QString &userName) const;
|
bool containsUser(const QString &userName) const;
|
||||||
void addPlayer(Server_AbstractUserInterface *userInterface,
|
void addPlayer(Server_AbstractUserInterface *userInterface,
|
||||||
ResponseContainer &rc,
|
ResponseContainer &rc,
|
||||||
bool spectator,
|
bool spectator,
|
||||||
|
bool judge,
|
||||||
bool broadcastUpdate = true);
|
bool broadcastUpdate = true);
|
||||||
void removePlayer(Server_Player *player, Event_Leave::LeaveReason reason);
|
void removePlayer(Server_Player *player, Event_Leave::LeaveReason reason);
|
||||||
void removeArrowsRelatedToPlayer(GameEventStorage &ges, Server_Player *player);
|
void removeArrowsRelatedToPlayer(GameEventStorage &ges, Server_Player *player);
|
||||||
|
|
|
@ -87,10 +87,11 @@ Server_Player::Server_Player(Server_Game *_game,
|
||||||
int _playerId,
|
int _playerId,
|
||||||
const ServerInfo_User &_userInfo,
|
const ServerInfo_User &_userInfo,
|
||||||
bool _spectator,
|
bool _spectator,
|
||||||
|
bool _judge,
|
||||||
Server_AbstractUserInterface *_userInterface)
|
Server_AbstractUserInterface *_userInterface)
|
||||||
: ServerInfo_User_Container(_userInfo), game(_game), userInterface(_userInterface), deck(nullptr), pingTime(0),
|
: ServerInfo_User_Container(_userInfo), game(_game), userInterface(_userInterface), deck(nullptr), pingTime(0),
|
||||||
playerId(_playerId), spectator(_spectator), initialCards(0), nextCardId(0), readyStart(false), conceded(false),
|
playerId(_playerId), spectator(_spectator), judge(_judge), initialCards(0), nextCardId(0), readyStart(false),
|
||||||
sideboardLocked(true)
|
conceded(false), sideboardLocked(true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,6 +252,7 @@ void Server_Player::getProperties(ServerInfo_PlayerProperties &result, bool with
|
||||||
result.set_sideboard_locked(sideboardLocked);
|
result.set_sideboard_locked(sideboardLocked);
|
||||||
result.set_ready_start(readyStart);
|
result.set_ready_start(readyStart);
|
||||||
}
|
}
|
||||||
|
result.set_judge(judge);
|
||||||
if (deck)
|
if (deck)
|
||||||
result.set_deck_hash(deck->getDeckHash().toStdString());
|
result.set_deck_hash(deck->getDeckHash().toStdString());
|
||||||
result.set_ping_seconds(pingTime);
|
result.set_ping_seconds(pingTime);
|
||||||
|
@ -353,7 +355,7 @@ Response::ResponseCode Server_Player::moveCard(GameEventStorage &ges,
|
||||||
{
|
{
|
||||||
// Disallow controller change to other zones than the table.
|
// Disallow controller change to other zones than the table.
|
||||||
if (((targetzone->getType() != ServerInfo_Zone::PublicZone) || !targetzone->hasCoords()) &&
|
if (((targetzone->getType() != ServerInfo_Zone::PublicZone) || !targetzone->hasCoords()) &&
|
||||||
(startzone->getPlayer() != targetzone->getPlayer()))
|
(startzone->getPlayer() != targetzone->getPlayer()) && !judge)
|
||||||
return Response::RespContextError;
|
return Response::RespContextError;
|
||||||
|
|
||||||
if (!targetzone->hasCoords() && (x <= -1))
|
if (!targetzone->hasCoords() && (x <= -1))
|
||||||
|
@ -797,6 +799,24 @@ Server_Player::cmdUnconcede(const Command_Unconcede & /*cmd*/, ResponseContainer
|
||||||
return Response::RespOk;
|
return Response::RespOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Response::ResponseCode Server_Player::cmdJudge(const Command_Judge &cmd, ResponseContainer &rc, GameEventStorage &ges)
|
||||||
|
{
|
||||||
|
if (!judge)
|
||||||
|
return Response::RespFunctionNotAllowed;
|
||||||
|
|
||||||
|
Server_Player *player = this->game->getPlayers().value(cmd.target_id());
|
||||||
|
|
||||||
|
ges.setForcedByJudge(playerId);
|
||||||
|
if (player == nullptr)
|
||||||
|
return Response::RespContextError;
|
||||||
|
|
||||||
|
for (int i = 0; i < cmd.game_command_size(); ++i) {
|
||||||
|
player->processGameCommand(cmd.game_command(i), rc, ges);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response::RespOk;
|
||||||
|
}
|
||||||
|
|
||||||
Response::ResponseCode
|
Response::ResponseCode
|
||||||
Server_Player::cmdReadyStart(const Command_ReadyStart &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges)
|
Server_Player::cmdReadyStart(const Command_ReadyStart &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges)
|
||||||
{
|
{
|
||||||
|
@ -988,7 +1008,7 @@ Server_Player::cmdMoveCard(const Command_MoveCard &cmd, ResponseContainer & /*rc
|
||||||
if (!startZone)
|
if (!startZone)
|
||||||
return Response::RespNameNotFound;
|
return Response::RespNameNotFound;
|
||||||
|
|
||||||
if ((startPlayer != this) && (!startZone->getPlayersWithWritePermission().contains(playerId)))
|
if ((startPlayer != this) && (!startZone->getPlayersWithWritePermission().contains(playerId)) && !judge)
|
||||||
return Response::RespContextError;
|
return Response::RespContextError;
|
||||||
|
|
||||||
Server_Player *targetPlayer = game->getPlayers().value(cmd.target_player_id());
|
Server_Player *targetPlayer = game->getPlayers().value(cmd.target_player_id());
|
||||||
|
@ -998,7 +1018,7 @@ Server_Player::cmdMoveCard(const Command_MoveCard &cmd, ResponseContainer & /*rc
|
||||||
if (!targetZone)
|
if (!targetZone)
|
||||||
return Response::RespNameNotFound;
|
return Response::RespNameNotFound;
|
||||||
|
|
||||||
if ((startPlayer != this) && (targetPlayer != this))
|
if ((startPlayer != this) && (targetPlayer != this) && !judge)
|
||||||
return Response::RespContextError;
|
return Response::RespContextError;
|
||||||
|
|
||||||
QList<const CardToMove *> cardsToMove;
|
QList<const CardToMove *> cardsToMove;
|
||||||
|
@ -1491,13 +1511,16 @@ Server_Player::cmdDelCounter(const Command_DelCounter &cmd, ResponseContainer &
|
||||||
Response::ResponseCode
|
Response::ResponseCode
|
||||||
Server_Player::cmdNextTurn(const Command_NextTurn & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/)
|
Server_Player::cmdNextTurn(const Command_NextTurn & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/)
|
||||||
{
|
{
|
||||||
|
if (!game->getGameStarted())
|
||||||
|
return Response::RespGameNotStarted;
|
||||||
|
|
||||||
|
if (!judge) {
|
||||||
if (spectator)
|
if (spectator)
|
||||||
return Response::RespFunctionNotAllowed;
|
return Response::RespFunctionNotAllowed;
|
||||||
|
|
||||||
if (!game->getGameStarted())
|
|
||||||
return Response::RespGameNotStarted;
|
|
||||||
if (conceded)
|
if (conceded)
|
||||||
return Response::RespContextError;
|
return Response::RespContextError;
|
||||||
|
}
|
||||||
|
|
||||||
game->nextTurn();
|
game->nextTurn();
|
||||||
return Response::RespOk;
|
return Response::RespOk;
|
||||||
|
@ -1507,16 +1530,20 @@ Response::ResponseCode Server_Player::cmdSetActivePhase(const Command_SetActiveP
|
||||||
ResponseContainer & /*rc*/,
|
ResponseContainer & /*rc*/,
|
||||||
GameEventStorage & /*ges*/)
|
GameEventStorage & /*ges*/)
|
||||||
{
|
{
|
||||||
|
if (!game->getGameStarted())
|
||||||
|
return Response::RespGameNotStarted;
|
||||||
|
|
||||||
|
if (!judge) {
|
||||||
if (spectator)
|
if (spectator)
|
||||||
return Response::RespFunctionNotAllowed;
|
return Response::RespFunctionNotAllowed;
|
||||||
|
|
||||||
if (!game->getGameStarted())
|
|
||||||
return Response::RespGameNotStarted;
|
|
||||||
if (conceded)
|
if (conceded)
|
||||||
return Response::RespContextError;
|
return Response::RespContextError;
|
||||||
|
|
||||||
if (game->getActivePlayer() != playerId)
|
if (game->getActivePlayer() != playerId)
|
||||||
return Response::RespContextError;
|
return Response::RespContextError;
|
||||||
|
}
|
||||||
|
|
||||||
game->setActivePhase(cmd.phase());
|
game->setActivePhase(cmd.phase());
|
||||||
|
|
||||||
return Response::RespOk;
|
return Response::RespOk;
|
||||||
|
@ -1858,6 +1885,9 @@ Server_Player::processGameCommand(const GameCommand &command, ResponseContainer
|
||||||
case GameCommand::UNCONCEDE:
|
case GameCommand::UNCONCEDE:
|
||||||
return cmdUnconcede(command.GetExtension(Command_Unconcede::ext), rc, ges);
|
return cmdUnconcede(command.GetExtension(Command_Unconcede::ext), rc, ges);
|
||||||
break;
|
break;
|
||||||
|
case GameCommand::JUDGE:
|
||||||
|
return cmdJudge(command.GetExtension(Command_Judge::ext), rc, ges);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return Response::RespInvalidCommand;
|
return Response::RespInvalidCommand;
|
||||||
|
|
|
@ -47,6 +47,7 @@ class Command_IncCardCounter;
|
||||||
class Command_ReadyStart;
|
class Command_ReadyStart;
|
||||||
class Command_Concede;
|
class Command_Concede;
|
||||||
class Command_Unconcede;
|
class Command_Unconcede;
|
||||||
|
class Command_Judge;
|
||||||
class Command_IncCounter;
|
class Command_IncCounter;
|
||||||
class Command_CreateCounter;
|
class Command_CreateCounter;
|
||||||
class Command_SetCounter;
|
class Command_SetCounter;
|
||||||
|
@ -77,6 +78,7 @@ private:
|
||||||
int pingTime;
|
int pingTime;
|
||||||
int playerId;
|
int playerId;
|
||||||
bool spectator;
|
bool spectator;
|
||||||
|
bool judge;
|
||||||
int initialCards;
|
int initialCards;
|
||||||
int nextCardId;
|
int nextCardId;
|
||||||
bool readyStart;
|
bool readyStart;
|
||||||
|
@ -89,6 +91,7 @@ public:
|
||||||
int _playerId,
|
int _playerId,
|
||||||
const ServerInfo_User &_userInfo,
|
const ServerInfo_User &_userInfo,
|
||||||
bool _spectator,
|
bool _spectator,
|
||||||
|
bool _judge,
|
||||||
Server_AbstractUserInterface *_handler);
|
Server_AbstractUserInterface *_handler);
|
||||||
~Server_Player() override;
|
~Server_Player() override;
|
||||||
void prepareDestroy();
|
void prepareDestroy();
|
||||||
|
@ -115,6 +118,10 @@ public:
|
||||||
{
|
{
|
||||||
return spectator;
|
return spectator;
|
||||||
}
|
}
|
||||||
|
bool getJudge() const
|
||||||
|
{
|
||||||
|
return judge;
|
||||||
|
}
|
||||||
bool getConceded() const
|
bool getConceded() const
|
||||||
{
|
{
|
||||||
return conceded;
|
return conceded;
|
||||||
|
@ -185,6 +192,7 @@ public:
|
||||||
cmdKickFromGame(const Command_KickFromGame &cmd, ResponseContainer &rc, GameEventStorage &ges);
|
cmdKickFromGame(const Command_KickFromGame &cmd, ResponseContainer &rc, GameEventStorage &ges);
|
||||||
Response::ResponseCode cmdConcede(const Command_Concede &cmd, ResponseContainer &rc, GameEventStorage &ges);
|
Response::ResponseCode cmdConcede(const Command_Concede &cmd, ResponseContainer &rc, GameEventStorage &ges);
|
||||||
Response::ResponseCode cmdUnconcede(const Command_Unconcede &cmd, ResponseContainer &rc, GameEventStorage &ges);
|
Response::ResponseCode cmdUnconcede(const Command_Unconcede &cmd, ResponseContainer &rc, GameEventStorage &ges);
|
||||||
|
Response::ResponseCode cmdJudge(const Command_Judge &cmd, ResponseContainer &rc, GameEventStorage &ges);
|
||||||
Response::ResponseCode cmdReadyStart(const Command_ReadyStart &cmd, ResponseContainer &rc, GameEventStorage &ges);
|
Response::ResponseCode cmdReadyStart(const Command_ReadyStart &cmd, ResponseContainer &rc, GameEventStorage &ges);
|
||||||
Response::ResponseCode cmdDeckSelect(const Command_DeckSelect &cmd, ResponseContainer &rc, GameEventStorage &ges);
|
Response::ResponseCode cmdDeckSelect(const Command_DeckSelect &cmd, ResponseContainer &rc, GameEventStorage &ges);
|
||||||
Response::ResponseCode
|
Response::ResponseCode
|
||||||
|
|
|
@ -762,6 +762,11 @@ Server_ProtocolHandler::cmdCreateGame(const Command_CreateGame &cmd, Server_Room
|
||||||
if (room->getGamesCreatedByUser(QString::fromStdString(userInfo->name())) >= server->getMaxGamesPerUser())
|
if (room->getGamesCreatedByUser(QString::fromStdString(userInfo->name())) >= server->getMaxGamesPerUser())
|
||||||
return Response::RespContextError;
|
return Response::RespContextError;
|
||||||
|
|
||||||
|
if (cmd.join_as_judge() && !server->permitCreateGameAsJudge() &&
|
||||||
|
!(userInfo->user_level() & ServerInfo_User::IsJudge)) {
|
||||||
|
return Response::RespContextError;
|
||||||
|
}
|
||||||
|
|
||||||
QList<int> gameTypes;
|
QList<int> gameTypes;
|
||||||
for (int i = cmd.game_type_ids_size() - 1; i >= 0; --i)
|
for (int i = cmd.game_type_ids_size() - 1; i >= 0; --i)
|
||||||
gameTypes.append(cmd.game_type_ids(i));
|
gameTypes.append(cmd.game_type_ids(i));
|
||||||
|
@ -776,7 +781,8 @@ Server_ProtocolHandler::cmdCreateGame(const Command_CreateGame &cmd, Server_Room
|
||||||
copyUserInfo(false), gameId, description, QString::fromStdString(cmd.password()), cmd.max_players(), gameTypes,
|
copyUserInfo(false), gameId, description, QString::fromStdString(cmd.password()), cmd.max_players(), gameTypes,
|
||||||
cmd.only_buddies(), onlyRegisteredUsers, cmd.spectators_allowed(), cmd.spectators_need_password(),
|
cmd.only_buddies(), onlyRegisteredUsers, cmd.spectators_allowed(), cmd.spectators_need_password(),
|
||||||
cmd.spectators_can_talk(), cmd.spectators_see_everything(), room);
|
cmd.spectators_can_talk(), cmd.spectators_see_everything(), room);
|
||||||
game->addPlayer(this, rc, false, false);
|
|
||||||
|
game->addPlayer(this, rc, false, cmd.join_as_judge(), false);
|
||||||
room->addGame(game);
|
room->addGame(game);
|
||||||
|
|
||||||
return Response::RespOk;
|
return Response::RespOk;
|
||||||
|
|
|
@ -53,6 +53,10 @@ void GameEventStorage::sendToGame(Server_Game *game)
|
||||||
|
|
||||||
GameEventContainer *contPrivate = new GameEventContainer;
|
GameEventContainer *contPrivate = new GameEventContainer;
|
||||||
GameEventContainer *contOthers = new GameEventContainer;
|
GameEventContainer *contOthers = new GameEventContainer;
|
||||||
|
if (forcedByJudge != -1) {
|
||||||
|
contPrivate->set_forced_by_judge(forcedByJudge);
|
||||||
|
contOthers->set_forced_by_judge(forcedByJudge);
|
||||||
|
}
|
||||||
for (int i = 0; i < gameEventList.size(); ++i) {
|
for (int i = 0; i < gameEventList.size(); ++i) {
|
||||||
const GameEvent &event = gameEventList[i]->getGameEvent();
|
const GameEvent &event = gameEventList[i]->getGameEvent();
|
||||||
const GameEventStorageItem::EventRecipients recipients = gameEventList[i]->getRecipients();
|
const GameEventStorageItem::EventRecipients recipients = gameEventList[i]->getRecipients();
|
||||||
|
|
|
@ -48,6 +48,7 @@ private:
|
||||||
::google::protobuf::Message *gameEventContext;
|
::google::protobuf::Message *gameEventContext;
|
||||||
QList<GameEventStorageItem *> gameEventList;
|
QList<GameEventStorageItem *> gameEventList;
|
||||||
int privatePlayerId;
|
int privatePlayerId;
|
||||||
|
int forcedByJudge = -1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GameEventStorage();
|
GameEventStorage();
|
||||||
|
@ -66,6 +67,10 @@ public:
|
||||||
{
|
{
|
||||||
return privatePlayerId;
|
return privatePlayerId;
|
||||||
}
|
}
|
||||||
|
void setForcedByJudge(int playerId)
|
||||||
|
{
|
||||||
|
forcedByJudge = playerId;
|
||||||
|
}
|
||||||
|
|
||||||
void enqueueGameEvent(const ::google::protobuf::Message &event,
|
void enqueueGameEvent(const ::google::protobuf::Message &event,
|
||||||
int playerId,
|
int playerId,
|
||||||
|
|
|
@ -262,9 +262,9 @@ Response::ResponseCode Server_Room::processJoinGameCommand(const Command_JoinGam
|
||||||
QMutexLocker gameLocker(&g->gameMutex);
|
QMutexLocker gameLocker(&g->gameMutex);
|
||||||
|
|
||||||
Response::ResponseCode result = g->checkJoin(userInterface->getUserInfo(), QString::fromStdString(cmd.password()),
|
Response::ResponseCode result = g->checkJoin(userInterface->getUserInfo(), QString::fromStdString(cmd.password()),
|
||||||
cmd.spectator(), cmd.override_restrictions());
|
cmd.spectator(), cmd.override_restrictions(), cmd.join_as_judge());
|
||||||
if (result == Response::RespOk)
|
if (result == Response::RespOk)
|
||||||
g->addPlayer(userInterface, rc, cmd.spectator());
|
g->addPlayer(userInterface, rc, cmd.spectator(), cmd.join_as_judge());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -304,6 +304,11 @@ max_game_inactivity_time=120
|
||||||
; the database. Default value is true.
|
; the database. Default value is true.
|
||||||
store_replays=true
|
store_replays=true
|
||||||
|
|
||||||
|
; Allow users to create a new game and join it as a judge. The host will be able to execute any action on
|
||||||
|
; the cards of every player. This is needed in order to support some games (eg. Werewolf).
|
||||||
|
; Default off to prevent abuse on servers that are mostly running other games.
|
||||||
|
allow_create_as_judge=false
|
||||||
|
|
||||||
[security]
|
[security]
|
||||||
; You may want to restrict the number of users that can connect to your server at any given time.
|
; You may want to restrict the number of users that can connect to your server at any given time.
|
||||||
enable_max_user_limit=false
|
enable_max_user_limit=false
|
||||||
|
|
|
@ -950,6 +950,11 @@ int Servatrice::getNumberOfTCPPools() const
|
||||||
return settingsCache->value("server/number_pools", 1).toInt();
|
return settingsCache->value("server/number_pools", 1).toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Servatrice::permitCreateGameAsJudge() const
|
||||||
|
{
|
||||||
|
return settingsCache->value("game/allow_create_as_judge", false).toBool();
|
||||||
|
}
|
||||||
|
|
||||||
QHostAddress Servatrice::getServerTCPHost() const
|
QHostAddress Servatrice::getServerTCPHost() const
|
||||||
{
|
{
|
||||||
QString host = settingsCache->value("server/host", "any").toString();
|
QString host = settingsCache->value("server/host", "any").toString();
|
||||||
|
|
|
@ -268,6 +268,7 @@ public:
|
||||||
int getCommandCountingInterval() const override;
|
int getCommandCountingInterval() const override;
|
||||||
int getMaxCommandCountPerInterval() const override;
|
int getMaxCommandCountPerInterval() const override;
|
||||||
int getMaxUserTotal() const override;
|
int getMaxUserTotal() const override;
|
||||||
|
bool permitCreateGameAsJudge() const override;
|
||||||
int getMaxTcpUserLimit() const;
|
int getMaxTcpUserLimit() const;
|
||||||
int getMaxWebSocketUserLimit() const;
|
int getMaxWebSocketUserLimit() const;
|
||||||
int getUsersWithAddress(const QHostAddress &address) const;
|
int getUsersWithAddress(const QHostAddress &address) const;
|
||||||
|
|
|
@ -549,10 +549,14 @@ ServerInfo_User Servatrice_DatabaseInterface::evalUserQueryResult(const QSqlQuer
|
||||||
|
|
||||||
const int is_admin = query->value(2).toInt();
|
const int is_admin = query->value(2).toInt();
|
||||||
int userLevel = ServerInfo_User::IsUser | ServerInfo_User::IsRegistered;
|
int userLevel = ServerInfo_User::IsUser | ServerInfo_User::IsRegistered;
|
||||||
if (is_admin == 1)
|
if (is_admin & 1)
|
||||||
userLevel |= ServerInfo_User::IsAdmin | ServerInfo_User::IsModerator;
|
userLevel |= ServerInfo_User::IsAdmin | ServerInfo_User::IsModerator;
|
||||||
else if (is_admin == 2)
|
else if (is_admin & 2)
|
||||||
userLevel |= ServerInfo_User::IsModerator;
|
userLevel |= ServerInfo_User::IsModerator;
|
||||||
|
|
||||||
|
if (is_admin & 4)
|
||||||
|
userLevel |= ServerInfo_User::IsJudge;
|
||||||
|
|
||||||
result.set_user_level(userLevel);
|
result.set_user_level(userLevel);
|
||||||
|
|
||||||
const QString country = query->value(3).toString();
|
const QString country = query->value(3).toString();
|
||||||
|
|
|
@ -1415,21 +1415,16 @@ Response::ResponseCode AbstractServerSocketInterface::cmdReloadConfig(const Comm
|
||||||
return Response::RespOk;
|
return Response::RespOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Response::ResponseCode AbstractServerSocketInterface::cmdAdjustMod(const Command_AdjustMod &cmd,
|
bool AbstractServerSocketInterface::addAdminFlagToUser(const QString &userName, int flag)
|
||||||
ResponseContainer & /*rc*/)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
QString userName = QString::fromStdString(cmd.user_name());
|
|
||||||
|
|
||||||
if (cmd.should_be_mod()) {
|
|
||||||
QSqlQuery *query =
|
QSqlQuery *query =
|
||||||
sqlInterface->prepareQuery("update {prefix}_users set admin = :adminlevel where name = :username");
|
sqlInterface->prepareQuery("update {prefix}_users set admin = (admin | :adminlevel) where name = :username");
|
||||||
query->bindValue(":adminlevel", 2);
|
query->bindValue(":adminlevel", flag);
|
||||||
query->bindValue(":username", userName);
|
query->bindValue(":username", userName);
|
||||||
if (!sqlInterface->execSqlQuery(query)) {
|
if (!sqlInterface->execSqlQuery(query)) {
|
||||||
logger->logMessage(
|
logger->logMessage(
|
||||||
QString::fromStdString("Failed to promote user %1: %2").arg(userName).arg(query->lastError().text()));
|
QString::fromStdString("Failed to promote user %1: %2").arg(userName).arg(query->lastError().text()));
|
||||||
return Response::RespInternalError;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractServerSocketInterface *user =
|
AbstractServerSocketInterface *user =
|
||||||
|
@ -1441,15 +1436,20 @@ Response::ResponseCode AbstractServerSocketInterface::cmdAdjustMod(const Command
|
||||||
user->sendProtocolItem(*se);
|
user->sendProtocolItem(*se);
|
||||||
delete se;
|
delete se;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AbstractServerSocketInterface::removeAdminFlagFromUser(const QString &userName, int flag)
|
||||||
|
{
|
||||||
QSqlQuery *query =
|
QSqlQuery *query =
|
||||||
sqlInterface->prepareQuery("update {prefix}_users set admin = :adminlevel where name = :username");
|
sqlInterface->prepareQuery("update {prefix}_users set admin = (admin & ~ :adminlevel) where name = :username");
|
||||||
query->bindValue(":adminlevel", 0);
|
query->bindValue(":adminlevel", flag);
|
||||||
query->bindValue(":username", userName);
|
query->bindValue(":username", userName);
|
||||||
if (!sqlInterface->execSqlQuery(query)) {
|
if (!sqlInterface->execSqlQuery(query)) {
|
||||||
logger->logMessage(
|
logger->logMessage(
|
||||||
QString::fromStdString("Failed to demote user %1: %2").arg(userName).arg(query->lastError().text()));
|
QString::fromStdString("Failed to demote user %1: %2").arg(userName).arg(query->lastError().text()));
|
||||||
return Response::RespInternalError;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractServerSocketInterface *user =
|
AbstractServerSocketInterface *user =
|
||||||
|
@ -1457,7 +1457,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdAdjustMod(const Command
|
||||||
if (user) {
|
if (user) {
|
||||||
Event_ConnectionClosed event;
|
Event_ConnectionClosed event;
|
||||||
event.set_reason(Event_ConnectionClosed::DEMOTED);
|
event.set_reason(Event_ConnectionClosed::DEMOTED);
|
||||||
event.set_reason_str("Your moderator status has been revoked.");
|
event.set_reason_str("Your moderator and/or judge status has been revoked.");
|
||||||
event.set_end_time(QDateTime::currentDateTime().toTime_t());
|
event.set_end_time(QDateTime::currentDateTime().toTime_t());
|
||||||
|
|
||||||
SessionEvent *se = user->prepareSessionEvent(event);
|
SessionEvent *se = user->prepareSessionEvent(event);
|
||||||
|
@ -1466,6 +1466,37 @@ Response::ResponseCode AbstractServerSocketInterface::cmdAdjustMod(const Command
|
||||||
}
|
}
|
||||||
|
|
||||||
QMetaObject::invokeMethod(user, "prepareDestroy", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(user, "prepareDestroy", Qt::QueuedConnection);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Response::ResponseCode AbstractServerSocketInterface::cmdAdjustMod(const Command_AdjustMod &cmd,
|
||||||
|
ResponseContainer & /*rc*/)
|
||||||
|
{
|
||||||
|
|
||||||
|
QString userName = QString::fromStdString(cmd.user_name());
|
||||||
|
|
||||||
|
if (cmd.has_should_be_mod()) {
|
||||||
|
if (cmd.should_be_mod()) {
|
||||||
|
if (!addAdminFlagToUser(userName, 2)) {
|
||||||
|
return Response::RespInternalError;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!removeAdminFlagFromUser(userName, 2)) {
|
||||||
|
return Response::RespInternalError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd.has_should_be_judge()) {
|
||||||
|
if (cmd.should_be_judge()) {
|
||||||
|
if (!addAdminFlagToUser(userName, 4)) {
|
||||||
|
return Response::RespInternalError;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!removeAdminFlagFromUser(userName, 4)) {
|
||||||
|
return Response::RespInternalError;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Response::RespOk;
|
return Response::RespOk;
|
||||||
|
|
|
@ -119,6 +119,9 @@ private:
|
||||||
Response::ResponseCode cmdAccountImage(const Command_AccountImage &cmd, ResponseContainer &rc);
|
Response::ResponseCode cmdAccountImage(const Command_AccountImage &cmd, ResponseContainer &rc);
|
||||||
Response::ResponseCode cmdAccountPassword(const Command_AccountPassword &cmd, ResponseContainer &rc);
|
Response::ResponseCode cmdAccountPassword(const Command_AccountPassword &cmd, ResponseContainer &rc);
|
||||||
|
|
||||||
|
bool addAdminFlagToUser(const QString &user, int flag);
|
||||||
|
bool removeAdminFlagFromUser(const QString &user, int flag);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AbstractServerSocketInterface(Servatrice *_server,
|
AbstractServerSocketInterface(Servatrice *_server,
|
||||||
Servatrice_DatabaseInterface *_databaseInterface,
|
Servatrice_DatabaseInterface *_databaseInterface,
|
||||||
|
|
Loading…
Reference in a new issue