diff --git a/cockatrice/cockatrice.pro b/cockatrice/cockatrice.pro index 3b917dd0..196b64bc 100644 --- a/cockatrice/cockatrice.pro +++ b/cockatrice/cockatrice.pro @@ -50,6 +50,7 @@ HEADERS += src/counter.h \ src/remotedecklist_treewidget.h \ src/deckview.h \ src/playerlistwidget.h \ + src/pingpixmapgenerator.h \ ../common/serializable_item.h \ ../common/decklist.h \ ../common/protocol.h \ @@ -99,6 +100,7 @@ SOURCES += src/counter.cpp \ src/remotedecklist_treewidget.cpp \ src/deckview.cpp \ src/playerlistwidget.cpp \ + src/pingpixmapgenerator.cpp \ ../common/serializable_item.cpp \ ../common/decklist.cpp \ ../common/protocol.cpp \ diff --git a/cockatrice/src/main.cpp b/cockatrice/src/main.cpp index 62a213ad..29d7286e 100644 --- a/cockatrice/src/main.cpp +++ b/cockatrice/src/main.cpp @@ -37,7 +37,7 @@ CardDatabase *db; QTranslator *translator; -void myMessageOutput(QtMsgType type, const char *msg) +void myMessageOutput(QtMsgType /*type*/, const char *msg) { static FILE *f = NULL; if (!f) diff --git a/cockatrice/src/pingpixmapgenerator.cpp b/cockatrice/src/pingpixmapgenerator.cpp new file mode 100644 index 00000000..81d509a5 --- /dev/null +++ b/cockatrice/src/pingpixmapgenerator.cpp @@ -0,0 +1,21 @@ +#include "pingpixmapgenerator.h" +#include + +QPixmap PingPixmapGenerator::generatePixmap(int size, int value, int max) +{ + QPixmap pixmap(size, size); + pixmap.fill(Qt::transparent); + QPainter painter(&pixmap); + QColor color; + if (max == -1) + color = Qt::black; + else + color.setHsv(120 * (1.0 - ((double) value / max)), 255, 255); + + QRadialGradient g(QPointF((double) pixmap.width() / 2, (double) pixmap.height() / 2), qMin(pixmap.width(), pixmap.height()) / 2.0); + g.setColorAt(0, color); + g.setColorAt(1, Qt::transparent); + painter.fillRect(0, 0, pixmap.width(), pixmap.height(), QBrush(g)); + + return pixmap; +} diff --git a/cockatrice/src/pingpixmapgenerator.h b/cockatrice/src/pingpixmapgenerator.h new file mode 100644 index 00000000..af813c22 --- /dev/null +++ b/cockatrice/src/pingpixmapgenerator.h @@ -0,0 +1,11 @@ +#ifndef PINGPIXMAPGENERATOR_H +#define PINGPIXMAPGENERATOR_H + +#include + +class PingPixmapGenerator { +public: + static QPixmap generatePixmap(int size, int value, int max); +}; + +#endif diff --git a/cockatrice/src/player.cpp b/cockatrice/src/player.cpp index a7638994..f8ec49cc 100644 --- a/cockatrice/src/player.cpp +++ b/cockatrice/src/player.cpp @@ -363,22 +363,6 @@ void Player::initSayMenu() } } -void Player::prepareForGame() -{ - if (local) { - sendGameCommand(new Command_CreateCounter(-1, "life", Qt::white, 25, 20)); - sendGameCommand(new Command_CreateCounter(-1, "w", QColor(255, 255, 150), 20, 0)); - sendGameCommand(new Command_CreateCounter(-1, "u", QColor(150, 150, 255), 20, 0)); - sendGameCommand(new Command_CreateCounter(-1, "b", QColor(150, 150, 150), 20, 0)); - sendGameCommand(new Command_CreateCounter(-1, "r", QColor(250, 150, 150), 20, 0)); - sendGameCommand(new Command_CreateCounter(-1, "g", QColor(150, 255, 150), 20, 0)); - sendGameCommand(new Command_CreateCounter(-1, "x", QColor(255, 255, 255), 20, 0)); - sendGameCommand(new Command_CreateCounter(-1, "storm", QColor(255, 255, 255), 20, 0)); - - mulliganCards = 7; - } -} - void Player::actViewLibrary() { emit toggleZoneView(this, "deck", -1); @@ -421,14 +405,7 @@ void Player::actDrawCard() void Player::actMulligan() { - if (mulliganCards <= 0) - return; - - const CardList &handCards = hand->getCards(); - for (int i = 0; i < handCards.size(); i++) - sendGameCommand(new Command_MoveCard(-1, "hand", handCards.at(i)->getId(), "deck", 0, -1, false)); - sendGameCommand(new Command_Shuffle); - sendGameCommand(new Command_DrawCards(-1, mulliganCards--)); + sendGameCommand(new Command_Mulligan); } void Player::actDrawCards() diff --git a/cockatrice/src/player.h b/cockatrice/src/player.h index c727a87e..2a73f064 100644 --- a/cockatrice/src/player.h +++ b/cockatrice/src/player.h @@ -114,7 +114,6 @@ private: void actMoveToExile(CardItem *card); int defaultNumberTopCards; - int mulliganCards; QString name; int id; bool active; @@ -188,7 +187,6 @@ public: bool getActive() const { return active; } void setActive(bool _active); - void prepareForGame(); void processPlayerInfo(ServerInfo_Player *info); void processGameEvent(GameEvent *event); void sendGameCommand(GameCommand *command); diff --git a/cockatrice/src/playerlistwidget.cpp b/cockatrice/src/playerlistwidget.cpp index 17b4f04d..96c88bb0 100644 --- a/cockatrice/src/playerlistwidget.cpp +++ b/cockatrice/src/playerlistwidget.cpp @@ -1,10 +1,11 @@ #include "playerlistwidget.h" #include "protocol_datastructures.h" +#include "pingpixmapgenerator.h" PlayerListWidget::PlayerListWidget(QWidget *parent) : QTreeWidget(parent) { - setColumnCount(1); + setColumnCount(2); setRootIsDecorated(false); retranslateUi(); } @@ -12,12 +13,14 @@ PlayerListWidget::PlayerListWidget(QWidget *parent) void PlayerListWidget::retranslateUi() { headerItem()->setText(0, tr("Player name")); + headerItem()->setText(1, tr("Role")); } void PlayerListWidget::addPlayer(ServerInfo_Player *player) { QTreeWidgetItem *newPlayer = new QTreeWidgetItem; newPlayer->setText(0, player->getName()); + newPlayer->setText(1, player->getSpectator() ? tr("Spectator") : tr("Player")); addTopLevelItem(newPlayer); players.insert(player->getPlayerId(), newPlayer); } @@ -37,6 +40,16 @@ void PlayerListWidget::setActivePlayer(int playerId) while (i.hasNext()) { i.next(); QTreeWidgetItem *twi = i.value(); - twi->setBackground(0, i.key() == playerId ? QColor(150, 255, 150) : Qt::white); + QColor c = i.key() == playerId ? QColor(150, 255, 150) : Qt::white; + twi->setBackground(0, c); + twi->setBackground(1, c); } } + +void PlayerListWidget::updatePing(int playerId, int pingTime) +{ + QTreeWidgetItem *twi = players.value(playerId, 0); + if (!twi) + return; + twi->setIcon(0, QIcon(PingPixmapGenerator::generatePixmap(10, pingTime, 10))); +} diff --git a/cockatrice/src/playerlistwidget.h b/cockatrice/src/playerlistwidget.h index 13f70c68..3020e49f 100644 --- a/cockatrice/src/playerlistwidget.h +++ b/cockatrice/src/playerlistwidget.h @@ -16,6 +16,7 @@ public: void addPlayer(ServerInfo_Player *player); void removePlayer(int playerId); void setActivePlayer(int playerId); + void updatePing(int playerId, int pingTime); }; #endif diff --git a/cockatrice/src/tab_deck_storage.cpp b/cockatrice/src/tab_deck_storage.cpp index 530a45cb..f079cc35 100644 --- a/cockatrice/src/tab_deck_storage.cpp +++ b/cockatrice/src/tab_deck_storage.cpp @@ -102,7 +102,10 @@ void TabDeckStorage::actUpload() if (!deck->loadFromFile(filePath, DeckList::CockatriceFormat)) return; if (deck->getName().isEmpty()) { - QString deckName = QInputDialog::getText(this, tr("Enter deck name"), tr("This decklist does not have a name.\nPlease enter a name:"), QLineEdit::Normal, tr("Unnamed deck")); + bool ok; + QString deckName = QInputDialog::getText(this, tr("Enter deck name"), tr("This decklist does not have a name.\nPlease enter a name:"), QLineEdit::Normal, tr("Unnamed deck"), &ok); + if (!ok) + return; if (deckName.isEmpty()) deckName = tr("Unnamed deck"); deck->setName(deckName); diff --git a/cockatrice/src/tab_game.cpp b/cockatrice/src/tab_game.cpp index ae8ada7a..33b3729d 100644 --- a/cockatrice/src/tab_game.cpp +++ b/cockatrice/src/tab_game.cpp @@ -20,8 +20,8 @@ #include "arrowitem.h" #include "main.h" -TabGame::TabGame(Client *_client, int _gameId, int _localPlayerId, bool _spectator) - : Tab(), client(_client), gameId(_gameId), localPlayerId(_localPlayerId), spectator(_spectator), started(false), currentPhase(-1) +TabGame::TabGame(Client *_client, int _gameId, int _localPlayerId, bool _spectator, bool _resuming) + : Tab(), client(_client), gameId(_gameId), localPlayerId(_localPlayerId), spectator(_spectator), started(false), resuming(_resuming), currentPhase(-1) { zoneLayout = new ZoneViewLayout; scene = new GameScene(zoneLayout, this); @@ -31,6 +31,7 @@ TabGame::TabGame(Client *_client, int _gameId, int _localPlayerId, bool _spectat loadLocalButton = new QPushButton; loadRemoteButton = new QPushButton; readyStartButton = new QPushButton; + readyStartButton->setEnabled(false); QHBoxLayout *buttonHBox = new QHBoxLayout; buttonHBox->addWidget(loadLocalButton); @@ -50,7 +51,7 @@ TabGame::TabGame(Client *_client, int _gameId, int _localPlayerId, bool _spectat sayLabel = new QLabel; sayEdit = new QLineEdit; sayLabel->setBuddy(sayEdit); - + QHBoxLayout *hLayout = new QHBoxLayout; hLayout->addWidget(sayLabel); hLayout->addWidget(sayEdit); @@ -71,6 +72,14 @@ TabGame::TabGame(Client *_client, int _gameId, int _localPlayerId, bool _spectat mainLayout->addWidget(deckViewContainer, 10); mainLayout->addLayout(verticalLayout); + if (spectator) { + sayLabel->hide(); + sayEdit->hide(); + loadLocalButton->hide(); + loadRemoteButton->hide(); + readyStartButton->hide(); + } + aCloseMostRecentZoneView = new QAction(this); connect(aCloseMostRecentZoneView, SIGNAL(triggered()), zoneLayout, SLOT(closeMostRecentZoneView())); addAction(aCloseMostRecentZoneView); @@ -214,13 +223,14 @@ Player *TabGame::addPlayer(int playerId, const QString &playerName) void TabGame::processGameEvent(GameEvent *event) { switch (event->getItemId()) { - case ItemId_Event_GameStart: eventGameStart(qobject_cast(event)); break; case ItemId_Event_GameStateChanged: eventGameStateChanged(qobject_cast(event)); break; case ItemId_Event_Join: eventJoin(qobject_cast(event)); break; case ItemId_Event_Leave: eventLeave(qobject_cast(event)); break; case ItemId_Event_GameClosed: eventGameClosed(qobject_cast(event)); break; case ItemId_Event_SetActivePlayer: eventSetActivePlayer(qobject_cast(event)); break; case ItemId_Event_SetActivePhase: eventSetActivePhase(qobject_cast(event)); break; + case ItemId_Event_Ping: eventPing(qobject_cast(event)); break; + default: { Player *player = players.value(event->getPlayerId(), 0); if (!player) { @@ -257,34 +267,33 @@ void TabGame::stopGame() deckViewContainer->show(); } -void TabGame::eventGameStart(Event_GameStart * /*event*/) -{ - startGame(); - messageLog->logGameStart(); - - QMapIterator i(players); - while (i.hasNext()) - i.next().value()->prepareForGame(); -} - void TabGame::eventGameStateChanged(Event_GameStateChanged *event) { const QList &plList = event->getPlayerList(); for (int i = 0; i < plList.size(); ++i) { ServerInfo_Player *pl = plList[i]; - Player *player = players.value(pl->getPlayerId(), 0); - if (!player) { - player = addPlayer(pl->getPlayerId(), pl->getName()); - playerListWidget->addPlayer(pl); - } - player->processPlayerInfo(pl); - if (player->getLocal() && pl->getDeck()) { - Deck_PictureCacher::cachePictures(pl->getDeck(), this); - deckView->setDeck(new DeckList(pl->getDeck())); + if (pl->getSpectator()) { + if (!spectators.contains(pl->getPlayerId())) { + spectators.insert(pl->getPlayerId(), pl->getName()); + playerListWidget->addPlayer(pl); + } + } else { + Player *player = players.value(pl->getPlayerId(), 0); + if (!player) { + player = addPlayer(pl->getPlayerId(), pl->getName()); + playerListWidget->addPlayer(pl); + } + player->processPlayerInfo(pl); + if (player->getLocal() && pl->getDeck()) { + Deck_PictureCacher::cachePictures(pl->getDeck(), this); + deckView->setDeck(new DeckList(pl->getDeck())); + } } } if (event->getGameStarted() && !started) { startGame(); + if (!resuming) + messageLog->logGameStart(); setActivePlayer(event->getActivePlayer()); setActivePhase(event->getActivePhase()); } else if (!event->getGameStarted() && started) { @@ -297,8 +306,9 @@ void TabGame::eventJoin(Event_Join *event) { ServerInfo_Player *playerInfo = event->getPlayer(); if (playerInfo->getSpectator()) { - spectatorList.append(playerInfo->getName()); + spectators.insert(playerInfo->getPlayerId(), playerInfo->getName()); messageLog->logJoinSpectator(playerInfo->getName()); + playerListWidget->addPlayer(playerInfo); } else { Player *newPlayer = addPlayer(playerInfo->getPlayerId(), playerInfo->getName()); messageLog->logJoin(newPlayer); @@ -309,12 +319,18 @@ void TabGame::eventJoin(Event_Join *event) void TabGame::eventLeave(Event_Leave *event) { int playerId = event->getPlayerId(); + Player *player = players.value(playerId, 0); - if (!player) - return; - - messageLog->logLeave(player); - playerListWidget->removePlayer(playerId); + if (player) { + messageLog->logLeave(player); + playerListWidget->removePlayer(playerId); + players.remove(playerId); + delete player; + } else if (spectators.contains(playerId)) { + messageLog->logLeaveSpectator(spectators.value(playerId)); + playerListWidget->removePlayer(playerId); + spectators.remove(playerId); + } } void TabGame::eventGameClosed(Event_GameClosed * /*event*/) @@ -362,6 +378,13 @@ void TabGame::eventSetActivePhase(Event_SetActivePhase *event) setActivePhase(phase); } +void TabGame::eventPing(Event_Ping *event) +{ + const QList &pingList = event->getPingList(); + for (int i = 0; i < pingList.size(); ++i) + playerListWidget->updatePing(pingList[i]->getPlayerId(), pingList[i]->getPingTime()); +} + void TabGame::loadLocalDeck() { QFileDialog dialog(this, tr("Load deck")); @@ -403,6 +426,7 @@ void TabGame::deckSelectFinished(ProtocolResponse *r) Deck_PictureCacher::cachePictures(resp->getDeck(), this); deckView->setDeck(new DeckList(resp->getDeck())); + readyStartButton->setEnabled(true); } void TabGame::readyStart() diff --git a/cockatrice/src/tab_game.h b/cockatrice/src/tab_game.h index 8cace4ce..bbab02aa 100644 --- a/cockatrice/src/tab_game.h +++ b/cockatrice/src/tab_game.h @@ -22,7 +22,6 @@ class PlayerListWidget; class ProtocolResponse; class GameEvent; class GameCommand; -class Event_GameStart; class Event_GameStateChanged; class Event_Join; class Event_Leave; @@ -30,6 +29,7 @@ class Event_GameClosed; class Event_GameStart; class Event_SetActivePlayer; class Event_SetActivePhase; +class Event_Ping; class Player; class CardZone; class CardItem; @@ -41,9 +41,10 @@ private: int gameId; int localPlayerId; bool spectator; - QStringList spectatorList; QMap players; + QMap spectators; bool started; + bool resuming; int currentPhase; QPushButton *loadLocalButton, *loadRemoteButton, *readyStartButton; @@ -68,7 +69,6 @@ private: void startGame(); void stopGame(); - void eventGameStart(Event_GameStart *event); void eventGameStateChanged(Event_GameStateChanged *event); void eventJoin(Event_Join *event); void eventLeave(Event_Leave *event); @@ -77,6 +77,7 @@ private: void eventSetActivePlayer(Event_SetActivePlayer *event); void setActivePhase(int phase); void eventSetActivePhase(Event_SetActivePhase *event); + void eventPing(Event_Ping *event); signals: void gameClosing(TabGame *tab); private slots: @@ -93,7 +94,7 @@ private slots: void actNextPhase(); void actNextTurn(); public: - TabGame(Client *_client, int _gameId, int _localPlayerId, bool _spectator); + TabGame(Client *_client, int _gameId, int _localPlayerId, bool _spectator, bool _resuming); ~TabGame(); void retranslateUi(); const QMap &getPlayers() const { return players; } diff --git a/cockatrice/src/tab_supervisor.cpp b/cockatrice/src/tab_supervisor.cpp index 7a5d91e7..35d80718 100644 --- a/cockatrice/src/tab_supervisor.cpp +++ b/cockatrice/src/tab_supervisor.cpp @@ -5,7 +5,7 @@ #include "tab_game.h" #include "tab_deck_storage.h" #include "protocol_items.h" -#include +#include "pingpixmapgenerator.h" TabSupervisor:: TabSupervisor(QWidget *parent) : QTabWidget(parent), client(0), tabServer(0), tabDeckStorage(0) @@ -83,26 +83,13 @@ void TabSupervisor::updatePingTime(int value, int max) { if (!tabServer) return; - QPixmap pixmap(15, 15); - pixmap.fill(Qt::transparent); - QPainter painter(&pixmap); - QColor color; - if (max == -1) - color = Qt::black; - else - color.setHsv(120 * (1.0 - ((double) value / max)), 255, 255); - QRadialGradient g(QPointF((double) pixmap.width() / 2, (double) pixmap.height() / 2), qMin(pixmap.width(), pixmap.height()) / 2.0); - g.setColorAt(0, color); - g.setColorAt(1, Qt::transparent); - painter.fillRect(0, 0, pixmap.width(), pixmap.height(), QBrush(g)); - - setTabIcon(0, QIcon(pixmap)); + setTabIcon(0, QIcon(PingPixmapGenerator::generatePixmap(15, value, max))); } void TabSupervisor::gameJoined(Event_GameJoined *event) { - TabGame *tab = new TabGame(client, event->getGameId(), event->getPlayerId(), event->getSpectator()); + TabGame *tab = new TabGame(client, event->getGameId(), event->getPlayerId(), event->getSpectator(), event->getResuming()); connect(tab, SIGNAL(gameClosing(TabGame *)), this, SLOT(gameLeft(TabGame *))); addTab(tab, tr("Game %1").arg(event->getGameId())); gameTabs.insert(event->getGameId(), tab); diff --git a/common/protocol.cpp b/common/protocol.cpp index edfa6e8f..f536454c 100644 --- a/common/protocol.cpp +++ b/common/protocol.cpp @@ -22,6 +22,7 @@ void ProtocolItem::initializeHash() registerSerializableItem("counter", ServerInfo_Counter::newItem); registerSerializableItem("arrow", ServerInfo_Arrow::newItem); registerSerializableItem("player", ServerInfo_Player::newItem); + registerSerializableItem("player_ping", ServerInfo_PlayerPing::newItem); registerSerializableItem("file", DeckList_File::newItem); registerSerializableItem("directory", DeckList_Directory::newItem); @@ -42,6 +43,7 @@ void ProtocolItem::initializeHash() registerSerializableItem("game_eventcreate_arrows", Event_CreateArrows::newItem); registerSerializableItem("game_eventcreate_counters", Event_CreateCounters::newItem); registerSerializableItem("game_eventdraw_cards", Event_DrawCards::newItem); + registerSerializableItem("game_eventping", Event_Ping::newItem); registerSerializableItem("chat_eventchat_list_players", Event_ChatListPlayers::newItem); } @@ -234,6 +236,13 @@ Event_GameStateChanged::Event_GameStateChanged(int _gameId, bool _gameStarted, i itemList.append(_playerList[i]); } +Event_Ping::Event_Ping(int _gameId, const QList &_pingList) + : GameEvent("ping", _gameId, -1) +{ + for (int i = 0; i < _pingList.size(); ++i) + itemList.append(_pingList[i]); +} + Event_CreateArrows::Event_CreateArrows(int _gameId, int _playerId, const QList &_arrowList) : GameEvent("create_arrows", _gameId, _playerId) { diff --git a/common/protocol.h b/common/protocol.h index fb488586..04904c2e 100644 --- a/common/protocol.h +++ b/common/protocol.h @@ -27,6 +27,7 @@ enum ItemId { ItemId_Event_CreateCounters = ItemId_Other + 205, ItemId_Event_DrawCards = ItemId_Other + 206, ItemId_Event_Join = ItemId_Other + 207, + ItemId_Event_Ping = ItemId_Other + 208, ItemId_Response_DeckList = ItemId_Other + 300, ItemId_Response_DeckDownload = ItemId_Other + 301, ItemId_Response_DeckUpload = ItemId_Other + 302, @@ -257,6 +258,15 @@ public: int getActivePhase() const { return static_cast(itemMap.value("active_phase"))->getData(); } }; +class Event_Ping : public GameEvent { + Q_OBJECT +public: + Event_Ping(int _gameId = -1, const QList &_pingList = QList()); + static SerializableItem *newItem() { return new Event_Ping; } + int getItemId() const { return ItemId_Event_Ping; } + QList getPingList() const { return typecastItemList(); } +}; + class Event_CreateArrows : public GameEvent { Q_OBJECT public: diff --git a/common/protocol_datastructures.cpp b/common/protocol_datastructures.cpp index 0185f8e6..1ce911f7 100644 --- a/common/protocol_datastructures.cpp +++ b/common/protocol_datastructures.cpp @@ -148,6 +148,13 @@ DeckList *ServerInfo_Player::getDeck() const return static_cast(itemMap.value("cockatrice_deck")); } +ServerInfo_PlayerPing::ServerInfo_PlayerPing(int _playerId, int _pingTime) + : SerializableItem_Map("player_ping") +{ + insertItem(new SerializableItem_Int("player_id", _playerId)); + insertItem(new SerializableItem_Int("ping_time", _pingTime)); +} + DeckList_TreeItem::DeckList_TreeItem(const QString &_itemType, const QString &_name, int _id) : SerializableItem_Map(_itemType) { diff --git a/common/protocol_datastructures.h b/common/protocol_datastructures.h index 9038d5dc..218845da 100644 --- a/common/protocol_datastructures.h +++ b/common/protocol_datastructures.h @@ -124,6 +124,14 @@ public: const QList &getArrowList() const { return arrowList; } }; +class ServerInfo_PlayerPing : public SerializableItem_Map { +public: + ServerInfo_PlayerPing(int _playerId = -1, int _pingTime = -1); + static SerializableItem *newItem() { return new ServerInfo_PlayerPing; } + int getPlayerId() const { return static_cast(itemMap.value("player_id"))->getData(); } + int getPingTime() const { return static_cast(itemMap.value("ping_time"))->getData(); } +}; + class DeckList_TreeItem : public SerializableItem_Map { public: DeckList_TreeItem(const QString &_itemType, const QString &_name, int _id); diff --git a/common/protocol_item_ids.h b/common/protocol_item_ids.h index 40dd12f0..6bdb1846 100644 --- a/common/protocol_item_ids.h +++ b/common/protocol_item_ids.h @@ -16,30 +16,30 @@ ItemId_Command_JoinGame = 1014, ItemId_Command_LeaveGame = 1015, ItemId_Command_Say = 1016, ItemId_Command_Shuffle = 1017, -ItemId_Command_RollDie = 1018, -ItemId_Command_DrawCards = 1019, -ItemId_Command_MoveCard = 1020, -ItemId_Command_CreateToken = 1021, -ItemId_Command_CreateArrow = 1022, -ItemId_Command_DeleteArrow = 1023, -ItemId_Command_SetCardAttr = 1024, -ItemId_Command_ReadyStart = 1025, -ItemId_Command_Concede = 1026, -ItemId_Command_IncCounter = 1027, -ItemId_Command_CreateCounter = 1028, -ItemId_Command_SetCounter = 1029, -ItemId_Command_DelCounter = 1030, -ItemId_Command_NextTurn = 1031, -ItemId_Command_SetActivePhase = 1032, -ItemId_Command_DumpZone = 1033, -ItemId_Command_StopDumpZone = 1034, -ItemId_Event_Say = 1035, -ItemId_Event_Leave = 1036, -ItemId_Event_DeckSelect = 1037, -ItemId_Event_GameClosed = 1038, -ItemId_Event_ReadyStart = 1039, -ItemId_Event_Concede = 1040, -ItemId_Event_GameStart = 1041, +ItemId_Command_Mulligan = 1018, +ItemId_Command_RollDie = 1019, +ItemId_Command_DrawCards = 1020, +ItemId_Command_MoveCard = 1021, +ItemId_Command_CreateToken = 1022, +ItemId_Command_CreateArrow = 1023, +ItemId_Command_DeleteArrow = 1024, +ItemId_Command_SetCardAttr = 1025, +ItemId_Command_ReadyStart = 1026, +ItemId_Command_Concede = 1027, +ItemId_Command_IncCounter = 1028, +ItemId_Command_CreateCounter = 1029, +ItemId_Command_SetCounter = 1030, +ItemId_Command_DelCounter = 1031, +ItemId_Command_NextTurn = 1032, +ItemId_Command_SetActivePhase = 1033, +ItemId_Command_DumpZone = 1034, +ItemId_Command_StopDumpZone = 1035, +ItemId_Event_Say = 1036, +ItemId_Event_Leave = 1037, +ItemId_Event_DeckSelect = 1038, +ItemId_Event_GameClosed = 1039, +ItemId_Event_ReadyStart = 1040, +ItemId_Event_Concede = 1041, ItemId_Event_Shuffle = 1042, ItemId_Event_RollDie = 1043, ItemId_Event_MoveCard = 1044, diff --git a/common/protocol_items.cpp b/common/protocol_items.cpp index 5bb3bf78..7c4d727d 100644 --- a/common/protocol_items.cpp +++ b/common/protocol_items.cpp @@ -86,6 +86,10 @@ Command_Shuffle::Command_Shuffle(int _gameId) : GameCommand("shuffle", _gameId) { } +Command_Mulligan::Command_Mulligan(int _gameId) + : GameCommand("mulligan", _gameId) +{ +} Command_RollDie::Command_RollDie(int _gameId, int _sides) : GameCommand("roll_die", _gameId) { @@ -220,10 +224,6 @@ Event_Concede::Event_Concede(int _gameId, int _playerId) : GameEvent("concede", _gameId, _playerId) { } -Event_GameStart::Event_GameStart(int _gameId, int _playerId) - : GameEvent("game_start", _gameId, _playerId) -{ -} Event_Shuffle::Event_Shuffle(int _gameId, int _playerId) : GameEvent("shuffle", _gameId, _playerId) { @@ -308,12 +308,13 @@ Event_ServerMessage::Event_ServerMessage(const QString &_message) { insertItem(new SerializableItem_String("message", _message)); } -Event_GameJoined::Event_GameJoined(int _gameId, int _playerId, bool _spectator) +Event_GameJoined::Event_GameJoined(int _gameId, int _playerId, bool _spectator, bool _resuming) : GenericEvent("game_joined") { insertItem(new SerializableItem_Int("game_id", _gameId)); insertItem(new SerializableItem_Int("player_id", _playerId)); insertItem(new SerializableItem_Bool("spectator", _spectator)); + insertItem(new SerializableItem_Bool("resuming", _resuming)); } Event_ChatJoinChannel::Event_ChatJoinChannel(const QString &_channel, const QString &_playerName) : ChatEvent("chat_join_channel", _channel) @@ -350,6 +351,7 @@ void ProtocolItem::initializeHashAuto() itemNameHash.insert("cmdleave_game", Command_LeaveGame::newItem); itemNameHash.insert("cmdsay", Command_Say::newItem); itemNameHash.insert("cmdshuffle", Command_Shuffle::newItem); + itemNameHash.insert("cmdmulligan", Command_Mulligan::newItem); itemNameHash.insert("cmdroll_die", Command_RollDie::newItem); itemNameHash.insert("cmddraw_cards", Command_DrawCards::newItem); itemNameHash.insert("cmdmove_card", Command_MoveCard::newItem); @@ -373,7 +375,6 @@ void ProtocolItem::initializeHashAuto() itemNameHash.insert("game_eventgame_closed", Event_GameClosed::newItem); itemNameHash.insert("game_eventready_start", Event_ReadyStart::newItem); itemNameHash.insert("game_eventconcede", Event_Concede::newItem); - itemNameHash.insert("game_eventgame_start", Event_GameStart::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 57518d9b..34ca634c 100644 --- a/common/protocol_items.dat +++ b/common/protocol_items.dat @@ -15,6 +15,7 @@ 2:leave_game 2:say:s,message 2:shuffle +2:mulligan 2:roll_die:i,sides 2:draw_cards:i,number 2:move_card:s,start_zone:i,card_id:s,target_zone:i,x:i,y:b,face_down @@ -38,7 +39,6 @@ 3:game_closed 3:ready_start 3:concede -3:game_start 3:shuffle 3:roll_die:i,sides:i,value 3:move_card:i,card_id:s,card_name:s,start_zone:i,position:s,target_zone:i,x:i,y:b,face_down @@ -52,7 +52,7 @@ 3:dump_zone:i,zone_owner_id:s,zone:i,number_cards 3:stop_dump_zone:i,zone_owner_id:s,zone 4:server_message:s,message -4:game_joined:i,game_id:i,player_id:b,spectator +4:game_joined:i,game_id:i,player_id:b,spectator:b,resuming 5:chat_join_channel:s,player_name 5:chat_leave_channel:s,player_name 5:chat_say:s,player_name:s,message diff --git a/common/protocol_items.h b/common/protocol_items.h index 0177920d..991b28b7 100644 --- a/common/protocol_items.h +++ b/common/protocol_items.h @@ -139,6 +139,13 @@ public: static SerializableItem *newItem() { return new Command_Shuffle; } int getItemId() const { return ItemId_Command_Shuffle; } }; +class Command_Mulligan : public GameCommand { + Q_OBJECT +public: + Command_Mulligan(int _gameId = -1); + static SerializableItem *newItem() { return new Command_Mulligan; } + int getItemId() const { return ItemId_Command_Mulligan; } +}; class Command_RollDie : public GameCommand { Q_OBJECT public: @@ -342,13 +349,6 @@ public: static SerializableItem *newItem() { return new Event_Concede; } int getItemId() const { return ItemId_Event_Concede; } }; -class Event_GameStart : public GameEvent { - Q_OBJECT -public: - Event_GameStart(int _gameId = -1, int _playerId = -1); - static SerializableItem *newItem() { return new Event_GameStart; } - int getItemId() const { return ItemId_Event_GameStart; } -}; class Event_Shuffle : public GameEvent { Q_OBJECT public: @@ -475,10 +475,11 @@ public: class Event_GameJoined : public GenericEvent { Q_OBJECT public: - Event_GameJoined(int _gameId = -1, int _playerId = -1, bool _spectator = false); + Event_GameJoined(int _gameId = -1, int _playerId = -1, bool _spectator = false, bool _resuming = false); int getGameId() const { return static_cast(itemMap.value("game_id"))->getData(); }; int getPlayerId() const { return static_cast(itemMap.value("player_id"))->getData(); }; bool getSpectator() const { return static_cast(itemMap.value("spectator"))->getData(); }; + bool getResuming() const { return static_cast(itemMap.value("resuming"))->getData(); }; static SerializableItem *newItem() { return new Event_GameJoined; } int getItemId() const { return ItemId_Event_GameJoined; } }; diff --git a/common/server.cpp b/common/server.cpp index 7026de83..5410b348 100644 --- a/common/server.cpp +++ b/common/server.cpp @@ -22,7 +22,7 @@ #include "server_counter.h" #include "server_chatchannel.h" #include "server_protocolhandler.h" -#include + Server::Server(QObject *parent) : QObject(parent), nextGameId(0) { @@ -56,17 +56,14 @@ void Server::removeClient(Server_ProtocolHandler *client) void Server::closeOldSession(const QString &playerName) { - qDebug() << "closing old"; Server_ProtocolHandler *session = 0; for (int i = 0; i < clients.size(); ++i) if (clients[i]->getPlayerName() == playerName) { session = clients[i]; break; } - if (session) { - qDebug() << "found"; + if (session) delete session; // ~Server_ProtocolHandler() will call Server::removeClient - } } Server_Game *Server::getGame(int gameId) const diff --git a/common/server_game.cpp b/common/server_game.cpp index 7ae84a22..fbad248e 100644 --- a/common/server_game.cpp +++ b/common/server_game.cpp @@ -25,11 +25,16 @@ #include "server_cardzone.h" #include "server_counter.h" #include +#include Server_Game::Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QString &_description, const QString &_password, int _maxPlayers, bool _spectatorsAllowed, QObject *parent) - : QObject(parent), gameStarted(false), gameId(_gameId), description(_description), password(_password), maxPlayers(_maxPlayers), spectatorsAllowed(_spectatorsAllowed) + : QObject(parent), gameStarted(false), gameId(_gameId), description(_description), password(_password), maxPlayers(_maxPlayers), activePlayer(-1), activePhase(-1), spectatorsAllowed(_spectatorsAllowed) { creator = addPlayer(_creator, false, false); + + pingClock = new QTimer(this); + connect(pingClock, SIGNAL(timeout()), this, SLOT(pingClockTimeout())); + pingClock->start(1000); } Server_Game::~Server_Game() @@ -40,25 +45,60 @@ Server_Game::~Server_Game() while (playerIterator.hasNext()) delete playerIterator.next().value(); players.clear(); - for (int i = 0; i < spectators.size(); ++i) - delete spectators[i]; - spectators.clear(); emit gameClosing(); qDebug("Server_Game destructor"); } +void Server_Game::pingClockTimeout() +{ + QDateTime now = QDateTime::currentDateTime(); + QList pingList; + QMapIterator playerIterator(players); + while (playerIterator.hasNext()) { + Server_Player *player = playerIterator.next().value(); + int pingTime = player->getProtocolHandler() ? player->getProtocolHandler()->getLastCommandTime().secsTo(now) : -1; + pingList.append(new ServerInfo_PlayerPing(player->getPlayerId(), pingTime)); + } + sendGameEvent(new Event_Ping(-1, pingList)); +} + +int Server_Game::getPlayerCount() const +{ + QMapIterator playerIterator(players); + int result = 0; + while (playerIterator.hasNext()) + if (!playerIterator.next().value()->getSpectator()) + ++result; + return result; +} + +int Server_Game::getSpectatorCount() const +{ + QMapIterator playerIterator(players); + int result = 0; + while (playerIterator.hasNext()) + if (playerIterator.next().value()->getSpectator()) + ++result; + return result; +} + void Server_Game::startGameIfReady() { - if (players.size() < maxPlayers) + if (getPlayerCount() < maxPlayers) return; QMapIterator playerIterator(players); - while (playerIterator.hasNext()) - if (!playerIterator.next().value()->getReadyStart()) + while (playerIterator.hasNext()) { + Server_Player *p = playerIterator.next().value(); + if (!p->getReadyStart() && !p->getSpectator()) return; + } playerIterator.toFront(); - while (playerIterator.hasNext()) - playerIterator.next().value()->setupZones(); + while (playerIterator.hasNext()) { + Server_Player *p = playerIterator.next().value(); + if (!p->getSpectator()) + p->setupZones(); + } gameStarted = true; playerIterator.toFront(); @@ -85,7 +125,6 @@ void Server_Game::startGameIfReady() query.exec(); } */ - sendGameEvent(new Event_GameStart); setActivePlayer(0); } @@ -125,27 +164,13 @@ ResponseCode Server_Game::checkJoin(const QString &_password, bool spectator) Server_Player *Server_Game::addPlayer(Server_ProtocolHandler *handler, bool spectator, bool broadcastUpdate) { - int playerId; - if (!spectator) { - int max = -1; - QMapIterator i(players); - while (i.hasNext()) { - int tmp = i.next().value()->getPlayerId(); - if (tmp > max) - max = tmp; - } - playerId = max + 1; - } else - playerId = -1; + const QList &keyList = players.keys(); + int playerId = keyList.isEmpty() ? 0 : (keyList.last() + 1); Server_Player *newPlayer = new Server_Player(this, playerId, handler->getPlayerName(), spectator, handler); sendGameEvent(new Event_Join(-1, new ServerInfo_Player(playerId, handler->getPlayerName(), spectator))); - - if (spectator) - spectators << newPlayer; - else - players.insert(playerId, newPlayer); - + players.insert(playerId, newPlayer); + if (broadcastUpdate) qobject_cast(parent())->broadcastGameListUpdate(this); @@ -154,14 +179,11 @@ Server_Player *Server_Game::addPlayer(Server_ProtocolHandler *handler, bool spec void Server_Game::removePlayer(Server_Player *player) { - if (player->getSpectator()) - spectators.removeAt(spectators.indexOf(player)); - else - players.remove(player->getPlayerId()); + players.remove(player->getPlayerId()); sendGameEvent(new Event_Leave(-1, player->getPlayerId())); delete player; - if (!players.size()) + if (!getPlayerCount()) deleteLater(); qobject_cast(parent())->broadcastGameListUpdate(this); } @@ -246,11 +268,12 @@ QList Server_Game::getGameState(Server_Player *playerWhosAs void Server_Game::sendGameEvent(GameEvent *event, Server_Player *exclude) { event->setGameId(gameId); - QList receivers = QList() << players.values() << spectators; - - for (int i = 0; i < receivers.size(); ++i) - if (receivers[i] != exclude) - receivers[i]->sendProtocolItem(event, false); + QMapIterator playerIterator(players); + while (playerIterator.hasNext()) { + Server_Player *p = playerIterator.next().value(); + if (p != exclude) + p->sendProtocolItem(event, false); + } delete event; } diff --git a/common/server_game.h b/common/server_game.h index 24291b37..f4efb350 100644 --- a/common/server_game.h +++ b/common/server_game.h @@ -26,12 +26,13 @@ #include "server_player.h" #include "protocol.h" +class QTimer; + class Server_Game : public QObject { Q_OBJECT private: QPointer creator; QMap players; - QList spectators; bool gameStarted; int gameId; QString description; @@ -39,16 +40,19 @@ private: int maxPlayers; int activePlayer, activePhase; bool spectatorsAllowed; + QTimer *pingClock; signals: void gameClosing(); +private slots: + void pingClockTimeout(); public: Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QString &_description, const QString &_password, int _maxPlayers, bool _spectatorsAllowed, QObject *parent = 0); ~Server_Game(); Server_Player *getCreator() const { return creator; } QString getCreatorName() const { return creator ? creator->getPlayerName() : QString(); } bool getGameStarted() const { return gameStarted; } - int getPlayerCount() const { return players.size(); } - int getSpectatorCount() const { return spectators.size(); } + int getPlayerCount() const; + int getSpectatorCount() const; QList getPlayers() const { return players.values(); } Server_Player *getPlayer(int playerId) const { return players.value(playerId, 0); } int getGameId() const { return gameId; } diff --git a/common/server_player.cpp b/common/server_player.cpp index ca495217..a4598bbd 100644 --- a/common/server_player.cpp +++ b/common/server_player.cpp @@ -66,6 +66,17 @@ void Server_Player::setupZones() addZone(new Server_CardZone(this, "grave", false, PublicZone)); addZone(new Server_CardZone(this, "rfg", false, PublicZone)); + addCounter(new Server_Counter(0, "life", Qt::white, 25, 20)); + addCounter(new Server_Counter(1, "w", QColor(255, 255, 150), 20, 0)); + addCounter(new Server_Counter(2, "u", QColor(150, 150, 255), 20, 0)); + addCounter(new Server_Counter(3, "b", QColor(150, 150, 150), 20, 0)); + addCounter(new Server_Counter(4, "r", QColor(250, 150, 150), 20, 0)); + addCounter(new Server_Counter(5, "g", QColor(150, 255, 150), 20, 0)); + addCounter(new Server_Counter(6, "x", QColor(255, 255, 255), 20, 0)); + addCounter(new Server_Counter(7, "storm", QColor(255, 255, 255), 20, 0)); + + initialCards = 7; + // ------------------------------------------------------------------ // Assign card ids and create deck from decklist diff --git a/common/server_player.h b/common/server_player.h index 3a324b69..bb1ae996 100644 --- a/common/server_player.h +++ b/common/server_player.h @@ -26,6 +26,7 @@ private: int playerId; QString playerName; bool spectator; + int initialCards; int nextCardId; void clearZones(); bool readyStart; @@ -33,9 +34,12 @@ private: public: Server_Player(Server_Game *_game, int _playerId, const QString &_playerName, bool _spectator, Server_ProtocolHandler *_handler); ~Server_Player(); + Server_ProtocolHandler *getProtocolHandler() const { return handler; } void setProtocolHandler(Server_ProtocolHandler *_handler) { handler = _handler; } void setPlayerId(int _id) { playerId = _id; } + int getInitialCards() const { return initialCards; } + void setInitialCards(int _initialCards) { initialCards = _initialCards; } bool getReadyStart() const { return readyStart; } void setReadyStart(bool _readyStart) { readyStart = _readyStart; } int getPlayerId() const { return playerId; } diff --git a/common/server_protocolhandler.cpp b/common/server_protocolhandler.cpp index 87f6fd85..c24ae36a 100644 --- a/common/server_protocolhandler.cpp +++ b/common/server_protocolhandler.cpp @@ -11,10 +11,15 @@ #include "server_game.h" #include "server_player.h" #include "decklist.h" +#include +#include Server_ProtocolHandler::Server_ProtocolHandler(Server *_server, QObject *parent) - : QObject(parent), server(_server), authState(PasswordWrong), acceptsGameListChanges(false) + : QObject(parent), server(_server), authState(PasswordWrong), acceptsGameListChanges(false), lastCommandTime(QDateTime::currentDateTime()) { + pingClock = new QTimer(this); + connect(pingClock, SIGNAL(timeout()), this, SLOT(pingClockTimeout())); + pingClock->start(1000); } Server_ProtocolHandler::~Server_ProtocolHandler() @@ -42,6 +47,8 @@ Server_ProtocolHandler::~Server_ProtocolHandler() void Server_ProtocolHandler::processCommand(Command *command) { + lastCommandTime = QDateTime::currentDateTime(); + ResponseCode response = RespInvalidCommand; ChatCommand *chatCommand = qobject_cast(command); @@ -84,6 +91,7 @@ void Server_ProtocolHandler::processCommand(Command *command) case ItemId_Command_Concede: response = cmdConcede(qobject_cast(command), game, player); break; case ItemId_Command_Say: response = cmdSay(qobject_cast(command), game, player); break; case ItemId_Command_Shuffle: response = cmdShuffle(qobject_cast(command), game, player); break; + case ItemId_Command_Mulligan: response = cmdMulligan(qobject_cast(command), game, player); break; case ItemId_Command_RollDie: response = cmdRollDie(qobject_cast(command), game, player); break; case ItemId_Command_DrawCards: response = cmdDrawCards(qobject_cast(command), game, player); break; case ItemId_Command_MoveCard: response = cmdMoveCard(qobject_cast(command), game, player); break; @@ -127,9 +135,15 @@ void Server_ProtocolHandler::processCommand(Command *command) sendProtocolItem(itemQueue.takeFirst()); } +void Server_ProtocolHandler::pingClockTimeout() +{ + if (lastCommandTime.secsTo(QDateTime::currentDateTime()) > 10) + deleteLater(); +} + void Server_ProtocolHandler::enqueueProtocolItem(ProtocolItem *item) { - itemQueue << item; + itemQueue.append(item); } QPair Server_ProtocolHandler::getGame(int gameId) const @@ -156,17 +170,19 @@ ResponseCode Server_ProtocolHandler::cmdLogin(Command_Login *cmd) playerName = userName; enqueueProtocolItem(new Event_ServerMessage(server->getLoginMessage())); - // This might not scale very well. Use an extra QMap if it becomes a problem. - const QList &serverGames = server->getGames(); - for (int i = 0; i < serverGames.size(); ++i) { - const QList &gamePlayers = serverGames[i]->getPlayers(); - for (int j = 0; j < gamePlayers.size(); ++j) - if (gamePlayers[j]->getPlayerName() == playerName) { - gamePlayers[j]->setProtocolHandler(this); - games.insert(serverGames[i]->getGameId(), QPair(serverGames[i], gamePlayers[j])); - enqueueProtocolItem(new Event_GameJoined(serverGames[i]->getGameId(), gamePlayers[j]->getPlayerId(), gamePlayers[j]->getSpectator())); - enqueueProtocolItem(new Event_GameStateChanged(serverGames[i]->getGameId(), serverGames[i]->getGameStarted(), serverGames[i]->getActivePlayer(), serverGames[i]->getActivePhase(), serverGames[i]->getGameState(gamePlayers[j]))); - } + if (authState == PasswordRight) { + // This might not scale very well. Use an extra QMap if it becomes a problem. + const QList &serverGames = server->getGames(); + for (int i = 0; i < serverGames.size(); ++i) { + const QList &gamePlayers = serverGames[i]->getPlayers(); + for (int j = 0; j < gamePlayers.size(); ++j) + if (gamePlayers[j]->getPlayerName() == playerName) { + gamePlayers[j]->setProtocolHandler(this); + games.insert(serverGames[i]->getGameId(), QPair(serverGames[i], gamePlayers[j])); + enqueueProtocolItem(new Event_GameJoined(serverGames[i]->getGameId(), gamePlayers[j]->getPlayerId(), gamePlayers[j]->getSpectator(), true)); + enqueueProtocolItem(new Event_GameStateChanged(serverGames[i]->getGameId(), serverGames[i]->getGameStarted(), serverGames[i]->getActivePlayer(), serverGames[i]->getActivePhase(), serverGames[i]->getGameState(gamePlayers[j]))); + } + } } return RespOk; @@ -249,7 +265,7 @@ ResponseCode Server_ProtocolHandler::cmdCreateGame(Command_CreateGame *cmd) Server_Player *creator = game->getCreator(); games.insert(game->getGameId(), QPair(game, creator)); - enqueueProtocolItem(new Event_GameJoined(game->getGameId(), creator->getPlayerId(), false)); + enqueueProtocolItem(new Event_GameJoined(game->getGameId(), creator->getPlayerId(), false, false)); enqueueProtocolItem(new Event_GameStateChanged(game->getGameId(), game->getGameStarted(), game->getActivePlayer(), game->getActivePhase(), game->getGameState(creator))); return RespOk; } @@ -264,7 +280,7 @@ ResponseCode Server_ProtocolHandler::cmdJoinGame(Command_JoinGame *cmd) if (result == RespOk) { Server_Player *player = g->addPlayer(this, cmd->getSpectator()); games.insert(cmd->getGameId(), QPair(g, player)); - enqueueProtocolItem(new Event_GameJoined(cmd->getGameId(), player->getPlayerId(), cmd->getSpectator())); + enqueueProtocolItem(new Event_GameJoined(cmd->getGameId(), player->getPlayerId(), cmd->getSpectator(), false)); enqueueProtocolItem(new Event_GameStateChanged(cmd->getGameId(), g->getGameStarted(), g->getActivePlayer(), g->getActivePhase(), g->getGameState(player))); } return result; @@ -272,6 +288,7 @@ ResponseCode Server_ProtocolHandler::cmdJoinGame(Command_JoinGame *cmd) ResponseCode Server_ProtocolHandler::cmdLeaveGame(Command_LeaveGame * /*cmd*/, Server_Game *game, Server_Player *player) { + games.remove(game->getGameId()); game->removePlayer(player); return RespOk; } @@ -330,17 +347,35 @@ ResponseCode Server_ProtocolHandler::cmdShuffle(Command_Shuffle * /*cmd*/, Serve return RespOk; } +ResponseCode Server_ProtocolHandler::cmdMulligan(Command_Mulligan * /*cmd*/, Server_Game *game, Server_Player *player) +{ + int number = player->getInitialCards(); + if (!number) + return RespContextError; + + Server_CardZone *hand = player->getZones().value("hand"); + while (!hand->cards.isEmpty()) + moveCard(game, player, "hand", hand->cards.first()->getId(), "deck", 0, 0, false); + + player->getZones().value("deck")->shuffle(); + game->sendGameEvent(new Event_Shuffle(-1, player->getPlayerId())); + + drawCards(game, player, number); + player->setInitialCards(number - 1); + + return RespOk; +} + ResponseCode Server_ProtocolHandler::cmdRollDie(Command_RollDie *cmd, Server_Game *game, Server_Player *player) { game->sendGameEvent(new Event_RollDie(-1, player->getPlayerId(), cmd->getSides(), rng->getNumber(1, cmd->getSides()))); return RespOk; } -ResponseCode Server_ProtocolHandler::cmdDrawCards(Command_DrawCards *cmd, Server_Game *game, Server_Player *player) +ResponseCode Server_ProtocolHandler::drawCards(Server_Game *game, Server_Player *player, int number) { Server_CardZone *deck = player->getZones().value("deck"); Server_CardZone *hand = player->getZones().value("hand"); - int number = cmd->getNumber(); if (deck->cards.size() < number) number = deck->cards.size(); @@ -350,53 +385,55 @@ ResponseCode Server_ProtocolHandler::cmdDrawCards(Command_DrawCards *cmd, Server hand->cards.append(card); cardList.append(new ServerInfo_Card(card->getId(), card->getName())); } - + player->sendProtocolItem(new Event_DrawCards(game->getGameId(), player->getPlayerId(), cardList.size(), cardList)); game->sendGameEvent(new Event_DrawCards(-1, player->getPlayerId(), cardList.size()), player); return RespOk; } -ResponseCode Server_ProtocolHandler::cmdMoveCard(Command_MoveCard *cmd, Server_Game *game, Server_Player *player) + +ResponseCode Server_ProtocolHandler::cmdDrawCards(Command_DrawCards *cmd, Server_Game *game, Server_Player *player) { - // ID Karte, Startzone, Zielzone, Koordinaten X, Y, Facedown - Server_CardZone *startzone = player->getZones().value(cmd->getStartZone()); - Server_CardZone *targetzone = player->getZones().value(cmd->getTargetZone()); + return drawCards(game, player, cmd->getNumber()); +} + +ResponseCode Server_ProtocolHandler::moveCard(Server_Game *game, Server_Player *player, const QString &_startZone, int _cardId, const QString &_targetZone, int x, int y, bool faceDown) +{ + Server_CardZone *startzone = player->getZones().value(_startZone); + Server_CardZone *targetzone = player->getZones().value(_targetZone); if ((!startzone) || (!targetzone)) return RespNameNotFound; int position = -1; - Server_Card *card = startzone->getCard(cmd->getCardId(), true, &position); + Server_Card *card = startzone->getCard(_cardId, true, &position); if (!card) return RespNameNotFound; - int x = cmd->getX(); if (x == -1) x = targetzone->cards.size(); - int y = 0; - if (targetzone->hasCoords()) - y = cmd->getY(); - bool facedown = cmd->getFaceDown(); + if (!targetzone->hasCoords()) + y = 0; targetzone->insertCard(card, x, y); bool targetBeingLookedAt = (targetzone->getType() != HiddenZone) || (targetzone->getCardsBeingLookedAt() > x) || (targetzone->getCardsBeingLookedAt() == -1); bool sourceBeingLookedAt = (startzone->getType() != HiddenZone) || (startzone->getCardsBeingLookedAt() > position) || (startzone->getCardsBeingLookedAt() == -1); - bool targetHiddenToPlayer = facedown || !targetBeingLookedAt; - bool targetHiddenToOthers = facedown || (targetzone->getType() != PublicZone); + bool targetHiddenToPlayer = faceDown || !targetBeingLookedAt; + bool targetHiddenToOthers = faceDown || (targetzone->getType() != PublicZone); bool sourceHiddenToPlayer = card->getFaceDown() || !sourceBeingLookedAt; bool sourceHiddenToOthers = card->getFaceDown() || (startzone->getType() != PublicZone); - + QString privateCardName, publicCardName; if (!(sourceHiddenToPlayer && targetHiddenToPlayer)) privateCardName = card->getName(); if (!(sourceHiddenToOthers && targetHiddenToOthers)) publicCardName = card->getName(); - - if (facedown) + + if (faceDown) card->setId(player->newCardId()); - card->setFaceDown(facedown); - + card->setFaceDown(faceDown); + // The player does not get to see which card he moved if it moves between two parts of hidden zones which // are not being looked at. int privateCardId = card->getId(); @@ -407,7 +444,7 @@ ResponseCode Server_ProtocolHandler::cmdMoveCard(Command_MoveCard *cmd, Server_G int privatePosition = -1; if (startzone->getType() == HiddenZone) privatePosition = position; - player->sendProtocolItem(new Event_MoveCard(game->getGameId(), player->getPlayerId(), privateCardId, privateCardName, startzone->getName(), privatePosition, targetzone->getName(), x, y, facedown)); + player->sendProtocolItem(new Event_MoveCard(game->getGameId(), player->getPlayerId(), privateCardId, privateCardName, startzone->getName(), privatePosition, targetzone->getName(), x, y, faceDown)); // Other players do not get to see the start and/or target position of the card if the respective // part of the zone is being looked at. The information is not needed anyway because in hidden zones, @@ -416,9 +453,9 @@ ResponseCode Server_ProtocolHandler::cmdMoveCard(Command_MoveCard *cmd, Server_G position = -1; if ((targetzone->getType() == HiddenZone) && ((targetzone->getCardsBeingLookedAt() > x) || (targetzone->getCardsBeingLookedAt() == -1))) x = -1; - + if ((startzone->getType() == PublicZone) || (targetzone->getType() == PublicZone)) - game->sendGameEvent(new Event_MoveCard(-1, player->getPlayerId(), card->getId(), publicCardName, startzone->getName(), position, targetzone->getName(), x, y, facedown), player); + game->sendGameEvent(new Event_MoveCard(-1, player->getPlayerId(), card->getId(), publicCardName, startzone->getName(), position, targetzone->getName(), x, y, faceDown), player); else game->sendGameEvent(new Event_MoveCard(-1, player->getPlayerId(), -1, QString(), startzone->getName(), position, targetzone->getName(), x, y, false), player); @@ -441,6 +478,11 @@ ResponseCode Server_ProtocolHandler::cmdMoveCard(Command_MoveCard *cmd, Server_G return RespOk; } +ResponseCode Server_ProtocolHandler::cmdMoveCard(Command_MoveCard *cmd, Server_Game *game, Server_Player *player) +{ + return moveCard(game, player, cmd->getStartZone(), cmd->getCardId(), cmd->getTargetZone(), cmd->getX(), cmd->getY(), cmd->getFaceDown()); +} + ResponseCode Server_ProtocolHandler::cmdCreateToken(Command_CreateToken *cmd, Server_Game *game, Server_Player *player) { // powtough wird erst mal ignoriert diff --git a/common/server_protocolhandler.h b/common/server_protocolhandler.h index 71126d13..910879e5 100644 --- a/common/server_protocolhandler.h +++ b/common/server_protocolhandler.h @@ -8,6 +8,7 @@ #include "protocol_items.h" class Server_Player; +class QTimer; class Server_ProtocolHandler : public QObject { Q_OBJECT @@ -16,7 +17,7 @@ protected: QMap > games; QMap chatChannels; QString playerName; - + Server *getServer() const { return server; } QPair getGame(int gameId) const; @@ -26,7 +27,9 @@ protected: private: QList itemQueue; - + QDateTime lastCommandTime; + QTimer *pingClock; + virtual DeckList *getDeckFromDatabase(int deckId) = 0; ResponseCode cmdPing(Command_Ping *cmd); @@ -50,8 +53,12 @@ private: ResponseCode cmdDeckSelect(Command_DeckSelect *cmd, Server_Game *game, Server_Player *player); ResponseCode cmdSay(Command_Say *cmd, Server_Game *game, Server_Player *player); ResponseCode cmdShuffle(Command_Shuffle *cmd, Server_Game *game, Server_Player *player); + ResponseCode cmdMulligan(Command_Mulligan *cmd, Server_Game *game, Server_Player *player); ResponseCode cmdRollDie(Command_RollDie *cmd, Server_Game *game, Server_Player *player); + // XXX Maybe the following function and others belong into Server_Player + ResponseCode drawCards(Server_Game *game, Server_Player *player, int number); ResponseCode cmdDrawCards(Command_DrawCards *cmd, Server_Game *game, Server_Player *player); + ResponseCode moveCard(Server_Game *game, Server_Player *player, const QString &_startZone, int _cardId, const QString &_targetZone, int _x, int _y, bool _faceDown); ResponseCode cmdMoveCard(Command_MoveCard *cmd, Server_Game *game, Server_Player *player); ResponseCode cmdCreateToken(Command_CreateToken *cmd, Server_Game *game, Server_Player *player); ResponseCode cmdCreateArrow(Command_CreateArrow *cmd, Server_Game *game, Server_Player *player); @@ -65,6 +72,8 @@ private: ResponseCode cmdSetActivePhase(Command_SetActivePhase *cmd, Server_Game *game, Server_Player *player); ResponseCode cmdDumpZone(Command_DumpZone *cmd, Server_Game *game, Server_Player *player); ResponseCode cmdStopDumpZone(Command_StopDumpZone *cmd, Server_Game *game, Server_Player *player); +private slots: + void pingClockTimeout(); public: Server_ProtocolHandler(Server *_server, QObject *parent = 0); ~Server_ProtocolHandler(); @@ -72,7 +81,8 @@ public: bool getAcceptsGameListChanges() const { return acceptsGameListChanges; } bool getAcceptsChatChannelListChanges() const { return acceptsChatChannelListChanges; } const QString &getPlayerName() const { return playerName; } - + const QDateTime &getLastCommandTime() const { return lastCommandTime; } + void processCommand(Command *command); virtual void sendProtocolItem(ProtocolItem *item, bool deleteItem = true) = 0; void enqueueProtocolItem(ProtocolItem *item);