implemented direct chat

This commit is contained in:
Max-Wilhelm Bruker 2010-09-18 23:47:39 +02:00
parent a8e166b609
commit e597325ec3
24 changed files with 821 additions and 335 deletions

View file

@ -52,6 +52,7 @@ HEADERS += src/counter.h \
src/tab.h \
src/tab_server.h \
src/tab_chatchannel.h \
src/tab_message.h \
src/tab_game.h \
src/tab_deck_storage.h \
src/tab_supervisor.h \
@ -125,6 +126,7 @@ SOURCES += src/counter.cpp \
src/arrowtarget.cpp \
src/tab_server.cpp \
src/tab_chatchannel.cpp \
src/tab_message.cpp \
src/tab_game.cpp \
src/tab_deck_storage.cpp \
src/tab_supervisor.cpp \

View file

@ -33,9 +33,12 @@ void AbstractClient::processProtocolItem(ProtocolItem *item)
if (genericEvent) {
switch (genericEvent->getItemId()) {
case ItemId_Event_ListGames: emit listGamesEventReceived(qobject_cast<Event_ListGames *>(item)); break;
case ItemId_Event_UserJoined: emit userJoinedEventReceived(qobject_cast<Event_UserJoined *>(item)); break;
case ItemId_Event_UserLeft: emit userLeftEventReceived(qobject_cast<Event_UserLeft *>(item)); break;
case ItemId_Event_ServerMessage: emit serverMessageEventReceived(qobject_cast<Event_ServerMessage *>(item)); break;
case ItemId_Event_ListChatChannels: emit listChatChannelsEventReceived(qobject_cast<Event_ListChatChannels *>(item)); break;
case ItemId_Event_GameJoined: emit gameJoinedEventReceived(qobject_cast<Event_GameJoined *>(item)); break;
case ItemId_Event_Message: emit messageEventReceived(qobject_cast<Event_Message *>(item)); break;
}
if (genericEvent->getReceiverMayDelete())
delete genericEvent;

View file

@ -13,9 +13,12 @@ class CommandContainer;
class ChatEvent;
class GameEventContainer;
class Event_ListGames;
class Event_UserJoined;
class Event_UserLeft;
class Event_ServerMessage;
class Event_ListChatChannels;
class Event_GameJoined;
class Event_Message;
enum ClientStatus {
StatusDisconnected,
@ -38,9 +41,12 @@ signals:
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 gameJoinedEventReceived(Event_GameJoined *event);
void messageEventReceived(Event_Message *event);
protected slots:
void processProtocolItem(ProtocolItem *item);
protected:

View file

@ -2,6 +2,7 @@
#include <QPainter>
#include <QSvgRenderer>
#include <math.h>
#include <QDebug>
QPixmap PingPixmapGenerator::generatePixmap(int size, int value, int max)
{
@ -39,11 +40,13 @@ QPixmap CountryPixmapGenerator::generatePixmap(int height, const QString &countr
return pmCache.value(key);
QSvgRenderer svg(QString(":/resources/countries/" + countryCode + ".svg"));
double aspect = (double) svg.defaultSize().width() / (double) svg.defaultSize().height();
QPixmap pixmap((int) round(aspect * height), height);
int width = (int) round(height * (double) svg.defaultSize().width() / (double) svg.defaultSize().height());
QPixmap pixmap(width, height);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
svg.render(&painter, QRectF(0, 0, aspect * height, height));
svg.render(&painter, QRectF(0, 0, width, height));
painter.setPen(Qt::black);
painter.drawRect(0.5, 0.5, width - 1, height - 1);
pmCache.insert(key, pixmap);
return pixmap;

View file

@ -466,7 +466,7 @@ void Player::actMoveTopCardsToGrave()
void Player::actMoveTopCardsToExile()
{
int number = QInputDialog::getInteger(0, tr("Move top cards to grave"), tr("Number:"));
int number = QInputDialog::getInteger(0, tr("Move top cards to exile"), tr("Number:"));
if (!number)
return;

View file

@ -13,6 +13,7 @@ PlayerListWidget::PlayerListWidget(QWidget *parent)
playerIcon = QIcon(":/resources/icon_player.svg");
spectatorIcon = QIcon(":/resources/icon_spectator.svg");
setIconSize(QSize(20, 15));
setColumnCount(5);
setRootIsDecorated(false);
setSelectionMode(NoSelection);
@ -47,7 +48,7 @@ void PlayerListWidget::updatePlayerProperties(ServerInfo_PlayerProperties *prop)
player->setIcon(2, gameStarted ? (prop->getConceded() ? concededIcon : QIcon()) : (prop->getReadyStart() ? readyIcon : notReadyIcon));
player->setText(3, prop->getUserInfo()->getName());
if (!prop->getUserInfo()->getCountry().isEmpty())
player->setIcon(3, QIcon(CountryPixmapGenerator::generatePixmap(10, prop->getUserInfo()->getCountry())));
player->setIcon(3, QIcon(CountryPixmapGenerator::generatePixmap(12, prop->getUserInfo()->getCountry())));
QString deckText;
if (!prop->getSpectator())

View file

@ -49,6 +49,14 @@ void TabChatChannel::retranslateUi()
aLeaveChannel->setText(tr("&Leave channel"));
}
QString TabChatChannel::sanitizeHtml(QString dirty) const
{
return dirty
.replace("&", "&amp;")
.replace("<", "&lt;")
.replace(">", "&gt;");
}
void TabChatChannel::sendMessage()
{
if (sayEdit->text().isEmpty())
@ -84,14 +92,14 @@ void TabChatChannel::processListPlayersEvent(Event_ChatListPlayers *event)
void TabChatChannel::processJoinChannelEvent(Event_ChatJoinChannel *event)
{
textEdit->append(tr("%1 has joined the channel.").arg(event->getUserInfo()->getName()));
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(event->getPlayerName()));
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);
@ -103,8 +111,8 @@ void TabChatChannel::processLeaveChannelEvent(Event_ChatLeaveChannel *event)
void TabChatChannel::processSayEvent(Event_ChatSay *event)
{
if (event->getPlayerName().isEmpty())
textEdit->append(QString("<font color=\"blue\">%1</font").arg(event->getMessage()));
textEdit->append(QString("<font color=\"blue\">%1</font").arg(sanitizeHtml(event->getMessage())));
else
textEdit->append(QString("<font color=\"red\">%1:</font> %2").arg(event->getPlayerName()).arg(event->getMessage()));
textEdit->append(QString("<font color=\"red\">%1:</font> %2").arg(sanitizeHtml(event->getPlayerName())).arg(sanitizeHtml(event->getMessage())));
emit userEvent();
}

View file

@ -24,6 +24,7 @@ private:
QLineEdit *sayEdit;
QAction *aLeaveChannel;
QString sanitizeHtml(QString dirty) const;
signals:
void channelClosing(TabChatChannel *tab);
private slots:

View file

@ -15,6 +15,8 @@
#include "abstractclient.h"
#include "protocol.h"
#include "protocol_items.h"
#include "pixmapgenerator.h"
#include <QDebug>
GameSelector::GameSelector(AbstractClient *_client, QWidget *parent)
: QGroupBox(parent), client(_client)
@ -235,23 +237,116 @@ void ServerMessageLog::processServerMessageEvent(Event_ServerMessage *event)
textEdit->append(event->getMessage());
}
UserList::UserList(AbstractClient *_client, QWidget *parent)
: QGroupBox(parent)
{
userTree = new QTreeWidget;
userTree->setColumnCount(2);
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(1, Qt::UserRole) == user->getName()) {
item = temp;
break;
}
}
if (!item) {
item = new QTreeWidgetItem;
userTree->addTopLevelItem(item);
retranslateUi();
}
item->setIcon(0, QIcon(CountryPixmapGenerator::generatePixmap(12, user->getCountry())));
item->setData(1, Qt::UserRole, user->getName());
item->setData(1, Qt::DisplayRole, user->getName());
}
void UserList::processResponse(ProtocolResponse *response)
{
Response_ListUsers *resp = qobject_cast<Response_ListUsers *>(response);
if (!resp)
return;
const QList<ServerInfo_User *> &respList = resp->getUserList();
for (int i = 0; i < respList.size(); ++i)
processUserInfo(respList[i]);
userTree->sortItems(1, Qt::AscendingOrder);
}
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(1, 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(1, Qt::UserRole).toString(), true);
}
TabServer::TabServer(AbstractClient *_client, QWidget *parent)
: Tab(parent), client(_client)
{
gameSelector = new GameSelector(client);
chatChannelSelector = new ChatChannelSelector(client);
serverMessageLog = new ServerMessageLog(client);
userList = new UserList(client);
connect(gameSelector, SIGNAL(gameJoined(int)), this, SIGNAL(gameJoined(int)));
connect(chatChannelSelector, SIGNAL(channelJoined(const QString &)), this, SIGNAL(chatChannelJoined(const QString &)));
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);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(gameSelector);
mainLayout->addLayout(hbox);
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(gameSelector);
vbox->addLayout(hbox);
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addLayout(vbox, 3);
mainLayout->addWidget(userList, 1);
setLayout(mainLayout);
}
@ -261,4 +356,5 @@ void TabServer::retranslateUi()
gameSelector->retranslateUi();
chatChannelSelector->retranslateUi();
serverMessageLog->retranslateUi();
userList->retranslateUi();
}

View file

@ -8,6 +8,7 @@
class AbstractClient;
class QTreeView;
class QTreeWidget;
class QTreeWidgetItem;
class QPushButton;
class QCheckBox;
class QTextEdit;
@ -18,6 +19,9 @@ class GamesProxyModel;
class Event_ListGames;
class Event_ListChatChannels;
class Event_ServerMessage;
class Event_UserJoined;
class Event_UserLeft;
class ProtocolResponse;
class GameSelector : public QGroupBox {
Q_OBJECT
@ -72,16 +76,37 @@ public:
void retranslateUi();
};
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);
void retranslateUi();
};
class TabServer : public Tab {
Q_OBJECT
signals:
void chatChannelJoined(const QString &channelName);
void gameJoined(int gameId);
void openMessageDialog(const QString &userName, bool focus);
void userLeft(const QString &userName);
private:
AbstractClient *client;
GameSelector *gameSelector;
ChatChannelSelector *chatChannelSelector;
ServerMessageLog *serverMessageLog;
UserList *userList;
public:
TabServer(AbstractClient *_client, QWidget *parent = 0);
void retranslateUi();

View file

@ -5,6 +5,7 @@
#include "tab_chatchannel.h"
#include "tab_game.h"
#include "tab_deck_storage.h"
#include "tab_message.h"
#include "protocol_items.h"
#include "pixmapgenerator.h"
#include <QDebug>
@ -56,10 +57,13 @@ void TabSupervisor::start(AbstractClient *_client)
connect(client, SIGNAL(chatEventReceived(ChatEvent *)), this, SLOT(processChatEvent(ChatEvent *)));
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 &)));
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);
updatePingTime(0, -1);
@ -173,6 +177,25 @@ void TabSupervisor::chatChannelLeft(TabChatChannel *tab)
removeTab(indexOf(tab));
}
TabMessage *TabSupervisor::addMessageTab(const QString &userName, bool focus)
{
TabMessage *tab = new TabMessage(client, userName);
connect(tab, SIGNAL(talkClosing(TabMessage *)), this, SLOT(talkLeft(TabMessage *)));
myAddTab(tab);
messageTabs.insert(userName, tab);
if (focus)
setCurrentWidget(tab);
return tab;
}
void TabSupervisor::talkLeft(TabMessage *tab)
{
emit setMenu(0);
messageTabs.remove(tab->getUserName());
removeTab(indexOf(tab));
}
void TabSupervisor::tabUserEvent()
{
Tab *tab = static_cast<Tab *>(sender());
@ -200,6 +223,23 @@ void TabSupervisor::processGameEventContainer(GameEventContainer *cont)
qDebug() << "gameEvent: invalid gameId";
}
void TabSupervisor::processMessageEvent(Event_Message *event)
{
TabMessage *tab = messageTabs.value(event->getSenderName());
if (!tab)
tab = messageTabs.value(event->getReceiverName());
if (!tab)
tab = addMessageTab(event->getSenderName(), false);
tab->processMessageEvent(event);
}
void TabSupervisor::processUserLeft(const QString &userName)
{
TabMessage *tab = messageTabs.value(userName);
if (tab)
tab->processUserLeft(userName);
}
void TabSupervisor::updateCurrent(int index)
{
if (index != -1) {

View file

@ -11,9 +11,11 @@ class TabServer;
class TabChatChannel;
class TabGame;
class TabDeckStorage;
class TabMessage;
class ChatEvent;
class GameEventContainer;
class Event_GameJoined;
class Event_Message;
class TabSupervisor : public QTabWidget {
Q_OBJECT
@ -25,6 +27,7 @@ private:
TabDeckStorage *tabDeckStorage;
QMap<QString, TabChatChannel *> chatChannelTabs;
QMap<int, TabGame *> gameTabs;
QMap<QString, TabMessage *> messageTabs;
void myAddTab(Tab *tab);
public:
TabSupervisor(QWidget *parent = 0);
@ -45,9 +48,13 @@ private slots:
void gameLeft(TabGame *tab);
void addChatChannelTab(const QString &channelName);
void chatChannelLeft(TabChatChannel *tab);
TabMessage *addMessageTab(const QString &userName, bool focus);
void processUserLeft(const QString &userName);
void talkLeft(TabMessage *tab);
void tabUserEvent();
void processChatEvent(ChatEvent *event);
void processGameEventContainer(GameEventContainer *cont);
void processMessageEvent(Event_Message *event);
};
#endif

View file

@ -398,27 +398,27 @@
<context>
<name>ChatChannelSelector</name>
<message>
<location filename="../src/tab_server.cpp" line="150"/>
<location filename="../src/tab_server.cpp" line="152"/>
<source>Chat channels</source>
<translation>Chaträume</translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="151"/>
<location filename="../src/tab_server.cpp" line="153"/>
<source>Joi&amp;n</source>
<translation>Teil&amp;nehmen</translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="154"/>
<location filename="../src/tab_server.cpp" line="156"/>
<source>Channel</source>
<translation>Raum</translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="155"/>
<location filename="../src/tab_server.cpp" line="157"/>
<source>Description</source>
<translation>Beschreibung</translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="156"/>
<location filename="../src/tab_server.cpp" line="158"/>
<source>Players</source>
<translation>Spieler</translation>
</message>
@ -1162,20 +1162,20 @@
<context>
<name>GameSelector</name>
<message>
<location filename="../src/tab_server.cpp" line="114"/>
<location filename="../src/tab_server.cpp" line="116"/>
<source>C&amp;reate</source>
<translation>Spiel e&amp;rstellen</translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="115"/>
<location filename="../src/tab_server.cpp" line="117"/>
<source>&amp;Join</source>
<translation>&amp;Teilnehmen</translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="77"/>
<location filename="../src/tab_server.cpp" line="78"/>
<location filename="../src/tab_server.cpp" line="79"/>
<location filename="../src/tab_server.cpp" line="80"/>
<location filename="../src/tab_server.cpp" line="81"/>
<location filename="../src/tab_server.cpp" line="82"/>
<source>Error</source>
<translation>Fehler</translation>
</message>
@ -1184,47 +1184,47 @@
<translation type="obsolete">XXX</translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="77"/>
<location filename="../src/tab_server.cpp" line="79"/>
<source>Wrong password.</source>
<translation>Falsches Passwort.</translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="78"/>
<location filename="../src/tab_server.cpp" line="80"/>
<source>Spectators are not allowed in this game.</source>
<translation>In diesem Spiel sind keine Zuschauer zugelassen.</translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="79"/>
<location filename="../src/tab_server.cpp" line="81"/>
<source>The game is already full.</source>
<translation>Das Spiel ist bereits voll.</translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="80"/>
<location filename="../src/tab_server.cpp" line="82"/>
<source>The game does not exist any more.</source>
<translation>Dieses Spiel gibt es nicht mehr.</translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="96"/>
<location filename="../src/tab_server.cpp" line="98"/>
<source>Join game</source>
<translation>Spiel beitreten</translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="96"/>
<location filename="../src/tab_server.cpp" line="98"/>
<source>Password:</source>
<translation>Passwort:</translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="112"/>
<location filename="../src/tab_server.cpp" line="114"/>
<source>Games</source>
<translation>Spiele</translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="113"/>
<location filename="../src/tab_server.cpp" line="115"/>
<source>&amp;Show full games</source>
<translation>&amp;Volle Spiele anzeigen</translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="116"/>
<location filename="../src/tab_server.cpp" line="118"/>
<source>J&amp;oin as spectator</source>
<translation>&amp;Zuschauen</translation>
</message>
@ -1810,27 +1810,37 @@
<translation>%1 legt %2%3 in sein Sideboard.</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="207"/>
<location filename="../src/messagelogwidget.cpp" line="208"/>
<source>%1 flips %2 face-down.</source>
<translation>%1 wendet %2 auf die Rückseite.</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="210"/>
<source>%1 flips %2 face-up.</source>
<translation>%1 wendet %2 auf die Vorderseite.</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="215"/>
<source>%1 destroys %2.</source>
<translation>%1 zerstört %2.</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="212"/>
<location filename="../src/messagelogwidget.cpp" line="220"/>
<source>%1 attaches %2 to %3&apos;s %4.</source>
<translation>%1 legt %2 an %3s %4 an.</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="217"/>
<location filename="../src/messagelogwidget.cpp" line="225"/>
<source>%1 unattaches %2.</source>
<translation>%1 löst %2 ab.</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="222"/>
<location filename="../src/messagelogwidget.cpp" line="230"/>
<source>%1 creates token: %2%3.</source>
<translation>%1 erstellt Token: %2%3.</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="228"/>
<location filename="../src/messagelogwidget.cpp" line="236"/>
<source>%1 points from %2&apos;s %3 to %4.</source>
<translation>%1 zeigt von %2s %3 auf %4.</translation>
</message>
@ -1839,12 +1849,12 @@
<translation type="obsolete">%1 erstellt einen Spielstein: %2 (%3).</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="235"/>
<location filename="../src/messagelogwidget.cpp" line="243"/>
<source>%1 points from %2&apos;s %3 to %4&apos;s %5.</source>
<translation>%1 zeigt von %2s %3 auf %4s %5.</translation>
</message>
<message numerus="yes">
<location filename="../src/messagelogwidget.cpp" line="250"/>
<location filename="../src/messagelogwidget.cpp" line="258"/>
<source>%1 places %n counter(s) (%2) on %3 (now %4).</source>
<translation>
<numerusform>%1 legt eine Marke (%2) auf %3 (jetzt %4).</numerusform>
@ -1852,7 +1862,7 @@
</translation>
</message>
<message numerus="yes">
<location filename="../src/messagelogwidget.cpp" line="252"/>
<location filename="../src/messagelogwidget.cpp" line="260"/>
<source>%1 removes %n counter(s) (%2) from %3 (now %4).</source>
<translation>
<numerusform>%1 entfernt eine Marke (%2) von %3 (jetzt %4).</numerusform>
@ -1860,37 +1870,37 @@
</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="255"/>
<location filename="../src/messagelogwidget.cpp" line="263"/>
<source>red</source>
<translation>rot</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="256"/>
<location filename="../src/messagelogwidget.cpp" line="264"/>
<source>yellow</source>
<translation>gelb</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="257"/>
<location filename="../src/messagelogwidget.cpp" line="265"/>
<source>green</source>
<translation>grün</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="276"/>
<location filename="../src/messagelogwidget.cpp" line="284"/>
<source>%1 sets counter %2 to %3 (%4%5).</source>
<translation>%1 setzt Zähler %2 auf %3 (%4%5).</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="291"/>
<location filename="../src/messagelogwidget.cpp" line="299"/>
<source>%1 sets PT of %2 to %3.</source>
<translation>%1 setzt Kampfwerte von %2 auf %3.</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="296"/>
<location filename="../src/messagelogwidget.cpp" line="304"/>
<source>%1 sets annotation of %2 to %3.</source>
<translation>%1 versieht %2 mit dem Hinweis %3.</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="302"/>
<location filename="../src/messagelogwidget.cpp" line="310"/>
<source>%1 is looking at the top %2 cards %3.</source>
<translation>%1 sieht sich die obersten %2 Karten %3 an.</translation>
</message>
@ -1987,7 +1997,7 @@
<translation type="obsolete">%1 entfernt %2 Zählmarken von %3 (jetzt %4).</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="271"/>
<location filename="../src/messagelogwidget.cpp" line="279"/>
<source>%1 %2 %3.</source>
<translation>%1 %2 %3.</translation>
</message>
@ -2000,17 +2010,17 @@
<translation type="obsolete">%1 sieht sich die obersten %2 Karten %3 an.</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="304"/>
<location filename="../src/messagelogwidget.cpp" line="312"/>
<source>%1 is looking at %2.</source>
<translation>%1 sieht sich %2 an.</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="310"/>
<location filename="../src/messagelogwidget.cpp" line="318"/>
<source>%1 stops looking at %2.</source>
<translation>%1 sieht sich %2 nicht mehr an.</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="334"/>
<location filename="../src/messagelogwidget.cpp" line="342"/>
<source>ending phase</source>
<translation>die Zugendphase</translation>
</message>
@ -2039,57 +2049,57 @@
<translation type="obsolete">%1 sieht sich %2s %3 nicht mehr an</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="316"/>
<location filename="../src/messagelogwidget.cpp" line="324"/>
<source>It is now %1&apos;s turn.</source>
<translation>%1 ist am Zug.</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="324"/>
<location filename="../src/messagelogwidget.cpp" line="332"/>
<source>untap step</source>
<translation>das Enttappsegment</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="325"/>
<location filename="../src/messagelogwidget.cpp" line="333"/>
<source>upkeep step</source>
<translation>das Versorgungssegment</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="326"/>
<location filename="../src/messagelogwidget.cpp" line="334"/>
<source>draw step</source>
<translation>das Ziehsegment</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="327"/>
<location filename="../src/messagelogwidget.cpp" line="335"/>
<source>first main phase</source>
<translation>die erste Hauptphase</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="328"/>
<location filename="../src/messagelogwidget.cpp" line="336"/>
<source>beginning of combat step</source>
<translation>das Anfangssegment der Kampfphase</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="329"/>
<location filename="../src/messagelogwidget.cpp" line="337"/>
<source>declare attackers step</source>
<translation>das Angreifer-Deklarieren-Segment</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="330"/>
<location filename="../src/messagelogwidget.cpp" line="338"/>
<source>declare blockers step</source>
<translation>das Blocker-Deklarieren-Segment</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="331"/>
<location filename="../src/messagelogwidget.cpp" line="339"/>
<source>combat damage step</source>
<translation>das Kampfschadenssegment</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="332"/>
<location filename="../src/messagelogwidget.cpp" line="340"/>
<source>end of combat step</source>
<translation>das Endsegment der Kampfphase</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="333"/>
<location filename="../src/messagelogwidget.cpp" line="341"/>
<source>second main phase</source>
<translation>die zweite Hauptphase</translation>
</message>
@ -2098,7 +2108,7 @@
<translation type="obsolete">das Ende-des-Zuges-Segment</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="336"/>
<location filename="../src/messagelogwidget.cpp" line="344"/>
<source>It is now the %1.</source>
<translation>Es ist nun %1.</translation>
</message>
@ -2107,12 +2117,12 @@
<translation type="obsolete">%1 bewegt %2 %3 nach %4</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="271"/>
<location filename="../src/messagelogwidget.cpp" line="279"/>
<source>taps</source>
<translation>tappt</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="271"/>
<location filename="../src/messagelogwidget.cpp" line="279"/>
<source>untaps</source>
<translation>enttappt</translation>
</message>
@ -2137,7 +2147,7 @@
<translation type="obsolete">%1 entfernt %2 Zählmarken von %3 (jetzt %4)</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="268"/>
<location filename="../src/messagelogwidget.cpp" line="276"/>
<source>his permanents</source>
<translation>seine bleibenden Karten</translation>
</message>
@ -2150,12 +2160,12 @@
<translation type="obsolete">%1 setzt Zähler &quot;%2&quot; auf %3 (%4%5)</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="283"/>
<location filename="../src/messagelogwidget.cpp" line="291"/>
<source>%1 sets %2 to not untap normally.</source>
<translation>%1 setzt %2 auf explizites Enttappen.</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="285"/>
<location filename="../src/messagelogwidget.cpp" line="293"/>
<source>%1 sets %2 to untap normally.</source>
<translation>%1 setzt %2 auf normales Enttappen.</translation>
</message>
@ -2260,41 +2270,51 @@
<context>
<name>Player</name>
<message>
<location filename="../src/player.cpp" line="290"/>
<location filename="../src/player.cpp" line="294"/>
<location filename="../src/player.cpp" line="298"/>
<location filename="../src/player.cpp" line="297"/>
<location filename="../src/player.cpp" line="301"/>
<location filename="../src/player.cpp" line="305"/>
<source>Move to &amp;top of library</source>
<translation>Oben auf die Biblio&amp;thek legen</translation>
</message>
<message>
<location filename="../src/player.cpp" line="291"/>
<location filename="../src/player.cpp" line="295"/>
<location filename="../src/player.cpp" line="299"/>
<location filename="../src/player.cpp" line="298"/>
<location filename="../src/player.cpp" line="302"/>
<location filename="../src/player.cpp" line="306"/>
<source>Move to &amp;bottom of library</source>
<translation>Unter die &amp;Bibliothek legen</translation>
</message>
<message>
<location filename="../src/player.cpp" line="302"/>
<location filename="../src/player.cpp" line="309"/>
<source>&amp;View library</source>
<translation>&amp;Zeige Bibliothek</translation>
</message>
<message>
<location filename="../src/player.cpp" line="337"/>
<location filename="../src/player.cpp" line="316"/>
<source>Move top cards to g&amp;raveyard...</source>
<translation>Oberste Karten in den F&amp;riedhof legen...</translation>
</message>
<message>
<location filename="../src/player.cpp" line="317"/>
<source>Move top cards to &amp;exile...</source>
<translation>Oberste Karten ins &amp;Exil schicken...</translation>
</message>
<message>
<location filename="../src/player.cpp" line="346"/>
<source>F3</source>
<translation>F3</translation>
</message>
<message>
<location filename="../src/player.cpp" line="303"/>
<location filename="../src/player.cpp" line="310"/>
<source>View &amp;top cards of library...</source>
<translation>Zeige die oberen Kar&amp;ten der Bibliothek...</translation>
</message>
<message>
<location filename="../src/player.cpp" line="283"/>
<location filename="../src/player.cpp" line="290"/>
<source>&amp;View graveyard</source>
<translation>&amp;Zeige Friedhof</translation>
</message>
<message>
<location filename="../src/player.cpp" line="339"/>
<location filename="../src/player.cpp" line="348"/>
<source>F4</source>
<translation>F4</translation>
</message>
@ -2303,32 +2323,32 @@
<translation type="obsolete">Zeige ent&amp;fernte Karten</translation>
</message>
<message>
<location filename="../src/player.cpp" line="304"/>
<location filename="../src/player.cpp" line="311"/>
<source>&amp;View sideboard</source>
<translation>Zeige &amp;Sideboard</translation>
</message>
<message>
<location filename="../src/player.cpp" line="285"/>
<location filename="../src/player.cpp" line="292"/>
<source>Player &quot;%1&quot;</source>
<translation>Spieler &quot;%1&quot;</translation>
</message>
<message>
<location filename="../src/player.cpp" line="307"/>
<location filename="../src/player.cpp" line="314"/>
<source>Take &amp;mulligan</source>
<translation>&amp;Mulligan nehmen</translation>
</message>
<message>
<location filename="../src/player.cpp" line="310"/>
<location filename="../src/player.cpp" line="319"/>
<source>&amp;Hand</source>
<translation>&amp;Hand</translation>
</message>
<message>
<location filename="../src/player.cpp" line="312"/>
<location filename="../src/player.cpp" line="321"/>
<source>&amp;Library</source>
<translation>Bib&amp;liothek</translation>
</message>
<message>
<location filename="../src/player.cpp" line="286"/>
<location filename="../src/player.cpp" line="293"/>
<source>&amp;Graveyard</source>
<translation>&amp;Friedhof</translation>
</message>
@ -2337,7 +2357,7 @@
<translation type="obsolete">Entfe&amp;rnte Karten</translation>
</message>
<message>
<location filename="../src/player.cpp" line="311"/>
<location filename="../src/player.cpp" line="320"/>
<source>&amp;Sideboard</source>
<translation>&amp;Sideboard</translation>
</message>
@ -2350,65 +2370,65 @@
<translation type="obsolete">&amp;Hinweis setzen...</translation>
</message>
<message>
<location filename="../src/player.cpp" line="399"/>
<location filename="../src/player.cpp" line="408"/>
<source>View top cards of library</source>
<translation>Zeige die obersten Karten der Bibliothek</translation>
</message>
<message>
<location filename="../src/player.cpp" line="399"/>
<location filename="../src/player.cpp" line="408"/>
<source>Number of cards:</source>
<translation>Anzahl der Karten:</translation>
</message>
<message>
<location filename="../src/player.cpp" line="305"/>
<location filename="../src/player.cpp" line="312"/>
<source>&amp;Draw card</source>
<translation>Karte &amp;ziehen</translation>
</message>
<message>
<location filename="../src/player.cpp" line="284"/>
<location filename="../src/player.cpp" line="291"/>
<source>&amp;View exile</source>
<translation>&amp;Zeige Exil</translation>
</message>
<message>
<location filename="../src/player.cpp" line="287"/>
<location filename="../src/player.cpp" line="294"/>
<source>&amp;Exile</source>
<translation>&amp;Exil</translation>
</message>
<message>
<location filename="../src/player.cpp" line="296"/>
<location filename="../src/player.cpp" line="300"/>
<location filename="../src/player.cpp" line="303"/>
<location filename="../src/player.cpp" line="307"/>
<source>Move to &amp;hand</source>
<translation>auf die &amp;Hand nehmen</translation>
</message>
<message>
<location filename="../src/player.cpp" line="292"/>
<location filename="../src/player.cpp" line="301"/>
<location filename="../src/player.cpp" line="299"/>
<location filename="../src/player.cpp" line="308"/>
<source>Move to g&amp;raveyard</source>
<translation>auf den &amp;Friedhof legen</translation>
</message>
<message>
<location filename="../src/player.cpp" line="293"/>
<location filename="../src/player.cpp" line="297"/>
<location filename="../src/player.cpp" line="300"/>
<location filename="../src/player.cpp" line="304"/>
<source>Move to &amp;exile</source>
<translation>ins &amp;Exil schicken</translation>
</message>
<message>
<location filename="../src/player.cpp" line="338"/>
<location filename="../src/player.cpp" line="347"/>
<source>Ctrl+W</source>
<translation>Ctrl+W</translation>
</message>
<message>
<location filename="../src/player.cpp" line="340"/>
<location filename="../src/player.cpp" line="349"/>
<source>Ctrl+D</source>
<translation>Ctrl+D</translation>
</message>
<message>
<location filename="../src/player.cpp" line="306"/>
<location filename="../src/player.cpp" line="313"/>
<source>D&amp;raw cards...</source>
<translation>Ka&amp;rten ziehen...</translation>
</message>
<message>
<location filename="../src/player.cpp" line="341"/>
<location filename="../src/player.cpp" line="350"/>
<source>Ctrl+E</source>
<translation>Ctrl+E</translation>
</message>
@ -2417,32 +2437,32 @@
<translation type="obsolete">&amp;Mulligan nehmen...</translation>
</message>
<message>
<location filename="../src/player.cpp" line="342"/>
<location filename="../src/player.cpp" line="351"/>
<source>Ctrl+M</source>
<translation>Ctrl+M</translation>
</message>
<message>
<location filename="../src/player.cpp" line="308"/>
<location filename="../src/player.cpp" line="315"/>
<source>&amp;Shuffle</source>
<translation>Mi&amp;schen</translation>
</message>
<message>
<location filename="../src/player.cpp" line="343"/>
<location filename="../src/player.cpp" line="352"/>
<source>Ctrl+S</source>
<translation>Ctrl+S</translation>
</message>
<message>
<location filename="../src/player.cpp" line="313"/>
<location filename="../src/player.cpp" line="322"/>
<source>&amp;Counters</source>
<translation>&amp;Zähler</translation>
</message>
<message>
<location filename="../src/player.cpp" line="315"/>
<location filename="../src/player.cpp" line="324"/>
<source>&amp;Untap all permanents</source>
<translation>&amp;Enttappe alle bleibenden Karten</translation>
</message>
<message>
<location filename="../src/player.cpp" line="344"/>
<location filename="../src/player.cpp" line="353"/>
<source>Ctrl+U</source>
<translation>Ctrl+U</translation>
</message>
@ -2471,42 +2491,42 @@
<translation type="obsolete">Ctrl+L</translation>
</message>
<message>
<location filename="../src/player.cpp" line="316"/>
<location filename="../src/player.cpp" line="325"/>
<source>R&amp;oll die...</source>
<translation>&amp;Würfeln...</translation>
</message>
<message>
<location filename="../src/player.cpp" line="345"/>
<location filename="../src/player.cpp" line="354"/>
<source>Ctrl+I</source>
<translation>Ctrl+I</translation>
</message>
<message>
<location filename="../src/player.cpp" line="317"/>
<location filename="../src/player.cpp" line="326"/>
<source>&amp;Create token...</source>
<translation>Spiels&amp;tein erstellen...</translation>
</message>
<message>
<location filename="../src/player.cpp" line="346"/>
<location filename="../src/player.cpp" line="355"/>
<source>Ctrl+T</source>
<translation>Ctrl+T</translation>
</message>
<message>
<location filename="../src/player.cpp" line="318"/>
<location filename="../src/player.cpp" line="327"/>
<source>C&amp;reate another token</source>
<translation>&amp;Noch einen Spielstein erstellen</translation>
</message>
<message>
<location filename="../src/player.cpp" line="347"/>
<location filename="../src/player.cpp" line="356"/>
<source>Ctrl+G</source>
<translation>Ctrl+G</translation>
</message>
<message>
<location filename="../src/player.cpp" line="319"/>
<location filename="../src/player.cpp" line="328"/>
<source>S&amp;ay</source>
<translation>S&amp;agen</translation>
</message>
<message>
<location filename="../src/player.cpp" line="325"/>
<location filename="../src/player.cpp" line="334"/>
<source>C&amp;ard</source>
<translation>&amp;Karte</translation>
</message>
@ -2599,38 +2619,50 @@
<translation type="obsolete">F10</translation>
</message>
<message>
<location filename="../src/player.cpp" line="438"/>
<location filename="../src/player.cpp" line="447"/>
<source>Draw cards</source>
<translation>Karten ziehen</translation>
</message>
<message>
<location filename="../src/player.cpp" line="438"/>
<location filename="../src/player.cpp" line="1185"/>
<location filename="../src/player.cpp" line="447"/>
<location filename="../src/player.cpp" line="454"/>
<location filename="../src/player.cpp" line="469"/>
<location filename="../src/player.cpp" line="1242"/>
<source>Number:</source>
<translation>Anzahl:</translation>
</message>
<message>
<location filename="../src/player.cpp" line="1103"/>
<location filename="../src/player.cpp" line="454"/>
<source>Move top cards to grave</source>
<translation>Oberste Karten in den Friedhof legen</translation>
</message>
<message>
<location filename="../src/player.cpp" line="469"/>
<source>Move top cards to exile</source>
<translation>Oberste Karten ins Exil schicken</translation>
</message>
<message>
<location filename="../src/player.cpp" line="1160"/>
<source>Set power/toughness</source>
<translation>Kampfwerte setzen</translation>
</message>
<message>
<location filename="../src/player.cpp" line="1103"/>
<location filename="../src/player.cpp" line="1160"/>
<source>Please enter the new PT:</source>
<translation>Bitte die neuen Kampfwerte eingeben:</translation>
</message>
<message>
<location filename="../src/player.cpp" line="1129"/>
<location filename="../src/player.cpp" line="1186"/>
<source>Set annotation</source>
<translation>Hinweis setzen</translation>
</message>
<message>
<location filename="../src/player.cpp" line="1129"/>
<location filename="../src/player.cpp" line="1186"/>
<source>Please enter the new annotation:</source>
<translation>Bitte den Hinweis eingeben:</translation>
</message>
<message>
<location filename="../src/player.cpp" line="1185"/>
<location filename="../src/player.cpp" line="1242"/>
<source>Set counters</source>
<translation>Setze Zählmarken</translation>
</message>
@ -2643,12 +2675,12 @@
<translation type="obsolete">Neue Lebenspunkte insgesamt:</translation>
</message>
<message>
<location filename="../src/player.cpp" line="451"/>
<location filename="../src/player.cpp" line="490"/>
<source>Roll die</source>
<translation>Würfeln</translation>
</message>
<message>
<location filename="../src/player.cpp" line="451"/>
<location filename="../src/player.cpp" line="490"/>
<source>Number of sides:</source>
<translation>Anzahl der Seiten:</translation>
</message>
@ -2664,29 +2696,41 @@
<context>
<name>PlayerListWidget</name>
<message>
<location filename="../src/playerlistwidget.cpp" line="27"/>
<location filename="../src/playerlistwidget.cpp" line="29"/>
<source>Player name</source>
<translation>Spielername</translation>
</message>
<message>
<location filename="../src/playerlistwidget.cpp" line="28"/>
<location filename="../src/playerlistwidget.cpp" line="30"/>
<source>Deck</source>
<translation>Deck</translation>
</message>
<message>
<location filename="../src/playerlistwidget.cpp" line="52"/>
<location filename="../src/playerlistwidget.cpp" line="56"/>
<source>---</source>
<translation>---</translation>
</message>
<message>
<location filename="../src/playerlistwidget.cpp" line="57"/>
<source>local</source>
<translation>lokal</translation>
</message>
<message>
<location filename="../src/playerlistwidget.cpp" line="58"/>
<source>#%1</source>
<translation>#%1</translation>
</message>
<message>
<source>no deck</source>
<translation>kein Deck</translation>
<translation type="obsolete">kein Deck</translation>
</message>
<message>
<location filename="../src/playerlistwidget.cpp" line="53"/>
<source>local deck</source>
<translation>lokales Deck</translation>
<translation type="obsolete">lokales Deck</translation>
</message>
<message>
<location filename="../src/playerlistwidget.cpp" line="54"/>
<source>ID #%1</source>
<translation>ID #%1</translation>
<translation type="obsolete">ID #%1</translation>
</message>
<message>
<source>Role</source>
@ -2750,7 +2794,7 @@
<context>
<name>ServerMessageLog</name>
<message>
<location filename="../src/tab_server.cpp" line="230"/>
<location filename="../src/tab_server.cpp" line="232"/>
<source>Server messages</source>
<translation>Servernachrichten</translation>
</message>
@ -2781,12 +2825,12 @@
<translation>Raum ver&amp;lassen</translation>
</message>
<message>
<location filename="../src/tab_chatchannel.cpp" line="87"/>
<location filename="../src/tab_chatchannel.cpp" line="95"/>
<source>%1 has joined the channel.</source>
<translation>%1 hat den Raum betreten.</translation>
</message>
<message>
<location filename="../src/tab_chatchannel.cpp" line="94"/>
<location filename="../src/tab_chatchannel.cpp" line="102"/>
<source>%1 has left the channel.</source>
<translation>%1 hat den Raum verlassen.</translation>
</message>
@ -2975,10 +3019,33 @@ Bitte geben Sie einen Namen ein:</translation>
<translation>Spiel %1: %2</translation>
</message>
</context>
<context>
<name>TabMessage</name>
<message>
<location filename="../src/tab_message.cpp" line="40"/>
<source>Personal &amp;talk</source>
<translation>Persönliches &amp;Gespräch</translation>
</message>
<message>
<location filename="../src/tab_message.cpp" line="41"/>
<source>&amp;Leave</source>
<translation>Ver&amp;lassen</translation>
</message>
<message>
<location filename="../src/tab_message.cpp" line="75"/>
<source>%1 has left the server.</source>
<translation>%1 hat den Server verlassen.</translation>
</message>
<message>
<location filename="../src/tab_message.h" line="35"/>
<source>Talking to %1</source>
<translation>Gespräch mit %1</translation>
</message>
</context>
<context>
<name>TabServer</name>
<message>
<location filename="../src/tab_server.h" line="88"/>
<location filename="../src/tab_server.h" line="113"/>
<source>Server</source>
<translation>Server</translation>
</message>
@ -3011,6 +3078,14 @@ Bitte geben Sie einen Namen ein:</translation>
<translation>Karten durch &amp;Doppelklick ausspielen (statt Einzelklick)</translation>
</message>
</context>
<context>
<name>UserList</name>
<message>
<location filename="../src/tab_server.cpp" line="268"/>
<source>Users online: %1</source>
<translation>Benutzer online: %1</translation>
</message>
</context>
<context>
<name>WndDeckEditor</name>
<message>

View file

@ -352,27 +352,27 @@
<context>
<name>ChatChannelSelector</name>
<message>
<location filename="../src/tab_server.cpp" line="150"/>
<location filename="../src/tab_server.cpp" line="152"/>
<source>Chat channels</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="151"/>
<location filename="../src/tab_server.cpp" line="153"/>
<source>Joi&amp;n</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="154"/>
<location filename="../src/tab_server.cpp" line="156"/>
<source>Channel</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="155"/>
<location filename="../src/tab_server.cpp" line="157"/>
<source>Description</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="156"/>
<location filename="../src/tab_server.cpp" line="158"/>
<source>Players</source>
<translation type="unfinished"></translation>
</message>
@ -785,65 +785,65 @@
<context>
<name>GameSelector</name>
<message>
<location filename="../src/tab_server.cpp" line="114"/>
<location filename="../src/tab_server.cpp" line="116"/>
<source>C&amp;reate</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="115"/>
<location filename="../src/tab_server.cpp" line="117"/>
<source>&amp;Join</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="77"/>
<location filename="../src/tab_server.cpp" line="78"/>
<location filename="../src/tab_server.cpp" line="79"/>
<location filename="../src/tab_server.cpp" line="80"/>
<location filename="../src/tab_server.cpp" line="81"/>
<location filename="../src/tab_server.cpp" line="82"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="77"/>
<location filename="../src/tab_server.cpp" line="79"/>
<source>Wrong password.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="78"/>
<location filename="../src/tab_server.cpp" line="80"/>
<source>Spectators are not allowed in this game.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="79"/>
<location filename="../src/tab_server.cpp" line="81"/>
<source>The game is already full.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="80"/>
<location filename="../src/tab_server.cpp" line="82"/>
<source>The game does not exist any more.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="96"/>
<location filename="../src/tab_server.cpp" line="98"/>
<source>Join game</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="96"/>
<location filename="../src/tab_server.cpp" line="98"/>
<source>Password:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="112"/>
<location filename="../src/tab_server.cpp" line="114"/>
<source>Games</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="113"/>
<location filename="../src/tab_server.cpp" line="115"/>
<source>&amp;Show full games</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_server.cpp" line="116"/>
<location filename="../src/tab_server.cpp" line="118"/>
<source>J&amp;oin as spectator</source>
<translation type="unfinished"></translation>
</message>
@ -1220,22 +1220,32 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="212"/>
<location filename="../src/messagelogwidget.cpp" line="208"/>
<source>%1 flips %2 face-down.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="210"/>
<source>%1 flips %2 face-up.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="220"/>
<source>%1 attaches %2 to %3&apos;s %4.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="217"/>
<location filename="../src/messagelogwidget.cpp" line="225"/>
<source>%1 unattaches %2.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="235"/>
<location filename="../src/messagelogwidget.cpp" line="243"/>
<source>%1 points from %2&apos;s %3 to %4&apos;s %5.</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<location filename="../src/messagelogwidget.cpp" line="250"/>
<location filename="../src/messagelogwidget.cpp" line="258"/>
<source>%1 places %n counter(s) (%2) on %3 (now %4).</source>
<translation>
<numerusform>%1 places a counter (%2) on %3 (now %4).</numerusform>
@ -1243,7 +1253,7 @@
</translation>
</message>
<message numerus="yes">
<location filename="../src/messagelogwidget.cpp" line="252"/>
<location filename="../src/messagelogwidget.cpp" line="260"/>
<source>%1 removes %n counter(s) (%2) from %3 (now %4).</source>
<translation>
<numerusform>%1 removes a counter (%2) from %3 (now %4).</numerusform>
@ -1251,37 +1261,37 @@
</translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="255"/>
<location filename="../src/messagelogwidget.cpp" line="263"/>
<source>red</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="256"/>
<location filename="../src/messagelogwidget.cpp" line="264"/>
<source>yellow</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="257"/>
<location filename="../src/messagelogwidget.cpp" line="265"/>
<source>green</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="276"/>
<location filename="../src/messagelogwidget.cpp" line="284"/>
<source>%1 sets counter %2 to %3 (%4%5).</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="291"/>
<location filename="../src/messagelogwidget.cpp" line="299"/>
<source>%1 sets PT of %2 to %3.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="296"/>
<location filename="../src/messagelogwidget.cpp" line="304"/>
<source>%1 sets annotation of %2 to %3.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="302"/>
<location filename="../src/messagelogwidget.cpp" line="310"/>
<source>%1 is looking at the top %2 cards %3.</source>
<translation type="unfinished"></translation>
</message>
@ -1346,42 +1356,42 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="207"/>
<location filename="../src/messagelogwidget.cpp" line="215"/>
<source>%1 destroys %2.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="222"/>
<location filename="../src/messagelogwidget.cpp" line="230"/>
<source>%1 creates token: %2%3.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="228"/>
<location filename="../src/messagelogwidget.cpp" line="236"/>
<source>%1 points from %2&apos;s %3 to %4.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="271"/>
<location filename="../src/messagelogwidget.cpp" line="279"/>
<source>%1 %2 %3.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="304"/>
<location filename="../src/messagelogwidget.cpp" line="312"/>
<source>%1 is looking at %2.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="310"/>
<location filename="../src/messagelogwidget.cpp" line="318"/>
<source>%1 stops looking at %2.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="334"/>
<location filename="../src/messagelogwidget.cpp" line="342"/>
<source>ending phase</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="316"/>
<location filename="../src/messagelogwidget.cpp" line="324"/>
<source>It is now %1&apos;s turn.</source>
<translation type="unfinished"></translation>
</message>
@ -1391,82 +1401,82 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="324"/>
<location filename="../src/messagelogwidget.cpp" line="332"/>
<source>untap step</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="325"/>
<location filename="../src/messagelogwidget.cpp" line="333"/>
<source>upkeep step</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="326"/>
<location filename="../src/messagelogwidget.cpp" line="334"/>
<source>draw step</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="327"/>
<location filename="../src/messagelogwidget.cpp" line="335"/>
<source>first main phase</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="328"/>
<location filename="../src/messagelogwidget.cpp" line="336"/>
<source>beginning of combat step</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="329"/>
<location filename="../src/messagelogwidget.cpp" line="337"/>
<source>declare attackers step</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="330"/>
<location filename="../src/messagelogwidget.cpp" line="338"/>
<source>declare blockers step</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="331"/>
<location filename="../src/messagelogwidget.cpp" line="339"/>
<source>combat damage step</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="332"/>
<location filename="../src/messagelogwidget.cpp" line="340"/>
<source>end of combat step</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="333"/>
<location filename="../src/messagelogwidget.cpp" line="341"/>
<source>second main phase</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="336"/>
<location filename="../src/messagelogwidget.cpp" line="344"/>
<source>It is now the %1.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="271"/>
<location filename="../src/messagelogwidget.cpp" line="279"/>
<source>taps</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="271"/>
<location filename="../src/messagelogwidget.cpp" line="279"/>
<source>untaps</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="283"/>
<location filename="../src/messagelogwidget.cpp" line="291"/>
<source>%1 sets %2 to not untap normally.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="285"/>
<location filename="../src/messagelogwidget.cpp" line="293"/>
<source>%1 sets %2 to untap normally.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/messagelogwidget.cpp" line="268"/>
<location filename="../src/messagelogwidget.cpp" line="276"/>
<source>his permanents</source>
<translation type="unfinished"></translation>
</message>
@ -1555,255 +1565,277 @@
<context>
<name>Player</name>
<message>
<location filename="../src/player.cpp" line="290"/>
<location filename="../src/player.cpp" line="294"/>
<location filename="../src/player.cpp" line="298"/>
<location filename="../src/player.cpp" line="297"/>
<location filename="../src/player.cpp" line="301"/>
<location filename="../src/player.cpp" line="305"/>
<source>Move to &amp;top of library</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="291"/>
<location filename="../src/player.cpp" line="295"/>
<location filename="../src/player.cpp" line="299"/>
<location filename="../src/player.cpp" line="298"/>
<location filename="../src/player.cpp" line="302"/>
<location filename="../src/player.cpp" line="306"/>
<source>Move to &amp;bottom of library</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="302"/>
<location filename="../src/player.cpp" line="309"/>
<source>&amp;View library</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="337"/>
<location filename="../src/player.cpp" line="346"/>
<source>F3</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="303"/>
<location filename="../src/player.cpp" line="310"/>
<source>View &amp;top cards of library...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="283"/>
<location filename="../src/player.cpp" line="290"/>
<source>&amp;View graveyard</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="339"/>
<location filename="../src/player.cpp" line="348"/>
<source>F4</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="304"/>
<location filename="../src/player.cpp" line="311"/>
<source>&amp;View sideboard</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="285"/>
<location filename="../src/player.cpp" line="292"/>
<source>Player &quot;%1&quot;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="310"/>
<location filename="../src/player.cpp" line="319"/>
<source>&amp;Hand</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="312"/>
<location filename="../src/player.cpp" line="321"/>
<source>&amp;Library</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="286"/>
<location filename="../src/player.cpp" line="293"/>
<source>&amp;Graveyard</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="311"/>
<location filename="../src/player.cpp" line="320"/>
<source>&amp;Sideboard</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="399"/>
<location filename="../src/player.cpp" line="408"/>
<source>View top cards of library</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="399"/>
<location filename="../src/player.cpp" line="408"/>
<source>Number of cards:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="305"/>
<location filename="../src/player.cpp" line="312"/>
<source>&amp;Draw card</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="284"/>
<location filename="../src/player.cpp" line="291"/>
<source>&amp;View exile</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="287"/>
<location filename="../src/player.cpp" line="294"/>
<source>&amp;Exile</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="296"/>
<location filename="../src/player.cpp" line="300"/>
<location filename="../src/player.cpp" line="303"/>
<location filename="../src/player.cpp" line="307"/>
<source>Move to &amp;hand</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="292"/>
<location filename="../src/player.cpp" line="301"/>
<location filename="../src/player.cpp" line="299"/>
<location filename="../src/player.cpp" line="308"/>
<source>Move to g&amp;raveyard</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="293"/>
<location filename="../src/player.cpp" line="297"/>
<location filename="../src/player.cpp" line="300"/>
<location filename="../src/player.cpp" line="304"/>
<source>Move to &amp;exile</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="338"/>
<location filename="../src/player.cpp" line="347"/>
<source>Ctrl+W</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="340"/>
<location filename="../src/player.cpp" line="349"/>
<source>Ctrl+D</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="306"/>
<location filename="../src/player.cpp" line="313"/>
<source>D&amp;raw cards...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="341"/>
<location filename="../src/player.cpp" line="350"/>
<source>Ctrl+E</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="307"/>
<location filename="../src/player.cpp" line="314"/>
<source>Take &amp;mulligan</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="342"/>
<location filename="../src/player.cpp" line="351"/>
<source>Ctrl+M</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="308"/>
<location filename="../src/player.cpp" line="315"/>
<source>&amp;Shuffle</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="343"/>
<location filename="../src/player.cpp" line="352"/>
<source>Ctrl+S</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="313"/>
<location filename="../src/player.cpp" line="322"/>
<source>&amp;Counters</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="315"/>
<location filename="../src/player.cpp" line="324"/>
<source>&amp;Untap all permanents</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="344"/>
<location filename="../src/player.cpp" line="353"/>
<source>Ctrl+U</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="316"/>
<location filename="../src/player.cpp" line="325"/>
<source>R&amp;oll die...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="345"/>
<location filename="../src/player.cpp" line="354"/>
<source>Ctrl+I</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="317"/>
<location filename="../src/player.cpp" line="326"/>
<source>&amp;Create token...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="346"/>
<location filename="../src/player.cpp" line="355"/>
<source>Ctrl+T</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="318"/>
<location filename="../src/player.cpp" line="327"/>
<source>C&amp;reate another token</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="347"/>
<location filename="../src/player.cpp" line="356"/>
<source>Ctrl+G</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="319"/>
<location filename="../src/player.cpp" line="328"/>
<source>S&amp;ay</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="325"/>
<location filename="../src/player.cpp" line="316"/>
<source>Move top cards to g&amp;raveyard...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="317"/>
<source>Move top cards to &amp;exile...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="334"/>
<source>C&amp;ard</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="438"/>
<location filename="../src/player.cpp" line="447"/>
<source>Draw cards</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="438"/>
<location filename="../src/player.cpp" line="1185"/>
<location filename="../src/player.cpp" line="447"/>
<location filename="../src/player.cpp" line="454"/>
<location filename="../src/player.cpp" line="469"/>
<location filename="../src/player.cpp" line="1242"/>
<source>Number:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="451"/>
<location filename="../src/player.cpp" line="454"/>
<source>Move top cards to grave</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="469"/>
<source>Move top cards to exile</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="490"/>
<source>Roll die</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="451"/>
<location filename="../src/player.cpp" line="490"/>
<source>Number of sides:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="1103"/>
<location filename="../src/player.cpp" line="1160"/>
<source>Set power/toughness</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="1103"/>
<location filename="../src/player.cpp" line="1160"/>
<source>Please enter the new PT:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="1129"/>
<location filename="../src/player.cpp" line="1186"/>
<source>Set annotation</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="1129"/>
<location filename="../src/player.cpp" line="1186"/>
<source>Please enter the new annotation:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="1185"/>
<location filename="../src/player.cpp" line="1242"/>
<source>Set counters</source>
<translation type="unfinished"></translation>
</message>
@ -1811,28 +1843,28 @@
<context>
<name>PlayerListWidget</name>
<message>
<location filename="../src/playerlistwidget.cpp" line="27"/>
<location filename="../src/playerlistwidget.cpp" line="29"/>
<source>Player name</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/playerlistwidget.cpp" line="28"/>
<location filename="../src/playerlistwidget.cpp" line="30"/>
<source>Deck</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/playerlistwidget.cpp" line="52"/>
<source>no deck</source>
<location filename="../src/playerlistwidget.cpp" line="56"/>
<source>---</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/playerlistwidget.cpp" line="53"/>
<source>local deck</source>
<location filename="../src/playerlistwidget.cpp" line="57"/>
<source>local</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/playerlistwidget.cpp" line="54"/>
<source>ID #%1</source>
<location filename="../src/playerlistwidget.cpp" line="58"/>
<source>#%1</source>
<translation type="unfinished"></translation>
</message>
</context>
@ -1885,7 +1917,7 @@
<context>
<name>ServerMessageLog</name>
<message>
<location filename="../src/tab_server.cpp" line="230"/>
<location filename="../src/tab_server.cpp" line="232"/>
<source>Server messages</source>
<translation type="unfinished"></translation>
</message>
@ -1916,12 +1948,12 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_chatchannel.cpp" line="87"/>
<location filename="../src/tab_chatchannel.cpp" line="95"/>
<source>%1 has joined the channel.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_chatchannel.cpp" line="94"/>
<location filename="../src/tab_chatchannel.cpp" line="102"/>
<source>%1 has left the channel.</source>
<translation type="unfinished"></translation>
</message>
@ -2081,10 +2113,33 @@ Please enter a name:</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TabMessage</name>
<message>
<location filename="../src/tab_message.cpp" line="40"/>
<source>Personal &amp;talk</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_message.cpp" line="41"/>
<source>&amp;Leave</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_message.cpp" line="75"/>
<source>%1 has left the server.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/tab_message.h" line="35"/>
<source>Talking to %1</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TabServer</name>
<message>
<location filename="../src/tab_server.h" line="88"/>
<location filename="../src/tab_server.h" line="113"/>
<source>Server</source>
<translation type="unfinished"></translation>
</message>
@ -2102,6 +2157,14 @@ Please enter a name:</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>UserList</name>
<message>
<location filename="../src/tab_server.cpp" line="268"/>
<source>Users online: %1</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>WndDeckEditor</name>
<message>

View file

@ -37,12 +37,14 @@ void ProtocolItem::initializeHash()
registerSerializableItem("resp", ProtocolResponse::newItem);
ProtocolResponse::initializeHash();
registerSerializableItem("resplist_users", Response_ListUsers::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("generic_eventlist_games", Event_ListGames::newItem);
registerSerializableItem("generic_eventuser_joined", Event_UserJoined::newItem);
registerSerializableItem("generic_eventlist_chat_channels", Event_ListChatChannels::newItem);
registerSerializableItem("game_eventjoin", Event_Join::newItem);
registerSerializableItem("game_eventgame_state_changed", Event_GameStateChanged::newItem);
@ -215,6 +217,13 @@ void ProtocolResponse::initializeHash()
responseHash.insert("spectators_not_allowed", RespSpectatorsNotAllowed);
}
Response_ListUsers::Response_ListUsers(int _cmdId, ResponseCode _responseCode, const QList<ServerInfo_User *> &_userList)
: ProtocolResponse(_cmdId, _responseCode, "list_users")
{
for (int i = 0; i < _userList.size(); ++i)
itemList.append(_userList[i]);
}
Response_DeckList::Response_DeckList(int _cmdId, ResponseCode _responseCode, DeckList_Directory *_root)
: ProtocolResponse(_cmdId, _responseCode, "deck_list")
{
@ -298,6 +307,14 @@ Event_ListGames::Event_ListGames(const QList<ServerInfo_Game *> &_gameList)
itemList.append(_gameList[i]);
}
Event_UserJoined::Event_UserJoined(ServerInfo_User *_userInfo)
: GenericEvent("user_joined")
{
if (!_userInfo)
_userInfo = new ServerInfo_User;
insertItem(_userInfo);
}
Event_Join::Event_Join(ServerInfo_PlayerProperties *player)
: GameEvent("join", -1)
{

View file

@ -29,17 +29,19 @@ enum ItemId {
ItemId_Event_ChatListPlayers = ItemId_Other + 201,
ItemId_Event_ChatJoinChannel = ItemId_Other + 202,
ItemId_Event_ListGames = ItemId_Other + 203,
ItemId_Event_GameStateChanged = ItemId_Other + 204,
ItemId_Event_PlayerPropertiesChanged = ItemId_Other + 205,
ItemId_Event_CreateArrows = ItemId_Other + 206,
ItemId_Event_CreateCounters = ItemId_Other + 207,
ItemId_Event_DrawCards = ItemId_Other + 208,
ItemId_Event_Join = ItemId_Other + 209,
ItemId_Event_Ping = ItemId_Other + 210,
ItemId_Response_DeckList = ItemId_Other + 300,
ItemId_Response_DeckDownload = ItemId_Other + 301,
ItemId_Response_DeckUpload = ItemId_Other + 302,
ItemId_Response_DumpZone = ItemId_Other + 303,
ItemId_Event_UserJoined = ItemId_Other + 204,
ItemId_Event_GameStateChanged = ItemId_Other + 205,
ItemId_Event_PlayerPropertiesChanged = ItemId_Other + 206,
ItemId_Event_CreateArrows = ItemId_Other + 207,
ItemId_Event_CreateCounters = ItemId_Other + 208,
ItemId_Event_DrawCards = ItemId_Other + 209,
ItemId_Event_Join = ItemId_Other + 210,
ItemId_Event_Ping = ItemId_Other + 211,
ItemId_Response_ListUsers = ItemId_Other + 300,
ItemId_Response_DeckList = ItemId_Other + 301,
ItemId_Response_DeckDownload = ItemId_Other + 302,
ItemId_Response_DeckUpload = ItemId_Other + 303,
ItemId_Response_DumpZone = ItemId_Other + 304,
ItemId_Invalid = ItemId_Other + 1000
};
@ -199,6 +201,15 @@ public:
ResponseCode getResponseCode() const { return responseHash.value(static_cast<SerializableItem_String *>(itemMap.value("response_code"))->getData(), RespOk); }
};
class Response_ListUsers : public ProtocolResponse {
Q_OBJECT
public:
Response_ListUsers(int _cmdId = -1, ResponseCode _responseCode = RespOk, const QList<ServerInfo_User *> &_userList = QList<ServerInfo_User *>());
int getItemId() const { return ItemId_Response_ListUsers; }
static SerializableItem *newItem() { return new Response_ListUsers; }
QList<ServerInfo_User *> getUserList() const { return typecastItemList<ServerInfo_User *>(); }
};
class Response_DeckList : public ProtocolResponse {
Q_OBJECT
public:
@ -323,6 +334,15 @@ public:
QList<ServerInfo_Game *> getGameList() const { return typecastItemList<ServerInfo_Game *>(); }
};
class Event_UserJoined : public GenericEvent {
Q_OBJECT
public:
Event_UserJoined(ServerInfo_User *_userInfo = 0);
int getItemId() const { return ItemId_Event_UserJoined; }
static SerializableItem *newItem() { return new Event_UserJoined; }
ServerInfo_User *getUserInfo() const { return static_cast<ServerInfo_User *>(itemMap.value("user")); }
};
class Event_Join : public GameEvent {
Q_OBJECT
public:

View file

@ -1,68 +1,72 @@
enum AutoItemId {
ItemId_Command_Ping = 1001,
ItemId_Command_Login = 1002,
ItemId_Command_DeckList = 1003,
ItemId_Command_DeckNewDir = 1004,
ItemId_Command_DeckDelDir = 1005,
ItemId_Command_DeckDel = 1006,
ItemId_Command_DeckDownload = 1007,
ItemId_Command_ListChatChannels = 1008,
ItemId_Command_ChatJoinChannel = 1009,
ItemId_Command_ChatLeaveChannel = 1010,
ItemId_Command_ChatSay = 1011,
ItemId_Command_ListGames = 1012,
ItemId_Command_CreateGame = 1013,
ItemId_Command_JoinGame = 1014,
ItemId_Command_LeaveGame = 1015,
ItemId_Command_Say = 1016,
ItemId_Command_Shuffle = 1017,
ItemId_Command_Mulligan = 1018,
ItemId_Command_RollDie = 1019,
ItemId_Command_DrawCards = 1020,
ItemId_Command_MoveCard = 1021,
ItemId_Command_FlipCard = 1022,
ItemId_Command_AttachCard = 1023,
ItemId_Command_CreateToken = 1024,
ItemId_Command_CreateArrow = 1025,
ItemId_Command_DeleteArrow = 1026,
ItemId_Command_SetCardAttr = 1027,
ItemId_Command_SetCardCounter = 1028,
ItemId_Command_IncCardCounter = 1029,
ItemId_Command_ReadyStart = 1030,
ItemId_Command_Concede = 1031,
ItemId_Command_IncCounter = 1032,
ItemId_Command_CreateCounter = 1033,
ItemId_Command_SetCounter = 1034,
ItemId_Command_DelCounter = 1035,
ItemId_Command_NextTurn = 1036,
ItemId_Command_SetActivePhase = 1037,
ItemId_Command_DumpZone = 1038,
ItemId_Command_StopDumpZone = 1039,
ItemId_Event_Say = 1040,
ItemId_Event_Leave = 1041,
ItemId_Event_GameClosed = 1042,
ItemId_Event_Shuffle = 1043,
ItemId_Event_RollDie = 1044,
ItemId_Event_MoveCard = 1045,
ItemId_Event_FlipCard = 1046,
ItemId_Event_DestroyCard = 1047,
ItemId_Event_AttachCard = 1048,
ItemId_Event_CreateToken = 1049,
ItemId_Event_DeleteArrow = 1050,
ItemId_Event_SetCardAttr = 1051,
ItemId_Event_SetCardCounter = 1052,
ItemId_Event_SetCounter = 1053,
ItemId_Event_DelCounter = 1054,
ItemId_Event_SetActivePlayer = 1055,
ItemId_Event_SetActivePhase = 1056,
ItemId_Event_DumpZone = 1057,
ItemId_Event_StopDumpZone = 1058,
ItemId_Event_ServerMessage = 1059,
ItemId_Event_GameJoined = 1060,
ItemId_Event_ChatLeaveChannel = 1061,
ItemId_Event_ChatSay = 1062,
ItemId_Context_ReadyStart = 1063,
ItemId_Context_Concede = 1064,
ItemId_Context_DeckSelect = 1065,
ItemId_Other = 1066
ItemId_Command_Message = 1003,
ItemId_Command_DeckList = 1004,
ItemId_Command_DeckNewDir = 1005,
ItemId_Command_DeckDelDir = 1006,
ItemId_Command_DeckDel = 1007,
ItemId_Command_DeckDownload = 1008,
ItemId_Command_ListChatChannels = 1009,
ItemId_Command_ChatJoinChannel = 1010,
ItemId_Command_ChatLeaveChannel = 1011,
ItemId_Command_ChatSay = 1012,
ItemId_Command_ListGames = 1013,
ItemId_Command_ListUsers = 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_Event_Say = 1042,
ItemId_Event_Leave = 1043,
ItemId_Event_GameClosed = 1044,
ItemId_Event_Shuffle = 1045,
ItemId_Event_RollDie = 1046,
ItemId_Event_MoveCard = 1047,
ItemId_Event_FlipCard = 1048,
ItemId_Event_DestroyCard = 1049,
ItemId_Event_AttachCard = 1050,
ItemId_Event_CreateToken = 1051,
ItemId_Event_DeleteArrow = 1052,
ItemId_Event_SetCardAttr = 1053,
ItemId_Event_SetCardCounter = 1054,
ItemId_Event_SetCounter = 1055,
ItemId_Event_DelCounter = 1056,
ItemId_Event_SetActivePlayer = 1057,
ItemId_Event_SetActivePhase = 1058,
ItemId_Event_DumpZone = 1059,
ItemId_Event_StopDumpZone = 1060,
ItemId_Event_ServerMessage = 1061,
ItemId_Event_Message = 1062,
ItemId_Event_GameJoined = 1063,
ItemId_Event_UserLeft = 1064,
ItemId_Event_ChatLeaveChannel = 1065,
ItemId_Event_ChatSay = 1066,
ItemId_Context_ReadyStart = 1067,
ItemId_Context_Concede = 1068,
ItemId_Context_DeckSelect = 1069,
ItemId_Other = 1070
};

View file

@ -11,6 +11,12 @@ Command_Login::Command_Login(const QString &_username, const QString &_password)
insertItem(new SerializableItem_String("username", _username));
insertItem(new SerializableItem_String("password", _password));
}
Command_Message::Command_Message(const QString &_userName, const QString &_text)
: Command("message")
{
insertItem(new SerializableItem_String("user_name", _userName));
insertItem(new SerializableItem_String("text", _text));
}
Command_DeckList::Command_DeckList()
: Command("deck_list")
{
@ -58,6 +64,10 @@ 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")
{
@ -370,6 +380,13 @@ Event_ServerMessage::Event_ServerMessage(const QString &_message)
{
insertItem(new SerializableItem_String("message", _message));
}
Event_Message::Event_Message(const QString &_senderName, const QString &_receiverName, const QString &_text)
: GenericEvent("message")
{
insertItem(new SerializableItem_String("sender_name", _senderName));
insertItem(new SerializableItem_String("receiver_name", _receiverName));
insertItem(new SerializableItem_String("text", _text));
}
Event_GameJoined::Event_GameJoined(int _gameId, const QString &_gameDescription, int _playerId, bool _spectator, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, bool _resuming)
: GenericEvent("game_joined")
{
@ -381,6 +398,11 @@ Event_GameJoined::Event_GameJoined(int _gameId, const QString &_gameDescription,
insertItem(new SerializableItem_Bool("spectators_see_everything", _spectatorsSeeEverything));
insertItem(new SerializableItem_Bool("resuming", _resuming));
}
Event_UserLeft::Event_UserLeft(const QString &_userName)
: GenericEvent("user_left")
{
insertItem(new SerializableItem_String("user_name", _userName));
}
Event_ChatLeaveChannel::Event_ChatLeaveChannel(const QString &_channel, const QString &_playerName)
: ChatEvent("chat_leave_channel", _channel)
{
@ -409,6 +431,7 @@ void ProtocolItem::initializeHashAuto()
{
itemNameHash.insert("cmdping", Command_Ping::newItem);
itemNameHash.insert("cmdlogin", Command_Login::newItem);
itemNameHash.insert("cmdmessage", Command_Message::newItem);
itemNameHash.insert("cmddeck_list", Command_DeckList::newItem);
itemNameHash.insert("cmddeck_new_dir", Command_DeckNewDir::newItem);
itemNameHash.insert("cmddeck_del_dir", Command_DeckDelDir::newItem);
@ -419,6 +442,7 @@ void ProtocolItem::initializeHashAuto()
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("cmdcreate_game", Command_CreateGame::newItem);
itemNameHash.insert("cmdjoin_game", Command_JoinGame::newItem);
itemNameHash.insert("cmdleave_game", Command_LeaveGame::newItem);
@ -466,7 +490,9 @@ void ProtocolItem::initializeHashAuto()
itemNameHash.insert("game_eventdump_zone", Event_DumpZone::newItem);
itemNameHash.insert("game_eventstop_dump_zone", Event_StopDumpZone::newItem);
itemNameHash.insert("generic_eventserver_message", Event_ServerMessage::newItem);
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("game_event_contextready_start", Context_ReadyStart::newItem);

View file

@ -1,5 +1,6 @@
0:ping
0:login:s,username:s,password
0:message:s,user_name:s,text
0:deck_list
0:deck_new_dir:s,path:s,dir_name
0:deck_del_dir:s,path
@ -10,6 +11,7 @@
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
2:leave_game
@ -57,7 +59,9 @@
3:dump_zone:i,zone_owner_id:s,zone:i,number_cards
3:stop_dump_zone:i,zone_owner_id:s,zone
4:server_message:s,message
4: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
6:ready_start

View file

@ -19,6 +19,15 @@ public:
static SerializableItem *newItem() { return new Command_Login; }
int getItemId() const { return ItemId_Command_Login; }
};
class Command_Message : public Command {
Q_OBJECT
public:
Command_Message(const QString &_userName = QString(), const QString &_text = QString());
QString getUserName() const { return static_cast<SerializableItem_String *>(itemMap.value("user_name"))->getData(); };
QString getText() const { return static_cast<SerializableItem_String *>(itemMap.value("text"))->getData(); };
static SerializableItem *newItem() { return new Command_Message; }
int getItemId() const { return ItemId_Command_Message; }
};
class Command_DeckList : public Command {
Q_OBJECT
public:
@ -96,6 +105,13 @@ public:
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:
@ -549,6 +565,16 @@ public:
static SerializableItem *newItem() { return new Event_ServerMessage; }
int getItemId() const { return ItemId_Event_ServerMessage; }
};
class Event_Message : public GenericEvent {
Q_OBJECT
public:
Event_Message(const QString &_senderName = QString(), const QString &_receiverName = QString(), const QString &_text = QString());
QString getSenderName() const { return static_cast<SerializableItem_String *>(itemMap.value("sender_name"))->getData(); };
QString getReceiverName() const { return static_cast<SerializableItem_String *>(itemMap.value("receiver_name"))->getData(); };
QString getText() const { return static_cast<SerializableItem_String *>(itemMap.value("text"))->getData(); };
static SerializableItem *newItem() { return new Event_Message; }
int getItemId() const { return ItemId_Event_Message; }
};
class Event_GameJoined : public GenericEvent {
Q_OBJECT
public:
@ -563,6 +589,14 @@ public:
static SerializableItem *newItem() { return new Event_GameJoined; }
int getItemId() const { return ItemId_Event_GameJoined; }
};
class Event_UserLeft : public GenericEvent {
Q_OBJECT
public:
Event_UserLeft(const QString &_userName = QString());
QString getUserName() const { return static_cast<SerializableItem_String *>(itemMap.value("user_name"))->getData(); };
static SerializableItem *newItem() { return new Event_UserLeft; }
int getItemId() const { return ItemId_Event_UserLeft; }
};
class Event_ChatLeaveChannel : public ChatEvent {
Q_OBJECT
public:

View file

@ -62,6 +62,12 @@ AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString
users.insert(name, session);
Event_UserJoined *event = new Event_UserJoined(new ServerInfo_User(data));
for (int i = 0; i < clients.size(); ++i)
if (clients[i]->getAcceptsUserListChanges())
clients[i]->sendProtocolItem(event, false);
delete event;
return authState;
}
@ -85,8 +91,15 @@ void Server::removeClient(Server_ProtocolHandler *client)
{
clients.removeAt(clients.indexOf(client));
ServerInfo_User *data = client->getUserInfo();
if (data)
if (data) {
Event_UserLeft *event = new Event_UserLeft(data->getName());
for (int i = 0; i < clients.size(); ++i)
if (clients[i]->getAcceptsUserListChanges())
clients[i]->sendProtocolItem(event, false);
delete event;
users.remove(data->getName());
}
qDebug() << "Server::removeClient: " << clients.size() << "clients; " << users.size() << "users left";
}

View file

@ -29,6 +29,7 @@ public:
const QMap<QString, Server_ChatChannel *> &getChatChannels() { return chatChannels; }
void broadcastGameListUpdate(Server_Game *game);
const QMap<QString, Server_ProtocolHandler *> &getUsers() const { return users; }
void addClient(Server_ProtocolHandler *player);
void removeClient(Server_ProtocolHandler *player);
virtual QString getLoginMessage() const = 0;

View file

@ -14,7 +14,7 @@
#include <QDateTime>
Server_ProtocolHandler::Server_ProtocolHandler(Server *_server, QObject *parent)
: QObject(parent), server(_server), authState(PasswordWrong), acceptsGameListChanges(false), userInfo(0), lastCommandTime(QDateTime::currentDateTime())
: QObject(parent), server(_server), authState(PasswordWrong), acceptsGameListChanges(false), acceptsUserListChanges(false), acceptsChatChannelListChanges(false), userInfo(0), lastCommandTime(QDateTime::currentDateTime())
{
connect(server, SIGNAL(pingClockTimeout()), this, SLOT(pingClockTimeout()));
}
@ -116,6 +116,7 @@ ResponseCode Server_ProtocolHandler::processCommandHelper(Command *command, Comm
switch (command->getItemId()) {
case ItemId_Command_Ping: return cmdPing(qobject_cast<Command_Ping *>(command), cont);
case ItemId_Command_Login: return cmdLogin(qobject_cast<Command_Login *>(command), cont);
case ItemId_Command_Message: return cmdMessage(qobject_cast<Command_Message *>(command), cont);
case ItemId_Command_DeckList: return cmdDeckList(qobject_cast<Command_DeckList *>(command), cont);
case ItemId_Command_DeckNewDir: return cmdDeckNewDir(qobject_cast<Command_DeckNewDir *>(command), cont);
case ItemId_Command_DeckDelDir: return cmdDeckDelDir(qobject_cast<Command_DeckDelDir *>(command), cont);
@ -124,6 +125,7 @@ ResponseCode Server_ProtocolHandler::processCommandHelper(Command *command, Comm
case ItemId_Command_DeckDownload: return cmdDeckDownload(qobject_cast<Command_DeckDownload *>(command), cont);
case ItemId_Command_ListChatChannels: return cmdListChatChannels(qobject_cast<Command_ListChatChannels *>(command), cont);
case ItemId_Command_ChatJoinChannel: return cmdChatJoinChannel(qobject_cast<Command_ChatJoinChannel *>(command), cont);
case ItemId_Command_ListUsers: return cmdListUsers(qobject_cast<Command_ListUsers *>(command), cont);
case ItemId_Command_ListGames: return cmdListGames(qobject_cast<Command_ListGames *>(command), cont);
case ItemId_Command_CreateGame: return cmdCreateGame(qobject_cast<Command_CreateGame *>(command), cont);
case ItemId_Command_JoinGame: return cmdJoinGame(qobject_cast<Command_JoinGame *>(command), cont);
@ -229,6 +231,21 @@ ResponseCode Server_ProtocolHandler::cmdLogin(Command_Login *cmd, CommandContain
return RespOk;
}
ResponseCode Server_ProtocolHandler::cmdMessage(Command_Message *cmd, CommandContainer *cont)
{
if (authState == PasswordWrong)
return RespLoginNeeded;
QString receiver = cmd->getUserName();
Server_ProtocolHandler *userHandler = server->getUsers().value(receiver);
if (!userHandler)
return RespNameNotFound;
cont->enqueueItem(new Event_Message(userInfo->getName(), receiver, cmd->getText()));
userHandler->sendProtocolItem(new Event_Message(userInfo->getName(), receiver, cmd->getText()));
return RespOk;
}
ResponseCode Server_ProtocolHandler::cmdListChatChannels(Command_ListChatChannels * /*cmd*/, CommandContainer *cont)
{
if (authState == PasswordWrong)
@ -277,6 +294,22 @@ ResponseCode Server_ProtocolHandler::cmdChatSay(Command_ChatSay *cmd, CommandCon
return RespOk;
}
ResponseCode Server_ProtocolHandler::cmdListUsers(Command_ListUsers * /*cmd*/, CommandContainer *cont)
{
if (authState == PasswordWrong)
return RespLoginNeeded;
QList<ServerInfo_User *> resultList;
QMapIterator<QString, Server_ProtocolHandler *> userIterator = server->getUsers();
while (userIterator.hasNext())
resultList.append(new ServerInfo_User(userIterator.next().value()->getUserInfo()));
acceptsUserListChanges = true;
cont->setResponse(new Response_ListUsers(cont->getCmdId(), RespOk, resultList));
return RespNothing;
}
ResponseCode Server_ProtocolHandler::cmdListGames(Command_ListGames * /*cmd*/, CommandContainer *cont)
{
if (authState == PasswordWrong)

View file

@ -24,6 +24,7 @@ protected:
AuthenticationResult authState;
bool acceptsGameListChanges;
bool acceptsUserListChanges;
bool acceptsChatChannelListChanges;
ServerInfo_User *userInfo;
@ -36,6 +37,7 @@ private:
ResponseCode cmdPing(Command_Ping *cmd, CommandContainer *cont);
ResponseCode cmdLogin(Command_Login *cmd, CommandContainer *cont);
ResponseCode cmdMessage(Command_Message *cmd, CommandContainer *cont);
virtual ResponseCode cmdDeckList(Command_DeckList *cmd, CommandContainer *cont) = 0;
virtual ResponseCode cmdDeckNewDir(Command_DeckNewDir *cmd, CommandContainer *cont) = 0;
virtual ResponseCode cmdDeckDelDir(Command_DeckDelDir *cmd, CommandContainer *cont) = 0;
@ -46,6 +48,7 @@ private:
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 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);
@ -91,6 +94,7 @@ public:
void playerRemovedFromGame(Server_Game *game);
bool getAcceptsGameListChanges() const { return acceptsGameListChanges; }
bool getAcceptsUserListChanges() const { return acceptsUserListChanges; }
bool getAcceptsChatChannelListChanges() const { return acceptsChatChannelListChanges; }
ServerInfo_User *getUserInfo() const { return userInfo; }
void setUserInfo(ServerInfo_User *_userInfo) { userInfo = _userInfo; }