diff --git a/cockatrice/cockatrice.pro b/cockatrice/cockatrice.pro index de38d7ad..bf439c09 100644 --- a/cockatrice/cockatrice.pro +++ b/cockatrice/cockatrice.pro @@ -7,7 +7,8 @@ OBJECTS_DIR = build RESOURCES = cockatrice.qrc QT += network svg -HEADERS += src/counter.h \ +HEADERS += src/abstractcounter.h \ + src/counter_general.h \ src/dlg_creategame.h \ src/dlg_connect.h \ src/dlg_create_token.h \ @@ -52,11 +53,12 @@ HEADERS += src/counter.h \ src/arrowtarget.h \ src/tab.h \ src/tab_server.h \ - src/tab_chatchannel.h \ + src/tab_room.h \ src/tab_message.h \ src/tab_game.h \ src/tab_deck_storage.h \ src/tab_supervisor.h \ + src/userlist.h \ src/remotedecklist_treewidget.h \ src/deckview.h \ src/playerlistwidget.h \ @@ -78,14 +80,15 @@ HEADERS += src/counter.h \ ../common/server_arrow.h \ ../common/server_card.h \ ../common/server_cardzone.h \ - ../common/server_chatchannel.h \ + ../common/server_room.h \ ../common/server_counter.h \ ../common/server_game.h \ ../common/server_player.h \ ../common/server_protocolhandler.h \ ../common/server_arrowtarget.h -SOURCES += src/counter.cpp \ +SOURCES += src/abstractcounter.cpp \ + src/counter_general.cpp \ src/dlg_creategame.cpp \ src/dlg_connect.cpp \ src/dlg_create_token.cpp \ @@ -130,11 +133,12 @@ SOURCES += src/counter.cpp \ src/arrowitem.cpp \ src/arrowtarget.cpp \ src/tab_server.cpp \ - src/tab_chatchannel.cpp \ + src/tab_room.cpp \ src/tab_message.cpp \ src/tab_game.cpp \ src/tab_deck_storage.cpp \ src/tab_supervisor.cpp \ + src/userlist.cpp \ src/remotedecklist_treewidget.cpp \ src/deckview.cpp \ src/playerlistwidget.cpp \ @@ -154,7 +158,7 @@ SOURCES += src/counter.cpp \ ../common/server.cpp \ ../common/server_card.cpp \ ../common/server_cardzone.cpp \ - ../common/server_chatchannel.cpp \ + ../common/server_room.cpp \ ../common/server_game.cpp \ ../common/server_player.cpp \ ../common/server_protocolhandler.cpp diff --git a/cockatrice/src/abstractcarditem.h b/cockatrice/src/abstractcarditem.h index 0f592d31..c07b78a0 100644 --- a/cockatrice/src/abstractcarditem.h +++ b/cockatrice/src/abstractcarditem.h @@ -11,7 +11,7 @@ class QTimer; const int CARD_WIDTH = 72; const int CARD_HEIGHT = 102; -class AbstractCardItem : public QObject, public ArrowTarget { +class AbstractCardItem : public ArrowTarget { Q_OBJECT protected: CardInfo *info; diff --git a/cockatrice/src/abstractclient.cpp b/cockatrice/src/abstractclient.cpp index 924c9617..627f6ed6 100644 --- a/cockatrice/src/abstractclient.cpp +++ b/cockatrice/src/abstractclient.cpp @@ -32,11 +32,10 @@ void AbstractClient::processProtocolItem(ProtocolItem *item) GenericEvent *genericEvent = qobject_cast(item); if (genericEvent) { switch (genericEvent->getItemId()) { - case ItemId_Event_ListGames: emit listGamesEventReceived(qobject_cast(item)); break; case ItemId_Event_UserJoined: emit userJoinedEventReceived(qobject_cast(item)); break; case ItemId_Event_UserLeft: emit userLeftEventReceived(qobject_cast(item)); break; case ItemId_Event_ServerMessage: emit serverMessageEventReceived(qobject_cast(item)); break; - case ItemId_Event_ListChatChannels: emit listChatChannelsEventReceived(qobject_cast(item)); break; + case ItemId_Event_ListRooms: emit listRoomsEventReceived(qobject_cast(item)); break; case ItemId_Event_GameJoined: emit gameJoinedEventReceived(qobject_cast(item)); break; case ItemId_Event_Message: emit messageEventReceived(qobject_cast(item)); break; } @@ -53,11 +52,11 @@ void AbstractClient::processProtocolItem(ProtocolItem *item) return; } - ChatEvent *chatEvent = qobject_cast(item); - if (chatEvent) { - emit chatEventReceived(chatEvent); - if (chatEvent->getReceiverMayDelete()) - delete chatEvent; + RoomEvent *roomEvent = qobject_cast(item); + if (roomEvent) { + emit roomEventReceived(roomEvent); + if (roomEvent->getReceiverMayDelete()) + delete roomEvent; return; } } @@ -75,4 +74,3 @@ void AbstractClient::sendCommand(Command *cmd) { sendCommandContainer(new CommandContainer(QList() << cmd)); } - diff --git a/cockatrice/src/abstractclient.h b/cockatrice/src/abstractclient.h index 601e55db..dae91752 100644 --- a/cockatrice/src/abstractclient.h +++ b/cockatrice/src/abstractclient.h @@ -10,13 +10,13 @@ class ProtocolItem; class ProtocolResponse; class TopLevelProtocolItem; class CommandContainer; -class ChatEvent; +class RoomEvent; class GameEventContainer; class Event_ListGames; class Event_UserJoined; class Event_UserLeft; class Event_ServerMessage; -class Event_ListChatChannels; +class Event_ListRooms; class Event_GameJoined; class Event_Message; @@ -35,18 +35,18 @@ signals: void statusChanged(ClientStatus _status); void serverError(ResponseCode resp); - // Chat events - void chatEventReceived(ChatEvent *event); + // Room events + void roomEventReceived(RoomEvent *event); // Game events void gameEventContainerReceived(GameEventContainer *event); // Generic events - void listGamesEventReceived(Event_ListGames *event); void userJoinedEventReceived(Event_UserJoined *event); void userLeftEventReceived(Event_UserLeft *event); void serverMessageEventReceived(Event_ServerMessage *event); - void listChatChannelsEventReceived(Event_ListChatChannels *event); + void listRoomsEventReceived(Event_ListRooms *event); void gameJoinedEventReceived(Event_GameJoined *event); void messageEventReceived(Event_Message *event); + void userInfoChanged(ServerInfo_User *userInfo); protected slots: void processProtocolItem(ProtocolItem *item); protected: diff --git a/cockatrice/src/counter.cpp b/cockatrice/src/abstractcounter.cpp similarity index 66% rename from cockatrice/src/counter.cpp rename to cockatrice/src/abstractcounter.cpp index ee6d060a..aed566c8 100644 --- a/cockatrice/src/counter.cpp +++ b/cockatrice/src/abstractcounter.cpp @@ -1,16 +1,17 @@ -#include "counter.h" +#include "abstractcounter.h" #include "player.h" #include "protocol_items.h" #include #include #include #include +#include -Counter::Counter(Player *_player, int _id, const QString &_name, QColor _color, int _radius, int _value, QGraphicsItem *parent) - : QGraphicsItem(parent), player(_player), id(_id), name(_name), color(_color), radius(_radius), value(_value), aDec(0), aInc(0), dialogSemaphore(false), deleteAfterDialog(false) +AbstractCounter::AbstractCounter(Player *_player, int _id, const QString &_name, bool _shownInCounterArea, int _value, QGraphicsItem *parent) + : QGraphicsItem(parent), player(_player), id(_id), name(_name), value(_value), hovered(false), aDec(0), aInc(0), dialogSemaphore(false), deleteAfterDialog(false), shownInCounterArea(_shownInCounterArea) { - if (radius > Player::counterAreaWidth / 2) - radius = Player::counterAreaWidth / 2; + setAcceptsHoverEvents(true); + if (player->getLocal()) { menu = new QMenu(name); aSet = new QAction(this); @@ -36,12 +37,12 @@ Counter::Counter(Player *_player, int _id, const QString &_name, QColor _color, retranslateUi(); } -Counter::~Counter() +AbstractCounter::~AbstractCounter() { delete menu; } -void Counter::delCounter() +void AbstractCounter::delCounter() { if (dialogSemaphore) deleteAfterDialog = true; @@ -49,14 +50,14 @@ void Counter::delCounter() deleteLater(); } -void Counter::retranslateUi() +void AbstractCounter::retranslateUi() { if (menu) { aSet->setText(tr("&Set counter...")); } } -void Counter::setShortcutsActive() +void AbstractCounter::setShortcutsActive() { if (name == "life") { aSet->setShortcut(tr("Ctrl+L")); @@ -65,7 +66,7 @@ void Counter::setShortcutsActive() } } -void Counter::setShortcutsInactive() +void AbstractCounter::setShortcutsInactive() { if (name == "life") { aSet->setShortcut(QKeySequence()); @@ -74,31 +75,13 @@ void Counter::setShortcutsInactive() } } -QRectF Counter::boundingRect() const -{ - return QRectF(0, 0, radius * 2, radius * 2); -} - -void Counter::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) -{ - painter->setBrush(QBrush(color)); - painter->drawEllipse(boundingRect()); - if (value) { - QFont f("Serif"); - f.setPixelSize(radius * 0.8); - f.setWeight(QFont::Bold); - painter->setFont(f); - painter->drawText(boundingRect(), Qt::AlignCenter, QString::number(value)); - } -} - -void Counter::setValue(int _value) +void AbstractCounter::setValue(int _value) { value = _value; update(); } -void Counter::mousePressEvent(QGraphicsSceneMouseEvent *event) +void AbstractCounter::mousePressEvent(QGraphicsSceneMouseEvent *event) { if (event->button() == Qt::LeftButton) { player->sendGameCommand(new Command_IncCounter(-1, id, 1)); @@ -114,13 +97,25 @@ void Counter::mousePressEvent(QGraphicsSceneMouseEvent *event) event->ignore(); } -void Counter::incrementCounter() +void AbstractCounter::hoverEnterEvent(QGraphicsSceneHoverEvent *event) +{ + hovered = true; + update(); +} + +void AbstractCounter::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) +{ + hovered = false; + update(); +} + +void AbstractCounter::incrementCounter() { int delta = static_cast(sender())->data().toInt(); player->sendGameCommand(new Command_IncCounter(-1, id, delta)); } -void Counter::setCounter() +void AbstractCounter::setCounter() { bool ok; dialogSemaphore = true; diff --git a/cockatrice/src/counter.h b/cockatrice/src/abstractcounter.h similarity index 61% rename from cockatrice/src/counter.h rename to cockatrice/src/abstractcounter.h index 7d7f932b..6a4a4188 100644 --- a/cockatrice/src/counter.h +++ b/cockatrice/src/abstractcounter.h @@ -7,35 +7,36 @@ class Player; class QMenu; class QAction; -class Counter : public QObject, public QGraphicsItem { +class AbstractCounter : public QObject, public QGraphicsItem { Q_OBJECT -private: +protected: Player *player; int id; QString name; - QColor color; - int radius; int value; + bool hovered; + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void hoverEnterEvent(QGraphicsSceneHoverEvent *event); + void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); +private: QAction *aSet, *aDec, *aInc; QMenu *menu; bool dialogSemaphore, deleteAfterDialog; + bool shownInCounterArea; private slots: void incrementCounter(); void setCounter(); -protected: - void mousePressEvent(QGraphicsSceneMouseEvent *event); public: - Counter(Player *_player, int _id, const QString &_name, QColor _color, int _radius, int _value, QGraphicsItem *parent = 0); - ~Counter(); - QRectF boundingRect() const; - void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + AbstractCounter(Player *_player, int _id, const QString &_name, bool _shownInCounterArea, int _value, QGraphicsItem *parent = 0); + ~AbstractCounter(); QMenu *getMenu() const { return menu; } void retranslateUi(); int getId() const { return id; } QString getName() const { return name; } + bool getShownInCounterArea() const { return shownInCounterArea; } int getValue() const { return value; } void setValue(int _value); void delCounter(); diff --git a/cockatrice/src/abstractgraphicsitem.h b/cockatrice/src/abstractgraphicsitem.h index ff13ff4f..2bb094d3 100644 --- a/cockatrice/src/abstractgraphicsitem.h +++ b/cockatrice/src/abstractgraphicsitem.h @@ -12,11 +12,12 @@ enum GraphicsItemType { typeOther = QGraphicsItem::UserType + 6 }; -class AbstractGraphicsItem : public QGraphicsItem { +class AbstractGraphicsItem : public QObject, public QGraphicsItem { + Q_OBJECT protected: void paintNumberEllipse(int number, int radius, const QColor &color, int position, int count, QPainter *painter); public: - AbstractGraphicsItem(QGraphicsItem *parent = 0) : QGraphicsItem(parent) { } + AbstractGraphicsItem(QGraphicsItem *parent = 0) : QObject(), QGraphicsItem(parent) { } }; #endif diff --git a/cockatrice/src/arrowitem.cpp b/cockatrice/src/arrowitem.cpp index cc4c67dc..1dc1bf2f 100644 --- a/cockatrice/src/arrowitem.cpp +++ b/cockatrice/src/arrowitem.cpp @@ -13,7 +13,7 @@ ArrowItem::ArrowItem(Player *_player, int _id, ArrowTarget *_startItem, ArrowTarget *_targetItem, const QColor &_color) : QGraphicsItem(), player(_player), id(_id), startItem(_startItem), targetItem(_targetItem), color(_color), fullColor(true) { - qDebug() << "ArrowItem constructor: startItem=" << startItem; + qDebug() << "ArrowItem constructor: startItem=" << static_cast(startItem); setZValue(2000000005); if (startItem) diff --git a/cockatrice/src/cardzone.h b/cockatrice/src/cardzone.h index e9a04c30..b8caf9ab 100644 --- a/cockatrice/src/cardzone.h +++ b/cockatrice/src/cardzone.h @@ -14,7 +14,7 @@ class QAction; class QPainter; class CardDragItem; -class CardZone : public QObject, public AbstractGraphicsItem { +class CardZone : public AbstractGraphicsItem { Q_OBJECT protected: Player *player; diff --git a/cockatrice/src/counter_general.cpp b/cockatrice/src/counter_general.cpp new file mode 100644 index 00000000..6b722834 --- /dev/null +++ b/cockatrice/src/counter_general.cpp @@ -0,0 +1,26 @@ +#include "counter_general.h" +#include + +GeneralCounter::GeneralCounter(Player *_player, int _id, const QString &_name, const QColor &_color, int _radius, int _value, QGraphicsItem *parent) + : AbstractCounter(_player, _id, _name, true, _value, parent), color(_color), radius(_radius) +{ +} + +QRectF GeneralCounter::boundingRect() const +{ + return QRectF(0, 0, radius * 2, radius * 2); +} + +void GeneralCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) +{ + painter->setBrush(QBrush(color)); + painter->drawEllipse(boundingRect()); + if (value) { + QFont f("Serif"); + f.setPixelSize(radius * 0.8); + f.setWeight(QFont::Bold); + painter->setFont(f); + painter->drawText(boundingRect(), Qt::AlignCenter, QString::number(value)); + } +} + diff --git a/cockatrice/src/counter_general.h b/cockatrice/src/counter_general.h new file mode 100644 index 00000000..58468aa8 --- /dev/null +++ b/cockatrice/src/counter_general.h @@ -0,0 +1,17 @@ +#ifndef COUNTER_GENERAL_H +#define COUNTER_GENERAL_H + +#include "abstractcounter.h" + +class GeneralCounter : public AbstractCounter { + Q_OBJECT +private: + QColor color; + int radius; +public: + GeneralCounter(Player *_player, int _id, const QString &_name, const QColor &_color, int _radius, int _value, QGraphicsItem *parent = 0); + QRectF boundingRect() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); +}; + +#endif \ No newline at end of file diff --git a/cockatrice/src/dlg_creategame.cpp b/cockatrice/src/dlg_creategame.cpp index 5cf957b6..e36a6815 100644 --- a/cockatrice/src/dlg_creategame.cpp +++ b/cockatrice/src/dlg_creategame.cpp @@ -11,8 +11,8 @@ #include "dlg_creategame.h" #include "protocol_items.h" -DlgCreateGame::DlgCreateGame(AbstractClient *_client, QWidget *parent) - : QDialog(parent), client(_client) +DlgCreateGame::DlgCreateGame(AbstractClient *_client, int _roomId, QWidget *parent) + : QDialog(parent), client(_client), roomId(_roomId) { descriptionLabel = new QLabel(tr("&Description:")); descriptionEdit = new QLineEdit; @@ -77,6 +77,7 @@ DlgCreateGame::DlgCreateGame(AbstractClient *_client, QWidget *parent) void DlgCreateGame::actOK() { Command_CreateGame *createCommand = new Command_CreateGame( + roomId, descriptionEdit->text(), passwordEdit->text(), maxPlayersEdit->value(), diff --git a/cockatrice/src/dlg_creategame.h b/cockatrice/src/dlg_creategame.h index af72fe18..dcd901df 100644 --- a/cockatrice/src/dlg_creategame.h +++ b/cockatrice/src/dlg_creategame.h @@ -14,13 +14,14 @@ class QSpinBox; class DlgCreateGame : public QDialog { Q_OBJECT public: - DlgCreateGame(AbstractClient *_client, QWidget *parent = 0); + DlgCreateGame(AbstractClient *_client, int _roomId, QWidget *parent = 0); private slots: void actOK(); void checkResponse(ResponseCode response); void spectatorsAllowedChanged(int state); private: AbstractClient *client; + int roomId; QGroupBox *spectatorsGroupBox; QLabel *descriptionLabel, *passwordLabel, *maxPlayersLabel; diff --git a/cockatrice/src/gamescene.cpp b/cockatrice/src/gamescene.cpp index d0c94cbf..330ebef5 100644 --- a/cockatrice/src/gamescene.cpp +++ b/cockatrice/src/gamescene.cpp @@ -82,7 +82,7 @@ void GameScene::toggleZoneView(Player *player, const QString &zoneName, int numb } } - ZoneViewWidget *item = new ZoneViewWidget(player, player->getZones().value(zoneName), numberCards); + ZoneViewWidget *item = new ZoneViewWidget(player, player->getZones().value(zoneName), numberCards, false); views.append(item); connect(item, SIGNAL(closePressed(ZoneViewWidget *)), this, SLOT(removeZoneView(ZoneViewWidget *))); addItem(item); @@ -91,7 +91,7 @@ void GameScene::toggleZoneView(Player *player, const QString &zoneName, int numb void GameScene::addRevealedZoneView(Player *player, CardZone *zone, const QList &cardList) { - ZoneViewWidget *item = new ZoneViewWidget(player, zone, -2, cardList); + ZoneViewWidget *item = new ZoneViewWidget(player, zone, -2, true, cardList); views.append(item); connect(item, SIGNAL(closePressed(ZoneViewWidget *)), this, SLOT(removeZoneView(ZoneViewWidget *))); addItem(item); diff --git a/cockatrice/src/handcounter.h b/cockatrice/src/handcounter.h index 9e942a64..46de6889 100644 --- a/cockatrice/src/handcounter.h +++ b/cockatrice/src/handcounter.h @@ -7,7 +7,7 @@ class QPainter; class QPixmap; -class HandCounter : public QObject, public AbstractGraphicsItem { +class HandCounter : public AbstractGraphicsItem { Q_OBJECT private: int number; diff --git a/cockatrice/src/handzone.cpp b/cockatrice/src/handzone.cpp index 1b78eb8e..1246c969 100644 --- a/cockatrice/src/handzone.cpp +++ b/cockatrice/src/handzone.cpp @@ -66,6 +66,9 @@ void HandZone::reorganizeCards() const int xPadding = 5; qreal totalWidth = boundingRect().width() - 2 * xPadding; qreal cardWidth = cards.at(0)->boundingRect().width(); + + if (cardWidth * cardCount < totalWidth) + cardWidth += 5; for (int i = 0; i < cardCount; i++) { CardItem *c = cards.at(i); diff --git a/cockatrice/src/localclient.cpp b/cockatrice/src/localclient.cpp index b42b810c..87b215ba 100644 --- a/cockatrice/src/localclient.cpp +++ b/cockatrice/src/localclient.cpp @@ -7,6 +7,7 @@ LocalClient::LocalClient(LocalServerInterface *_lsi, const QString &_playerName, { connect(lsi, SIGNAL(itemToClient(ProtocolItem *)), this, SLOT(itemFromServer(ProtocolItem *))); sendCommand(new Command_Login(_playerName, QString())); + sendCommand(new Command_JoinRoom(0)); } LocalClient::~LocalClient() diff --git a/cockatrice/src/localserver.cpp b/cockatrice/src/localserver.cpp index 1af04676..da403f91 100644 --- a/cockatrice/src/localserver.cpp +++ b/cockatrice/src/localserver.cpp @@ -1,9 +1,11 @@ #include "localserver.h" #include "localserverinterface.h" +#include "server_room.h" LocalServer::LocalServer(QObject *parent) : Server(parent) { + addRoom(new Server_Room(0, QString(), QString(), false, QString(), this)); } LocalServer::~LocalServer() diff --git a/cockatrice/src/messagelogwidget.cpp b/cockatrice/src/messagelogwidget.cpp index 7e42c0b3..4ce4621d 100644 --- a/cockatrice/src/messagelogwidget.cpp +++ b/cockatrice/src/messagelogwidget.cpp @@ -181,7 +181,7 @@ void MessageLogWidget::logMoveCard(Player *player, QString cardName, CardZone *s { QString startName = startZone->getName(); QString targetName = targetZone->getName(); - if (((startName == "table") && (targetName == "table")) || ((startName == "hand") && (targetName == "hand"))) + if (((startName == "table") && (targetName == "table") && (startZone == targetZone)) || ((startName == "hand") && (targetName == "hand"))) return; QPair temp = getFromStr(startZone, cardName, oldX); bool cardNameContainsStartZone = false; @@ -190,6 +190,18 @@ void MessageLogWidget::logMoveCard(Player *player, QString cardName, CardZone *s cardName = temp.first; } QString fromStr = temp.second; + QString cardStr; + if (cardNameContainsStartZone) + cardStr = cardName; + else if (cardName.isEmpty()) + cardStr = tr("a card"); + else + cardStr = QString("%1").arg(sanitizeHtml(cardName)); + + if ((startName == "table") && (targetName == "table")) { + append(tr("%1 gives %2 control over %3.").arg(sanitizeHtml(player->getName())).arg(sanitizeHtml(targetZone->getPlayer()->getName())).arg(cardStr)); + return; + } QString finalStr; if (targetName == "table") @@ -214,14 +226,6 @@ void MessageLogWidget::logMoveCard(Player *player, QString cardName, CardZone *s else if (targetName == "stack") finalStr = tr("%1 plays %2%3."); - QString cardStr; - if (cardNameContainsStartZone) - cardStr = cardName; - else if (cardName.isEmpty()) - cardStr = tr("a card"); - else - cardStr = QString("%1").arg(sanitizeHtml(cardName)); - append(finalStr.arg(sanitizeHtml(player->getName())).arg(cardStr).arg(fromStr).arg(newX)); } diff --git a/cockatrice/src/player.cpp b/cockatrice/src/player.cpp index 49b1fe97..742ff67d 100644 --- a/cockatrice/src/player.cpp +++ b/cockatrice/src/player.cpp @@ -1,7 +1,7 @@ #include "player.h" #include "cardzone.h" #include "playertarget.h" -#include "counter.h" +#include "counter_general.h" #include "arrowitem.h" #include "zoneviewzone.h" #include "zoneviewwidget.h" @@ -32,26 +32,28 @@ Player::Player(ServerInfo_User *info, int _id, bool _local, TabGame *_parent) updateBgPixmap(); playerTarget = new PlayerTarget(this); - playerTarget->setPos(QPointF(counterAreaWidth + (CARD_HEIGHT + 5 - playerTarget->boundingRect().width()) / 2.0, 5)); + qreal avatarMargin = (counterAreaWidth + CARD_HEIGHT + 15 - playerTarget->boundingRect().width()) / 2.0; + playerTarget->setPos(QPointF(avatarMargin, avatarMargin)); PileZone *deck = new PileZone(this, "deck", true, false, this); - QPointF base = QPointF(counterAreaWidth + (CARD_HEIGHT - CARD_WIDTH + 5) / 2.0, 5 + playerTarget->boundingRect().height() + 5 - (CARD_HEIGHT - CARD_WIDTH) / 2.0); + QPointF base = QPointF(counterAreaWidth + (CARD_HEIGHT - CARD_WIDTH + 15) / 2.0, 10 + playerTarget->boundingRect().height() + 5 - (CARD_HEIGHT - CARD_WIDTH) / 2.0); deck->setPos(base); qreal h = deck->boundingRect().width() + 5; + HandCounter *handCounter = new HandCounter(this); + handCounter->setPos(base + QPointF(0, h + 10)); + qreal h2 = handCounter->boundingRect().height(); + PileZone *grave = new PileZone(this, "grave", false, true, this); - grave->setPos(base + QPointF(0, h)); + grave->setPos(base + QPointF(0, h + h2 + 10)); PileZone *rfg = new PileZone(this, "rfg", false, true, this); - rfg->setPos(base + QPointF(0, 2 * h)); + rfg->setPos(base + QPointF(0, 2 * h + h2 + 10)); PileZone *sb = new PileZone(this, "sb", false, false, this); sb->setVisible(false); - HandCounter *handCounter = new HandCounter(this); - handCounter->setPos(base + QPointF(0, 3 * h + 7)); - table = new TableZone(this, this); connect(table, SIGNAL(sizeChanged()), this, SLOT(updateBoundingRect())); @@ -312,7 +314,7 @@ void Player::playerListActionTriggered() void Player::rearrangeZones() { - QPointF base = QPointF(CARD_HEIGHT + counterAreaWidth + 5, 0); + QPointF base = QPointF(CARD_HEIGHT + counterAreaWidth + 15, 0); if (settingsCache->getHorizontalHand()) { if (mirrored) { @@ -370,7 +372,7 @@ void Player::updateBgPixmap() void Player::updateBoundingRect() { prepareGeometryChange(); - qreal width = CARD_HEIGHT + 5 + counterAreaWidth + stack->boundingRect().width(); + qreal width = CARD_HEIGHT + 15 + counterAreaWidth + stack->boundingRect().width(); if (settingsCache->getHorizontalHand()) { qreal handHeight = hand->isVisible() ? hand->boundingRect().height() : 0; bRect = QRectF(0, 0, width + table->boundingRect().width(), table->boundingRect().height() + handHeight); @@ -426,7 +428,7 @@ void Player::retranslateUi() aCreateAnotherToken->setText(tr("C&reate another token")); sayMenu->setTitle(tr("S&ay")); - QMapIterator counterIterator(counters); + QMapIterator counterIterator(counters); while (counterIterator.hasNext()) counterIterator.next().value()->retranslateUi(); @@ -457,7 +459,7 @@ void Player::setShortcutsActive() aCreateToken->setShortcut(tr("Ctrl+T")); aCreateAnotherToken->setShortcut(tr("Ctrl+G")); - QMapIterator counterIterator(counters); + QMapIterator counterIterator(counters); while (counterIterator.hasNext()) counterIterator.next().value()->setShortcutsActive(); } @@ -478,7 +480,7 @@ void Player::setShortcutsInactive() aCreateToken->setShortcut(QKeySequence()); aCreateAnotherToken->setShortcut(QKeySequence()); - QMapIterator counterIterator(counters); + QMapIterator counterIterator(counters); while (counterIterator.hasNext()) counterIterator.next().value()->setShortcutsInactive(); } @@ -752,7 +754,7 @@ void Player::eventCreateCounters(Event_CreateCounters *event) void Player::eventSetCounter(Event_SetCounter *event) { - Counter *c = counters.value(event->getCounterId(), 0); + AbstractCounter *c = counters.value(event->getCounterId(), 0); if (!c) return; int oldValue = c->getValue(); @@ -1011,7 +1013,7 @@ QRectF Player::boundingRect() const void Player::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) { - int totalWidth = CARD_HEIGHT + counterAreaWidth + 5; + int totalWidth = CARD_HEIGHT + counterAreaWidth + 15; if (bgPixmap.isNull()) painter->fillRect(QRectF(0, 0, totalWidth, boundingRect().height()), QColor(200, 200, 200)); else @@ -1111,14 +1113,22 @@ void Player::addZone(CardZone *z) zones.insert(z->getName(), z); } -Counter *Player::addCounter(ServerInfo_Counter *counter) +AbstractCounter *Player::addCounter(ServerInfo_Counter *counter) { return addCounter(counter->getId(), counter->getName(), counter->getColor().getQColor(), counter->getRadius(), counter->getCount()); } -Counter *Player::addCounter(int counterId, const QString &name, QColor color, int radius, int value) +AbstractCounter *Player::addCounter(int counterId, const QString &name, QColor color, int radius, int value) { - Counter *c = new Counter(this, counterId, name, color, radius, value, this); + qDebug() << "addCounter:" << getName() << counterId << name; + if (counters.contains(counterId)) + return 0; + + AbstractCounter *c; + if (name == "life") + c = playerTarget->addCounter(counterId, name, value); + else + c = new GeneralCounter(this, counterId, name, color, radius, value, this); counters.insert(counterId, c); if (countersMenu) countersMenu->addMenu(c->getMenu()); @@ -1130,9 +1140,11 @@ Counter *Player::addCounter(int counterId, const QString &name, QColor color, in void Player::delCounter(int counterId) { - Counter *c = counters.value(counterId, 0); + AbstractCounter *c = counters.value(counterId, 0); if (!c) return; + if (c->getName() == "life") + playerTarget->delCounter(); counters.remove(counterId); c->delCounter(); rearrangeCounters(); @@ -1140,10 +1152,11 @@ void Player::delCounter(int counterId) void Player::clearCounters() { - QMapIterator counterIterator(counters); + QMapIterator counterIterator(counters); while (counterIterator.hasNext()) counterIterator.next().value()->delCounter(); counters.clear(); + playerTarget->delCounter(); } ArrowItem *Player::addArrow(ServerInfo_Arrow *arrow) @@ -1204,15 +1217,16 @@ void Player::clearArrows() void Player::rearrangeCounters() { - qreal marginTop = 15; - qreal marginBottom = 15; + qreal marginTop = 80; + qreal marginBottom = 10; // Determine total height of bounding rectangles qreal totalHeight = 0; - QMapIterator counterIterator(counters); + QMapIterator counterIterator(counters); while (counterIterator.hasNext()) { counterIterator.next(); - totalHeight += counterIterator.value()->boundingRect().height(); + if (counterIterator.value()->getShownInCounterArea()) + totalHeight += counterIterator.value()->boundingRect().height(); } // Determine free space between objects @@ -1226,8 +1240,11 @@ void Player::rearrangeCounters() // Place objects for (counterIterator.toFront(); counterIterator.hasNext(); ) { - Counter *c = counterIterator.next().value(); + AbstractCounter *c = counterIterator.next().value(); + if (!c->getShownInCounterArea()) + continue; + QRectF br = c->boundingRect(); c->setPos((counterAreaWidth - br.width()) / 2, y); y += br.height() + padding; @@ -1282,7 +1299,7 @@ void Player::cardMenuAction(QAction *a) break; } case 4: - commandList.append(new Command_CreateToken(-1, card->getZone()->getName(), card->getName(), card->getColor(), card->getPT(), card->getAnnotation(), card->getDestroyOnZoneChange(), -1, card->getGridPoint().y())); + commandList.append(new Command_CreateToken(-1, card->getZone()->getName(), card->getName(), card->getColor(), card->getPT(), card->getAnnotation(), true, -1, card->getGridPoint().y())); break; case 5: commandList.append(new Command_MoveCard(-1, card->getZone()->getName(), card->getId(), getId(), "deck", 0, 0, false)); @@ -1431,7 +1448,7 @@ QString Player::getName() const qreal Player::getMinimumWidth() const { - qreal result = table->getMinimumWidth() + CARD_HEIGHT + 5 + counterAreaWidth + stack->boundingRect().width(); + qreal result = table->getMinimumWidth() + CARD_HEIGHT + 15 + counterAreaWidth + stack->boundingRect().width(); if (!settingsCache->getHorizontalHand()) result += hand->boundingRect().width(); return result; @@ -1450,7 +1467,7 @@ void Player::processSceneSizeChange(const QSizeF &newSize) // This will need to be changed if player areas are displayed side by side (e.g. 2x2 for a 4-player game) qreal fullPlayerWidth = newSize.width(); - qreal tableWidth = fullPlayerWidth - CARD_HEIGHT - 5 - counterAreaWidth - stack->boundingRect().width(); + qreal tableWidth = fullPlayerWidth - CARD_HEIGHT - 15 - counterAreaWidth - stack->boundingRect().width(); if (!settingsCache->getHorizontalHand()) tableWidth -= hand->boundingRect().width(); diff --git a/cockatrice/src/player.h b/cockatrice/src/player.h index 904bc549..49ccab69 100644 --- a/cockatrice/src/player.h +++ b/cockatrice/src/player.h @@ -11,7 +11,7 @@ class QMenu; class QAction; class ZoneViewZone; class TabGame; -class Counter; +class AbstractCounter; class ArrowItem; class CardZone; class StackZone; @@ -148,7 +148,7 @@ private: QPixmap bgPixmap; QRectF bRect; - QMap counters; + QMap counters; QMap arrows; void rearrangeCounters(); @@ -174,7 +174,7 @@ private: void eventDrawCards(Event_DrawCards *event); void eventRevealCards(Event_RevealCards *event); public: - static const int counterAreaWidth = 65; + static const int counterAreaWidth = 55; enum { Type = typeOther }; int type() const { return Type; } @@ -186,8 +186,8 @@ public: void deleteCard(CardItem *c); void addZone(CardZone *z); - Counter *addCounter(ServerInfo_Counter *counter); - Counter *addCounter(int counterId, const QString &name, QColor color, int radius, int value); + AbstractCounter *addCounter(ServerInfo_Counter *counter); + AbstractCounter *addCounter(int counterId, const QString &name, QColor color, int radius, int value); void delCounter(int counterId); void clearCounters(); diff --git a/cockatrice/src/playertarget.cpp b/cockatrice/src/playertarget.cpp index 1df53388..e4f5aa58 100644 --- a/cockatrice/src/playertarget.cpp +++ b/cockatrice/src/playertarget.cpp @@ -5,9 +5,49 @@ #include #include #include +#include + +PlayerCounter::PlayerCounter(Player *_player, int _id, const QString &_name, int _value, QGraphicsItem *parent) + : AbstractCounter(_player, _id, _name, false, _value, parent) +{ +} + +QRectF PlayerCounter::boundingRect() const +{ + return QRectF(0, 0, 50, 30); +} + +void PlayerCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) +{ + const int radius = 8; + const qreal border = 1; + QPainterPath path(QPointF(50 - border / 2, border / 2)); + path.lineTo(radius, border / 2); + path.arcTo(border / 2, border / 2, 2 * radius, 2 * radius, 90, 90); + path.lineTo(border / 2, 30 - border / 2); + path.lineTo(50 - border / 2, 30 - border / 2); + path.closeSubpath(); + + QPen pen(QColor(100, 100, 100)); + pen.setWidth(border); + painter->setPen(pen); + painter->setBrush(hovered ? QColor(50, 50, 50, 160) : QColor(0, 0, 0, 160)); + + painter->drawPath(path); + + QRectF translatedRect = painter->combinedTransform().mapRect(boundingRect()); + QSize translatedSize = translatedRect.size().toSize(); + painter->resetTransform(); + QFont font("Serif"); + font.setWeight(QFont::Bold); + font.setPixelSize(qMax((int) round(translatedSize.height() / 1.3), 9)); + painter->setFont(font); + painter->setPen(Qt::white); + painter->drawText(translatedRect, Qt::AlignCenter, QString::number(value)); +} PlayerTarget::PlayerTarget(Player *_owner) - : ArrowTarget(_owner, _owner) + : ArrowTarget(_owner, _owner), playerCounter(0) { setCacheMode(DeviceCoordinateCache); @@ -17,15 +57,17 @@ PlayerTarget::PlayerTarget(Player *_owner) QRectF PlayerTarget::boundingRect() const { - return QRectF(0, 0, 100, 64); + return QRectF(0, 0, 160, 64); } void PlayerTarget::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) { ServerInfo_User *info = owner->getUserInfo(); - painter->save(); - QRectF translatedRect = painter->combinedTransform().mapRect(boundingRect()); + const qreal border = 2; + + QRectF avatarBoundingRect = boundingRect().adjusted(border, border, -border, -border); + QRectF translatedRect = painter->combinedTransform().mapRect(avatarBoundingRect); QSize translatedSize = translatedRect.size().toSize(); QPixmap cachedPixmap; const QString cacheKey = "avatar" + QString::number(translatedSize.width()) + "_" + QString::number(info->getUserLevel()) + "_" + QString::number(fullPixmap.cacheKey()); @@ -34,16 +76,35 @@ void PlayerTarget::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*o #else if (!QPixmapCache::find(cacheKey, cachedPixmap)) { #endif + cachedPixmap = QPixmap(translatedSize.width(), translatedSize.height()); + + QPainter tempPainter(&cachedPixmap); + QRadialGradient grad(translatedRect.center(), sqrt(translatedSize.width() * translatedSize.width() + translatedSize.height() * translatedSize.height()) / 2); + grad.setColorAt(1, Qt::black); + grad.setColorAt(0, QColor(180, 180, 180)); + tempPainter.fillRect(QRectF(0, 0, translatedSize.width(), translatedSize.height()), grad); + + QPixmap tempPixmap; if (fullPixmap.isNull()) - cachedPixmap = UserLevelPixmapGenerator::generatePixmap(translatedSize.height(), info->getUserLevel()); + tempPixmap = UserLevelPixmapGenerator::generatePixmap(translatedSize.height(), info->getUserLevel()); else - cachedPixmap = fullPixmap.scaled(translatedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); + tempPixmap = fullPixmap.scaled(translatedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); + + tempPainter.drawPixmap((translatedSize.width() - tempPixmap.width()) / 2, (translatedSize.height() - tempPixmap.height()) / 2, tempPixmap); QPixmapCache::insert(cacheKey, cachedPixmap); } - painter->resetTransform(); + painter->save(); + painter->resetTransform(); painter->translate((translatedSize.width() - cachedPixmap.width()) / 2.0, 0); - painter->drawPixmap(cachedPixmap.rect(), cachedPixmap, cachedPixmap.rect()); + painter->drawPixmap(translatedRect, cachedPixmap, cachedPixmap.rect()); + painter->restore(); + + QRectF nameRect = QRectF(0, boundingRect().height() - 20, 110, 20); + painter->fillRect(nameRect, QColor(0, 0, 0, 160)); + QRectF translatedNameRect = painter->combinedTransform().mapRect(nameRect); + + painter->save(); painter->resetTransform(); QString name = info->getName(); @@ -51,14 +112,35 @@ void PlayerTarget::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*o name = name.mid(0, 10) + "..."; QFont font; - font.setPixelSize(qMax(translatedSize.height() / 4, 9)); + font.setPixelSize(qMax((int) round(translatedNameRect.height() / 1.5), 9)); painter->setFont(font); - painter->setBackgroundMode(Qt::OpaqueMode); - painter->setBackground(QColor(0, 0, 0, 100)); painter->setPen(Qt::white); - painter->drawText(translatedRect, Qt::AlignHCenter | Qt::AlignTop | Qt::TextWrapAnywhere, name); + painter->drawText(translatedNameRect, Qt::AlignVCenter | Qt::AlignLeft, " " + name); painter->restore(); + QPen pen(QColor(100, 100, 100)); + pen.setWidth(border); + pen.setJoinStyle(Qt::RoundJoin); + painter->setPen(pen); + painter->drawRect(boundingRect().adjusted(border / 2, border / 2, -border / 2, -border / 2)); + if (getBeingPointedAt()) painter->fillRect(boundingRect(), QBrush(QColor(255, 0, 0, 100))); } + +AbstractCounter *PlayerTarget::addCounter(int _counterId, const QString &_name, int _value) +{ + if (playerCounter) + return 0; + + playerCounter = new PlayerCounter(owner, _counterId, _name, _value, this); + playerCounter->setPos(boundingRect().width() - playerCounter->boundingRect().width(), boundingRect().height() - playerCounter->boundingRect().height()); + connect(playerCounter, SIGNAL(destroyed()), this, SLOT(delCounter())); + + return playerCounter; +} + +void PlayerTarget::delCounter() +{ + playerCounter = 0; +} \ No newline at end of file diff --git a/cockatrice/src/playertarget.h b/cockatrice/src/playertarget.h index 95dfd4b7..5957b517 100644 --- a/cockatrice/src/playertarget.h +++ b/cockatrice/src/playertarget.h @@ -2,14 +2,27 @@ #define PLAYERTARGET_H #include "arrowtarget.h" +#include "abstractcounter.h" #include #include class Player; +class PlayerCounter : public AbstractCounter { + Q_OBJECT +public: + PlayerCounter(Player *_player, int _id, const QString &_name, int _value, QGraphicsItem *parent = 0); + QRectF boundingRect() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); +}; + class PlayerTarget : public ArrowTarget { + Q_OBJECT private: QPixmap fullPixmap; + PlayerCounter *playerCounter; +public slots: + void delCounter(); public: enum { Type = typePlayerTarget }; int type() const { return Type; } @@ -17,6 +30,8 @@ public: PlayerTarget(Player *parent = 0); QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + + AbstractCounter *addCounter(int _counterId, const QString &_name, int _value); }; #endif \ No newline at end of file diff --git a/cockatrice/src/remoteclient.cpp b/cockatrice/src/remoteclient.cpp index 4e3f9724..dd7c12d9 100644 --- a/cockatrice/src/remoteclient.cpp +++ b/cockatrice/src/remoteclient.cpp @@ -42,12 +42,17 @@ void RemoteClient::slotConnected() setStatus(StatusAwaitingWelcome); } -void RemoteClient::loginResponse(ResponseCode response) +void RemoteClient::loginResponse(ProtocolResponse *response) { - if (response == RespOk) + Response_Login *resp = qobject_cast(response); + if (!resp) + disconnectFromServer(); + + if (resp->getResponseCode() == RespOk) { setStatus(StatusLoggedIn); - else { - emit serverError(response); + emit userInfoChanged(resp->getUserInfo()); + } else { + emit serverError(resp->getResponseCode()); setStatus(StatusDisconnecting); } } @@ -78,7 +83,7 @@ void RemoteClient::readData() setStatus(StatusLoggingIn); Command_Login *cmdLogin = new Command_Login(userName, password); - connect(cmdLogin, SIGNAL(finished(ResponseCode)), this, SLOT(loginResponse(ResponseCode))); + connect(cmdLogin, SIGNAL(finished(ProtocolResponse *)), this, SLOT(loginResponse(ProtocolResponse *))); sendCommand(cmdLogin); } } diff --git a/cockatrice/src/remoteclient.h b/cockatrice/src/remoteclient.h index 10d7c417..30313fbb 100644 --- a/cockatrice/src/remoteclient.h +++ b/cockatrice/src/remoteclient.h @@ -2,7 +2,6 @@ #define REMOTECLIENT_H #include -#include "protocol_datastructures.h" #include "abstractclient.h" class QTimer; @@ -22,7 +21,7 @@ private slots: void readData(); void slotSocketError(QAbstractSocket::SocketError error); void ping(); - void loginResponse(ResponseCode response); + void loginResponse(ProtocolResponse *response); private: static const int maxTimeout = 10; diff --git a/cockatrice/src/tab_chatchannel.cpp b/cockatrice/src/tab_chatchannel.cpp deleted file mode 100644 index 515844f1..00000000 --- a/cockatrice/src/tab_chatchannel.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "tab_chatchannel.h" -#include "abstractclient.h" -#include "protocol_items.h" - -TabChatChannel::TabChatChannel(AbstractClient *_client, const QString &_channelName) - : Tab(), client(_client), channelName(_channelName) -{ - playerList = new QListWidget; - playerList->setFixedWidth(150); - - textEdit = new QTextEdit; - textEdit->setReadOnly(true); - sayEdit = new QLineEdit; - connect(sayEdit, SIGNAL(returnPressed()), this, SLOT(sendMessage())); - - QVBoxLayout *vbox = new QVBoxLayout; - vbox->addWidget(textEdit); - vbox->addWidget(sayEdit); - - QHBoxLayout *hbox = new QHBoxLayout; - hbox->addLayout(vbox); - hbox->addWidget(playerList); - - aLeaveChannel = new QAction(this); - connect(aLeaveChannel, SIGNAL(triggered()), this, SLOT(actLeaveChannel())); - - tabMenu = new QMenu(this); - tabMenu->addAction(aLeaveChannel); - - retranslateUi(); - setLayout(hbox); -} - -TabChatChannel::~TabChatChannel() -{ - emit channelClosing(this); -} - -void TabChatChannel::retranslateUi() -{ - tabMenu->setTitle(tr("C&hat channel")); - aLeaveChannel->setText(tr("&Leave channel")); -} - -QString TabChatChannel::sanitizeHtml(QString dirty) const -{ - return dirty - .replace("&", "&") - .replace("<", "<") - .replace(">", ">"); -} - -void TabChatChannel::sendMessage() -{ - if (sayEdit->text().isEmpty()) - return; - - client->sendCommand(new Command_ChatSay(channelName, sayEdit->text())); - sayEdit->clear(); -} - -void TabChatChannel::actLeaveChannel() -{ - client->sendCommand(new Command_ChatLeaveChannel(channelName)); - deleteLater(); -} - -void TabChatChannel::processChatEvent(ChatEvent *event) -{ - switch (event->getItemId()) { - case ItemId_Event_ChatListPlayers: processListPlayersEvent(qobject_cast(event)); break; - case ItemId_Event_ChatJoinChannel: processJoinChannelEvent(qobject_cast(event)); break; - case ItemId_Event_ChatLeaveChannel: processLeaveChannelEvent(qobject_cast(event)); break; - case ItemId_Event_ChatSay: processSayEvent(qobject_cast(event)); break; - default: ; - } -} - -void TabChatChannel::processListPlayersEvent(Event_ChatListPlayers *event) -{ - const QList &players = event->getPlayerList(); - for (int i = 0; i < players.size(); ++i) - playerList->addItem(players[i]->getName()); -} - -void TabChatChannel::processJoinChannelEvent(Event_ChatJoinChannel *event) -{ - textEdit->append(tr("%1 has joined the channel.").arg(sanitizeHtml(event->getUserInfo()->getName()))); - playerList->addItem(event->getUserInfo()->getName()); - emit userEvent(); -} - -void TabChatChannel::processLeaveChannelEvent(Event_ChatLeaveChannel *event) -{ - textEdit->append(tr("%1 has left the channel.").arg(sanitizeHtml(event->getPlayerName()))); - for (int i = 0; i < playerList->count(); ++i) - if (playerList->item(i)->text() == event->getPlayerName()) { - delete playerList->takeItem(i); - break; - } - emit userEvent(); -} - -void TabChatChannel::processSayEvent(Event_ChatSay *event) -{ - if (event->getPlayerName().isEmpty()) - textEdit->append(QString("%1getMessage()))); - else - textEdit->append(QString("%1: %2").arg(sanitizeHtml(event->getPlayerName())).arg(sanitizeHtml(event->getMessage()))); - emit userEvent(); -} diff --git a/cockatrice/src/tab_chatchannel.h b/cockatrice/src/tab_chatchannel.h deleted file mode 100644 index 2c329199..00000000 --- a/cockatrice/src/tab_chatchannel.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef TAB_CHATCHANNEL_H -#define TAB_CHATCHANNEL_H - -#include "tab.h" - -class AbstractClient; -class QListWidget; -class QTextEdit; -class QLineEdit; -class ChatEvent; -class Event_ChatListPlayers; -class Event_ChatJoinChannel; -class Event_ChatLeaveChannel; -class Event_ChatSay; - -class TabChatChannel : public Tab { - Q_OBJECT -private: - AbstractClient *client; - QString channelName; - - QListWidget *playerList; - QTextEdit *textEdit; - QLineEdit *sayEdit; - - QAction *aLeaveChannel; - QString sanitizeHtml(QString dirty) const; -signals: - void channelClosing(TabChatChannel *tab); -private slots: - void sendMessage(); - void actLeaveChannel(); - - void processListPlayersEvent(Event_ChatListPlayers *event); - void processJoinChannelEvent(Event_ChatJoinChannel *event); - void processLeaveChannelEvent(Event_ChatLeaveChannel *event); - void processSayEvent(Event_ChatSay *event); -public: - TabChatChannel(AbstractClient *_client, const QString &_channelName); - ~TabChatChannel(); - void retranslateUi(); - void processChatEvent(ChatEvent *event); - QString getChannelName() const { return channelName; } - QString getTabText() const { return channelName; } -}; - -#endif diff --git a/cockatrice/src/tab_room.cpp b/cockatrice/src/tab_room.cpp new file mode 100644 index 00000000..18c9b123 --- /dev/null +++ b/cockatrice/src/tab_room.cpp @@ -0,0 +1,282 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dlg_creategame.h" +#include "tab_room.h" +#include "userlist.h" +#include "abstractclient.h" +#include "protocol_items.h" +#include "gamesmodel.h" + +#include + +GameSelector::GameSelector(AbstractClient *_client, int _roomId, QWidget *parent) + : QGroupBox(parent), client(_client), roomId(_roomId) +{ + gameListView = new QTreeView; + gameListModel = new GamesModel(this); + gameListProxyModel = new GamesProxyModel(this); + gameListProxyModel->setSourceModel(gameListModel); + gameListView->setModel(gameListProxyModel); + gameListView->header()->setResizeMode(0, QHeaderView::ResizeToContents); + + showFullGamesCheckBox = new QCheckBox; + createButton = new QPushButton; + joinButton = new QPushButton; + spectateButton = new QPushButton; + QHBoxLayout *buttonLayout = new QHBoxLayout; + buttonLayout->addWidget(showFullGamesCheckBox); + buttonLayout->addStretch(); + buttonLayout->addWidget(createButton); + buttonLayout->addWidget(joinButton); + buttonLayout->addWidget(spectateButton); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(gameListView); + mainLayout->addLayout(buttonLayout); + + retranslateUi(); + setLayout(mainLayout); + + setMinimumWidth(gameListView->columnWidth(0) * gameListModel->columnCount()); + setMinimumHeight(400); + + connect(showFullGamesCheckBox, SIGNAL(stateChanged(int)), this, SLOT(showFullGamesChanged(int))); + connect(createButton, SIGNAL(clicked()), this, SLOT(actCreate())); + connect(joinButton, SIGNAL(clicked()), this, SLOT(actJoin())); + connect(spectateButton, SIGNAL(clicked()), this, SLOT(actJoin())); +} + +void GameSelector::showFullGamesChanged(int state) +{ + gameListProxyModel->setFullGamesVisible(state); +} + +void GameSelector::actCreate() +{ + DlgCreateGame dlg(client, roomId, this); + dlg.exec(); +} + +void GameSelector::checkResponse(ResponseCode response) +{ + createButton->setEnabled(true); + joinButton->setEnabled(true); + spectateButton->setEnabled(true); + + switch (response) { + case RespWrongPassword: QMessageBox::critical(this, tr("Error"), tr("Wrong password.")); break; + case RespSpectatorsNotAllowed: QMessageBox::critical(this, tr("Error"), tr("Spectators are not allowed in this game.")); break; + case RespGameFull: QMessageBox::critical(this, tr("Error"), tr("The game is already full.")); break; + case RespNameNotFound: QMessageBox::critical(this, tr("Error"), tr("The game does not exist any more.")); break; + default: ; + } +} + +void GameSelector::actJoin() +{ + bool spectator = sender() == spectateButton; + + QModelIndex ind = gameListView->currentIndex(); + if (!ind.isValid()) + return; + ServerInfo_Game *game = gameListModel->getGame(ind.data(Qt::UserRole).toInt()); + QString password; + if (game->getHasPassword() && !(spectator && !game->getSpectatorsNeedPassword())) { + bool ok; + password = QInputDialog::getText(this, tr("Join game"), tr("Password:"), QLineEdit::Password, QString(), &ok); + if (!ok) + return; + } + + Command_JoinGame *commandJoinGame = new Command_JoinGame(roomId, game->getGameId(), password, spectator); + connect(commandJoinGame, SIGNAL(finished(ResponseCode)), this, SLOT(checkResponse(ResponseCode))); + client->sendCommand(commandJoinGame); + + createButton->setEnabled(false); + joinButton->setEnabled(false); + spectateButton->setEnabled(false); +} + +void GameSelector::retranslateUi() +{ + setTitle(tr("Games")); + showFullGamesCheckBox->setText(tr("Show &full games")); + createButton->setText(tr("C&reate")); + joinButton->setText(tr("&Join")); + spectateButton->setText(tr("J&oin as spectator")); +} + +void GameSelector::processGameInfo(ServerInfo_Game *info) +{ + gameListModel->updateGameList(info); +} + +ChatView::ChatView(const QString &_ownName, QWidget *parent) + : QTextEdit(parent), ownName(_ownName) +{ + setTextInteractionFlags(Qt::TextSelectableByMouse); + + QTextTableFormat format; + format.setBorderStyle(QTextFrameFormat::BorderStyle_None); + table = textCursor().insertTable(1, 3, format); +} + +void ChatView::appendMessage(const QString &sender, const QString &message) +{ + QTextCursor cellCursor = table->cellAt(table->rows() - 1, 0).lastCursorPosition(); + cellCursor.insertText(QDateTime::currentDateTime().toString("[hh:mm]")); + QTextTableCell senderCell = table->cellAt(table->rows() - 1, 1); + QTextCharFormat senderFormat; + if (sender == ownName) { + senderFormat.setFontWeight(QFont::Bold); + senderFormat.setForeground(Qt::red); + } else + senderFormat.setForeground(Qt::blue); + senderCell.setFormat(senderFormat); + cellCursor = senderCell.lastCursorPosition(); + cellCursor.insertText(sender); + QTextTableCell messageCell = table->cellAt(table->rows() - 1, 2); + QTextCharFormat messageFormat; + if (sender.isEmpty()) + messageFormat.setForeground(Qt::darkGreen); + messageCell.setFormat(messageFormat); + cellCursor = messageCell.lastCursorPosition(); + cellCursor.insertText(message); + + table->appendRows(1); + + verticalScrollBar()->setValue(verticalScrollBar()->maximum()); +} + +TabRoom::TabRoom(AbstractClient *_client, const QString &_ownName, ServerInfo_Room *info) + : Tab(), client(_client), roomId(info->getRoomId()), roomName(info->getName()), ownName(_ownName) +{ + gameSelector = new GameSelector(client, roomId); + userList = new UserList(false); + connect(userList, SIGNAL(openMessageDialog(const QString &, bool)), this, SIGNAL(openMessageDialog(const QString &, bool))); + + chatView = new ChatView(ownName); + sayLabel = new QLabel; + sayEdit = new QLineEdit; + sayLabel->setBuddy(sayEdit); + connect(sayEdit, SIGNAL(returnPressed()), this, SLOT(sendMessage())); + + QHBoxLayout *sayHbox = new QHBoxLayout; + sayHbox->addWidget(sayLabel); + sayHbox->addWidget(sayEdit); + + QVBoxLayout *chatVbox = new QVBoxLayout; + chatVbox->addWidget(chatView); + chatVbox->addLayout(sayHbox); + + chatGroupBox = new QGroupBox; + chatGroupBox->setLayout(chatVbox); + + QVBoxLayout *vbox = new QVBoxLayout; + vbox->addWidget(gameSelector); + vbox->addWidget(chatGroupBox); + + QHBoxLayout *hbox = new QHBoxLayout; + hbox->addLayout(vbox, 3); + hbox->addWidget(userList, 1); + + aLeaveRoom = new QAction(this); + connect(aLeaveRoom, SIGNAL(triggered()), this, SLOT(actLeaveRoom())); + + tabMenu = new QMenu(this); + tabMenu->addAction(aLeaveRoom); + + retranslateUi(); + setLayout(hbox); + + const QList users = info->getUserList(); + for (int i = 0; i < users.size(); ++i) + userList->processUserInfo(users[i]); + + const QList games = info->getGameList(); + for (int i = 0; i < games.size(); ++i) + gameSelector->processGameInfo(games[i]); +} + +TabRoom::~TabRoom() +{ + emit roomClosing(this); +} + +void TabRoom::retranslateUi() +{ + sayLabel->setText(tr("&Say:")); + chatGroupBox->setTitle(tr("Chat")); + tabMenu->setTitle(tr("&Room")); + aLeaveRoom->setText(tr("&Leave room")); +} + +QString TabRoom::sanitizeHtml(QString dirty) const +{ + return dirty + .replace("&", "&") + .replace("<", "<") + .replace(">", ">"); +} + +void TabRoom::sendMessage() +{ + if (sayEdit->text().isEmpty()) + return; + + client->sendCommand(new Command_RoomSay(roomId, sayEdit->text())); + sayEdit->clear(); +} + +void TabRoom::actLeaveRoom() +{ + client->sendCommand(new Command_LeaveRoom(roomId)); + deleteLater(); +} + +void TabRoom::processRoomEvent(RoomEvent *event) +{ + switch (event->getItemId()) { + case ItemId_Event_ListGames: processListGamesEvent(qobject_cast(event)); break; + case ItemId_Event_JoinRoom: processJoinRoomEvent(qobject_cast(event)); break; + case ItemId_Event_LeaveRoom: processLeaveRoomEvent(qobject_cast(event)); break; + case ItemId_Event_RoomSay: processSayEvent(qobject_cast(event)); break; + default: ; + } +} + +void TabRoom::processListGamesEvent(Event_ListGames *event) +{ + const QList &gameList = event->getGameList(); + for (int i = 0; i < gameList.size(); ++i) + gameSelector->processGameInfo(gameList[i]); +} + +void TabRoom::processJoinRoomEvent(Event_JoinRoom *event) +{ + chatView->appendMessage(QString(), tr("%1 has joined the room.").arg(event->getUserInfo()->getName())); + userList->processUserInfo(event->getUserInfo()); +} + +void TabRoom::processLeaveRoomEvent(Event_LeaveRoom *event) +{ + chatView->appendMessage(QString(), tr("%1 has left the room.").arg(event->getPlayerName())); + userList->deleteUser(event->getPlayerName()); +} + +void TabRoom::processSayEvent(Event_RoomSay *event) +{ + chatView->appendMessage(event->getPlayerName(), event->getMessage()); + emit userEvent(); +} diff --git a/cockatrice/src/tab_room.h b/cockatrice/src/tab_room.h new file mode 100644 index 00000000..fd4f8f5c --- /dev/null +++ b/cockatrice/src/tab_room.h @@ -0,0 +1,100 @@ +#ifndef TAB_ROOM_H +#define TAB_ROOM_H + +#include "tab.h" +#include "protocol_datastructures.h" +#include +#include + +class AbstractClient; +class UserList; +class QLabel; +class QTextEdit; +class QLineEdit; +class QTreeView; +class QPushButton; +class QTextTable; +class QCheckBox; +class GamesModel; +class GamesProxyModel; +class RoomEvent; +class ServerInfo_Room; +class ServerInfo_Game; +class Event_ListGames; +class Event_JoinRoom; +class Event_LeaveRoom; +class Event_RoomSay; + +class GameSelector : public QGroupBox { + Q_OBJECT +private slots: + void showFullGamesChanged(int state); + void actCreate(); + void actJoin(); + void checkResponse(ResponseCode response); +signals: + void gameJoined(int gameId); +private: + AbstractClient *client; + int roomId; + + QTreeView *gameListView; + GamesModel *gameListModel; + GamesProxyModel *gameListProxyModel; + QPushButton *createButton, *joinButton, *spectateButton; + QCheckBox *showFullGamesCheckBox; +public: + GameSelector(AbstractClient *_client, int _roomId, QWidget *parent = 0); + void retranslateUi(); + void processGameInfo(ServerInfo_Game *info); +}; + +class ChatView : public QTextEdit { + Q_OBJECT; +private: + QTextTable *table; + QString ownName; +public: + ChatView(const QString &_ownName, QWidget *parent = 0); + void appendMessage(const QString &sender, const QString &message); +}; + +class TabRoom : public Tab { + Q_OBJECT +private: + AbstractClient *client; + int roomId; + QString roomName; + QString ownName; + + GameSelector *gameSelector; + UserList *userList; + ChatView *chatView; + QLabel *sayLabel; + QLineEdit *sayEdit; + QGroupBox *chatGroupBox; + + QAction *aLeaveRoom; + QString sanitizeHtml(QString dirty) const; +signals: + void roomClosing(TabRoom *tab); + void openMessageDialog(const QString &userName, bool focus); +private slots: + void sendMessage(); + void actLeaveRoom(); + + void processListGamesEvent(Event_ListGames *event); + void processJoinRoomEvent(Event_JoinRoom *event); + void processLeaveRoomEvent(Event_LeaveRoom *event); + void processSayEvent(Event_RoomSay *event); +public: + TabRoom(AbstractClient *_client, const QString &_ownName, ServerInfo_Room *info); + ~TabRoom(); + void retranslateUi(); + void processRoomEvent(RoomEvent *event); + int getRoomId() const { return roomId; } + QString getChannelName() const { return roomName; } + QString getTabText() const { return roomName; } +}; + +#endif diff --git a/cockatrice/src/tab_server.cpp b/cockatrice/src/tab_server.cpp index d64c0a00..21b88e5b 100644 --- a/cockatrice/src/tab_server.cpp +++ b/cockatrice/src/tab_server.cpp @@ -10,126 +10,24 @@ #include #include #include "tab_server.h" -#include "gamesmodel.h" -#include "dlg_creategame.h" #include "abstractclient.h" #include "protocol.h" #include "protocol_items.h" +#include "userlist.h" #include "pixmapgenerator.h" #include -GameSelector::GameSelector(AbstractClient *_client, QWidget *parent) +RoomSelector::RoomSelector(AbstractClient *_client, QWidget *parent) : QGroupBox(parent), client(_client) { - gameListView = new QTreeView; - gameListModel = new GamesModel(this); - gameListProxyModel = new GamesProxyModel(this); - gameListProxyModel->setSourceModel(gameListModel); - gameListView->setModel(gameListProxyModel); - gameListView->header()->setResizeMode(0, QHeaderView::ResizeToContents); - - showFullGamesCheckBox = new QCheckBox; - createButton = new QPushButton; - joinButton = new QPushButton; - spectateButton = new QPushButton; - QHBoxLayout *buttonLayout = new QHBoxLayout; - buttonLayout->addWidget(showFullGamesCheckBox); - buttonLayout->addStretch(); - buttonLayout->addWidget(createButton); - buttonLayout->addWidget(joinButton); - buttonLayout->addWidget(spectateButton); - - QVBoxLayout *mainLayout = new QVBoxLayout; - mainLayout->addWidget(gameListView); - mainLayout->addLayout(buttonLayout); - - retranslateUi(); - setLayout(mainLayout); - - setMinimumWidth(gameListView->columnWidth(0) * gameListModel->columnCount()); - setMinimumHeight(400); - - connect(showFullGamesCheckBox, SIGNAL(stateChanged(int)), this, SLOT(showFullGamesChanged(int))); - connect(createButton, SIGNAL(clicked()), this, SLOT(actCreate())); - connect(joinButton, SIGNAL(clicked()), this, SLOT(actJoin())); - connect(spectateButton, SIGNAL(clicked()), this, SLOT(actJoin())); - - connect(client, SIGNAL(listGamesEventReceived(Event_ListGames *)), this, SLOT(processListGamesEvent(Event_ListGames *))); - client->sendCommand(new Command_ListGames); -} - -void GameSelector::showFullGamesChanged(int state) -{ - gameListProxyModel->setFullGamesVisible(state); -} - -void GameSelector::actCreate() -{ - DlgCreateGame dlg(client, this); - dlg.exec(); -} - -void GameSelector::checkResponse(ResponseCode response) -{ - createButton->setEnabled(true); - joinButton->setEnabled(true); - spectateButton->setEnabled(true); - - switch (response) { - case RespWrongPassword: QMessageBox::critical(this, tr("Error"), tr("Wrong password.")); break; - case RespSpectatorsNotAllowed: QMessageBox::critical(this, tr("Error"), tr("Spectators are not allowed in this game.")); break; - case RespGameFull: QMessageBox::critical(this, tr("Error"), tr("The game is already full.")); break; - case RespNameNotFound: QMessageBox::critical(this, tr("Error"), tr("The game does not exist any more.")); break; - default: ; - } -} - -void GameSelector::actJoin() -{ - bool spectator = sender() == spectateButton; - - QModelIndex ind = gameListView->currentIndex(); - if (!ind.isValid()) - return; - ServerInfo_Game *game = gameListModel->getGame(ind.data(Qt::UserRole).toInt()); - QString password; - if (game->getHasPassword() && !(spectator && !game->getSpectatorsNeedPassword())) { - bool ok; - password = QInputDialog::getText(this, tr("Join game"), tr("Password:"), QLineEdit::Password, QString(), &ok); - if (!ok) - return; - } - - Command_JoinGame *commandJoinGame = new Command_JoinGame(game->getGameId(), password, spectator); - connect(commandJoinGame, SIGNAL(finished(ResponseCode)), this, SLOT(checkResponse(ResponseCode))); - client->sendCommand(commandJoinGame); - - createButton->setEnabled(false); - joinButton->setEnabled(false); - spectateButton->setEnabled(false); -} - -void GameSelector::retranslateUi() -{ - setTitle(tr("Games")); - showFullGamesCheckBox->setText(tr("&Show full games")); - createButton->setText(tr("C&reate")); - joinButton->setText(tr("&Join")); - spectateButton->setText(tr("J&oin as spectator")); -} - -void GameSelector::processListGamesEvent(Event_ListGames *event) -{ - const QList &gamesToUpdate = event->getGameList(); - for (int i = 0; i < gamesToUpdate.size(); ++i) - gameListModel->updateGameList(gamesToUpdate[i]); -} - -ChatChannelSelector::ChatChannelSelector(AbstractClient *_client, QWidget *parent) - : QGroupBox(parent), client(_client) -{ - channelList = new QTreeWidget; - channelList->setRootIsDecorated(false); + roomList = new QTreeWidget; + roomList->setRootIsDecorated(false); + roomList->setColumnCount(4); + roomList->header()->setStretchLastSection(false); + roomList->header()->setResizeMode(0, QHeaderView::ResizeToContents); + roomList->header()->setResizeMode(1, QHeaderView::Stretch); + roomList->header()->setResizeMode(2, QHeaderView::ResizeToContents); + roomList->header()->setResizeMode(3, QHeaderView::ResizeToContents); joinButton = new QPushButton; connect(joinButton, SIGNAL(clicked()), this, SLOT(joinClicked())); @@ -137,209 +35,89 @@ ChatChannelSelector::ChatChannelSelector(AbstractClient *_client, QWidget *paren buttonLayout->addStretch(); buttonLayout->addWidget(joinButton); QVBoxLayout *vbox = new QVBoxLayout; - vbox->addWidget(channelList); + vbox->addWidget(roomList); vbox->addLayout(buttonLayout); retranslateUi(); setLayout(vbox); - connect(client, SIGNAL(listChatChannelsEventReceived(Event_ListChatChannels *)), this, SLOT(processListChatChannelsEvent(Event_ListChatChannels *))); - client->sendCommand(new Command_ListChatChannels); + connect(client, SIGNAL(listRoomsEventReceived(Event_ListRooms *)), this, SLOT(processListRoomsEvent(Event_ListRooms *))); + client->sendCommand(new Command_ListRooms); } -void ChatChannelSelector::retranslateUi() +void RoomSelector::retranslateUi() { - setTitle(tr("Chat channels")); + setTitle(tr("Rooms")); joinButton->setText(tr("Joi&n")); - QTreeWidgetItem *header = channelList->headerItem(); - header->setText(0, tr("Channel")); + QTreeWidgetItem *header = roomList->headerItem(); + header->setText(0, tr("Room")); header->setText(1, tr("Description")); header->setText(2, tr("Players")); + header->setText(3, tr("Games")); header->setTextAlignment(2, Qt::AlignRight); + header->setTextAlignment(3, Qt::AlignRight); } -void ChatChannelSelector::processListChatChannelsEvent(Event_ListChatChannels *event) +void RoomSelector::processListRoomsEvent(Event_ListRooms *event) { - const QList &channelsToUpdate = event->getChannelList(); - for (int i = 0; i < channelsToUpdate.size(); ++i) { - ServerInfo_ChatChannel *channel = channelsToUpdate[i]; + const QList &roomsToUpdate = event->getRoomList(); + for (int i = 0; i < roomsToUpdate.size(); ++i) { + ServerInfo_Room *room = roomsToUpdate[i]; - for (int j = 0; j < channelList->topLevelItemCount(); ++j) { - QTreeWidgetItem *twi = channelList->topLevelItem(j); - if (twi->text(0) == channel->getName()) { - twi->setText(1, channel->getDescription()); - twi->setText(2, QString::number(channel->getPlayerCount())); + for (int j = 0; j < roomList->topLevelItemCount(); ++j) { + QTreeWidgetItem *twi = roomList->topLevelItem(j); + if (twi->data(0, Qt::UserRole).toInt() == room->getRoomId()) { + twi->setData(0, Qt::DisplayRole, room->getName()); + twi->setData(1, Qt::DisplayRole, room->getDescription()); + twi->setData(2, Qt::DisplayRole, room->getPlayerCount()); + twi->setData(3, Qt::DisplayRole, room->getGameCount()); return; } } - QTreeWidgetItem *twi = new QTreeWidgetItem(QStringList() << channel->getName() << channel->getDescription() << QString::number(channel->getPlayerCount())); + QTreeWidgetItem *twi = new QTreeWidgetItem; + twi->setData(0, Qt::UserRole, room->getRoomId()); + twi->setData(0, Qt::DisplayRole, room->getName()); + twi->setData(1, Qt::DisplayRole, room->getDescription()); + twi->setData(2, Qt::DisplayRole, room->getPlayerCount()); + twi->setData(3, Qt::DisplayRole, room->getGameCount()); twi->setTextAlignment(2, Qt::AlignRight); - channelList->addTopLevelItem(twi); - channelList->resizeColumnToContents(0); - channelList->resizeColumnToContents(1); - channelList->resizeColumnToContents(2); - if (channel->getAutoJoin()) - joinChannel(channel->getName()); + twi->setTextAlignment(3, Qt::AlignRight); + roomList->addTopLevelItem(twi); + if (room->getAutoJoin()) + joinRoom(room->getRoomId(), false); } } -void ChatChannelSelector::joinChannel(const QString &channelName) +void RoomSelector::joinRoom(int id, bool setCurrent) { - Command_ChatJoinChannel *command = new Command_ChatJoinChannel(channelName); - connect(command, SIGNAL(finished(ResponseCode)), this, SLOT(joinFinished(ResponseCode))); + Command_JoinRoom *command = new Command_JoinRoom(id); + command->setExtraData(setCurrent); + connect(command, SIGNAL(finished(ProtocolResponse *)), this, SLOT(joinFinished(ProtocolResponse *))); client->sendCommand(command); } -void ChatChannelSelector::joinClicked() +void RoomSelector::joinClicked() { - QTreeWidgetItem *twi = channelList->currentItem(); + QTreeWidgetItem *twi = roomList->currentItem(); if (!twi) return; - QString channelName = twi->text(0); - joinChannel(channelName); + joinRoom(twi->data(0, Qt::UserRole).toInt(), true); } -void ChatChannelSelector::joinFinished(ResponseCode resp) +void RoomSelector::joinFinished(ProtocolResponse *r) { - if (resp != RespOk) + if (r->getResponseCode() != RespOk) return; - - Command_ChatJoinChannel *command = qobject_cast(sender()); - QString channelName = command->getChannel(); - - emit channelJoined(channelName); -} - -ServerMessageLog::ServerMessageLog(AbstractClient *_client, QWidget *parent) - : QGroupBox(parent) -{ - textEdit = new QTextEdit; - textEdit->setReadOnly(true); - - QVBoxLayout *vbox = new QVBoxLayout; - vbox->addWidget(textEdit); - - setLayout(vbox); - retranslateUi(); - - connect(_client, SIGNAL(serverMessageEventReceived(Event_ServerMessage *)), this, SLOT(processServerMessageEvent(Event_ServerMessage *))); -} - -void ServerMessageLog::retranslateUi() -{ - setTitle(tr("Server messages")); -} - -void ServerMessageLog::processServerMessageEvent(Event_ServerMessage *event) -{ - textEdit->append(event->getMessage()); -} - -UserListTWI::UserListTWI() - : QTreeWidgetItem(Type) -{ -} - -bool UserListTWI::operator<(const QTreeWidgetItem &other) const -{ - // Equal user level => sort by name - if (data(0, Qt::UserRole) == other.data(0, Qt::UserRole)) - return data(2, Qt::UserRole).toString().toLower() < other.data(2, Qt::UserRole).toString().toLower(); - // Else sort by user level - return data(0, Qt::UserRole).toInt() > other.data(0, Qt::UserRole).toInt(); -} - -UserList::UserList(AbstractClient *_client, QWidget *parent) - : QGroupBox(parent) -{ - userTree = new QTreeWidget; - userTree->setColumnCount(3); - userTree->header()->setResizeMode(QHeaderView::ResizeToContents); - userTree->setHeaderHidden(true); - userTree->setRootIsDecorated(false); - userTree->setIconSize(QSize(20, 12)); - connect(userTree, SIGNAL(itemActivated(QTreeWidgetItem *, int)), this, SLOT(userClicked(QTreeWidgetItem *, int))); - - QVBoxLayout *vbox = new QVBoxLayout; - vbox->addWidget(userTree); - - setLayout(vbox); - - retranslateUi(); - - connect(_client, SIGNAL(userJoinedEventReceived(Event_UserJoined *)), this, SLOT(processUserJoinedEvent(Event_UserJoined *))); - connect(_client, SIGNAL(userLeftEventReceived(Event_UserLeft *)), this, SLOT(processUserLeftEvent(Event_UserLeft *))); - - Command_ListUsers *cmd = new Command_ListUsers; - connect(cmd, SIGNAL(finished(ProtocolResponse *)), this, SLOT(processResponse(ProtocolResponse *))); - _client->sendCommand(cmd); -} - -void UserList::retranslateUi() -{ - setTitle(tr("Users online: %1").arg(userTree->topLevelItemCount())); -} - -void UserList::processUserInfo(ServerInfo_User *user) -{ - QTreeWidgetItem *item = 0; - for (int i = 0; i < userTree->topLevelItemCount(); ++i) { - QTreeWidgetItem *temp = userTree->topLevelItem(i); - if (temp->data(2, Qt::UserRole) == user->getName()) { - item = temp; - break; - } - } - if (!item) { - item = new UserListTWI; - userTree->addTopLevelItem(item); - retranslateUi(); - } - item->setData(0, Qt::UserRole, user->getUserLevel()); - item->setIcon(0, QIcon(UserLevelPixmapGenerator::generatePixmap(12, user->getUserLevel()))); - item->setIcon(1, QIcon(CountryPixmapGenerator::generatePixmap(12, user->getCountry()))); - item->setData(2, Qt::UserRole, user->getName()); - item->setData(2, Qt::DisplayRole, user->getName()); -} - -void UserList::processResponse(ProtocolResponse *response) -{ - Response_ListUsers *resp = qobject_cast(response); + Response_JoinRoom *resp = qobject_cast(r); if (!resp) return; - const QList &respList = resp->getUserList(); - for (int i = 0; i < respList.size(); ++i) - processUserInfo(respList[i]); - - userTree->sortItems(1, Qt::AscendingOrder); + emit roomJoined(resp->getRoomInfo(), static_cast(sender())->getExtraData().toBool()); } -void UserList::processUserJoinedEvent(Event_UserJoined *event) -{ - processUserInfo(event->getUserInfo()); - userTree->sortItems(1, Qt::AscendingOrder); -} - -void UserList::processUserLeftEvent(Event_UserLeft *event) -{ - for (int i = 0; i < userTree->topLevelItemCount(); ++i) - if (userTree->topLevelItem(i)->data(2, Qt::UserRole) == event->getUserName()) { - emit userLeft(event->getUserName()); - delete userTree->takeTopLevelItem(i); - retranslateUi(); - break; - } -} - -void UserList::userClicked(QTreeWidgetItem *item, int /*column*/) -{ - emit openMessageDialog(item->data(2, Qt::UserRole).toString(), true); -} - -UserInfoBox::UserInfoBox(AbstractClient *_client, QWidget *parent) +UserInfoBox::UserInfoBox(ServerInfo_User *userInfo, QWidget *parent) : QWidget(parent) { avatarLabel = new QLabel; @@ -367,9 +145,7 @@ UserInfoBox::UserInfoBox(AbstractClient *_client, QWidget *parent) setLayout(mainLayout); - Command_GetUserInfo *cmd = new Command_GetUserInfo; - connect(cmd, SIGNAL(finished(ProtocolResponse *)), this, SLOT(processResponse(ProtocolResponse *))); - _client->sendCommand(cmd); + updateInfo(userInfo); } void UserInfoBox::retranslateUi() @@ -378,12 +154,8 @@ void UserInfoBox::retranslateUi() userLevelLabel1->setText(tr("User level:")); } -void UserInfoBox::processResponse(ProtocolResponse *response) +void UserInfoBox::updateInfo(ServerInfo_User *user) { - Response_GetUserInfo *resp = qobject_cast(response); - if (!resp) - return; - ServerInfo_User *user = resp->getUserInfo(); int userLevel = user->getUserLevel(); QPixmap avatarPixmap; @@ -406,27 +178,28 @@ void UserInfoBox::processResponse(ProtocolResponse *response) userLevelLabel3->setText(userLevelText); } -TabServer::TabServer(AbstractClient *_client, QWidget *parent) +TabServer::TabServer(AbstractClient *_client, ServerInfo_User *userInfo, QWidget *parent) : Tab(parent), client(_client) { - gameSelector = new GameSelector(client); - chatChannelSelector = new ChatChannelSelector(client); - serverMessageLog = new ServerMessageLog(client); - userInfoBox = new UserInfoBox(client); - userList = new UserList(client); + roomSelector = new RoomSelector(client); + serverInfoBox = new QTextBrowser; + userInfoBox = new UserInfoBox(userInfo); + userList = new UserList(true); - connect(gameSelector, SIGNAL(gameJoined(int)), this, SIGNAL(gameJoined(int))); - connect(chatChannelSelector, SIGNAL(channelJoined(const QString &)), this, SIGNAL(chatChannelJoined(const QString &))); + connect(roomSelector, SIGNAL(roomJoined(ServerInfo_Room *, bool)), this, SIGNAL(roomJoined(ServerInfo_Room *, bool))); connect(userList, SIGNAL(openMessageDialog(const QString &, bool)), this, SIGNAL(openMessageDialog(const QString &, bool))); - connect(userList, SIGNAL(userLeft(const QString &)), this, SIGNAL(userLeft(const QString &))); - QHBoxLayout *hbox = new QHBoxLayout; - hbox->addWidget(chatChannelSelector); - hbox->addWidget(serverMessageLog); + connect(client, SIGNAL(userJoinedEventReceived(Event_UserJoined *)), this, SLOT(processUserJoinedEvent(Event_UserJoined *))); + connect(client, SIGNAL(userLeftEventReceived(Event_UserLeft *)), this, SLOT(processUserLeftEvent(Event_UserLeft *))); + connect(client, SIGNAL(serverMessageEventReceived(Event_ServerMessage *)), this, SLOT(processServerMessageEvent(Event_ServerMessage *))); + + Command_ListUsers *cmd = new Command_ListUsers; + connect(cmd, SIGNAL(finished(ProtocolResponse *)), this, SLOT(processListUsersResponse(ProtocolResponse *))); + client->sendCommand(cmd); QVBoxLayout *vbox = new QVBoxLayout; - vbox->addWidget(gameSelector); - vbox->addLayout(hbox); + vbox->addWidget(roomSelector); + vbox->addWidget(serverInfoBox); QVBoxLayout *vbox2 = new QVBoxLayout; vbox2->addWidget(userInfoBox); @@ -441,9 +214,37 @@ TabServer::TabServer(AbstractClient *_client, QWidget *parent) void TabServer::retranslateUi() { - gameSelector->retranslateUi(); - chatChannelSelector->retranslateUi(); - serverMessageLog->retranslateUi(); + roomSelector->retranslateUi(); userInfoBox->retranslateUi(); userList->retranslateUi(); } + +void TabServer::processServerMessageEvent(Event_ServerMessage *event) +{ + serverInfoBox->setHtml(event->getMessage()); +} + +void TabServer::processListUsersResponse(ProtocolResponse *response) +{ + Response_ListUsers *resp = qobject_cast(response); + if (!resp) + return; + + const QList &respList = resp->getUserList(); + for (int i = 0; i < respList.size(); ++i) + userList->processUserInfo(respList[i]); + + userList->sortItems(); +} + +void TabServer::processUserJoinedEvent(Event_UserJoined *event) +{ + userList->processUserInfo(event->getUserInfo()); + userList->sortItems(); +} + +void TabServer::processUserLeftEvent(Event_UserLeft *event) +{ + if (userList->deleteUser(event->getUserName())) + emit userLeft(event->getUserName()); +} \ No newline at end of file diff --git a/cockatrice/src/tab_server.h b/cockatrice/src/tab_server.h index 642c1456..de5e384e 100644 --- a/cockatrice/src/tab_server.h +++ b/cockatrice/src/tab_server.h @@ -3,102 +3,39 @@ #include #include +#include #include "tab.h" -#include "protocol_datastructures.h" class AbstractClient; -class QTreeView; -class QTreeWidget; -class QTreeWidgetItem; -class QPushButton; -class QCheckBox; class QTextEdit; class QLabel; +class UserList; +class QPushButton; -class GamesModel; -class GamesProxyModel; - -class Event_ListGames; -class Event_ListChatChannels; +class Event_ListRooms; class Event_ServerMessage; class Event_UserJoined; class Event_UserLeft; class ProtocolResponse; +class ServerInfo_User; +class ServerInfo_Room; -class GameSelector : public QGroupBox { - Q_OBJECT -public: - GameSelector(AbstractClient *_client, QWidget *parent = 0); - void retranslateUi(); -private slots: - void processListGamesEvent(Event_ListGames *event); - void showFullGamesChanged(int state); - void actCreate(); - void actJoin(); - void checkResponse(ResponseCode response); -signals: - void gameJoined(int gameId); -private: - AbstractClient *client; - - QTreeView *gameListView; - GamesModel *gameListModel; - GamesProxyModel *gameListProxyModel; - QPushButton *createButton, *joinButton, *spectateButton; - QCheckBox *showFullGamesCheckBox; -}; - -class ChatChannelSelector : public QGroupBox { +class RoomSelector : public QGroupBox { Q_OBJECT private: - QTreeWidget *channelList; + QTreeWidget *roomList; QPushButton *joinButton; AbstractClient *client; - void joinChannel(const QString &channelName); + void joinRoom(int id, bool setCurrent); private slots: - void processListChatChannelsEvent(Event_ListChatChannels *event); + void processListRoomsEvent(Event_ListRooms *event); void joinClicked(); - void joinFinished(ResponseCode resp); + void joinFinished(ProtocolResponse *resp); signals: - void channelJoined(const QString &channelName); + void roomJoined(ServerInfo_Room *info, bool setCurrent); public: - ChatChannelSelector(AbstractClient *_client, QWidget *parent = 0); - void retranslateUi(); -}; - -class ServerMessageLog : public QGroupBox { - Q_OBJECT -private: - QTextEdit *textEdit; -private slots: - void processServerMessageEvent(Event_ServerMessage *event); -public: - ServerMessageLog(AbstractClient *_client, QWidget *parent = 0); - void retranslateUi(); -}; - -class UserListTWI : public QTreeWidgetItem { -public: - UserListTWI(); - bool operator<(const QTreeWidgetItem &other) const; -}; - -class UserList : public QGroupBox { - Q_OBJECT -private: - QTreeWidget *userTree; - void processUserInfo(ServerInfo_User *user); -private slots: - void processResponse(ProtocolResponse *response); - void processUserJoinedEvent(Event_UserJoined *event); - void processUserLeftEvent(Event_UserLeft *event); - void userClicked(QTreeWidgetItem *item, int column); -signals: - void openMessageDialog(const QString &userName, bool focus); - void userLeft(const QString &userName); -public: - UserList(AbstractClient *_client, QWidget *parent = 0); + RoomSelector(AbstractClient *_client, QWidget *parent = 0); void retranslateUi(); }; @@ -106,29 +43,31 @@ class UserInfoBox : public QWidget { Q_OBJECT private: QLabel *avatarLabel, *nameLabel, *countryLabel1, *countryLabel2, *userLevelLabel1, *userLevelLabel2, *userLevelLabel3; -private slots: - void processResponse(ProtocolResponse *response); + void updateInfo(ServerInfo_User *user); public: - UserInfoBox(AbstractClient *_client, QWidget *parent = 0); + UserInfoBox(ServerInfo_User *userInfo, QWidget *parent = 0); void retranslateUi(); }; class TabServer : public Tab { Q_OBJECT signals: - void chatChannelJoined(const QString &channelName); - void gameJoined(int gameId); + void roomJoined(ServerInfo_Room *info, bool setCurrent); void openMessageDialog(const QString &userName, bool focus); void userLeft(const QString &userName); +private slots: + void processListUsersResponse(ProtocolResponse *response); + void processUserJoinedEvent(Event_UserJoined *event); + void processUserLeftEvent(Event_UserLeft *event); + void processServerMessageEvent(Event_ServerMessage *event); private: AbstractClient *client; - GameSelector *gameSelector; - ChatChannelSelector *chatChannelSelector; - ServerMessageLog *serverMessageLog; + RoomSelector *roomSelector; + QTextBrowser *serverInfoBox; UserList *userList; UserInfoBox *userInfoBox; public: - TabServer(AbstractClient *_client, QWidget *parent = 0); + TabServer(AbstractClient *_client, ServerInfo_User *userInfo, QWidget *parent = 0); void retranslateUi(); QString getTabText() const { return tr("Server"); } }; diff --git a/cockatrice/src/tab_supervisor.cpp b/cockatrice/src/tab_supervisor.cpp index b5075470..148409ee 100644 --- a/cockatrice/src/tab_supervisor.cpp +++ b/cockatrice/src/tab_supervisor.cpp @@ -2,7 +2,7 @@ #include "tab_supervisor.h" #include "abstractclient.h" #include "tab_server.h" -#include "tab_chatchannel.h" +#include "tab_room.h" #include "tab_game.h" #include "tab_deck_storage.h" #include "tab_message.h" @@ -32,9 +32,9 @@ void TabSupervisor::retranslateUi() tabs.append(tabServer); if (tabDeckStorage) tabs.append(tabDeckStorage); - QMapIterator chatChannelIterator(chatChannelTabs); - while (chatChannelIterator.hasNext()) - tabs.append(chatChannelIterator.next().value()); + QMapIterator roomIterator(roomTabs); + while (roomIterator.hasNext()) + tabs.append(roomIterator.next().value()); QMapIterator gameIterator(gameTabs); while (gameIterator.hasNext()) tabs.append(gameIterator.next().value()); @@ -51,17 +51,19 @@ void TabSupervisor::myAddTab(Tab *tab) addTab(tab, tab->getTabText()); } -void TabSupervisor::start(AbstractClient *_client) +void TabSupervisor::start(AbstractClient *_client, ServerInfo_User *userInfo) { client = _client; - connect(client, SIGNAL(chatEventReceived(ChatEvent *)), this, SLOT(processChatEvent(ChatEvent *))); + userName = userInfo->getName(); + + connect(client, SIGNAL(roomEventReceived(RoomEvent *)), this, SLOT(processRoomEvent(RoomEvent *))); connect(client, SIGNAL(gameEventContainerReceived(GameEventContainer *)), this, SLOT(processGameEventContainer(GameEventContainer *))); connect(client, SIGNAL(gameJoinedEventReceived(Event_GameJoined *)), this, SLOT(gameJoined(Event_GameJoined *))); connect(client, SIGNAL(messageEventReceived(Event_Message *)), this, SLOT(processMessageEvent(Event_Message *))); connect(client, SIGNAL(maxPingTime(int, int)), this, SLOT(updatePingTime(int, int))); - tabServer = new TabServer(client); - connect(tabServer, SIGNAL(chatChannelJoined(const QString &)), this, SLOT(addChatChannelTab(const QString &))); + tabServer = new TabServer(client, userInfo); + connect(tabServer, SIGNAL(roomJoined(ServerInfo_Room *, bool)), this, SLOT(addRoomTab(ServerInfo_Room *, bool))); connect(tabServer, SIGNAL(openMessageDialog(const QString &, bool)), this, SLOT(addMessageTab(const QString &, bool))); connect(tabServer, SIGNAL(userLeft(const QString &)), this, SLOT(processUserLeft(const QString &))); myAddTab(tabServer); @@ -107,10 +109,10 @@ void TabSupervisor::stop() tabDeckStorage->deleteLater(); tabDeckStorage = 0; - QMapIterator chatChannelIterator(chatChannelTabs); - while (chatChannelIterator.hasNext()) - chatChannelIterator.next().value()->deleteLater(); - chatChannelTabs.clear(); + QMapIterator roomIterator(roomTabs); + while (roomIterator.hasNext()) + roomIterator.next().value()->deleteLater(); + roomTabs.clear(); QMapIterator gameIterator(gameTabs); while (gameIterator.hasNext()) @@ -144,7 +146,7 @@ void TabSupervisor::localGameJoined(Event_GameJoined *event) setCurrentWidget(tab); for (int i = 1; i < localClients.size(); ++i) { - Command_JoinGame *cmd = new Command_JoinGame(event->getGameId()); + Command_JoinGame *cmd = new Command_JoinGame(0, event->getGameId()); localClients[i]->sendCommand(cmd); } } @@ -160,29 +162,33 @@ void TabSupervisor::gameLeft(TabGame *tab) stop(); } -void TabSupervisor::addChatChannelTab(const QString &channelName) +void TabSupervisor::addRoomTab(ServerInfo_Room *info, bool setCurrent) { - TabChatChannel *tab = new TabChatChannel(client, channelName); - connect(tab, SIGNAL(channelClosing(TabChatChannel *)), this, SLOT(chatChannelLeft(TabChatChannel *))); + TabRoom *tab = new TabRoom(client, userName, info); + connect(tab, SIGNAL(roomClosing(TabRoom *)), this, SLOT(roomLeft(TabRoom *))); myAddTab(tab); - chatChannelTabs.insert(channelName, tab); - setCurrentWidget(tab); + roomTabs.insert(info->getRoomId(), tab); + if (setCurrent) + setCurrentWidget(tab); } -void TabSupervisor::chatChannelLeft(TabChatChannel *tab) +void TabSupervisor::roomLeft(TabRoom *tab) { emit setMenu(0); - chatChannelTabs.remove(tab->getChannelName()); + roomTabs.remove(tab->getRoomId()); removeTab(indexOf(tab)); } -TabMessage *TabSupervisor::addMessageTab(const QString &userName, bool focus) +TabMessage *TabSupervisor::addMessageTab(const QString &receiverName, bool focus) { - TabMessage *tab = new TabMessage(client, userName); + if (receiverName == userName) + return 0; + + TabMessage *tab = new TabMessage(client, receiverName); connect(tab, SIGNAL(talkClosing(TabMessage *)), this, SLOT(talkLeft(TabMessage *))); myAddTab(tab); - messageTabs.insert(userName, tab); + messageTabs.insert(receiverName, tab); if (focus) setCurrentWidget(tab); return tab; @@ -206,11 +212,11 @@ void TabSupervisor::tabUserEvent() QApplication::alert(this); } -void TabSupervisor::processChatEvent(ChatEvent *event) +void TabSupervisor::processRoomEvent(RoomEvent *event) { - TabChatChannel *tab = chatChannelTabs.value(event->getChannel(), 0); + TabRoom *tab = roomTabs.value(event->getRoomId(), 0); if (tab) - tab->processChatEvent(event); + tab->processRoomEvent(event); } void TabSupervisor::processGameEventContainer(GameEventContainer *cont) @@ -230,6 +236,8 @@ void TabSupervisor::processMessageEvent(Event_Message *event) tab = messageTabs.value(event->getReceiverName()); if (!tab) tab = addMessageTab(event->getSenderName(), false); + if (!tab) + return; tab->processMessageEvent(event); } diff --git a/cockatrice/src/tab_supervisor.h b/cockatrice/src/tab_supervisor.h index 7d1965f8..413d37be 100644 --- a/cockatrice/src/tab_supervisor.h +++ b/cockatrice/src/tab_supervisor.h @@ -8,24 +8,27 @@ class QMenu; class AbstractClient; class Tab; class TabServer; -class TabChatChannel; +class TabRoom; class TabGame; class TabDeckStorage; class TabMessage; -class ChatEvent; +class RoomEvent; class GameEventContainer; class Event_GameJoined; class Event_Message; +class ServerInfo_Room; +class ServerInfo_User; class TabSupervisor : public QTabWidget { Q_OBJECT private: + QString userName; QIcon *tabChangedIcon; AbstractClient *client; QList localClients; TabServer *tabServer; TabDeckStorage *tabDeckStorage; - QMap chatChannelTabs; + QMap roomTabs; QMap gameTabs; QMap messageTabs; void myAddTab(Tab *tab); @@ -33,7 +36,7 @@ public: TabSupervisor(QWidget *parent = 0); ~TabSupervisor(); void retranslateUi(); - void start(AbstractClient *_client); + void start(AbstractClient *_client, ServerInfo_User *userInfo); void startLocal(const QList &_clients); void stop(); int getGameCount() const { return gameTabs.size(); } @@ -46,13 +49,13 @@ private slots: void gameJoined(Event_GameJoined *event); void localGameJoined(Event_GameJoined *event); void gameLeft(TabGame *tab); - void addChatChannelTab(const QString &channelName); - void chatChannelLeft(TabChatChannel *tab); + void addRoomTab(ServerInfo_Room *info, bool setCurrent); + void roomLeft(TabRoom *tab); TabMessage *addMessageTab(const QString &userName, bool focus); void processUserLeft(const QString &userName); void talkLeft(TabMessage *tab); void tabUserEvent(); - void processChatEvent(ChatEvent *event); + void processRoomEvent(RoomEvent *event); void processGameEventContainer(GameEventContainer *cont); void processMessageEvent(Event_Message *event); }; diff --git a/cockatrice/src/userlist.cpp b/cockatrice/src/userlist.cpp new file mode 100644 index 00000000..54fb4703 --- /dev/null +++ b/cockatrice/src/userlist.cpp @@ -0,0 +1,93 @@ +#include "userlist.h" +#include "abstractclient.h" +#include "pixmapgenerator.h" +#include +#include + +UserListTWI::UserListTWI() + : QTreeWidgetItem(Type) +{ +} + +bool UserListTWI::operator<(const QTreeWidgetItem &other) const +{ + // Equal user level => sort by name + if (data(0, Qt::UserRole) == other.data(0, Qt::UserRole)) + return data(2, Qt::UserRole).toString().toLower() < other.data(2, Qt::UserRole).toString().toLower(); + // Else sort by user level + return data(0, Qt::UserRole).toInt() > other.data(0, Qt::UserRole).toInt(); +} + +UserList::UserList(bool _global, QWidget *parent) + : QGroupBox(parent), global(_global) +{ + userTree = new QTreeWidget; + userTree->setColumnCount(3); + userTree->header()->setResizeMode(QHeaderView::ResizeToContents); + userTree->setHeaderHidden(true); + userTree->setRootIsDecorated(false); + userTree->setIconSize(QSize(20, 12)); + connect(userTree, SIGNAL(itemActivated(QTreeWidgetItem *, int)), this, SLOT(userClicked(QTreeWidgetItem *, int))); + + QVBoxLayout *vbox = new QVBoxLayout; + vbox->addWidget(userTree); + + setLayout(vbox); + + retranslateUi(); +} + +void UserList::retranslateUi() +{ + titleStr = global ? tr("Users online: %1") : tr("Users in this room: %1"); + updateCount(); +} + +void UserList::processUserInfo(ServerInfo_User *user) +{ + QTreeWidgetItem *item = 0; + for (int i = 0; i < userTree->topLevelItemCount(); ++i) { + QTreeWidgetItem *temp = userTree->topLevelItem(i); + if (temp->data(2, Qt::UserRole) == user->getName()) { + item = temp; + break; + } + } + if (!item) { + item = new UserListTWI; + userTree->addTopLevelItem(item); + retranslateUi(); + } + item->setData(0, Qt::UserRole, user->getUserLevel()); + item->setIcon(0, QIcon(UserLevelPixmapGenerator::generatePixmap(12, user->getUserLevel()))); + item->setIcon(1, QIcon(CountryPixmapGenerator::generatePixmap(12, user->getCountry()))); + item->setData(2, Qt::UserRole, user->getName()); + item->setData(2, Qt::DisplayRole, user->getName()); +} + +bool UserList::deleteUser(const QString &userName) +{ + for (int i = 0; i < userTree->topLevelItemCount(); ++i) + if (userTree->topLevelItem(i)->data(2, Qt::UserRole) == userName) { + delete userTree->takeTopLevelItem(i); + updateCount(); + return true; + } + + return false; +} + +void UserList::updateCount() +{ + setTitle(titleStr.arg(userTree->topLevelItemCount())); +} + +void UserList::userClicked(QTreeWidgetItem *item, int /*column*/) +{ + emit openMessageDialog(item->data(2, Qt::UserRole).toString(), true); +} + +void UserList::sortItems() +{ + userTree->sortItems(1, Qt::AscendingOrder); +} diff --git a/cockatrice/src/userlist.h b/cockatrice/src/userlist.h new file mode 100644 index 00000000..0694eee0 --- /dev/null +++ b/cockatrice/src/userlist.h @@ -0,0 +1,35 @@ +#ifndef USERLIST_H +#define USERLIST_H + +#include +#include + +class QTreeWidget; +class ServerInfo_User; + +class UserListTWI : public QTreeWidgetItem { +public: + UserListTWI(); + bool operator<(const QTreeWidgetItem &other) const; +}; + +class UserList : public QGroupBox { + Q_OBJECT +private: + QTreeWidget *userTree; + bool global; + QString titleStr; + void updateCount(); +private slots: + void userClicked(QTreeWidgetItem *item, int column); +signals: + void openMessageDialog(const QString &userName, bool focus); +public: + UserList(bool _global, QWidget *parent = 0); + void retranslateUi(); + void processUserInfo(ServerInfo_User *user); + bool deleteUser(const QString &userName); + void sortItems(); +}; + +#endif \ No newline at end of file diff --git a/cockatrice/src/window_main.cpp b/cockatrice/src/window_main.cpp index d4c11b59..1badc0f0 100644 --- a/cockatrice/src/window_main.cpp +++ b/cockatrice/src/window_main.cpp @@ -64,15 +64,18 @@ void MainWindow::statusChanged(ClientStatus _status) aConnect->setEnabled(false); aDisconnect->setEnabled(true); break; - case StatusLoggedIn: { - tabSupervisor->start(client); + case StatusLoggedIn: break; - } default: break; } } +void MainWindow::userInfoReceived(ServerInfo_User *info) +{ + tabSupervisor->start(client, info); +} + // Actions void MainWindow::actConnect() @@ -110,7 +113,7 @@ void MainWindow::actSinglePlayer() } tabSupervisor->startLocal(localClients); - Command_CreateGame *createCommand = new Command_CreateGame(QString(), QString(), numberPlayers, false, false, false, false); + Command_CreateGame *createCommand = new Command_CreateGame(0, QString(), QString(), numberPlayers, false, false, false, false); mainClient->sendCommand(createCommand); } @@ -150,7 +153,15 @@ void MainWindow::actExit() void MainWindow::actAbout() { - QMessageBox::about(this, tr("About Cockatrice"), trUtf8("Cockatrice
Version %1


Authors:
Max-Wilhelm Bruker
Marcus Schütz
Marius van Zundert

Translators:
Spanish: Gocho
Portugese: Milton Gonçalves
").arg(versionString)); + QMessageBox::about(this, tr("About Cockatrice"), QString( + "Cockatrice
" + + tr("Version %1").arg(versionString) + + "


" + tr("Authors:") + "
Max-Wilhelm Bruker
Marcus Schütz

" + + "" + tr("Translators:") + "
" + + tr("Spanish:") + " Víctor Martínez
" + + tr("Portugese:") + " Milton Gonçalves
" + + tr("French:") + " Yannick Hammer
" + )); } void MainWindow::serverTimeout() @@ -260,6 +271,7 @@ MainWindow::MainWindow(QWidget *parent) connect(client, SIGNAL(serverTimeout()), this, SLOT(serverTimeout())); connect(client, SIGNAL(statusChanged(ClientStatus)), this, SLOT(statusChanged(ClientStatus))); connect(client, SIGNAL(protocolVersionMismatch(int, int)), this, SLOT(protocolVersionMismatch(int, int))); + connect(client, SIGNAL(userInfoChanged(ServerInfo_User *)), this, SLOT(userInfoReceived(ServerInfo_User *))); tabSupervisor = new TabSupervisor; connect(tabSupervisor, SIGNAL(setMenu(QMenu *)), this, SLOT(updateTabMenu(QMenu *))); diff --git a/cockatrice/src/window_main.h b/cockatrice/src/window_main.h index adb4e20e..e6bcb155 100644 --- a/cockatrice/src/window_main.h +++ b/cockatrice/src/window_main.h @@ -28,6 +28,7 @@ class TabSupervisor; class RemoteClient; class LocalClient; class LocalServer; +class ServerInfo_User; class MainWindow : public QMainWindow { Q_OBJECT @@ -38,6 +39,7 @@ private slots: void serverError(ResponseCode r); void socketError(const QString &errorStr); void protocolVersionMismatch(int localVersion, int remoteVersion); + void userInfoReceived(ServerInfo_User *userInfo); void localGameEnded(); void actConnect(); diff --git a/cockatrice/src/zoneviewwidget.cpp b/cockatrice/src/zoneviewwidget.cpp index 7179be78..2f124fed 100644 --- a/cockatrice/src/zoneviewwidget.cpp +++ b/cockatrice/src/zoneviewwidget.cpp @@ -9,7 +9,7 @@ #include "protocol_items.h" #include "settingscache.h" -ZoneViewWidget::ZoneViewWidget(Player *_player, CardZone *_origZone, int numberCards, const QList &cardList) +ZoneViewWidget::ZoneViewWidget(Player *_player, CardZone *_origZone, int numberCards, bool _revealZone, const QList &cardList) : QGraphicsWidget(0, Qt::Tool | Qt::CustomizeWindowHint | Qt::WindowSystemMenuHint | Qt::WindowTitleHint/* | Qt::WindowCloseButtonHint*/), player(_player) { setAttribute(Qt::WA_DeleteOnClose); @@ -48,7 +48,7 @@ ZoneViewWidget::ZoneViewWidget(Player *_player, CardZone *_origZone, int numberC extraHeight = vbox->sizeHint(Qt::PreferredSize).height(); resize(150, 150); - zone = new ZoneViewZone(player, _origZone, numberCards, this); + zone = new ZoneViewZone(player, _origZone, numberCards, _revealZone, this); connect(zone, SIGNAL(optimumRectChanged()), this, SLOT(resizeToZoneContents())); connect(zone, SIGNAL(beingDeleted()), this, SLOT(zoneDeleted())); vbox->addItem(zone); diff --git a/cockatrice/src/zoneviewwidget.h b/cockatrice/src/zoneviewwidget.h index 71dcd754..afa63eb3 100644 --- a/cockatrice/src/zoneviewwidget.h +++ b/cockatrice/src/zoneviewwidget.h @@ -30,7 +30,7 @@ private slots: void resizeToZoneContents(); void zoneDeleted(); public: - ZoneViewWidget(Player *_player, CardZone *_origZone, int numberCards = 0, const QList &cardList = QList()); + ZoneViewWidget(Player *_player, CardZone *_origZone, int numberCards = 0, bool _revealZone = false, const QList &cardList = QList()); ZoneViewZone *getZone() const { return zone; } void retranslateUi(); protected: diff --git a/cockatrice/src/zoneviewzone.cpp b/cockatrice/src/zoneviewzone.cpp index bcf59775..f8034541 100644 --- a/cockatrice/src/zoneviewzone.cpp +++ b/cockatrice/src/zoneviewzone.cpp @@ -5,17 +5,19 @@ #include "protocol_items.h" #include "carddragitem.h" -ZoneViewZone::ZoneViewZone(Player *_p, CardZone *_origZone, int _numberCards, QGraphicsItem *parent) - : SelectZone(_p, _origZone->getName(), false, false, true, parent, true), bRect(QRectF()), minRows(0), numberCards(_numberCards), origZone(_origZone), sortByName(false), sortByType(false) +ZoneViewZone::ZoneViewZone(Player *_p, CardZone *_origZone, int _numberCards, bool _revealZone, QGraphicsItem *parent) + : SelectZone(_p, _origZone->getName(), false, false, true, parent, true), bRect(QRectF()), minRows(0), numberCards(_numberCards), origZone(_origZone), revealZone(_revealZone), sortByName(false), sortByType(false) { - origZone->setView(this); + if (!revealZone) + origZone->setView(this); } ZoneViewZone::~ZoneViewZone() { emit beingDeleted(); qDebug("ZoneViewZone destructor"); - origZone->setView(NULL); + if (!revealZone) + origZone->setView(NULL); } QRectF ZoneViewZone::boundingRect() const diff --git a/cockatrice/src/zoneviewzone.h b/cockatrice/src/zoneviewzone.h index d2208768..d1c1acd2 100644 --- a/cockatrice/src/zoneviewzone.h +++ b/cockatrice/src/zoneviewzone.h @@ -15,9 +15,10 @@ private: int minRows, numberCards; void handleDropEvent(CardDragItem *dragItem, CardZone *startZone, const QPoint &dropPoint, bool faceDown); CardZone *origZone; + bool revealZone; bool sortByName, sortByType; public: - ZoneViewZone(Player *_p, CardZone *_origZone, int _numberCards = -1, QGraphicsItem *parent = 0); + ZoneViewZone(Player *_p, CardZone *_origZone, int _numberCards = -1, bool _revealZone = false, QGraphicsItem *parent = 0); ~ZoneViewZone(); QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); diff --git a/cockatrice/translations/cockatrice_de.ts b/cockatrice/translations/cockatrice_de.ts index f12aa06d..580b0039 100644 --- a/cockatrice/translations/cockatrice_de.ts +++ b/cockatrice/translations/cockatrice_de.ts @@ -27,57 +27,56 @@ AppearanceSettingsPage - + Zone background pictures Hintergrundbilder für Kartenzonen - + Path to hand background: Hintergrundbild für die Hand: - + Path to stack background: Hintergrundbild für den Stapel: - + Path to table background: Hintergrundbild für das Spielfeld: - + Path to player info background: Hintergrundbild für den Spielerbereich: - + Path to picture of card back: Pfad zum Bild der Kartenrückseite: - + Hand layout Kartenhand - + Display hand horizontally (wastes space) Hand horizonal anzeigen (verschwendet Platz) - + Table grid layout Spielfeldraster - Economical layout - Platzsparende Anordnung + Platzsparende Anordnung - + Invert vertical coordinate Vertikale Koordinate umkehren @@ -86,17 +85,17 @@ Platzsparende Anordnung - + Zone view layout Aussehen des Zonenbetrachters - + Sort by name nach Namen sortieren - + Sort by type nach Kartentypen sortieren @@ -105,11 +104,11 @@ standardmäßig alphabetisch sortieren - - - - - + + + + + Choose path Pfad auswählen @@ -176,112 +175,117 @@ CardItem - + + &Play + + + + &Tap &Tappen - + &Untap E&nttappen - + Toggle &normal untapping N&ormales Enttappen umschalten - + &Flip &Umdrehen - + &Clone &Kopieren - + &Attach to card... &An Karte anlegen... - + Ctrl+A Ctrl+A - + Unattac&h &Von Karte lösen - + Set &P/T... &Kampfwerte setzen... - + &Set annotation... &Hinweis setzen... - + red rot - + yellow gelb - + green grün - + &Add counter (%1) Zählmarke &hinzufügen (%1) - + &Remove counter (%1) Zählmarke &entfernen (%1) - + &Set counters (%1)... Zählmarken &setzen (%1)... - + &top of library &auf die Bibliothek - + &bottom of library &unter die Bibliothek - + &graveyard in den &Friedhof - + Ctrl+Del Ctrl+Del - + &exile ins &Exil - + &Move to &Verschieben @@ -613,29 +617,24 @@ ChatChannelSelector - Chat channels - Chaträume + Chaträume - Joi&n - Teil&nehmen + Teil&nehmen - Channel - Raum + Raum - Description - Beschreibung + Beschreibung - Players - Spieler + Spieler @@ -887,7 +886,7 @@ Spiel erstellen - + Error Fehler @@ -896,7 +895,7 @@ Ungültige Anzahl an Spielern. - + Server error. Serverfehler. @@ -1069,9 +1068,9 @@ DlgSettings - - - + + + Error Fehler @@ -1088,47 +1087,47 @@ Der Pfad zum Kartenbilderverzeichnis ist ungültig. - + Your card database is invalid. Would you like to go back and set the correct path? Ihre Kartendatenbank ist ungültig. Möchten Sie zurückgehen und den korrekten Pfad einstellen? - + The path to your deck directory is invalid. Would you like to go back and set the correct path? Der Pfad zu Ihrem Deckordner ist ungültig. Möchten Sie zurückgehen und den korrekten Pfad einstellen? - + The path to your card pictures directory is invalid. Would you like to go back and set the correct path? Der Pfad zu Ihrem Kartenbilderordner ist ungültig. Möchten Sie zurückgehen und den korrekten Pfad einstellen? - + Settings Einstellungen - + General Allgemeines - + Appearance Erscheinungsbild - + User interface Bedienung - + Messages Nachrichten - + &Close S&chließen @@ -1394,20 +1393,20 @@ GameSelector - + C&reate Spiel e&rstellen - + &Join &Teilnehmen - - - - + + + + Error Fehler @@ -1416,47 +1415,51 @@ XXX - + Wrong password. Falsches Passwort. - + Spectators are not allowed in this game. In diesem Spiel sind keine Zuschauer zugelassen. - + The game is already full. Das Spiel ist bereits voll. - + The game does not exist any more. Dieses Spiel gibt es nicht mehr. - + Join game Spiel beitreten - + Password: Passwort: - + Games Spiele - - &Show full games - &Volle Spiele anzeigen + + Show &full games + - + &Show full games + &Volle Spiele anzeigen + + + J&oin as spectator &Zuschauen @@ -1464,7 +1467,7 @@ GameView - + Esc Esc @@ -1575,106 +1578,131 @@ MainWindow - + Number of players Spieleranzahl - + Please enter the number of players. Bitte die Spieleranzahl eingeben: - - + + Player %1 Spieler %1 - + About Cockatrice - - - <font size="8"><b>Cockatrice</b></font><br>Version %1<br><br><br><b>Authors:</b><br>Max-Wilhelm Bruker<br>Marcus Schütz<br>Marius van Zundert<br><br><b>Translators:</b><br>Spanish: Gocho<br>Portugese: Milton Gonçalves<br> - - - - - + Version %1 + + + + + Authors: + + + + + Translators: + + + + + Spanish: + + + + + Portugese: + + + + + French: + + + + + + + Error Fehler - + Server timeout Server Zeitüberschreitung - + Invalid login data. Ungültige Anmeldedaten. - + Socket error: %1 Netzwerkfehler: %1 - + Protocol version mismatch. Local version: %1, remote version: %2. Protokollversionen stimmen nicht überein. Lokale Version: %1, Serverversion: %2. - + Connecting to %1... Verbinde zu %1... - + Disconnected nicht verbunden - + Logged in at %1 Angemeldet bei %1 - + &Connect... &Verbinden... - + &Disconnect Verbindung &trennen - + Start &local game... &Lokales Spiel starten... - + &About Cockatrice - + &Help - + Are you sure? Sind Sie sicher? - + There are still open games. Are you sure you want to quit? Es gibt noch offene Spiele. Wollen Sie das Programm wirklich beenden? @@ -1691,27 +1719,27 @@ Spiel ver&lassen - + &Deck editor &Deck-Editor - + &Full screen &Vollbild - + Ctrl+F Ctrl+F - + &Settings... &Einstellungen... - + &Exit &Beenden @@ -1724,7 +1752,7 @@ Esc - + &Cockatrice &Cockatrice @@ -1808,8 +1836,8 @@ %1 zieht %2 Karten - - + + a card eine Karte @@ -2023,107 +2051,112 @@ vom Stapel - + + %1 gives %2 control over %3. + + + + %1 puts %2 into play%3. %1 bringt %2%3 ins Spiel. - + %1 puts %2%3 into graveyard. %1 legt %2%3 auf den Friedhof. - + %1 exiles %2%3. %1 schickt %2%3 ins Exil. - + %1 moves %2%3 to hand. %1 nimmt %2%3 auf die Hand. - + %1 puts %2%3 into his library. %1 legt %2%3 in seine Bibliothek. - + %1 puts %2%3 on bottom of his library. %1 legt %2%3 unter seine Bibliothek. - + %1 puts %2%3 on top of his library. %1 legt %2%3 auf die Bibliothek. - + %1 puts %2%3 into his library at position %4. %1 legt %2%3 in seine Bibliothek an %4. Stelle. - + %1 moves %2%3 to sideboard. %1 legt %2%3 in sein Sideboard. - + %1 plays %2%3. %1 spielt %2%3 aus. - + %1 flips %2 face-down. %1 wendet %2 auf die Rückseite. - + %1 flips %2 face-up. %1 wendet %2 auf die Vorderseite. - + %1 destroys %2. %1 zerstört %2. - + %1 attaches %2 to %3's %4. %1 legt %2 an %3s %4 an. - + %1 unattaches %2. %1 löst %2 ab. - + %1 creates token: %2%3. %1 erstellt Token: %2%3. - + %1 points from %2's %3 to %4. %1 zeigt von %2s %3 auf %4. - + %1 randomly reveals %2%3 to %4. %1 zeigt %4 zufällig %2%3 vor. - + %1 randomly reveals %2%3. %1 zeigt zufällig %2%3 offen vor. - + %1 reveals %2%3 to %4. %1 zeigt %4 %2%3 vor. - + %1 reveals %2%3. %1 zeigt %2%3 offen vor. @@ -2132,12 +2165,12 @@ %1 erstellt einen Spielstein: %2 (%3). - + %1 points from %2's %3 to %4's %5. %1 zeigt von %2s %3 auf %4s %5. - + %1 places %n counter(s) (%2) on %3 (now %4). %1 legt eine Marke (%2) auf %3 (jetzt %4). @@ -2145,7 +2178,7 @@ - + %1 removes %n counter(s) (%2) from %3 (now %4). %1 entfernt eine Marke (%2) von %3 (jetzt %4). @@ -2153,37 +2186,37 @@ - + red rot - + yellow gelb - + green grün - + %1 sets counter %2 to %3 (%4%5). %1 setzt Zähler %2 auf %3 (%4%5). - + %1 sets PT of %2 to %3. %1 setzt Kampfwerte von %2 auf %3. - + %1 sets annotation of %2 to %3. %1 versieht %2 mit dem Hinweis %3. - + %1 is looking at the top %2 cards %3. %1 sieht sich die obersten %2 Karten %3 an. @@ -2280,7 +2313,7 @@ %1 entfernt %2 Zählmarken von %3 (jetzt %4). - + %1 %2 %3. %1 %2 %3. @@ -2293,22 +2326,22 @@ %1 sieht sich die obersten %2 Karten %3 an. - + %1 is looking at %2. %1 sieht sich %2 an. - + %1 stops looking at %2. %1 sieht sich %2 nicht mehr an. - + %1 reveals %2 to %3. %1 zeigt %3 %2. - + %1 reveals %2. %1 zeigt %2 offen vor. @@ -2329,7 +2362,7 @@ %1 zeigt %2 aus %3 offen vor. - + ending phase die Zugendphase @@ -2358,57 +2391,57 @@ %1 sieht sich %2s %3 nicht mehr an - + It is now %1's turn. %1 ist am Zug. - + untap step das Enttappsegment - + upkeep step das Versorgungssegment - + draw step das Ziehsegment - + first main phase die erste Hauptphase - + beginning of combat step das Anfangssegment der Kampfphase - + declare attackers step das Angreifer-Deklarieren-Segment - + declare blockers step das Blocker-Deklarieren-Segment - + combat damage step das Kampfschadenssegment - + end of combat step das Endsegment der Kampfphase - + second main phase die zweite Hauptphase @@ -2417,7 +2450,7 @@ das Ende-des-Zuges-Segment - + It is now the %1. Es ist nun %1. @@ -2426,12 +2459,12 @@ %1 bewegt %2 %3 nach %4 - + taps tappt - + untaps enttappt @@ -2456,7 +2489,7 @@ %1 entfernt %2 Zählmarken von %3 (jetzt %4) - + his permanents seine bleibenden Karten @@ -2469,12 +2502,12 @@ %1 setzt Zähler "%2" auf %3 (%4%5) - + %1 sets %2 to not untap normally. %1 setzt %2 auf explizites Enttappen. - + %1 sets %2 to untap normally. %1 setzt %2 auf normales Enttappen. @@ -2490,12 +2523,12 @@ MessagesSettingsPage - + &Add &Hinzufügen - + &Remove &Entfernen @@ -2508,12 +2541,12 @@ Entfernen - + Add message Nachricht hinzufügen - + Message: Nachricht: @@ -2579,21 +2612,21 @@ Player - - - + + + Move to &top of library Oben auf die Biblio&thek legen - - - + + + Move to &bottom of library Unter die &Bibliothek legen - + &View library &Zeige Bibliothek @@ -2602,32 +2635,32 @@ Oberste Karten in den F&riedhof legen... - + Move top cards to &exile... Oberste Karten ins &Exil schicken... - + F3 F3 - + View &top cards of library... Zeige die oberen Kar&ten der Bibliothek... - + &View graveyard &Zeige Friedhof - + &All players &allen Spielern - + F4 F4 @@ -2636,63 +2669,68 @@ Zeige ent&fernte Karten - + &View sideboard Zeige &Sideboard - + Player "%1" Spieler "%1" - - + + Move to &graveyard Auf den &Friedhof legen - + Reveal &library to &Bibliothek jemandem zeigen - + Reveal t&op card to &Oberste Karte jemandem zeigen - + Take &mulligan &Mulligan nehmen - + Move top cards to &graveyard... Oberste Karten auf den F&riedhof legen... - + + Put top card on &bottom + + + + &Hand &Hand - + &Reveal to Jemandem &zeigen - + Reveal r&andom card to Z&ufällige Karte jemandem zeigen - + &Library Bib&liothek - + &Graveyard &Friedhof @@ -2701,7 +2739,7 @@ Entfe&rnte Karten - + &Sideboard &Sideboard @@ -2714,33 +2752,33 @@ &Hinweis setzen... - + View top cards of library Zeige die obersten Karten der Bibliothek - + Number of cards: Anzahl der Karten: - + &Draw card Karte &ziehen - + &View exile &Zeige Exil - + &Exile &Exil - - + + Move to &hand auf die &Hand nehmen @@ -2749,28 +2787,28 @@ auf den &Friedhof legen - - + + Move to &exile ins &Exil schicken - + Ctrl+W Ctrl+W - + Ctrl+D Ctrl+D - + D&raw cards... Ka&rten ziehen... - + Ctrl+E Ctrl+E @@ -2779,32 +2817,32 @@ &Mulligan nehmen... - + Ctrl+M Ctrl+M - + &Shuffle Mi&schen - + Ctrl+S Ctrl+S - + &Counters &Zähler - + &Untap all permanents &Enttappe alle bleibenden Karten - + Ctrl+U Ctrl+U @@ -2833,42 +2871,42 @@ Ctrl+L - + R&oll die... &Würfeln... - + Ctrl+I Ctrl+I - + &Create token... Spiels&tein erstellen... - + Ctrl+T Ctrl+T - + C&reate another token &Noch einen Spielstein erstellen - + Ctrl+G Ctrl+G - + S&ay S&agen - + C&ard &Karte @@ -2961,50 +2999,50 @@ F10 - + Draw cards Karten ziehen - - - - + + + + Number: Anzahl: - + Move top cards to grave Oberste Karten in den Friedhof legen - + Move top cards to exile Oberste Karten ins Exil schicken - + Set power/toughness Kampfwerte setzen - + Please enter the new PT: Bitte die neuen Kampfwerte eingeben: - + Set annotation Hinweis setzen - + Please enter the new annotation: Bitte den Hinweis eingeben: - + Set counters Setze Zählmarken @@ -3017,12 +3055,12 @@ Neue Lebenspunkte insgesamt: - + Roll die Würfeln - + Number of sides: Anzahl der Seiten: @@ -3133,12 +3171,44 @@ Änderungsdatum + + RoomSelector + + + Rooms + + + + + Joi&n + Teil&nehmen + + + + Room + + + + + Description + Beschreibung + + + + Players + + + + + Games + Spiele + + ServerMessageLog - Server messages - Servernachrichten + Servernachrichten @@ -3157,24 +3227,20 @@ TabChatChannel - C&hat channel - C&hatraum + C&hatraum - &Leave channel - Raum ver&lassen + Raum ver&lassen - %1 has joined the channel. - %1 hat den Raum betreten. + %1 hat den Raum betreten. - %1 has left the channel. - %1 hat den Raum verlassen. + %1 hat den Raum verlassen. @@ -3384,10 +3450,43 @@ Bitte geben Sie einen Namen ein: Gespräch mit %1 + + TabRoom + + + &Say: + &Sagen: + + + + Chat + + + + + &Room + + + + + &Leave room + + + + + %1 has joined the room. + + + + + %1 has left the room. + + + TabServer - + Server Server @@ -3410,35 +3509,55 @@ Bitte geben Sie einen Namen ein: UserInfoBox - + Location: Ort: - + User level: Nutzerstatus: + + + Administrator + + + + + Judge + + + + + Registered user + + + + + Unregistered user + + UserInterfaceSettingsPage - + General interface settings Allgemeine Bedienung - + &Double-click cards to play them (instead of single-click) Karten durch &Doppelklick ausspielen (statt Einzelklick) - + Animation settings Animationseinstellungen - + &Tap/untap animation Animiertes &Tappen/Enttappen @@ -3446,10 +3565,15 @@ Bitte geben Sie einen Namen ein: UserList - + Users online: %1 Benutzer online: %1 + + + Users in this room: %1 + + WndDeckEditor @@ -3637,7 +3761,20 @@ Willst du die Änderungen speichern? Deck laden - + + + Error + Fehler + + + + + The deck could not be saved. +Please check that the directory is writable and try again. + + + + Save deck Deck speichern diff --git a/cockatrice/translations/cockatrice_en.ts b/cockatrice/translations/cockatrice_en.ts index 60ebb47d..dfb6231d 100644 --- a/cockatrice/translations/cockatrice_en.ts +++ b/cockatrice/translations/cockatrice_en.ts @@ -4,81 +4,76 @@ AppearanceSettingsPage - + Zone background pictures - + Path to hand background: - + Path to stack background: - + Path to table background: - + Path to player info background: - + Path to picture of card back: - + Hand layout - + Display hand horizontally (wastes space) - + Table grid layout - - Economical layout - - - - + Invert vertical coordinate - + Zone view layout - + Sort by name - + Sort by type - - - - - + + + + + Choose path @@ -137,112 +132,117 @@ CardItem - + + &Play + + + + &Tap - + &Untap - + Toggle &normal untapping - + &Flip - + &Clone - + &Attach to card... - + Ctrl+A - + Unattac&h - + Set &P/T... - + &Set annotation... - + red - + yellow - + green - + &Add counter (%1) - + &Remove counter (%1) - + &Set counters (%1)... - + &top of library - + &bottom of library - + &graveyard - + Ctrl+Del - + &exile - + &Move to @@ -430,34 +430,6 @@ - - ChatChannelSelector - - - Chat channels - - - - - Joi&n - - - - - Channel - - - - - Description - - - - - Players - - - Counter @@ -669,12 +641,12 @@ - + Error - + Server error. @@ -816,54 +788,54 @@ DlgSettings - - - + + + Error - + Your card database is invalid. Would you like to go back and set the correct path? - + The path to your deck directory is invalid. Would you like to go back and set the correct path? - + The path to your card pictures directory is invalid. Would you like to go back and set the correct path? - + Settings - + General - + Appearance - + User interface - + Messages - + &Close @@ -871,65 +843,65 @@ GameSelector - + C&reate - + &Join - - - - + + + + Error - + Wrong password. - + Spectators are not allowed in this game. - + The game is already full. - + The game does not exist any more. - + Join game - + Password: - + Games - - &Show full games + + Show &full games - + J&oin as spectator @@ -937,7 +909,7 @@ GameView - + Esc @@ -1044,136 +1016,161 @@ MainWindow - + Number of players - + Please enter the number of players. - - + + Player %1 - + About Cockatrice - - - <font size="8"><b>Cockatrice</b></font><br>Version %1<br><br><br><b>Authors:</b><br>Max-Wilhelm Bruker<br>Marcus Schütz<br>Marius van Zundert<br><br><b>Translators:</b><br>Spanish: Gocho<br>Portugese: Milton Gonçalves<br> - - - - - + Version %1 + + + + + Authors: + + + + + Translators: + + + + + Spanish: + + + + + Portugese: + + + + + French: + + + + + + + Error - + Server timeout - + Invalid login data. - + Socket error: %1 - + Protocol version mismatch. Local version: %1, remote version: %2. - + Connecting to %1... - + Disconnected - + Logged in at %1 - + &Connect... - + &Disconnect - + Start &local game... - + &Deck editor - + &Full screen - + Ctrl+F - + &Settings... - + &Exit - + &Cockatrice - + &About Cockatrice - + &Help - + Are you sure? - + There are still open games. Are you sure you want to quit? @@ -1281,88 +1278,93 @@ - + + %1 gives %2 control over %3. + + + + %1 puts %2 into play%3. - + %1 puts %2%3 into graveyard. - + %1 exiles %2%3. - + %1 moves %2%3 to hand. - + %1 puts %2%3 into his library. - + %1 puts %2%3 on bottom of his library. - + %1 puts %2%3 on top of his library. - + %1 puts %2%3 into his library at position %4. - + %1 moves %2%3 to sideboard. - + %1 plays %2%3. - - + + a card - + %1 flips %2 face-down. - + %1 flips %2 face-up. - + %1 attaches %2 to %3's %4. - + %1 unattaches %2. - + %1 points from %2's %3 to %4's %5. - + %1 places %n counter(s) (%2) on %3 (now %4). %1 places a counter (%2) on %3 (now %4). @@ -1370,7 +1372,7 @@ - + %1 removes %n counter(s) (%2) from %3 (now %4). %1 removes a counter (%2) from %3 (now %4). @@ -1378,37 +1380,37 @@ - + red - + yellow - + green - + %1 sets counter %2 to %3 (%4%5). - + %1 sets PT of %2 to %3. - + %1 sets annotation of %2 to %3. - + %1 is looking at the top %2 cards %3. @@ -1473,52 +1475,52 @@ - + %1 destroys %2. - + %1 creates token: %2%3. - + %1 points from %2's %3 to %4. - + %1 %2 %3. - + %1 is looking at %2. - + %1 stops looking at %2. - + %1 reveals %2 to %3. - + %1 reveals %2. - + ending phase - + It is now %1's turn. @@ -1528,102 +1530,102 @@ - + %1 randomly reveals %2%3 to %4. - + %1 randomly reveals %2%3. - + %1 reveals %2%3 to %4. - + %1 reveals %2%3. - + untap step - + upkeep step - + draw step - + first main phase - + beginning of combat step - + declare attackers step - + declare blockers step - + combat damage step - + end of combat step - + second main phase - + It is now the %1. - + taps - + untaps - + %1 sets %2 to not untap normally. - + %1 sets %2 to untap normally. - + his permanents @@ -1631,22 +1633,22 @@ MessagesSettingsPage - + &Add - + &Remove - + Add message - + Message: @@ -1712,302 +1714,307 @@ Player - - - + + + Move to &top of library - - - + + + Move to &bottom of library - - + + Move to &graveyard - + &View library - + Reveal &library to - + Reveal t&op card to - + Move top cards to &graveyard... - + F3 - + View &top cards of library... - + &View graveyard - + F4 - + &View sideboard - + Player "%1" - + &Hand - + &Library - + &Graveyard - + &Sideboard - + View top cards of library - + Number of cards: - + &Draw card - + &View exile - + &Exile + + + + Move to &hand + + - Move to &hand - - - - - Move to &exile - + Ctrl+W - + Ctrl+D - + D&raw cards... - + Ctrl+E - + Take &mulligan - + Ctrl+M - + &Shuffle - + Ctrl+S - + &Counters - + &Untap all permanents - + Ctrl+U - + R&oll die... - + Ctrl+I - + &Create token... - + Ctrl+T - + C&reate another token - + Ctrl+G - + S&ay - + Move top cards to &exile... - + + Put top card on &bottom + + + + &Reveal to - + Reveal r&andom card to - + C&ard - + &All players - + Draw cards - - - - + + + + Number: - + Move top cards to grave - + Move top cards to exile - + Roll die - + Number of sides: - + Set power/toughness - + Please enter the new PT: - + Set annotation - + Please enter the new annotation: - + Set counters @@ -2087,10 +2094,35 @@ - ServerMessageLog + RoomSelector - - Server messages + + Rooms + + + + + Joi&n + + + + + Room + + + + + Description + + + + + Players + + + + + Games @@ -2107,29 +2139,6 @@ - - TabChatChannel - - - C&hat channel - - - - - &Leave channel - - - - - %1 has joined the channel. - - - - - %1 has left the channel. - - - TabDeckStorage @@ -2308,10 +2317,43 @@ Please enter a name: + + TabRoom + + + &Say: + + + + + Chat + + + + + &Room + + + + + &Leave room + + + + + %1 has joined the room. + + + + + %1 has left the room. + + + TabServer - + Server @@ -2319,35 +2361,55 @@ Please enter a name: UserInfoBox - + Location: - + User level: + + + Administrator + + + + + Judge + + + + + Registered user + + + + + Unregistered user + + UserInterfaceSettingsPage - + General interface settings - + &Double-click cards to play them (instead of single-click) - + Animation settings - + &Tap/untap animation @@ -2355,10 +2417,15 @@ Please enter a name: UserList - + Users online: %1 + + + Users in this room: %1 + + WndDeckEditor @@ -2443,7 +2510,20 @@ Please enter a name: - + + + Error + + + + + + The deck could not be saved. +Please check that the directory is writable and try again. + + + + Save deck diff --git a/cockatrice/translations/cockatrice_es.ts b/cockatrice/translations/cockatrice_es.ts index 0457d2f2..5e99e46a 100644 --- a/cockatrice/translations/cockatrice_es.ts +++ b/cockatrice/translations/cockatrice_es.ts @@ -4,57 +4,56 @@ AppearanceSettingsPage - + Zone background pictures Imagenes de la zona de fondo - + Path to hand background: Ruta a la imagen de fondo de la mano: - + Path to stack background: Ruta a la imagen de fondo de la pila: - + Path to table background: Ruta a la imagen de fondo de la mesa: - + Path to player info background: Ruta a la imagen de fondo de la información del jugador: - + Path to picture of card back: Ruta al reverso de las cartas: - + Hand layout Disposición de la mano - + Display hand horizontally (wastes space) Mostrar la mano horizontalmente (desperdicia espacio) - + Table grid layout Disposición de la rejilla de la mesa - Economical layout - Disposición Económica + Disposición Económica - + Invert vertical coordinate Invertir coordenada vertical @@ -63,26 +62,26 @@ Disposición económica - + Zone view layout Distribución de la zona de visionado - + Sort by name Ordenar por nombre - + Sort by type Ordenar por tipo - - - - - + + + + + Choose path Elija ruta @@ -141,112 +140,117 @@ CardItem - + + &Play + + + + &Tap &Girar - + &Untap &Enderezar - + Toggle &normal untapping Alternar enderezamiento &normal - + &Flip &Voltear - + &Clone &Clonar - + &Attach to card... Ane&xar a una carta... - + Ctrl+A Ctrl+A - + Unattac&h Desane&xar - + Set &P/T... Establecer &F/R... - + &Set annotation... E&scribir anotación... - + red rojo - + yellow amarillo - + green verde - + &Add counter (%1) &Añadir contador (%1) - + &Remove counter (%1) &Quitar contador (%1) - + &Set counters (%1)... E&stablecer contadores (%1)... - + &top of library &parte superior de la biblioteca - + &bottom of library &fondo de la biblioteca - + &graveyard &cementerio - + Ctrl+Del Ctrl+Del - + &exile &exilio - + &Move to &Mover a @@ -567,29 +571,24 @@ ChatChannelSelector - Chat channels - Canales de Chat + Canales de Chat - Joi&n - E&ntrar + E&ntrar - Channel - Canal + Canal - Description - Descripción + Descripción - Players - Jugadores + Jugadores @@ -803,12 +802,12 @@ Crear partida - + Error Error - + Server error. Error del servidor. @@ -950,9 +949,9 @@ DlgSettings - - - + + + Error Error @@ -969,47 +968,47 @@ La ruta a tu directorio de imagenes de las cartas es invalida. - + Your card database is invalid. Would you like to go back and set the correct path? Tu base de datos de cartas es invalida. ¿Deseas volver y seleccionar la ruta correcta? - + The path to your deck directory is invalid. Would you like to go back and set the correct path? La ruta a tu directorio de mazos es invalida. ¿Deseas volver y seleccionar la ruta correcta? - + The path to your card pictures directory is invalid. Would you like to go back and set the correct path? La ruta a tu directorio de imagenes de las cartas es invalida.¿Deseas volver y seleccionar la ruta correcta? - + Settings Preferencias - + General General - + Appearance Apariencia - + User interface Interfaz de usuario - + Messages Mensajes - + &Close &Cerrar @@ -1017,65 +1016,69 @@ GameSelector - + C&reate C&rear - + &Join E&ntrar - - - - + + + + Error Error - + Wrong password. Contraseña incorrecta. - + Spectators are not allowed in this game. No se permiten espectadores en esta partida. - + The game is already full. La partida no tiene plazas libres. - + The game does not exist any more. La partida ya no existe. - + Join game Entrar en la partida - + Password: Contraseña: - + Games Partidas - - &Show full games - &Ver partidas sin plazas libres + + Show &full games + - + &Show full games + &Ver partidas sin plazas libres + + + J&oin as spectator Entrar como e&spectador @@ -1083,7 +1086,7 @@ GameView - + Esc Esc @@ -1190,136 +1193,161 @@ MainWindow - + Number of players Número de jugadores - + Please enter the number of players. Por favor, introduzca el número de jugadores. - - + + Player %1 Jugador %1 - + About Cockatrice Acerca de Cockatrice - - - <font size="8"><b>Cockatrice</b></font><br>Version %1<br><br><br><b>Authors:</b><br>Max-Wilhelm Bruker<br>Marcus Schütz<br>Marius van Zundert<br><br><b>Translators:</b><br>Spanish: Gocho<br>Portugese: Milton Gonçalves<br> - - - - - + Version %1 + + + + + Authors: + + + + + Translators: + + + + + Spanish: + + + + + Portugese: + + + + + French: + + + + + + + Error Error - + Server timeout Tiempo de espera del servidor agotado - + Invalid login data. Datos de conexión invalidos. - + Socket error: %1 Error del Socket: %1 - + Protocol version mismatch. Local version: %1, remote version: %2. La versión del protocolo es diferente. Version local: %1, version remota: %2. - + Connecting to %1... Conectando a %1... - + Disconnected Desconectado - + Logged in at %1 Conectado en %1 - + &Connect... &Conectar... - + &Disconnect &Desconectar - + Start &local game... Empezar partida &local... - + &Deck editor Editor de &mazos - + &Full screen &Pantalla completa - + Ctrl+F CTRL+F - + &Settings... &Preferencias... - + &Exit &Salir - + &Cockatrice &Cockatrice - + &About Cockatrice &Acerca de Cockatrice - + &Help A&yuda - + Are you sure? ¿Estás seguro? - + There are still open games. Are you sure you want to quit? Todavía hay partidas abiertas. ¿Estás seguro que quieres salir? @@ -1427,88 +1455,93 @@ de la pila - + + %1 gives %2 control over %3. + + + + %1 puts %2 into play%3. %1 pone %2 en juego%3. - + %1 puts %2%3 into graveyard. %1 pone %2%3 en el cementerio. - + %1 exiles %2%3. %1 exilia %2%3. - + %1 moves %2%3 to hand. %1 mueve %2%3 a la mano. - + %1 puts %2%3 into his library. %1 pone %2%3 en la biblioteca. - + %1 puts %2%3 on bottom of his library. %1 pone %2%3 en la parte inferior de su biblioteca. - + %1 puts %2%3 on top of his library. %1 pone %2%3 en la parte superior de su biblioteca. - + %1 puts %2%3 into his library at position %4. %1 pone %2%3 en su biblioteca en la posición %4. - + %1 moves %2%3 to sideboard. %1 mueve %2%3 a la reserva. - + %1 plays %2%3. %1 juega %2%3. - - + + a card una carta - + %1 flips %2 face-down. %1 voltea %2 boca abajo. - + %1 flips %2 face-up. %1 voltea %2 boca arriba. - + %1 attaches %2 to %3's %4. %1 anexa %2 a el %4 de %3. - + %1 unattaches %2. %1 desanexa %2. - + %1 points from %2's %3 to %4's %5. %1 apunta desde el %3 de %2 al %5 de %4. - + %1 places %n counter(s) (%2) on %3 (now %4). %1 pone un contador (%2) en %3 (ahora %4). @@ -1516,7 +1549,7 @@ - + %1 removes %n counter(s) (%2) from %3 (now %4). %1 remueve un contador (%2) de %3 (ahora %4). @@ -1524,37 +1557,37 @@ - + red rojo - + yellow amarillo - + green verde - + %1 sets counter %2 to %3 (%4%5). %1 establece los contadores de %2 a %3 (%4%5). - + %1 sets PT of %2 to %3. %1 establece F/R de %2 a %3. - + %1 sets annotation of %2 to %3. %1 establece la anotación de %2 a %3. - + %1 is looking at the top %2 cards %3. %1 esta mirando las primeras %2 cartas de %3. @@ -1619,52 +1652,52 @@ %1 roba %2 cartas. - + %1 destroys %2. %1 destruye %2. - + %1 creates token: %2%3. %1 crea una ficha: %2%3. - + %1 points from %2's %3 to %4. %1 apunta desde el %3 de %2 a %4. - + %1 %2 %3. %1 %2 %3. - + %1 is looking at %2. %1 está mirando: %2. - + %1 stops looking at %2. %1 termina de mirar: %2. - + %1 reveals %2 to %3. %1 revela %2 a %3. - + %1 reveals %2. %1 revela %2. - + ending phase fase de fin de turno - + It is now %1's turn. Es el turno de %1. @@ -1674,102 +1707,102 @@ %1 baraja su biblioteca. - + %1 randomly reveals %2%3 to %4. %1 revela aleatoriamente %2%3 a %4. - + %1 randomly reveals %2%3. %1 revela aleatoriamente %2%3. - + %1 reveals %2%3 to %4. %1 revela %2%3 a %4. - + %1 reveals %2%3. %1 revela %2%3. - + untap step paso de enderezar - + upkeep step paso de mantenimiento - + draw step paso de robar - + first main phase primera fase principal - + beginning of combat step paso de inicio de combate - + declare attackers step paso de declarar atacantes - + declare blockers step paso de declarar bloqueadores - + combat damage step paso de daño de combate - + end of combat step paso de fin de combate - + second main phase segunda fase principal - + It is now the %1. Ahora es el %1. - + taps gira - + untaps endereza - + %1 sets %2 to not untap normally. %1 establece que %2 no se endereze normalmente. - + %1 sets %2 to untap normally. %1 establece que %2 se endereze normalmente. - + his permanents sus permanentes @@ -1777,22 +1810,22 @@ MessagesSettingsPage - + &Add &Añadir - + &Remove &Quitar - + Add message Añadir mensaje - + Message: Mensaje: @@ -1858,123 +1891,123 @@ Player - - - + + + Move to &top of library Mover a la &parte superior de la biblioteca - - - + + + Move to &bottom of library Mover al &fondo de la biblioteca - - + + Move to &graveyard Mover al &cementerio - + &View library &Ver biblioteca - + Reveal &library to Revelar &biblioteca a - + Reveal t&op card to Revelar la carta &superior de la biblioteca a - + Move top cards to &graveyard... Mover cartas de la parte s&uperior de la biblioteca al cementerio... - + F3 F3 - + View &top cards of library... Ver cartas de la parte &superior de la biblioteca... - + &View graveyard Ver &Cementerio - + F4 F4 - + &View sideboard Ver &sideboard - + Player "%1" Jugador "%1" - + &Hand &Mano - + &Library &Biblioteca - + &Graveyard &Cementerio - + &Sideboard &Reserva - + View top cards of library Ver cartas de la parte superior de la biblioteca - + Number of cards: Número de cartas: - + &Draw card &Robar carta - + &View exile Ver &exilio - + &Exile &Exilio - - + + Move to &hand Mover a la m&ano @@ -1983,98 +2016,98 @@ Mover al &cementerio - - + + Move to &exile Mover al &exilio - + Ctrl+W Ctrl+W - + Ctrl+D Ctrl+D - + D&raw cards... &Robar cartas... - + Ctrl+E Ctrl+E - + Take &mulligan Hacer &mulligan - + Ctrl+M Ctrl+M - + &Shuffle &Barajar - + Ctrl+S Ctrl+S - + &Counters &Contadores - + &Untap all permanents &Enderezar todos los permanentes - + Ctrl+U Ctrl+U - + R&oll die... &Lanzar dado... - + Ctrl+I Ctrl+I - + &Create token... Crear &Ficha... - + Ctrl+T Ctrl+T - + C&reate another token C&rea otra ficha - + Ctrl+G Ctrl+G - + S&ay D&ecir @@ -2083,85 +2116,90 @@ Mover cartas superiores al ce&menterio... - + Move top cards to &exile... Mover cartas superiores al &exilio... - + + Put top card on &bottom + + + + &Reveal to &Revelar a - + Reveal r&andom card to Revelar carta &aleatoriamente a - + C&ard C&arta - + &All players &Todos los jugadores - + Draw cards Robar cartas - - - - + + + + Number: Número: - + Move top cards to grave Mover cartas superiores al cementerio - + Move top cards to exile Mover cartas superiores al exilio - + Roll die Lanzar dado - + Number of sides: Número de caras: - + Set power/toughness Establecer fuerza/resistencia - + Please enter the new PT: Por favor, introduzca la nueva F/R: - + Set annotation Escribir anotación - + Please enter the new annotation: Por favor, introduza la nueva anotación: - + Set counters Establecer contadores @@ -2252,12 +2290,44 @@ Tiempo de subida + + RoomSelector + + + Rooms + + + + + Joi&n + E&ntrar + + + + Room + + + + + Description + Descripción + + + + Players + Jugadores + + + + Games + Partidas + + ServerMessageLog - Server messages - Mensajes del servidor + Mensajes del servidor @@ -2276,24 +2346,20 @@ TabChatChannel - C&hat channel - Canal de c&hat + Canal de c&hat - &Leave channel - &Abandonar el canal + &Abandonar el canal - %1 has joined the channel. - %1 se ha unido al canal. + %1 se ha unido al canal. - %1 has left the channel. - %1 ha abandonado el canal. + %1 ha abandonado el canal. @@ -2475,10 +2541,43 @@ Por favor, introduzca un nombre: Hablando con %1 + + TabRoom + + + &Say: + &Decir: + + + + Chat + + + + + &Room + + + + + &Leave room + + + + + %1 has joined the room. + + + + + %1 has left the room. + + + TabServer - + Server Servidor @@ -2486,35 +2585,55 @@ Por favor, introduzca un nombre: UserInfoBox - + Location: Localización: - + User level: Nivel de usuario: + + + Administrator + + + + + Judge + + + + + Registered user + + + + + Unregistered user + + UserInterfaceSettingsPage - + General interface settings Preferencias generales de la interfaz - + &Double-click cards to play them (instead of single-click) &Doble click en las cartas para jugarlas (en lugar de un solo click) - + Animation settings Opciones de animación - + &Tap/untap animation Animación de &girar/enderezar @@ -2522,10 +2641,15 @@ Por favor, introduzca un nombre: UserList - + Users online: %1 Usuarios online: %1 + + + Users in this room: %1 + + WndDeckEditor @@ -2610,7 +2734,20 @@ Por favor, introduzca un nombre: Cargar mazo - + + + Error + Error + + + + + The deck could not be saved. +Please check that the directory is writable and try again. + + + + Save deck Guardar mazo diff --git a/cockatrice/translations/cockatrice_fr.ts b/cockatrice/translations/cockatrice_fr.ts index 53f8d1ad..874e2d48 100644 --- a/cockatrice/translations/cockatrice_fr.ts +++ b/cockatrice/translations/cockatrice_fr.ts @@ -4,83 +4,78 @@ AppearanceSettingsPage - + Zone background pictures - + Path to hand background: - + Chemin vers fond de la main - + Path to stack background: - + Path to table background: - + Path to player info background: - + Path to picture of card back: - + Hand layout - + Display hand horizontally (wastes space) - + Table grid layout - - Economical layout - - - - + Invert vertical coordinate - + Zone view layout - + Voir disposition de la zone - + Sort by name - + tri par nom - + Sort by type - + tri par type - - - - - + + + + + Choose path - + Choisir le chemin @@ -88,27 +83,27 @@ Name - + Nom Sets - + Sets Mana cost - + Cout de mana Card type - + Type de carte P/T - + F/E @@ -116,135 +111,140 @@ Name: - + Nom: Mana cost: - + Cout de mana: Card type: - + Type de carte P / T: - + F / E: CardItem - + + &Play + + + + &Tap - + &Engager - + &Untap - + &Dégager - + Toggle &normal untapping - + &Flip - + &Inverser - + &Clone - + &Clone - + &Attach to card... - + &Attacher à la carte - + Ctrl+A - + Ctrl+A - + Unattac&h - + Détac&her - + Set &P/T... - + Fixer &F/E... - + &Set annotation... - + Fi&xer annotation - + red - + rouge - + yellow - + jaune - + green - + vert - + &Add counter (%1) - + &Ajouter compteur (%1) - + &Remove counter (%1) - + &Retirer compteur (%1) - + &Set counters (%1)... - + &Fixer compteurs (%1)... - + &top of library - + Dessus de la &Bibliothèque - + &bottom of library - + &Dessous de la bibliothèque - + &graveyard - + &Cimetière - + Ctrl+Del - + Ctrl+Del - + &exile - + &exiler - + &Move to - + &Aller à @@ -253,109 +253,109 @@ his hand nominative - + sa main %1's hand nominative - + main de %1 of his hand genitive - + de sa main of %1's hand genitive - + de la main de %1 his hand accusative - + sa main %1's hand accusative - + main de %1 his library nominative - + de sa bibliothèque %1's library nominative - + bibliothèque de %1 of his library genitive - + de sa bibliothèque of %1's library genitive - + de la bibliothèque de %1 his library accusative - + de sa bibliothèque %1's library accusative - + Bibliothèque de %1 his graveyard nominative - + son cimetière %1's graveyard nominative - + le cimetière de %1 of his graveyard genitive - + de son cimetière of %1's graveyard genitive - + du cimetière de %1 his graveyard accusative - + son cimetière %1's graveyard accusative - + le cimetière de %1 @@ -433,29 +433,24 @@ ChatChannelSelector - Chat channels - + Canaux de discussion - Joi&n - + &Rejoindre - Channel - + Canal - Description - + Description - Players - + Joueurs @@ -463,32 +458,32 @@ &Set counter... - + &Fixer les compteurs Ctrl+L - + Ctrl+L F11 - + F11 F12 - + F12 Set counter - + Fixer compteurs New value for counter '%1': - + Nouvelle valeur pour le compteur '%1': @@ -496,12 +491,12 @@ Number - + Nombre Card - + Carte @@ -509,22 +504,22 @@ Load &local deck - + Charger un deck local Load d&eck from server - + Charger un d&eck depuis le serveur Ready to s&tart - + Pret à démarrer Load deck - + Charger deck @@ -532,7 +527,7 @@ Caching card pictures... - + Mise en cache des images @@ -540,37 +535,37 @@ Card name: - + Nom de la carte: Card text: - + Texte de la carte: Card type (OR): - + Type de la carte (OR): Color (OR): - + Couleur (OR): O&K - + O&K &Cancel - + &Annuler Card search - + Recherche de carte @@ -578,37 +573,37 @@ &Host: - + &Hôte: &Port: - + &Port: Player &name: - + &Nom du joueur: P&assword: - + Mot de p&asse: &OK - + &OK &Cancel - + &Annuler Connect to server - + Connecter au serveur @@ -616,67 +611,67 @@ &Description: - + &Description: &Password: - + Mot de &Passe: P&layers: - + &Spectators allowed - + &Spectateurs autorisés Spectators &need a password to join - + Les spectateurs ont besoin d'un mot de passe pour rejoindre Spectators can &chat - + Les spectateurs peuvent discuter Spectators see &everything - + Les spectateurs p&euvent tout voir Spectators - + Spectateurs &OK - + &OK &Cancel - + &Annuler Create game - + Créer partie - + Error - + Erreur - + Server error. - + Erreur serveur. @@ -684,82 +679,82 @@ &Name: - + &Nom Token - + Jeton C&olor: - + C&ouleur: white - + blanc blue - + bleu black - + noir red - + rouge green - + vert multicolor - + multicolor colorless - + incolore &P/T: - + &F/E: &Annotation: - + &Annotation: &Destroy token when it leaves the table - + &Detruire le jeton quand il quitte la table &OK - + &OK &Cancel - + &Annuler Create token - + Créer jeton @@ -767,32 +762,32 @@ &Refresh - + &Rafraichir &OK - + &OK &Cancel - + &Annuler Load deck from clipboard - + Charger deck depuis le presse-papier Error - + Erreur Invalid deck list. - + Deck list invalide. @@ -800,146 +795,151 @@ O&K - + O&K &Cancel - + &Annuler Load deck - + Charger deck DlgSettings - - - + + + Error - + Erreur - + Your card database is invalid. Would you like to go back and set the correct path? - + Votre base de carte est invalide. Voulez vous reparamétrer le chemin d'accès? - + The path to your deck directory is invalid. Would you like to go back and set the correct path? - + Le chemin d'accès pour le répertoire de votre deck est invalide. Voulez vous reparamétrer le chemin d'accès? - + The path to your card pictures directory is invalid. Would you like to go back and set the correct path? - + Le chemin d'accès pour le répertoire de vos images est invalide. Voulez vous reparamétrer le chemin d'accès? - + Settings - + Paramètres - + General - + Géneral - + Appearance - + Apparance - + User interface - + Interface utilisateur - + Messages - + Messages - + &Close - + &Fermer GameSelector - - - - + + + + Error - + Erreur - + Wrong password. - + Mauvais mot de passe - + Spectators are not allowed in this game. - + Les spectateurs ne sont pas autorisés dans cette partie - + The game is already full. - + Cette partie est déjà pleine. - + The game does not exist any more. - + La partie n'existe plus. - + Join game - + Rejoindre partie - + Password: - + Mot de passe: - + Games + Parties + + + + Show &full games - &Show full games - + toutes ou complèetes? + &Montrer toutes les parties - + C&reate - + C&réer - + &Join - + Re&joindre - + J&oin as spectator - + J&oindre en tant que spectateur GameView - + Esc - + Esc @@ -947,47 +947,47 @@ yes - + oui yes, free for spectators - + oui, libre pour les spectateurs no - + non not allowed - + non autorisé Description - + Description Creator - + Créateur Password - + Mot de passe Players - + Joueurs Spectators - + Spectateurs @@ -996,186 +996,216 @@ English - + Anglais Choose path - + Choisir chemin d'accès Personal settings - + Paramètres personnels Language: - + Langage Download card pictures on the fly - + Télécharger les images de cartes à la volée Paths - + Chemins Decks directory: - + Répertoire des decks Pictures directory: - + Répertoire des images Path to card database: - + Chemin vers la base des cartes MainWindow - + Number of players - + Nombre de joueurs - + Please enter the number of players. - + Entrez s'il vous plait le nombre de joueurs - - + + Player %1 - + Joueur %1 - + About Cockatrice - + à propos de Cockatrice - <font size="8"><b>Cockatrice</b></font><br>Version %1<br><br><br><b>Authors:</b><br>Max-Wilhelm Bruker<br>Marcus Schütz<br>Marius van Zundert<br><br><b>Translators:</b><br>Spanish: Gocho<br>Portugese: Milton Gonçalves<br> - + <font size="8"><b>Cockatrice</b></font><br>Version %1<br><br><br><b>Auteurs:</b><br>Max-Wilhelm Bruker<br>Marcus Schütz<br>Marius van Zundert<br><br><b>Tranducteurs:</b><br>Espagnol: Gocho<br>Portugais: Milton Gonçalves<br>Portugais: Milton Gonçalves<br>Français: Yannick HAMMER<br> - - - + Version %1 + + + + + Authors: + + + + + Translators: + + + + + Spanish: + + + + + Portugese: + + + + + French: + + + + + + + Error - + Erreur - + Server timeout - + Délai de la demande dépassé - + Invalid login data. - - - - - Socket error: %1 - - - - - Protocol version mismatch. Local version: %1, remote version: %2. - + Information de connexion érronée - Connecting to %1... - + Socket error: %1 + Erreur de socket: %1 - - Disconnected - - - - - Logged in at %1 - + + Protocol version mismatch. Local version: %1, remote version: %2. + Version de protocole différente. Version locale: %1 ,version distante: %2. - &Connect... - + Connecting to %1... + Connexion à %1... - &Disconnect - + Disconnected + Déconnecté - Start &local game... - - - - - &Deck editor - - - - - &Full screen - - - - - Ctrl+F - - - - - &Settings... - - - - - &Exit - - - - - &Cockatrice - + Logged in at %1 + Connecté à %1 - &About Cockatrice - + &Connect... + à verifier + &Connecter... + &Disconnect + &Déconnecter + + + + Start &local game... + Démarrer une partie &locale... + + + + &Deck editor + Editeur de &deck + + + + &Full screen + &Plein écran + + + + Ctrl+F + Ctrl+F + + + + &Settings... + &Paramètres + + + + &Exit + &Quitter + + + + &Cockatrice + &Cockatrice + + + + &About Cockatrice + &A propos de Cockatrice + + + &Help - + A&ide - + Are you sure? - + Etes vous sur? - + There are still open games. Are you sure you want to quit? - + Il y a encore des parties en cours. Etes vous sure de vouloir quitter? @@ -1183,472 +1213,493 @@ Connecting to %1... - + Connexion à %1... Connected. - + Connecté. Disconnected from server. - + Déconnecté du serveur. Invalid password. - + Mot de passe invalide Protocol version mismatch. Client: %1, Server: %2 - + Version de protocole différente. Version locale: %1 ,version distante: %2. Protocol error. - + Erreur de protocole. You have joined game #%1. - + Vous avez rejoins la partie #%1. %1 has joined the game. - + %1 a rejoins la partie. %1 has left the game. - + %1 a quitté la partie. The game has been closed. - + La partie a été fermée. %1 is now watching the game. - + %1 est maintenant spectateur. %1 is not watching the game any more. - + %1 n'est plus spectateur. %1 has loaded a local deck. - + %1 a chargé un deck local. %1 has loaded deck #%2. - + %1 a chargé le deck #%2. %1 is ready to start the game. - + %1 est prêt à démarrer la partie. %1 is not ready to start the game any more. - + %1 n'est plus prêt à démarrer la partie. %1 has conceded the game. - + partie ou jeu + %1 a concédé la partie. The game has started. - + Le jeu a commencé. %1 shuffles his library. - + %1 mélange sa bibliothèque. %1 rolls a %2 with a %3-sided die. - + is it always a dice? + %1 lance un %2 avec %3 faces. %1 draws a card. - + %1 pioche une carte. %1 draws %2 cards. - + %1 pioche %2 cartes. from table - + de la table from graveyard - + depuis le cimetière from exile - + depuis la zone d'éxil from hand - + depuis la main the bottom card of his library - + la carte du dessous de sa bibliothèque from the bottom of his library - + depuis le dessous de sa bibliothèque the top card of his library - + le carte du dessus de sa bibliothèque from the top of his library - + du dessus de sa bibliothèque from library - + de la bibliothèque from sideboard - + de la réserve from the stack - + de la pile - + %1 puts %2 into play%3. - + what is %3? plz exemple + %1 met %2 en jeu %3 - + %1 puts %2%3 into graveyard. - + %1 met %2%3 dans le cimetière - + %1 exiles %2%3. - + %1 exile %2%3. - + %1 moves %2%3 to hand. - + %1 déplace %2%3 dans sa main - + %1 puts %2%3 into his library. - + %1 met %2%3 dans sa bibliothèque. - + %1 puts %2%3 on bottom of his library. - - - - - %1 puts %2%3 on top of his library. - - - - - %1 puts %2%3 into his library at position %4. - - - - - %1 moves %2%3 to sideboard. - - - - - %1 plays %2%3. - + %1 met %2%3 en dessous de sa bibliothèque. - + %1 puts %2%3 on top of his library. + %1 met %2%3 au dessus de sa bibliothèque. + + + + %1 puts %2%3 into his library at position %4. + %1 met %2%3 dans sa bibliothèque à la position %4. + + + + %1 moves %2%3 to sideboard. + %1 déplace %2%3 vers la réserve. + + + + %1 plays %2%3. + %1 joue %2%3. + + + + a card + une carte + + + + %1 gives %2 control over %3. - + %1 flips %2 face-down. - + %1 retourne %2 face cachée. - + %1 flips %2 face-up. - + %1 retourne %2 face visible. - + %1 destroys %2. - + %1 détruit %2. - + %1 attaches %2 to %3's %4. - + need exemple + %1 attache %2 à - + %1 unattaches %2. - + %1 détache %2. - + %1 creates token: %2%3. - + %1 crée un jeton %2%3. - + %1 points from %2's %3 to %4. - + need exemple + %1 désigne - + %1 points from %2's %3 to %4's %5. + need exemple - + %1 places %n counter(s) (%2) on %3 (now %4). + need exemple - + %1 removes %n counter(s) (%2) from %3 (now %4). + need exemple - + %1 retire %n compteur(s) (%2) depuis %3 (maintenant %4). - + red - + rouge - + yellow - + jaune - + green - + vert - + his permanents - + ses permanents - + %1 %2 %3. - + wtf ? + %1 %2 %3. - + taps - + engage - + untaps - + dégage - + %1 sets counter %2 to %3 (%4%5). - + need exemple + %1 met les compteurs %2 à %3 (%4%5). - + %1 sets %2 to not untap normally. - + need exemple + %1 met %2 pour ne pas se dégager normalement. - + %1 sets %2 to untap normally. - + %1 met %2 pour ne se dégager normalement. - + %1 sets PT of %2 to %3. - + exemple plz + %1 - + %1 sets annotation of %2 to %3. - + %1 met l'annotation de %2 à %3. - + %1 is looking at the top %2 cards %3. - + exemple plz + %1 regarde les %2 cartes du dessus de%3. - + %1 is looking at %2. - + exemple plz + %1 regarde %2. - + %1 stops looking at %2. - + need exemple to be sure + %1 arrète de regarder à %2 - + %1 reveals %2 to %3. - + %1 révèle %2 à %3. - + %1 reveals %2. - + %1 révèle %2. - + %1 randomly reveals %2%3 to %4. - + %1 révèle aléatoirement %2%3 à %4. - + %1 randomly reveals %2%3. - + %1 révèle aléatoirement %2%3. - + %1 reveals %2%3 to %4. - + %1 révèle %2%3 à %4. - + %1 reveals %2%3. - + %1 révèle %2%3 - + It is now %1's turn. - - - - - untap step - - - - - upkeep step - - - - - draw step - - - - - first main phase - + C'est maintenant le tour de %1. - beginning of combat step - + untap step + étape de dégagement - declare attackers step - + upkeep step + étape d'entretien - declare blockers step - + draw step + étape de pioche - combat damage step - + first main phase + première phase principale - end of combat step - + beginning of combat step + étape de début du combat - second main phase - + declare attackers step + étape de déclaration des attaquants - ending phase - + declare blockers step + étape de déclaration des attaquants + + + + combat damage step + étape de répartition des blessures + end of combat step + étape de fin de combat + + + + second main phase + seconde phase principale + + + + ending phase + phase de fin + + + It is now the %1. - + need exemple + C'est maintenant %1. MessagesSettingsPage - + Add message - + Ajouter message - + Message: - + Message: - + &Add - + &Ajouter - + &Remove - + &Enlever @@ -1656,360 +1707,366 @@ Untap step - + Étape de dégagement Upkeep step - + Étape d'entretien Draw step - + Étape de pioche First main phase - + Première phase principale Beginning of combat step - + Étape de début du combat Declare attackers step - + Étape de déclaration des attaquants Declare blockers step - + Étape de déclaration des attaquants Combat damage step - + Étape de répartition des blessures End of combat step - + Étape de fin de combat Second main phase - + Seconde phase principale End of turn step - + Étape de fin de tour Player - - - &View graveyard - - - - - &View exile - - - - - Player "%1" - - - &Graveyard - + &View graveyard + &Voir le cimetière - &Exile - + &View exile + &Voir la zone d'exil + + + + Player "%1" + Joueur "%1" + + + + &Graveyard + &Cimetière - - - Move to &top of library - - - - - - - Move to &bottom of library - - - - - - Move to &graveyard - + &Exile + &Exil - Move to &exile - + + Move to &top of library + Déplacer vers le &dessus de la bibliothèque + + + + + + Move to &bottom of library + Déplacer en des&sous de la bibliothèque + + + + + Move to &graveyard + Déplacer vers le cimetière - Move to &hand - - - - - &View library - + Move to &exile + Déplacer vers l'&exil + - View &top cards of library... - - - - - Reveal &library to - + Move to &hand + Déplacer vers la &main - Reveal t&op card to - + &View library + &Voir la bibliothèque - &View sideboard - + View &top cards of library... + Voir les cartes du &dessus de la bibliothèque... - &Draw card - + Reveal &library to + Révéler la &bibliothèque à - D&raw cards... - + Reveal t&op card to + Révéler la carte du &dessus à - Take &mulligan - + &View sideboard + &Voir la réserve - &Shuffle - + &Draw card + &Piocher carte - Move top cards to &graveyard... - + D&raw cards... + P&iocher plusieurs cartes... - Move top cards to &exile... - + Take &mulligan + Prendre un &mulligan + + + + &Shuffle + &Mélanger - &Hand - + Move top cards to &graveyard... + Déplacer les cartes du dessus vers le &cimetière... - &Reveal to - + Move top cards to &exile... + Déplacer les cartes du dessus vers le &exil... - Reveal r&andom card to - - - - - &Sideboard + Put top card on &bottom - &Library - + &Hand + &Main - &Counters - + &Reveal to + &Révéler à + + + + Reveal r&andom card to + Révéler &aléatoirement une carte à - &Untap all permanents - + &Sideboard + Ré&serve - R&oll die... - + &Library + &Bibliothèque - &Create token... - - - - - C&reate another token - + &Counters + &Compteurs + &Untap all permanents + &Dégager tous les permanents + + + + R&oll die... + Lancer le &dé... + + + + &Create token... + &Créer un jeton... + + + + C&reate another token + C&réer un autre jeton + + + S&ay - + D&ire - + C&ard - + C&arte - + &All players - - - - - F3 - - - - - Ctrl+W - - - - - F4 - - - - - Ctrl+D - + &Tout les joueurs - Ctrl+E - + F3 + F3 - Ctrl+M - + Ctrl+W + Ctrl+W - Ctrl+S - + F4 + F4 - Ctrl+U - + Ctrl+D + Ctrl+D - Ctrl+I - + Ctrl+E + Ctrl+E - Ctrl+T - + Ctrl+M + Ctrl+M + Ctrl+S + Ctrl+S + + + + Ctrl+U + Ctrl+U + + + + Ctrl+I + Ctrl+I + + + + Ctrl+T + Ctrl+T + + + Ctrl+G - + Ctrl+G - + View top cards of library - + Voir les cartes du dessus de la bibliothèque - + Number of cards: - + Nombre de cartes: - + Draw cards - + Piocher des cartes - - - - + + + + Number: - + Nombre: - + Move top cards to grave - + Déplacer les cartes du dessus dans le cimetière - + Move top cards to exile - + Déplacer les cartes du dessus vers le exil - + Roll die - + Lancer le dé... - + Number of sides: - + Nombre de faces: - + Set power/toughness - + Fixer force/endurance - + Please enter the new PT: - + maybe better with / + Entrer la nouvelle F/E - + Set annotation - + Mettre annotation - + Please enter the new annotation: - + Entrez la nouvelle annotation - + Set counters - + Mettre des compteurs @@ -2017,27 +2074,27 @@ Player name - + Nom du joueur Deck - + Deck --- - + --- local - + local #%1 - + #%1 @@ -2050,22 +2107,22 @@ Sideboard - + Réserve Cockatrice decks (*.cod) - + Deck Cockatrice (*.cod) Plain text decks (*.dec *.mwDeck) - + Deck au format texte (*.dec *.mwDeck) All files (*.*) - + Tous les fichiers (*.*) @@ -2073,25 +2130,58 @@ Name - + Nom ID - + ID Upload time + nedd exemple + + RoomSelector + + + Rooms + + + + + Joi&n + &Rejoindre + + + + Room + + + + + Description + Description + + + + Players + Joueurs + + + + Games + Parties + + ServerMessageLog - Server messages - + Messages serveur @@ -2099,35 +2189,31 @@ Short name - + Nom court Long name - + Nom long TabChatChannel - C&hat channel - + C&anal de discussion - &Leave channel - + &Quitter le canal - %1 has joined the channel. - + %1 a rejoint le canal. - %1 has left the channel. - + %1 a quitté le canal. @@ -2135,66 +2221,67 @@ Local file system - + Système de fichier local Server deck storage - + Serveur de stockage de deck Open in deck editor - + Ouvrir l'éditeur de deck Upload deck - + Envoyer deck Download deck - + Télécharger deck New folder - + Nouveau dossier Delete - + Supprimer Enter deck name - + Entrez le nom du deck This decklist does not have a name. Please enter a name: - + Cette decklist n'a pas de nom. +Entrez un nom s'il vous plait: Unnamed deck - + Deck sans nom Name of new folder: - + Nom du nouveau dossier: Deck storage - + Stockage de deck @@ -2202,87 +2289,87 @@ Please enter a name: &Game - + &Partie Next &phase - + &Prochaine phase Ctrl+Space - + Ctrl+Espace Next &turn - + Prochain &Tour Ctrl+Return - + Ctrl+Retour Ctrl+Enter - + Ctrl+Entrée &Remove all local arrows - + &Retirer toutes les fléches locale Ctrl+R - + Ctrl+R &Concede - + &Concéder F2 - + F2 &Leave game - + &Quitter la partie &Say: - + &Dire: Concede - + Concéder Are you sure you want to concede this game? - + Etes vous sur de vouloir concéder la partie? Leave game - + Quitter la partie Are you sure you want to leave this game? - + Etes vous sur de vouloir quitter la partie? Game %1: %2 - + Partie %1:%2 @@ -2290,73 +2377,132 @@ Please enter a name: Personal &talk - + need exemple + &Discussion personnelle &Leave - + &Quitter %1 has left the server. - + %1 a quitté le serveur. Talking to %1 + Vous parlez à %1 + + + + TabRoom + + + &Say: + &Dire: + + + + Chat + + + + + &Room + + + + + &Leave room + + + + + %1 has joined the room. + + + + + %1 has left the room. TabServer - + Server - + Serveur UserInfoBox - + Location: + Localisation: + + + + User level: + Niveau utilisateur: + + + + Administrator - - User level: + + Judge + + + + + Registered user + + + + + Unregistered user UserInterfaceSettingsPage - + General interface settings - + Réglages généraux de l'interface - + &Double-click cards to play them (instead of single-click) - + &Double cliquer sur la carte pour la jouer (au lieu d'un simple clic) - + Animation settings - + Réglages des animations - + &Tap/untap animation - + Animation d'engagement et dégagement UserList - + Users online: %1 + Utilisateurs en ligne:%1 + + + + Users in this room: %1 @@ -2365,173 +2511,189 @@ Please enter a name: &Search... - + &Chercher... &Clear search - + &Effacer la recherche &Search for: - + &Rechercher: Deck &name: - + &Nom du deck: &Comments: - + &Commentaires: Deck editor [*] - + Editeur de deck [*] &New deck - + &Nouveau deck &Load deck... - + Char&ger deck... &Save deck - + &Sauvegarder le deck Save deck &as... - + Sauvegarder le deck &sous... Load deck from cl&ipboard... - + Charger deck depuis le &presse-papier... Save deck to clip&board - + Sauvegarder le deck dans le presse-papier &Print deck... - + Im&primer le deck... &Close - + &Fermer Ctrl+Q - + Ctrl+Q &Edit sets... - + &Editer les editions... &Deck - + &Deck &Card database - + Base des &cartes Add card to &maindeck - + Ajouter carte au &jeu Return - + Retour Enter - + Entrée Add card to &sideboard - + Ajouter carte à la ré&serve Ctrl+Return - + Ctrl+Retour Ctrl+Enter - + Ctrl+Entrée &Remove row - + &Retirer la ligne Del - + Supprimer &Increment number - + to check + &Incrémenter le nombre + - + + &Decrement number - + to check + &Décrementer la valeur - - + - Are you sure? - + Etes vous sur? The decklist has been modified. Do you want to save the changes? - + Le deck a été modifié. +Voulez vous enregistrer les modifications? Load deck + Charger deck + + + + + Error + Erreur + + + + + The deck could not be saved. +Please check that the directory is writable and try again. - + Save deck - + Sauvegarder le deck @@ -2547,17 +2709,17 @@ Do you want to save the changes? sort by name - + tri par nom sort by type - + tri par type shuffle when closing - + melanger en quittant diff --git a/cockatrice/translations/cockatrice_pt.ts b/cockatrice/translations/cockatrice_pt.ts index 67f79abd..5ff82cbf 100644 --- a/cockatrice/translations/cockatrice_pt.ts +++ b/cockatrice/translations/cockatrice_pt.ts @@ -4,81 +4,80 @@ AppearanceSettingsPage - + Zone background pictures Zona das imagens de fundo - + Path to hand background: Directorio da imagem de fundo da mão: - + Path to stack background: Directório da imagem de fundo da pilha: - + Path to table background: Directório da imagem de fundo do campo de batalha: - + Path to player info background: Directório da imagem de fundo da informação de jogador: - + Path to picture of card back: Directório da imagem do verso da carta: - + Hand layout Disposição da Mão - + Display hand horizontally (wastes space) Mostrar mão horizontalmente (desperdiça espaço) - + Table grid layout Esquema da mesa - Economical layout - Esquema económico + Esquema económico - + Invert vertical coordinate Inverter coordenada vertical - + Zone view layout Distribuição da zona de vizualização - + Sort by name Ordenar por nome - + Sort by type Ordenar por tipo - - - - - + + + + + Choose path Escolher directório @@ -137,112 +136,117 @@ CardItem - + + &Play + + + + &Tap &Virar - + &Untap Desv&irar - + Toggle &normal untapping A&lterar desvirar normalmente - + &Flip Vol&tar - + &Clone Copi&ar - + &Attach to card... Ane&xar a carta... - + Ctrl+A Ctrl+A - + Unattac&h De&sanexar - + Set &P/T... Definir &P/R... - + &Set annotation... Colocar &nota... - + red vermelho - + yellow amarelo - + green verde - + &Add counter (%1) Adicionar &marcador (%1) - + &Remove counter (%1) &Remover marcador (%1) - + &Set counters (%1)... &Denifir marcadores (%1)... - + &top of library Topo do &grimório - + &bottom of library &Fundo do grimório - + &graveyard &Cemitério - + Ctrl+Del Ctrl+Del - + &exile &Exílio - + &Move to M&over para @@ -433,29 +437,24 @@ ChatChannelSelector - Chat channels - Canais de Conversação + Canais de Conversação - Joi&n - E&ntrar + E&ntrar - Channel - Canal + Canal - Description - Descrição + Descrição - Players - Jogadores + Jogadores @@ -669,12 +668,12 @@ Criar jogo - + Error Erro - + Server error. Erro do servidor. @@ -816,54 +815,54 @@ DlgSettings - - - + + + Error Erro - + Your card database is invalid. Would you like to go back and set the correct path? A sua base de dados é inválida. Gostaria de voltar atrás e corrigir o directório? - + The path to your deck directory is invalid. Would you like to go back and set the correct path? O directório do seu deck é inválido. Gostaria de voltar atrás e corrigir o directório? - + The path to your card pictures directory is invalid. Would you like to go back and set the correct path? O directório das imagens das cartas é inválido. Gostaria de voltar atrás e corrigir o directório? - + Settings Definições - + General Geral - + Appearance Aparência - + User interface Interface do utilizador - + Messages Mensagens - + &Close &Fechar @@ -871,65 +870,69 @@ GameSelector - - - - + + + + Error Erro - + Wrong password. Password incorrecta. - + Spectators are not allowed in this game. Não são permitidos espectadores neste jogo. - + The game is already full. O jogo já se encontra cheio. - + The game does not exist any more. O jogo já não existe. - + Join game Entrar no jogo - + Password: Password: - + Games Jogos - - &Show full games - &Mostrar jogos cheios + + Show &full games + - + &Show full games + &Mostrar jogos cheios + + + C&reate &Criar - + &Join &Entrar - + J&oin as spectator Entrar como &espectador @@ -937,7 +940,7 @@ GameView - + Esc Esc @@ -1044,136 +1047,165 @@ MainWindow - + Number of players Número de jogadores - + Please enter the number of players. Por favor introduza o número de jogadores. - - + + Player %1 Jogador %1 - + About Cockatrice Sobre o Cockatrice - <font size="8"><b>Cockatrice</b></font><br>Version %1<br><br><br><b>Authors:</b><br>Max-Wilhelm Bruker<br>Marcus Schütz<br>Marius van Zundert<br><br><b>Translators:</b><br>Spanish: Gocho<br>Portugese: Milton Gonçalves<br> - <font size="8"><b>Cockatrice</b></font><br>Versão %1<br><br><br><b>Autores:</b><br>Max-Wilhelm Bruker<br>Marcus Schütz<br>Marius van Zundert<br><br><b>Tradutores:</b><br>Espanhol: Gocho<br>Português: Milton Gonçalves<br> + <font size="8"><b>Cockatrice</b></font><br>Versão %1<br><br><br><b>Autores:</b><br>Max-Wilhelm Bruker<br>Marcus Schütz<br>Marius van Zundert<br><br><b>Tradutores:</b><br>Espanhol: Gocho<br>Português: Milton Gonçalves<br> - - - + Version %1 + + + + + Authors: + + + + + Translators: + + + + + Spanish: + + + + + Portugese: + + + + + French: + + + + + + + Error Erro - + Server timeout Tempo do servidor esgotado - + Invalid login data. Informação de login incorrecta. - + Socket error: %1 Erro de ligação:%1 - + Protocol version mismatch. Local version: %1, remote version: %2. Versão dos protocolos incompatível. Versão local:%1, versão remota:%2. - + Connecting to %1... Ligando a %1... - + Disconnected Desligado - + Logged in at %1 Logado em %1 - + &Connect... &Ligar... - + &Disconnect &Desligar - + Start &local game... Começar &jogo local... - + &Deck editor &Editor de decks - + &Full screen Ecrã &inteiro - + Ctrl+F Ctrl+F - + &Settings... &Configurações... - + &Exit &Sair - + &Cockatrice &Cockatrice - + &About Cockatrice S&obre o Cockatrice - + &Help &Ajuda - + Are you sure? Tens a certeza? - + There are still open games. Are you sure you want to quit? Ainda há jogos abertos. Tem a certeza que deseja sair? @@ -1346,103 +1378,108 @@ da pilha - + %1 puts %2 into play%3. %1 coloca %2 em jogo %3. - + %1 puts %2%3 into graveyard. %1 coloca %2%3 no cemitério. - + %1 exiles %2%3. %1 exila %2%3. - + %1 moves %2%3 to hand. %1 move %2%3 para a mão. - + %1 puts %2%3 into his library. %1 coloca %2%3 no seu grimório. - + %1 puts %2%3 on bottom of his library. %1 coloca %2%3 no topo do seu grimório. - + %1 puts %2%3 on top of his library. %1 coloca %2%3 no topo do seu grimório. - + %1 puts %2%3 into his library at position %4. %1 coloca %2%3 no seu grimório na posição %4. - + %1 moves %2%3 to sideboard. %1 move %2%3 para o sideboard. - + %1 plays %2%3. %1 joga %2%3. - - + + a card uma carta - + + %1 gives %2 control over %3. + + + + %1 flips %2 face-down. %1 volta a face de %2 para baixo. - + %1 flips %2 face-up. %1 volta a face de %2 para cima. - + %1 destroys %2. %1 destroí %2. - + %1 attaches %2 to %3's %4. %1 anexa %2 a %4 de %3. - + %1 unattaches %2. %1 desanexa %2. - + %1 creates token: %2%3. %1 cria ficha: %2%3. - + %1 points from %2's %3 to %4. %1 aponta de %3 de %2 para %4. - + %1 points from %2's %3 to %4's %5. %1 aponta de %3 de %2 para %5 de %4. - + %1 places %n counter(s) (%2) on %3 (now %4). %1 coloca %n marcador (%2)de %3 (agora com %4). @@ -1450,7 +1487,7 @@ - + %1 removes %n counter(s) (%2) from %3 (now %4). %1 remove %n marcador (%2)de %3 (agora com %4). @@ -1458,172 +1495,172 @@ - + red vermelho - + yellow amarelo - + green verde - + his permanents as suas permanentes - + %1 %2 %3. %1 %2 %3. - + taps vira - + untaps desvira - + %1 sets counter %2 to %3 (%4%5). %1 altera o número de marcadores %2 para %3(%4%5). - + %1 sets %2 to not untap normally. %1 define %2 para não desvirar normalmente. - + %1 sets %2 to untap normally. %1 define %2 para desvirar normalmente. - + %1 sets PT of %2 to %3. %1 define o P/R de %2 como %3. - + %1 sets annotation of %2 to %3. %1 coloca uma nota de %2 em%3. - + %1 is looking at the top %2 cards %3. %1 está a olhar para as %2 cartas do topo %3. - + %1 is looking at %2. %1 está a olhar para %2. - + %1 stops looking at %2. %1 para de olhar para %2. - + %1 reveals %2 to %3. %1 revela %2 a %3. - + %1 reveals %2. %1 revela %2. - + %1 randomly reveals %2%3 to %4. %1 revela aleatoreamente %2%3. a %4. - + %1 randomly reveals %2%3. %1 revela aleatoreamente %2%3. - + %1 reveals %2%3 to %4. %1 revela %2%3 a %4. - + %1 reveals %2%3. %1 revela %2%3. - + It is now %1's turn. É agora o turno de %1. - + untap step Etapa de Desvirar - + upkeep step Etapa de Manutenção - + draw step Etapa de Compra - + first main phase 1ª Fase Principal (pré-combate) - + beginning of combat step Etapa de Início de Combate - + declare attackers step Etapa de Declaração de Atacantes - + declare blockers step Etapa de Declaração de Bloqueadores - + combat damage step Etapa de Dano de Combate - + end of combat step Etapa de Fim de Combate - + second main phase 2ª Fase Principal (pós-combate) - + ending phase Fase Final - + It is now the %1. É agora a %1. @@ -1631,22 +1668,22 @@ MessagesSettingsPage - + Add message Adicionar mensagem - + Message: Mensagem: - + &Add &Adicionar - + &Remove &Remover @@ -1712,302 +1749,307 @@ Player - + &View graveyard &Ver cemitério - + &View exile &Ver exílio - + Player "%1" Jogador "%1" - + &Graveyard &Cemitério - + &Exile &Exílio - - - + + + Move to &top of library Mover para o &topo do grimório - - - + + + Move to &bottom of library Mover para o &fundo do grimório - - + + Move to &graveyard Mover para o &cemitério - - + + Move to &exile Mover para o &exílio - - + + Move to &hand Mover para a &mão - + &View library &Ver grimório - + View &top cards of library... Ver as cartas do &topo do grimório... - + Reveal &library to Revelar &grimório a - + Reveal t&op card to Revelar carta do t&opo a - + &View sideboard &Ver sideboard - + &Draw card &Comprar carta - + D&raw cards... C&omprar cartas... - + Take &mulligan Fazer &mulligan - + &Shuffle &Baralhar - + Move top cards to &graveyard... Mover as cartas do topo para o &cemitério... - + Move top cards to &exile... Mover as cartas do topo para o &exílio... - + + Put top card on &bottom + + + + &Hand &Mão - + &Reveal to &Revelar a - + Reveal r&andom card to Revelar carta &aleatória a - + &Sideboard &Sideboard - + &Library &Grimório - + &Counters &Marcadores - + &Untap all permanents &Desvirar topas as permanentes - + R&oll die... &Lançar dado... - + &Create token... Criar fic&ha... - + C&reate another token Cr&iar outra ficha - + S&ay &Dizer - + C&ard C&arta - + &All players Todos os &jogadores - + F3 F3 - + Ctrl+W Ctrl+W - + F4 F4 - + Ctrl+D Ctrl+D - + Ctrl+E Ctrl+E - + Ctrl+M Ctrl+M - + Ctrl+S Ctrl+S - + Ctrl+U Ctrl+U - + Ctrl+I Ctrl+I - + Ctrl+T Ctrl+T - + Ctrl+G Ctrl+G - + View top cards of library Ver as cartas do topo do grimório - + Number of cards: Número de cartas: - + Draw cards Comprar cartas - - - - + + + + Number: Número: - + Move top cards to grave Mover as cartas to topo para o cemitério - + Move top cards to exile Mover as cartas to topo para o exílio - + Roll die Lançar dado - + Number of sides: Número de faces: - + Set power/toughness Definir poder/resistência - + Please enter the new PT: Por favor introduza o novo P/R: - + Set annotation Colocar nota - + Please enter the new annotation: Por favor introduza a nova nota: - + Set counters Definir marcadores @@ -2086,12 +2128,44 @@ Hora de upload + + RoomSelector + + + Rooms + + + + + Joi&n + E&ntrar + + + + Room + + + + + Description + Descrição + + + + Players + Jogadores + + + + Games + Jogos + + ServerMessageLog - Server messages - Mensagens do serivdor + Mensagens do serivdor @@ -2110,24 +2184,20 @@ TabChatChannel - C&hat channel - Ca&nal de Conversação + Ca&nal de Conversação - &Leave channel - &Abandonar canal + &Abandonar canal - %1 has joined the channel. - %1 entrou no canal. + %1 entrou no canal. - %1 has left the channel. - %1 abandonou o canal. + %1 abandonou o canal. @@ -2309,10 +2379,43 @@ Por favor introduza um nome: Falar para %1 + + TabRoom + + + &Say: + &Dizer: + + + + Chat + + + + + &Room + + + + + &Leave room + + + + + %1 has joined the room. + + + + + %1 has left the room. + + + TabServer - + Server Servidor @@ -2320,35 +2423,55 @@ Por favor introduza um nome: UserInfoBox - + Location: Localização: - + User level: Nível de utilizador: + + + Administrator + + + + + Judge + + + + + Registered user + + + + + Unregistered user + + UserInterfaceSettingsPage - + General interface settings Configurações gerais da interface - + &Double-click cards to play them (instead of single-click) Clicar &duas vezes nas cartas para as jogar (ao invés de clicar apenas uma vez) - + Animation settings Configurações de Animações - + &Tap/untap animation Animação de &virar/desvirar @@ -2356,10 +2479,15 @@ Por favor introduza um nome: UserList - + Users online: %1 Utilizadores online: %1 + + + Users in this room: %1 + + WndDeckEditor @@ -2531,7 +2659,20 @@ Gostaria de guardar as alterações? Carregar deck - + + + Error + Erro + + + + + The deck could not be saved. +Please check that the directory is writable and try again. + + + + Save deck Guardar deck diff --git a/common/protocol.cpp b/common/protocol.cpp index ccfc081a..b6060f2e 100644 --- a/common/protocol.cpp +++ b/common/protocol.cpp @@ -14,7 +14,7 @@ void ProtocolItem::initializeHash() initializeHashAuto(); registerSerializableItem("move_card_to_zone", MoveCardToZone::newItem); - registerSerializableItem("chat_channel", ServerInfo_ChatChannel::newItem); + registerSerializableItem("room", ServerInfo_Room::newItem); registerSerializableItem("user", ServerInfo_User::newItem); registerSerializableItem("game", ServerInfo_Game::newItem); registerSerializableItem("card_counter", ServerInfo_CardCounter::newItem); @@ -37,16 +37,19 @@ void ProtocolItem::initializeHash() registerSerializableItem("resp", ProtocolResponse::newItem); ProtocolResponse::initializeHash(); + registerSerializableItem("respjoin_room", Response_JoinRoom::newItem); registerSerializableItem("resplist_users", Response_ListUsers::newItem); registerSerializableItem("respget_user_info", Response_GetUserInfo::newItem); registerSerializableItem("respdeck_list", Response_DeckList::newItem); registerSerializableItem("respdeck_download", Response_DeckDownload::newItem); registerSerializableItem("respdeck_upload", Response_DeckUpload::newItem); registerSerializableItem("respdump_zone", Response_DumpZone::newItem); + registerSerializableItem("resplogin", Response_Login::newItem); - registerSerializableItem("generic_eventlist_games", Event_ListGames::newItem); + registerSerializableItem("room_eventlist_games", Event_ListGames::newItem); + registerSerializableItem("room_eventjoin_room", Event_JoinRoom::newItem); registerSerializableItem("generic_eventuser_joined", Event_UserJoined::newItem); - registerSerializableItem("generic_eventlist_chat_channels", Event_ListChatChannels::newItem); + registerSerializableItem("generic_eventlist_rooms", Event_ListRooms::newItem); registerSerializableItem("game_eventjoin", Event_Join::newItem); registerSerializableItem("game_eventgame_state_changed", Event_GameStateChanged::newItem); registerSerializableItem("game_eventplayer_properties_changed", Event_PlayerPropertiesChanged::newItem); @@ -55,8 +58,6 @@ void ProtocolItem::initializeHash() registerSerializableItem("game_eventdraw_cards", Event_DrawCards::newItem); registerSerializableItem("game_eventreveal_cards", Event_RevealCards::newItem); registerSerializableItem("game_eventping", Event_Ping::newItem); - registerSerializableItem("chat_eventchat_list_players", Event_ChatListPlayers::newItem); - registerSerializableItem("chat_eventchat_join_channel", Event_ChatJoinChannel::newItem); } TopLevelProtocolItem::TopLevelProtocolItem() @@ -221,6 +222,14 @@ void ProtocolResponse::initializeHash() responseHash.insert("spectators_not_allowed", RespSpectatorsNotAllowed); } +Response_JoinRoom::Response_JoinRoom(int _cmdId, ResponseCode _responseCode, ServerInfo_Room *_roomInfo) + : ProtocolResponse(_cmdId, _responseCode, "join_room") +{ + if (!_roomInfo) + _roomInfo = new ServerInfo_Room; + insertItem(_roomInfo); +} + Response_ListUsers::Response_ListUsers(int _cmdId, ResponseCode _responseCode, const QList &_userList) : ProtocolResponse(_cmdId, _responseCode, "list_users") { @@ -273,6 +282,14 @@ Response_DumpZone::Response_DumpZone(int _cmdId, ResponseCode _responseCode, Ser insertItem(_zone); } +Response_Login::Response_Login(int _cmdId, ResponseCode _responseCode, ServerInfo_User *_userInfo) + : ProtocolResponse(_cmdId, _responseCode, "login") +{ + if (!_userInfo) + _userInfo = new ServerInfo_User; + insertItem(_userInfo); +} + GameEvent::GameEvent(const QString &_eventName, int _playerId) : ProtocolItem("game_event", _eventName) { @@ -284,36 +301,29 @@ GameEventContext::GameEventContext(const QString &_contextName) { } -ChatEvent::ChatEvent(const QString &_eventName, const QString &_channel) - : ProtocolItem("chat_event", _eventName) +RoomEvent::RoomEvent(const QString &_eventName, int _roomId) + : ProtocolItem("room_event", _eventName) { - insertItem(new SerializableItem_String("channel", _channel)); + insertItem(new SerializableItem_Int("room_id", _roomId)); } -Event_ListChatChannels::Event_ListChatChannels(const QList &_channelList) - : GenericEvent("list_chat_channels") +Event_ListRooms::Event_ListRooms(const QList &_roomList) + : GenericEvent("list_rooms") { - for (int i = 0; i < _channelList.size(); ++i) - itemList.append(_channelList[i]); + for (int i = 0; i < _roomList.size(); ++i) + itemList.append(_roomList[i]); } -Event_ChatListPlayers::Event_ChatListPlayers(const QString &_channel, const QList &_playerList) - : ChatEvent("chat_list_players", _channel) -{ - for (int i = 0; i < _playerList.size(); ++i) - itemList.append(_playerList[i]); -} - -Event_ChatJoinChannel::Event_ChatJoinChannel(const QString &_channel, ServerInfo_User *_info) - : ChatEvent("chat_join_channel", _channel) +Event_JoinRoom::Event_JoinRoom(int _roomId, ServerInfo_User *_info) + : RoomEvent("join_room", _roomId) { if (!_info) _info = new ServerInfo_User; insertItem(_info); } -Event_ListGames::Event_ListGames(const QList &_gameList) - : GenericEvent("list_games") +Event_ListGames::Event_ListGames(int _roomId, const QList &_gameList) + : RoomEvent("list_games", _roomId) { for (int i = 0; i < _gameList.size(); ++i) itemList.append(_gameList[i]); diff --git a/common/protocol.h b/common/protocol.h index e42d5456..e882823b 100644 --- a/common/protocol.h +++ b/common/protocol.h @@ -25,9 +25,8 @@ enum ItemId { ItemId_Command_DeckUpload = ItemId_Other + 100, ItemId_Command_DeckSelect = ItemId_Other + 101, ItemId_Command_SetSideboardPlan = ItemId_Other + 102, - ItemId_Event_ListChatChannels = ItemId_Other + 200, - ItemId_Event_ChatListPlayers = ItemId_Other + 201, - ItemId_Event_ChatJoinChannel = ItemId_Other + 202, + ItemId_Event_ListRooms = ItemId_Other + 200, + ItemId_Event_JoinRoom = ItemId_Other + 201, ItemId_Event_ListGames = ItemId_Other + 203, ItemId_Event_UserJoined = ItemId_Other + 204, ItemId_Event_GameStateChanged = ItemId_Other + 205, @@ -44,6 +43,8 @@ enum ItemId { ItemId_Response_DeckDownload = ItemId_Other + 303, ItemId_Response_DeckUpload = ItemId_Other + 304, ItemId_Response_DumpZone = ItemId_Other + 305, + ItemId_Response_JoinRoom = ItemId_Other + 306, + ItemId_Response_Login = ItemId_Other + 307, ItemId_Invalid = ItemId_Other + 1000 }; @@ -53,7 +54,7 @@ private: static void initializeHashAuto(); bool receiverMayDelete; public: - static const int protocolVersion = 10; + static const int protocolVersion = 11; static void initializeHash(); virtual int getItemId() const = 0; bool getReceiverMayDelete() const { return receiverMayDelete; } @@ -136,15 +137,15 @@ public: int getPrivatePlayerId() const { return privatePlayerId; } }; -class ChatCommand : public Command { +class RoomCommand : public Command { Q_OBJECT public: - ChatCommand(const QString &_cmdName, const QString &_channel) + RoomCommand(const QString &_cmdName, int _roomId) : Command(_cmdName) { - insertItem(new SerializableItem_String("channel", _channel)); + insertItem(new SerializableItem_Int("room_id", _roomId)); } - QString getChannel() const { return static_cast(itemMap.value("channel"))->getData(); } + int getRoomId() const { return static_cast(itemMap.value("room_id"))->getData(); } }; class GameCommand : public Command { @@ -205,6 +206,15 @@ public: ResponseCode getResponseCode() const { return responseHash.value(static_cast(itemMap.value("response_code"))->getData(), RespOk); } }; +class Response_JoinRoom : public ProtocolResponse { + Q_OBJECT +public: + Response_JoinRoom(int _cmdId = -1, ResponseCode _responseCode = RespOk, ServerInfo_Room *_roomInfo = 0); + int getItemId() const { return ItemId_Response_JoinRoom; } + static SerializableItem *newItem() { return new Response_JoinRoom; } + ServerInfo_Room *getRoomInfo() const { return static_cast(itemMap.value("room")); } +}; + class Response_ListUsers : public ProtocolResponse { Q_OBJECT public: @@ -259,6 +269,15 @@ public: ServerInfo_Zone *getZone() const { return static_cast(itemMap.value("zone")); } }; +class Response_Login : public ProtocolResponse { + Q_OBJECT +public: + Response_Login(int _cmdId = -1, ResponseCode _responseCode = RespOk, ServerInfo_User *_userInfo = 0); + int getItemId() const { return ItemId_Response_Login; } + static SerializableItem *newItem() { return new Response_Login; } + ServerInfo_User *getUserInfo() const { return static_cast(itemMap.value("user")); } +}; + // -------------- // --- EVENTS --- // -------------- @@ -304,44 +323,35 @@ public: void setGameId(int _gameId) { static_cast(itemMap.value("game_id"))->setData(_gameId); } }; -class ChatEvent : public ProtocolItem { +class RoomEvent : public ProtocolItem { Q_OBJECT public: - ChatEvent(const QString &_eventName, const QString &_channel); - QString getChannel() const { return static_cast(itemMap.value("channel"))->getData(); } + RoomEvent(const QString &_eventName, int _roomId); + int getRoomId() const { return static_cast(itemMap.value("room_id"))->getData(); } }; -class Event_ListChatChannels : public GenericEvent { +class Event_ListRooms : public GenericEvent { Q_OBJECT public: - Event_ListChatChannels(const QList &_channelList = QList()); - int getItemId() const { return ItemId_Event_ListChatChannels; } - static SerializableItem *newItem() { return new Event_ListChatChannels; } - QList getChannelList() const { return typecastItemList(); } + Event_ListRooms(const QList &_roomList = QList()); + int getItemId() const { return ItemId_Event_ListRooms; } + static SerializableItem *newItem() { return new Event_ListRooms; } + QList getRoomList() const { return typecastItemList(); } }; -class Event_ChatListPlayers : public ChatEvent { +class Event_JoinRoom : public RoomEvent { Q_OBJECT public: - Event_ChatListPlayers(const QString &_channel = QString(), const QList &_playerList = QList()); - int getItemId() const { return ItemId_Event_ChatListPlayers; } - static SerializableItem *newItem() { return new Event_ChatListPlayers; } - QList getPlayerList() const { return typecastItemList(); } -}; - -class Event_ChatJoinChannel : public ChatEvent { - Q_OBJECT -public: - Event_ChatJoinChannel(const QString &_channel = QString(), ServerInfo_User *_info = 0); - int getItemId() const { return ItemId_Event_ChatJoinChannel; } - static SerializableItem *newItem() { return new Event_ChatJoinChannel; } + Event_JoinRoom(int _roomId = -1, ServerInfo_User *_info = 0); + int getItemId() const { return ItemId_Event_JoinRoom; } + static SerializableItem *newItem() { return new Event_JoinRoom; } ServerInfo_User *getUserInfo() const { return static_cast(itemMap.value("user")); } }; -class Event_ListGames : public GenericEvent { +class Event_ListGames : public RoomEvent { Q_OBJECT public: - Event_ListGames(const QList &_gameList = QList()); + Event_ListGames(int _roomId = -1, const QList &_gameList = QList()); int getItemId() const { return ItemId_Event_ListGames; } static SerializableItem *newItem() { return new Event_ListGames; } QList getGameList() const { return typecastItemList(); } diff --git a/common/protocol_datastructures.cpp b/common/protocol_datastructures.cpp index afbf726a..ccf34bcb 100644 --- a/common/protocol_datastructures.cpp +++ b/common/protocol_datastructures.cpp @@ -3,15 +3,6 @@ #include #include -ServerInfo_ChatChannel::ServerInfo_ChatChannel(const QString &_name, const QString &_description, int _playerCount, bool _autoJoin) - : SerializableItem_Map("chat_channel") -{ - insertItem(new SerializableItem_String("name", _name)); - insertItem(new SerializableItem_String("description", _description)); - insertItem(new SerializableItem_Int("player_count", _playerCount)); - insertItem(new SerializableItem_Bool("auto_join", _autoJoin)); -} - ServerInfo_User::ServerInfo_User(const QString &_name, int _userLevel, const QString &_country, const QByteArray &_avatarBmp) : SerializableItem_Map("user") { @@ -21,13 +12,13 @@ ServerInfo_User::ServerInfo_User(const QString &_name, int _userLevel, const QSt insertItem(new SerializableItem_ByteArray("avatar_bmp", _avatarBmp)); } -ServerInfo_User::ServerInfo_User(const ServerInfo_User *other) +ServerInfo_User::ServerInfo_User(const ServerInfo_User *other, bool complete) : SerializableItem_Map("user") { insertItem(new SerializableItem_String("name", other->getName())); insertItem(new SerializableItem_Int("userlevel", other->getUserLevel())); insertItem(new SerializableItem_String("country", other->getCountry())); - insertItem(new SerializableItem_ByteArray("avatar_bmp", other->getAvatarBmp())); + insertItem(new SerializableItem_ByteArray("avatar_bmp", complete ? other->getAvatarBmp() : QByteArray())); } ServerInfo_Game::ServerInfo_Game(int _gameId, const QString &_description, bool _hasPassword, int _playerCount, int _maxPlayers, ServerInfo_User *_creatorInfo, bool _spectatorsAllowed, bool _spectatorsNeedPassword, int _spectatorCount) @@ -46,6 +37,40 @@ ServerInfo_Game::ServerInfo_Game(int _gameId, const QString &_description, bool insertItem(new SerializableItem_Int("spectator_count", _spectatorCount)); } +ServerInfo_Room::ServerInfo_Room(int _roomId, const QString &_name, const QString &_description, int _gameCount, int _playerCount, bool _autoJoin, const QList &_gameList, const QList &_userList) + : SerializableItem_Map("room") +{ + insertItem(new SerializableItem_Int("room_id", _roomId)); + insertItem(new SerializableItem_String("name", _name)); + insertItem(new SerializableItem_String("description", _description)); + insertItem(new SerializableItem_Int("game_count", _gameCount)); + insertItem(new SerializableItem_Int("player_count", _playerCount)); + insertItem(new SerializableItem_Bool("auto_join", _autoJoin)); + + gameList = _gameList; + for (int i = 0; i < _gameList.size(); ++i) + itemList.append(_gameList[i]); + userList = _userList; + for (int i = 0; i < _userList.size(); ++i) + itemList.append(_userList[i]); +} + +void ServerInfo_Room::extractData() +{ + for (int i = 0; i < itemList.size(); ++i) { + ServerInfo_User *user = dynamic_cast(itemList[i]); + if (user) { + userList.append(user); + continue; + } + ServerInfo_Game *game = dynamic_cast(itemList[i]); + if (game) { + gameList.append(game); + continue; + } + } +} + ServerInfo_CardCounter::ServerInfo_CardCounter(int _id, int _value) : SerializableItem_Map("card_counter") { diff --git a/common/protocol_datastructures.h b/common/protocol_datastructures.h index ff16b667..5f5649ec 100644 --- a/common/protocol_datastructures.h +++ b/common/protocol_datastructures.h @@ -20,16 +20,6 @@ enum ResponseCode { RespNothing, RespOk, RespInvalidCommand, RespInvalidData, Re // list index, whereas cards in any other zone are referenced by their ids. enum ZoneType { PrivateZone, PublicZone, HiddenZone }; -class ServerInfo_ChatChannel : public SerializableItem_Map { -public: - ServerInfo_ChatChannel(const QString &_name = QString(), const QString &_description = QString(), int _playerCount = -1, bool _autoJoin = false); - static SerializableItem *newItem() { return new ServerInfo_ChatChannel; } - QString getName() const { return static_cast(itemMap.value("name"))->getData(); } - QString getDescription() const { return static_cast(itemMap.value("description"))->getData(); } - int getPlayerCount() const { return static_cast(itemMap.value("player_count"))->getData(); } - bool getAutoJoin() const { return static_cast(itemMap.value("auto_join"))->getData(); } -}; - class ServerInfo_User : public SerializableItem_Map { public: enum UserLevelFlags { @@ -40,7 +30,7 @@ public: IsAdmin = 0x08 }; ServerInfo_User(const QString &_name = QString(), int _userLevel = IsNothing, const QString &_country = QString(), const QByteArray &_avatarBmp = QByteArray()); - ServerInfo_User(const ServerInfo_User *other); + ServerInfo_User(const ServerInfo_User *other, bool complete = true); static SerializableItem *newItem() { return new ServerInfo_User; } QString getName() const { return static_cast(itemMap.value("name"))->getData(); } int getUserLevel() const { return static_cast(itemMap.value("userlevel"))->getData(); } @@ -64,6 +54,25 @@ public: int getSpectatorCount() const { return static_cast(itemMap.value("spectator_count"))->getData(); } }; +class ServerInfo_Room : public SerializableItem_Map { +private: + QList gameList; + QList userList; +protected: + void extractData(); +public: + ServerInfo_Room(int _id = -1, const QString &_name = QString(), const QString &_description = QString(), int _gameCount = -1, int _playerCount = -1, bool _autoJoin = false, const QList &_gameList = QList(), const QList &_userList = QList()); + static SerializableItem *newItem() { return new ServerInfo_Room; } + int getRoomId() const { return static_cast(itemMap.value("room_id"))->getData(); } + QString getName() const { return static_cast(itemMap.value("name"))->getData(); } + QString getDescription() const { return static_cast(itemMap.value("description"))->getData(); } + int getGameCount() const { return static_cast(itemMap.value("game_count"))->getData(); } + int getPlayerCount() const { return static_cast(itemMap.value("player_count"))->getData(); } + bool getAutoJoin() const { return static_cast(itemMap.value("auto_join"))->getData(); } + const QList &getGameList() const { return gameList; } + const QList &getUserList() const { return userList; } +}; + class ServerInfo_CardCounter : public SerializableItem_Map { public: ServerInfo_CardCounter(int _id = -1, int _value = 0); diff --git a/common/protocol_item_ids.h b/common/protocol_item_ids.h index 8404364b..428a3f17 100644 --- a/common/protocol_item_ids.h +++ b/common/protocol_item_ids.h @@ -2,73 +2,72 @@ enum AutoItemId { ItemId_Command_Ping = 1001, ItemId_Command_Login = 1002, ItemId_Command_Message = 1003, -ItemId_Command_GetUserInfo = 1004, -ItemId_Command_DeckList = 1005, -ItemId_Command_DeckNewDir = 1006, -ItemId_Command_DeckDelDir = 1007, -ItemId_Command_DeckDel = 1008, -ItemId_Command_DeckDownload = 1009, -ItemId_Command_ListChatChannels = 1010, -ItemId_Command_ChatJoinChannel = 1011, -ItemId_Command_ChatLeaveChannel = 1012, -ItemId_Command_ChatSay = 1013, -ItemId_Command_ListGames = 1014, -ItemId_Command_ListUsers = 1015, -ItemId_Command_CreateGame = 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_MoveCard = 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_ServerMessage = 1063, -ItemId_Event_Message = 1064, -ItemId_Event_GameJoined = 1065, -ItemId_Event_UserLeft = 1066, -ItemId_Event_ChatLeaveChannel = 1067, -ItemId_Event_ChatSay = 1068, -ItemId_Context_ReadyStart = 1069, -ItemId_Context_Concede = 1070, -ItemId_Context_DeckSelect = 1071, -ItemId_Other = 1072 +ItemId_Command_ListUsers = 1004, +ItemId_Command_GetUserInfo = 1005, +ItemId_Command_DeckList = 1006, +ItemId_Command_DeckNewDir = 1007, +ItemId_Command_DeckDelDir = 1008, +ItemId_Command_DeckDel = 1009, +ItemId_Command_DeckDownload = 1010, +ItemId_Command_ListRooms = 1011, +ItemId_Command_JoinRoom = 1012, +ItemId_Command_LeaveRoom = 1013, +ItemId_Command_RoomSay = 1014, +ItemId_Command_CreateGame = 1015, +ItemId_Command_JoinGame = 1016, +ItemId_Command_LeaveGame = 1017, +ItemId_Command_Say = 1018, +ItemId_Command_Shuffle = 1019, +ItemId_Command_Mulligan = 1020, +ItemId_Command_RollDie = 1021, +ItemId_Command_DrawCards = 1022, +ItemId_Command_MoveCard = 1023, +ItemId_Command_FlipCard = 1024, +ItemId_Command_AttachCard = 1025, +ItemId_Command_CreateToken = 1026, +ItemId_Command_CreateArrow = 1027, +ItemId_Command_DeleteArrow = 1028, +ItemId_Command_SetCardAttr = 1029, +ItemId_Command_SetCardCounter = 1030, +ItemId_Command_IncCardCounter = 1031, +ItemId_Command_ReadyStart = 1032, +ItemId_Command_Concede = 1033, +ItemId_Command_IncCounter = 1034, +ItemId_Command_CreateCounter = 1035, +ItemId_Command_SetCounter = 1036, +ItemId_Command_DelCounter = 1037, +ItemId_Command_NextTurn = 1038, +ItemId_Command_SetActivePhase = 1039, +ItemId_Command_DumpZone = 1040, +ItemId_Command_StopDumpZone = 1041, +ItemId_Command_RevealCards = 1042, +ItemId_Event_Say = 1043, +ItemId_Event_Leave = 1044, +ItemId_Event_GameClosed = 1045, +ItemId_Event_Shuffle = 1046, +ItemId_Event_RollDie = 1047, +ItemId_Event_MoveCard = 1048, +ItemId_Event_FlipCard = 1049, +ItemId_Event_DestroyCard = 1050, +ItemId_Event_AttachCard = 1051, +ItemId_Event_CreateToken = 1052, +ItemId_Event_DeleteArrow = 1053, +ItemId_Event_SetCardAttr = 1054, +ItemId_Event_SetCardCounter = 1055, +ItemId_Event_SetCounter = 1056, +ItemId_Event_DelCounter = 1057, +ItemId_Event_SetActivePlayer = 1058, +ItemId_Event_SetActivePhase = 1059, +ItemId_Event_DumpZone = 1060, +ItemId_Event_StopDumpZone = 1061, +ItemId_Event_ServerMessage = 1062, +ItemId_Event_Message = 1063, +ItemId_Event_GameJoined = 1064, +ItemId_Event_UserLeft = 1065, +ItemId_Event_LeaveRoom = 1066, +ItemId_Event_RoomSay = 1067, +ItemId_Context_ReadyStart = 1068, +ItemId_Context_Concede = 1069, +ItemId_Context_DeckSelect = 1070, +ItemId_Other = 1071 }; diff --git a/common/protocol_items.cpp b/common/protocol_items.cpp index 47b5c000..652f1a4c 100644 --- a/common/protocol_items.cpp +++ b/common/protocol_items.cpp @@ -17,6 +17,10 @@ Command_Message::Command_Message(const QString &_userName, const QString &_text) insertItem(new SerializableItem_String("user_name", _userName)); insertItem(new SerializableItem_String("text", _text)); } +Command_ListUsers::Command_ListUsers() + : Command("list_users") +{ +} Command_GetUserInfo::Command_GetUserInfo(const QString &_userName) : Command("get_user_info") { @@ -47,34 +51,26 @@ Command_DeckDownload::Command_DeckDownload(int _deckId) { insertItem(new SerializableItem_Int("deck_id", _deckId)); } -Command_ListChatChannels::Command_ListChatChannels() - : Command("list_chat_channels") +Command_ListRooms::Command_ListRooms() + : Command("list_rooms") { } -Command_ChatJoinChannel::Command_ChatJoinChannel(const QString &_channel) - : Command("chat_join_channel") +Command_JoinRoom::Command_JoinRoom(int _roomId) + : Command("join_room") { - insertItem(new SerializableItem_String("channel", _channel)); + insertItem(new SerializableItem_Int("room_id", _roomId)); } -Command_ChatLeaveChannel::Command_ChatLeaveChannel(const QString &_channel) - : ChatCommand("chat_leave_channel", _channel) +Command_LeaveRoom::Command_LeaveRoom(int _roomId) + : RoomCommand("leave_room", _roomId) { } -Command_ChatSay::Command_ChatSay(const QString &_channel, const QString &_message) - : ChatCommand("chat_say", _channel) +Command_RoomSay::Command_RoomSay(int _roomId, const QString &_message) + : RoomCommand("room_say", _roomId) { insertItem(new SerializableItem_String("message", _message)); } -Command_ListGames::Command_ListGames() - : Command("list_games") -{ -} -Command_ListUsers::Command_ListUsers() - : Command("list_users") -{ -} -Command_CreateGame::Command_CreateGame(const QString &_description, const QString &_password, int _maxPlayers, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything) - : Command("create_game") +Command_CreateGame::Command_CreateGame(int _roomId, const QString &_description, const QString &_password, int _maxPlayers, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything) + : RoomCommand("create_game", _roomId) { insertItem(new SerializableItem_String("description", _description)); insertItem(new SerializableItem_String("password", _password)); @@ -84,8 +80,8 @@ Command_CreateGame::Command_CreateGame(const QString &_description, const QStrin insertItem(new SerializableItem_Bool("spectators_can_talk", _spectatorsCanTalk)); insertItem(new SerializableItem_Bool("spectators_see_everything", _spectatorsSeeEverything)); } -Command_JoinGame::Command_JoinGame(int _gameId, const QString &_password, bool _spectator) - : Command("join_game") +Command_JoinGame::Command_JoinGame(int _roomId, int _gameId, const QString &_password, bool _spectator) + : RoomCommand("join_game", _roomId) { insertItem(new SerializableItem_Int("game_id", _gameId)); insertItem(new SerializableItem_String("password", _password)); @@ -417,13 +413,13 @@ Event_UserLeft::Event_UserLeft(const QString &_userName) { insertItem(new SerializableItem_String("user_name", _userName)); } -Event_ChatLeaveChannel::Event_ChatLeaveChannel(const QString &_channel, const QString &_playerName) - : ChatEvent("chat_leave_channel", _channel) +Event_LeaveRoom::Event_LeaveRoom(int _roomId, const QString &_playerName) + : RoomEvent("leave_room", _roomId) { insertItem(new SerializableItem_String("player_name", _playerName)); } -Event_ChatSay::Event_ChatSay(const QString &_channel, const QString &_playerName, const QString &_message) - : ChatEvent("chat_say", _channel) +Event_RoomSay::Event_RoomSay(int _roomId, const QString &_playerName, const QString &_message) + : RoomEvent("room_say", _roomId) { insertItem(new SerializableItem_String("player_name", _playerName)); insertItem(new SerializableItem_String("message", _message)); @@ -446,18 +442,17 @@ void ProtocolItem::initializeHashAuto() itemNameHash.insert("cmdping", Command_Ping::newItem); itemNameHash.insert("cmdlogin", Command_Login::newItem); itemNameHash.insert("cmdmessage", Command_Message::newItem); + itemNameHash.insert("cmdlist_users", Command_ListUsers::newItem); itemNameHash.insert("cmdget_user_info", Command_GetUserInfo::newItem); itemNameHash.insert("cmddeck_list", Command_DeckList::newItem); itemNameHash.insert("cmddeck_new_dir", Command_DeckNewDir::newItem); itemNameHash.insert("cmddeck_del_dir", Command_DeckDelDir::newItem); itemNameHash.insert("cmddeck_del", Command_DeckDel::newItem); itemNameHash.insert("cmddeck_download", Command_DeckDownload::newItem); - itemNameHash.insert("cmdlist_chat_channels", Command_ListChatChannels::newItem); - itemNameHash.insert("cmdchat_join_channel", Command_ChatJoinChannel::newItem); - itemNameHash.insert("cmdchat_leave_channel", Command_ChatLeaveChannel::newItem); - itemNameHash.insert("cmdchat_say", Command_ChatSay::newItem); - itemNameHash.insert("cmdlist_games", Command_ListGames::newItem); - itemNameHash.insert("cmdlist_users", Command_ListUsers::newItem); + itemNameHash.insert("cmdlist_rooms", Command_ListRooms::newItem); + itemNameHash.insert("cmdjoin_room", Command_JoinRoom::newItem); + itemNameHash.insert("cmdleave_room", Command_LeaveRoom::newItem); + itemNameHash.insert("cmdroom_say", Command_RoomSay::newItem); itemNameHash.insert("cmdcreate_game", Command_CreateGame::newItem); itemNameHash.insert("cmdjoin_game", Command_JoinGame::newItem); itemNameHash.insert("cmdleave_game", Command_LeaveGame::newItem); @@ -509,8 +504,8 @@ void ProtocolItem::initializeHashAuto() itemNameHash.insert("generic_eventmessage", Event_Message::newItem); itemNameHash.insert("generic_eventgame_joined", Event_GameJoined::newItem); itemNameHash.insert("generic_eventuser_left", Event_UserLeft::newItem); - itemNameHash.insert("chat_eventchat_leave_channel", Event_ChatLeaveChannel::newItem); - itemNameHash.insert("chat_eventchat_say", Event_ChatSay::newItem); + itemNameHash.insert("room_eventleave_room", Event_LeaveRoom::newItem); + itemNameHash.insert("room_eventroom_say", Event_RoomSay::newItem); itemNameHash.insert("game_event_contextready_start", Context_ReadyStart::newItem); itemNameHash.insert("game_event_contextconcede", Context_Concede::newItem); itemNameHash.insert("game_event_contextdeck_select", Context_DeckSelect::newItem); diff --git a/common/protocol_items.dat b/common/protocol_items.dat index 68b1e568..2819ddec 100644 --- a/common/protocol_items.dat +++ b/common/protocol_items.dat @@ -1,20 +1,19 @@ 0:ping 0:login:s,username:s,password 0:message:s,user_name:s,text +0:list_users 0:get_user_info:s,user_name 0:deck_list 0:deck_new_dir:s,path:s,dir_name 0:deck_del_dir:s,path 0:deck_del:i,deck_id 0:deck_download:i,deck_id -0:list_chat_channels -0:chat_join_channel:s,channel -1:chat_leave_channel -1:chat_say:s,message -0:list_games -0:list_users -0:create_game:s,description:s,password:i,max_players:b,spectators_allowed:b,spectators_need_password:b,spectators_can_talk:b,spectators_see_everything -0:join_game:i,game_id:s,password:b,spectator +0:list_rooms +0:join_room:i,room_id +1:leave_room +1:room_say:s,message +1:create_game:s,description:s,password:i,max_players:b,spectators_allowed:b,spectators_need_password:b,spectators_can_talk:b,spectators_see_everything +1:join_game:i,game_id:s,password:b,spectator 2:leave_game 2:say:s,message 2:shuffle @@ -64,8 +63,8 @@ 4:message:s,sender_name:s,receiver_name:s,text 4:game_joined:i,game_id:s,game_description:i,player_id:b,spectator:b,spectators_can_talk:b,spectators_see_everything:b,resuming 4:user_left:s,user_name -5:chat_leave_channel:s,player_name -5:chat_say:s,player_name:s,message +5:leave_room:s,player_name +5:room_say:s,player_name:s,message 6:ready_start 6:concede 6:deck_select:i,deck_id diff --git a/common/protocol_items.h b/common/protocol_items.h index 331c2610..8a32ace1 100644 --- a/common/protocol_items.h +++ b/common/protocol_items.h @@ -28,6 +28,13 @@ public: static SerializableItem *newItem() { return new Command_Message; } int getItemId() const { return ItemId_Command_Message; } }; +class Command_ListUsers : public Command { + Q_OBJECT +public: + Command_ListUsers(); + static SerializableItem *newItem() { return new Command_ListUsers; } + int getItemId() const { return ItemId_Command_ListUsers; } +}; class Command_GetUserInfo : public Command { Q_OBJECT public: @@ -76,54 +83,40 @@ public: static SerializableItem *newItem() { return new Command_DeckDownload; } int getItemId() const { return ItemId_Command_DeckDownload; } }; -class Command_ListChatChannels : public Command { +class Command_ListRooms : public Command { Q_OBJECT public: - Command_ListChatChannels(); - static SerializableItem *newItem() { return new Command_ListChatChannels; } - int getItemId() const { return ItemId_Command_ListChatChannels; } + Command_ListRooms(); + static SerializableItem *newItem() { return new Command_ListRooms; } + int getItemId() const { return ItemId_Command_ListRooms; } }; -class Command_ChatJoinChannel : public Command { +class Command_JoinRoom : public Command { Q_OBJECT public: - Command_ChatJoinChannel(const QString &_channel = QString()); - QString getChannel() const { return static_cast(itemMap.value("channel"))->getData(); }; - static SerializableItem *newItem() { return new Command_ChatJoinChannel; } - int getItemId() const { return ItemId_Command_ChatJoinChannel; } + Command_JoinRoom(int _roomId = -1); + int getRoomId() const { return static_cast(itemMap.value("room_id"))->getData(); }; + static SerializableItem *newItem() { return new Command_JoinRoom; } + int getItemId() const { return ItemId_Command_JoinRoom; } }; -class Command_ChatLeaveChannel : public ChatCommand { +class Command_LeaveRoom : public RoomCommand { Q_OBJECT public: - Command_ChatLeaveChannel(const QString &_channel = QString()); - static SerializableItem *newItem() { return new Command_ChatLeaveChannel; } - int getItemId() const { return ItemId_Command_ChatLeaveChannel; } + Command_LeaveRoom(int _roomId = -1); + static SerializableItem *newItem() { return new Command_LeaveRoom; } + int getItemId() const { return ItemId_Command_LeaveRoom; } }; -class Command_ChatSay : public ChatCommand { +class Command_RoomSay : public RoomCommand { Q_OBJECT public: - Command_ChatSay(const QString &_channel = QString(), const QString &_message = QString()); + Command_RoomSay(int _roomId = -1, const QString &_message = QString()); QString getMessage() const { return static_cast(itemMap.value("message"))->getData(); }; - static SerializableItem *newItem() { return new Command_ChatSay; } - int getItemId() const { return ItemId_Command_ChatSay; } + static SerializableItem *newItem() { return new Command_RoomSay; } + int getItemId() const { return ItemId_Command_RoomSay; } }; -class Command_ListGames : public Command { +class Command_CreateGame : public RoomCommand { Q_OBJECT public: - Command_ListGames(); - static SerializableItem *newItem() { return new Command_ListGames; } - int getItemId() const { return ItemId_Command_ListGames; } -}; -class Command_ListUsers : public Command { - Q_OBJECT -public: - Command_ListUsers(); - static SerializableItem *newItem() { return new Command_ListUsers; } - int getItemId() const { return ItemId_Command_ListUsers; } -}; -class Command_CreateGame : public Command { - Q_OBJECT -public: - Command_CreateGame(const QString &_description = QString(), const QString &_password = QString(), int _maxPlayers = -1, bool _spectatorsAllowed = false, bool _spectatorsNeedPassword = false, bool _spectatorsCanTalk = false, bool _spectatorsSeeEverything = false); + Command_CreateGame(int _roomId = -1, const QString &_description = QString(), const QString &_password = QString(), int _maxPlayers = -1, bool _spectatorsAllowed = false, bool _spectatorsNeedPassword = false, bool _spectatorsCanTalk = false, bool _spectatorsSeeEverything = false); QString getDescription() const { return static_cast(itemMap.value("description"))->getData(); }; QString getPassword() const { return static_cast(itemMap.value("password"))->getData(); }; int getMaxPlayers() const { return static_cast(itemMap.value("max_players"))->getData(); }; @@ -134,10 +127,10 @@ public: static SerializableItem *newItem() { return new Command_CreateGame; } int getItemId() const { return ItemId_Command_CreateGame; } }; -class Command_JoinGame : public Command { +class Command_JoinGame : public RoomCommand { Q_OBJECT public: - Command_JoinGame(int _gameId = -1, const QString &_password = QString(), bool _spectator = false); + Command_JoinGame(int _roomId = -1, int _gameId = -1, const QString &_password = QString(), bool _spectator = false); int getGameId() const { return static_cast(itemMap.value("game_id"))->getData(); }; QString getPassword() const { return static_cast(itemMap.value("password"))->getData(); }; bool getSpectator() const { return static_cast(itemMap.value("spectator"))->getData(); }; @@ -617,22 +610,22 @@ public: static SerializableItem *newItem() { return new Event_UserLeft; } int getItemId() const { return ItemId_Event_UserLeft; } }; -class Event_ChatLeaveChannel : public ChatEvent { +class Event_LeaveRoom : public RoomEvent { Q_OBJECT public: - Event_ChatLeaveChannel(const QString &_channel = QString(), const QString &_playerName = QString()); + Event_LeaveRoom(int _roomId = -1, const QString &_playerName = QString()); QString getPlayerName() const { return static_cast(itemMap.value("player_name"))->getData(); }; - static SerializableItem *newItem() { return new Event_ChatLeaveChannel; } - int getItemId() const { return ItemId_Event_ChatLeaveChannel; } + static SerializableItem *newItem() { return new Event_LeaveRoom; } + int getItemId() const { return ItemId_Event_LeaveRoom; } }; -class Event_ChatSay : public ChatEvent { +class Event_RoomSay : public RoomEvent { Q_OBJECT public: - Event_ChatSay(const QString &_channel = QString(), const QString &_playerName = QString(), const QString &_message = QString()); + Event_RoomSay(int _roomId = -1, const QString &_playerName = QString(), const QString &_message = QString()); QString getPlayerName() const { return static_cast(itemMap.value("player_name"))->getData(); }; QString getMessage() const { return static_cast(itemMap.value("message"))->getData(); }; - static SerializableItem *newItem() { return new Event_ChatSay; } - int getItemId() const { return ItemId_Event_ChatSay; } + static SerializableItem *newItem() { return new Event_RoomSay; } + int getItemId() const { return ItemId_Event_RoomSay; } }; class Context_ReadyStart : public GameEventContext { Q_OBJECT diff --git a/common/protocol_mc.pl b/common/protocol_mc.pl index 696915d9..3dae3a16 100755 --- a/common/protocol_mc.pl +++ b/common/protocol_mc.pl @@ -34,10 +34,10 @@ while () { } elsif ($type == 1) { $type = 'cmd'; $namePrefix = 'Command'; - $baseClass = 'ChatCommand'; - $parentConstructorCall = "$baseClass(\"$name1\", _channel)"; - $constructorParamsH = "const QString &_channel = QString()"; - $constructorParamsCpp = "const QString &_channel"; + $baseClass = 'RoomCommand'; + $parentConstructorCall = "$baseClass(\"$name1\", _roomId)"; + $constructorParamsH = "int _roomId = -1"; + $constructorParamsCpp = "int _roomId"; } elsif ($type == 2) { $type = 'cmd'; $namePrefix = 'Command'; @@ -60,12 +60,12 @@ while () { $constructorParamsH = ""; $constructorParamsCpp = ""; } elsif ($type == 5) { - $type = 'chat_event'; + $type = 'room_event'; $namePrefix = 'Event'; - $baseClass = 'ChatEvent'; - $parentConstructorCall = "$baseClass(\"$name1\", _channel)"; - $constructorParamsH = "const QString &_channel = QString()"; - $constructorParamsCpp = "const QString &_channel"; + $baseClass = 'RoomEvent'; + $parentConstructorCall = "$baseClass(\"$name1\", _roomId)"; + $constructorParamsH = "int _roomId = -1"; + $constructorParamsCpp = "int _roomId"; } elsif ($type == 6) { $type = 'game_event_context'; $namePrefix = 'Context'; diff --git a/common/server.cpp b/common/server.cpp index dc4125b2..4890f04f 100644 --- a/common/server.cpp +++ b/common/server.cpp @@ -20,7 +20,7 @@ #include "server.h" #include "server_game.h" #include "server_counter.h" -#include "server_chatchannel.h" +#include "server_room.h" #include "server_protocolhandler.h" #include "protocol_datastructures.h" #include @@ -69,17 +69,6 @@ AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString return authState; } -Server_Game *Server::createGame(const QString &description, const QString &password, int maxPlayers, bool spectatorsAllowed, bool spectatorsNeedPassword, bool spectatorsCanTalk, bool spectatorsSeeEverything, Server_ProtocolHandler *creator) -{ - Server_Game *newGame = new Server_Game(creator, nextGameId++, description, password, maxPlayers, spectatorsAllowed, spectatorsNeedPassword, spectatorsCanTalk, spectatorsSeeEverything, this); - games.insert(newGame->getGameId(), newGame); - connect(newGame, SIGNAL(gameClosing()), this, SLOT(gameClosing())); - - broadcastGameListUpdate(newGame); - - return newGame; -} - void Server::addClient(Server_ProtocolHandler *client) { clients << client; @@ -106,56 +95,34 @@ Server_Game *Server::getGame(int gameId) const return games.value(gameId); } -void Server::broadcastGameListUpdate(Server_Game *game) +void Server::broadcastRoomUpdate() { - QList eventGameList; - if (game->getPlayerCount()) - // Game is open - eventGameList.append(new ServerInfo_Game( - game->getGameId(), - game->getDescription(), - !game->getPassword().isEmpty(), - game->getPlayerCount(), - game->getMaxPlayers(), - new ServerInfo_User(game->getCreatorInfo()), - game->getSpectatorsAllowed(), - game->getSpectatorsNeedPassword(), - game->getSpectatorCount() - )); - else - // Game is closing - eventGameList.append(new ServerInfo_Game(game->getGameId(), QString(), false, 0, game->getMaxPlayers(), 0, false, 0)); - Event_ListGames *event = new Event_ListGames(eventGameList); - - for (int i = 0; i < clients.size(); i++) - if (clients[i]->getAcceptsGameListChanges()) - clients[i]->sendProtocolItem(event, false); - delete event; -} - -void Server::broadcastChannelUpdate() -{ - Server_ChatChannel *channel = static_cast(sender()); - QList eventChannelList; - eventChannelList.append(new ServerInfo_ChatChannel(channel->getName(), channel->getDescription(), channel->size(), channel->getAutoJoin())); - Event_ListChatChannels *event = new Event_ListChatChannels(eventChannelList); + Server_Room *room = static_cast(sender()); + QList eventRoomList; + eventRoomList.append(new ServerInfo_Room(room->getId(), room->getName(), room->getDescription(), room->getGames().size(), room->size(), room->getAutoJoin())); + Event_ListRooms *event = new Event_ListRooms(eventRoomList); for (int i = 0; i < clients.size(); ++i) - if (clients[i]->getAcceptsChatChannelListChanges()) + if (clients[i]->getAcceptsRoomListChanges()) clients[i]->sendProtocolItem(event, false); delete event; } -void Server::gameClosing() +void Server::gameCreated(Server_Game *game) { - qDebug("Server::gameClosing"); - Server_Game *game = static_cast(sender()); - broadcastGameListUpdate(game); - games.remove(games.key(game)); + games.insert(game->getGameId(), game); } -void Server::addChatChannel(Server_ChatChannel *newChannel) +void Server::gameClosing(int gameId) { - chatChannels.insert(newChannel->getName(), newChannel); - connect(newChannel, SIGNAL(channelInfoChanged()), this, SLOT(broadcastChannelUpdate())); + qDebug("Server::gameClosing"); + games.remove(gameId); +} + +void Server::addRoom(Server_Room *newRoom) +{ + rooms.insert(newRoom->getId(), newRoom); + connect(newRoom, SIGNAL(roomInfoChanged()), this, SLOT(broadcastRoomUpdate())); + connect(newRoom, SIGNAL(gameCreated(Server_Game *)), this, SLOT(gameCreated(Server_Game *))); + connect(newRoom, SIGNAL(gameClosing(int)), this, SLOT(gameClosing(int))); } diff --git a/common/server.h b/common/server.h index 3f4dfd56..d382626a 100644 --- a/common/server.h +++ b/common/server.h @@ -6,7 +6,7 @@ #include class Server_Game; -class Server_ChatChannel; +class Server_Room; class Server_ProtocolHandler; class ServerInfo_User; @@ -18,22 +18,22 @@ class Server : public QObject signals: void pingClockTimeout(); private slots: - void gameClosing(); - void broadcastChannelUpdate(); + void gameCreated(Server_Game *game); + void gameClosing(int gameId); + void broadcastRoomUpdate(); public: Server(QObject *parent = 0); ~Server(); AuthenticationResult loginUser(Server_ProtocolHandler *session, QString &name, const QString &password); QList getGames() const { return games.values(); } Server_Game *getGame(int gameId) const; - const QMap &getChatChannels() { return chatChannels; } - void broadcastGameListUpdate(Server_Game *game); + const QMap &getRooms() { return rooms; } + int getNextGameId() { return nextGameId++; } const QMap &getUsers() const { return users; } void addClient(Server_ProtocolHandler *player); void removeClient(Server_ProtocolHandler *player); virtual QString getLoginMessage() const = 0; - Server_Game *createGame(const QString &description, const QString &password, int maxPlayers, bool spectatorsAllowed, bool spectatorsNeedPassword, bool spectatorsCanTalk, bool spectatorsSeeEverything, Server_ProtocolHandler *creator); virtual bool getGameShouldPing() const = 0; virtual int getMaxGameInactivityTime() const = 0; @@ -42,12 +42,12 @@ protected: QMap games; QList clients; QMap users; - QMap chatChannels; + QMap rooms; virtual AuthenticationResult checkUserPassword(const QString &user, const QString &password) = 0; virtual ServerInfo_User *getUserData(const QString &name) = 0; int nextGameId; - void addChatChannel(Server_ChatChannel *newChannel); + void addRoom(Server_Room *newRoom); }; #endif diff --git a/common/server_chatchannel.cpp b/common/server_chatchannel.cpp deleted file mode 100644 index 2bdd8574..00000000 --- a/common/server_chatchannel.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "server_chatchannel.h" -#include "server_protocolhandler.h" - -Server_ChatChannel::Server_ChatChannel(const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage) - : name(_name), description(_description), autoJoin(_autoJoin), joinMessage(_joinMessage) -{ -} - -void Server_ChatChannel::addClient(Server_ProtocolHandler *client) -{ - sendChatEvent(new Event_ChatJoinChannel(name, new ServerInfo_User(client->getUserInfo()))); - append(client); - - QList eventUserList; - for (int i = 0; i < size(); ++i) - eventUserList.append(new ServerInfo_User(at(i)->getUserInfo())); - Event_ChatListPlayers *eventCLP = new Event_ChatListPlayers(name, eventUserList); - client->enqueueProtocolItem(eventCLP); - - client->enqueueProtocolItem(new Event_ChatSay(name, QString(), joinMessage)); - - emit channelInfoChanged(); -} - -void Server_ChatChannel::removeClient(Server_ProtocolHandler *client) -{ - removeAt(indexOf(client)); - sendChatEvent(new Event_ChatLeaveChannel(name, client->getUserInfo()->getName())); - emit channelInfoChanged(); -} - -void Server_ChatChannel::say(Server_ProtocolHandler *client, const QString &s) -{ - sendChatEvent(new Event_ChatSay(name, client->getUserInfo()->getName(), s)); -} - -void Server_ChatChannel::sendChatEvent(ChatEvent *event) -{ - for (int i = 0; i < size(); ++i) - at(i)->sendProtocolItem(event, false); - delete event; -} diff --git a/common/server_chatchannel.h b/common/server_chatchannel.h deleted file mode 100644 index 22b2f360..00000000 --- a/common/server_chatchannel.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef CHATCHANNEL_H -#define CHATCHANNEL_H - -#include -#include -#include - -class Server_ProtocolHandler; -class ChatEvent; - -class Server_ChatChannel : public QObject, public QList { - Q_OBJECT -signals: - void channelInfoChanged(); -private: - QString name; - QString description; - bool autoJoin; - QString joinMessage; -public: - Server_ChatChannel(const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage); - QString getName() const { return name; } - QString getDescription() const { return description; } - bool getAutoJoin() const { return autoJoin; } - void addClient(Server_ProtocolHandler *client); - void removeClient(Server_ProtocolHandler *client); - void say(Server_ProtocolHandler *client, const QString &s); - - void sendChatEvent(ChatEvent *event); -}; - -#endif diff --git a/common/server_game.cpp b/common/server_game.cpp index 2b9add86..84a46cc5 100644 --- a/common/server_game.cpp +++ b/common/server_game.cpp @@ -18,6 +18,7 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "server.h" +#include "server_room.h" #include "server_game.h" #include "server_protocolhandler.h" #include "server_arrow.h" @@ -27,12 +28,12 @@ #include #include -Server_Game::Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QString &_description, const QString &_password, int _maxPlayers, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, Server *parent) +Server_Game::Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QString &_description, const QString &_password, int _maxPlayers, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, Server_Room *parent) : QObject(parent), creatorInfo(new ServerInfo_User(_creator->getUserInfo())), gameStarted(false), gameId(_gameId), description(_description), password(_password), maxPlayers(_maxPlayers), activePlayer(-1), activePhase(-1), spectatorsAllowed(_spectatorsAllowed), spectatorsNeedPassword(_spectatorsNeedPassword), spectatorsCanTalk(_spectatorsCanTalk), spectatorsSeeEverything(_spectatorsSeeEverything), inactivityCounter(0) { addPlayer(_creator, false, false); - if (parent->getGameShouldPing()) { + if (parent->getServer()->getGameShouldPing()) { pingClock = new QTimer(this); connect(pingClock, SIGNAL(timeout()), this, SLOT(pingClockTimeout())); pingClock->start(1000); @@ -71,7 +72,7 @@ void Server_Game::pingClockTimeout() } sendGameEvent(new Event_Ping(pingList)); - const int maxTime = static_cast(parent())->getMaxGameInactivityTime(); + const int maxTime = static_cast(parent())->getServer()->getMaxGameInactivityTime(); if (allPlayersInactive) { if ((++inactivityCounter >= maxTime) && (maxTime > 0)) deleteLater(); @@ -193,7 +194,7 @@ Server_Player *Server_Game::addPlayer(Server_ProtocolHandler *handler, bool spec players.insert(playerId, newPlayer); if (broadcastUpdate) - qobject_cast(parent())->broadcastGameListUpdate(this); + qobject_cast(parent())->broadcastGameListUpdate(this); return newPlayer; } @@ -231,7 +232,7 @@ void Server_Game::removePlayer(Server_Player *player) deleteLater(); else if (!spectator) stopGameIfFinished(); - qobject_cast(parent())->broadcastGameListUpdate(this); + qobject_cast(parent())->broadcastGameListUpdate(this); } void Server_Game::setActivePlayer(int _activePlayer) @@ -391,3 +392,23 @@ void Server_Game::sendGameEventToPlayer(Server_Player *player, GameEvent *event) { player->sendProtocolItem(new GameEventContainer(QList() << event, gameId)); } + +ServerInfo_Game *Server_Game::getInfo() const +{ + if (players.isEmpty()) + // Game is open + return new ServerInfo_Game(getGameId(), QString(), false, 0, getMaxPlayers(), 0, false, 0); + else + // Game is closing + return new ServerInfo_Game( + getGameId(), + getDescription(), + !getPassword().isEmpty(), + getPlayerCount(), + getMaxPlayers(), + new ServerInfo_User(getCreatorInfo()), + getSpectatorsAllowed(), + getSpectatorsNeedPassword(), + getSpectatorCount() + ); +} \ No newline at end of file diff --git a/common/server_game.h b/common/server_game.h index 41c52698..420847dd 100644 --- a/common/server_game.h +++ b/common/server_game.h @@ -27,7 +27,7 @@ #include "protocol.h" class QTimer; -class Server; +class Server_Room; class ServerInfo_User; class Server_Game : public QObject { @@ -52,8 +52,9 @@ signals: private slots: void pingClockTimeout(); public: - Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QString &_description, const QString &_password, int _maxPlayers, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, Server *parent); + Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QString &_description, const QString &_password, int _maxPlayers, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, Server_Room *parent); ~Server_Game(); + ServerInfo_Game *getInfo() const; ServerInfo_User *getCreatorInfo() const { return creatorInfo; } bool getGameStarted() const { return gameStarted; } int getPlayerCount() const; diff --git a/common/server_protocolhandler.cpp b/common/server_protocolhandler.cpp index d641bb86..d63fb981 100644 --- a/common/server_protocolhandler.cpp +++ b/common/server_protocolhandler.cpp @@ -3,7 +3,7 @@ #include "server_protocolhandler.h" #include "protocol.h" #include "protocol_items.h" -#include "server_chatchannel.h" +#include "server_room.h" #include "server_card.h" #include "server_arrow.h" #include "server_cardzone.h" @@ -14,7 +14,7 @@ #include Server_ProtocolHandler::Server_ProtocolHandler(Server *_server, QObject *parent) - : QObject(parent), server(_server), authState(PasswordWrong), acceptsGameListChanges(false), acceptsUserListChanges(false), acceptsChatChannelListChanges(false), userInfo(0), lastCommandTime(QDateTime::currentDateTime()) + : QObject(parent), server(_server), authState(PasswordWrong), acceptsUserListChanges(false), acceptsRoomListChanges(false), userInfo(0), lastCommandTime(QDateTime::currentDateTime()) { connect(server, SIGNAL(pingClockTimeout()), this, SLOT(pingClockTimeout())); } @@ -25,6 +25,10 @@ Server_ProtocolHandler::~Server_ProtocolHandler() // so it will not receive the game update event. server->removeClient(this); + QMapIterator roomIterator(rooms); + while (roomIterator.hasNext()) + roomIterator.next().value()->removeClient(this); + QMapIterator > gameIterator(games); while (gameIterator.hasNext()) { gameIterator.next(); @@ -37,10 +41,6 @@ Server_ProtocolHandler::~Server_ProtocolHandler() p->setProtocolHandler(0); } - QMapIterator chatChannelIterator(chatChannels); - while (chatChannelIterator.hasNext()) - chatChannelIterator.next().value()->removeClient(this); - delete userInfo; } @@ -54,20 +54,22 @@ ResponseCode Server_ProtocolHandler::processCommandHelper(Command *command, Comm { lastCommandTime = QDateTime::currentDateTime(); - ChatCommand *chatCommand = qobject_cast(command); + RoomCommand *roomCommand = qobject_cast(command); GameCommand *gameCommand = qobject_cast(command); - if (chatCommand) { - qDebug() << "received ChatCommand: channel =" << chatCommand->getChannel(); + if (roomCommand) { + qDebug() << "received RoomCommand: roomId =" << roomCommand->getRoomId(); if (authState == PasswordWrong) return RespLoginNeeded; - Server_ChatChannel *channel = chatChannels.value(chatCommand->getChannel(), 0); - if (!channel) + Server_Room *room = rooms.value(roomCommand->getRoomId(), 0); + if (!room) return RespNameNotFound; switch (command->getItemId()) { - case ItemId_Command_ChatLeaveChannel: return cmdChatLeaveChannel(qobject_cast(command), cont, channel); - case ItemId_Command_ChatSay: return cmdChatSay(qobject_cast(command), cont, channel); + case ItemId_Command_LeaveRoom: return cmdLeaveRoom(qobject_cast(command), cont, room); + case ItemId_Command_RoomSay: return cmdRoomSay(qobject_cast(command), cont, room); + case ItemId_Command_CreateGame: return cmdCreateGame(qobject_cast(command), cont, room); + case ItemId_Command_JoinGame: return cmdJoinGame(qobject_cast(command), cont, room); } } else if (gameCommand) { qDebug() << "received GameCommand: game =" << gameCommand->getGameId(); @@ -125,12 +127,9 @@ ResponseCode Server_ProtocolHandler::processCommandHelper(Command *command, Comm case ItemId_Command_DeckUpload: return cmdDeckUpload(qobject_cast(command), cont); case ItemId_Command_DeckDownload: return cmdDeckDownload(qobject_cast(command), cont); case ItemId_Command_GetUserInfo: return cmdGetUserInfo(qobject_cast(command), cont); - case ItemId_Command_ListChatChannels: return cmdListChatChannels(qobject_cast(command), cont); - case ItemId_Command_ChatJoinChannel: return cmdChatJoinChannel(qobject_cast(command), cont); + case ItemId_Command_ListRooms: return cmdListRooms(qobject_cast(command), cont); + case ItemId_Command_JoinRoom: return cmdJoinRoom(qobject_cast(command), cont); case ItemId_Command_ListUsers: return cmdListUsers(qobject_cast(command), cont); - case ItemId_Command_ListGames: return cmdListGames(qobject_cast(command), cont); - case ItemId_Command_CreateGame: return cmdCreateGame(qobject_cast(command), cont); - case ItemId_Command_JoinGame: return cmdJoinGame(qobject_cast(command), cont); } } return RespInvalidCommand; @@ -235,8 +234,9 @@ ResponseCode Server_ProtocolHandler::cmdLogin(Command_Login *cmd, CommandContain } } } - - return RespOk; + + cont->setResponse(new Response_Login(cont->getCmdId(), RespOk, new ServerInfo_User(userInfo, true))); + return RespNothing; } ResponseCode Server_ProtocolHandler::cmdMessage(Command_Message *cmd, CommandContainer *cont) @@ -273,51 +273,52 @@ ResponseCode Server_ProtocolHandler::cmdGetUserInfo(Command_GetUserInfo *cmd, Co return RespNothing; } -ResponseCode Server_ProtocolHandler::cmdListChatChannels(Command_ListChatChannels * /*cmd*/, CommandContainer *cont) +ResponseCode Server_ProtocolHandler::cmdListRooms(Command_ListRooms * /*cmd*/, CommandContainer *cont) { if (authState == PasswordWrong) return RespLoginNeeded; - QList eventChannelList; - QMapIterator channelIterator(server->getChatChannels()); - while (channelIterator.hasNext()) { - Server_ChatChannel *c = channelIterator.next().value(); - eventChannelList.append(new ServerInfo_ChatChannel(c->getName(), c->getDescription(), c->size(), c->getAutoJoin())); - } - cont->enqueueItem(new Event_ListChatChannels(eventChannelList)); + QList eventRoomList; + QMapIterator roomIterator(server->getRooms()); + while (roomIterator.hasNext()) + eventRoomList.append(roomIterator.next().value()->getInfo(false)); + cont->enqueueItem(new Event_ListRooms(eventRoomList)); - acceptsChatChannelListChanges = true; + acceptsRoomListChanges = true; return RespOk; } -ResponseCode Server_ProtocolHandler::cmdChatJoinChannel(Command_ChatJoinChannel *cmd, CommandContainer *cont) +ResponseCode Server_ProtocolHandler::cmdJoinRoom(Command_JoinRoom *cmd, CommandContainer *cont) { if (authState == PasswordWrong) return RespLoginNeeded; - if (chatChannels.contains(cmd->getChannel())) + if (rooms.contains(cmd->getRoomId())) return RespContextError; - QMap allChannels = server->getChatChannels(); - Server_ChatChannel *c = allChannels.value(cmd->getChannel(), 0); - if (!c) + Server_Room *r = server->getRooms().value(cmd->getRoomId(), 0); + if (!r) return RespNameNotFound; - c->addClient(this); - chatChannels.insert(cmd->getChannel(), c); + r->addClient(this); + rooms.insert(r->getId(), r); + + enqueueProtocolItem(new Event_RoomSay(r->getId(), QString(), r->getJoinMessage())); + + cont->setResponse(new Response_JoinRoom(cont->getCmdId(), RespOk, r->getInfo(true))); + return RespNothing; +} + +ResponseCode Server_ProtocolHandler::cmdLeaveRoom(Command_LeaveRoom * /*cmd*/, CommandContainer *cont, Server_Room *room) +{ + rooms.remove(room->getId()); + room->removeClient(this); return RespOk; } -ResponseCode Server_ProtocolHandler::cmdChatLeaveChannel(Command_ChatLeaveChannel * /*cmd*/, CommandContainer *cont, Server_ChatChannel *channel) +ResponseCode Server_ProtocolHandler::cmdRoomSay(Command_RoomSay *cmd, CommandContainer *cont, Server_Room *room) { - chatChannels.remove(channel->getName()); - channel->removeClient(this); - return RespOk; -} - -ResponseCode Server_ProtocolHandler::cmdChatSay(Command_ChatSay *cmd, CommandContainer *cont, Server_ChatChannel *channel) -{ - channel->say(this, cmd->getMessage()); + room->say(this, cmd->getMessage()); return RespOk; } @@ -337,39 +338,12 @@ ResponseCode Server_ProtocolHandler::cmdListUsers(Command_ListUsers * /*cmd*/, C return RespNothing; } -ResponseCode Server_ProtocolHandler::cmdListGames(Command_ListGames * /*cmd*/, CommandContainer *cont) +ResponseCode Server_ProtocolHandler::cmdCreateGame(Command_CreateGame *cmd, CommandContainer *cont, Server_Room *room) { if (authState == PasswordWrong) return RespLoginNeeded; - const QList &gameList = server->getGames(); - QList eventGameList; - for (int i = 0; i < gameList.size(); ++i) { - Server_Game *g = gameList[i]; - eventGameList.append(new ServerInfo_Game( - g->getGameId(), - g->getDescription(), - !g->getPassword().isEmpty(), - g->getPlayerCount(), - g->getMaxPlayers(), - new ServerInfo_User(g->getCreatorInfo()), - g->getSpectatorsAllowed(), - g->getSpectatorsNeedPassword(), - g->getSpectatorCount() - )); - } - cont->enqueueItem(new Event_ListGames(eventGameList)); - - acceptsGameListChanges = true; - return RespOk; -} - -ResponseCode Server_ProtocolHandler::cmdCreateGame(Command_CreateGame *cmd, CommandContainer *cont) -{ - if (authState == PasswordWrong) - return RespLoginNeeded; - - Server_Game *game = server->createGame(cmd->getDescription(), cmd->getPassword(), cmd->getMaxPlayers(), cmd->getSpectatorsAllowed(), cmd->getSpectatorsNeedPassword(), cmd->getSpectatorsCanTalk(), cmd->getSpectatorsSeeEverything(), this); + Server_Game *game = room->createGame(cmd->getDescription(), cmd->getPassword(), cmd->getMaxPlayers(), cmd->getSpectatorsAllowed(), cmd->getSpectatorsNeedPassword(), cmd->getSpectatorsCanTalk(), cmd->getSpectatorsSeeEverything(), this); Server_Player *creator = game->getPlayers().values().first(); games.insert(game->getGameId(), QPair(game, creator)); @@ -378,7 +352,7 @@ ResponseCode Server_ProtocolHandler::cmdCreateGame(Command_CreateGame *cmd, Comm return RespOk; } -ResponseCode Server_ProtocolHandler::cmdJoinGame(Command_JoinGame *cmd, CommandContainer *cont) +ResponseCode Server_ProtocolHandler::cmdJoinGame(Command_JoinGame *cmd, CommandContainer *cont, Server_Room *room) { if (authState == PasswordWrong) return RespLoginNeeded; @@ -386,7 +360,7 @@ ResponseCode Server_ProtocolHandler::cmdJoinGame(Command_JoinGame *cmd, CommandC if (games.contains(cmd->getGameId())) return RespContextError; - Server_Game *g = server->getGame(cmd->getGameId()); + Server_Game *g = room->getGames().value(cmd->getGameId()); if (!g) return RespNameNotFound; @@ -503,12 +477,10 @@ ResponseCode Server_ProtocolHandler::cmdMulligan(Command_Mulligan * /*cmd*/, Com if (!game->getGameStarted()) return RespGameNotStarted; - - int number = player->getInitialCards(); - if (!number) - return RespContextError; - + Server_CardZone *hand = player->getZones().value("hand"); + int number = (hand->cards.size() <= 1) ? player->getInitialCards() : hand->cards.size() - 1; + Server_CardZone *deck = player->getZones().value("deck"); while (!hand->cards.isEmpty()) player->moveCard(cont, hand, hand->cards.first()->getId(), deck, 0, 0, false, false); @@ -518,7 +490,6 @@ ResponseCode Server_ProtocolHandler::cmdMulligan(Command_Mulligan * /*cmd*/, Com cont->enqueueGameEventPublic(new Event_Shuffle(player->getPlayerId()), game->getGameId()); drawCards(game, player, cont, number); - player->setInitialCards(number - 1); return RespOk; } diff --git a/common/server_protocolhandler.h b/common/server_protocolhandler.h index aa515760..d9ffa154 100644 --- a/common/server_protocolhandler.h +++ b/common/server_protocolhandler.h @@ -10,6 +10,7 @@ class Server_Player; class Server_Card; class ServerInfo_User; +class Server_Room; class QTimer; class Server_ProtocolHandler : public QObject { @@ -17,15 +18,14 @@ class Server_ProtocolHandler : public QObject { protected: Server *server; QMap > games; - QMap chatChannels; + QMap rooms; Server *getServer() const { return server; } QPair getGame(int gameId) const; AuthenticationResult authState; - bool acceptsGameListChanges; bool acceptsUserListChanges; - bool acceptsChatChannelListChanges; + bool acceptsRoomListChanges; ServerInfo_User *userInfo; private: @@ -45,14 +45,13 @@ private: virtual ResponseCode cmdDeckUpload(Command_DeckUpload *cmd, CommandContainer *cont) = 0; virtual ResponseCode cmdDeckDownload(Command_DeckDownload *cmd, CommandContainer *cont) = 0; ResponseCode cmdGetUserInfo(Command_GetUserInfo *cmd, CommandContainer *cont); - ResponseCode cmdListChatChannels(Command_ListChatChannels *cmd, CommandContainer *cont); - ResponseCode cmdChatJoinChannel(Command_ChatJoinChannel *cmd, CommandContainer *cont); - ResponseCode cmdChatLeaveChannel(Command_ChatLeaveChannel *cmd, CommandContainer *cont, Server_ChatChannel *channel); - ResponseCode cmdChatSay(Command_ChatSay *cmd, CommandContainer *cont, Server_ChatChannel *channel); + ResponseCode cmdListRooms(Command_ListRooms *cmd, CommandContainer *cont); + ResponseCode cmdJoinRoom(Command_JoinRoom *cmd, CommandContainer *cont); + ResponseCode cmdLeaveRoom(Command_LeaveRoom *cmd, CommandContainer *cont, Server_Room *room); + ResponseCode cmdRoomSay(Command_RoomSay *cmd, CommandContainer *cont, Server_Room *room); ResponseCode cmdListUsers(Command_ListUsers *cmd, CommandContainer *cont); - ResponseCode cmdListGames(Command_ListGames *cmd, CommandContainer *cont); - ResponseCode cmdCreateGame(Command_CreateGame *cmd, CommandContainer *cont); - ResponseCode cmdJoinGame(Command_JoinGame *cmd, CommandContainer *cont); + 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 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); @@ -91,9 +90,8 @@ public: ~Server_ProtocolHandler(); void playerRemovedFromGame(Server_Game *game); - bool getAcceptsGameListChanges() const { return acceptsGameListChanges; } bool getAcceptsUserListChanges() const { return acceptsUserListChanges; } - bool getAcceptsChatChannelListChanges() const { return acceptsChatChannelListChanges; } + bool getAcceptsRoomListChanges() const { return acceptsRoomListChanges; } ServerInfo_User *getUserInfo() const { return userInfo; } void setUserInfo(ServerInfo_User *_userInfo) { userInfo = _userInfo; } const QDateTime &getLastCommandTime() const { return lastCommandTime; } diff --git a/common/server_room.cpp b/common/server_room.cpp new file mode 100644 index 00000000..865c0cd7 --- /dev/null +++ b/common/server_room.cpp @@ -0,0 +1,94 @@ +#include "server_room.h" +#include "server_protocolhandler.h" +#include "server_game.h" +#include + +Server_Room::Server_Room(int _id, const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage, Server *parent) + : QObject(parent), id(_id), name(_name), description(_description), autoJoin(_autoJoin), joinMessage(_joinMessage) +{ +} + +Server *Server_Room::getServer() const +{ + return static_cast(parent()); +} + +ServerInfo_Room *Server_Room::getInfo(bool complete) const +{ + QList gameList; + QList userList; + if (complete) { + QMapIterator gameIterator(games); + while (gameIterator.hasNext()) + gameList.append(gameIterator.next().value()->getInfo()); + + for (int i = 0; i < size(); ++i) + userList.append(new ServerInfo_User(at(i)->getUserInfo(), false)); + } + + return new ServerInfo_Room(id, name, description, games.size(), size(), autoJoin, gameList, userList); +} + +void Server_Room::addClient(Server_ProtocolHandler *client) +{ + sendRoomEvent(new Event_JoinRoom(id, new ServerInfo_User(client->getUserInfo()))); + append(client); + + QList eventUserList; + for (int i = 0; i < size(); ++i) + eventUserList.append(new ServerInfo_User(at(i)->getUserInfo())); + + emit roomInfoChanged(); +} + +void Server_Room::removeClient(Server_ProtocolHandler *client) +{ + removeAt(indexOf(client)); + sendRoomEvent(new Event_LeaveRoom(id, client->getUserInfo()->getName())); + emit roomInfoChanged(); +} + +void Server_Room::say(Server_ProtocolHandler *client, const QString &s) +{ + sendRoomEvent(new Event_RoomSay(id, client->getUserInfo()->getName(), s)); +} + +void Server_Room::sendRoomEvent(RoomEvent *event) +{ + for (int i = 0; i < size(); ++i) + at(i)->sendProtocolItem(event, false); + delete event; +} + +void Server_Room::broadcastGameListUpdate(Server_Game *game) +{ + Event_ListGames *event = new Event_ListGames(id, QList() << game->getInfo()); + + for (int i = 0; i < size(); i++) + at(i)->sendProtocolItem(event, false); + delete event; +} + +Server_Game *Server_Room::createGame(const QString &description, const QString &password, int maxPlayers, bool spectatorsAllowed, bool spectatorsNeedPassword, bool spectatorsCanTalk, bool spectatorsSeeEverything, Server_ProtocolHandler *creator) +{ + Server_Game *newGame = new Server_Game(creator, static_cast(parent())->getNextGameId(), description, password, maxPlayers, spectatorsAllowed, spectatorsNeedPassword, spectatorsCanTalk, spectatorsSeeEverything, this); + games.insert(newGame->getGameId(), newGame); + connect(newGame, SIGNAL(gameClosing()), this, SLOT(removeGame())); + + broadcastGameListUpdate(newGame); + + emit gameCreated(newGame); + emit roomInfoChanged(); + + return newGame; +} + +void Server_Room::removeGame() +{ + Server_Game *game = static_cast(sender()); + broadcastGameListUpdate(game); + games.remove(game->getGameId()); + + emit gameClosing(game->getGameId()); + emit roomInfoChanged(); +} diff --git a/common/server_room.h b/common/server_room.h new file mode 100644 index 00000000..3df55b87 --- /dev/null +++ b/common/server_room.h @@ -0,0 +1,51 @@ +#ifndef SERVER_ROOM_H +#define SERVER_ROOM_H + +#include +#include +#include +#include + +class Server_ProtocolHandler; +class RoomEvent; +class ServerInfo_User; +class ServerInfo_Room; +class Server_Game; +class Server; + +class Server_Room : public QObject, public QList { + Q_OBJECT +signals: + void roomInfoChanged(); + void gameCreated(Server_Game *game); + void gameClosing(int gameId); +private: + int id; + QString name; + QString description; + bool autoJoin; + QString joinMessage; + QMap games; +private slots: + void removeGame(); +public: + Server_Room(int _id, const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage, Server *parent); + int getId() const { return id; } + QString getName() const { return name; } + QString getDescription() const { return description; } + bool getAutoJoin() const { return autoJoin; } + QString getJoinMessage() const { return joinMessage; } + const QMap &getGames() const { return games; } + Server *getServer() const; + ServerInfo_Room *getInfo(bool complete) const; + + void addClient(Server_ProtocolHandler *client); + void removeClient(Server_ProtocolHandler *client); + void say(Server_ProtocolHandler *client, const QString &s); + void broadcastGameListUpdate(Server_Game *game); + Server_Game *createGame(const QString &description, const QString &password, int maxPlayers, bool spectatorsAllowed, bool spectatorsNeedPassword, bool spectatorsCanTalk, bool spectatorsSeeEverything, Server_ProtocolHandler *creator); + + void sendRoomEvent(RoomEvent *event); +}; + +#endif diff --git a/servatrice/servatrice.ini.example b/servatrice/servatrice.ini.example index e75d0c45..e9d1246e 100644 --- a/servatrice/servatrice.ini.example +++ b/servatrice/servatrice.ini.example @@ -1,5 +1,6 @@ [server] port=4747 +statusupdate=15000 [authentication] method=none @@ -12,15 +13,12 @@ database=servatrice user=servatrice password=foobar -[messages] -login="Example line" - -[chatchannels] +[rooms] size=1 -1\name="General Chat" -1\description="Discuss anything here." +1\name="General room" +1\description="Play anything here." 1\autojoin=true -1\joinmessage="This is the general chat channel. This message is only here to show that channels can have a join message." +1\joinmessage="This message is only here to show that rooms can have a join message." [game] max_game_inactivity_time=120 diff --git a/servatrice/servatrice.pro b/servatrice/servatrice.pro index d89ecf08..9f7fcc70 100755 --- a/servatrice/servatrice.pro +++ b/servatrice/servatrice.pro @@ -27,7 +27,7 @@ HEADERS += src/servatrice.h \ ../common/server_arrow.h \ ../common/server_card.h \ ../common/server_cardzone.h \ - ../common/server_chatchannel.h \ + ../common/server_room.h \ ../common/server_counter.h \ ../common/server_game.h \ ../common/server_player.h \ @@ -48,7 +48,7 @@ SOURCES += src/main.cpp \ ../common/server.cpp \ ../common/server_card.cpp \ ../common/server_cardzone.cpp \ - ../common/server_chatchannel.cpp \ + ../common/server_room.cpp \ ../common/server_game.cpp \ ../common/server_player.cpp \ ../common/server_protocolhandler.cpp diff --git a/servatrice/src/servatrice.cpp b/servatrice/src/servatrice.cpp index 4be6b7f3..2a77f506 100644 --- a/servatrice/src/servatrice.cpp +++ b/servatrice/src/servatrice.cpp @@ -22,7 +22,7 @@ #include #include #include "servatrice.h" -#include "server_chatchannel.h" +#include "server_room.h" #include "serversocketinterface.h" #include "protocol.h" @@ -33,36 +33,44 @@ Servatrice::Servatrice(QObject *parent) connect(pingClock, SIGNAL(timeout()), this, SIGNAL(pingClockTimeout())); pingClock->start(1000); - statusUpdateClock = new QTimer(this); - connect(statusUpdateClock, SIGNAL(timeout()), this, SLOT(statusUpdate())); - statusUpdateClock->start(15000); - ProtocolItem::initializeHash(); settings = new QSettings("servatrice.ini", QSettings::IniFormat, this); + int statusUpdateTime = settings->value("server/statusupdate").toInt(); + statusUpdateClock = new QTimer(this); + connect(statusUpdateClock, SIGNAL(timeout()), this, SLOT(statusUpdate())); + if (statusUpdateTime != 0) { + qDebug() << "Starting status update clock, interval " << statusUpdateTime << " ms"; + statusUpdateClock->start(statusUpdateTime); + } + tcpServer = new QTcpServer(this); connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection())); - tcpServer->listen(QHostAddress::Any, settings->value("server/port", 4747).toInt()); + int port = settings->value("server/port", 4747).toInt(); + qDebug() << "Starting server on port" << port; + tcpServer->listen(QHostAddress::Any, port); QString dbType = settings->value("database/type").toString(); dbPrefix = settings->value("database/prefix").toString(); if (dbType == "mysql") openDatabase(); - int size = settings->beginReadArray("chatchannels"); + int size = settings->beginReadArray("rooms"); for (int i = 0; i < size; ++i) { settings->setArrayIndex(i); - Server_ChatChannel *newChannel = new Server_ChatChannel( + Server_Room *newRoom = new Server_Room( + i, settings->value("name").toString(), settings->value("description").toString(), settings->value("autojoin").toBool(), - settings->value("joinmessage").toString() + settings->value("joinmessage").toString(), + this ); - addChatChannel(newChannel); + addRoom(newRoom); } settings->endArray(); - loginMessage = settings->value("messages/login").toString(); + updateLoginMessage(); maxGameInactivityTime = settings->value("game/max_game_inactivity_time").toInt(); maxPlayerInactivityTime = settings->value("game/max_player_inactivity_time").toInt(); @@ -183,6 +191,16 @@ ServerInfo_User *Servatrice::getUserData(const QString &name) return new ServerInfo_User(name, ServerInfo_User::IsUser); } +void Servatrice::updateLoginMessage() +{ + checkSql(); + QSqlQuery query; + query.prepare("select message from " + dbPrefix + "_servermessages order by timest desc limit 1"); + if (execSqlQuery(query)) + if (query.next()) + loginMessage = query.value(0).toString(); +} + void Servatrice::statusUpdate() { uptime += statusUpdateClock->interval() / 1000; @@ -197,4 +215,4 @@ void Servatrice::statusUpdate() execSqlQuery(query); } -const QString Servatrice::versionString = "Servatrice 0.20101116"; +const QString Servatrice::versionString = "Servatrice 0.20110103"; diff --git a/servatrice/src/servatrice.h b/servatrice/src/servatrice.h index 39a1a1a6..479af4fd 100644 --- a/servatrice/src/servatrice.h +++ b/servatrice/src/servatrice.h @@ -46,6 +46,7 @@ public: int getMaxGameInactivityTime() const { return maxGameInactivityTime; } int getMaxPlayerInactivityTime() const { return maxPlayerInactivityTime; } QString getDbPrefix() const { return dbPrefix; } + void updateLoginMessage(); protected: AuthenticationResult checkUserPassword(const QString &user, const QString &password); ServerInfo_User *getUserData(const QString &name);