mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-06-22 06:43:54 -07:00
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
|
|
@ -34,6 +34,7 @@ message Command_AdjustMod {
|
|||
optional Command_AdjustMod ext = 1003;
|
||||
}
|
||||
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 bool spectator = 5;
|
||||
optional bool resuming = 6;
|
||||
optional bool judge = 7;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,15 @@ message GameCommand {
|
|||
SET_SIDEBOARD_LOCK = 1030;
|
||||
CHANGE_ZONE_PROPERTIES = 1031;
|
||||
UNCONCEDE = 1032;
|
||||
|
||||
JUDGE = 1033;
|
||||
}
|
||||
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;
|
||||
optional GameEventContext context = 3;
|
||||
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_see_everything = 9;
|
||||
repeated uint32 game_type_ids = 10;
|
||||
optional bool join_as_judge = 11;
|
||||
}
|
||||
|
||||
message Command_JoinGame {
|
||||
|
|
@ -46,4 +47,5 @@ message Command_JoinGame {
|
|||
optional string password = 2;
|
||||
optional bool spectator = 3;
|
||||
optional bool override_restrictions = 4;
|
||||
optional bool join_as_judge = 5;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,4 +10,5 @@ message ServerInfo_PlayerProperties {
|
|||
optional string deck_hash = 6;
|
||||
optional sint32 ping_seconds = 7;
|
||||
optional bool sideboard_locked = 8;
|
||||
optional bool judge = 9;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ message ServerInfo_User {
|
|||
IsRegistered = 2;
|
||||
IsModerator = 4;
|
||||
IsAdmin = 8;
|
||||
IsJudge = 16;
|
||||
};
|
||||
enum Gender {
|
||||
GenderUnknown = -1;
|
||||
|
|
|
|||
|
|
@ -172,6 +172,10 @@ public:
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
virtual bool permitCreateGameAsJudge() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Server_DatabaseInterface *getDatabaseInterface() const;
|
||||
int getNextLocalGameId()
|
||||
|
|
|
|||
|
|
@ -390,8 +390,11 @@ void Server_Game::stopGameIfFinished()
|
|||
emit gameInfoChanged(gameInfo);
|
||||
}
|
||||
|
||||
Response::ResponseCode
|
||||
Server_Game::checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions)
|
||||
Response::ResponseCode Server_Game::checkJoin(ServerInfo_User *user,
|
||||
const QString &_password,
|
||||
bool spectator,
|
||||
bool overrideRestrictions,
|
||||
bool asJudge)
|
||||
{
|
||||
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())
|
||||
return Response::RespContextError;
|
||||
}
|
||||
|
||||
if (asJudge && !(user->user_level() & ServerInfo_User::IsJudge)) {
|
||||
return Response::RespUserLevelTooLow;
|
||||
}
|
||||
if (!(overrideRestrictions && (user->user_level() & ServerInfo_User::IsModerator))) {
|
||||
if ((_password != password) && !(spectator && !spectatorsNeedPassword))
|
||||
return Response::RespWrongPassword;
|
||||
|
|
@ -437,12 +444,14 @@ bool Server_Game::containsUser(const QString &userName) const
|
|||
void Server_Game::addPlayer(Server_AbstractUserInterface *userInterface,
|
||||
ResponseContainer &rc,
|
||||
bool spectator,
|
||||
bool judge,
|
||||
bool broadcastUpdate)
|
||||
{
|
||||
QMutexLocker locker(&gameMutex);
|
||||
|
||||
Server_Player *newPlayer = new Server_Player(this, nextPlayerId++, userInterface->copyUserInfo(true, true, true),
|
||||
spectator, userInterface);
|
||||
spectator, judge, userInterface);
|
||||
|
||||
newPlayer->moveToThread(thread());
|
||||
|
||||
Event_Join joinEvent;
|
||||
|
|
@ -663,6 +672,7 @@ void Server_Game::createGameJoinedEvent(Server_Player *player, ResponseContainer
|
|||
event1.set_host_id(hostId);
|
||||
event1.set_player_id(player->getPlayerId());
|
||||
event1.set_spectator(player->getSpectator());
|
||||
event1.set_judge(player->getJudge());
|
||||
event1.set_resuming(resuming);
|
||||
if (resuming) {
|
||||
const QStringList &allGameTypes = room->getGameTypes();
|
||||
|
|
|
|||
|
|
@ -157,11 +157,12 @@ public:
|
|||
return spectatorsSeeEverything;
|
||||
}
|
||||
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;
|
||||
void addPlayer(Server_AbstractUserInterface *userInterface,
|
||||
ResponseContainer &rc,
|
||||
bool spectator,
|
||||
bool judge,
|
||||
bool broadcastUpdate = true);
|
||||
void removePlayer(Server_Player *player, Event_Leave::LeaveReason reason);
|
||||
void removeArrowsRelatedToPlayer(GameEventStorage &ges, Server_Player *player);
|
||||
|
|
|
|||
|
|
@ -87,10 +87,11 @@ Server_Player::Server_Player(Server_Game *_game,
|
|||
int _playerId,
|
||||
const ServerInfo_User &_userInfo,
|
||||
bool _spectator,
|
||||
bool _judge,
|
||||
Server_AbstractUserInterface *_userInterface)
|
||||
: ServerInfo_User_Container(_userInfo), game(_game), userInterface(_userInterface), deck(nullptr), pingTime(0),
|
||||
playerId(_playerId), spectator(_spectator), initialCards(0), nextCardId(0), readyStart(false), conceded(false),
|
||||
sideboardLocked(true)
|
||||
playerId(_playerId), spectator(_spectator), judge(_judge), initialCards(0), nextCardId(0), readyStart(false),
|
||||
conceded(false), sideboardLocked(true)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -251,6 +252,7 @@ void Server_Player::getProperties(ServerInfo_PlayerProperties &result, bool with
|
|||
result.set_sideboard_locked(sideboardLocked);
|
||||
result.set_ready_start(readyStart);
|
||||
}
|
||||
result.set_judge(judge);
|
||||
if (deck)
|
||||
result.set_deck_hash(deck->getDeckHash().toStdString());
|
||||
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.
|
||||
if (((targetzone->getType() != ServerInfo_Zone::PublicZone) || !targetzone->hasCoords()) &&
|
||||
(startzone->getPlayer() != targetzone->getPlayer()))
|
||||
(startzone->getPlayer() != targetzone->getPlayer()) && !judge)
|
||||
return Response::RespContextError;
|
||||
|
||||
if (!targetzone->hasCoords() && (x <= -1))
|
||||
|
|
@ -797,6 +799,24 @@ Server_Player::cmdUnconcede(const Command_Unconcede & /*cmd*/, ResponseContainer
|
|||
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
|
||||
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)
|
||||
return Response::RespNameNotFound;
|
||||
|
||||
if ((startPlayer != this) && (!startZone->getPlayersWithWritePermission().contains(playerId)))
|
||||
if ((startPlayer != this) && (!startZone->getPlayersWithWritePermission().contains(playerId)) && !judge)
|
||||
return Response::RespContextError;
|
||||
|
||||
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)
|
||||
return Response::RespNameNotFound;
|
||||
|
||||
if ((startPlayer != this) && (targetPlayer != this))
|
||||
if ((startPlayer != this) && (targetPlayer != this) && !judge)
|
||||
return Response::RespContextError;
|
||||
|
||||
QList<const CardToMove *> cardsToMove;
|
||||
|
|
@ -1491,13 +1511,16 @@ Server_Player::cmdDelCounter(const Command_DelCounter &cmd, ResponseContainer &
|
|||
Response::ResponseCode
|
||||
Server_Player::cmdNextTurn(const Command_NextTurn & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/)
|
||||
{
|
||||
if (spectator)
|
||||
return Response::RespFunctionNotAllowed;
|
||||
|
||||
if (!game->getGameStarted())
|
||||
return Response::RespGameNotStarted;
|
||||
if (conceded)
|
||||
return Response::RespContextError;
|
||||
|
||||
if (!judge) {
|
||||
if (spectator)
|
||||
return Response::RespFunctionNotAllowed;
|
||||
|
||||
if (conceded)
|
||||
return Response::RespContextError;
|
||||
}
|
||||
|
||||
game->nextTurn();
|
||||
return Response::RespOk;
|
||||
|
|
@ -1507,16 +1530,20 @@ Response::ResponseCode Server_Player::cmdSetActivePhase(const Command_SetActiveP
|
|||
ResponseContainer & /*rc*/,
|
||||
GameEventStorage & /*ges*/)
|
||||
{
|
||||
if (spectator)
|
||||
return Response::RespFunctionNotAllowed;
|
||||
|
||||
if (!game->getGameStarted())
|
||||
return Response::RespGameNotStarted;
|
||||
if (conceded)
|
||||
return Response::RespContextError;
|
||||
|
||||
if (game->getActivePlayer() != playerId)
|
||||
return Response::RespContextError;
|
||||
if (!judge) {
|
||||
if (spectator)
|
||||
return Response::RespFunctionNotAllowed;
|
||||
|
||||
if (conceded)
|
||||
return Response::RespContextError;
|
||||
|
||||
if (game->getActivePlayer() != playerId)
|
||||
return Response::RespContextError;
|
||||
}
|
||||
|
||||
game->setActivePhase(cmd.phase());
|
||||
|
||||
return Response::RespOk;
|
||||
|
|
@ -1858,6 +1885,9 @@ Server_Player::processGameCommand(const GameCommand &command, ResponseContainer
|
|||
case GameCommand::UNCONCEDE:
|
||||
return cmdUnconcede(command.GetExtension(Command_Unconcede::ext), rc, ges);
|
||||
break;
|
||||
case GameCommand::JUDGE:
|
||||
return cmdJudge(command.GetExtension(Command_Judge::ext), rc, ges);
|
||||
break;
|
||||
|
||||
default:
|
||||
return Response::RespInvalidCommand;
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ class Command_IncCardCounter;
|
|||
class Command_ReadyStart;
|
||||
class Command_Concede;
|
||||
class Command_Unconcede;
|
||||
class Command_Judge;
|
||||
class Command_IncCounter;
|
||||
class Command_CreateCounter;
|
||||
class Command_SetCounter;
|
||||
|
|
@ -77,6 +78,7 @@ private:
|
|||
int pingTime;
|
||||
int playerId;
|
||||
bool spectator;
|
||||
bool judge;
|
||||
int initialCards;
|
||||
int nextCardId;
|
||||
bool readyStart;
|
||||
|
|
@ -89,6 +91,7 @@ public:
|
|||
int _playerId,
|
||||
const ServerInfo_User &_userInfo,
|
||||
bool _spectator,
|
||||
bool _judge,
|
||||
Server_AbstractUserInterface *_handler);
|
||||
~Server_Player() override;
|
||||
void prepareDestroy();
|
||||
|
|
@ -115,6 +118,10 @@ public:
|
|||
{
|
||||
return spectator;
|
||||
}
|
||||
bool getJudge() const
|
||||
{
|
||||
return judge;
|
||||
}
|
||||
bool getConceded() const
|
||||
{
|
||||
return conceded;
|
||||
|
|
@ -185,6 +192,7 @@ public:
|
|||
cmdKickFromGame(const Command_KickFromGame &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 cmdJudge(const Command_Judge &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
|
||||
|
|
|
|||
|
|
@ -762,6 +762,11 @@ Server_ProtocolHandler::cmdCreateGame(const Command_CreateGame &cmd, Server_Room
|
|||
if (room->getGamesCreatedByUser(QString::fromStdString(userInfo->name())) >= server->getMaxGamesPerUser())
|
||||
return Response::RespContextError;
|
||||
|
||||
if (cmd.join_as_judge() && !server->permitCreateGameAsJudge() &&
|
||||
!(userInfo->user_level() & ServerInfo_User::IsJudge)) {
|
||||
return Response::RespContextError;
|
||||
}
|
||||
|
||||
QList<int> gameTypes;
|
||||
for (int i = cmd.game_type_ids_size() - 1; i >= 0; --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,
|
||||
cmd.only_buddies(), onlyRegisteredUsers, cmd.spectators_allowed(), cmd.spectators_need_password(),
|
||||
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);
|
||||
|
||||
return Response::RespOk;
|
||||
|
|
|
|||
|
|
@ -53,6 +53,10 @@ void GameEventStorage::sendToGame(Server_Game *game)
|
|||
|
||||
GameEventContainer *contPrivate = 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) {
|
||||
const GameEvent &event = gameEventList[i]->getGameEvent();
|
||||
const GameEventStorageItem::EventRecipients recipients = gameEventList[i]->getRecipients();
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ private:
|
|||
::google::protobuf::Message *gameEventContext;
|
||||
QList<GameEventStorageItem *> gameEventList;
|
||||
int privatePlayerId;
|
||||
int forcedByJudge = -1;
|
||||
|
||||
public:
|
||||
GameEventStorage();
|
||||
|
|
@ -66,6 +67,10 @@ public:
|
|||
{
|
||||
return privatePlayerId;
|
||||
}
|
||||
void setForcedByJudge(int playerId)
|
||||
{
|
||||
forcedByJudge = playerId;
|
||||
}
|
||||
|
||||
void enqueueGameEvent(const ::google::protobuf::Message &event,
|
||||
int playerId,
|
||||
|
|
|
|||
|
|
@ -262,9 +262,9 @@ Response::ResponseCode Server_Room::processJoinGameCommand(const Command_JoinGam
|
|||
QMutexLocker gameLocker(&g->gameMutex);
|
||||
|
||||
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)
|
||||
g->addPlayer(userInterface, rc, cmd.spectator());
|
||||
g->addPlayer(userInterface, rc, cmd.spectator(), cmd.join_as_judge());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue