diff --git a/cockatrice/src/playerlistwidget.cpp b/cockatrice/src/playerlistwidget.cpp index 87171cc28..03c798677 100644 --- a/cockatrice/src/playerlistwidget.cpp +++ b/cockatrice/src/playerlistwidget.cpp @@ -2,10 +2,37 @@ #include "playerlistwidget.h" #include "protocol_datastructures.h" #include "pixmapgenerator.h" +#include "abstractclient.h" +#include "tab_game.h" +#include "tab_supervisor.h" +#include "tab_userlists.h" +#include "protocol_items.h" +#include "userlist.h" +#include "userinfobox.h" #include +#include +#include +#include -PlayerListWidget::PlayerListWidget(QWidget *parent) - : QTreeWidget(parent), gameStarted(false) +PlayerListItemDelegate::PlayerListItemDelegate(QObject *const parent) + : QStyledItemDelegate(parent) +{ +} + +bool PlayerListItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) +{ + if ((event->type() == QEvent::MouseButtonPress) && index.isValid()) { + QMouseEvent *const mouseEvent = static_cast(event); + if (mouseEvent->button() == Qt::RightButton) { + static_cast(parent())->showContextMenu(mouseEvent->globalPos(), index); + return true; + } + } + return QStyledItemDelegate::editorEvent(event, model, option, index); +} + +PlayerListWidget::PlayerListWidget(TabSupervisor *_tabSupervisor, AbstractClient *_client, TabGame *_game, bool _gameCreator, QWidget *parent) + : QTreeWidget(parent), tabSupervisor(_tabSupervisor), client(_client), game(_game), gameCreator(_gameCreator), gameStarted(false) { readyIcon = QIcon(":/resources/icon_ready_start.svg"); notReadyIcon = QIcon(":/resources/icon_not_ready_start.svg"); @@ -13,23 +40,20 @@ PlayerListWidget::PlayerListWidget(QWidget *parent) playerIcon = QIcon(":/resources/icon_player.svg"); spectatorIcon = QIcon(":/resources/icon_spectator.svg"); - setMinimumHeight(100); + itemDelegate = new PlayerListItemDelegate(this); + setItemDelegate(itemDelegate); + + setMinimumHeight(60); setIconSize(QSize(20, 15)); setColumnCount(6); + setHeaderHidden(true); setRootIsDecorated(false); - setSelectionMode(NoSelection); header()->setResizeMode(QHeaderView::ResizeToContents); retranslateUi(); } void PlayerListWidget::retranslateUi() { - headerItem()->setText(0, QString()); - headerItem()->setText(1, QString()); - headerItem()->setText(2, QString()); - headerItem()->setText(3, QString()); - headerItem()->setText(4, tr("Player name")); - headerItem()->setText(5, tr("Deck")); } void PlayerListWidget::addPlayer(ServerInfo_PlayerProperties *player) @@ -52,13 +76,15 @@ void PlayerListWidget::updatePlayerProperties(ServerInfo_PlayerProperties *prop) player->setText(4, prop->getUserInfo()->getName()); if (!prop->getUserInfo()->getCountry().isEmpty()) player->setIcon(4, QIcon(CountryPixmapGenerator::generatePixmap(12, prop->getUserInfo()->getCountry()))); + player->setData(4, Qt::UserRole, prop->getUserInfo()->getName()); + player->setData(4, Qt::UserRole + 1, prop->getPlayerId()); QString deckText; if (!prop->getSpectator()) switch (prop->getDeckId()) { - case -2: deckText = tr("---"); break; - case -1: deckText = tr("local"); break; - default: deckText = tr("#%1").arg(prop->getDeckId()); + case -2: deckText = QString(); break; + case -1: deckText = tr("local deck"); break; + default: deckText = tr("deck #%1").arg(prop->getDeckId()); } player->setText(5, deckText); } @@ -100,3 +126,66 @@ void PlayerListWidget::setGameStarted(bool _gameStarted) twi->setIcon(2, gameStarted ? QIcon() : notReadyIcon); } } + +void PlayerListWidget::showContextMenu(const QPoint &pos, const QModelIndex &index) +{ + const QString &userName = index.sibling(index.row(), 4).data(Qt::UserRole).toString(); + int playerId = index.sibling(index.row(), 4).data(Qt::UserRole + 1).toInt(); + + QAction *aUserName = new QAction(userName, this); + aUserName->setEnabled(false); + QAction *aDetails = new QAction(tr("User &details"), this); + QAction *aChat = new QAction(tr("Direct &chat"), this); + QAction *aAddToBuddyList = new QAction(tr("Add to &buddy list"), this); + QAction *aRemoveFromBuddyList = new QAction(tr("Remove from &buddy list"), this); + QAction *aAddToIgnoreList = new QAction(tr("Add to &ignore list"), this); + QAction *aRemoveFromIgnoreList = new QAction(tr("Remove from &ignore list"), this); + QAction *aKick = new QAction(tr("Kick from &game"), this); + + QMenu *menu = new QMenu(this); + menu->addAction(aUserName); + menu->addSeparator(); + menu->addAction(aDetails); + menu->addAction(aChat); + menu->addSeparator(); + if (tabSupervisor->getUserListsTab()->getBuddyList()->userInList(userName)) + menu->addAction(aRemoveFromBuddyList); + else + menu->addAction(aAddToBuddyList); + if (tabSupervisor->getUserListsTab()->getIgnoreList()->userInList(userName)) + menu->addAction(aRemoveFromIgnoreList); + else + menu->addAction(aAddToIgnoreList); + if (gameCreator) { + menu->addSeparator(); + menu->addAction(aKick); + } + + QAction *actionClicked = menu->exec(pos); + if (actionClicked == aDetails) { + UserInfoBox *infoWidget = new UserInfoBox(client, true, this, Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint); + infoWidget->setAttribute(Qt::WA_DeleteOnClose); + infoWidget->updateInfo(userName); + } else if (actionClicked == aChat) + emit openMessageDialog(userName, true); + else if (actionClicked == aAddToBuddyList) + client->sendCommand(new Command_AddToList("buddy", userName)); + else if (actionClicked == aRemoveFromBuddyList) + client->sendCommand(new Command_RemoveFromList("buddy", userName)); + else if (actionClicked == aAddToIgnoreList) + client->sendCommand(new Command_AddToList("ignore", userName)); + else if (actionClicked == aRemoveFromIgnoreList) + client->sendCommand(new Command_RemoveFromList("ignore", userName)); + else if (actionClicked == aKick) + game->sendGameCommand(new Command_KickFromGame(-1, playerId)); + + delete menu; + delete aUserName; + delete aDetails; + delete aChat; + delete aAddToBuddyList; + delete aRemoveFromBuddyList; + delete aAddToIgnoreList; + delete aRemoveFromIgnoreList; + delete aKick; +} diff --git a/cockatrice/src/playerlistwidget.h b/cockatrice/src/playerlistwidget.h index b2933c407..2b1d619f2 100644 --- a/cockatrice/src/playerlistwidget.h +++ b/cockatrice/src/playerlistwidget.h @@ -4,17 +4,34 @@ #include #include #include +#include class ServerInfo_PlayerProperties; +class TabSupervisor; +class AbstractClient; +class TabGame; + +class PlayerListItemDelegate : public QStyledItemDelegate { +public: + PlayerListItemDelegate(QObject *const parent); + bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index); +}; class PlayerListWidget : public QTreeWidget { Q_OBJECT private: + PlayerListItemDelegate *itemDelegate; QMap players; + TabSupervisor *tabSupervisor; + AbstractClient *client; + TabGame *game; + bool gameCreator; QIcon readyIcon, notReadyIcon, concededIcon, playerIcon, spectatorIcon; bool gameStarted; +signals: + void openMessageDialog(const QString &userName, bool focus); public: - PlayerListWidget(QWidget *parent = 0); + PlayerListWidget(TabSupervisor *_tabSupervisor, AbstractClient *_client, TabGame *_game, bool _gameCreator, QWidget *parent = 0); void retranslateUi(); void addPlayer(ServerInfo_PlayerProperties *player); void removePlayer(int playerId); @@ -22,6 +39,7 @@ public: void updatePing(int playerId, int pingTime); void updatePlayerProperties(ServerInfo_PlayerProperties *prop); void setGameStarted(bool _gameStarted); + void showContextMenu(const QPoint &pos, const QModelIndex &index); }; #endif diff --git a/cockatrice/src/tab_game.cpp b/cockatrice/src/tab_game.cpp index 41b7c5b2c..8f3f3326d 100644 --- a/cockatrice/src/tab_game.cpp +++ b/cockatrice/src/tab_game.cpp @@ -171,8 +171,10 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor, QList &_client gameView->hide(); cardInfo = new CardInfoWidget(CardInfoWidget::ModeGameTab); - playerListWidget = new PlayerListWidget; + playerListWidget = new PlayerListWidget(tabSupervisor, clients.first(), this, true); playerListWidget->setFocusPolicy(Qt::NoFocus); + connect(playerListWidget, SIGNAL(openMessageDialog(QString, bool)), this, SIGNAL(openMessageDialog(QString, bool))); + timeElapsedLabel = new QLabel; timeElapsedLabel->setAlignment(Qt::AlignCenter); messageLog = new MessageLogWidget; @@ -397,8 +399,8 @@ void TabGame::processGameEventContainer(GameEventContainer *cont, AbstractClient if (spectators.contains(event->getPlayerId())) { switch (event->getItemId()) { - case ItemId_Event_Say: eventSpectatorSay(qobject_cast(event), context); break; - case ItemId_Event_Leave: eventSpectatorLeave(qobject_cast(event), context); break; + case ItemId_Event_Say: eventSpectatorSay(static_cast(event), context); break; + case ItemId_Event_Leave: eventSpectatorLeave(static_cast(event), context); break; default: { qDebug() << "unhandled spectator game event"; break; @@ -410,14 +412,15 @@ void TabGame::processGameEventContainer(GameEventContainer *cont, AbstractClient continue; switch (event->getItemId()) { - case ItemId_Event_GameStateChanged: eventGameStateChanged(qobject_cast(event), context); break; - case ItemId_Event_PlayerPropertiesChanged: eventPlayerPropertiesChanged(qobject_cast(event), context); break; - case ItemId_Event_Join: eventJoin(qobject_cast(event), context); break; - case ItemId_Event_Leave: eventLeave(qobject_cast(event), context); break; - case ItemId_Event_GameClosed: eventGameClosed(qobject_cast(event), context); break; - case ItemId_Event_SetActivePlayer: eventSetActivePlayer(qobject_cast(event), context); break; - case ItemId_Event_SetActivePhase: eventSetActivePhase(qobject_cast(event), context); break; - case ItemId_Event_Ping: eventPing(qobject_cast(event), context); break; + case ItemId_Event_GameStateChanged: eventGameStateChanged(static_cast(event), context); break; + case ItemId_Event_PlayerPropertiesChanged: eventPlayerPropertiesChanged(static_cast(event), context); break; + case ItemId_Event_Join: eventJoin(static_cast(event), context); break; + case ItemId_Event_Leave: eventLeave(static_cast(event), context); break; + case ItemId_Event_Kicked: eventKicked(static_cast(event), context); break; + case ItemId_Event_GameClosed: eventGameClosed(static_cast(event), context); break; + case ItemId_Event_SetActivePlayer: eventSetActivePlayer(static_cast(event), context); break; + case ItemId_Event_SetActivePhase: eventSetActivePhase(static_cast(event), context); break; + case ItemId_Event_Ping: eventPing(static_cast(event), context); break; default: { Player *player = players.value(event->getPlayerId(), 0); @@ -642,6 +645,13 @@ void TabGame::eventLeave(Event_Leave *event, GameEventContext * /*context*/) emit userEvent(); } +void TabGame::eventKicked(Event_Kicked * /*event*/, GameEventContext * /*context*/) +{ + emit userEvent(); + QMessageBox::critical(this, tr("Kicked"), tr("You have been kicked out of the game.")); + deleteLater(); +} + void TabGame::eventGameClosed(Event_GameClosed * /*event*/, GameEventContext * /*context*/) { started = false; diff --git a/cockatrice/src/tab_game.h b/cockatrice/src/tab_game.h index f79088b90..b11f857c0 100644 --- a/cockatrice/src/tab_game.h +++ b/cockatrice/src/tab_game.h @@ -35,6 +35,7 @@ class Event_SetActivePlayer; class Event_SetActivePhase; class Event_Ping; class Event_Say; +class Event_Kicked; class Player; class CardZone; class AbstractCardItem; @@ -128,6 +129,7 @@ private: void eventPlayerPropertiesChanged(Event_PlayerPropertiesChanged *event, GameEventContext *context); void eventJoin(Event_Join *event, GameEventContext *context); void eventLeave(Event_Leave *event, GameEventContext *context); + void eventKicked(Event_Kicked *event, GameEventContext *context); void eventGameClosed(Event_GameClosed *event, GameEventContext *context); Player *setActivePlayer(int id); void eventSetActivePlayer(Event_SetActivePlayer *event, GameEventContext *context); @@ -140,6 +142,7 @@ signals: void playerRemoved(Player *player); void containerProcessingStarted(GameEventContext *context); void containerProcessingDone(); + void openMessageDialog(const QString &userName, bool focus); private slots: void newCardAdded(AbstractCardItem *card); void showCardInfoPopup(const QPoint &pos, const QString &cardName); diff --git a/cockatrice/src/tab_supervisor.cpp b/cockatrice/src/tab_supervisor.cpp index 9ed8ba17c..7a79b5cc0 100644 --- a/cockatrice/src/tab_supervisor.cpp +++ b/cockatrice/src/tab_supervisor.cpp @@ -155,6 +155,7 @@ void TabSupervisor::gameJoined(Event_GameJoined *event) { TabGame *tab = new TabGame(this, QList() << client, event->getGameId(), event->getGameDescription(), event->getPlayerId(), event->getSpectator(), event->getSpectatorsCanTalk(), event->getSpectatorsSeeEverything(), event->getResuming()); connect(tab, SIGNAL(gameClosing(TabGame *)), this, SLOT(gameLeft(TabGame *))); + connect(tab, SIGNAL(openMessageDialog(const QString &, bool)), this, SLOT(addMessageTab(const QString &, bool))); myAddTab(tab); gameTabs.insert(event->getGameId(), tab); setCurrentWidget(tab); diff --git a/common/protocol_item_ids.h b/common/protocol_item_ids.h index 1b2378d4c..d45045d02 100644 --- a/common/protocol_item_ids.h +++ b/common/protocol_item_ids.h @@ -16,65 +16,67 @@ ItemId_Command_JoinRoom = 1014, ItemId_Command_LeaveRoom = 1015, ItemId_Command_RoomSay = 1016, ItemId_Command_JoinGame = 1017, -ItemId_Command_LeaveGame = 1018, -ItemId_Command_Say = 1019, -ItemId_Command_Shuffle = 1020, -ItemId_Command_Mulligan = 1021, -ItemId_Command_RollDie = 1022, -ItemId_Command_DrawCards = 1023, -ItemId_Command_UndoDraw = 1024, -ItemId_Command_FlipCard = 1025, -ItemId_Command_AttachCard = 1026, -ItemId_Command_CreateToken = 1027, -ItemId_Command_CreateArrow = 1028, -ItemId_Command_DeleteArrow = 1029, -ItemId_Command_SetCardAttr = 1030, -ItemId_Command_SetCardCounter = 1031, -ItemId_Command_IncCardCounter = 1032, -ItemId_Command_ReadyStart = 1033, -ItemId_Command_Concede = 1034, -ItemId_Command_IncCounter = 1035, -ItemId_Command_CreateCounter = 1036, -ItemId_Command_SetCounter = 1037, -ItemId_Command_DelCounter = 1038, -ItemId_Command_NextTurn = 1039, -ItemId_Command_SetActivePhase = 1040, -ItemId_Command_DumpZone = 1041, -ItemId_Command_StopDumpZone = 1042, -ItemId_Command_RevealCards = 1043, -ItemId_Event_Say = 1044, -ItemId_Event_Leave = 1045, -ItemId_Event_GameClosed = 1046, -ItemId_Event_Shuffle = 1047, -ItemId_Event_RollDie = 1048, -ItemId_Event_MoveCard = 1049, -ItemId_Event_FlipCard = 1050, -ItemId_Event_DestroyCard = 1051, -ItemId_Event_AttachCard = 1052, -ItemId_Event_CreateToken = 1053, -ItemId_Event_DeleteArrow = 1054, -ItemId_Event_SetCardAttr = 1055, -ItemId_Event_SetCardCounter = 1056, -ItemId_Event_SetCounter = 1057, -ItemId_Event_DelCounter = 1058, -ItemId_Event_SetActivePlayer = 1059, -ItemId_Event_SetActivePhase = 1060, -ItemId_Event_DumpZone = 1061, -ItemId_Event_StopDumpZone = 1062, -ItemId_Event_RemoveFromList = 1063, -ItemId_Event_ServerMessage = 1064, -ItemId_Event_ConnectionClosed = 1065, -ItemId_Event_Message = 1066, -ItemId_Event_GameJoined = 1067, -ItemId_Event_UserLeft = 1068, -ItemId_Event_LeaveRoom = 1069, -ItemId_Event_RoomSay = 1070, -ItemId_Context_ReadyStart = 1071, -ItemId_Context_Concede = 1072, -ItemId_Context_DeckSelect = 1073, -ItemId_Context_UndoDraw = 1074, -ItemId_Context_MoveCard = 1075, -ItemId_Command_UpdateServerMessage = 1076, -ItemId_Command_BanFromServer = 1077, -ItemId_Other = 1078 +ItemId_Command_KickFromGame = 1018, +ItemId_Command_LeaveGame = 1019, +ItemId_Command_Say = 1020, +ItemId_Command_Shuffle = 1021, +ItemId_Command_Mulligan = 1022, +ItemId_Command_RollDie = 1023, +ItemId_Command_DrawCards = 1024, +ItemId_Command_UndoDraw = 1025, +ItemId_Command_FlipCard = 1026, +ItemId_Command_AttachCard = 1027, +ItemId_Command_CreateToken = 1028, +ItemId_Command_CreateArrow = 1029, +ItemId_Command_DeleteArrow = 1030, +ItemId_Command_SetCardAttr = 1031, +ItemId_Command_SetCardCounter = 1032, +ItemId_Command_IncCardCounter = 1033, +ItemId_Command_ReadyStart = 1034, +ItemId_Command_Concede = 1035, +ItemId_Command_IncCounter = 1036, +ItemId_Command_CreateCounter = 1037, +ItemId_Command_SetCounter = 1038, +ItemId_Command_DelCounter = 1039, +ItemId_Command_NextTurn = 1040, +ItemId_Command_SetActivePhase = 1041, +ItemId_Command_DumpZone = 1042, +ItemId_Command_StopDumpZone = 1043, +ItemId_Command_RevealCards = 1044, +ItemId_Event_Say = 1045, +ItemId_Event_Leave = 1046, +ItemId_Event_GameClosed = 1047, +ItemId_Event_Kicked = 1048, +ItemId_Event_Shuffle = 1049, +ItemId_Event_RollDie = 1050, +ItemId_Event_MoveCard = 1051, +ItemId_Event_FlipCard = 1052, +ItemId_Event_DestroyCard = 1053, +ItemId_Event_AttachCard = 1054, +ItemId_Event_CreateToken = 1055, +ItemId_Event_DeleteArrow = 1056, +ItemId_Event_SetCardAttr = 1057, +ItemId_Event_SetCardCounter = 1058, +ItemId_Event_SetCounter = 1059, +ItemId_Event_DelCounter = 1060, +ItemId_Event_SetActivePlayer = 1061, +ItemId_Event_SetActivePhase = 1062, +ItemId_Event_DumpZone = 1063, +ItemId_Event_StopDumpZone = 1064, +ItemId_Event_RemoveFromList = 1065, +ItemId_Event_ServerMessage = 1066, +ItemId_Event_ConnectionClosed = 1067, +ItemId_Event_Message = 1068, +ItemId_Event_GameJoined = 1069, +ItemId_Event_UserLeft = 1070, +ItemId_Event_LeaveRoom = 1071, +ItemId_Event_RoomSay = 1072, +ItemId_Context_ReadyStart = 1073, +ItemId_Context_Concede = 1074, +ItemId_Context_DeckSelect = 1075, +ItemId_Context_UndoDraw = 1076, +ItemId_Context_MoveCard = 1077, +ItemId_Command_UpdateServerMessage = 1078, +ItemId_Command_BanFromServer = 1079, +ItemId_Other = 1080 }; diff --git a/common/protocol_items.cpp b/common/protocol_items.cpp index 5fde8b1ff..c75a991ed 100644 --- a/common/protocol_items.cpp +++ b/common/protocol_items.cpp @@ -88,6 +88,11 @@ Command_JoinGame::Command_JoinGame(int _roomId, int _gameId, const QString &_pas insertItem(new SerializableItem_String("password", _password)); insertItem(new SerializableItem_Bool("spectator", _spectator)); } +Command_KickFromGame::Command_KickFromGame(int _gameId, int _playerId) + : GameCommand("kick_from_game", _gameId) +{ + insertItem(new SerializableItem_Int("player_id", _playerId)); +} Command_LeaveGame::Command_LeaveGame(int _gameId) : GameCommand("leave_game", _gameId) { @@ -263,6 +268,10 @@ Event_GameClosed::Event_GameClosed(int _playerId) : GameEvent("game_closed", _playerId) { } +Event_Kicked::Event_Kicked(int _playerId) + : GameEvent("kicked", _playerId) +{ +} Event_Shuffle::Event_Shuffle(int _playerId) : GameEvent("shuffle", _playerId) { @@ -478,6 +487,7 @@ void ProtocolItem::initializeHashAuto() itemNameHash.insert("cmdleave_room", Command_LeaveRoom::newItem); itemNameHash.insert("cmdroom_say", Command_RoomSay::newItem); itemNameHash.insert("cmdjoin_game", Command_JoinGame::newItem); + itemNameHash.insert("cmdkick_from_game", Command_KickFromGame::newItem); itemNameHash.insert("cmdleave_game", Command_LeaveGame::newItem); itemNameHash.insert("cmdsay", Command_Say::newItem); itemNameHash.insert("cmdshuffle", Command_Shuffle::newItem); @@ -507,6 +517,7 @@ void ProtocolItem::initializeHashAuto() itemNameHash.insert("game_eventsay", Event_Say::newItem); itemNameHash.insert("game_eventleave", Event_Leave::newItem); itemNameHash.insert("game_eventgame_closed", Event_GameClosed::newItem); + itemNameHash.insert("game_eventkicked", Event_Kicked::newItem); itemNameHash.insert("game_eventshuffle", Event_Shuffle::newItem); itemNameHash.insert("game_eventroll_die", Event_RollDie::newItem); itemNameHash.insert("game_eventmove_card", Event_MoveCard::newItem); diff --git a/common/protocol_items.dat b/common/protocol_items.dat index 8ca86b97c..4e37333df 100644 --- a/common/protocol_items.dat +++ b/common/protocol_items.dat @@ -15,6 +15,7 @@ 1:leave_room 1:room_say:s,message 1:join_game:i,game_id:s,password:b,spectator +2:kick_from_game:i,player_id 2:leave_game 2:say:s,message 2:shuffle @@ -44,6 +45,7 @@ 3:say:s,message 3:leave 3:game_closed +3:kicked 3:shuffle 3:roll_die:i,sides:i,value 3:move_card:i,card_id:s,card_name:s,start_zone:i,position:i,target_player_id:s,target_zone:i,x:i,y:i,new_card_id:b,face_down diff --git a/common/protocol_items.h b/common/protocol_items.h index 314957589..14d6eb1ff 100644 --- a/common/protocol_items.h +++ b/common/protocol_items.h @@ -141,6 +141,14 @@ public: static SerializableItem *newItem() { return new Command_JoinGame; } int getItemId() const { return ItemId_Command_JoinGame; } }; +class Command_KickFromGame : public GameCommand { + Q_OBJECT +public: + Command_KickFromGame(int _gameId = -1, int _playerId = -1); + int getPlayerId() const { return static_cast(itemMap.value("player_id"))->getData(); }; + static SerializableItem *newItem() { return new Command_KickFromGame; } + int getItemId() const { return ItemId_Command_KickFromGame; } +}; class Command_LeaveGame : public GameCommand { Q_OBJECT public: @@ -403,6 +411,13 @@ public: static SerializableItem *newItem() { return new Event_GameClosed; } int getItemId() const { return ItemId_Event_GameClosed; } }; +class Event_Kicked : public GameEvent { + Q_OBJECT +public: + Event_Kicked(int _playerId = -1); + static SerializableItem *newItem() { return new Event_Kicked; } + int getItemId() const { return ItemId_Event_Kicked; } +}; class Event_Shuffle : public GameEvent { Q_OBJECT public: diff --git a/common/server_game.cpp b/common/server_game.cpp index 704b23c24..dec374d1b 100644 --- a/common/server_game.cpp +++ b/common/server_game.cpp @@ -247,6 +247,18 @@ void Server_Game::removePlayer(Server_Player *player) qobject_cast(parent())->broadcastGameListUpdate(this); } +bool Server_Game::kickPlayer(int playerId) +{ + Server_Player *playerToKick = players.value(playerId); + if (!playerToKick) + return false; + + removePlayer(playerToKick); + sendGameEventToPlayer(playerToKick, new Event_Kicked); + + return true; +} + void Server_Game::setActivePlayer(int _activePlayer) { activePlayer = _activePlayer; diff --git a/common/server_game.h b/common/server_game.h index a58a213df..991df2e42 100644 --- a/common/server_game.h +++ b/common/server_game.h @@ -75,6 +75,7 @@ public: ResponseCode checkJoin(ServerInfo_User *user, const QString &_password, bool spectator); Server_Player *addPlayer(Server_ProtocolHandler *handler, bool spectator, bool broadcastUpdate = true); void removePlayer(Server_Player *player); + bool kickPlayer(int playerId); void startGameIfReady(); void stopGameIfFinished(); int getActivePlayer() const { return activePlayer; } diff --git a/common/server_protocolhandler.cpp b/common/server_protocolhandler.cpp index 69bca1466..27296e981 100644 --- a/common/server_protocolhandler.cpp +++ b/common/server_protocolhandler.cpp @@ -94,6 +94,7 @@ ResponseCode Server_ProtocolHandler::processCommandHelper(Command *command, Comm case ItemId_Command_DeckSelect: return cmdDeckSelect(static_cast(command), cont, game, player); case ItemId_Command_SetSideboardPlan: return cmdSetSideboardPlan(static_cast(command), cont, game, player); case ItemId_Command_LeaveGame: return cmdLeaveGame(static_cast(command), cont, game, player); + case ItemId_Command_KickFromGame: return cmdKickFromGame(static_cast(command), cont, game, player); case ItemId_Command_ReadyStart: return cmdReadyStart(static_cast(command), cont, game, player); case ItemId_Command_Concede: return cmdConcede(static_cast(command), cont, game, player); case ItemId_Command_Say: return cmdSay(static_cast(command), cont, game, player); @@ -456,6 +457,17 @@ ResponseCode Server_ProtocolHandler::cmdLeaveGame(Command_LeaveGame * /*cmd*/, C return RespOk; } +ResponseCode Server_ProtocolHandler::cmdKickFromGame(Command_KickFromGame *cmd, CommandContainer * /*cont*/, Server_Game *game, Server_Player *player) +{ + if (game->getCreatorInfo()->getName() != player->getUserInfo()->getName()) + return RespFunctionNotAllowed; + + if (!game->kickPlayer(cmd->getPlayerId())) + return RespNameNotFound; + + return RespOk; +} + ResponseCode Server_ProtocolHandler::cmdDeckSelect(Command_DeckSelect *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player) { if (player->getSpectator()) diff --git a/common/server_protocolhandler.h b/common/server_protocolhandler.h index 103606317..677ba0956 100644 --- a/common/server_protocolhandler.h +++ b/common/server_protocolhandler.h @@ -56,6 +56,7 @@ private: ResponseCode cmdCreateGame(Command_CreateGame *cmd, CommandContainer *cont, Server_Room *room); ResponseCode cmdJoinGame(Command_JoinGame *cmd, CommandContainer *cont, Server_Room *room); ResponseCode cmdLeaveGame(Command_LeaveGame *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); + ResponseCode cmdKickFromGame(Command_KickFromGame *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); ResponseCode cmdConcede(Command_Concede *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); ResponseCode cmdReadyStart(Command_ReadyStart *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); ResponseCode cmdDeckSelect(Command_DeckSelect *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player);