diff --git a/cockatrice/cockatrice.pro b/cockatrice/cockatrice.pro index 61a98550..d3e826a9 100644 --- a/cockatrice/cockatrice.pro +++ b/cockatrice/cockatrice.pro @@ -7,7 +7,8 @@ OBJECTS_DIR = build RESOURCES = cockatrice.qrc QT += network svg -HEADERS += src/counter.h \ +HEADERS += src/abstractcounter.h \ + src/counter_general.h \ src/dlg_creategame.h \ src/dlg_connect.h \ src/dlg_create_token.h \ @@ -16,6 +17,7 @@ HEADERS += src/counter.h \ src/remoteclient.h \ src/window_main.h \ src/cardzone.h \ + src/selectzone.h \ src/player.h \ src/playertarget.h \ src/cardlist.h \ @@ -51,11 +53,14 @@ HEADERS += src/counter.h \ src/arrowtarget.h \ src/tab.h \ src/tab_server.h \ - src/tab_chatchannel.h \ + src/tab_room.h \ src/tab_message.h \ src/tab_game.h \ src/tab_deck_storage.h \ src/tab_supervisor.h \ + src/tab_admin.h \ + src/userlist.h \ + src/userinfobox.h \ src/remotedecklist_treewidget.h \ src/deckview.h \ src/playerlistwidget.h \ @@ -77,14 +82,15 @@ HEADERS += src/counter.h \ ../common/server_arrow.h \ ../common/server_card.h \ ../common/server_cardzone.h \ - ../common/server_chatchannel.h \ + ../common/server_room.h \ ../common/server_counter.h \ ../common/server_game.h \ ../common/server_player.h \ ../common/server_protocolhandler.h \ ../common/server_arrowtarget.h -SOURCES += src/counter.cpp \ +SOURCES += src/abstractcounter.cpp \ + src/counter_general.cpp \ src/dlg_creategame.cpp \ src/dlg_connect.cpp \ src/dlg_create_token.cpp \ @@ -96,6 +102,7 @@ SOURCES += src/counter.cpp \ src/player.cpp \ src/playertarget.cpp \ src/cardzone.cpp \ + src/selectzone.cpp \ src/cardlist.cpp \ src/abstractcarditem.cpp \ src/carditem.cpp \ @@ -128,11 +135,14 @@ SOURCES += src/counter.cpp \ src/arrowitem.cpp \ src/arrowtarget.cpp \ src/tab_server.cpp \ - src/tab_chatchannel.cpp \ + src/tab_room.cpp \ src/tab_message.cpp \ src/tab_game.cpp \ src/tab_deck_storage.cpp \ src/tab_supervisor.cpp \ + src/tab_admin.cpp \ + src/userlist.cpp \ + src/userinfobox.cpp \ src/remotedecklist_treewidget.cpp \ src/deckview.cpp \ src/playerlistwidget.cpp \ @@ -152,7 +162,7 @@ SOURCES += src/counter.cpp \ ../common/server.cpp \ ../common/server_card.cpp \ ../common/server_cardzone.cpp \ - ../common/server_chatchannel.cpp \ + ../common/server_room.cpp \ ../common/server_game.cpp \ ../common/server_player.cpp \ ../common/server_protocolhandler.cpp @@ -162,7 +172,9 @@ TRANSLATIONS += \ translations/cockatrice_en.ts \ translations/cockatrice_es.ts \ translations/cockatrice_pt.ts \ - translations/cockatrice_fr.ts + translations/cockatrice_pt-br.ts \ + translations/cockatrice_fr.ts \ + translations/cockatrice_jp.ts win32 { RC_FILE = cockatrice.rc } diff --git a/cockatrice/cockatrice.qrc b/cockatrice/cockatrice.qrc index 1391fc83..bea7ad2c 100644 --- a/cockatrice/cockatrice.qrc +++ b/cockatrice/cockatrice.qrc @@ -28,7 +28,9 @@ translations/cockatrice_en.qm translations/cockatrice_es.qm translations/cockatrice_pt.qm + translations/cockatrice_pt-br.qm translations/cockatrice_fr.qm + translations/cockatrice_jp.qm resources/appicon.svg resources/add_to_sideboard.svg resources/decrement.svg @@ -63,6 +65,7 @@ resources/countries/mx.svg resources/countries/nl.svg resources/countries/no.svg + resources/countries/ph.svg resources/countries/pl.svg resources/countries/pt.svg resources/countries/ru.svg diff --git a/cockatrice/resources/countries/br.svg b/cockatrice/resources/countries/br.svg index 213c362f..a50a00bc 100644 --- a/cockatrice/resources/countries/br.svg +++ b/cockatrice/resources/countries/br.svg @@ -1,112 +1,47 @@ - - - - Flag of Brazil - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + Clipart by Rodrigo Tjäder - Flag of Brazil + Flag of Brazil based on .CDR file available in Brazilian Government's website + + + flags + sign + signs_and_symbols + + america + + + + + Rodrigo Tjäder + + + + image/svg+xml + + + + + pt + + + + + + + + + \ No newline at end of file diff --git a/cockatrice/resources/countries/ph.svg b/cockatrice/resources/countries/ph.svg new file mode 100644 index 00000000..48752391 --- /dev/null +++ b/cockatrice/resources/countries/ph.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/cockatrice/src/abstractcarddragitem.h b/cockatrice/src/abstractcarddragitem.h index 62f36436..047c4f55 100644 --- a/cockatrice/src/abstractcarddragitem.h +++ b/cockatrice/src/abstractcarddragitem.h @@ -20,6 +20,7 @@ public: ~AbstractCardDragItem(); QRectF boundingRect() const { return QRectF(0, 0, CARD_WIDTH, CARD_HEIGHT); } void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + AbstractCardItem *getItem() const { return item; } QPointF getHotSpot() const { return hotSpot; } void addChildDrag(AbstractCardDragItem *child); virtual void updatePosition(const QPointF &cursorScenePos) = 0; diff --git a/cockatrice/src/abstractcarditem.h b/cockatrice/src/abstractcarditem.h index 0f592d31..c07b78a0 100644 --- a/cockatrice/src/abstractcarditem.h +++ b/cockatrice/src/abstractcarditem.h @@ -11,7 +11,7 @@ class QTimer; const int CARD_WIDTH = 72; const int CARD_HEIGHT = 102; -class AbstractCardItem : public QObject, public ArrowTarget { +class AbstractCardItem : public ArrowTarget { Q_OBJECT protected: CardInfo *info; diff --git a/cockatrice/src/abstractclient.cpp b/cockatrice/src/abstractclient.cpp index 924c9617..627f6ed6 100644 --- a/cockatrice/src/abstractclient.cpp +++ b/cockatrice/src/abstractclient.cpp @@ -32,11 +32,10 @@ void AbstractClient::processProtocolItem(ProtocolItem *item) GenericEvent *genericEvent = qobject_cast(item); if (genericEvent) { switch (genericEvent->getItemId()) { - case ItemId_Event_ListGames: emit listGamesEventReceived(qobject_cast(item)); break; case ItemId_Event_UserJoined: emit userJoinedEventReceived(qobject_cast(item)); break; case ItemId_Event_UserLeft: emit userLeftEventReceived(qobject_cast(item)); break; case ItemId_Event_ServerMessage: emit serverMessageEventReceived(qobject_cast(item)); break; - case ItemId_Event_ListChatChannels: emit listChatChannelsEventReceived(qobject_cast(item)); break; + case ItemId_Event_ListRooms: emit listRoomsEventReceived(qobject_cast(item)); break; case ItemId_Event_GameJoined: emit gameJoinedEventReceived(qobject_cast(item)); break; case ItemId_Event_Message: emit messageEventReceived(qobject_cast(item)); break; } @@ -53,11 +52,11 @@ void AbstractClient::processProtocolItem(ProtocolItem *item) return; } - ChatEvent *chatEvent = qobject_cast(item); - if (chatEvent) { - emit chatEventReceived(chatEvent); - if (chatEvent->getReceiverMayDelete()) - delete chatEvent; + RoomEvent *roomEvent = qobject_cast(item); + if (roomEvent) { + emit roomEventReceived(roomEvent); + if (roomEvent->getReceiverMayDelete()) + delete roomEvent; return; } } @@ -75,4 +74,3 @@ void AbstractClient::sendCommand(Command *cmd) { sendCommandContainer(new CommandContainer(QList() << cmd)); } - diff --git a/cockatrice/src/abstractclient.h b/cockatrice/src/abstractclient.h index 601e55db..dae91752 100644 --- a/cockatrice/src/abstractclient.h +++ b/cockatrice/src/abstractclient.h @@ -10,13 +10,13 @@ class ProtocolItem; class ProtocolResponse; class TopLevelProtocolItem; class CommandContainer; -class ChatEvent; +class RoomEvent; class GameEventContainer; class Event_ListGames; class Event_UserJoined; class Event_UserLeft; class Event_ServerMessage; -class Event_ListChatChannels; +class Event_ListRooms; class Event_GameJoined; class Event_Message; @@ -35,18 +35,18 @@ signals: void statusChanged(ClientStatus _status); void serverError(ResponseCode resp); - // Chat events - void chatEventReceived(ChatEvent *event); + // Room events + void roomEventReceived(RoomEvent *event); // Game events void gameEventContainerReceived(GameEventContainer *event); // Generic events - void listGamesEventReceived(Event_ListGames *event); void userJoinedEventReceived(Event_UserJoined *event); void userLeftEventReceived(Event_UserLeft *event); void serverMessageEventReceived(Event_ServerMessage *event); - void listChatChannelsEventReceived(Event_ListChatChannels *event); + void listRoomsEventReceived(Event_ListRooms *event); void gameJoinedEventReceived(Event_GameJoined *event); void messageEventReceived(Event_Message *event); + void userInfoChanged(ServerInfo_User *userInfo); protected slots: void processProtocolItem(ProtocolItem *item); protected: diff --git a/cockatrice/src/counter.cpp b/cockatrice/src/abstractcounter.cpp similarity index 66% rename from cockatrice/src/counter.cpp rename to cockatrice/src/abstractcounter.cpp index ee6d060a..aed566c8 100644 --- a/cockatrice/src/counter.cpp +++ b/cockatrice/src/abstractcounter.cpp @@ -1,16 +1,17 @@ -#include "counter.h" +#include "abstractcounter.h" #include "player.h" #include "protocol_items.h" #include #include #include #include +#include -Counter::Counter(Player *_player, int _id, const QString &_name, QColor _color, int _radius, int _value, QGraphicsItem *parent) - : QGraphicsItem(parent), player(_player), id(_id), name(_name), color(_color), radius(_radius), value(_value), aDec(0), aInc(0), dialogSemaphore(false), deleteAfterDialog(false) +AbstractCounter::AbstractCounter(Player *_player, int _id, const QString &_name, bool _shownInCounterArea, int _value, QGraphicsItem *parent) + : QGraphicsItem(parent), player(_player), id(_id), name(_name), value(_value), hovered(false), aDec(0), aInc(0), dialogSemaphore(false), deleteAfterDialog(false), shownInCounterArea(_shownInCounterArea) { - if (radius > Player::counterAreaWidth / 2) - radius = Player::counterAreaWidth / 2; + setAcceptsHoverEvents(true); + if (player->getLocal()) { menu = new QMenu(name); aSet = new QAction(this); @@ -36,12 +37,12 @@ Counter::Counter(Player *_player, int _id, const QString &_name, QColor _color, retranslateUi(); } -Counter::~Counter() +AbstractCounter::~AbstractCounter() { delete menu; } -void Counter::delCounter() +void AbstractCounter::delCounter() { if (dialogSemaphore) deleteAfterDialog = true; @@ -49,14 +50,14 @@ void Counter::delCounter() deleteLater(); } -void Counter::retranslateUi() +void AbstractCounter::retranslateUi() { if (menu) { aSet->setText(tr("&Set counter...")); } } -void Counter::setShortcutsActive() +void AbstractCounter::setShortcutsActive() { if (name == "life") { aSet->setShortcut(tr("Ctrl+L")); @@ -65,7 +66,7 @@ void Counter::setShortcutsActive() } } -void Counter::setShortcutsInactive() +void AbstractCounter::setShortcutsInactive() { if (name == "life") { aSet->setShortcut(QKeySequence()); @@ -74,31 +75,13 @@ void Counter::setShortcutsInactive() } } -QRectF Counter::boundingRect() const -{ - return QRectF(0, 0, radius * 2, radius * 2); -} - -void Counter::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) -{ - painter->setBrush(QBrush(color)); - painter->drawEllipse(boundingRect()); - if (value) { - QFont f("Serif"); - f.setPixelSize(radius * 0.8); - f.setWeight(QFont::Bold); - painter->setFont(f); - painter->drawText(boundingRect(), Qt::AlignCenter, QString::number(value)); - } -} - -void Counter::setValue(int _value) +void AbstractCounter::setValue(int _value) { value = _value; update(); } -void Counter::mousePressEvent(QGraphicsSceneMouseEvent *event) +void AbstractCounter::mousePressEvent(QGraphicsSceneMouseEvent *event) { if (event->button() == Qt::LeftButton) { player->sendGameCommand(new Command_IncCounter(-1, id, 1)); @@ -114,13 +97,25 @@ void Counter::mousePressEvent(QGraphicsSceneMouseEvent *event) event->ignore(); } -void Counter::incrementCounter() +void AbstractCounter::hoverEnterEvent(QGraphicsSceneHoverEvent *event) +{ + hovered = true; + update(); +} + +void AbstractCounter::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) +{ + hovered = false; + update(); +} + +void AbstractCounter::incrementCounter() { int delta = static_cast(sender())->data().toInt(); player->sendGameCommand(new Command_IncCounter(-1, id, delta)); } -void Counter::setCounter() +void AbstractCounter::setCounter() { bool ok; dialogSemaphore = true; diff --git a/cockatrice/src/counter.h b/cockatrice/src/abstractcounter.h similarity index 61% rename from cockatrice/src/counter.h rename to cockatrice/src/abstractcounter.h index 7d7f932b..6a4a4188 100644 --- a/cockatrice/src/counter.h +++ b/cockatrice/src/abstractcounter.h @@ -7,35 +7,36 @@ class Player; class QMenu; class QAction; -class Counter : public QObject, public QGraphicsItem { +class AbstractCounter : public QObject, public QGraphicsItem { Q_OBJECT -private: +protected: Player *player; int id; QString name; - QColor color; - int radius; int value; + bool hovered; + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void hoverEnterEvent(QGraphicsSceneHoverEvent *event); + void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); +private: QAction *aSet, *aDec, *aInc; QMenu *menu; bool dialogSemaphore, deleteAfterDialog; + bool shownInCounterArea; private slots: void incrementCounter(); void setCounter(); -protected: - void mousePressEvent(QGraphicsSceneMouseEvent *event); public: - Counter(Player *_player, int _id, const QString &_name, QColor _color, int _radius, int _value, QGraphicsItem *parent = 0); - ~Counter(); - QRectF boundingRect() const; - void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + AbstractCounter(Player *_player, int _id, const QString &_name, bool _shownInCounterArea, int _value, QGraphicsItem *parent = 0); + ~AbstractCounter(); QMenu *getMenu() const { return menu; } void retranslateUi(); int getId() const { return id; } QString getName() const { return name; } + bool getShownInCounterArea() const { return shownInCounterArea; } int getValue() const { return value; } void setValue(int _value); void delCounter(); diff --git a/cockatrice/src/abstractgraphicsitem.h b/cockatrice/src/abstractgraphicsitem.h index ff13ff4f..2bb094d3 100644 --- a/cockatrice/src/abstractgraphicsitem.h +++ b/cockatrice/src/abstractgraphicsitem.h @@ -12,11 +12,12 @@ enum GraphicsItemType { typeOther = QGraphicsItem::UserType + 6 }; -class AbstractGraphicsItem : public QGraphicsItem { +class AbstractGraphicsItem : public QObject, public QGraphicsItem { + Q_OBJECT protected: void paintNumberEllipse(int number, int radius, const QColor &color, int position, int count, QPainter *painter); public: - AbstractGraphicsItem(QGraphicsItem *parent = 0) : QGraphicsItem(parent) { } + AbstractGraphicsItem(QGraphicsItem *parent = 0) : QObject(), QGraphicsItem(parent) { } }; #endif diff --git a/cockatrice/src/arrowitem.cpp b/cockatrice/src/arrowitem.cpp index 146b0d1b..1dc1bf2f 100644 --- a/cockatrice/src/arrowitem.cpp +++ b/cockatrice/src/arrowitem.cpp @@ -13,7 +13,7 @@ ArrowItem::ArrowItem(Player *_player, int _id, ArrowTarget *_startItem, ArrowTarget *_targetItem, const QColor &_color) : QGraphicsItem(), player(_player), id(_id), startItem(_startItem), targetItem(_targetItem), color(_color), fullColor(true) { - qDebug() << "ArrowItem constructor: startItem=" << startItem; + qDebug() << "ArrowItem constructor: startItem=" << static_cast(startItem); setZValue(2000000005); if (startItem) @@ -154,7 +154,7 @@ void ArrowDragItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) QList colliding = scene()->items(endPos); ArrowTarget *cursorItem = 0; - int cursorItemZ = -1; + qreal cursorItemZ = -1; for (int i = colliding.size() - 1; i >= 0; i--) if (qgraphicsitem_cast(colliding.at(i)) || qgraphicsitem_cast(colliding.at(i))) if (colliding.at(i)->zValue() > cursorItemZ) { @@ -243,11 +243,14 @@ void ArrowAttachItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) QList colliding = scene()->items(endPos); ArrowTarget *cursorItem = 0; + qreal cursorItemZ = -1; for (int i = colliding.size() - 1; i >= 0; i--) - if (qgraphicsitem_cast(colliding.at(i))) { - cursorItem = static_cast(colliding.at(i)); - break; - } + if (qgraphicsitem_cast(colliding.at(i))) + if (colliding.at(i)->zValue() > cursorItemZ) { + cursorItem = static_cast(colliding.at(i)); + cursorItemZ = cursorItem->zValue(); + } + if ((cursorItem != targetItem) && targetItem) targetItem->setBeingPointedAt(false); if (!cursorItem) { diff --git a/cockatrice/src/carddragitem.cpp b/cockatrice/src/carddragitem.cpp index 5375bae0..56d6c2c6 100644 --- a/cockatrice/src/carddragitem.cpp +++ b/cockatrice/src/carddragitem.cpp @@ -72,17 +72,18 @@ void CardDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) QPointF sp = pos(); sc->removeItem(this); + QList dragItemList; CardZone *startZone = static_cast(item)->getZone(); if (currentZone && !(static_cast(item)->getAttachedTo() && (startZone == currentZone))) { - if (!occupied) - currentZone->handleDropEvent(id, startZone, (sp - currentZone->scenePos()).toPoint(), faceDown); + dragItemList.append(this); for (int i = 0; i < childDrags.size(); i++) { CardDragItem *c = static_cast(childDrags[i]); if (!(static_cast(c->item)->getAttachedTo() && (startZone == currentZone)) && !c->occupied) - currentZone->handleDropEvent(c->id, startZone, (sp - currentZone->scenePos() + c->getHotSpot()).toPoint(), faceDown); + dragItemList.append(c); sc->removeItem(c); } } + currentZone->handleDropEvent(dragItemList, startZone, (sp - currentZone->scenePos()).toPoint(), faceDown); event->accept(); } diff --git a/cockatrice/src/carddragitem.h b/cockatrice/src/carddragitem.h index 82f1d66a..95cc71ce 100644 --- a/cockatrice/src/carddragitem.h +++ b/cockatrice/src/carddragitem.h @@ -13,6 +13,7 @@ private: CardZone *currentZone; public: CardDragItem(CardItem *_item, int _id, const QPointF &_hotSpot, bool _faceDown, AbstractCardDragItem *parentDrag = 0); + int getId() const { return id; } void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); void updatePosition(const QPointF &cursorScenePos); protected: diff --git a/cockatrice/src/carditem.cpp b/cockatrice/src/carditem.cpp index c3da70d8..5bd4d655 100644 --- a/cockatrice/src/carditem.cpp +++ b/cockatrice/src/carditem.cpp @@ -16,92 +16,71 @@ #include "settingscache.h" #include "tab_game.h" -CardItem::CardItem(Player *_owner, const QString &_name, int _cardid, QGraphicsItem *parent) - : AbstractCardItem(_name, _owner, parent), id(_cardid), attacking(false), facedown(false), destroyOnZoneChange(false), doesntUntap(false), dragItem(0), attachedTo(0) +CardItem::CardItem(Player *_owner, const QString &_name, int _cardid, bool _revealedCard, QGraphicsItem *parent) + : AbstractCardItem(_name, _owner, parent), zone(0), id(_cardid), revealedCard(_revealedCard), attacking(false), facedown(false), destroyOnZoneChange(false), doesntUntap(false), dragItem(0), attachedTo(0) { owner->addCard(this); - if (owner->getLocal()) { - aTap = new QAction(this); - aTap->setData(0); - connect(aTap, SIGNAL(triggered()), owner, SLOT(cardMenuAction())); - aUntap = new QAction(this); - aUntap->setData(1); - connect(aUntap, SIGNAL(triggered()), owner, SLOT(cardMenuAction())); - aDoesntUntap = new QAction(this); - aDoesntUntap->setData(2); - connect(aDoesntUntap, SIGNAL(triggered()), owner, SLOT(cardMenuAction())); - aAttach = new QAction(this); - connect(aAttach, SIGNAL(triggered()), owner, SLOT(actAttach())); - aUnattach = new QAction(this); - connect(aUnattach, SIGNAL(triggered()), owner, SLOT(actUnattach())); - aSetPT = new QAction(this); - connect(aSetPT, SIGNAL(triggered()), owner, SLOT(actSetPT())); - aSetAnnotation = new QAction(this); - connect(aSetAnnotation, SIGNAL(triggered()), owner, SLOT(actSetAnnotation())); - aFlip = new QAction(this); - aFlip->setData(3); - connect(aFlip, SIGNAL(triggered()), owner, SLOT(cardMenuAction())); - aClone = new QAction(this); - aClone->setData(4); - connect(aClone, SIGNAL(triggered()), owner, SLOT(cardMenuAction())); - aMoveToTopLibrary = new QAction(this); - aMoveToTopLibrary->setData(5); - aMoveToBottomLibrary = new QAction(this); - aMoveToBottomLibrary->setData(6); - aMoveToGraveyard = new QAction(this); - aMoveToGraveyard->setData(7); - aMoveToExile = new QAction(this); - aMoveToExile->setData(8); - connect(aMoveToTopLibrary, SIGNAL(triggered()), owner, SLOT(cardMenuAction())); - connect(aMoveToBottomLibrary, SIGNAL(triggered()), owner, SLOT(cardMenuAction())); - connect(aMoveToGraveyard, SIGNAL(triggered()), owner, SLOT(cardMenuAction())); - connect(aMoveToExile, SIGNAL(triggered()), owner, SLOT(cardMenuAction())); + aTap = new QAction(this); + aTap->setData(0); + connect(aTap, SIGNAL(triggered()), this, SLOT(cardMenuAction())); + aUntap = new QAction(this); + aUntap->setData(1); + connect(aUntap, SIGNAL(triggered()), this, SLOT(cardMenuAction())); + aDoesntUntap = new QAction(this); + aDoesntUntap->setData(2); + connect(aDoesntUntap, SIGNAL(triggered()), this, SLOT(cardMenuAction())); + aAttach = new QAction(this); + connect(aAttach, SIGNAL(triggered()), this, SLOT(actAttach())); + aUnattach = new QAction(this); + connect(aUnattach, SIGNAL(triggered()), this, SLOT(actUnattach())); + aSetPT = new QAction(this); + connect(aSetPT, SIGNAL(triggered()), this, SLOT(actSetPT())); + aSetAnnotation = new QAction(this); + connect(aSetAnnotation, SIGNAL(triggered()), this, SLOT(actSetAnnotation())); + aFlip = new QAction(this); + aFlip->setData(3); + connect(aFlip, SIGNAL(triggered()), this, SLOT(cardMenuAction())); + aClone = new QAction(this); + aClone->setData(4); + connect(aClone, SIGNAL(triggered()), this, SLOT(cardMenuAction())); + aMoveToTopLibrary = new QAction(this); + aMoveToTopLibrary->setData(5); + aMoveToBottomLibrary = new QAction(this); + aMoveToBottomLibrary->setData(6); + aMoveToGraveyard = new QAction(this); + aMoveToGraveyard->setData(7); + aMoveToExile = new QAction(this); + aMoveToExile->setData(8); + connect(aMoveToTopLibrary, SIGNAL(triggered()), this, SLOT(cardMenuAction())); + connect(aMoveToBottomLibrary, SIGNAL(triggered()), this, SLOT(cardMenuAction())); + connect(aMoveToGraveyard, SIGNAL(triggered()), this, SLOT(cardMenuAction())); + connect(aMoveToExile, SIGNAL(triggered()), this, SLOT(cardMenuAction())); + + aPlay = new QAction(this); + connect(aPlay, SIGNAL(triggered()), this, SLOT(actPlay())); + aHide = new QAction(this); + connect(aHide, SIGNAL(triggered()), this, SLOT(actHide())); - cardMenu = new QMenu; - cardMenu->addAction(aTap); - cardMenu->addAction(aUntap); - cardMenu->addAction(aDoesntUntap); - cardMenu->addAction(aFlip); - cardMenu->addSeparator(); - cardMenu->addAction(aAttach); - cardMenu->addAction(aUnattach); - cardMenu->addSeparator(); - cardMenu->addAction(aSetPT); - cardMenu->addAction(aSetAnnotation); - cardMenu->addSeparator(); - cardMenu->addAction(aClone); - for (int i = 0; i < 3; ++i) { - QAction *tempAddCounter = new QAction(this); - tempAddCounter->setData(9 + i * 1000); - QAction *tempRemoveCounter = new QAction(this); - tempRemoveCounter->setData(10 + i * 1000); - QAction *tempSetCounter = new QAction(this); - tempSetCounter->setData(11 + i * 1000); - aAddCounter.append(tempAddCounter); - aRemoveCounter.append(tempRemoveCounter); - aSetCounter.append(tempSetCounter); - connect(tempAddCounter, SIGNAL(triggered()), owner, SLOT(actCardCounterTrigger())); - connect(tempRemoveCounter, SIGNAL(triggered()), owner, SLOT(actCardCounterTrigger())); - connect(tempSetCounter, SIGNAL(triggered()), owner, SLOT(actCardCounterTrigger())); - - cardMenu->addSeparator(); - cardMenu->addAction(tempAddCounter); - cardMenu->addAction(tempRemoveCounter); - cardMenu->addAction(tempSetCounter); - } - cardMenu->addSeparator(); - - moveMenu = cardMenu->addMenu(QString()); - moveMenu->addAction(aMoveToTopLibrary); - moveMenu->addAction(aMoveToBottomLibrary); - moveMenu->addAction(aMoveToGraveyard); - moveMenu->addAction(aMoveToExile); - - - retranslateUi(); - } else - cardMenu = 0; + for (int i = 0; i < 3; ++i) { + QAction *tempAddCounter = new QAction(this); + tempAddCounter->setData(9 + i * 1000); + QAction *tempRemoveCounter = new QAction(this); + tempRemoveCounter->setData(10 + i * 1000); + QAction *tempSetCounter = new QAction(this); + tempSetCounter->setData(11 + i * 1000); + aAddCounter.append(tempAddCounter); + aRemoveCounter.append(tempRemoveCounter); + aSetCounter.append(tempSetCounter); + connect(tempAddCounter, SIGNAL(triggered()), this, SLOT(actCardCounterTrigger())); + connect(tempRemoveCounter, SIGNAL(triggered()), this, SLOT(actCardCounterTrigger())); + connect(tempSetCounter, SIGNAL(triggered()), this, SLOT(actCardCounterTrigger())); + } + cardMenu = new QMenu; + moveMenu = new QMenu; + + retranslateUi(); + updateCardMenu(); } CardItem::~CardItem() @@ -110,6 +89,8 @@ CardItem::~CardItem() delete cardMenu; cardMenu = 0; + delete moveMenu; + moveMenu = 0; deleteDragItem(); } @@ -139,37 +120,88 @@ void CardItem::deleteLater() AbstractCardItem::deleteLater(); } +void CardItem::setZone(CardZone *_zone) +{ + zone = _zone; + updateCardMenu(); +} + +void CardItem::updateCardMenu() +{ + cardMenu->clear(); + + if (revealedCard) + cardMenu->addAction(aHide); + else if (owner->getLocal()) { + if (zone) { + if (zone->getName() == "table") { + cardMenu->addAction(aTap); + cardMenu->addAction(aUntap); + cardMenu->addAction(aDoesntUntap); + cardMenu->addAction(aFlip); + cardMenu->addSeparator(); + cardMenu->addAction(aAttach); + if (attachedTo) + cardMenu->addAction(aUnattach); + cardMenu->addSeparator(); + cardMenu->addAction(aSetPT); + cardMenu->addAction(aSetAnnotation); + cardMenu->addSeparator(); + cardMenu->addAction(aClone); + + for (int i = 0; i < aAddCounter.size(); ++i) { + cardMenu->addSeparator(); + cardMenu->addAction(aAddCounter[i]); + cardMenu->addAction(aRemoveCounter[i]); + cardMenu->addAction(aSetCounter[i]); + } + cardMenu->addSeparator(); + } else { + cardMenu->addAction(aPlay); + } + } + + moveMenu->clear(); + moveMenu->addAction(aMoveToTopLibrary); + moveMenu->addAction(aMoveToBottomLibrary); + moveMenu->addAction(aMoveToGraveyard); + moveMenu->addAction(aMoveToExile); + cardMenu->addMenu(moveMenu); + } +} + void CardItem::retranslateUi() { - if (owner->getLocal()) { - aTap->setText(tr("&Tap")); - aUntap->setText(tr("&Untap")); - aDoesntUntap->setText(tr("Toggle &normal untapping")); - aFlip->setText(tr("&Flip")); - aClone->setText(tr("&Clone")); - aAttach->setText(tr("&Attach to card...")); - aAttach->setShortcut(tr("Ctrl+A")); - aUnattach->setText(tr("Unattac&h")); - aSetPT->setText(tr("Set &P/T...")); - aSetAnnotation->setText(tr("&Set annotation...")); - QStringList counterColors; - counterColors.append(tr("red")); - counterColors.append(tr("yellow")); - counterColors.append(tr("green")); - for (int i = 0; i < aAddCounter.size(); ++i) - aAddCounter[i]->setText(tr("&Add counter (%1)").arg(counterColors[i])); - for (int i = 0; i < aRemoveCounter.size(); ++i) - aRemoveCounter[i]->setText(tr("&Remove counter (%1)").arg(counterColors[i])); - for (int i = 0; i < aSetCounter.size(); ++i) - aSetCounter[i]->setText(tr("&Set counters (%1)...").arg(counterColors[i])); - aMoveToTopLibrary->setText(tr("&top of library")); - aMoveToBottomLibrary->setText(tr("&bottom of library")); - aMoveToGraveyard->setText(tr("&graveyard")); - aMoveToGraveyard->setShortcut(tr("Ctrl+Del")); - aMoveToExile->setText(tr("&exile")); - - moveMenu->setTitle(tr("&Move to")); - } + aPlay->setText(tr("&Play")); + aHide->setText(tr("&Hide")); + + aTap->setText(tr("&Tap")); + aUntap->setText(tr("&Untap")); + aDoesntUntap->setText(tr("Toggle &normal untapping")); + aFlip->setText(tr("&Flip")); + aClone->setText(tr("&Clone")); + aAttach->setText(tr("&Attach to card...")); + aAttach->setShortcut(tr("Ctrl+A")); + aUnattach->setText(tr("Unattac&h")); + aSetPT->setText(tr("Set &P/T...")); + aSetAnnotation->setText(tr("&Set annotation...")); + QStringList counterColors; + counterColors.append(tr("red")); + counterColors.append(tr("yellow")); + counterColors.append(tr("green")); + for (int i = 0; i < aAddCounter.size(); ++i) + aAddCounter[i]->setText(tr("&Add counter (%1)").arg(counterColors[i])); + for (int i = 0; i < aRemoveCounter.size(); ++i) + aRemoveCounter[i]->setText(tr("&Remove counter (%1)").arg(counterColors[i])); + for (int i = 0; i < aSetCounter.size(); ++i) + aSetCounter[i]->setText(tr("&Set counters (%1)...").arg(counterColors[i])); + aMoveToTopLibrary->setText(tr("&top of library")); + aMoveToBottomLibrary->setText(tr("&bottom of library")); + aMoveToGraveyard->setText(tr("&graveyard")); + aMoveToGraveyard->setShortcut(tr("Ctrl+Del")); + aMoveToExile->setText(tr("&exile")); + + moveMenu->setTitle(tr("&Move to")); } void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) @@ -263,6 +295,8 @@ void CardItem::setAttachedTo(CardItem *_attachedTo) if (zone) zone->reorganizeCards(); + + updateCardMenu(); } void CardItem::resetState() @@ -376,7 +410,7 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) setCursor(Qt::OpenHandCursor); } -void CardItem::playCard(QGraphicsSceneMouseEvent *event) +void CardItem::playCard(bool faceDown) { // Do nothing if the card belongs to another player if (!owner->getLocal()) @@ -385,22 +419,22 @@ void CardItem::playCard(QGraphicsSceneMouseEvent *event) TableZone *tz = qobject_cast(zone); if (tz) tz->toggleTapped(); - else { - bool faceDown = event->modifiers().testFlag(Qt::ShiftModifier); - bool tapped = info->getCipt(); - - zone->getPlayer()->playCard(this, faceDown, tapped); - } + else + zone->getPlayer()->playCard(this, faceDown, info->getCipt()); } void CardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { if (event->button() == Qt::RightButton) { if (cardMenu) - cardMenu->exec(event->screenPos()); + if (!cardMenu->isEmpty()) + cardMenu->exec(event->screenPos()); } else if ((event->button() == Qt::LeftButton) && !settingsCache->getDoubleClickToPlay()) { setCursor(Qt::OpenHandCursor); - playCard(event); + if (revealedCard) + actHide(); + else + playCard(event->modifiers().testFlag(Qt::ShiftModifier)); } AbstractCardItem::mouseReleaseEvent(event); @@ -408,14 +442,18 @@ void CardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) void CardItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { - if (settingsCache->getDoubleClickToPlay()) - playCard(event); + if (settingsCache->getDoubleClickToPlay()) { + if (revealedCard) + actHide(); + else + playCard(event->modifiers().testFlag(Qt::ShiftModifier)); + } event->accept(); } QVariant CardItem::itemChange(GraphicsItemChange change, const QVariant &value) { - if (change == ItemSelectedHasChanged) { + if ((change == ItemSelectedHasChanged) && owner) { if (value == true) owner->setCardMenu(cardMenu); else if (owner->getCardMenu() == cardMenu) @@ -423,3 +461,43 @@ QVariant CardItem::itemChange(GraphicsItemChange change, const QVariant &value) } return QGraphicsItem::itemChange(change, value); } + +void CardItem::cardMenuAction() +{ + owner->cardMenuAction(static_cast(sender())); +} + +void CardItem::actAttach() +{ + owner->actAttach(static_cast(sender())); +} + +void CardItem::actUnattach() +{ + owner->actUnattach(static_cast(sender())); +} + +void CardItem::actSetPT() +{ + owner->actSetPT(static_cast(sender())); +} + +void CardItem::actSetAnnotation() +{ + owner->actSetAnnotation(static_cast(sender())); +} + +void CardItem::actCardCounterTrigger() +{ + owner->actCardCounterTrigger(static_cast(sender())); +} + +void CardItem::actPlay() +{ + playCard(false); +} + +void CardItem::actHide() +{ + zone->removeCard(this); +} \ No newline at end of file diff --git a/cockatrice/src/carditem.h b/cockatrice/src/carditem.h index 52642abb..97b86774 100644 --- a/cockatrice/src/carditem.h +++ b/cockatrice/src/carditem.h @@ -17,6 +17,7 @@ class CardItem : public AbstractCardItem { private: CardZone *zone; int id; + bool revealedCard; bool attacking; bool facedown; QMap counters; @@ -30,28 +31,40 @@ private: QList attachedCards; QList aAddCounter, aSetCounter, aRemoveCounter; - QAction *aTap, *aUntap, *aDoesntUntap, *aAttach, *aUnattach, *aSetPT, *aSetAnnotation, *aFlip, *aClone, + QAction *aPlay, + *aHide, + *aTap, *aUntap, *aDoesntUntap, *aAttach, *aUnattach, *aSetPT, *aSetAnnotation, *aFlip, *aClone, *aMoveToTopLibrary, *aMoveToBottomLibrary, *aMoveToGraveyard, *aMoveToExile; QMenu *cardMenu, *moveMenu; - void playCard(QGraphicsSceneMouseEvent *event); + void playCard(bool faceDown); void prepareDelete(); +private slots: + void cardMenuAction(); + void actCardCounterTrigger(); + void actAttach(); + void actUnattach(); + void actSetPT(); + void actSetAnnotation(); + void actPlay(); + void actHide(); public slots: void deleteLater(); public: enum { Type = typeCard }; int type() const { return Type; } - CardItem(Player *_owner, const QString &_name = QString(), int _cardid = -1, QGraphicsItem *parent = 0); + CardItem(Player *_owner, const QString &_name = QString(), int _cardid = -1, bool revealedCard = false, QGraphicsItem *parent = 0); ~CardItem(); void retranslateUi(); CardZone *getZone() const { return zone; } - void setZone(CardZone *_zone) { zone = _zone; } + void setZone(CardZone *_zone); QMenu *getCardMenu() const { return cardMenu; } void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); QPoint getGridPoint() const { return gridPoint; } void setGridPoint(const QPoint &_gridPoint) { gridPoint = _gridPoint; } QPoint getGridPos() const { return gridPoint; } Player *getOwner() const { return owner; } + void setOwner(Player *_owner) { owner = _owner; } int getId() const { return id; } void setId(int _id) { id = _id; } bool getAttacking() const { return attacking; } @@ -75,6 +88,7 @@ public: const QList &getAttachedCards() const { return attachedCards; } void resetState(); void processCardInfo(ServerInfo_Card *info); + void updateCardMenu(); CardDragItem *createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool faceDown); void deleteDragItem(); diff --git a/cockatrice/src/cardzone.cpp b/cockatrice/src/cardzone.cpp index 6052f34e..9f9c275a 100644 --- a/cockatrice/src/cardzone.cpp +++ b/cockatrice/src/cardzone.cpp @@ -157,16 +157,25 @@ CardItem *CardZone::takeCard(int position, int cardId, bool /*canResize*/) return c; } +void CardZone::removeCard(CardItem *card) +{ + cards.removeAt(cards.indexOf(card)); + reorganizeCards(); + emit cardCountChanged(); + player->deleteCard(card); +} + void CardZone::moveAllToZone() { QList data = static_cast(sender())->data().toList(); QString targetZone = data[0].toString(); int targetX = data[1].toInt(); - // Cards need to be moved in reverse order so that the other - // cards' list index doesn't change - for (int i = cards.size() - 1; i >= 0; i--) - player->sendGameCommand(new Command_MoveCard(-1, getName(), cards.at(i)->getId(), targetZone, targetX)); + QList idList; + for (int i = 0; i < cards.size(); ++i) + idList.append(new CardId(cards[i]->getId())); + + player->sendGameCommand(new Command_MoveCard(-1, getName(), idList, player->getId(), targetZone, targetX)); } QPointF CardZone::closestGridPoint(const QPointF &point) diff --git a/cockatrice/src/cardzone.h b/cockatrice/src/cardzone.h index b8e834f6..0b1809bb 100644 --- a/cockatrice/src/cardzone.h +++ b/cockatrice/src/cardzone.h @@ -12,8 +12,9 @@ class ZoneViewZone; class QMenu; class QAction; class QPainter; +class CardDragItem; -class CardZone : public QObject, public AbstractGraphicsItem { +class CardZone : public AbstractGraphicsItem { Q_OBJECT protected: Player *player; @@ -34,7 +35,7 @@ public slots: public: enum { Type = typeZone }; int type() const { return Type; } - virtual void handleDropEvent(int cardId, CardZone *startZone, const QPoint &dropPoint, bool faceDown) = 0; + virtual void handleDropEvent(const QList &dragItem, CardZone *startZone, const QPoint &dropPoint, bool faceDown) = 0; CardZone(Player *_player, const QString &_name, bool _hasCardAttr, bool _isShufflable, bool _contentsKnown, QGraphicsItem *parent = 0, bool isView = false); ~CardZone(); void retranslateUi(); @@ -53,6 +54,7 @@ public: CardItem *getCard(int cardId, const QString &cardName); // takeCard() finds a card by position and removes it from the zone and from all of its views. virtual CardItem *takeCard(int position, int cardId, bool canResize = true); + void removeCard(CardItem *card); ZoneViewZone *getView() const { return view; } void setView(ZoneViewZone *_view) { view = _view; } virtual void reorganizeCards() = 0; diff --git a/cockatrice/src/counter_general.cpp b/cockatrice/src/counter_general.cpp new file mode 100644 index 00000000..6b722834 --- /dev/null +++ b/cockatrice/src/counter_general.cpp @@ -0,0 +1,26 @@ +#include "counter_general.h" +#include + +GeneralCounter::GeneralCounter(Player *_player, int _id, const QString &_name, const QColor &_color, int _radius, int _value, QGraphicsItem *parent) + : AbstractCounter(_player, _id, _name, true, _value, parent), color(_color), radius(_radius) +{ +} + +QRectF GeneralCounter::boundingRect() const +{ + return QRectF(0, 0, radius * 2, radius * 2); +} + +void GeneralCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) +{ + painter->setBrush(QBrush(color)); + painter->drawEllipse(boundingRect()); + if (value) { + QFont f("Serif"); + f.setPixelSize(radius * 0.8); + f.setWeight(QFont::Bold); + painter->setFont(f); + painter->drawText(boundingRect(), Qt::AlignCenter, QString::number(value)); + } +} + diff --git a/cockatrice/src/counter_general.h b/cockatrice/src/counter_general.h new file mode 100644 index 00000000..58468aa8 --- /dev/null +++ b/cockatrice/src/counter_general.h @@ -0,0 +1,17 @@ +#ifndef COUNTER_GENERAL_H +#define COUNTER_GENERAL_H + +#include "abstractcounter.h" + +class GeneralCounter : public AbstractCounter { + Q_OBJECT +private: + QColor color; + int radius; +public: + GeneralCounter(Player *_player, int _id, const QString &_name, const QColor &_color, int _radius, int _value, QGraphicsItem *parent = 0); + QRectF boundingRect() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); +}; + +#endif \ No newline at end of file diff --git a/cockatrice/src/dlg_creategame.cpp b/cockatrice/src/dlg_creategame.cpp index 5cf957b6..e36a6815 100644 --- a/cockatrice/src/dlg_creategame.cpp +++ b/cockatrice/src/dlg_creategame.cpp @@ -11,8 +11,8 @@ #include "dlg_creategame.h" #include "protocol_items.h" -DlgCreateGame::DlgCreateGame(AbstractClient *_client, QWidget *parent) - : QDialog(parent), client(_client) +DlgCreateGame::DlgCreateGame(AbstractClient *_client, int _roomId, QWidget *parent) + : QDialog(parent), client(_client), roomId(_roomId) { descriptionLabel = new QLabel(tr("&Description:")); descriptionEdit = new QLineEdit; @@ -77,6 +77,7 @@ DlgCreateGame::DlgCreateGame(AbstractClient *_client, QWidget *parent) void DlgCreateGame::actOK() { Command_CreateGame *createCommand = new Command_CreateGame( + roomId, descriptionEdit->text(), passwordEdit->text(), maxPlayersEdit->value(), diff --git a/cockatrice/src/dlg_creategame.h b/cockatrice/src/dlg_creategame.h index af72fe18..dcd901df 100644 --- a/cockatrice/src/dlg_creategame.h +++ b/cockatrice/src/dlg_creategame.h @@ -14,13 +14,14 @@ class QSpinBox; class DlgCreateGame : public QDialog { Q_OBJECT public: - DlgCreateGame(AbstractClient *_client, QWidget *parent = 0); + DlgCreateGame(AbstractClient *_client, int _roomId, QWidget *parent = 0); private slots: void actOK(); void checkResponse(ResponseCode response); void spectatorsAllowedChanged(int state); private: AbstractClient *client; + int roomId; QGroupBox *spectatorsGroupBox; QLabel *descriptionLabel, *passwordLabel, *maxPlayersLabel; diff --git a/cockatrice/src/dlg_settings.cpp b/cockatrice/src/dlg_settings.cpp index bf332947..46ffeff7 100644 --- a/cockatrice/src/dlg_settings.cpp +++ b/cockatrice/src/dlg_settings.cpp @@ -228,17 +228,12 @@ AppearanceSettingsPage::AppearanceSettingsPage() handGroupBox = new QGroupBox; handGroupBox->setLayout(handGrid); - economicalGridCheckBox = new QCheckBox; - economicalGridCheckBox->setChecked(settingsCache->getEconomicalGrid()); - connect(economicalGridCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setEconomicalGrid(int))); - invertVerticalCoordinateCheckBox = new QCheckBox; invertVerticalCoordinateCheckBox->setChecked(settingsCache->getInvertVerticalCoordinate()); connect(invertVerticalCoordinateCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setInvertVerticalCoordinate(int))); QGridLayout *tableGrid = new QGridLayout; - tableGrid->addWidget(economicalGridCheckBox, 0, 0, 1, 2); - tableGrid->addWidget(invertVerticalCoordinateCheckBox, 1, 0, 1, 2); + tableGrid->addWidget(invertVerticalCoordinateCheckBox, 0, 0, 1, 2); tableGroupBox = new QGroupBox; tableGroupBox->setLayout(tableGrid); @@ -279,7 +274,6 @@ void AppearanceSettingsPage::retranslateUi() horizontalHandCheckBox->setText(tr("Display hand horizontally (wastes space)")); tableGroupBox->setTitle(tr("Table grid layout")); - economicalGridCheckBox->setText(tr("Economical layout")); invertVerticalCoordinateCheckBox->setText(tr("Invert vertical coordinate")); zoneViewGroupBox->setTitle(tr("Zone view layout")); diff --git a/cockatrice/src/dlg_settings.h b/cockatrice/src/dlg_settings.h index a0b45ab6..abdac076 100644 --- a/cockatrice/src/dlg_settings.h +++ b/cockatrice/src/dlg_settings.h @@ -67,7 +67,7 @@ signals: private: QLabel *handBgLabel, *stackBgLabel, *tableBgLabel, *playerAreaBgLabel, *cardBackPicturePathLabel; QLineEdit *handBgEdit, *stackBgEdit, *tableBgEdit, *playerAreaBgEdit, *cardBackPicturePathEdit; - QCheckBox *horizontalHandCheckBox, *economicalGridCheckBox, *invertVerticalCoordinateCheckBox, *zoneViewSortByNameCheckBox, *zoneViewSortByTypeCheckBox; + QCheckBox *horizontalHandCheckBox, *invertVerticalCoordinateCheckBox, *zoneViewSortByNameCheckBox, *zoneViewSortByTypeCheckBox; QGroupBox *zoneBgGroupBox, *handGroupBox, *tableGroupBox, *zoneViewGroupBox; public: AppearanceSettingsPage(); diff --git a/cockatrice/src/gamescene.cpp b/cockatrice/src/gamescene.cpp index e92fb820..330ebef5 100644 --- a/cockatrice/src/gamescene.cpp +++ b/cockatrice/src/gamescene.cpp @@ -82,7 +82,7 @@ void GameScene::toggleZoneView(Player *player, const QString &zoneName, int numb } } - ZoneViewWidget *item = new ZoneViewWidget(player, player->getZones().value(zoneName), numberCards); + ZoneViewWidget *item = new ZoneViewWidget(player, player->getZones().value(zoneName), numberCards, false); views.append(item); connect(item, SIGNAL(closePressed(ZoneViewWidget *)), this, SLOT(removeZoneView(ZoneViewWidget *))); addItem(item); @@ -91,7 +91,7 @@ void GameScene::toggleZoneView(Player *player, const QString &zoneName, int numb void GameScene::addRevealedZoneView(Player *player, CardZone *zone, const QList &cardList) { - ZoneViewWidget *item = new ZoneViewWidget(player, zone, -2, cardList); + ZoneViewWidget *item = new ZoneViewWidget(player, zone, -2, true, cardList); views.append(item); connect(item, SIGNAL(closePressed(ZoneViewWidget *)), this, SLOT(removeZoneView(ZoneViewWidget *))); addItem(item); @@ -195,3 +195,18 @@ bool GameScene::event(QEvent *event) } return QGraphicsScene::event(event); } + +void GameScene::startRubberBand(const QPointF &selectionOrigin) +{ + emit sigStartRubberBand(selectionOrigin); +} + +void GameScene::resizeRubberBand(const QPointF &cursorPoint) +{ + emit sigResizeRubberBand(cursorPoint); +} + +void GameScene::stopRubberBand() +{ + emit sigStopRubberBand(); +} diff --git a/cockatrice/src/gamescene.h b/cockatrice/src/gamescene.h index da35320e..67031fc2 100644 --- a/cockatrice/src/gamescene.h +++ b/cockatrice/src/gamescene.h @@ -23,6 +23,10 @@ public: void retranslateUi(); const QRectF &getPlayersRect() const { return playersRect; } void processViewSizeChange(const QSize &newSize); + + void startRubberBand(const QPointF &selectionOrigin); + void resizeRubberBand(const QPointF &cursorPoint); + void stopRubberBand(); public slots: void toggleZoneView(Player *player, const QString &zoneName, int numberCards); void addRevealedZoneView(Player *player, CardZone *zone, const QList &cardList); @@ -35,6 +39,10 @@ private slots: void rearrange(); protected: bool event(QEvent *event); +signals: + void sigStartRubberBand(const QPointF &selectionOrigin); + void sigResizeRubberBand(const QPointF &cursorPoint); + void sigStopRubberBand(); }; #endif diff --git a/cockatrice/src/gameview.cpp b/cockatrice/src/gameview.cpp index fd716827..7b13ae11 100644 --- a/cockatrice/src/gameview.cpp +++ b/cockatrice/src/gameview.cpp @@ -2,17 +2,21 @@ #include "gamescene.h" #include #include +#include GameView::GameView(QGraphicsScene *scene, QWidget *parent) - : QGraphicsView(scene, parent) + : QGraphicsView(scene, parent), rubberBand(0) { setBackgroundBrush(QBrush(QColor(0, 0, 0))); setRenderHints(QPainter::TextAntialiasing | QPainter::Antialiasing/* | QPainter::SmoothPixmapTransform*/); - setDragMode(RubberBandDrag); setFocusPolicy(Qt::NoFocus); setViewportUpdateMode(BoundingRectViewportUpdate); connect(scene, SIGNAL(sceneRectChanged(const QRectF &)), this, SLOT(updateSceneRect(const QRectF &))); + + connect(scene, SIGNAL(sigStartRubberBand(const QPointF &)), this, SLOT(startRubberBand(const QPointF &))); + connect(scene, SIGNAL(sigResizeRubberBand(const QPointF &)), this, SLOT(resizeRubberBand(const QPointF &))); + connect(scene, SIGNAL(sigStopRubberBand()), this, SLOT(stopRubberBand())); aCloseMostRecentZoneView = new QAction(this); aCloseMostRecentZoneView->setShortcut(tr("Esc")); @@ -35,3 +39,25 @@ void GameView::updateSceneRect(const QRectF &rect) qDebug(QString("updateSceneRect = %1,%2").arg(rect.width()).arg(rect.height()).toLatin1()); fitInView(rect, Qt::KeepAspectRatio); } + +void GameView::startRubberBand(const QPointF &_selectionOrigin) +{ + selectionOrigin = _selectionOrigin; + rubberBand = new QRubberBand(QRubberBand::Rectangle, this); + rubberBand->setGeometry(QRect(mapFromScene(selectionOrigin), QSize(0, 0))); + rubberBand->show(); +} + +void GameView::resizeRubberBand(const QPointF &cursorPoint) +{ + if (rubberBand) + rubberBand->setGeometry(QRect(mapFromScene(selectionOrigin), mapFromScene(cursorPoint)).normalized()); +} + +void GameView::stopRubberBand() +{ + if (rubberBand) { + rubberBand->deleteLater(); + rubberBand = 0; + } +} diff --git a/cockatrice/src/gameview.h b/cockatrice/src/gameview.h index c45e675e..84acf45e 100644 --- a/cockatrice/src/gameview.h +++ b/cockatrice/src/gameview.h @@ -3,12 +3,20 @@ #include +class QRubberBand; + class GameView : public QGraphicsView { Q_OBJECT private: QAction *aCloseMostRecentZoneView; + QRubberBand *rubberBand; + QPointF selectionOrigin; protected: void resizeEvent(QResizeEvent *event); +private slots: + void startRubberBand(const QPointF &selectionOrigin); + void resizeRubberBand(const QPointF &cursorPoint); + void stopRubberBand(); public slots: void updateSceneRect(const QRectF &rect); public: diff --git a/cockatrice/src/handcounter.h b/cockatrice/src/handcounter.h index 9e942a64..46de6889 100644 --- a/cockatrice/src/handcounter.h +++ b/cockatrice/src/handcounter.h @@ -7,7 +7,7 @@ class QPainter; class QPixmap; -class HandCounter : public QObject, public AbstractGraphicsItem { +class HandCounter : public AbstractGraphicsItem { Q_OBJECT private: int number; diff --git a/cockatrice/src/handzone.cpp b/cockatrice/src/handzone.cpp index d871c54d..258567e3 100644 --- a/cockatrice/src/handzone.cpp +++ b/cockatrice/src/handzone.cpp @@ -3,9 +3,10 @@ #include "settingscache.h" #include "player.h" #include "protocol_items.h" +#include "carddragitem.h" HandZone::HandZone(Player *_p, bool _contentsKnown, int _zoneHeight, QGraphicsItem *parent) - : CardZone(_p, "hand", false, false, _contentsKnown, parent), zoneHeight(_zoneHeight) + : SelectZone(_p, "hand", false, false, _contentsKnown, parent), zoneHeight(_zoneHeight) { connect(settingsCache, SIGNAL(handBgPathChanged()), this, SLOT(updateBgPixmap())); updateBgPixmap(); @@ -36,9 +37,13 @@ void HandZone::addCardImpl(CardItem *card, int x, int /*y*/) card->update(); } -void HandZone::handleDropEvent(int cardId, CardZone *startZone, const QPoint &/*dropPoint*/, bool /*faceDown*/) +void HandZone::handleDropEvent(const QList &dragItems, CardZone *startZone, const QPoint &/*dropPoint*/, bool /*faceDown*/) { - player->sendGameCommand(new Command_MoveCard(-1, startZone->getName(), cardId, getName(), cards.size(), -1, false)); + QList idList; + for (int i = 0; i < dragItems.size(); ++i) + idList.append(new CardId(dragItems[i]->getId())); + + player->sendGameCommand(new Command_MoveCard(-1, startZone->getName(), idList, player->getId(), getName(), cards.size(), -1, false)); } QRectF HandZone::boundingRect() const @@ -65,7 +70,7 @@ void HandZone::reorganizeCards() const int xPadding = 5; qreal totalWidth = boundingRect().width() - 2 * xPadding; qreal cardWidth = cards.at(0)->boundingRect().width(); - + for (int i = 0; i < cardCount; i++) { CardItem *c = cards.at(i); diff --git a/cockatrice/src/handzone.h b/cockatrice/src/handzone.h index 1392fa16..85dde951 100644 --- a/cockatrice/src/handzone.h +++ b/cockatrice/src/handzone.h @@ -1,9 +1,9 @@ #ifndef HANDZONE_H #define HANDZONE_H -#include "cardzone.h" +#include "selectzone.h" -class HandZone : public CardZone { +class HandZone : public SelectZone { Q_OBJECT private: qreal width, zoneHeight; @@ -14,7 +14,7 @@ public slots: void updateOrientation(); public: HandZone(Player *_p, bool _contentsKnown, int _zoneHeight, QGraphicsItem *parent = 0); - void handleDropEvent(int cardId, CardZone *startZone, const QPoint &dropPoint, bool faceDown); + void handleDropEvent(const QList &dragItems, CardZone *startZone, const QPoint &dropPoint, bool faceDown); QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); void reorganizeCards(); diff --git a/cockatrice/src/localclient.cpp b/cockatrice/src/localclient.cpp index b42b810c..87b215ba 100644 --- a/cockatrice/src/localclient.cpp +++ b/cockatrice/src/localclient.cpp @@ -7,6 +7,7 @@ LocalClient::LocalClient(LocalServerInterface *_lsi, const QString &_playerName, { connect(lsi, SIGNAL(itemToClient(ProtocolItem *)), this, SLOT(itemFromServer(ProtocolItem *))); sendCommand(new Command_Login(_playerName, QString())); + sendCommand(new Command_JoinRoom(0)); } LocalClient::~LocalClient() diff --git a/cockatrice/src/localserver.cpp b/cockatrice/src/localserver.cpp index 1af04676..da403f91 100644 --- a/cockatrice/src/localserver.cpp +++ b/cockatrice/src/localserver.cpp @@ -1,9 +1,11 @@ #include "localserver.h" #include "localserverinterface.h" +#include "server_room.h" LocalServer::LocalServer(QObject *parent) : Server(parent) { + addRoom(new Server_Room(0, QString(), QString(), false, QString(), this)); } LocalServer::~LocalServer() diff --git a/cockatrice/src/localserverinterface.h b/cockatrice/src/localserverinterface.h index 0f954844..f88d4940 100644 --- a/cockatrice/src/localserverinterface.h +++ b/cockatrice/src/localserverinterface.h @@ -16,6 +16,7 @@ private: ResponseCode cmdDeckDel(Command_DeckDel * /*cmd*/, CommandContainer * /*cont*/) { return RespFunctionNotAllowed; } ResponseCode cmdDeckUpload(Command_DeckUpload * /*cmd*/, CommandContainer * /*cont*/) { return RespFunctionNotAllowed; } ResponseCode cmdDeckDownload(Command_DeckDownload * /*cmd*/, CommandContainer * /*cont*/) { return RespFunctionNotAllowed; } + ResponseCode cmdUpdateServerMessage(Command_UpdateServerMessage * /*cmd*/, CommandContainer * /*cont*/) { return RespFunctionNotAllowed; } public: LocalServerInterface(LocalServer *_server); ~LocalServerInterface(); diff --git a/cockatrice/src/messagelogwidget.cpp b/cockatrice/src/messagelogwidget.cpp index 7e42c0b3..4ce4621d 100644 --- a/cockatrice/src/messagelogwidget.cpp +++ b/cockatrice/src/messagelogwidget.cpp @@ -181,7 +181,7 @@ void MessageLogWidget::logMoveCard(Player *player, QString cardName, CardZone *s { QString startName = startZone->getName(); QString targetName = targetZone->getName(); - if (((startName == "table") && (targetName == "table")) || ((startName == "hand") && (targetName == "hand"))) + if (((startName == "table") && (targetName == "table") && (startZone == targetZone)) || ((startName == "hand") && (targetName == "hand"))) return; QPair temp = getFromStr(startZone, cardName, oldX); bool cardNameContainsStartZone = false; @@ -190,6 +190,18 @@ void MessageLogWidget::logMoveCard(Player *player, QString cardName, CardZone *s cardName = temp.first; } QString fromStr = temp.second; + QString cardStr; + if (cardNameContainsStartZone) + cardStr = cardName; + else if (cardName.isEmpty()) + cardStr = tr("a card"); + else + cardStr = QString("%1").arg(sanitizeHtml(cardName)); + + if ((startName == "table") && (targetName == "table")) { + append(tr("%1 gives %2 control over %3.").arg(sanitizeHtml(player->getName())).arg(sanitizeHtml(targetZone->getPlayer()->getName())).arg(cardStr)); + return; + } QString finalStr; if (targetName == "table") @@ -214,14 +226,6 @@ void MessageLogWidget::logMoveCard(Player *player, QString cardName, CardZone *s else if (targetName == "stack") finalStr = tr("%1 plays %2%3."); - QString cardStr; - if (cardNameContainsStartZone) - cardStr = cardName; - else if (cardName.isEmpty()) - cardStr = tr("a card"); - else - cardStr = QString("%1").arg(sanitizeHtml(cardName)); - append(finalStr.arg(sanitizeHtml(player->getName())).arg(cardStr).arg(fromStr).arg(newX)); } diff --git a/cockatrice/src/phasestoolbar.cpp b/cockatrice/src/phasestoolbar.cpp index f26e6a5f..2078113f 100644 --- a/cockatrice/src/phasestoolbar.cpp +++ b/cockatrice/src/phasestoolbar.cpp @@ -2,20 +2,24 @@ #include #include #include +#include #include "phasestoolbar.h" #include "protocol_items.h" PhaseButton::PhaseButton(const QIcon &icon, QAction *_doubleClickAction) - : QPushButton(icon, QString()), active(false), doubleClickAction(_doubleClickAction), activePixmap(50, 50), inactivePixmap(50, 50) + : QPushButton(icon, QString()), active(false), activeAnimationCounter(0), doubleClickAction(_doubleClickAction), pixmap(50, 50) { setFocusPolicy(Qt::NoFocus); setFixedSize(50, 50); - updatePixmap(activePixmap, true); - updatePixmap(inactivePixmap, false); + activeAnimationTimer = new QTimer(this); + connect(activeAnimationTimer, SIGNAL(timeout()), this, SLOT(updateAnimation())); + activeAnimationTimer->setSingleShot(false); + + updatePixmap(pixmap); } -void PhaseButton::updatePixmap(QPixmap &pixmap, bool active) +void PhaseButton::updatePixmap(QPixmap &pixmap) { pixmap.fill(Qt::transparent); @@ -23,21 +27,44 @@ void PhaseButton::updatePixmap(QPixmap &pixmap, bool active) int height = pixmap.height(); int width = pixmap.width(); - if (active) - painter.setBrush(Qt::red); - painter.setPen(Qt::gray); - painter.drawRect(1, 1, width - 2, height - 2); - icon().paint(&painter, 5, 5, width - 10, height - 10); } void PhaseButton::paintEvent(QPaintEvent */*event*/) { QPainter painter(this); - if (active) - painter.drawPixmap(0, 0, size().width(), size().height(), activePixmap); - else - painter.drawPixmap(0, 0, size().width(), size().height(), inactivePixmap); + + painter.setBrush(QColor(220 * (activeAnimationCounter / 10.0), 220 * (activeAnimationCounter / 10.0), 220 * (activeAnimationCounter / 10.0))); + painter.setPen(Qt::gray); + painter.drawRect(1, 1, pixmap.width() - 2, pixmap.height() - 2); + + painter.drawPixmap(0, 0, size().width(), size().height(), pixmap); + +// painter.setBrush(QColor(220 * (activeAnimationCounter / 10.0), 220 * (activeAnimationCounter / 10.0), 220 * (activeAnimationCounter / 10.0), 255 * ((10 - activeAnimationCounter) / 15.0))); + painter.setBrush(QColor(0, 0, 0, 255 * ((10 - activeAnimationCounter) / 15.0))); + painter.setPen(Qt::gray); + painter.drawRect(1, 1, pixmap.width() - 2, pixmap.height() - 2); +} + +void PhaseButton::setActive(bool _active) +{ + if (active == _active) + return; + + active = _active; + activeAnimationTimer->start(50); +} + +void PhaseButton::updateAnimation() +{ + if (active) { + if (++activeAnimationCounter >= 10) + activeAnimationTimer->stop(); + } else { + if (--activeAnimationCounter <= 0) + activeAnimationTimer->stop(); + } + update(); } void PhaseButton::setPhaseText(const QString &_phaseText) @@ -60,6 +87,9 @@ void PhaseButton::triggerDoubleClickAction() PhasesToolbar::PhasesToolbar(QWidget *parent) : QFrame(parent) { + setBackgroundRole(QPalette::Shadow); + setAutoFillBackground(true); + QAction *aUntapAll = new QAction(this); connect(aUntapAll, SIGNAL(triggered()), this, SLOT(actUntapAll())); QAction *aDrawCard = new QAction(this); diff --git a/cockatrice/src/phasestoolbar.h b/cockatrice/src/phasestoolbar.h index 5f0acf8d..c685d50b 100644 --- a/cockatrice/src/phasestoolbar.h +++ b/cockatrice/src/phasestoolbar.h @@ -13,15 +13,19 @@ class PhaseButton : public QPushButton { private: QString phaseText; bool active; + int activeAnimationCounter; + QTimer *activeAnimationTimer; QAction *doubleClickAction; - QPixmap activePixmap, inactivePixmap; + QPixmap pixmap; - void updatePixmap(QPixmap &pixmap, bool active); + void updatePixmap(QPixmap &pixmap); +private slots: + void updateAnimation(); public: PhaseButton(const QIcon &icon, QAction *_doubleClickAction = 0); void setPhaseText(const QString &_phaseText); QString getPhaseText() const { return phaseText; } - void setActive(bool _active) { active = _active; update(); } + void setActive(bool _active); bool getActive() const { return active; } void triggerDoubleClickAction(); protected: diff --git a/cockatrice/src/pilezone.cpp b/cockatrice/src/pilezone.cpp index e3278998..1c9df8f9 100644 --- a/cockatrice/src/pilezone.cpp +++ b/cockatrice/src/pilezone.cpp @@ -48,9 +48,13 @@ void PileZone::addCardImpl(CardItem *card, int x, int /*y*/) card->setParentItem(this); } -void PileZone::handleDropEvent(int cardId, CardZone *startZone, const QPoint &/*dropPoint*/, bool /*faceDown*/) +void PileZone::handleDropEvent(const QList &dragItems, CardZone *startZone, const QPoint &/*dropPoint*/, bool /*faceDown*/) { - player->sendGameCommand(new Command_MoveCard(-1, startZone->getName(), cardId, getName(), 0, 0, false)); + QList idList; + for (int i = 0; i < dragItems.size(); ++i) + idList.append(new CardId(dragItems[i]->getId())); + + player->sendGameCommand(new Command_MoveCard(-1, startZone->getName(), idList, player->getId(), getName(), 0, 0, false)); } void PileZone::reorganizeCards() diff --git a/cockatrice/src/pilezone.h b/cockatrice/src/pilezone.h index 0b786333..0e946066 100644 --- a/cockatrice/src/pilezone.h +++ b/cockatrice/src/pilezone.h @@ -9,7 +9,7 @@ public: QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); void reorganizeCards(); - void handleDropEvent(int cardId, CardZone *startZone, const QPoint &dropPoint, bool faceDown); + void handleDropEvent(const QList &dragItems, CardZone *startZone, const QPoint &dropPoint, bool faceDown); protected: void mousePressEvent(QGraphicsSceneMouseEvent *event); void mouseMoveEvent(QGraphicsSceneMouseEvent *event); diff --git a/cockatrice/src/player.cpp b/cockatrice/src/player.cpp index c13c13bf..0d7ab7a4 100644 --- a/cockatrice/src/player.cpp +++ b/cockatrice/src/player.cpp @@ -1,7 +1,7 @@ #include "player.h" #include "cardzone.h" #include "playertarget.h" -#include "counter.h" +#include "counter_general.h" #include "arrowitem.h" #include "zoneviewzone.h" #include "zoneviewwidget.h" @@ -32,26 +32,28 @@ Player::Player(ServerInfo_User *info, int _id, bool _local, TabGame *_parent) updateBgPixmap(); playerTarget = new PlayerTarget(this); - playerTarget->setPos(QPointF(counterAreaWidth + (CARD_HEIGHT + 5 - playerTarget->boundingRect().width()) / 2.0, 5)); + qreal avatarMargin = (counterAreaWidth + CARD_HEIGHT + 15 - playerTarget->boundingRect().width()) / 2.0; + playerTarget->setPos(QPointF(avatarMargin, avatarMargin)); PileZone *deck = new PileZone(this, "deck", true, false, this); - QPointF base = QPointF(counterAreaWidth + (CARD_HEIGHT - CARD_WIDTH + 5) / 2.0, 5 + playerTarget->boundingRect().height() + 5 - (CARD_HEIGHT - CARD_WIDTH) / 2.0); + QPointF base = QPointF(counterAreaWidth + (CARD_HEIGHT - CARD_WIDTH + 15) / 2.0, 10 + playerTarget->boundingRect().height() + 5 - (CARD_HEIGHT - CARD_WIDTH) / 2.0); deck->setPos(base); qreal h = deck->boundingRect().width() + 5; + HandCounter *handCounter = new HandCounter(this); + handCounter->setPos(base + QPointF(0, h + 10)); + qreal h2 = handCounter->boundingRect().height(); + PileZone *grave = new PileZone(this, "grave", false, true, this); - grave->setPos(base + QPointF(0, h)); + grave->setPos(base + QPointF(0, h + h2 + 10)); PileZone *rfg = new PileZone(this, "rfg", false, true, this); - rfg->setPos(base + QPointF(0, 2 * h)); + rfg->setPos(base + QPointF(0, 2 * h + h2 + 10)); PileZone *sb = new PileZone(this, "sb", false, false, this); sb->setVisible(false); - HandCounter *handCounter = new HandCounter(this); - handCounter->setPos(base + QPointF(0, 3 * h + 7)); - table = new TableZone(this, this); connect(table, SIGNAL(sizeChanged()), this, SLOT(updateBoundingRect())); @@ -136,6 +138,8 @@ Player::Player(ServerInfo_User *info, int _id, bool _local, TabGame *_parent) connect(aMoveTopCardsToGrave, SIGNAL(triggered()), this, SLOT(actMoveTopCardsToGrave())); aMoveTopCardsToExile = new QAction(this); connect(aMoveTopCardsToExile, SIGNAL(triggered()), this, SLOT(actMoveTopCardsToExile())); + aMoveTopCardToBottom = new QAction(this); + connect(aMoveTopCardToBottom, SIGNAL(triggered()), this, SLOT(actMoveTopCardToBottom())); } playerMenu = new QMenu(QString()); @@ -166,6 +170,7 @@ Player::Player(ServerInfo_User *info, int _id, bool _local, TabGame *_parent) libraryMenu->addSeparator(); libraryMenu->addAction(aMoveTopCardsToGrave); libraryMenu->addAction(aMoveTopCardsToExile); + libraryMenu->addAction(aMoveTopCardToBottom); deck->setMenu(libraryMenu, aDrawCard); } else { handMenu = 0; @@ -309,7 +314,7 @@ void Player::playerListActionTriggered() void Player::rearrangeZones() { - QPointF base = QPointF(CARD_HEIGHT + counterAreaWidth + 5, 0); + QPointF base = QPointF(CARD_HEIGHT + counterAreaWidth + 15, 0); if (settingsCache->getHorizontalHand()) { if (mirrored) { @@ -367,7 +372,7 @@ void Player::updateBgPixmap() void Player::updateBoundingRect() { prepareGeometryChange(); - qreal width = CARD_HEIGHT + 5 + counterAreaWidth + stack->boundingRect().width(); + qreal width = CARD_HEIGHT + 15 + counterAreaWidth + stack->boundingRect().width(); if (settingsCache->getHorizontalHand()) { qreal handHeight = hand->isVisible() ? hand->boundingRect().height() : 0; bRect = QRectF(0, 0, width + table->boundingRect().width(), table->boundingRect().height() + handHeight); @@ -408,6 +413,7 @@ void Player::retranslateUi() aShuffle->setText(tr("&Shuffle")); aMoveTopCardsToGrave->setText(tr("Move top cards to &graveyard...")); aMoveTopCardsToExile->setText(tr("Move top cards to &exile...")); + aMoveTopCardToBottom->setText(tr("Put top card on &bottom")); handMenu->setTitle(tr("&Hand")); mRevealHand->setTitle(tr("&Reveal to")); @@ -422,7 +428,7 @@ void Player::retranslateUi() aCreateAnotherToken->setText(tr("C&reate another token")); sayMenu->setTitle(tr("S&ay")); - QMapIterator counterIterator(counters); + QMapIterator counterIterator(counters); while (counterIterator.hasNext()) counterIterator.next().value()->retranslateUi(); @@ -453,7 +459,7 @@ void Player::setShortcutsActive() aCreateToken->setShortcut(tr("Ctrl+T")); aCreateAnotherToken->setShortcut(tr("Ctrl+G")); - QMapIterator counterIterator(counters); + QMapIterator counterIterator(counters); while (counterIterator.hasNext()) counterIterator.next().value()->setShortcutsActive(); } @@ -474,7 +480,7 @@ void Player::setShortcutsInactive() aCreateToken->setShortcut(QKeySequence()); aCreateAnotherToken->setShortcut(QKeySequence()); - QMapIterator counterIterator(counters); + QMapIterator counterIterator(counters); while (counterIterator.hasNext()) counterIterator.next().value()->setShortcutsInactive(); } @@ -557,9 +563,10 @@ void Player::actMoveTopCardsToGrave() const int maxCards = zones.value("deck")->getCards().size(); if (number > maxCards) number = maxCards; + QList idList; for (int i = 0; i < number; ++i) - commandList.append(new Command_MoveCard(-1, "deck", 0, "grave", 0, 0, false)); - sendCommandContainer(new CommandContainer(commandList)); + idList.append(new CardId(i)); + sendGameCommand(new Command_MoveCard(-1, "deck", idList, getId(), "grave", 0, 0, false)); } void Player::actMoveTopCardsToExile() @@ -572,9 +579,15 @@ void Player::actMoveTopCardsToExile() const int maxCards = zones.value("deck")->getCards().size(); if (number > maxCards) number = maxCards; + QList idList; for (int i = 0; i < number; ++i) - commandList.append(new Command_MoveCard(-1, "deck", 0, "rfg", 0, 0, false)); - sendCommandContainer(new CommandContainer(commandList)); + idList.append(new CardId(i)); + sendGameCommand(new Command_MoveCard(-1, "deck", idList, getId(), "rfg", 0, 0, false)); +} + +void Player::actMoveTopCardToBottom() +{ + sendGameCommand(new Command_MoveCard(-1, "deck", QList() << new CardId(0), getId(), "deck", -1, 0, false)); } void Player::actUntapAll() @@ -743,7 +756,7 @@ void Player::eventCreateCounters(Event_CreateCounters *event) void Player::eventSetCounter(Event_SetCounter *event) { - Counter *c = counters.value(event->getCounterId(), 0); + AbstractCounter *c = counters.value(event->getCounterId(), 0); if (!c) return; int oldValue = c->getValue(); @@ -781,7 +794,10 @@ void Player::eventStopDumpZone(Event_StopDumpZone *event) void Player::eventMoveCard(Event_MoveCard *event) { CardZone *startZone = zones.value(event->getStartZone(), 0); - CardZone *targetZone = zones.value(event->getTargetZone(), 0); + Player *targetPlayer = static_cast(parent())->getPlayers().value(event->getTargetPlayerId()); + if (!targetPlayer) + return; + CardZone *targetZone = targetPlayer->getZones().value(event->getTargetZone(), 0); if (!startZone || !targetZone) return; @@ -798,9 +814,12 @@ void Player::eventMoveCard(Event_MoveCard *event) return; card->setName(event->getCardName()); - if (card->getAttachedTo() && (startZone != targetZone)) + if (card->getAttachedTo() && (startZone != targetZone)) { + CardItem *parentCard = card->getAttachedTo(); card->setAttachedTo(0); - + parentCard->getZone()->reorganizeCards(); + } + card->deleteDragItem(); card->setId(event->getNewCardId()); @@ -808,6 +827,13 @@ void Player::eventMoveCard(Event_MoveCard *event) if (startZone != targetZone) { card->setBeingPointedAt(false); card->setHovered(false); + + const QList &attachedCards = card->getAttachedCards(); + for (int i = 0; i < attachedCards.size(); ++i) + attachedCards[i]->setParentItem(targetZone); + + if (startZone->getPlayer() != targetZone->getPlayer()) + card->setOwner(targetZone->getPlayer()); } // The log event has to be sent before the card is added to the target zone @@ -989,7 +1015,7 @@ QRectF Player::boundingRect() const void Player::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) { - int totalWidth = CARD_HEIGHT + counterAreaWidth + 5; + int totalWidth = CARD_HEIGHT + counterAreaWidth + 15; if (bgPixmap.isNull()) painter->fillRect(QRectF(0, 0, totalWidth, boundingRect().height()), QColor(200, 200, 200)); else @@ -1064,10 +1090,10 @@ void Player::playCard(CardItem *c, bool faceDown, bool tapped) { CardInfo *ci = c->getInfo(); if (ci->getTableRow() == 3) - stack->handleDropEvent(c->getId(), c->getZone(), QPoint(), false); + sendGameCommand(new Command_MoveCard(-1, c->getZone()->getName(), QList() << new CardId(c->getId()), getId(), "stack", 0, 0, false)); else { QPoint gridPoint = QPoint(-1, 2 - ci->getTableRow()); - table->handleDropEventByGrid(c->getId(), c->getZone(), gridPoint, faceDown, tapped); + sendGameCommand(new Command_MoveCard(-1, c->getZone()->getName(), QList() << new CardId(c->getId()), getId(), "table", gridPoint.x(), gridPoint.y(), faceDown, tapped)); } } @@ -1089,14 +1115,22 @@ void Player::addZone(CardZone *z) zones.insert(z->getName(), z); } -Counter *Player::addCounter(ServerInfo_Counter *counter) +AbstractCounter *Player::addCounter(ServerInfo_Counter *counter) { return addCounter(counter->getId(), counter->getName(), counter->getColor().getQColor(), counter->getRadius(), counter->getCount()); } -Counter *Player::addCounter(int counterId, const QString &name, QColor color, int radius, int value) +AbstractCounter *Player::addCounter(int counterId, const QString &name, QColor color, int radius, int value) { - Counter *c = new Counter(this, counterId, name, color, radius, value, this); + qDebug() << "addCounter:" << getName() << counterId << name; + if (counters.contains(counterId)) + return 0; + + AbstractCounter *c; + if (name == "life") + c = playerTarget->addCounter(counterId, name, value); + else + c = new GeneralCounter(this, counterId, name, color, radius, value, this); counters.insert(counterId, c); if (countersMenu) countersMenu->addMenu(c->getMenu()); @@ -1108,9 +1142,11 @@ Counter *Player::addCounter(int counterId, const QString &name, QColor color, in void Player::delCounter(int counterId) { - Counter *c = counters.value(counterId, 0); + AbstractCounter *c = counters.value(counterId, 0); if (!c) return; + if (c->getName() == "life") + playerTarget->delCounter(); counters.remove(counterId); c->delCounter(); rearrangeCounters(); @@ -1118,10 +1154,11 @@ void Player::delCounter(int counterId) void Player::clearCounters() { - QMapIterator counterIterator(counters); + QMapIterator counterIterator(counters); while (counterIterator.hasNext()) counterIterator.next().value()->delCounter(); counters.clear(); + playerTarget->delCounter(); } ArrowItem *Player::addArrow(ServerInfo_Arrow *arrow) @@ -1182,15 +1219,16 @@ void Player::clearArrows() void Player::rearrangeCounters() { - qreal marginTop = 15; - qreal marginBottom = 15; + qreal marginTop = 80; + qreal marginBottom = 10; // Determine total height of bounding rectangles qreal totalHeight = 0; - QMapIterator counterIterator(counters); + QMapIterator counterIterator(counters); while (counterIterator.hasNext()) { counterIterator.next(); - totalHeight += counterIterator.value()->boundingRect().height(); + if (counterIterator.value()->getShownInCounterArea()) + totalHeight += counterIterator.value()->boundingRect().height(); } // Determine free space between objects @@ -1204,8 +1242,11 @@ void Player::rearrangeCounters() // Place objects for (counterIterator.toFront(); counterIterator.hasNext(); ) { - Counter *c = counterIterator.next().value(); + AbstractCounter *c = counterIterator.next().value(); + if (!c->getShownInCounterArea()) + continue; + QRectF br = c->boundingRect(); c->setPos((counterAreaWidth - br.width()) / 2, y); y += br.height() + padding; @@ -1234,46 +1275,57 @@ bool Player::clearCardsToDelete() return true; } -void Player::cardMenuAction() +void Player::cardMenuAction(QAction *a) { - QAction *a = static_cast(sender()); QList sel = scene()->selectedItems(); + QList cardList; + while (!sel.isEmpty()) + cardList.append(qgraphicsitem_cast(sel.takeFirst())); + QList commandList; - while (!sel.isEmpty()) { - unsigned int i = (unsigned int) (((double) sel.size()) * qrand() / (RAND_MAX + 1.0)); - CardItem *card = qgraphicsitem_cast(sel.takeAt(i)); - - switch (a->data().toInt()) { - case 0: - if (!card->getTapped()) - commandList.append(new Command_SetCardAttr(-1, card->getZone()->getName(), card->getId(), "tapped", "1")); - break; - case 1: - if (card->getTapped()) - commandList.append(new Command_SetCardAttr(-1, card->getZone()->getName(), card->getId(), "tapped", "0")); - break; - case 2: - commandList.append(new Command_SetCardAttr(-1, card->getZone()->getName(), card->getId(), "doesnt_untap", QString::number(!card->getDoesntUntap()))); - break; - case 3: { - QString zone = card->getZone()->getName(); - commandList.append(new Command_FlipCard(-1, zone, card->getId(), !card->getFaceDown())); - break; + if (a->data().toInt() <= 4) + for (int i = 0; i < cardList.size(); ++i) { + CardItem *card = cardList[i]; + switch (a->data().toInt()) { + case 0: + if (!card->getTapped()) + commandList.append(new Command_SetCardAttr(-1, card->getZone()->getName(), card->getId(), "tapped", "1")); + break; + case 1: + if (card->getTapped()) + commandList.append(new Command_SetCardAttr(-1, card->getZone()->getName(), card->getId(), "tapped", "0")); + break; + case 2: + commandList.append(new Command_SetCardAttr(-1, card->getZone()->getName(), card->getId(), "doesnt_untap", QString::number(!card->getDoesntUntap()))); + break; + case 3: { + QString zone = card->getZone()->getName(); + commandList.append(new Command_FlipCard(-1, zone, card->getId(), !card->getFaceDown())); + break; + } + case 4: + commandList.append(new Command_CreateToken(-1, card->getZone()->getName(), card->getName(), card->getColor(), card->getPT(), card->getAnnotation(), true, -1, card->getGridPoint().y())); + break; } - case 4: - commandList.append(new Command_CreateToken(-1, card->getZone()->getName(), card->getName(), card->getColor(), card->getPT(), card->getAnnotation(), card->getDestroyOnZoneChange(), -1, card->getGridPoint().y())); - break; + } + else { + QList idList; + for (int i = 0; i < cardList.size(); ++i) + idList.append(new CardId(cardList[i]->getId())); + QString startZone = cardList[0]->getZone()->getName(); + + switch (a->data().toInt()) { case 5: - commandList.append(new Command_MoveCard(-1, card->getZone()->getName(), card->getId(), "deck", 0, 0, false)); + commandList.append(new Command_MoveCard(-1, startZone, idList, getId(), "deck", 0, 0, false)); break; case 6: - commandList.append(new Command_MoveCard(-1, card->getZone()->getName(), card->getId(), "deck", -1, 0, false)); + commandList.append(new Command_MoveCard(-1, startZone, idList, getId(), "deck", -1, 0, false)); break; case 7: - commandList.append(new Command_MoveCard(-1, card->getZone()->getName(), card->getId(), "grave", 0, 0, false)); + commandList.append(new Command_MoveCard(-1, startZone, idList, getId(), "grave", 0, 0, false)); break; case 8: - commandList.append(new Command_MoveCard(-1, card->getZone()->getName(), card->getId(), "rfg", 0, 0, false)); + commandList.append(new Command_MoveCard(-1, startZone, idList, getId(), "rfg", 0, 0, false)); break; default: ; } @@ -1281,7 +1333,7 @@ void Player::cardMenuAction() sendCommandContainer(new CommandContainer(commandList)); } -void Player::actSetPT() +void Player::actSetPT(QAction * /*a*/) { QString oldPT; QListIterator i(scene()->selectedItems()); @@ -1306,7 +1358,7 @@ void Player::actSetPT() } } -void Player::actSetAnnotation() +void Player::actSetAnnotation(QAction * /*a*/) { QString oldAnnotation; QListIterator i(scene()->selectedItems()); @@ -1332,24 +1384,22 @@ void Player::actSetAnnotation() } } -void Player::actAttach() +void Player::actAttach(QAction *a) { - CardItem *card = static_cast(sender()->parent()); + CardItem *card = static_cast(a->parent()); ArrowAttachItem *arrow = new ArrowAttachItem(card); scene()->addItem(arrow); arrow->grabMouse(); } -void Player::actUnattach() +void Player::actUnattach(QAction *a) { - CardItem *card = static_cast(sender()->parent()); + CardItem *card = static_cast(a->parent()); sendGameCommand(new Command_AttachCard(-1, card->getZone()->getName(), card->getId(), -1, QString(), -1)); } -void Player::actCardCounterTrigger() +void Player::actCardCounterTrigger(QAction *a) { - QAction *a = static_cast(sender()); - int counterId = a->data().toInt() / 1000; int action = a->data().toInt() % 1000; switch (action) { @@ -1412,7 +1462,7 @@ QString Player::getName() const qreal Player::getMinimumWidth() const { - qreal result = table->getMinimumWidth() + CARD_HEIGHT + 5 + counterAreaWidth + stack->boundingRect().width(); + qreal result = table->getMinimumWidth() + CARD_HEIGHT + 15 + counterAreaWidth + stack->boundingRect().width(); if (!settingsCache->getHorizontalHand()) result += hand->boundingRect().width(); return result; @@ -1431,7 +1481,7 @@ void Player::processSceneSizeChange(const QSizeF &newSize) // This will need to be changed if player areas are displayed side by side (e.g. 2x2 for a 4-player game) qreal fullPlayerWidth = newSize.width(); - qreal tableWidth = fullPlayerWidth - CARD_HEIGHT - 5 - counterAreaWidth - stack->boundingRect().width(); + qreal tableWidth = fullPlayerWidth - CARD_HEIGHT - 15 - counterAreaWidth - stack->boundingRect().width(); if (!settingsCache->getHorizontalHand()) tableWidth -= hand->boundingRect().width(); diff --git a/cockatrice/src/player.h b/cockatrice/src/player.h index ee91934f..49ccab69 100644 --- a/cockatrice/src/player.h +++ b/cockatrice/src/player.h @@ -11,7 +11,7 @@ class QMenu; class QAction; class ZoneViewZone; class TabGame; -class Counter; +class AbstractCounter; class ArrowItem; class CardZone; class StackZone; @@ -84,6 +84,7 @@ public slots: void actMulligan(); void actMoveTopCardsToGrave(); void actMoveTopCardsToExile(); + void actMoveTopCardToBottom(); void actViewLibrary(); void actViewTopCards(); @@ -93,12 +94,12 @@ public slots: void actSayMessage(); - void actAttach(); - void actUnattach(); - void actSetPT(); - void actSetAnnotation(); - void cardMenuAction(); - void actCardCounterTrigger(); + void actAttach(QAction *action); + void actUnattach(QAction *action); + void actSetPT(QAction *action); + void actSetAnnotation(QAction *action); + void cardMenuAction(QAction *action); + void actCardCounterTrigger(QAction *action); private slots: void addPlayer(Player *player); @@ -116,7 +117,7 @@ private: QAction *aMoveHandToTopLibrary, *aMoveHandToBottomLibrary, *aMoveHandToGrave, *aMoveHandToRfg, *aMoveGraveToTopLibrary, *aMoveGraveToBottomLibrary, *aMoveGraveToHand, *aMoveGraveToRfg, *aMoveRfgToTopLibrary, *aMoveRfgToBottomLibrary, *aMoveRfgToHand, *aMoveRfgToGrave, - *aViewLibrary, *aViewTopCards, *aMoveTopCardsToGrave, *aMoveTopCardsToExile, + *aViewLibrary, *aViewTopCards, *aMoveTopCardsToGrave, *aMoveTopCardsToExile, *aMoveTopCardToBottom, *aViewGraveyard, *aViewRfg, *aViewSideboard, *aDrawCard, *aDrawCards, *aMulligan, *aShuffle, *aUntapAll, *aRollDie, *aCreateToken, *aCreateAnotherToken, @@ -147,7 +148,7 @@ private: QPixmap bgPixmap; QRectF bRect; - QMap counters; + QMap counters; QMap arrows; void rearrangeCounters(); @@ -173,7 +174,7 @@ private: void eventDrawCards(Event_DrawCards *event); void eventRevealCards(Event_RevealCards *event); public: - static const int counterAreaWidth = 65; + static const int counterAreaWidth = 55; enum { Type = typeOther }; int type() const { return Type; } @@ -185,8 +186,8 @@ public: void deleteCard(CardItem *c); void addZone(CardZone *z); - Counter *addCounter(ServerInfo_Counter *counter); - Counter *addCounter(int counterId, const QString &name, QColor color, int radius, int value); + AbstractCounter *addCounter(ServerInfo_Counter *counter); + AbstractCounter *addCounter(int counterId, const QString &name, QColor color, int radius, int value); void delCounter(int counterId); void clearCounters(); diff --git a/cockatrice/src/playertarget.cpp b/cockatrice/src/playertarget.cpp index 1df53388..e4f5aa58 100644 --- a/cockatrice/src/playertarget.cpp +++ b/cockatrice/src/playertarget.cpp @@ -5,9 +5,49 @@ #include #include #include +#include + +PlayerCounter::PlayerCounter(Player *_player, int _id, const QString &_name, int _value, QGraphicsItem *parent) + : AbstractCounter(_player, _id, _name, false, _value, parent) +{ +} + +QRectF PlayerCounter::boundingRect() const +{ + return QRectF(0, 0, 50, 30); +} + +void PlayerCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) +{ + const int radius = 8; + const qreal border = 1; + QPainterPath path(QPointF(50 - border / 2, border / 2)); + path.lineTo(radius, border / 2); + path.arcTo(border / 2, border / 2, 2 * radius, 2 * radius, 90, 90); + path.lineTo(border / 2, 30 - border / 2); + path.lineTo(50 - border / 2, 30 - border / 2); + path.closeSubpath(); + + QPen pen(QColor(100, 100, 100)); + pen.setWidth(border); + painter->setPen(pen); + painter->setBrush(hovered ? QColor(50, 50, 50, 160) : QColor(0, 0, 0, 160)); + + painter->drawPath(path); + + QRectF translatedRect = painter->combinedTransform().mapRect(boundingRect()); + QSize translatedSize = translatedRect.size().toSize(); + painter->resetTransform(); + QFont font("Serif"); + font.setWeight(QFont::Bold); + font.setPixelSize(qMax((int) round(translatedSize.height() / 1.3), 9)); + painter->setFont(font); + painter->setPen(Qt::white); + painter->drawText(translatedRect, Qt::AlignCenter, QString::number(value)); +} PlayerTarget::PlayerTarget(Player *_owner) - : ArrowTarget(_owner, _owner) + : ArrowTarget(_owner, _owner), playerCounter(0) { setCacheMode(DeviceCoordinateCache); @@ -17,15 +57,17 @@ PlayerTarget::PlayerTarget(Player *_owner) QRectF PlayerTarget::boundingRect() const { - return QRectF(0, 0, 100, 64); + return QRectF(0, 0, 160, 64); } void PlayerTarget::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) { ServerInfo_User *info = owner->getUserInfo(); - painter->save(); - QRectF translatedRect = painter->combinedTransform().mapRect(boundingRect()); + const qreal border = 2; + + QRectF avatarBoundingRect = boundingRect().adjusted(border, border, -border, -border); + QRectF translatedRect = painter->combinedTransform().mapRect(avatarBoundingRect); QSize translatedSize = translatedRect.size().toSize(); QPixmap cachedPixmap; const QString cacheKey = "avatar" + QString::number(translatedSize.width()) + "_" + QString::number(info->getUserLevel()) + "_" + QString::number(fullPixmap.cacheKey()); @@ -34,16 +76,35 @@ void PlayerTarget::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*o #else if (!QPixmapCache::find(cacheKey, cachedPixmap)) { #endif + cachedPixmap = QPixmap(translatedSize.width(), translatedSize.height()); + + QPainter tempPainter(&cachedPixmap); + QRadialGradient grad(translatedRect.center(), sqrt(translatedSize.width() * translatedSize.width() + translatedSize.height() * translatedSize.height()) / 2); + grad.setColorAt(1, Qt::black); + grad.setColorAt(0, QColor(180, 180, 180)); + tempPainter.fillRect(QRectF(0, 0, translatedSize.width(), translatedSize.height()), grad); + + QPixmap tempPixmap; if (fullPixmap.isNull()) - cachedPixmap = UserLevelPixmapGenerator::generatePixmap(translatedSize.height(), info->getUserLevel()); + tempPixmap = UserLevelPixmapGenerator::generatePixmap(translatedSize.height(), info->getUserLevel()); else - cachedPixmap = fullPixmap.scaled(translatedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); + tempPixmap = fullPixmap.scaled(translatedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); + + tempPainter.drawPixmap((translatedSize.width() - tempPixmap.width()) / 2, (translatedSize.height() - tempPixmap.height()) / 2, tempPixmap); QPixmapCache::insert(cacheKey, cachedPixmap); } - painter->resetTransform(); + painter->save(); + painter->resetTransform(); painter->translate((translatedSize.width() - cachedPixmap.width()) / 2.0, 0); - painter->drawPixmap(cachedPixmap.rect(), cachedPixmap, cachedPixmap.rect()); + painter->drawPixmap(translatedRect, cachedPixmap, cachedPixmap.rect()); + painter->restore(); + + QRectF nameRect = QRectF(0, boundingRect().height() - 20, 110, 20); + painter->fillRect(nameRect, QColor(0, 0, 0, 160)); + QRectF translatedNameRect = painter->combinedTransform().mapRect(nameRect); + + painter->save(); painter->resetTransform(); QString name = info->getName(); @@ -51,14 +112,35 @@ void PlayerTarget::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*o name = name.mid(0, 10) + "..."; QFont font; - font.setPixelSize(qMax(translatedSize.height() / 4, 9)); + font.setPixelSize(qMax((int) round(translatedNameRect.height() / 1.5), 9)); painter->setFont(font); - painter->setBackgroundMode(Qt::OpaqueMode); - painter->setBackground(QColor(0, 0, 0, 100)); painter->setPen(Qt::white); - painter->drawText(translatedRect, Qt::AlignHCenter | Qt::AlignTop | Qt::TextWrapAnywhere, name); + painter->drawText(translatedNameRect, Qt::AlignVCenter | Qt::AlignLeft, " " + name); painter->restore(); + QPen pen(QColor(100, 100, 100)); + pen.setWidth(border); + pen.setJoinStyle(Qt::RoundJoin); + painter->setPen(pen); + painter->drawRect(boundingRect().adjusted(border / 2, border / 2, -border / 2, -border / 2)); + if (getBeingPointedAt()) painter->fillRect(boundingRect(), QBrush(QColor(255, 0, 0, 100))); } + +AbstractCounter *PlayerTarget::addCounter(int _counterId, const QString &_name, int _value) +{ + if (playerCounter) + return 0; + + playerCounter = new PlayerCounter(owner, _counterId, _name, _value, this); + playerCounter->setPos(boundingRect().width() - playerCounter->boundingRect().width(), boundingRect().height() - playerCounter->boundingRect().height()); + connect(playerCounter, SIGNAL(destroyed()), this, SLOT(delCounter())); + + return playerCounter; +} + +void PlayerTarget::delCounter() +{ + playerCounter = 0; +} \ No newline at end of file diff --git a/cockatrice/src/playertarget.h b/cockatrice/src/playertarget.h index 95dfd4b7..5957b517 100644 --- a/cockatrice/src/playertarget.h +++ b/cockatrice/src/playertarget.h @@ -2,14 +2,27 @@ #define PLAYERTARGET_H #include "arrowtarget.h" +#include "abstractcounter.h" #include #include class Player; +class PlayerCounter : public AbstractCounter { + Q_OBJECT +public: + PlayerCounter(Player *_player, int _id, const QString &_name, int _value, QGraphicsItem *parent = 0); + QRectF boundingRect() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); +}; + class PlayerTarget : public ArrowTarget { + Q_OBJECT private: QPixmap fullPixmap; + PlayerCounter *playerCounter; +public slots: + void delCounter(); public: enum { Type = typePlayerTarget }; int type() const { return Type; } @@ -17,6 +30,8 @@ public: PlayerTarget(Player *parent = 0); QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + + AbstractCounter *addCounter(int _counterId, const QString &_name, int _value); }; #endif \ No newline at end of file diff --git a/cockatrice/src/remoteclient.cpp b/cockatrice/src/remoteclient.cpp index 4e3f9724..e378fb8b 100644 --- a/cockatrice/src/remoteclient.cpp +++ b/cockatrice/src/remoteclient.cpp @@ -21,7 +21,6 @@ RemoteClient::RemoteClient(QObject *parent) xmlReader = new QXmlStreamReader; xmlWriter = new QXmlStreamWriter; - xmlWriter->setAutoFormatting(true); xmlWriter->setDevice(socket); } @@ -42,12 +41,18 @@ void RemoteClient::slotConnected() setStatus(StatusAwaitingWelcome); } -void RemoteClient::loginResponse(ResponseCode response) +void RemoteClient::loginResponse(ProtocolResponse *response) { - if (response == RespOk) + if (response->getResponseCode() == RespOk) { + Response_Login *resp = qobject_cast(response); + if (!resp) { + disconnectFromServer(); + return; + } setStatus(StatusLoggedIn); - else { - emit serverError(response); + emit userInfoChanged(resp->getUserInfo()); + } else { + emit serverError(response->getResponseCode()); setStatus(StatusDisconnecting); } } @@ -78,7 +83,7 @@ void RemoteClient::readData() setStatus(StatusLoggingIn); Command_Login *cmdLogin = new Command_Login(userName, password); - connect(cmdLogin, SIGNAL(finished(ResponseCode)), this, SLOT(loginResponse(ResponseCode))); + connect(cmdLogin, SIGNAL(finished(ProtocolResponse *)), this, SLOT(loginResponse(ProtocolResponse *))); sendCommand(cmdLogin); } } diff --git a/cockatrice/src/remoteclient.h b/cockatrice/src/remoteclient.h index 10d7c417..30313fbb 100644 --- a/cockatrice/src/remoteclient.h +++ b/cockatrice/src/remoteclient.h @@ -2,7 +2,6 @@ #define REMOTECLIENT_H #include -#include "protocol_datastructures.h" #include "abstractclient.h" class QTimer; @@ -22,7 +21,7 @@ private slots: void readData(); void slotSocketError(QAbstractSocket::SocketError error); void ping(); - void loginResponse(ResponseCode response); + void loginResponse(ProtocolResponse *response); private: static const int maxTimeout = 10; diff --git a/cockatrice/src/selectzone.cpp b/cockatrice/src/selectzone.cpp new file mode 100644 index 00000000..30156df6 --- /dev/null +++ b/cockatrice/src/selectzone.cpp @@ -0,0 +1,51 @@ +#include +#include "selectzone.h" +#include "gamescene.h" + +SelectZone::SelectZone(Player *_player, const QString &_name, bool _hasCardAttr, bool _isShufflable, bool _contentsKnown, QGraphicsItem *parent, bool isView) + : CardZone(_player, _name, _hasCardAttr, _isShufflable, _contentsKnown, parent, isView) +{ +} + +void SelectZone::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + if (event->buttons().testFlag(Qt::LeftButton)) { + QPointF pos = event->pos(); + if (pos.x() < 0) + pos.setX(0); + QRectF br = boundingRect(); + if (pos.x() > br.width()) + pos.setX(br.width()); + if (pos.y() < 0) + pos.setY(0); + if (pos.y() > br.height()) + pos.setY(br.height()); + + QRectF selectionRect = QRectF(selectionOrigin, pos).normalized(); + for (int i = 0; i < cards.size(); ++i) + cards[i]->setSelected(selectionRect.intersects(cards[i]->mapRectToParent(cards[i]->boundingRect()))); + + static_cast(scene())->resizeRubberBand(scenePos() + pos); + event->accept(); + } +} + +void SelectZone::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + scene()->clearSelection(); + + selectionOrigin = event->pos(); + static_cast(scene())->startRubberBand(event->scenePos()); + event->accept(); + } else + CardZone::mousePressEvent(event); +} + +void SelectZone::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + selectionOrigin = QPoint(); + static_cast(scene())->stopRubberBand(); + event->accept(); +} + diff --git a/cockatrice/src/selectzone.h b/cockatrice/src/selectzone.h new file mode 100644 index 00000000..23e82d1c --- /dev/null +++ b/cockatrice/src/selectzone.h @@ -0,0 +1,18 @@ +#ifndef SELECTZONE_H +#define SELECTZONE_H + +#include "cardzone.h" + +class SelectZone : public CardZone { + Q_OBJECT +private: + QPointF selectionOrigin; +protected: + void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); +public: + SelectZone(Player *_player, const QString &_name, bool _hasCardAttr, bool _isShufflable, bool _contentsKnown, QGraphicsItem *parent = 0, bool isView = false); +}; + +#endif diff --git a/cockatrice/src/settingscache.cpp b/cockatrice/src/settingscache.cpp index 3023d911..0ac6a94b 100644 --- a/cockatrice/src/settingscache.cpp +++ b/cockatrice/src/settingscache.cpp @@ -21,7 +21,6 @@ SettingsCache::SettingsCache() doubleClickToPlay = settings->value("interface/doubleclicktoplay", true).toBool(); cardInfoMinimized = settings->value("interface/cardinfominimized", false).toBool(); horizontalHand = settings->value("hand/horizontal", true).toBool(); - economicalGrid = settings->value("table/economic", false).toBool(); invertVerticalCoordinate = settings->value("table/invert_vertical", false).toBool(); tapAnimation = settings->value("cards/tapanimation", true).toBool(); @@ -117,13 +116,6 @@ void SettingsCache::setHorizontalHand(int _horizontalHand) emit horizontalHandChanged(); } -void SettingsCache::setEconomicalGrid(int _economicalGrid) -{ - economicalGrid = _economicalGrid; - settings->setValue("table/economic", economicalGrid); - emit economicalGridChanged(); -} - void SettingsCache::setInvertVerticalCoordinate(int _invertVerticalCoordinate) { invertVerticalCoordinate = _invertVerticalCoordinate; diff --git a/cockatrice/src/settingscache.h b/cockatrice/src/settingscache.h index 607c9187..196d9bab 100644 --- a/cockatrice/src/settingscache.h +++ b/cockatrice/src/settingscache.h @@ -18,7 +18,6 @@ signals: void cardBackPicturePathChanged(); void picDownloadChanged(); void horizontalHandChanged(); - void economicalGridChanged(); void invertVerticalCoordinateChanged(); private: QSettings *settings; @@ -30,7 +29,6 @@ private: bool doubleClickToPlay; bool cardInfoMinimized; bool horizontalHand; - bool economicalGrid; bool invertVerticalCoordinate; bool tapAnimation; bool zoneViewSortByName, zoneViewSortByType; @@ -49,7 +47,6 @@ public: bool getDoubleClickToPlay() const { return doubleClickToPlay; } bool getCardInfoMinimized() const { return cardInfoMinimized; } bool getHorizontalHand() const { return horizontalHand; } - bool getEconomicalGrid() const { return economicalGrid; } bool getInvertVerticalCoordinate() const { return invertVerticalCoordinate; } bool getTapAnimation() const { return tapAnimation; } bool getZoneViewSortByName() const { return zoneViewSortByName; } @@ -68,7 +65,6 @@ public slots: void setDoubleClickToPlay(int _doubleClickToPlay); void setCardInfoMinimized(bool _cardInfoMinimized); void setHorizontalHand(int _horizontalHand); - void setEconomicalGrid(int _economicalGrid); void setInvertVerticalCoordinate(int _invertVerticalCoordinate); void setTapAnimation(int _tapAnimation); void setZoneViewSortByName(int _zoneViewSortByName); diff --git a/cockatrice/src/stackzone.cpp b/cockatrice/src/stackzone.cpp index b164db1f..2a2cc4cb 100644 --- a/cockatrice/src/stackzone.cpp +++ b/cockatrice/src/stackzone.cpp @@ -5,9 +5,10 @@ #include "settingscache.h" #include "player.h" #include "protocol_items.h" +#include "carddragitem.h" StackZone::StackZone(Player *_p, int _zoneHeight, QGraphicsItem *parent) - : CardZone(_p, "stack", false, false, true, parent), zoneHeight(_zoneHeight) + : SelectZone(_p, "stack", false, false, true, parent), zoneHeight(_zoneHeight) { connect(settingsCache, SIGNAL(stackBgPathChanged()), this, SLOT(updateBgPixmap())); updateBgPixmap(); @@ -51,11 +52,16 @@ void StackZone::paint(QPainter *painter, const QStyleOptionGraphicsItem */*optio painter->fillRect(boundingRect(), QBrush(bgPixmap)); } -void StackZone::handleDropEvent(int cardId, CardZone *startZone, const QPoint &/*dropPoint*/, bool /*faceDown*/) +void StackZone::handleDropEvent(const QList &dragItems, CardZone *startZone, const QPoint &/*dropPoint*/, bool /*faceDown*/) { if (startZone == this) return; - player->sendGameCommand(new Command_MoveCard(-1, startZone->getName(), cardId, getName(), 0, 0, false)); + + QList idList; + for (int i = 0; i < dragItems.size(); ++i) + idList.append(new CardId(dragItems[i]->getId())); + + player->sendGameCommand(new Command_MoveCard(-1, startZone->getName(), idList, player->getId(), getName(), 0, 0, false)); } void StackZone::reorganizeCards() diff --git a/cockatrice/src/stackzone.h b/cockatrice/src/stackzone.h index 7717a114..d03f151a 100644 --- a/cockatrice/src/stackzone.h +++ b/cockatrice/src/stackzone.h @@ -1,9 +1,9 @@ #ifndef STACKZONE_H #define STACKZONE_H -#include "cardzone.h" +#include "selectzone.h" -class StackZone : public CardZone { +class StackZone : public SelectZone { Q_OBJECT private: qreal zoneHeight; @@ -12,7 +12,7 @@ private slots: void updateBgPixmap(); public: StackZone(Player *_p, int _zoneHeight, QGraphicsItem *parent = 0); - void handleDropEvent(int cardId, CardZone *startZone, const QPoint &dropPoint, bool faceDown); + void handleDropEvent(const QList &dragItems, CardZone *startZone, const QPoint &dropPoint, bool faceDown); QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); void reorganizeCards(); diff --git a/cockatrice/src/tab_admin.cpp b/cockatrice/src/tab_admin.cpp new file mode 100644 index 00000000..3c520077 --- /dev/null +++ b/cockatrice/src/tab_admin.cpp @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include "tab_admin.h" +#include "abstractclient.h" +#include "protocol_items.h" + +TabAdmin::TabAdmin(AbstractClient *_client, QWidget *parent) + : Tab(parent), client(_client) +{ + updateServerMessageButton = new QPushButton; + connect(updateServerMessageButton, SIGNAL(clicked()), this, SLOT(actUpdateServerMessage())); + + QVBoxLayout *vbox = new QVBoxLayout; + vbox->addWidget(updateServerMessageButton); + vbox->addStretch(); + + adminGroupBox = new QGroupBox; + adminGroupBox->setLayout(vbox); + adminGroupBox->setEnabled(false); + + unlockButton = new QPushButton; + connect(unlockButton, SIGNAL(clicked()), this, SLOT(actUnlock())); + lockButton = new QPushButton; + lockButton->setEnabled(false); + connect(lockButton, SIGNAL(clicked()), this, SLOT(actLock())); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(adminGroupBox); + mainLayout->addWidget(unlockButton); + mainLayout->addWidget(lockButton); + + retranslateUi(); + setLayout(mainLayout); +} + +void TabAdmin::retranslateUi() +{ + updateServerMessageButton->setText(tr("Update server &message")); + adminGroupBox->setTitle(tr("Server administration functions")); + + unlockButton->setText(tr("&Unlock functions")); + lockButton->setText(tr("&Lock functions")); +} + +void TabAdmin::actUpdateServerMessage() +{ + client->sendCommand(new Command_UpdateServerMessage()); +} + +void TabAdmin::actUnlock() +{ + if (QMessageBox::question(this, tr("Unlock administration functions"), tr("Do you really want to unlock the administration functions?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + adminGroupBox->setEnabled(true); + lockButton->setEnabled(true); + unlockButton->setEnabled(false); + } +} + +void TabAdmin::actLock() +{ + adminGroupBox->setEnabled(false); + lockButton->setEnabled(false); + unlockButton->setEnabled(true); +} \ No newline at end of file diff --git a/cockatrice/src/tab_admin.h b/cockatrice/src/tab_admin.h new file mode 100644 index 00000000..f3d9b860 --- /dev/null +++ b/cockatrice/src/tab_admin.h @@ -0,0 +1,29 @@ +#ifndef TAB_ADMIN_H +#define TAB_ADMIN_H + +#include "tab.h" + +class AbstractClient; + +class QGroupBox; +class QPushButton; + +class TabAdmin : public Tab { + Q_OBJECT +private: + AbstractClient *client; + QPushButton *updateServerMessageButton; + QGroupBox *adminGroupBox; + QPushButton *unlockButton, *lockButton; +private slots: + void actUpdateServerMessage(); + + void actUnlock(); + void actLock(); +public: + TabAdmin(AbstractClient *_client, QWidget *parent = 0); + void retranslateUi(); + QString getTabText() const { return tr("Administration"); } +}; + +#endif diff --git a/cockatrice/src/tab_chatchannel.cpp b/cockatrice/src/tab_chatchannel.cpp deleted file mode 100644 index 515844f1..00000000 --- a/cockatrice/src/tab_chatchannel.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "tab_chatchannel.h" -#include "abstractclient.h" -#include "protocol_items.h" - -TabChatChannel::TabChatChannel(AbstractClient *_client, const QString &_channelName) - : Tab(), client(_client), channelName(_channelName) -{ - playerList = new QListWidget; - playerList->setFixedWidth(150); - - textEdit = new QTextEdit; - textEdit->setReadOnly(true); - sayEdit = new QLineEdit; - connect(sayEdit, SIGNAL(returnPressed()), this, SLOT(sendMessage())); - - QVBoxLayout *vbox = new QVBoxLayout; - vbox->addWidget(textEdit); - vbox->addWidget(sayEdit); - - QHBoxLayout *hbox = new QHBoxLayout; - hbox->addLayout(vbox); - hbox->addWidget(playerList); - - aLeaveChannel = new QAction(this); - connect(aLeaveChannel, SIGNAL(triggered()), this, SLOT(actLeaveChannel())); - - tabMenu = new QMenu(this); - tabMenu->addAction(aLeaveChannel); - - retranslateUi(); - setLayout(hbox); -} - -TabChatChannel::~TabChatChannel() -{ - emit channelClosing(this); -} - -void TabChatChannel::retranslateUi() -{ - tabMenu->setTitle(tr("C&hat channel")); - aLeaveChannel->setText(tr("&Leave channel")); -} - -QString TabChatChannel::sanitizeHtml(QString dirty) const -{ - return dirty - .replace("&", "&") - .replace("<", "<") - .replace(">", ">"); -} - -void TabChatChannel::sendMessage() -{ - if (sayEdit->text().isEmpty()) - return; - - client->sendCommand(new Command_ChatSay(channelName, sayEdit->text())); - sayEdit->clear(); -} - -void TabChatChannel::actLeaveChannel() -{ - client->sendCommand(new Command_ChatLeaveChannel(channelName)); - deleteLater(); -} - -void TabChatChannel::processChatEvent(ChatEvent *event) -{ - switch (event->getItemId()) { - case ItemId_Event_ChatListPlayers: processListPlayersEvent(qobject_cast(event)); break; - case ItemId_Event_ChatJoinChannel: processJoinChannelEvent(qobject_cast(event)); break; - case ItemId_Event_ChatLeaveChannel: processLeaveChannelEvent(qobject_cast(event)); break; - case ItemId_Event_ChatSay: processSayEvent(qobject_cast(event)); break; - default: ; - } -} - -void TabChatChannel::processListPlayersEvent(Event_ChatListPlayers *event) -{ - const QList &players = event->getPlayerList(); - for (int i = 0; i < players.size(); ++i) - playerList->addItem(players[i]->getName()); -} - -void TabChatChannel::processJoinChannelEvent(Event_ChatJoinChannel *event) -{ - textEdit->append(tr("%1 has joined the channel.").arg(sanitizeHtml(event->getUserInfo()->getName()))); - playerList->addItem(event->getUserInfo()->getName()); - emit userEvent(); -} - -void TabChatChannel::processLeaveChannelEvent(Event_ChatLeaveChannel *event) -{ - textEdit->append(tr("%1 has left the channel.").arg(sanitizeHtml(event->getPlayerName()))); - for (int i = 0; i < playerList->count(); ++i) - if (playerList->item(i)->text() == event->getPlayerName()) { - delete playerList->takeItem(i); - break; - } - emit userEvent(); -} - -void TabChatChannel::processSayEvent(Event_ChatSay *event) -{ - if (event->getPlayerName().isEmpty()) - textEdit->append(QString("%1getMessage()))); - else - textEdit->append(QString("%1: %2").arg(sanitizeHtml(event->getPlayerName())).arg(sanitizeHtml(event->getMessage()))); - emit userEvent(); -} diff --git a/cockatrice/src/tab_chatchannel.h b/cockatrice/src/tab_chatchannel.h deleted file mode 100644 index 2c329199..00000000 --- a/cockatrice/src/tab_chatchannel.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef TAB_CHATCHANNEL_H -#define TAB_CHATCHANNEL_H - -#include "tab.h" - -class AbstractClient; -class QListWidget; -class QTextEdit; -class QLineEdit; -class ChatEvent; -class Event_ChatListPlayers; -class Event_ChatJoinChannel; -class Event_ChatLeaveChannel; -class Event_ChatSay; - -class TabChatChannel : public Tab { - Q_OBJECT -private: - AbstractClient *client; - QString channelName; - - QListWidget *playerList; - QTextEdit *textEdit; - QLineEdit *sayEdit; - - QAction *aLeaveChannel; - QString sanitizeHtml(QString dirty) const; -signals: - void channelClosing(TabChatChannel *tab); -private slots: - void sendMessage(); - void actLeaveChannel(); - - void processListPlayersEvent(Event_ChatListPlayers *event); - void processJoinChannelEvent(Event_ChatJoinChannel *event); - void processLeaveChannelEvent(Event_ChatLeaveChannel *event); - void processSayEvent(Event_ChatSay *event); -public: - TabChatChannel(AbstractClient *_client, const QString &_channelName); - ~TabChatChannel(); - void retranslateUi(); - void processChatEvent(ChatEvent *event); - QString getChannelName() const { return channelName; } - QString getTabText() const { return channelName; } -}; - -#endif diff --git a/cockatrice/src/tab_game.cpp b/cockatrice/src/tab_game.cpp index 8d9a9511..13719e78 100644 --- a/cockatrice/src/tab_game.cpp +++ b/cockatrice/src/tab_game.cpp @@ -169,6 +169,8 @@ TabGame::TabGame(QList &_clients, int _gameId, const QString & cardInfo = new CardInfoWidget(CardInfoWidget::ModeGameTab); playerListWidget = new PlayerListWidget; playerListWidget->setFocusPolicy(Qt::NoFocus); + timeElapsedLabel = new QLabel; + timeElapsedLabel->setAlignment(Qt::AlignCenter); messageLog = new MessageLogWidget; connect(messageLog, SIGNAL(cardNameHovered(QString)), cardInfo, SLOT(setCard(QString))); connect(messageLog, SIGNAL(showCardInfoPopup(QPoint, QString)), this, SLOT(showCardInfoPopup(QPoint, QString))); @@ -190,6 +192,7 @@ TabGame::TabGame(QList &_clients, int _gameId, const QString & QVBoxLayout *verticalLayout = new QVBoxLayout; verticalLayout->addWidget(cardInfo); verticalLayout->addWidget(playerListWidget, 1); + verticalLayout->addWidget(timeElapsedLabel); verticalLayout->addWidget(messageLog, 5); verticalLayout->addLayout(hLayout); @@ -651,6 +654,13 @@ void TabGame::eventPing(Event_Ping *event, GameEventContext * /*context*/) const QList &pingList = event->getPingList(); for (int i = 0; i < pingList.size(); ++i) playerListWidget->updatePing(pingList[i]->getPlayerId(), pingList[i]->getPingTime()); + + int seconds = event->getSecondsElapsed(); + int minutes = seconds / 60; + seconds -= minutes * 60; + int hours = minutes / 60; + minutes -= hours * 60; + timeElapsedLabel->setText(QString::number(hours).rightJustified(2, '0') + ":" + QString::number(minutes).rightJustified(2, '0') + ":" + QString::number(seconds).rightJustified(2, '0')); } void TabGame::newCardAdded(AbstractCardItem *card) diff --git a/cockatrice/src/tab_game.h b/cockatrice/src/tab_game.h index db7ebd0b..0a022adf 100644 --- a/cockatrice/src/tab_game.h +++ b/cockatrice/src/tab_game.h @@ -99,6 +99,7 @@ private: CardInfoWidget *infoPopup; CardInfoWidget *cardInfo; PlayerListWidget *playerListWidget; + QLabel *timeElapsedLabel; MessageLogWidget *messageLog; QLabel *sayLabel; QLineEdit *sayEdit; diff --git a/cockatrice/src/tab_room.cpp b/cockatrice/src/tab_room.cpp new file mode 100644 index 00000000..8b7fb13b --- /dev/null +++ b/cockatrice/src/tab_room.cpp @@ -0,0 +1,282 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dlg_creategame.h" +#include "tab_room.h" +#include "userlist.h" +#include "abstractclient.h" +#include "protocol_items.h" +#include "gamesmodel.h" + +#include + +GameSelector::GameSelector(AbstractClient *_client, int _roomId, QWidget *parent) + : QGroupBox(parent), client(_client), roomId(_roomId) +{ + gameListView = new QTreeView; + gameListModel = new GamesModel(this); + gameListProxyModel = new GamesProxyModel(this); + gameListProxyModel->setSourceModel(gameListModel); + gameListView->setModel(gameListProxyModel); + gameListView->header()->setResizeMode(0, QHeaderView::ResizeToContents); + + showFullGamesCheckBox = new QCheckBox; + createButton = new QPushButton; + joinButton = new QPushButton; + spectateButton = new QPushButton; + QHBoxLayout *buttonLayout = new QHBoxLayout; + buttonLayout->addWidget(showFullGamesCheckBox); + buttonLayout->addStretch(); + buttonLayout->addWidget(createButton); + buttonLayout->addWidget(joinButton); + buttonLayout->addWidget(spectateButton); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(gameListView); + mainLayout->addLayout(buttonLayout); + + retranslateUi(); + setLayout(mainLayout); + + setMinimumWidth(gameListView->columnWidth(0) * gameListModel->columnCount()); + setMinimumHeight(400); + + connect(showFullGamesCheckBox, SIGNAL(stateChanged(int)), this, SLOT(showFullGamesChanged(int))); + connect(createButton, SIGNAL(clicked()), this, SLOT(actCreate())); + connect(joinButton, SIGNAL(clicked()), this, SLOT(actJoin())); + connect(spectateButton, SIGNAL(clicked()), this, SLOT(actJoin())); +} + +void GameSelector::showFullGamesChanged(int state) +{ + gameListProxyModel->setFullGamesVisible(state); +} + +void GameSelector::actCreate() +{ + DlgCreateGame dlg(client, roomId, this); + dlg.exec(); +} + +void GameSelector::checkResponse(ResponseCode response) +{ + createButton->setEnabled(true); + joinButton->setEnabled(true); + spectateButton->setEnabled(true); + + switch (response) { + case RespWrongPassword: QMessageBox::critical(this, tr("Error"), tr("Wrong password.")); break; + case RespSpectatorsNotAllowed: QMessageBox::critical(this, tr("Error"), tr("Spectators are not allowed in this game.")); break; + case RespGameFull: QMessageBox::critical(this, tr("Error"), tr("The game is already full.")); break; + case RespNameNotFound: QMessageBox::critical(this, tr("Error"), tr("The game does not exist any more.")); break; + default: ; + } +} + +void GameSelector::actJoin() +{ + bool spectator = sender() == spectateButton; + + QModelIndex ind = gameListView->currentIndex(); + if (!ind.isValid()) + return; + ServerInfo_Game *game = gameListModel->getGame(ind.data(Qt::UserRole).toInt()); + QString password; + if (game->getHasPassword() && !(spectator && !game->getSpectatorsNeedPassword())) { + bool ok; + password = QInputDialog::getText(this, tr("Join game"), tr("Password:"), QLineEdit::Password, QString(), &ok); + if (!ok) + return; + } + + Command_JoinGame *commandJoinGame = new Command_JoinGame(roomId, game->getGameId(), password, spectator); + connect(commandJoinGame, SIGNAL(finished(ResponseCode)), this, SLOT(checkResponse(ResponseCode))); + client->sendCommand(commandJoinGame); + + createButton->setEnabled(false); + joinButton->setEnabled(false); + spectateButton->setEnabled(false); +} + +void GameSelector::retranslateUi() +{ + setTitle(tr("Games")); + showFullGamesCheckBox->setText(tr("Show &full games")); + createButton->setText(tr("C&reate")); + joinButton->setText(tr("&Join")); + spectateButton->setText(tr("J&oin as spectator")); +} + +void GameSelector::processGameInfo(ServerInfo_Game *info) +{ + gameListModel->updateGameList(info); +} + +ChatView::ChatView(const QString &_ownName, QWidget *parent) + : QTextEdit(parent), ownName(_ownName) +{ + setTextInteractionFlags(Qt::TextSelectableByMouse); + + QTextTableFormat format; + format.setBorderStyle(QTextFrameFormat::BorderStyle_None); + table = textCursor().insertTable(1, 3, format); +} + +void ChatView::appendMessage(const QString &sender, const QString &message) +{ + QTextCursor cellCursor = table->cellAt(table->rows() - 1, 0).lastCursorPosition(); + cellCursor.insertText(QDateTime::currentDateTime().toString("[hh:mm]")); + QTextTableCell senderCell = table->cellAt(table->rows() - 1, 1); + QTextCharFormat senderFormat; + if (sender == ownName) { + senderFormat.setFontWeight(QFont::Bold); + senderFormat.setForeground(Qt::red); + } else + senderFormat.setForeground(Qt::blue); + senderCell.setFormat(senderFormat); + cellCursor = senderCell.lastCursorPosition(); + cellCursor.insertText(sender); + QTextTableCell messageCell = table->cellAt(table->rows() - 1, 2); + QTextCharFormat messageFormat; + if (sender.isEmpty()) + messageFormat.setForeground(Qt::darkGreen); + messageCell.setFormat(messageFormat); + cellCursor = messageCell.lastCursorPosition(); + cellCursor.insertText(message); + + table->appendRows(1); + + verticalScrollBar()->setValue(verticalScrollBar()->maximum()); +} + +TabRoom::TabRoom(AbstractClient *_client, const QString &_ownName, ServerInfo_Room *info) + : Tab(), client(_client), roomId(info->getRoomId()), roomName(info->getName()), ownName(_ownName) +{ + gameSelector = new GameSelector(client, roomId); + userList = new UserList(client, false); + connect(userList, SIGNAL(openMessageDialog(const QString &, bool)), this, SIGNAL(openMessageDialog(const QString &, bool))); + + chatView = new ChatView(ownName); + sayLabel = new QLabel; + sayEdit = new QLineEdit; + sayLabel->setBuddy(sayEdit); + connect(sayEdit, SIGNAL(returnPressed()), this, SLOT(sendMessage())); + + QHBoxLayout *sayHbox = new QHBoxLayout; + sayHbox->addWidget(sayLabel); + sayHbox->addWidget(sayEdit); + + QVBoxLayout *chatVbox = new QVBoxLayout; + chatVbox->addWidget(chatView); + chatVbox->addLayout(sayHbox); + + chatGroupBox = new QGroupBox; + chatGroupBox->setLayout(chatVbox); + + QVBoxLayout *vbox = new QVBoxLayout; + vbox->addWidget(gameSelector); + vbox->addWidget(chatGroupBox); + + QHBoxLayout *hbox = new QHBoxLayout; + hbox->addLayout(vbox, 3); + hbox->addWidget(userList, 1); + + aLeaveRoom = new QAction(this); + connect(aLeaveRoom, SIGNAL(triggered()), this, SLOT(actLeaveRoom())); + + tabMenu = new QMenu(this); + tabMenu->addAction(aLeaveRoom); + + retranslateUi(); + setLayout(hbox); + + const QList users = info->getUserList(); + for (int i = 0; i < users.size(); ++i) + userList->processUserInfo(users[i]); + + const QList games = info->getGameList(); + for (int i = 0; i < games.size(); ++i) + gameSelector->processGameInfo(games[i]); +} + +TabRoom::~TabRoom() +{ + emit roomClosing(this); +} + +void TabRoom::retranslateUi() +{ + sayLabel->setText(tr("&Say:")); + chatGroupBox->setTitle(tr("Chat")); + tabMenu->setTitle(tr("&Room")); + aLeaveRoom->setText(tr("&Leave room")); +} + +QString TabRoom::sanitizeHtml(QString dirty) const +{ + return dirty + .replace("&", "&") + .replace("<", "<") + .replace(">", ">"); +} + +void TabRoom::sendMessage() +{ + if (sayEdit->text().isEmpty()) + return; + + client->sendCommand(new Command_RoomSay(roomId, sayEdit->text())); + sayEdit->clear(); +} + +void TabRoom::actLeaveRoom() +{ + client->sendCommand(new Command_LeaveRoom(roomId)); + deleteLater(); +} + +void TabRoom::processRoomEvent(RoomEvent *event) +{ + switch (event->getItemId()) { + case ItemId_Event_ListGames: processListGamesEvent(qobject_cast(event)); break; + case ItemId_Event_JoinRoom: processJoinRoomEvent(qobject_cast(event)); break; + case ItemId_Event_LeaveRoom: processLeaveRoomEvent(qobject_cast(event)); break; + case ItemId_Event_RoomSay: processSayEvent(qobject_cast(event)); break; + default: ; + } +} + +void TabRoom::processListGamesEvent(Event_ListGames *event) +{ + const QList &gameList = event->getGameList(); + for (int i = 0; i < gameList.size(); ++i) + gameSelector->processGameInfo(gameList[i]); +} + +void TabRoom::processJoinRoomEvent(Event_JoinRoom *event) +{ + chatView->appendMessage(QString(), tr("%1 has joined the room.").arg(event->getUserInfo()->getName())); + userList->processUserInfo(event->getUserInfo()); +} + +void TabRoom::processLeaveRoomEvent(Event_LeaveRoom *event) +{ + chatView->appendMessage(QString(), tr("%1 has left the room.").arg(event->getPlayerName())); + userList->deleteUser(event->getPlayerName()); +} + +void TabRoom::processSayEvent(Event_RoomSay *event) +{ + chatView->appendMessage(event->getPlayerName(), event->getMessage()); + emit userEvent(); +} diff --git a/cockatrice/src/tab_room.h b/cockatrice/src/tab_room.h new file mode 100644 index 00000000..fd4f8f5c --- /dev/null +++ b/cockatrice/src/tab_room.h @@ -0,0 +1,100 @@ +#ifndef TAB_ROOM_H +#define TAB_ROOM_H + +#include "tab.h" +#include "protocol_datastructures.h" +#include +#include + +class AbstractClient; +class UserList; +class QLabel; +class QTextEdit; +class QLineEdit; +class QTreeView; +class QPushButton; +class QTextTable; +class QCheckBox; +class GamesModel; +class GamesProxyModel; +class RoomEvent; +class ServerInfo_Room; +class ServerInfo_Game; +class Event_ListGames; +class Event_JoinRoom; +class Event_LeaveRoom; +class Event_RoomSay; + +class GameSelector : public QGroupBox { + Q_OBJECT +private slots: + void showFullGamesChanged(int state); + void actCreate(); + void actJoin(); + void checkResponse(ResponseCode response); +signals: + void gameJoined(int gameId); +private: + AbstractClient *client; + int roomId; + + QTreeView *gameListView; + GamesModel *gameListModel; + GamesProxyModel *gameListProxyModel; + QPushButton *createButton, *joinButton, *spectateButton; + QCheckBox *showFullGamesCheckBox; +public: + GameSelector(AbstractClient *_client, int _roomId, QWidget *parent = 0); + void retranslateUi(); + void processGameInfo(ServerInfo_Game *info); +}; + +class ChatView : public QTextEdit { + Q_OBJECT; +private: + QTextTable *table; + QString ownName; +public: + ChatView(const QString &_ownName, QWidget *parent = 0); + void appendMessage(const QString &sender, const QString &message); +}; + +class TabRoom : public Tab { + Q_OBJECT +private: + AbstractClient *client; + int roomId; + QString roomName; + QString ownName; + + GameSelector *gameSelector; + UserList *userList; + ChatView *chatView; + QLabel *sayLabel; + QLineEdit *sayEdit; + QGroupBox *chatGroupBox; + + QAction *aLeaveRoom; + QString sanitizeHtml(QString dirty) const; +signals: + void roomClosing(TabRoom *tab); + void openMessageDialog(const QString &userName, bool focus); +private slots: + void sendMessage(); + void actLeaveRoom(); + + void processListGamesEvent(Event_ListGames *event); + void processJoinRoomEvent(Event_JoinRoom *event); + void processLeaveRoomEvent(Event_LeaveRoom *event); + void processSayEvent(Event_RoomSay *event); +public: + TabRoom(AbstractClient *_client, const QString &_ownName, ServerInfo_Room *info); + ~TabRoom(); + void retranslateUi(); + void processRoomEvent(RoomEvent *event); + int getRoomId() const { return roomId; } + QString getChannelName() const { return roomName; } + QString getTabText() const { return roomName; } +}; + +#endif diff --git a/cockatrice/src/tab_server.cpp b/cockatrice/src/tab_server.cpp index 04eb7e1b..5c4766c2 100644 --- a/cockatrice/src/tab_server.cpp +++ b/cockatrice/src/tab_server.cpp @@ -10,126 +10,25 @@ #include #include #include "tab_server.h" -#include "gamesmodel.h" -#include "dlg_creategame.h" #include "abstractclient.h" #include "protocol.h" #include "protocol_items.h" -#include "pixmapgenerator.h" +#include "userlist.h" +#include "userinfobox.h" +//#include "pixmapgenerator.h" #include -GameSelector::GameSelector(AbstractClient *_client, QWidget *parent) +RoomSelector::RoomSelector(AbstractClient *_client, QWidget *parent) : QGroupBox(parent), client(_client) { - gameListView = new QTreeView; - gameListModel = new GamesModel(this); - gameListProxyModel = new GamesProxyModel(this); - gameListProxyModel->setSourceModel(gameListModel); - gameListView->setModel(gameListProxyModel); - gameListView->header()->setResizeMode(0, QHeaderView::ResizeToContents); - - showFullGamesCheckBox = new QCheckBox; - createButton = new QPushButton; - joinButton = new QPushButton; - spectateButton = new QPushButton; - QHBoxLayout *buttonLayout = new QHBoxLayout; - buttonLayout->addWidget(showFullGamesCheckBox); - buttonLayout->addStretch(); - buttonLayout->addWidget(createButton); - buttonLayout->addWidget(joinButton); - buttonLayout->addWidget(spectateButton); - - QVBoxLayout *mainLayout = new QVBoxLayout; - mainLayout->addWidget(gameListView); - mainLayout->addLayout(buttonLayout); - - retranslateUi(); - setLayout(mainLayout); - - setMinimumWidth(gameListView->columnWidth(0) * gameListModel->columnCount()); - setMinimumHeight(400); - - connect(showFullGamesCheckBox, SIGNAL(stateChanged(int)), this, SLOT(showFullGamesChanged(int))); - connect(createButton, SIGNAL(clicked()), this, SLOT(actCreate())); - connect(joinButton, SIGNAL(clicked()), this, SLOT(actJoin())); - connect(spectateButton, SIGNAL(clicked()), this, SLOT(actJoin())); - - connect(client, SIGNAL(listGamesEventReceived(Event_ListGames *)), this, SLOT(processListGamesEvent(Event_ListGames *))); - client->sendCommand(new Command_ListGames); -} - -void GameSelector::showFullGamesChanged(int state) -{ - gameListProxyModel->setFullGamesVisible(state); -} - -void GameSelector::actCreate() -{ - DlgCreateGame dlg(client, this); - dlg.exec(); -} - -void GameSelector::checkResponse(ResponseCode response) -{ - createButton->setEnabled(true); - joinButton->setEnabled(true); - spectateButton->setEnabled(true); - - switch (response) { - case RespWrongPassword: QMessageBox::critical(this, tr("Error"), tr("Wrong password.")); break; - case RespSpectatorsNotAllowed: QMessageBox::critical(this, tr("Error"), tr("Spectators are not allowed in this game.")); break; - case RespGameFull: QMessageBox::critical(this, tr("Error"), tr("The game is already full.")); break; - case RespNameNotFound: QMessageBox::critical(this, tr("Error"), tr("The game does not exist any more.")); break; - default: ; - } -} - -void GameSelector::actJoin() -{ - bool spectator = sender() == spectateButton; - - QModelIndex ind = gameListView->currentIndex(); - if (!ind.isValid()) - return; - ServerInfo_Game *game = gameListModel->getGame(ind.data(Qt::UserRole).toInt()); - QString password; - if (game->getHasPassword() && !(spectator && !game->getSpectatorsNeedPassword())) { - bool ok; - password = QInputDialog::getText(this, tr("Join game"), tr("Password:"), QLineEdit::Password, QString(), &ok); - if (!ok) - return; - } - - Command_JoinGame *commandJoinGame = new Command_JoinGame(game->getGameId(), password, spectator); - connect(commandJoinGame, SIGNAL(finished(ResponseCode)), this, SLOT(checkResponse(ResponseCode))); - client->sendCommand(commandJoinGame); - - createButton->setEnabled(false); - joinButton->setEnabled(false); - spectateButton->setEnabled(false); -} - -void GameSelector::retranslateUi() -{ - setTitle(tr("Games")); - showFullGamesCheckBox->setText(tr("&Show full games")); - createButton->setText(tr("C&reate")); - joinButton->setText(tr("&Join")); - spectateButton->setText(tr("J&oin as spectator")); -} - -void GameSelector::processListGamesEvent(Event_ListGames *event) -{ - const QList &gamesToUpdate = event->getGameList(); - for (int i = 0; i < gamesToUpdate.size(); ++i) - gameListModel->updateGameList(gamesToUpdate[i]); -} - -ChatChannelSelector::ChatChannelSelector(AbstractClient *_client, QWidget *parent) - : QGroupBox(parent), client(_client) -{ - channelList = new QTreeWidget; - channelList->setRootIsDecorated(false); + roomList = new QTreeWidget; + roomList->setRootIsDecorated(false); + roomList->setColumnCount(4); + roomList->header()->setStretchLastSection(false); + roomList->header()->setResizeMode(0, QHeaderView::ResizeToContents); + roomList->header()->setResizeMode(1, QHeaderView::Stretch); + roomList->header()->setResizeMode(2, QHeaderView::ResizeToContents); + roomList->header()->setResizeMode(3, QHeaderView::ResizeToContents); joinButton = new QPushButton; connect(joinButton, SIGNAL(clicked()), this, SLOT(joinClicked())); @@ -137,281 +36,111 @@ ChatChannelSelector::ChatChannelSelector(AbstractClient *_client, QWidget *paren buttonLayout->addStretch(); buttonLayout->addWidget(joinButton); QVBoxLayout *vbox = new QVBoxLayout; - vbox->addWidget(channelList); + vbox->addWidget(roomList); vbox->addLayout(buttonLayout); retranslateUi(); setLayout(vbox); - connect(client, SIGNAL(listChatChannelsEventReceived(Event_ListChatChannels *)), this, SLOT(processListChatChannelsEvent(Event_ListChatChannels *))); - client->sendCommand(new Command_ListChatChannels); + connect(client, SIGNAL(listRoomsEventReceived(Event_ListRooms *)), this, SLOT(processListRoomsEvent(Event_ListRooms *))); + client->sendCommand(new Command_ListRooms); } -void ChatChannelSelector::retranslateUi() +void RoomSelector::retranslateUi() { - setTitle(tr("Chat channels")); + setTitle(tr("Rooms")); joinButton->setText(tr("Joi&n")); - QTreeWidgetItem *header = channelList->headerItem(); - header->setText(0, tr("Channel")); + QTreeWidgetItem *header = roomList->headerItem(); + header->setText(0, tr("Room")); header->setText(1, tr("Description")); header->setText(2, tr("Players")); + header->setText(3, tr("Games")); header->setTextAlignment(2, Qt::AlignRight); + header->setTextAlignment(3, Qt::AlignRight); } -void ChatChannelSelector::processListChatChannelsEvent(Event_ListChatChannels *event) +void RoomSelector::processListRoomsEvent(Event_ListRooms *event) { - const QList &channelsToUpdate = event->getChannelList(); - for (int i = 0; i < channelsToUpdate.size(); ++i) { - ServerInfo_ChatChannel *channel = channelsToUpdate[i]; + const QList &roomsToUpdate = event->getRoomList(); + for (int i = 0; i < roomsToUpdate.size(); ++i) { + ServerInfo_Room *room = roomsToUpdate[i]; - for (int j = 0; j < channelList->topLevelItemCount(); ++j) { - QTreeWidgetItem *twi = channelList->topLevelItem(j); - if (twi->text(0) == channel->getName()) { - twi->setText(1, channel->getDescription()); - twi->setText(2, QString::number(channel->getPlayerCount())); + for (int j = 0; j < roomList->topLevelItemCount(); ++j) { + QTreeWidgetItem *twi = roomList->topLevelItem(j); + if (twi->data(0, Qt::UserRole).toInt() == room->getRoomId()) { + twi->setData(0, Qt::DisplayRole, room->getName()); + twi->setData(1, Qt::DisplayRole, room->getDescription()); + twi->setData(2, Qt::DisplayRole, room->getPlayerCount()); + twi->setData(3, Qt::DisplayRole, room->getGameCount()); return; } } - QTreeWidgetItem *twi = new QTreeWidgetItem(QStringList() << channel->getName() << channel->getDescription() << QString::number(channel->getPlayerCount())); + QTreeWidgetItem *twi = new QTreeWidgetItem; + twi->setData(0, Qt::UserRole, room->getRoomId()); + twi->setData(0, Qt::DisplayRole, room->getName()); + twi->setData(1, Qt::DisplayRole, room->getDescription()); + twi->setData(2, Qt::DisplayRole, room->getPlayerCount()); + twi->setData(3, Qt::DisplayRole, room->getGameCount()); twi->setTextAlignment(2, Qt::AlignRight); - channelList->addTopLevelItem(twi); - channelList->resizeColumnToContents(0); - channelList->resizeColumnToContents(1); - channelList->resizeColumnToContents(2); - if (channel->getAutoJoin()) - joinChannel(channel->getName()); + twi->setTextAlignment(3, Qt::AlignRight); + roomList->addTopLevelItem(twi); + if (room->getAutoJoin()) + joinRoom(room->getRoomId(), false); } } -void ChatChannelSelector::joinChannel(const QString &channelName) +void RoomSelector::joinRoom(int id, bool setCurrent) { - Command_ChatJoinChannel *command = new Command_ChatJoinChannel(channelName); - connect(command, SIGNAL(finished(ResponseCode)), this, SLOT(joinFinished(ResponseCode))); + Command_JoinRoom *command = new Command_JoinRoom(id); + command->setExtraData(setCurrent); + connect(command, SIGNAL(finished(ProtocolResponse *)), this, SLOT(joinFinished(ProtocolResponse *))); client->sendCommand(command); } -void ChatChannelSelector::joinClicked() +void RoomSelector::joinClicked() { - QTreeWidgetItem *twi = channelList->currentItem(); + QTreeWidgetItem *twi = roomList->currentItem(); if (!twi) return; - QString channelName = twi->text(0); - joinChannel(channelName); + joinRoom(twi->data(0, Qt::UserRole).toInt(), true); } -void ChatChannelSelector::joinFinished(ResponseCode resp) +void RoomSelector::joinFinished(ProtocolResponse *r) { - if (resp != RespOk) + if (r->getResponseCode() != RespOk) return; - - Command_ChatJoinChannel *command = qobject_cast(sender()); - QString channelName = command->getChannel(); - - emit channelJoined(channelName); -} - -ServerMessageLog::ServerMessageLog(AbstractClient *_client, QWidget *parent) - : QGroupBox(parent) -{ - textEdit = new QTextEdit; - textEdit->setReadOnly(true); - - QVBoxLayout *vbox = new QVBoxLayout; - vbox->addWidget(textEdit); - - setLayout(vbox); - retranslateUi(); - - connect(_client, SIGNAL(serverMessageEventReceived(Event_ServerMessage *)), this, SLOT(processServerMessageEvent(Event_ServerMessage *))); -} - -void ServerMessageLog::retranslateUi() -{ - setTitle(tr("Server messages")); -} - -void ServerMessageLog::processServerMessageEvent(Event_ServerMessage *event) -{ - textEdit->append(event->getMessage()); -} - -UserListTWI::UserListTWI() - : QTreeWidgetItem(Type) -{ -} - -bool UserListTWI::operator<(const QTreeWidgetItem &other) const -{ - // Equal user level => sort by name - if (data(0, Qt::UserRole) == other.data(0, Qt::UserRole)) - return data(2, Qt::UserRole).toString().toLower() < other.data(2, Qt::UserRole).toString().toLower(); - // Else sort by user level - return data(0, Qt::UserRole).toInt() > other.data(0, Qt::UserRole).toInt(); -} - -UserList::UserList(AbstractClient *_client, QWidget *parent) - : QGroupBox(parent) -{ - userTree = new QTreeWidget; - userTree->setColumnCount(3); - userTree->header()->setResizeMode(QHeaderView::ResizeToContents); - userTree->setHeaderHidden(true); - userTree->setRootIsDecorated(false); - userTree->setIconSize(QSize(20, 12)); - connect(userTree, SIGNAL(itemActivated(QTreeWidgetItem *, int)), this, SLOT(userClicked(QTreeWidgetItem *, int))); - - QVBoxLayout *vbox = new QVBoxLayout; - vbox->addWidget(userTree); - - setLayout(vbox); - - retranslateUi(); - - connect(_client, SIGNAL(userJoinedEventReceived(Event_UserJoined *)), this, SLOT(processUserJoinedEvent(Event_UserJoined *))); - connect(_client, SIGNAL(userLeftEventReceived(Event_UserLeft *)), this, SLOT(processUserLeftEvent(Event_UserLeft *))); - - Command_ListUsers *cmd = new Command_ListUsers; - connect(cmd, SIGNAL(finished(ProtocolResponse *)), this, SLOT(processResponse(ProtocolResponse *))); - _client->sendCommand(cmd); -} - -void UserList::retranslateUi() -{ - setTitle(tr("Users online: %1").arg(userTree->topLevelItemCount())); -} - -void UserList::processUserInfo(ServerInfo_User *user) -{ - QTreeWidgetItem *item = 0; - for (int i = 0; i < userTree->topLevelItemCount(); ++i) { - QTreeWidgetItem *temp = userTree->topLevelItem(i); - if (temp->data(2, Qt::UserRole) == user->getName()) { - item = temp; - break; - } - } - if (!item) { - item = new UserListTWI; - userTree->addTopLevelItem(item); - retranslateUi(); - } - item->setData(0, Qt::UserRole, user->getUserLevel()); - item->setIcon(0, QIcon(UserLevelPixmapGenerator::generatePixmap(12, user->getUserLevel()))); - item->setIcon(1, QIcon(CountryPixmapGenerator::generatePixmap(12, user->getCountry()))); - item->setData(2, Qt::UserRole, user->getName()); - item->setData(2, Qt::DisplayRole, user->getName()); -} - -void UserList::processResponse(ProtocolResponse *response) -{ - Response_ListUsers *resp = qobject_cast(response); + Response_JoinRoom *resp = qobject_cast(r); if (!resp) return; - const QList &respList = resp->getUserList(); - for (int i = 0; i < respList.size(); ++i) - processUserInfo(respList[i]); - - userTree->sortItems(1, Qt::AscendingOrder); + emit roomJoined(resp->getRoomInfo(), static_cast(sender())->getExtraData().toBool()); } -void UserList::processUserJoinedEvent(Event_UserJoined *event) -{ - processUserInfo(event->getUserInfo()); - userTree->sortItems(1, Qt::AscendingOrder); -} - -void UserList::processUserLeftEvent(Event_UserLeft *event) -{ - for (int i = 0; i < userTree->topLevelItemCount(); ++i) - if (userTree->topLevelItem(i)->data(2, Qt::UserRole) == event->getUserName()) { - emit userLeft(event->getUserName()); - delete userTree->takeTopLevelItem(i); - retranslateUi(); - break; - } -} - -void UserList::userClicked(QTreeWidgetItem *item, int /*column*/) -{ - emit openMessageDialog(item->data(2, Qt::UserRole).toString(), true); -} - -UserInfoBox::UserInfoBox(AbstractClient *_client, QWidget *parent) - : QWidget(parent) -{ - avatarLabel = new QLabel; - nameLabel = new QLabel; - QFont nameFont = nameLabel->font(); - nameFont.setBold(true); - nameFont.setPointSize(nameFont.pointSize() * 1.5); - nameLabel->setFont(nameFont); - countryLabel1 = new QLabel; - countryLabel2 = new QLabel; - userLevelLabel1 = new QLabel; - userLevelLabel2 = new QLabel; - - QGridLayout *mainLayout = new QGridLayout; - mainLayout->addWidget(avatarLabel, 0, 0, 3, 1); - mainLayout->addWidget(nameLabel, 0, 1, 1, 2); - mainLayout->addWidget(countryLabel1, 1, 1, 1, 1); - mainLayout->addWidget(countryLabel2, 1, 2, 1, 1); - mainLayout->addWidget(userLevelLabel1, 2, 1, 1, 1); - mainLayout->addWidget(userLevelLabel2, 2, 2, 1, 1); - - setLayout(mainLayout); - - Command_GetUserInfo *cmd = new Command_GetUserInfo; - connect(cmd, SIGNAL(finished(ProtocolResponse *)), this, SLOT(processResponse(ProtocolResponse *))); - _client->sendCommand(cmd); -} - -void UserInfoBox::retranslateUi() -{ - countryLabel1->setText(tr("Location:")); - userLevelLabel1->setText(tr("User level:")); -} - -void UserInfoBox::processResponse(ProtocolResponse *response) -{ - Response_GetUserInfo *resp = qobject_cast(response); - if (!resp) - return; - ServerInfo_User *user = resp->getUserInfo(); - - QPixmap avatarPixmap; - if (!avatarPixmap.loadFromData(user->getAvatarBmp())) - avatarPixmap = UserLevelPixmapGenerator::generatePixmap(64, user->getUserLevel()); - avatarLabel->setPixmap(avatarPixmap); - - nameLabel->setText(user->getName()); - countryLabel2->setPixmap(CountryPixmapGenerator::generatePixmap(15, user->getCountry())); - userLevelLabel2->setPixmap(UserLevelPixmapGenerator::generatePixmap(15, user->getUserLevel())); -} - -TabServer::TabServer(AbstractClient *_client, QWidget *parent) +TabServer::TabServer(AbstractClient *_client, ServerInfo_User *userInfo, QWidget *parent) : Tab(parent), client(_client) { - gameSelector = new GameSelector(client); - chatChannelSelector = new ChatChannelSelector(client); - serverMessageLog = new ServerMessageLog(client); - userInfoBox = new UserInfoBox(client); - userList = new UserList(client); + roomSelector = new RoomSelector(client); + serverInfoBox = new QTextBrowser; + userInfoBox = new UserInfoBox(_client, false); + userInfoBox->updateInfo(userInfo); + userList = new UserList(client, true); - connect(gameSelector, SIGNAL(gameJoined(int)), this, SIGNAL(gameJoined(int))); - connect(chatChannelSelector, SIGNAL(channelJoined(const QString &)), this, SIGNAL(chatChannelJoined(const QString &))); + connect(roomSelector, SIGNAL(roomJoined(ServerInfo_Room *, bool)), this, SIGNAL(roomJoined(ServerInfo_Room *, bool))); connect(userList, SIGNAL(openMessageDialog(const QString &, bool)), this, SIGNAL(openMessageDialog(const QString &, bool))); - connect(userList, SIGNAL(userLeft(const QString &)), this, SIGNAL(userLeft(const QString &))); - QHBoxLayout *hbox = new QHBoxLayout; - hbox->addWidget(chatChannelSelector); - hbox->addWidget(serverMessageLog); + connect(client, SIGNAL(userJoinedEventReceived(Event_UserJoined *)), this, SLOT(processUserJoinedEvent(Event_UserJoined *))); + connect(client, SIGNAL(userLeftEventReceived(Event_UserLeft *)), this, SLOT(processUserLeftEvent(Event_UserLeft *))); + connect(client, SIGNAL(serverMessageEventReceived(Event_ServerMessage *)), this, SLOT(processServerMessageEvent(Event_ServerMessage *))); + + Command_ListUsers *cmd = new Command_ListUsers; + connect(cmd, SIGNAL(finished(ProtocolResponse *)), this, SLOT(processListUsersResponse(ProtocolResponse *))); + client->sendCommand(cmd); QVBoxLayout *vbox = new QVBoxLayout; - vbox->addWidget(gameSelector); - vbox->addLayout(hbox); + vbox->addWidget(roomSelector); + vbox->addWidget(serverInfoBox); QVBoxLayout *vbox2 = new QVBoxLayout; vbox2->addWidget(userInfoBox); @@ -426,9 +155,38 @@ TabServer::TabServer(AbstractClient *_client, QWidget *parent) void TabServer::retranslateUi() { - gameSelector->retranslateUi(); - chatChannelSelector->retranslateUi(); - serverMessageLog->retranslateUi(); + roomSelector->retranslateUi(); userInfoBox->retranslateUi(); userList->retranslateUi(); } + +void TabServer::processServerMessageEvent(Event_ServerMessage *event) +{ + serverInfoBox->setHtml(event->getMessage()); + emit userEvent(); +} + +void TabServer::processListUsersResponse(ProtocolResponse *response) +{ + Response_ListUsers *resp = qobject_cast(response); + if (!resp) + return; + + const QList &respList = resp->getUserList(); + for (int i = 0; i < respList.size(); ++i) + userList->processUserInfo(respList[i]); + + userList->sortItems(); +} + +void TabServer::processUserJoinedEvent(Event_UserJoined *event) +{ + userList->processUserInfo(event->getUserInfo()); + userList->sortItems(); +} + +void TabServer::processUserLeftEvent(Event_UserLeft *event) +{ + if (userList->deleteUser(event->getUserName())) + emit userLeft(event->getUserName()); +} \ No newline at end of file diff --git a/cockatrice/src/tab_server.h b/cockatrice/src/tab_server.h index 3ddd89cd..0bdf4570 100644 --- a/cockatrice/src/tab_server.h +++ b/cockatrice/src/tab_server.h @@ -3,132 +3,62 @@ #include #include +#include #include "tab.h" -#include "protocol_datastructures.h" class AbstractClient; -class QTreeView; -class QTreeWidget; -class QTreeWidgetItem; -class QPushButton; -class QCheckBox; class QTextEdit; class QLabel; +class UserList; +class QPushButton; +class UserInfoBox; -class GamesModel; -class GamesProxyModel; - -class Event_ListGames; -class Event_ListChatChannels; +class Event_ListRooms; class Event_ServerMessage; class Event_UserJoined; class Event_UserLeft; class ProtocolResponse; +class ServerInfo_User; +class ServerInfo_Room; -class GameSelector : public QGroupBox { - Q_OBJECT -public: - GameSelector(AbstractClient *_client, QWidget *parent = 0); - void retranslateUi(); -private slots: - void processListGamesEvent(Event_ListGames *event); - void showFullGamesChanged(int state); - void actCreate(); - void actJoin(); - void checkResponse(ResponseCode response); -signals: - void gameJoined(int gameId); -private: - AbstractClient *client; - - QTreeView *gameListView; - GamesModel *gameListModel; - GamesProxyModel *gameListProxyModel; - QPushButton *createButton, *joinButton, *spectateButton; - QCheckBox *showFullGamesCheckBox; -}; - -class ChatChannelSelector : public QGroupBox { +class RoomSelector : public QGroupBox { Q_OBJECT private: - QTreeWidget *channelList; + QTreeWidget *roomList; QPushButton *joinButton; AbstractClient *client; - void joinChannel(const QString &channelName); + void joinRoom(int id, bool setCurrent); private slots: - void processListChatChannelsEvent(Event_ListChatChannels *event); + void processListRoomsEvent(Event_ListRooms *event); void joinClicked(); - void joinFinished(ResponseCode resp); + void joinFinished(ProtocolResponse *resp); signals: - void channelJoined(const QString &channelName); + void roomJoined(ServerInfo_Room *info, bool setCurrent); public: - ChatChannelSelector(AbstractClient *_client, QWidget *parent = 0); - void retranslateUi(); -}; - -class ServerMessageLog : public QGroupBox { - Q_OBJECT -private: - QTextEdit *textEdit; -private slots: - void processServerMessageEvent(Event_ServerMessage *event); -public: - ServerMessageLog(AbstractClient *_client, QWidget *parent = 0); - void retranslateUi(); -}; - -class UserListTWI : public QTreeWidgetItem { -public: - UserListTWI(); - bool operator<(const QTreeWidgetItem &other) const; -}; - -class UserList : public QGroupBox { - Q_OBJECT -private: - QTreeWidget *userTree; - void processUserInfo(ServerInfo_User *user); -private slots: - void processResponse(ProtocolResponse *response); - void processUserJoinedEvent(Event_UserJoined *event); - void processUserLeftEvent(Event_UserLeft *event); - void userClicked(QTreeWidgetItem *item, int column); -signals: - void openMessageDialog(const QString &userName, bool focus); - void userLeft(const QString &userName); -public: - UserList(AbstractClient *_client, QWidget *parent = 0); - void retranslateUi(); -}; - -class UserInfoBox : public QWidget { - Q_OBJECT -private: - QLabel *avatarLabel, *nameLabel, *countryLabel1, *countryLabel2, *userLevelLabel1, *userLevelLabel2; -private slots: - void processResponse(ProtocolResponse *response); -public: - UserInfoBox(AbstractClient *_client, QWidget *parent = 0); + RoomSelector(AbstractClient *_client, QWidget *parent = 0); void retranslateUi(); }; class TabServer : public Tab { Q_OBJECT signals: - void chatChannelJoined(const QString &channelName); - void gameJoined(int gameId); + void roomJoined(ServerInfo_Room *info, bool setCurrent); void openMessageDialog(const QString &userName, bool focus); void userLeft(const QString &userName); +private slots: + void processListUsersResponse(ProtocolResponse *response); + void processUserJoinedEvent(Event_UserJoined *event); + void processUserLeftEvent(Event_UserLeft *event); + void processServerMessageEvent(Event_ServerMessage *event); private: AbstractClient *client; - GameSelector *gameSelector; - ChatChannelSelector *chatChannelSelector; - ServerMessageLog *serverMessageLog; + RoomSelector *roomSelector; + QTextBrowser *serverInfoBox; UserList *userList; UserInfoBox *userInfoBox; public: - TabServer(AbstractClient *_client, QWidget *parent = 0); + TabServer(AbstractClient *_client, ServerInfo_User *userInfo, QWidget *parent = 0); void retranslateUi(); QString getTabText() const { return tr("Server"); } }; diff --git a/cockatrice/src/tab_supervisor.cpp b/cockatrice/src/tab_supervisor.cpp index b5075470..70f712b2 100644 --- a/cockatrice/src/tab_supervisor.cpp +++ b/cockatrice/src/tab_supervisor.cpp @@ -2,16 +2,17 @@ #include "tab_supervisor.h" #include "abstractclient.h" #include "tab_server.h" -#include "tab_chatchannel.h" +#include "tab_room.h" #include "tab_game.h" #include "tab_deck_storage.h" +#include "tab_admin.h" #include "tab_message.h" #include "protocol_items.h" #include "pixmapgenerator.h" #include TabSupervisor:: TabSupervisor(QWidget *parent) - : QTabWidget(parent), client(0), tabServer(0), tabDeckStorage(0) + : QTabWidget(parent), client(0), tabServer(0), tabDeckStorage(0), tabAdmin(0) { tabChangedIcon = new QIcon(":/resources/icon_tab_changed.svg"); setElideMode(Qt::ElideRight); @@ -32,9 +33,9 @@ void TabSupervisor::retranslateUi() tabs.append(tabServer); if (tabDeckStorage) tabs.append(tabDeckStorage); - QMapIterator chatChannelIterator(chatChannelTabs); - while (chatChannelIterator.hasNext()) - tabs.append(chatChannelIterator.next().value()); + QMapIterator roomIterator(roomTabs); + while (roomIterator.hasNext()) + tabs.append(roomIterator.next().value()); QMapIterator gameIterator(gameTabs); while (gameIterator.hasNext()) tabs.append(gameIterator.next().value()); @@ -51,24 +52,35 @@ void TabSupervisor::myAddTab(Tab *tab) addTab(tab, tab->getTabText()); } -void TabSupervisor::start(AbstractClient *_client) +void TabSupervisor::start(AbstractClient *_client, ServerInfo_User *userInfo) { client = _client; - connect(client, SIGNAL(chatEventReceived(ChatEvent *)), this, SLOT(processChatEvent(ChatEvent *))); + userName = userInfo->getName(); + + connect(client, SIGNAL(roomEventReceived(RoomEvent *)), this, SLOT(processRoomEvent(RoomEvent *))); connect(client, SIGNAL(gameEventContainerReceived(GameEventContainer *)), this, SLOT(processGameEventContainer(GameEventContainer *))); connect(client, SIGNAL(gameJoinedEventReceived(Event_GameJoined *)), this, SLOT(gameJoined(Event_GameJoined *))); connect(client, SIGNAL(messageEventReceived(Event_Message *)), this, SLOT(processMessageEvent(Event_Message *))); connect(client, SIGNAL(maxPingTime(int, int)), this, SLOT(updatePingTime(int, int))); - tabServer = new TabServer(client); - connect(tabServer, SIGNAL(chatChannelJoined(const QString &)), this, SLOT(addChatChannelTab(const QString &))); + tabServer = new TabServer(client, userInfo); + connect(tabServer, SIGNAL(roomJoined(ServerInfo_Room *, bool)), this, SLOT(addRoomTab(ServerInfo_Room *, bool))); connect(tabServer, SIGNAL(openMessageDialog(const QString &, bool)), this, SLOT(addMessageTab(const QString &, bool))); connect(tabServer, SIGNAL(userLeft(const QString &)), this, SLOT(processUserLeft(const QString &))); myAddTab(tabServer); updatePingTime(0, -1); - tabDeckStorage = new TabDeckStorage(client); - myAddTab(tabDeckStorage); + if (userInfo->getUserLevel() & ServerInfo_User::IsRegistered) { + tabDeckStorage = new TabDeckStorage(client); + myAddTab(tabDeckStorage); + } else + tabDeckStorage = 0; + + if (userInfo->getUserLevel() & ServerInfo_User::IsAdmin) { + tabAdmin = new TabAdmin(client); + myAddTab(tabAdmin); + } else + tabAdmin = 0; retranslateUi(); } @@ -107,10 +119,10 @@ void TabSupervisor::stop() tabDeckStorage->deleteLater(); tabDeckStorage = 0; - QMapIterator chatChannelIterator(chatChannelTabs); - while (chatChannelIterator.hasNext()) - chatChannelIterator.next().value()->deleteLater(); - chatChannelTabs.clear(); + QMapIterator roomIterator(roomTabs); + while (roomIterator.hasNext()) + roomIterator.next().value()->deleteLater(); + roomTabs.clear(); QMapIterator gameIterator(gameTabs); while (gameIterator.hasNext()) @@ -122,6 +134,8 @@ void TabSupervisor::updatePingTime(int value, int max) { if (!tabServer) return; + if (tabServer->getContentsChanged()) + return; setTabIcon(0, QIcon(PingPixmapGenerator::generatePixmap(15, value, max))); } @@ -144,7 +158,7 @@ void TabSupervisor::localGameJoined(Event_GameJoined *event) setCurrentWidget(tab); for (int i = 1; i < localClients.size(); ++i) { - Command_JoinGame *cmd = new Command_JoinGame(event->getGameId()); + Command_JoinGame *cmd = new Command_JoinGame(0, event->getGameId()); localClients[i]->sendCommand(cmd); } } @@ -160,29 +174,33 @@ void TabSupervisor::gameLeft(TabGame *tab) stop(); } -void TabSupervisor::addChatChannelTab(const QString &channelName) +void TabSupervisor::addRoomTab(ServerInfo_Room *info, bool setCurrent) { - TabChatChannel *tab = new TabChatChannel(client, channelName); - connect(tab, SIGNAL(channelClosing(TabChatChannel *)), this, SLOT(chatChannelLeft(TabChatChannel *))); + TabRoom *tab = new TabRoom(client, userName, info); + connect(tab, SIGNAL(roomClosing(TabRoom *)), this, SLOT(roomLeft(TabRoom *))); myAddTab(tab); - chatChannelTabs.insert(channelName, tab); - setCurrentWidget(tab); + roomTabs.insert(info->getRoomId(), tab); + if (setCurrent) + setCurrentWidget(tab); } -void TabSupervisor::chatChannelLeft(TabChatChannel *tab) +void TabSupervisor::roomLeft(TabRoom *tab) { emit setMenu(0); - chatChannelTabs.remove(tab->getChannelName()); + roomTabs.remove(tab->getRoomId()); removeTab(indexOf(tab)); } -TabMessage *TabSupervisor::addMessageTab(const QString &userName, bool focus) +TabMessage *TabSupervisor::addMessageTab(const QString &receiverName, bool focus) { - TabMessage *tab = new TabMessage(client, userName); + if (receiverName == userName) + return 0; + + TabMessage *tab = new TabMessage(client, receiverName); connect(tab, SIGNAL(talkClosing(TabMessage *)), this, SLOT(talkLeft(TabMessage *))); myAddTab(tab); - messageTabs.insert(userName, tab); + messageTabs.insert(receiverName, tab); if (focus) setCurrentWidget(tab); return tab; @@ -206,11 +224,11 @@ void TabSupervisor::tabUserEvent() QApplication::alert(this); } -void TabSupervisor::processChatEvent(ChatEvent *event) +void TabSupervisor::processRoomEvent(RoomEvent *event) { - TabChatChannel *tab = chatChannelTabs.value(event->getChannel(), 0); + TabRoom *tab = roomTabs.value(event->getRoomId(), 0); if (tab) - tab->processChatEvent(event); + tab->processRoomEvent(event); } void TabSupervisor::processGameEventContainer(GameEventContainer *cont) @@ -230,6 +248,8 @@ void TabSupervisor::processMessageEvent(Event_Message *event) tab = messageTabs.value(event->getReceiverName()); if (!tab) tab = addMessageTab(event->getSenderName(), false); + if (!tab) + return; tab->processMessageEvent(event); } diff --git a/cockatrice/src/tab_supervisor.h b/cockatrice/src/tab_supervisor.h index 7d1965f8..f10140ec 100644 --- a/cockatrice/src/tab_supervisor.h +++ b/cockatrice/src/tab_supervisor.h @@ -8,24 +8,29 @@ class QMenu; class AbstractClient; class Tab; class TabServer; -class TabChatChannel; +class TabRoom; class TabGame; class TabDeckStorage; +class TabAdmin; class TabMessage; -class ChatEvent; +class RoomEvent; class GameEventContainer; class Event_GameJoined; class Event_Message; +class ServerInfo_Room; +class ServerInfo_User; class TabSupervisor : public QTabWidget { Q_OBJECT private: + QString userName; QIcon *tabChangedIcon; AbstractClient *client; QList localClients; TabServer *tabServer; TabDeckStorage *tabDeckStorage; - QMap chatChannelTabs; + TabAdmin *tabAdmin; + QMap roomTabs; QMap gameTabs; QMap messageTabs; void myAddTab(Tab *tab); @@ -33,7 +38,7 @@ public: TabSupervisor(QWidget *parent = 0); ~TabSupervisor(); void retranslateUi(); - void start(AbstractClient *_client); + void start(AbstractClient *_client, ServerInfo_User *userInfo); void startLocal(const QList &_clients); void stop(); int getGameCount() const { return gameTabs.size(); } @@ -46,13 +51,13 @@ private slots: void gameJoined(Event_GameJoined *event); void localGameJoined(Event_GameJoined *event); void gameLeft(TabGame *tab); - void addChatChannelTab(const QString &channelName); - void chatChannelLeft(TabChatChannel *tab); + void addRoomTab(ServerInfo_Room *info, bool setCurrent); + void roomLeft(TabRoom *tab); TabMessage *addMessageTab(const QString &userName, bool focus); void processUserLeft(const QString &userName); void talkLeft(TabMessage *tab); void tabUserEvent(); - void processChatEvent(ChatEvent *event); + void processRoomEvent(RoomEvent *event); void processGameEventContainer(GameEventContainer *cont); void processMessageEvent(Event_Message *event); }; diff --git a/cockatrice/src/tablezone.cpp b/cockatrice/src/tablezone.cpp index 4d52cf93..bb74b403 100644 --- a/cockatrice/src/tablezone.cpp +++ b/cockatrice/src/tablezone.cpp @@ -7,19 +7,16 @@ #include "protocol_items.h" #include "settingscache.h" #include "arrowitem.h" +#include "carddragitem.h" TableZone::TableZone(Player *_p, QGraphicsItem *parent) - : CardZone(_p, "table", true, false, true, parent), active(false) + : SelectZone(_p, "table", true, false, true, parent), active(false) { connect(settingsCache, SIGNAL(tableBgPathChanged()), this, SLOT(updateBgPixmap())); - connect(settingsCache, SIGNAL(economicalGridChanged()), this, SLOT(reorganizeCards())); connect(settingsCache, SIGNAL(invertVerticalCoordinateChanged()), this, SLOT(reorganizeCards())); updateBgPixmap(); - if (settingsCache->getEconomicalGrid()) - height = 2 * boxLineWidth + (int) (11.0 / 3 * CARD_HEIGHT + 2 * paddingY); - else - height = 2 * boxLineWidth + 3 * CARD_HEIGHT + 2 * paddingY; + height = 2 * boxLineWidth + 3 * (CARD_HEIGHT + 20) + 2 * paddingY; width = minWidth + 2 * marginX + 2 * boxLineWidth; currentMinimumWidth = minWidth; @@ -52,7 +49,7 @@ void TableZone::paint(QPainter *painter, const QStyleOptionGraphicsItem */*optio else painter->fillRect(boundingRect(), QBrush(bgPixmap)); painter->setPen(QColor(255, 255, 255, 40)); - qreal separatorY = 2 * (CARD_HEIGHT + paddingY) + boxLineWidth - paddingY / 2; + qreal separatorY = 2 * (CARD_HEIGHT + 20 + paddingY) + boxLineWidth - paddingY / 2; if (isInverted()) separatorY = height - separatorY; painter->drawLine(QPointF(0, separatorY), QPointF(width, separatorY)); @@ -88,14 +85,18 @@ void TableZone::addCardImpl(CardItem *card, int _x, int _y) card->update(); } -void TableZone::handleDropEvent(int cardId, CardZone *startZone, const QPoint &dropPoint, bool faceDown) +void TableZone::handleDropEvent(const QList &dragItems, CardZone *startZone, const QPoint &dropPoint, bool faceDown) { - handleDropEventByGrid(cardId, startZone, mapToGrid(dropPoint), faceDown); + handleDropEventByGrid(dragItems, startZone, mapToGrid(dropPoint), faceDown); } -void TableZone::handleDropEventByGrid(int cardId, CardZone *startZone, const QPoint &gridPoint, bool faceDown, bool tapped) +void TableZone::handleDropEventByGrid(const QList &dragItems, CardZone *startZone, const QPoint &gridPoint, bool faceDown, bool tapped) { - player->sendGameCommand(new Command_MoveCard(-1, startZone->getName(), cardId, getName(), gridPoint.x(), gridPoint.y(), faceDown, tapped)); + QList idList; + for (int i = 0; i < dragItems.size(); ++i) + idList.append(new CardId(dragItems[i]->getId())); + + startZone->getPlayer()->sendGameCommand(new Command_MoveCard(-1, startZone->getName(), idList, player->getId(), getName(), gridPoint.x(), gridPoint.y(), faceDown, tapped)); } void TableZone::reorganizeCards() @@ -103,13 +104,27 @@ void TableZone::reorganizeCards() QList arrowsToUpdate; // Calculate table grid distortion so that the mapping functions work properly - gridPointWidth.clear(); + QMap gridPointStackCount; for (int i = 0; i < cards.size(); ++i) { - QPoint gridPoint = cards[i]->getGridPos(); + const QPoint &gridPoint = cards[i]->getGridPos(); if (gridPoint.x() == -1) continue; - gridPointWidth.insert(gridPoint.x() + gridPoint.y() * 1000, CARD_WIDTH * (1 + cards[i]->getAttachedCards().size() / 3.0)); + const int key = gridPoint.x() / 3 + gridPoint.y() * 1000; + gridPointStackCount.insert(key, gridPointStackCount.value(key, 0) + 1); + } + gridPointWidth.clear(); + for (int i = 0; i < cards.size(); ++i) { + const QPoint &gridPoint = cards[i]->getGridPos(); + if (gridPoint.x() == -1) + continue; + + const int key = gridPoint.x() / 3 + gridPoint.y() * 1000; + const int stackCount = gridPointStackCount.value(key, 0); + if (stackCount == 1) + gridPointWidth.insert(key, CARD_WIDTH * (1 + cards[i]->getAttachedCards().size() / 3.0)); + else + gridPointWidth.insert(key, CARD_WIDTH * (1 + (stackCount - 1) / 3.0)); } for (int i = 0; i < cards.size(); ++i) { @@ -213,22 +228,21 @@ CardItem *TableZone::getCardFromCoords(const QPointF &point) const return getCardFromGrid(gridPoint); } -QPointF TableZone::mapFromGrid(const QPoint &gridPoint) const +QPointF TableZone::mapFromGrid(QPoint gridPoint) const { qreal x, y; - if ((gridPoint.y() == 2) && (settingsCache->getEconomicalGrid())) { - x = marginX + (CARD_WIDTH * gridPoint.x() + CARD_WIDTH * (gridPoint.x() / 3)) / 2; - y = boxLineWidth + (CARD_HEIGHT + paddingY) * gridPoint.y() + (gridPoint.x() % 3 * CARD_HEIGHT) / 3; - } else { - x = marginX + 0.5 * CARD_WIDTH * gridPoint.x(); - for (int i = 0; i < gridPoint.x(); ++i) - x += gridPointWidth.value(gridPoint.y() * 1000 + i, CARD_WIDTH); - - y = boxLineWidth + (CARD_HEIGHT + paddingY) * gridPoint.y(); - } + x = marginX + (gridPoint.x() % 3) * CARD_WIDTH / 3.0; + for (int i = 0; i < gridPoint.x() / 3; ++i) + x += gridPointWidth.value(gridPoint.y() * 1000 + i, CARD_WIDTH) + paddingX; + + if (isInverted()) + gridPoint.setY(2 - gridPoint.y()); + + y = boxLineWidth + gridPoint.y() * (CARD_HEIGHT + paddingY + 20) + (gridPoint.x() % 3) * 10; +/* if (isInverted()) y = height - CARD_HEIGHT - y; - +*/ return QPointF(x, y); } @@ -236,9 +250,9 @@ QPoint TableZone::mapToGrid(const QPointF &mapPoint) const { qreal x = mapPoint.x() - marginX; qreal y = mapPoint.y(); - if (isInverted()) +/* if (isInverted()) y = height - y; - y += paddingY / 2 - boxLineWidth; +*/ y -= boxLineWidth; if (x < 0) x = 0; @@ -249,27 +263,32 @@ QPoint TableZone::mapToGrid(const QPointF &mapPoint) const else if (y > height - CARD_HEIGHT) y = height - CARD_HEIGHT; - int resultY = (int) (y / (CARD_HEIGHT + paddingY)); + int resultY = round(y / (CARD_HEIGHT + paddingY + 20)); + if (isInverted()) + resultY = 2 - resultY; - if ((resultY == 2) && (settingsCache->getEconomicalGrid())) - return QPoint( - (int) (x * 2 / CARD_WIDTH - floor(x / (2 * CARD_WIDTH))), - 2 - ); - else { - int resultX = -1; - qreal tempX = 0; - do { - ++resultX; - tempX += gridPointWidth.value(resultY * 1000 + resultX, CARD_WIDTH) + 0.5 * CARD_WIDTH; - } while (tempX < x + 1); - return QPoint(resultX, resultY); - } + int baseX = -1; + qreal oldTempX = 0, tempX = 0; + do { + ++baseX; + oldTempX = tempX; + tempX += gridPointWidth.value(resultY * 1000 + baseX, CARD_WIDTH) + paddingX; + } while (tempX < x + 1); + + qreal xdiff = x - oldTempX; + int resultX = baseX * 3 + qMin((int) floor(xdiff * 3 / CARD_WIDTH), 2); + return QPoint(resultX, resultY); } QPointF TableZone::closestGridPoint(const QPointF &point) { - return mapFromGrid(mapToGrid(point + QPoint(CARD_WIDTH / 2, CARD_HEIGHT / 2))); + QPoint gridPoint = mapToGrid(point + QPoint(1, 1)); + gridPoint.setX((gridPoint.x() / 3) * 3); + if (getCardFromGrid(gridPoint)) + gridPoint.setX(gridPoint.x() + 1); + if (getCardFromGrid(gridPoint)) + gridPoint.setX(gridPoint.x() + 1); + return mapFromGrid(gridPoint); } void TableZone::setWidth(qreal _width) diff --git a/cockatrice/src/tablezone.h b/cockatrice/src/tablezone.h index 9f9f0650..b6566b4e 100644 --- a/cockatrice/src/tablezone.h +++ b/cockatrice/src/tablezone.h @@ -1,15 +1,16 @@ #ifndef TABLEZONE_H #define TABLEZONE_H -#include "cardzone.h" +#include "selectzone.h" -class TableZone : public CardZone { +class TableZone : public SelectZone { Q_OBJECT signals: void sizeChanged(); private: static const int boxLineWidth = 10; - static const int paddingY = 20; + static const int paddingX = 35; + static const int paddingY = 10; static const int marginX = 20; static const int minWidth = 15 * CARD_WIDTH / 2; @@ -28,11 +29,11 @@ public: QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); void toggleTapped(); - void handleDropEvent(int cardId, CardZone *startZone, const QPoint &dropPoint, bool faceDown = false); - void handleDropEventByGrid(int cardId, CardZone *startZone, const QPoint &gridPoint, bool faceDown = false, bool tapped = false); + void handleDropEvent(const QList &dragItems, CardZone *startZone, const QPoint &dropPoint, bool faceDown = false); + void handleDropEventByGrid(const QList &dragItems, CardZone *startZone, const QPoint &gridPoint, bool faceDown = false, bool tapped = false); CardItem *getCardFromGrid(const QPoint &gridPoint) const; CardItem *getCardFromCoords(const QPointF &point) const; - QPointF mapFromGrid(const QPoint &gridPoint) const; + QPointF mapFromGrid(QPoint gridPoint) const; QPoint mapToGrid(const QPointF &mapPoint) const; QPointF closestGridPoint(const QPointF &point); CardItem *takeCard(int position, int cardId, bool canResize = true); diff --git a/cockatrice/src/userinfobox.cpp b/cockatrice/src/userinfobox.cpp new file mode 100644 index 00000000..40b4b012 --- /dev/null +++ b/cockatrice/src/userinfobox.cpp @@ -0,0 +1,91 @@ +#include "userinfobox.h" +#include "protocol_datastructures.h" +#include "pixmapgenerator.h" +#include "protocol_items.h" +#include "abstractclient.h" +#include +#include + +UserInfoBox::UserInfoBox(AbstractClient *_client, bool _fullInfo, QWidget *parent, Qt::WindowFlags flags) + : QWidget(parent, flags), client(_client), fullInfo(_fullInfo) +{ + avatarLabel = new QLabel; + nameLabel = new QLabel; + QFont nameFont = nameLabel->font(); + nameFont.setBold(true); + nameFont.setPointSize(nameFont.pointSize() * 1.5); + nameLabel->setFont(nameFont); + realNameLabel1 = new QLabel; + realNameLabel2 = new QLabel; + countryLabel1 = new QLabel; + countryLabel2 = new QLabel; + userLevelLabel1 = new QLabel; + userLevelLabel2 = new QLabel; + userLevelLabel3 = new QLabel; + + QGridLayout *mainLayout = new QGridLayout; + mainLayout->addWidget(avatarLabel, 0, 0, 1, 3, Qt::AlignCenter); + mainLayout->addWidget(nameLabel, 1, 0, 1, 3); + mainLayout->addWidget(realNameLabel1, 2, 0, 1, 1); + mainLayout->addWidget(realNameLabel2, 2, 1, 1, 2); + mainLayout->addWidget(countryLabel1, 3, 0, 1, 1); + mainLayout->addWidget(countryLabel2, 3, 1, 1, 2); + mainLayout->addWidget(userLevelLabel1, 4, 0, 1, 1); + mainLayout->addWidget(userLevelLabel2, 4, 1, 1, 1); + mainLayout->addWidget(userLevelLabel3, 4, 2, 1, 1); + mainLayout->setColumnStretch(2, 10); + + setWindowTitle(tr("User information")); + setLayout(mainLayout); + retranslateUi(); +} + +void UserInfoBox::retranslateUi() +{ + realNameLabel1->setText(tr("Real name:")); + countryLabel1->setText(tr("Location:")); + userLevelLabel1->setText(tr("User level:")); +} + +void UserInfoBox::updateInfo(ServerInfo_User *user) +{ + int userLevel = user->getUserLevel(); + + QPixmap avatarPixmap; + if (!avatarPixmap.loadFromData(user->getAvatarBmp())) + avatarPixmap = UserLevelPixmapGenerator::generatePixmap(64, userLevel); + avatarLabel->setPixmap(avatarPixmap); + + nameLabel->setText(user->getName()); + realNameLabel2->setText(user->getRealName()); + countryLabel2->setPixmap(CountryPixmapGenerator::generatePixmap(15, user->getCountry())); + userLevelLabel2->setPixmap(UserLevelPixmapGenerator::generatePixmap(15, userLevel)); + QString userLevelText; + if (userLevel & ServerInfo_User::IsAdmin) + userLevelText = tr("Administrator"); + else if (userLevel & ServerInfo_User::IsJudge) + userLevelText = tr("Judge"); + else if (userLevel & ServerInfo_User::IsRegistered) + userLevelText = tr("Registered user"); + else + userLevelText = tr("Unregistered user"); + userLevelLabel3->setText(userLevelText); +} + +void UserInfoBox::updateInfo(const QString &userName) +{ + Command_GetUserInfo *command = new Command_GetUserInfo(userName); + connect(command, SIGNAL(finished(ProtocolResponse *)), this, SLOT(processResponse(ProtocolResponse *))); + client->sendCommand(command); +} + +void UserInfoBox::processResponse(ProtocolResponse *r) +{ + Response_GetUserInfo *response = qobject_cast(r); + if (!response) + return; + + updateInfo(response->getUserInfo()); + setFixedSize(sizeHint()); + show(); +} \ No newline at end of file diff --git a/cockatrice/src/userinfobox.h b/cockatrice/src/userinfobox.h new file mode 100644 index 00000000..adf5f832 --- /dev/null +++ b/cockatrice/src/userinfobox.h @@ -0,0 +1,27 @@ +#ifndef USERINFOBOX_H +#define USERINFOBOX_H + +#include + +class QLabel; +class ServerInfo_User; +class AbstractClient; +class ProtocolResponse; + +class UserInfoBox : public QWidget { + Q_OBJECT +private: + AbstractClient *client; + bool fullInfo; + QLabel *avatarLabel, *nameLabel, *realNameLabel1, *realNameLabel2, *countryLabel1, *countryLabel2, *userLevelLabel1, *userLevelLabel2, *userLevelLabel3; +public: + UserInfoBox(AbstractClient *_client, bool fullInfo, QWidget *parent = 0, Qt::WindowFlags flags = 0); + void retranslateUi(); +private slots: + void processResponse(ProtocolResponse *r); +public slots: + void updateInfo(ServerInfo_User *user); + void updateInfo(const QString &userName); +}; + +#endif \ No newline at end of file diff --git a/cockatrice/src/userlist.cpp b/cockatrice/src/userlist.cpp new file mode 100644 index 00000000..dbf8bf6e --- /dev/null +++ b/cockatrice/src/userlist.cpp @@ -0,0 +1,145 @@ +#include "userlist.h" +#include "abstractclient.h" +#include "pixmapgenerator.h" +#include "userinfobox.h" +#include +#include +#include +#include + +UserListItemDelegate::UserListItemDelegate(QObject *const parent) + : QItemDelegate(parent) +{ +} + +bool UserListItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) +{ + if ((event->type() == QEvent::MouseButtonPress) && index.isValid()) { + QMouseEvent *const mouseEvent = static_cast(event); + if (mouseEvent->button() == Qt::RightButton) { + static_cast(parent())->showContextMenu(mouseEvent->globalPos(), index); + return true; + } + } + return QItemDelegate::editorEvent(event, model, option, index); +} + +UserListTWI::UserListTWI() + : QTreeWidgetItem(Type) +{ +} + +bool UserListTWI::operator<(const QTreeWidgetItem &other) const +{ + // Equal user level => sort by name + if (data(0, Qt::UserRole) == other.data(0, Qt::UserRole)) + return data(2, Qt::UserRole).toString().toLower() < other.data(2, Qt::UserRole).toString().toLower(); + // Else sort by user level + return data(0, Qt::UserRole).toInt() > other.data(0, Qt::UserRole).toInt(); +} + +UserList::UserList(AbstractClient *_client, bool _global, QWidget *parent) + : QGroupBox(parent), client(_client), global(_global) +{ + itemDelegate = new UserListItemDelegate(this); + + userTree = new QTreeWidget; + userTree->setColumnCount(3); + userTree->header()->setResizeMode(QHeaderView::ResizeToContents); + userTree->setHeaderHidden(true); + userTree->setRootIsDecorated(false); + userTree->setIconSize(QSize(20, 12)); + userTree->setItemDelegate(itemDelegate); + connect(userTree, SIGNAL(itemActivated(QTreeWidgetItem *, int)), this, SLOT(userClicked(QTreeWidgetItem *, int))); + + QVBoxLayout *vbox = new QVBoxLayout; + vbox->addWidget(userTree); + + setLayout(vbox); + + retranslateUi(); +} + +void UserList::retranslateUi() +{ + titleStr = global ? tr("Users online: %1") : tr("Users in this room: %1"); + updateCount(); +} + +void UserList::processUserInfo(ServerInfo_User *user) +{ + QTreeWidgetItem *item = 0; + for (int i = 0; i < userTree->topLevelItemCount(); ++i) { + QTreeWidgetItem *temp = userTree->topLevelItem(i); + if (temp->data(2, Qt::UserRole) == user->getName()) { + item = temp; + break; + } + } + if (!item) { + item = new UserListTWI; + userTree->addTopLevelItem(item); + retranslateUi(); + } + item->setData(0, Qt::UserRole, user->getUserLevel()); + item->setIcon(0, QIcon(UserLevelPixmapGenerator::generatePixmap(12, user->getUserLevel()))); + item->setIcon(1, QIcon(CountryPixmapGenerator::generatePixmap(12, user->getCountry()))); + item->setData(2, Qt::UserRole, user->getName()); + item->setData(2, Qt::DisplayRole, user->getName()); +} + +bool UserList::deleteUser(const QString &userName) +{ + for (int i = 0; i < userTree->topLevelItemCount(); ++i) + if (userTree->topLevelItem(i)->data(2, Qt::UserRole) == userName) { + delete userTree->takeTopLevelItem(i); + updateCount(); + return true; + } + + return false; +} + +void UserList::updateCount() +{ + setTitle(titleStr.arg(userTree->topLevelItemCount())); +} + +void UserList::userClicked(QTreeWidgetItem *item, int /*column*/) +{ + emit openMessageDialog(item->data(2, Qt::UserRole).toString(), true); +} + +void UserList::showContextMenu(const QPoint &pos, const QModelIndex &index) +{ + const QString &userName = index.sibling(index.row(), 2).data(Qt::UserRole).toString(); + + QAction *aUserName = new QAction(userName, this); + aUserName->setEnabled(false); + QAction *aDetails = new QAction(tr("User &details"), this); + QAction *aChat = new QAction(tr("Direct &chat"), this); + + QMenu *menu = new QMenu(this); + menu->addAction(aUserName); + menu->addSeparator(); + menu->addAction(aDetails); + menu->addAction(aChat); + + QAction *actionClicked = menu->exec(pos); + if (actionClicked == aDetails) { + UserInfoBox *infoWidget = new UserInfoBox(client, true, this, Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint); + infoWidget->setAttribute(Qt::WA_DeleteOnClose); + infoWidget->updateInfo(userName); + } else if (actionClicked == aChat) + emit openMessageDialog(userName, true); + + delete menu; + delete aUserName; + delete aDetails; + delete aChat; +} + +void UserList::sortItems() +{ + userTree->sortItems(1, Qt::AscendingOrder); +} diff --git a/cockatrice/src/userlist.h b/cockatrice/src/userlist.h new file mode 100644 index 00000000..86726d67 --- /dev/null +++ b/cockatrice/src/userlist.h @@ -0,0 +1,46 @@ +#ifndef USERLIST_H +#define USERLIST_H + +#include +#include +#include + +class QTreeWidget; +class ServerInfo_User; +class AbstractClient; + +class UserListItemDelegate : public QItemDelegate { +public: + UserListItemDelegate(QObject *const parent); + bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index); +}; + +class UserListTWI : public QTreeWidgetItem { +public: + UserListTWI(); + bool operator<(const QTreeWidgetItem &other) const; +}; + +class UserList : public QGroupBox { + Q_OBJECT +private: + AbstractClient *client; + QTreeWidget *userTree; + UserListItemDelegate *itemDelegate; + bool global; + QString titleStr; + void updateCount(); +private slots: + void userClicked(QTreeWidgetItem *item, int column); +signals: + void openMessageDialog(const QString &userName, bool focus); +public: + UserList(AbstractClient *_client, bool _global, QWidget *parent = 0); + void retranslateUi(); + void processUserInfo(ServerInfo_User *user); + bool deleteUser(const QString &userName); + void showContextMenu(const QPoint &pos, const QModelIndex &index); + void sortItems(); +}; + +#endif \ No newline at end of file diff --git a/cockatrice/src/window_deckeditor.cpp b/cockatrice/src/window_deckeditor.cpp index 3b091026..e9f2f44e 100644 --- a/cockatrice/src/window_deckeditor.cpp +++ b/cockatrice/src/window_deckeditor.cpp @@ -308,8 +308,9 @@ bool WndDeckEditor::actSaveDeck() else if (deckModel->getDeckList()->saveToFile(lastFileName, lastFileFormat)) { setWindowModified(false); return true; - } else - return false; + } + QMessageBox::critical(this, tr("Error"), tr("The deck could not be saved.\nPlease check that the directory is writable and try again.")); + return false; } bool WndDeckEditor::actSaveDeckAs() @@ -332,6 +333,7 @@ bool WndDeckEditor::actSaveDeckAs() setWindowModified(false); return true; } + QMessageBox::critical(this, tr("Error"), tr("The deck could not be saved.\nPlease check that the directory is writable and try again.")); return false; } diff --git a/cockatrice/src/window_main.cpp b/cockatrice/src/window_main.cpp index d4c11b59..671738a9 100644 --- a/cockatrice/src/window_main.cpp +++ b/cockatrice/src/window_main.cpp @@ -64,15 +64,18 @@ void MainWindow::statusChanged(ClientStatus _status) aConnect->setEnabled(false); aDisconnect->setEnabled(true); break; - case StatusLoggedIn: { - tabSupervisor->start(client); + case StatusLoggedIn: break; - } default: break; } } +void MainWindow::userInfoReceived(ServerInfo_User *info) +{ + tabSupervisor->start(client, info); +} + // Actions void MainWindow::actConnect() @@ -110,7 +113,7 @@ void MainWindow::actSinglePlayer() } tabSupervisor->startLocal(localClients); - Command_CreateGame *createCommand = new Command_CreateGame(QString(), QString(), numberPlayers, false, false, false, false); + Command_CreateGame *createCommand = new Command_CreateGame(0, QString(), QString(), numberPlayers, false, false, false, false); mainClient->sendCommand(createCommand); } @@ -150,7 +153,17 @@ void MainWindow::actExit() void MainWindow::actAbout() { - QMessageBox::about(this, tr("About Cockatrice"), trUtf8("Cockatrice
Version %1


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

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


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

" + + "" + tr("Translators:") + "
" + + tr("Spanish:") + " Víctor Martínez
" + + tr("Portugese (Portugal):") + " Milton Gonçalves
" + + tr("Portugese (Brazil):") + " Thiago Queiroz
" + + tr("French:") + " Yannick Hammer
" + + tr("Japanese:") + " Takumi Nakase
" + )); } void MainWindow::serverTimeout() @@ -260,6 +273,7 @@ MainWindow::MainWindow(QWidget *parent) connect(client, SIGNAL(serverTimeout()), this, SLOT(serverTimeout())); connect(client, SIGNAL(statusChanged(ClientStatus)), this, SLOT(statusChanged(ClientStatus))); connect(client, SIGNAL(protocolVersionMismatch(int, int)), this, SLOT(protocolVersionMismatch(int, int))); + connect(client, SIGNAL(userInfoChanged(ServerInfo_User *)), this, SLOT(userInfoReceived(ServerInfo_User *))); tabSupervisor = new TabSupervisor; connect(tabSupervisor, SIGNAL(setMenu(QMenu *)), this, SLOT(updateTabMenu(QMenu *))); diff --git a/cockatrice/src/window_main.h b/cockatrice/src/window_main.h index adb4e20e..e6bcb155 100644 --- a/cockatrice/src/window_main.h +++ b/cockatrice/src/window_main.h @@ -28,6 +28,7 @@ class TabSupervisor; class RemoteClient; class LocalClient; class LocalServer; +class ServerInfo_User; class MainWindow : public QMainWindow { Q_OBJECT @@ -38,6 +39,7 @@ private slots: void serverError(ResponseCode r); void socketError(const QString &errorStr); void protocolVersionMismatch(int localVersion, int remoteVersion); + void userInfoReceived(ServerInfo_User *userInfo); void localGameEnded(); void actConnect(); diff --git a/cockatrice/src/zoneviewwidget.cpp b/cockatrice/src/zoneviewwidget.cpp index 7179be78..2f124fed 100644 --- a/cockatrice/src/zoneviewwidget.cpp +++ b/cockatrice/src/zoneviewwidget.cpp @@ -9,7 +9,7 @@ #include "protocol_items.h" #include "settingscache.h" -ZoneViewWidget::ZoneViewWidget(Player *_player, CardZone *_origZone, int numberCards, const QList &cardList) +ZoneViewWidget::ZoneViewWidget(Player *_player, CardZone *_origZone, int numberCards, bool _revealZone, const QList &cardList) : QGraphicsWidget(0, Qt::Tool | Qt::CustomizeWindowHint | Qt::WindowSystemMenuHint | Qt::WindowTitleHint/* | Qt::WindowCloseButtonHint*/), player(_player) { setAttribute(Qt::WA_DeleteOnClose); @@ -48,7 +48,7 @@ ZoneViewWidget::ZoneViewWidget(Player *_player, CardZone *_origZone, int numberC extraHeight = vbox->sizeHint(Qt::PreferredSize).height(); resize(150, 150); - zone = new ZoneViewZone(player, _origZone, numberCards, this); + zone = new ZoneViewZone(player, _origZone, numberCards, _revealZone, this); connect(zone, SIGNAL(optimumRectChanged()), this, SLOT(resizeToZoneContents())); connect(zone, SIGNAL(beingDeleted()), this, SLOT(zoneDeleted())); vbox->addItem(zone); diff --git a/cockatrice/src/zoneviewwidget.h b/cockatrice/src/zoneviewwidget.h index 71dcd754..afa63eb3 100644 --- a/cockatrice/src/zoneviewwidget.h +++ b/cockatrice/src/zoneviewwidget.h @@ -30,7 +30,7 @@ private slots: void resizeToZoneContents(); void zoneDeleted(); public: - ZoneViewWidget(Player *_player, CardZone *_origZone, int numberCards = 0, const QList &cardList = QList()); + ZoneViewWidget(Player *_player, CardZone *_origZone, int numberCards = 0, bool _revealZone = false, const QList &cardList = QList()); ZoneViewZone *getZone() const { return zone; } void retranslateUi(); protected: diff --git a/cockatrice/src/zoneviewzone.cpp b/cockatrice/src/zoneviewzone.cpp index e7fc9e13..5e3f1edc 100644 --- a/cockatrice/src/zoneviewzone.cpp +++ b/cockatrice/src/zoneviewzone.cpp @@ -3,18 +3,21 @@ #include "zoneviewzone.h" #include "player.h" #include "protocol_items.h" +#include "carddragitem.h" -ZoneViewZone::ZoneViewZone(Player *_p, CardZone *_origZone, int _numberCards, QGraphicsItem *parent) - : CardZone(_p, _origZone->getName(), false, false, true, parent, true), bRect(QRectF()), minRows(0), numberCards(_numberCards), origZone(_origZone), sortByName(false), sortByType(false) +ZoneViewZone::ZoneViewZone(Player *_p, CardZone *_origZone, int _numberCards, bool _revealZone, QGraphicsItem *parent) + : SelectZone(_p, _origZone->getName(), false, false, true, parent, true), bRect(QRectF()), minRows(0), numberCards(_numberCards), origZone(_origZone), revealZone(_revealZone), sortByName(false), sortByType(false) { - origZone->setView(this); + if (!revealZone) + origZone->setView(this); } ZoneViewZone::~ZoneViewZone() { emit beingDeleted(); qDebug("ZoneViewZone destructor"); - origZone->setView(NULL); + if (!revealZone) + origZone->setView(NULL); } QRectF ZoneViewZone::boundingRect() const @@ -30,7 +33,7 @@ void ZoneViewZone::initializeCards(const QList &cardList) { if (!cardList.isEmpty()) { for (int i = 0; i < cardList.size(); ++i) - addCard(new CardItem(player, cardList[i]->getName(), cardList[i]->getId(), this), false, i); + addCard(new CardItem(player, cardList[i]->getName(), cardList[i]->getId(), revealZone, this), false, i); reorganizeCards(); } else if (!origZone->contentsKnown()) { Command_DumpZone *command = new Command_DumpZone(-1, player->getId(), name, numberCards); @@ -41,7 +44,7 @@ void ZoneViewZone::initializeCards(const QList &cardList) int number = numberCards == -1 ? c.size() : (numberCards < c.size() ? numberCards : c.size()); for (int i = 0; i < number; i++) { CardItem *card = c.at(i); - addCard(new CardItem(player, card->getName(), card->getId(), this), false, i); + addCard(new CardItem(player, card->getName(), card->getId(), revealZone, this), false, i); } reorganizeCards(); } @@ -55,7 +58,7 @@ void ZoneViewZone::zoneDumpReceived(ProtocolResponse *r) const QList &respCardList = resp->getZone()->getCardList(); for (int i = 0; i < respCardList.size(); i++) { - CardItem *card = new CardItem(player, respCardList[i]->getName(), respCardList[i]->getId(), this); + CardItem *card = new CardItem(player, respCardList[i]->getName(), respCardList[i]->getId(), revealZone, this); addCard(card, false, i); } @@ -84,7 +87,6 @@ void ZoneViewZone::reorganizeCards() cols = 2; qDebug() << "reorganizeCards: rows=" << rows << "cols=" << cols; - qDebug() << "SORT BY NAME:" << sortByName << "SORT BY TYPE:" << sortByType; CardList cardsToDisplay(cards); if (sortByName || sortByType) @@ -122,9 +124,13 @@ void ZoneViewZone::addCardImpl(CardItem *card, int x, int /*y*/) card->update(); } -void ZoneViewZone::handleDropEvent(int cardId, CardZone *startZone, const QPoint &/*dropPoint*/, bool /*faceDown*/) +void ZoneViewZone::handleDropEvent(const QList &dragItems, CardZone *startZone, const QPoint &/*dropPoint*/, bool /*faceDown*/) { - player->sendGameCommand(new Command_MoveCard(-1, startZone->getName(), cardId, getName(), 0, 0, false)); + QList idList; + for (int i = 0; i < dragItems.size(); ++i) + idList.append(new CardId(dragItems[i]->getId())); + + player->sendGameCommand(new Command_MoveCard(-1, startZone->getName(), idList, player->getId(), getName(), 0, 0, false)); } void ZoneViewZone::removeCard(int position) diff --git a/cockatrice/src/zoneviewzone.h b/cockatrice/src/zoneviewzone.h index e331b7a2..b6fe2bfd 100644 --- a/cockatrice/src/zoneviewzone.h +++ b/cockatrice/src/zoneviewzone.h @@ -1,23 +1,24 @@ #ifndef ZONEVIEWERZONE_H #define ZONEVIEWERZONE_H -#include "cardzone.h" +#include "selectzone.h" #include class ZoneViewWidget; class ProtocolResponse; class ServerInfo_Card; -class ZoneViewZone : public CardZone, public QGraphicsLayoutItem { +class ZoneViewZone : public SelectZone, public QGraphicsLayoutItem { Q_OBJECT private: QRectF bRect, optimumRect; int minRows, numberCards; - void handleDropEvent(int cardId, CardZone *startZone, const QPoint &dropPoint, bool faceDown); + void handleDropEvent(const QList &dragItems, CardZone *startZone, const QPoint &dropPoint, bool faceDown); CardZone *origZone; + bool revealZone; bool sortByName, sortByType; public: - ZoneViewZone(Player *_p, CardZone *_origZone, int _numberCards = -1, QGraphicsItem *parent = 0); + ZoneViewZone(Player *_p, CardZone *_origZone, int _numberCards = -1, bool _revealZone = false, QGraphicsItem *parent = 0); ~ZoneViewZone(); QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); diff --git a/cockatrice/translations/cockatrice_de.ts b/cockatrice/translations/cockatrice_de.ts index f12aa06d..dae8f4bd 100644 --- a/cockatrice/translations/cockatrice_de.ts +++ b/cockatrice/translations/cockatrice_de.ts @@ -24,60 +24,92 @@ %1 sieht sich %2's %3 an + + AbstractCounter + + + &Set counter... + Zähler &setzen... + + + + Ctrl+L + Ctrl+L + + + + F11 + F11 + + + + F12 + F12 + + + + Set counter + Zähler setzen + + + + New value for counter '%1': + Neuer Wert für den Zähler '%1': + + AppearanceSettingsPage - + Zone background pictures Hintergrundbilder für Kartenzonen - + Path to hand background: Hintergrundbild für die Hand: - + Path to stack background: Hintergrundbild für den Stapel: - + Path to table background: Hintergrundbild für das Spielfeld: - + Path to player info background: Hintergrundbild für den Spielerbereich: - + Path to picture of card back: Pfad zum Bild der Kartenrückseite: - + Hand layout Kartenhand - + Display hand horizontally (wastes space) Hand horizonal anzeigen (verschwendet Platz) - + Table grid layout Spielfeldraster - Economical layout - Platzsparende Anordnung + Platzsparende Anordnung - + Invert vertical coordinate Vertikale Koordinate umkehren @@ -86,17 +118,17 @@ Platzsparende Anordnung - + Zone view layout Aussehen des Zonenbetrachters - + Sort by name nach Namen sortieren - + Sort by type nach Kartentypen sortieren @@ -105,11 +137,11 @@ standardmäßig alphabetisch sortieren - - - - - + + + + + Choose path Pfad auswählen @@ -176,112 +208,122 @@ CardItem - + + &Play + &Ausspielen + + + + &Hide + &Verstecken + + + &Tap &Tappen - + &Untap E&nttappen - + Toggle &normal untapping N&ormales Enttappen umschalten - + &Flip &Umdrehen - + &Clone &Kopieren - + &Attach to card... &An Karte anlegen... - + Ctrl+A Ctrl+A - + Unattac&h &Von Karte lösen - + Set &P/T... &Kampfwerte setzen... - + &Set annotation... &Hinweis setzen... - + red rot - + yellow gelb - + green grün - + &Add counter (%1) Zählmarke &hinzufügen (%1) - + &Remove counter (%1) Zählmarke &entfernen (%1) - + &Set counters (%1)... Zählmarken &setzen (%1)... - + &top of library &auf die Bibliothek - + &bottom of library &unter die Bibliothek - + &graveyard in den &Friedhof - + Ctrl+Del Ctrl+Del - + &exile ins &Exil - + &Move to &Verschieben @@ -613,29 +655,24 @@ ChatChannelSelector - Chat channels - Chaträume + Chaträume - Joi&n - Teil&nehmen + Teil&nehmen - Channel - Raum + Raum - Description - Beschreibung + Beschreibung - Players - Spieler + Spieler @@ -660,34 +697,28 @@ Counter - &Set counter... - Zähler &setzen... + Zähler &setzen... - Ctrl+L - Ctrl+L + Ctrl+L - F11 - F11 + F11 - F12 - F12 + F12 - Set counter - Zähler setzen + Zähler setzen - New value for counter '%1': - Neuer Wert für den Zähler '%1': + Neuer Wert für den Zähler '%1': @@ -887,7 +918,7 @@ Spiel erstellen - + Error Fehler @@ -896,7 +927,7 @@ Ungültige Anzahl an Spielern. - + Server error. Serverfehler. @@ -1069,9 +1100,9 @@ DlgSettings - - - + + + Error Fehler @@ -1088,47 +1119,47 @@ Der Pfad zum Kartenbilderverzeichnis ist ungültig. - + Your card database is invalid. Would you like to go back and set the correct path? Ihre Kartendatenbank ist ungültig. Möchten Sie zurückgehen und den korrekten Pfad einstellen? - + The path to your deck directory is invalid. Would you like to go back and set the correct path? Der Pfad zu Ihrem Deckordner ist ungültig. Möchten Sie zurückgehen und den korrekten Pfad einstellen? - + The path to your card pictures directory is invalid. Would you like to go back and set the correct path? Der Pfad zu Ihrem Kartenbilderordner ist ungültig. Möchten Sie zurückgehen und den korrekten Pfad einstellen? - + Settings Einstellungen - + General Allgemeines - + Appearance Erscheinungsbild - + User interface Bedienung - + Messages Nachrichten - + &Close S&chließen @@ -1394,20 +1425,20 @@ GameSelector - + C&reate Spiel e&rstellen - + &Join &Teilnehmen - - - - + + + + Error Fehler @@ -1416,47 +1447,51 @@ XXX - + Wrong password. Falsches Passwort. - + Spectators are not allowed in this game. In diesem Spiel sind keine Zuschauer zugelassen. - + The game is already full. Das Spiel ist bereits voll. - + The game does not exist any more. Dieses Spiel gibt es nicht mehr. - + Join game Spiel beitreten - + Password: Passwort: - + Games Spiele - - &Show full games + + Show &full games &Volle Spiele anzeigen - + &Show full games + &Volle Spiele anzeigen + + + J&oin as spectator &Zuschauen @@ -1464,7 +1499,7 @@ GameView - + Esc Esc @@ -1575,106 +1610,141 @@ MainWindow - + Number of players Spieleranzahl - + Please enter the number of players. Bitte die Spieleranzahl eingeben: - - + + Player %1 Spieler %1 - + About Cockatrice - - - - - <font size="8"><b>Cockatrice</b></font><br>Version %1<br><br><br><b>Authors:</b><br>Max-Wilhelm Bruker<br>Marcus Schütz<br>Marius van Zundert<br><br><b>Translators:</b><br>Spanish: Gocho<br>Portugese: Milton Gonçalves<br> - + Über Cockatrice + Version %1 + Version %1 + + + + Authors: + Autoren: + + + + Translators: + Übersetzer: + + + + Spanish: + Spanisch: + + + + Portugese (Portugal): + Portugiesisch (Portugal): + + + + Portugese (Brazil): + Portugiesisch (Brasilien): + + + French: + Französisch: + + + + Japanese: + Japanisch: + + - + + + Error Fehler - + Server timeout Server Zeitüberschreitung - + Invalid login data. Ungültige Anmeldedaten. - + Socket error: %1 Netzwerkfehler: %1 - + Protocol version mismatch. Local version: %1, remote version: %2. Protokollversionen stimmen nicht überein. Lokale Version: %1, Serverversion: %2. - + Connecting to %1... Verbinde zu %1... - + Disconnected nicht verbunden - + Logged in at %1 Angemeldet bei %1 - + &Connect... &Verbinden... - + &Disconnect Verbindung &trennen - + Start &local game... &Lokales Spiel starten... - + &About Cockatrice - + &Über Cockatrice - + &Help - + &Hilfe - + Are you sure? Sind Sie sicher? - + There are still open games. Are you sure you want to quit? Es gibt noch offene Spiele. Wollen Sie das Programm wirklich beenden? @@ -1691,27 +1761,27 @@ Spiel ver&lassen - + &Deck editor &Deck-Editor - + &Full screen &Vollbild - + Ctrl+F Ctrl+F - + &Settings... &Einstellungen... - + &Exit &Beenden @@ -1724,7 +1794,7 @@ Esc - + &Cockatrice &Cockatrice @@ -1808,8 +1878,8 @@ %1 zieht %2 Karten - - + + a card eine Karte @@ -2023,107 +2093,112 @@ vom Stapel - + + %1 gives %2 control over %3. + %1 überlässt %2 die Kontrolle über %3. + + + %1 puts %2 into play%3. %1 bringt %2%3 ins Spiel. - + %1 puts %2%3 into graveyard. %1 legt %2%3 auf den Friedhof. - + %1 exiles %2%3. %1 schickt %2%3 ins Exil. - + %1 moves %2%3 to hand. %1 nimmt %2%3 auf die Hand. - + %1 puts %2%3 into his library. %1 legt %2%3 in seine Bibliothek. - + %1 puts %2%3 on bottom of his library. %1 legt %2%3 unter seine Bibliothek. - + %1 puts %2%3 on top of his library. %1 legt %2%3 auf die Bibliothek. - + %1 puts %2%3 into his library at position %4. %1 legt %2%3 in seine Bibliothek an %4. Stelle. - + %1 moves %2%3 to sideboard. %1 legt %2%3 in sein Sideboard. - + %1 plays %2%3. %1 spielt %2%3 aus. - + %1 flips %2 face-down. %1 wendet %2 auf die Rückseite. - + %1 flips %2 face-up. %1 wendet %2 auf die Vorderseite. - + %1 destroys %2. %1 zerstört %2. - + %1 attaches %2 to %3's %4. %1 legt %2 an %3s %4 an. - + %1 unattaches %2. %1 löst %2 ab. - + %1 creates token: %2%3. %1 erstellt Token: %2%3. - + %1 points from %2's %3 to %4. %1 zeigt von %2s %3 auf %4. - + %1 randomly reveals %2%3 to %4. %1 zeigt %4 zufällig %2%3 vor. - + %1 randomly reveals %2%3. %1 zeigt zufällig %2%3 offen vor. - + %1 reveals %2%3 to %4. %1 zeigt %4 %2%3 vor. - + %1 reveals %2%3. %1 zeigt %2%3 offen vor. @@ -2132,12 +2207,12 @@ %1 erstellt einen Spielstein: %2 (%3). - + %1 points from %2's %3 to %4's %5. %1 zeigt von %2s %3 auf %4s %5. - + %1 places %n counter(s) (%2) on %3 (now %4). %1 legt eine Marke (%2) auf %3 (jetzt %4). @@ -2145,7 +2220,7 @@ - + %1 removes %n counter(s) (%2) from %3 (now %4). %1 entfernt eine Marke (%2) von %3 (jetzt %4). @@ -2153,37 +2228,37 @@ - + red rot - + yellow gelb - + green grün - + %1 sets counter %2 to %3 (%4%5). %1 setzt Zähler %2 auf %3 (%4%5). - + %1 sets PT of %2 to %3. %1 setzt Kampfwerte von %2 auf %3. - + %1 sets annotation of %2 to %3. %1 versieht %2 mit dem Hinweis %3. - + %1 is looking at the top %2 cards %3. %1 sieht sich die obersten %2 Karten %3 an. @@ -2280,7 +2355,7 @@ %1 entfernt %2 Zählmarken von %3 (jetzt %4). - + %1 %2 %3. %1 %2 %3. @@ -2293,22 +2368,22 @@ %1 sieht sich die obersten %2 Karten %3 an. - + %1 is looking at %2. %1 sieht sich %2 an. - + %1 stops looking at %2. %1 sieht sich %2 nicht mehr an. - + %1 reveals %2 to %3. %1 zeigt %3 %2. - + %1 reveals %2. %1 zeigt %2 offen vor. @@ -2329,7 +2404,7 @@ %1 zeigt %2 aus %3 offen vor. - + ending phase die Zugendphase @@ -2358,57 +2433,57 @@ %1 sieht sich %2s %3 nicht mehr an - + It is now %1's turn. %1 ist am Zug. - + untap step das Enttappsegment - + upkeep step das Versorgungssegment - + draw step das Ziehsegment - + first main phase die erste Hauptphase - + beginning of combat step das Anfangssegment der Kampfphase - + declare attackers step das Angreifer-Deklarieren-Segment - + declare blockers step das Blocker-Deklarieren-Segment - + combat damage step das Kampfschadenssegment - + end of combat step das Endsegment der Kampfphase - + second main phase die zweite Hauptphase @@ -2417,7 +2492,7 @@ das Ende-des-Zuges-Segment - + It is now the %1. Es ist nun %1. @@ -2426,12 +2501,12 @@ %1 bewegt %2 %3 nach %4 - + taps tappt - + untaps enttappt @@ -2456,7 +2531,7 @@ %1 entfernt %2 Zählmarken von %3 (jetzt %4) - + his permanents seine bleibenden Karten @@ -2469,12 +2544,12 @@ %1 setzt Zähler "%2" auf %3 (%4%5) - + %1 sets %2 to not untap normally. %1 setzt %2 auf explizites Enttappen. - + %1 sets %2 to untap normally. %1 setzt %2 auf normales Enttappen. @@ -2490,12 +2565,12 @@ MessagesSettingsPage - + &Add &Hinzufügen - + &Remove &Entfernen @@ -2508,12 +2583,12 @@ Entfernen - + Add message Nachricht hinzufügen - + Message: Nachricht: @@ -2521,57 +2596,57 @@ PhasesToolbar - + Untap step Enttappsegment - + Upkeep step Versorgungssegment - + Draw step Ziehsegment - + First main phase erste Hauptphase - + Beginning of combat step Anfangssegment der Kampfphase - + Declare attackers step Angreifer-Deklarieren-Segment - + Declare blockers step Blocker-Deklarieren-Segment - + Combat damage step Kampfschadenssegment - + End of combat step Endsegment der Kampfphase - + Second main phase zweite Hauptphase - + End of turn step Ende-des-Zuges-Segment @@ -2579,21 +2654,21 @@ Player - - - + + + Move to &top of library Oben auf die Biblio&thek legen - - - + + + Move to &bottom of library Unter die &Bibliothek legen - + &View library &Zeige Bibliothek @@ -2602,32 +2677,32 @@ Oberste Karten in den F&riedhof legen... - + Move top cards to &exile... Oberste Karten ins &Exil schicken... - + F3 F3 - + View &top cards of library... Zeige die oberen Kar&ten der Bibliothek... - + &View graveyard &Zeige Friedhof - + &All players &allen Spielern - + F4 F4 @@ -2636,63 +2711,68 @@ Zeige ent&fernte Karten - + &View sideboard Zeige &Sideboard - + Player "%1" Spieler "%1" - - + + Move to &graveyard Auf den &Friedhof legen - + Reveal &library to &Bibliothek jemandem zeigen - + Reveal t&op card to &Oberste Karte jemandem zeigen - + Take &mulligan &Mulligan nehmen - + Move top cards to &graveyard... Oberste Karten auf den F&riedhof legen... - + + Put top card on &bottom + Oberste Karte nach &unten legen + + + &Hand &Hand - + &Reveal to Jemandem &zeigen - + Reveal r&andom card to Z&ufällige Karte jemandem zeigen - + &Library Bib&liothek - + &Graveyard &Friedhof @@ -2701,7 +2781,7 @@ Entfe&rnte Karten - + &Sideboard &Sideboard @@ -2714,33 +2794,33 @@ &Hinweis setzen... - + View top cards of library Zeige die obersten Karten der Bibliothek - + Number of cards: Anzahl der Karten: - + &Draw card Karte &ziehen - + &View exile &Zeige Exil - + &Exile &Exil - - + + Move to &hand auf die &Hand nehmen @@ -2749,28 +2829,28 @@ auf den &Friedhof legen - - + + Move to &exile ins &Exil schicken - + Ctrl+W Ctrl+W - + Ctrl+D Ctrl+D - + D&raw cards... Ka&rten ziehen... - + Ctrl+E Ctrl+E @@ -2779,32 +2859,32 @@ &Mulligan nehmen... - + Ctrl+M Ctrl+M - + &Shuffle Mi&schen - + Ctrl+S Ctrl+S - + &Counters &Zähler - + &Untap all permanents &Enttappe alle bleibenden Karten - + Ctrl+U Ctrl+U @@ -2833,42 +2913,42 @@ Ctrl+L - + R&oll die... &Würfeln... - + Ctrl+I Ctrl+I - + &Create token... Spiels&tein erstellen... - + Ctrl+T Ctrl+T - + C&reate another token &Noch einen Spielstein erstellen - + Ctrl+G Ctrl+G - + S&ay S&agen - + C&ard &Karte @@ -2961,50 +3041,50 @@ F10 - + Draw cards Karten ziehen - - - - + + + + Number: Anzahl: - + Move top cards to grave Oberste Karten in den Friedhof legen - + Move top cards to exile Oberste Karten ins Exil schicken - + Set power/toughness Kampfwerte setzen - + Please enter the new PT: Bitte die neuen Kampfwerte eingeben: - + Set annotation Hinweis setzen - + Please enter the new annotation: Bitte den Hinweis eingeben: - + Set counters Setze Zählmarken @@ -3017,12 +3097,12 @@ Neue Lebenspunkte insgesamt: - + Roll die Würfeln - + Number of sides: Anzahl der Seiten: @@ -3100,17 +3180,17 @@ Sideboard - + Cockatrice decks (*.cod) Cockatrice Decks (*.cod) - + Plain text decks (*.dec *.mwDeck) Text Decks (*.dec *.mwDeck) - + All files (*.*) Alle Dateien (*.*) @@ -3133,12 +3213,44 @@ Änderungsdatum + + RoomSelector + + + Rooms + Räume + + + + Joi&n + Teil&nehmen + + + + Room + Raum + + + + Description + Beschreibung + + + + Players + Spieler + + + + Games + Spiele + + ServerMessageLog - Server messages - Servernachrichten + Servernachrichten @@ -3154,27 +3266,61 @@ Langer Name + + TabAdmin + + + Update server &message + Server&nachricht aktualisieren + + + + Server administration functions + Funktionen zur Serverwartung + + + + &Unlock functions + &Sperre aufheben + + + + &Lock functions + Funktionen s&perren + + + + Unlock administration functions + Wartungsfunktionen entsperren + + + + Do you really want to unlock the administration functions? + Möchten Sie wirklich die Sperre der Wartungsfunktionen aufheben? + + + + Administration + Wartung + + TabChatChannel - C&hat channel - C&hatraum + C&hatraum - &Leave channel - Raum ver&lassen + Raum ver&lassen - %1 has joined the channel. - %1 hat den Raum betreten. + %1 hat den Raum betreten. - %1 has left the channel. - %1 hat den Raum verlassen. + %1 hat den Raum verlassen. @@ -3248,57 +3394,57 @@ Bitte geben Sie einen Namen ein: TabGame - + &Game Spi&el - + Next &phase Nächste &Phase - + Ctrl+Space Ctrl+Space - + Next &turn Nächster &Zug - + Ctrl+Return Ctrl+Return - + Ctrl+Enter Ctrl+Enter - + &Remove all local arrows &Lokale Pfeile entfernen - + Ctrl+R Ctrl+R - + &Concede - + F2 F2 - + &Leave game Spiel ver&lassen @@ -3319,7 +3465,7 @@ Bitte geben Sie einen Namen ein: Spiel s&tarten - + &Say: &Sagen: @@ -3332,22 +3478,22 @@ Bitte geben Sie einen Namen ein: Esc - + Concede Aufgeben - + Are you sure you want to concede this game? Sind Sie sicher, dass Sie das Spiel aufgeben möchten? - + Leave game Spiel verlassen - + Are you sure you want to leave this game? Sind Sie sicher, dass Sie das Spiel verlassen möchten? @@ -3356,7 +3502,7 @@ Bitte geben Sie einen Namen ein: Deck laden - + Game %1: %2 Spiel %1: %2 @@ -3384,10 +3530,43 @@ Bitte geben Sie einen Namen ein: Gespräch mit %1 + + TabRoom + + + &Say: + &Sagen: + + + + Chat + Unterhaltung + + + + &Room + &Raum + + + + &Leave room + Raum ver&lassen + + + + %1 has joined the room. + %1 hat den Raum betreten. + + + + %1 has left the room. + %1 hat den Raum verlassen. + + TabServer - + Server Server @@ -3410,35 +3589,65 @@ Bitte geben Sie einen Namen ein: UserInfoBox - + + User information + Benutzerinformationen + + + + Real name: + Richtiger Name: + + + Location: Ort: - + User level: Nutzerstatus: + + + Administrator + Administrator + + + + Judge + Schiedsrichter + + + + Registered user + Registrierter Benutzer + + + + Unregistered user + Unregistrierter Benutzer + UserInterfaceSettingsPage - + General interface settings Allgemeine Bedienung - + &Double-click cards to play them (instead of single-click) Karten durch &Doppelklick ausspielen (statt Einzelklick) - + Animation settings Animationseinstellungen - + &Tap/untap animation Animiertes &Tappen/Enttappen @@ -3446,10 +3655,25 @@ Bitte geben Sie einen Namen ein: UserList - + Users online: %1 Benutzer online: %1 + + + Users in this room: %1 + Benutzer in diesem Raum: %1 + + + + User &details + Benutzer&details + + + + Direct &chat + &Persönliches Gespräch + WndDeckEditor @@ -3637,7 +3861,21 @@ Willst du die Änderungen speichern? Deck laden - + + + Error + Fehler + + + + + The deck could not be saved. +Please check that the directory is writable and try again. + Das Deck konnte nicht gespeichert werden. +Bitte überprüfen Sie, dass Sie Schreibrechte in dem Verzeichnis haben, und versuchen Sie es erneut. + + + Save deck Deck speichern diff --git a/cockatrice/translations/cockatrice_en.ts b/cockatrice/translations/cockatrice_en.ts index 60ebb47d..a47980be 100644 --- a/cockatrice/translations/cockatrice_en.ts +++ b/cockatrice/translations/cockatrice_en.ts @@ -1,84 +1,112 @@ + + AbstractCounter + + + &Set counter... + + + + + Ctrl+L + + + + + F11 + + + + + F12 + + + + + Set counter + + + + + New value for counter '%1': + + + AppearanceSettingsPage - + Zone background pictures - + Path to hand background: - + Path to stack background: - + Path to table background: - + Path to player info background: - + Path to picture of card back: - + Hand layout - + Display hand horizontally (wastes space) - + Table grid layout - - Economical layout - - - - + Invert vertical coordinate - + Zone view layout - + Sort by name - + Sort by type - - - - - + + + + + Choose path @@ -137,112 +165,122 @@ CardItem - + + &Play + + + + + &Hide + + + + &Tap - + &Untap - + Toggle &normal untapping - + &Flip - + &Clone - + &Attach to card... - + Ctrl+A - + Unattac&h - + Set &P/T... - + &Set annotation... - + red - + yellow - + green - + &Add counter (%1) - + &Remove counter (%1) - + &Set counters (%1)... - + &top of library - + &bottom of library - + &graveyard - + Ctrl+Del - + &exile - + &Move to @@ -430,67 +468,6 @@ - - ChatChannelSelector - - - Chat channels - - - - - Joi&n - - - - - Channel - - - - - Description - - - - - Players - - - - - Counter - - - &Set counter... - - - - - Ctrl+L - - - - - F11 - - - - - F12 - - - - - Set counter - - - - - New value for counter '%1': - - - DeckListModel @@ -669,12 +646,12 @@ - + Error - + Server error. @@ -816,54 +793,54 @@ DlgSettings - - - + + + Error - + Your card database is invalid. Would you like to go back and set the correct path? - + The path to your deck directory is invalid. Would you like to go back and set the correct path? - + The path to your card pictures directory is invalid. Would you like to go back and set the correct path? - + Settings - + General - + Appearance - + User interface - + Messages - + &Close @@ -871,65 +848,65 @@ GameSelector - + C&reate - + &Join - - - - + + + + Error - + Wrong password. - + Spectators are not allowed in this game. - + The game is already full. - + The game does not exist any more. - + Join game - + Password: - + Games - - &Show full games + + Show &full games - + J&oin as spectator @@ -937,7 +914,7 @@ GameView - + Esc @@ -1044,136 +1021,171 @@ MainWindow - + Number of players - + Please enter the number of players. - - + + Player %1 - + About Cockatrice - - - <font size="8"><b>Cockatrice</b></font><br>Version %1<br><br><br><b>Authors:</b><br>Max-Wilhelm Bruker<br>Marcus Schütz<br>Marius van Zundert<br><br><b>Translators:</b><br>Spanish: Gocho<br>Portugese: Milton Gonçalves<br> - - + Version %1 + + + + + Authors: + + + + + Translators: + + + + + Spanish: + + + + + Portugese (Portugal): + + + + + Portugese (Brazil): + + + + French: + + + + + Japanese: + + + - + + + Error - + Server timeout - + Invalid login data. - + Socket error: %1 - + Protocol version mismatch. Local version: %1, remote version: %2. - + Connecting to %1... - + Disconnected - + Logged in at %1 - + &Connect... - + &Disconnect - + Start &local game... - + &Deck editor - + &Full screen - + Ctrl+F - + &Settings... - + &Exit - + &Cockatrice - + &About Cockatrice - + &Help - + Are you sure? - + There are still open games. Are you sure you want to quit? @@ -1281,88 +1293,93 @@ - + + %1 gives %2 control over %3. + + + + %1 puts %2 into play%3. - + %1 puts %2%3 into graveyard. - + %1 exiles %2%3. - + %1 moves %2%3 to hand. - + %1 puts %2%3 into his library. - + %1 puts %2%3 on bottom of his library. - + %1 puts %2%3 on top of his library. - + %1 puts %2%3 into his library at position %4. - + %1 moves %2%3 to sideboard. - + %1 plays %2%3. - - + + a card - + %1 flips %2 face-down. - + %1 flips %2 face-up. - + %1 attaches %2 to %3's %4. - + %1 unattaches %2. - + %1 points from %2's %3 to %4's %5. - + %1 places %n counter(s) (%2) on %3 (now %4). %1 places a counter (%2) on %3 (now %4). @@ -1370,7 +1387,7 @@ - + %1 removes %n counter(s) (%2) from %3 (now %4). %1 removes a counter (%2) from %3 (now %4). @@ -1378,37 +1395,37 @@ - + red - + yellow - + green - + %1 sets counter %2 to %3 (%4%5). - + %1 sets PT of %2 to %3. - + %1 sets annotation of %2 to %3. - + %1 is looking at the top %2 cards %3. @@ -1473,52 +1490,52 @@ - + %1 destroys %2. - + %1 creates token: %2%3. - + %1 points from %2's %3 to %4. - + %1 %2 %3. - + %1 is looking at %2. - + %1 stops looking at %2. - + %1 reveals %2 to %3. - + %1 reveals %2. - + ending phase - + It is now %1's turn. @@ -1528,102 +1545,102 @@ - + %1 randomly reveals %2%3 to %4. - + %1 randomly reveals %2%3. - + %1 reveals %2%3 to %4. - + %1 reveals %2%3. - + untap step - + upkeep step - + draw step - + first main phase - + beginning of combat step - + declare attackers step - + declare blockers step - + combat damage step - + end of combat step - + second main phase - + It is now the %1. - + taps - + untaps - + %1 sets %2 to not untap normally. - + %1 sets %2 to untap normally. - + his permanents @@ -1631,22 +1648,22 @@ MessagesSettingsPage - + &Add - + &Remove - + Add message - + Message: @@ -1654,57 +1671,57 @@ PhasesToolbar - + Untap step - + Upkeep step - + Draw step - + First main phase - + Beginning of combat step - + Declare attackers step - + Declare blockers step - + Combat damage step - + End of combat step - + Second main phase - + End of turn step @@ -1712,302 +1729,307 @@ Player - - - - Move to &top of library - - - - - Move to &bottom of library - - - - - - Move to &graveyard - - - - - &View library - - - - - Reveal &library to - - - - - Reveal t&op card to - - - - - Move top cards to &graveyard... - - - - - F3 - - - - View &top cards of library... - - - - - &View graveyard - - - - - F4 - - - - - &View sideboard - - - - - Player "%1" - - - - - &Hand - - - - - &Library - - - - - &Graveyard - - - - - &Sideboard - - - - - View top cards of library - - - - - Number of cards: - - - - - &Draw card - - - - - &View exile - - - - - &Exile + Move to &top of library - Move to &hand + + Move to &bottom of library - - Move to &exile + + Move to &graveyard - - Ctrl+W - - - - - Ctrl+D - - - - - D&raw cards... - - - - - Ctrl+E + + &View library - Take &mulligan - - - - - Ctrl+M + Reveal &library to - &Shuffle - - - - - Ctrl+S - - - - - &Counters - - - - - &Untap all permanents - - - - - Ctrl+U - - - - - R&oll die... - - - - - Ctrl+I - - - - - &Create token... - - - - - Ctrl+T - - - - - C&reate another token - - - - - Ctrl+G - - - - - S&ay - - - - - Move top cards to &exile... - - - - - &Reveal to + Reveal t&op card to - Reveal r&andom card to + Move top cards to &graveyard... + + + + + F3 + + + + + View &top cards of library... + + + + + &View graveyard + + + + + F4 + + + + + &View sideboard + + + + + Player "%1" + + + + + &Hand + + + + + &Library + + + + + &Graveyard + + + + + &Sideboard + + + + + View top cards of library + + + + + Number of cards: + + + + + &Draw card + + + + + &View exile + + + + + &Exile + + + + + + Move to &hand + + + + + + Move to &exile + + + + + Ctrl+W + + + + + Ctrl+D + + + + + D&raw cards... + + + + + Ctrl+E + + + + + Take &mulligan + + + + + Ctrl+M + + + + + &Shuffle + + + + + Ctrl+S + + + + + &Counters + + + + + &Untap all permanents + + + + + Ctrl+U + + + + + R&oll die... + + + + + Ctrl+I + + + + + &Create token... + + + + + Ctrl+T + + + + + C&reate another token + + + + + Ctrl+G + S&ay + + + + + Move top cards to &exile... + + + + + Put top card on &bottom + + + + + &Reveal to + + + + + Reveal r&andom card to + + + + C&ard - + &All players - + Draw cards - - - - + + + + Number: - + Move top cards to grave - + Move top cards to exile - + Roll die - + Number of sides: - + Set power/toughness - + Please enter the new PT: - + Set annotation - + Please enter the new annotation: - + Set counters @@ -2053,17 +2075,17 @@ - + Cockatrice decks (*.cod) - + Plain text decks (*.dec *.mwDeck) - + All files (*.*) @@ -2087,10 +2109,35 @@ - ServerMessageLog + RoomSelector - - Server messages + + Rooms + + + + + Joi&n + + + + + Room + + + + + Description + + + + + Players + + + + + Games @@ -2108,25 +2155,40 @@ - TabChatChannel + TabAdmin - - C&hat channel + + Update server &message - - &Leave channel + + Server administration functions - - %1 has joined the channel. + + &Unlock functions - - %1 has left the channel. + + &Lock functions + + + + + Unlock administration functions + + + + + Do you really want to unlock the administration functions? + + + + + Administration @@ -2200,87 +2262,87 @@ Please enter a name: TabGame - + &Game - + Next &phase - + Ctrl+Space - + Next &turn - + Ctrl+Return - + Ctrl+Enter - + &Remove all local arrows - + Ctrl+R - + &Concede - + F2 - + &Leave game - + &Say: - + Concede - + Are you sure you want to concede this game? - + Leave game - + Are you sure you want to leave this game? - + Game %1: %2 @@ -2308,10 +2370,43 @@ Please enter a name: + + TabRoom + + + &Say: + + + + + Chat + + + + + &Room + + + + + &Leave room + + + + + %1 has joined the room. + + + + + %1 has left the room. + + + TabServer - + Server @@ -2319,35 +2414,65 @@ Please enter a name: UserInfoBox - + + User information + + + + + Real name: + + + + Location: - + User level: + + + Administrator + + + + + Judge + + + + + Registered user + + + + + Unregistered user + + UserInterfaceSettingsPage - + General interface settings - + &Double-click cards to play them (instead of single-click) - + Animation settings - + &Tap/untap animation @@ -2355,10 +2480,25 @@ Please enter a name: UserList - + Users online: %1 + + + Users in this room: %1 + + + + + User &details + + + + + Direct &chat + + WndDeckEditor @@ -2443,7 +2583,20 @@ Please enter a name: - + + + Error + + + + + + The deck could not be saved. +Please check that the directory is writable and try again. + + + + Save deck diff --git a/cockatrice/translations/cockatrice_es.ts b/cockatrice/translations/cockatrice_es.ts index 0457d2f2..44daecba 100644 --- a/cockatrice/translations/cockatrice_es.ts +++ b/cockatrice/translations/cockatrice_es.ts @@ -1,60 +1,92 @@ + + AbstractCounter + + + &Set counter... + E&stablecer contadores... + + + + Ctrl+L + Ctrl+L + + + + F11 + F11 + + + + F12 + F12 + + + + Set counter + Establecer contador + + + + New value for counter '%1': + Nuevo valor para el contador '%1': + + AppearanceSettingsPage - + Zone background pictures Imagenes de la zona de fondo - + Path to hand background: Ruta a la imagen de fondo de la mano: - + Path to stack background: Ruta a la imagen de fondo de la pila: - + Path to table background: Ruta a la imagen de fondo de la mesa: - + Path to player info background: Ruta a la imagen de fondo de la información del jugador: - + Path to picture of card back: Ruta al reverso de las cartas: - + Hand layout Disposición de la mano - + Display hand horizontally (wastes space) Mostrar la mano horizontalmente (desperdicia espacio) - + Table grid layout Disposición de la rejilla de la mesa - Economical layout - Disposición Económica + Disposición Económica - + Invert vertical coordinate Invertir coordenada vertical @@ -63,26 +95,26 @@ Disposición económica - + Zone view layout Distribución de la zona de visionado - + Sort by name Ordenar por nombre - + Sort by type Ordenar por tipo - - - - - + + + + + Choose path Elija ruta @@ -141,112 +173,122 @@ CardItem - + + &Play + + + + + &Hide + + + + &Tap &Girar - + &Untap &Enderezar - + Toggle &normal untapping Alternar enderezamiento &normal - + &Flip &Voltear - + &Clone &Clonar - + &Attach to card... Ane&xar a una carta... - + Ctrl+A Ctrl+A - + Unattac&h Desane&xar - + Set &P/T... Establecer &F/R... - + &Set annotation... E&scribir anotación... - + red rojo - + yellow amarillo - + green verde - + &Add counter (%1) &Añadir contador (%1) - + &Remove counter (%1) &Quitar contador (%1) - + &Set counters (%1)... E&stablecer contadores (%1)... - + &top of library &parte superior de la biblioteca - + &bottom of library &fondo de la biblioteca - + &graveyard &cementerio - + Ctrl+Del Ctrl+Del - + &exile &exilio - + &Move to &Mover a @@ -567,62 +609,51 @@ ChatChannelSelector - Chat channels - Canales de Chat + Canales de Chat - Joi&n - E&ntrar + E&ntrar - Channel - Canal + Canal - Description - Descripción + Descripción - Players - Jugadores + Jugadores Counter - &Set counter... - E&stablecer contadores... + E&stablecer contadores... - Ctrl+L - Ctrl+L + Ctrl+L - F11 - F11 + F11 - F12 - F12 + F12 - Set counter - Establecer contador + Establecer contador - New value for counter '%1': - Nuevo valor para el contador '%1': + Nuevo valor para el contador '%1': @@ -803,12 +834,12 @@ Crear partida - + Error Error - + Server error. Error del servidor. @@ -950,9 +981,9 @@ DlgSettings - - - + + + Error Error @@ -969,47 +1000,47 @@ La ruta a tu directorio de imagenes de las cartas es invalida. - + Your card database is invalid. Would you like to go back and set the correct path? Tu base de datos de cartas es invalida. ¿Deseas volver y seleccionar la ruta correcta? - + The path to your deck directory is invalid. Would you like to go back and set the correct path? La ruta a tu directorio de mazos es invalida. ¿Deseas volver y seleccionar la ruta correcta? - + The path to your card pictures directory is invalid. Would you like to go back and set the correct path? La ruta a tu directorio de imagenes de las cartas es invalida.¿Deseas volver y seleccionar la ruta correcta? - + Settings Preferencias - + General General - + Appearance Apariencia - + User interface Interfaz de usuario - + Messages Mensajes - + &Close &Cerrar @@ -1017,65 +1048,69 @@ GameSelector - + C&reate C&rear - + &Join E&ntrar - - - - + + + + Error Error - + Wrong password. Contraseña incorrecta. - + Spectators are not allowed in this game. No se permiten espectadores en esta partida. - + The game is already full. La partida no tiene plazas libres. - + The game does not exist any more. La partida ya no existe. - + Join game Entrar en la partida - + Password: Contraseña: - + Games Partidas - - &Show full games - &Ver partidas sin plazas libres + + Show &full games + - + &Show full games + &Ver partidas sin plazas libres + + + J&oin as spectator Entrar como e&spectador @@ -1083,7 +1118,7 @@ GameView - + Esc Esc @@ -1190,136 +1225,171 @@ MainWindow - + Number of players Número de jugadores - + Please enter the number of players. Por favor, introduzca el número de jugadores. - - + + Player %1 Jugador %1 - + About Cockatrice Acerca de Cockatrice - - - <font size="8"><b>Cockatrice</b></font><br>Version %1<br><br><br><b>Authors:</b><br>Max-Wilhelm Bruker<br>Marcus Schütz<br>Marius van Zundert<br><br><b>Translators:</b><br>Spanish: Gocho<br>Portugese: Milton Gonçalves<br> - - + Version %1 + + + + + Authors: + + + + + Translators: + + + + + Spanish: + + + + + Portugese (Portugal): + + + + + Portugese (Brazil): + + + + French: + + + + + Japanese: + + + - + + + Error Error - + Server timeout Tiempo de espera del servidor agotado - + Invalid login data. Datos de conexión invalidos. - + Socket error: %1 Error del Socket: %1 - + Protocol version mismatch. Local version: %1, remote version: %2. La versión del protocolo es diferente. Version local: %1, version remota: %2. - + Connecting to %1... Conectando a %1... - + Disconnected Desconectado - + Logged in at %1 Conectado en %1 - + &Connect... &Conectar... - + &Disconnect &Desconectar - + Start &local game... Empezar partida &local... - + &Deck editor Editor de &mazos - + &Full screen &Pantalla completa - + Ctrl+F CTRL+F - + &Settings... &Preferencias... - + &Exit &Salir - + &Cockatrice &Cockatrice - + &About Cockatrice &Acerca de Cockatrice - + &Help A&yuda - + Are you sure? ¿Estás seguro? - + There are still open games. Are you sure you want to quit? Todavía hay partidas abiertas. ¿Estás seguro que quieres salir? @@ -1427,88 +1497,93 @@ de la pila - + + %1 gives %2 control over %3. + + + + %1 puts %2 into play%3. %1 pone %2 en juego%3. - + %1 puts %2%3 into graveyard. %1 pone %2%3 en el cementerio. - + %1 exiles %2%3. %1 exilia %2%3. - + %1 moves %2%3 to hand. %1 mueve %2%3 a la mano. - + %1 puts %2%3 into his library. %1 pone %2%3 en la biblioteca. - + %1 puts %2%3 on bottom of his library. %1 pone %2%3 en la parte inferior de su biblioteca. - + %1 puts %2%3 on top of his library. %1 pone %2%3 en la parte superior de su biblioteca. - + %1 puts %2%3 into his library at position %4. %1 pone %2%3 en su biblioteca en la posición %4. - + %1 moves %2%3 to sideboard. %1 mueve %2%3 a la reserva. - + %1 plays %2%3. %1 juega %2%3. - - + + a card una carta - + %1 flips %2 face-down. %1 voltea %2 boca abajo. - + %1 flips %2 face-up. %1 voltea %2 boca arriba. - + %1 attaches %2 to %3's %4. %1 anexa %2 a el %4 de %3. - + %1 unattaches %2. %1 desanexa %2. - + %1 points from %2's %3 to %4's %5. %1 apunta desde el %3 de %2 al %5 de %4. - + %1 places %n counter(s) (%2) on %3 (now %4). %1 pone un contador (%2) en %3 (ahora %4). @@ -1516,7 +1591,7 @@ - + %1 removes %n counter(s) (%2) from %3 (now %4). %1 remueve un contador (%2) de %3 (ahora %4). @@ -1524,37 +1599,37 @@ - + red rojo - + yellow amarillo - + green verde - + %1 sets counter %2 to %3 (%4%5). %1 establece los contadores de %2 a %3 (%4%5). - + %1 sets PT of %2 to %3. %1 establece F/R de %2 a %3. - + %1 sets annotation of %2 to %3. %1 establece la anotación de %2 a %3. - + %1 is looking at the top %2 cards %3. %1 esta mirando las primeras %2 cartas de %3. @@ -1619,52 +1694,52 @@ %1 roba %2 cartas. - + %1 destroys %2. %1 destruye %2. - + %1 creates token: %2%3. %1 crea una ficha: %2%3. - + %1 points from %2's %3 to %4. %1 apunta desde el %3 de %2 a %4. - + %1 %2 %3. %1 %2 %3. - + %1 is looking at %2. %1 está mirando: %2. - + %1 stops looking at %2. %1 termina de mirar: %2. - + %1 reveals %2 to %3. %1 revela %2 a %3. - + %1 reveals %2. %1 revela %2. - + ending phase fase de fin de turno - + It is now %1's turn. Es el turno de %1. @@ -1674,102 +1749,102 @@ %1 baraja su biblioteca. - + %1 randomly reveals %2%3 to %4. %1 revela aleatoriamente %2%3 a %4. - + %1 randomly reveals %2%3. %1 revela aleatoriamente %2%3. - + %1 reveals %2%3 to %4. %1 revela %2%3 a %4. - + %1 reveals %2%3. %1 revela %2%3. - + untap step paso de enderezar - + upkeep step paso de mantenimiento - + draw step paso de robar - + first main phase primera fase principal - + beginning of combat step paso de inicio de combate - + declare attackers step paso de declarar atacantes - + declare blockers step paso de declarar bloqueadores - + combat damage step paso de daño de combate - + end of combat step paso de fin de combate - + second main phase segunda fase principal - + It is now the %1. Ahora es el %1. - + taps gira - + untaps endereza - + %1 sets %2 to not untap normally. %1 establece que %2 no se endereze normalmente. - + %1 sets %2 to untap normally. %1 establece que %2 se endereze normalmente. - + his permanents sus permanentes @@ -1777,22 +1852,22 @@ MessagesSettingsPage - + &Add &Añadir - + &Remove &Quitar - + Add message Añadir mensaje - + Message: Mensaje: @@ -1800,57 +1875,57 @@ PhasesToolbar - + Untap step Paso de enderezar - + Upkeep step Paso de mantenimiento - + Draw step Paso de robar - + First main phase Primera fase principal - + Beginning of combat step Paso de inicio del combate - + Declare attackers step Paso de declarar atacantes - + Declare blockers step Paso de declarar bloqueadores - + Combat damage step Paso de daño de combate - + End of combat step Paso de final del combate - + Second main phase Segunda fase principal - + End of turn step Paso final @@ -1858,123 +1933,123 @@ Player - - - + + + Move to &top of library Mover a la &parte superior de la biblioteca - - - + + + Move to &bottom of library Mover al &fondo de la biblioteca - - + + Move to &graveyard Mover al &cementerio - + &View library &Ver biblioteca - + Reveal &library to Revelar &biblioteca a - + Reveal t&op card to Revelar la carta &superior de la biblioteca a - + Move top cards to &graveyard... Mover cartas de la parte s&uperior de la biblioteca al cementerio... - + F3 F3 - + View &top cards of library... Ver cartas de la parte &superior de la biblioteca... - + &View graveyard Ver &Cementerio - + F4 F4 - + &View sideboard Ver &sideboard - + Player "%1" Jugador "%1" - + &Hand &Mano - + &Library &Biblioteca - + &Graveyard &Cementerio - + &Sideboard &Reserva - + View top cards of library Ver cartas de la parte superior de la biblioteca - + Number of cards: Número de cartas: - + &Draw card &Robar carta - + &View exile Ver &exilio - + &Exile &Exilio - - + + Move to &hand Mover a la m&ano @@ -1983,98 +2058,98 @@ Mover al &cementerio - - + + Move to &exile Mover al &exilio - + Ctrl+W Ctrl+W - + Ctrl+D Ctrl+D - + D&raw cards... &Robar cartas... - + Ctrl+E Ctrl+E - + Take &mulligan Hacer &mulligan - + Ctrl+M Ctrl+M - + &Shuffle &Barajar - + Ctrl+S Ctrl+S - + &Counters &Contadores - + &Untap all permanents &Enderezar todos los permanentes - + Ctrl+U Ctrl+U - + R&oll die... &Lanzar dado... - + Ctrl+I Ctrl+I - + &Create token... Crear &Ficha... - + Ctrl+T Ctrl+T - + C&reate another token C&rea otra ficha - + Ctrl+G Ctrl+G - + S&ay D&ecir @@ -2083,85 +2158,90 @@ Mover cartas superiores al ce&menterio... - + Move top cards to &exile... Mover cartas superiores al &exilio... - + + Put top card on &bottom + + + + &Reveal to &Revelar a - + Reveal r&andom card to Revelar carta &aleatoriamente a - + C&ard C&arta - + &All players &Todos los jugadores - + Draw cards Robar cartas - - - - + + + + Number: Número: - + Move top cards to grave Mover cartas superiores al cementerio - + Move top cards to exile Mover cartas superiores al exilio - + Roll die Lanzar dado - + Number of sides: Número de caras: - + Set power/toughness Establecer fuerza/resistencia - + Please enter the new PT: Por favor, introduzca la nueva F/R: - + Set annotation Escribir anotación - + Please enter the new annotation: Por favor, introduza la nueva anotación: - + Set counters Establecer contadores @@ -2219,17 +2299,17 @@ Reserva - + Cockatrice decks (*.cod) Mazos de Cockatrice (*.cod) - + Plain text decks (*.dec *.mwDeck) Archivos de texto plano (*.dec *.mwDeck) - + All files (*.*) Todos los archivos (*.*) @@ -2252,12 +2332,44 @@ Tiempo de subida + + RoomSelector + + + Rooms + + + + + Joi&n + E&ntrar + + + + Room + + + + + Description + Descripción + + + + Players + Jugadores + + + + Games + Partidas + + ServerMessageLog - Server messages - Mensajes del servidor + Mensajes del servidor @@ -2273,27 +2385,61 @@ Nombre largo + + TabAdmin + + + Update server &message + + + + + Server administration functions + + + + + &Unlock functions + + + + + &Lock functions + + + + + Unlock administration functions + + + + + Do you really want to unlock the administration functions? + + + + + Administration + + + TabChatChannel - C&hat channel - Canal de c&hat + Canal de c&hat - &Leave channel - &Abandonar el canal + &Abandonar el canal - %1 has joined the channel. - %1 se ha unido al canal. + %1 se ha unido al canal. - %1 has left the channel. - %1 ha abandonado el canal. + %1 ha abandonado el canal. @@ -2367,87 +2513,87 @@ Por favor, introduzca un nombre: TabGame - + &Game &Partida - + Next &phase Próxima &fase - + Ctrl+Space Ctrl+Space - + Next &turn Próximo &turno - + Ctrl+Return Ctrl+Return - + Ctrl+Enter Ctrl+Enter - + &Remove all local arrows &Retirar todas las flechas locales - + Ctrl+R Ctrl+R - + &Concede &Conceder - + F2 F2 - + &Leave game &Abandonar la partida - + &Say: &Decir: - + Concede Conceder - + Are you sure you want to concede this game? ¿Estás seguro de que quieres conceder esta partida? - + Leave game Abandonar la partida - + Are you sure you want to leave this game? ¿Estás seguro de que quieres abandonar la partida? - + Game %1: %2 Partida %1: %2 @@ -2475,10 +2621,43 @@ Por favor, introduzca un nombre: Hablando con %1 + + TabRoom + + + &Say: + &Decir: + + + + Chat + + + + + &Room + + + + + &Leave room + + + + + %1 has joined the room. + + + + + %1 has left the room. + + + TabServer - + Server Servidor @@ -2486,35 +2665,65 @@ Por favor, introduzca un nombre: UserInfoBox - + + User information + + + + + Real name: + + + + Location: Localización: - + User level: Nivel de usuario: + + + Administrator + + + + + Judge + + + + + Registered user + + + + + Unregistered user + + UserInterfaceSettingsPage - + General interface settings Preferencias generales de la interfaz - + &Double-click cards to play them (instead of single-click) &Doble click en las cartas para jugarlas (en lugar de un solo click) - + Animation settings Opciones de animación - + &Tap/untap animation Animación de &girar/enderezar @@ -2522,10 +2731,25 @@ Por favor, introduzca un nombre: UserList - + Users online: %1 Usuarios online: %1 + + + Users in this room: %1 + + + + + User &details + + + + + Direct &chat + + WndDeckEditor @@ -2610,7 +2834,20 @@ Por favor, introduzca un nombre: Cargar mazo - + + + Error + Error + + + + + The deck could not be saved. +Please check that the directory is writable and try again. + + + + Save deck Guardar mazo diff --git a/cockatrice/translations/cockatrice_fr.ts b/cockatrice/translations/cockatrice_fr.ts index 53f8d1ad..04f53a8b 100644 --- a/cockatrice/translations/cockatrice_fr.ts +++ b/cockatrice/translations/cockatrice_fr.ts @@ -1,86 +1,114 @@ + + AbstractCounter + + + &Set counter... + &Fixer les compteurs + + + + Ctrl+L + Ctrl+L + + + + F11 + F11 + + + + F12 + F12 + + + + Set counter + Fixer compteurs + + + + New value for counter '%1': + Nouvelle valeur pour le compteur '%1': + + AppearanceSettingsPage - + Zone background pictures - + Path to hand background: - + Chemin vers fond de la main - + Path to stack background: - + Path to table background: - + Path to player info background: - + Path to picture of card back: - + Hand layout - + Display hand horizontally (wastes space) - + Table grid layout - - Economical layout - - - - + Invert vertical coordinate - + Zone view layout - + Voir disposition de la zone - + Sort by name - + tri par nom - + Sort by type - + tri par type - - - - - + + + + + Choose path - + Choisir le chemin @@ -88,27 +116,27 @@ Name - + Nom Sets - + Sets Mana cost - + Cout de mana Card type - + Type de carte P/T - + F/E @@ -116,135 +144,145 @@ Name: - + Nom: Mana cost: - + Cout de mana: Card type: - + Type de carte P / T: - + F / E: CardItem - + + &Play + + + + + &Hide + + + + &Tap - + &Engager - + &Untap - + &Dégager - + Toggle &normal untapping - + &Flip - + &Inverser - + &Clone - + &Clone - + &Attach to card... - + &Attacher à la carte - + Ctrl+A - + Ctrl+A - + Unattac&h - + Détac&her - + Set &P/T... - + Fixer &F/E... - + &Set annotation... - + Fi&xer annotation - + red - + rouge - + yellow - + jaune - + green - + vert - + &Add counter (%1) - + &Ajouter compteur (%1) - + &Remove counter (%1) - + &Retirer compteur (%1) - + &Set counters (%1)... - + &Fixer compteurs (%1)... - + &top of library - + Dessus de la &Bibliothèque - + &bottom of library - + &Dessous de la bibliothèque - + &graveyard - + &Cimetière - + Ctrl+Del - + Ctrl+Del - + &exile - + &exiler - + &Move to - + &Aller à @@ -253,109 +291,109 @@ his hand nominative - + sa main %1's hand nominative - + main de %1 of his hand genitive - + de sa main of %1's hand genitive - + de la main de %1 his hand accusative - + sa main %1's hand accusative - + main de %1 his library nominative - + de sa bibliothèque %1's library nominative - + bibliothèque de %1 of his library genitive - + de sa bibliothèque of %1's library genitive - + de la bibliothèque de %1 his library accusative - + de sa bibliothèque %1's library accusative - + Bibliothèque de %1 his graveyard nominative - + son cimetière %1's graveyard nominative - + le cimetière de %1 of his graveyard genitive - + de son cimetière of %1's graveyard genitive - + du cimetière de %1 his graveyard accusative - + son cimetière %1's graveyard accusative - + le cimetière de %1 @@ -433,62 +471,51 @@ ChatChannelSelector - Chat channels - + Canaux de discussion - Joi&n - + &Rejoindre - Channel - + Canal - Description - + Description - Players - + Joueurs Counter - &Set counter... - + &Fixer les compteurs - Ctrl+L - + Ctrl+L - F11 - + F11 - F12 - + F12 - Set counter - + Fixer compteurs - New value for counter '%1': - + Nouvelle valeur pour le compteur '%1': @@ -496,12 +523,12 @@ Number - + Nombre Card - + Carte @@ -509,22 +536,22 @@ Load &local deck - + Charger un deck local Load d&eck from server - + Charger un d&eck depuis le serveur Ready to s&tart - + Pret à démarrer Load deck - + Charger deck @@ -532,7 +559,7 @@ Caching card pictures... - + Mise en cache des images @@ -540,37 +567,37 @@ Card name: - + Nom de la carte: Card text: - + Texte de la carte: Card type (OR): - + Type de la carte (OR): Color (OR): - + Couleur (OR): O&K - + O&K &Cancel - + &Annuler Card search - + Recherche de carte @@ -578,37 +605,37 @@ &Host: - + &Hôte: &Port: - + &Port: Player &name: - + &Nom du joueur: P&assword: - + Mot de p&asse: &OK - + &OK &Cancel - + &Annuler Connect to server - + Connecter au serveur @@ -616,67 +643,67 @@ &Description: - + &Description: &Password: - + Mot de &Passe: P&layers: - + &Spectators allowed - + &Spectateurs autorisés Spectators &need a password to join - + Les spectateurs ont besoin d'un mot de passe pour rejoindre Spectators can &chat - + Les spectateurs peuvent discuter Spectators see &everything - + Les spectateurs p&euvent tout voir Spectators - + Spectateurs &OK - + &OK &Cancel - + &Annuler Create game - + Créer partie - + Error - + Erreur - + Server error. - + Erreur serveur. @@ -684,82 +711,82 @@ &Name: - + &Nom Token - + Jeton C&olor: - + C&ouleur: white - + blanc blue - + bleu black - + noir red - + rouge green - + vert multicolor - + multicolor colorless - + incolore &P/T: - + &F/E: &Annotation: - + &Annotation: &Destroy token when it leaves the table - + &Detruire le jeton quand il quitte la table &OK - + &OK &Cancel - + &Annuler Create token - + Créer jeton @@ -767,32 +794,32 @@ &Refresh - + &Rafraichir &OK - + &OK &Cancel - + &Annuler Load deck from clipboard - + Charger deck depuis le presse-papier Error - + Erreur Invalid deck list. - + Deck list invalide. @@ -800,146 +827,151 @@ O&K - + O&K &Cancel - + &Annuler Load deck - + Charger deck DlgSettings - - - + + + Error - + Erreur - + Your card database is invalid. Would you like to go back and set the correct path? - + Votre base de carte est invalide. Voulez vous reparamétrer le chemin d'accès? - + The path to your deck directory is invalid. Would you like to go back and set the correct path? - + Le chemin d'accès pour le répertoire de votre deck est invalide. Voulez vous reparamétrer le chemin d'accès? - + The path to your card pictures directory is invalid. Would you like to go back and set the correct path? - + Le chemin d'accès pour le répertoire de vos images est invalide. Voulez vous reparamétrer le chemin d'accès? - + Settings - + Paramètres - + General - + Géneral - + Appearance - + Apparance - + User interface - + Interface utilisateur - + Messages - + Messages - + &Close - + &Fermer GameSelector - - - - + + + + Error - + Erreur - + Wrong password. - + Mauvais mot de passe - + Spectators are not allowed in this game. - + Les spectateurs ne sont pas autorisés dans cette partie - + The game is already full. - + Cette partie est déjà pleine. - + The game does not exist any more. - + La partie n'existe plus. - + Join game - + Rejoindre partie - + Password: - + Mot de passe: - + Games + Parties + + + + Show &full games - &Show full games - + toutes ou complèetes? + &Montrer toutes les parties - + C&reate - + C&réer - + &Join - + Re&joindre - + J&oin as spectator - + J&oindre en tant que spectateur GameView - + Esc - + Esc @@ -947,47 +979,47 @@ yes - + oui yes, free for spectators - + oui, libre pour les spectateurs no - + non not allowed - + non autorisé Description - + Description Creator - + Créateur Password - + Mot de passe Players - + Joueurs Spectators - + Spectateurs @@ -996,186 +1028,226 @@ English - + Anglais Choose path - + Choisir chemin d'accès Personal settings - + Paramètres personnels Language: - + Langage Download card pictures on the fly - + Télécharger les images de cartes à la volée Paths - + Chemins Decks directory: - + Répertoire des decks Pictures directory: - + Répertoire des images Path to card database: - + Chemin vers la base des cartes MainWindow - + Number of players - + Nombre de joueurs - + Please enter the number of players. - + Entrez s'il vous plait le nombre de joueurs - - + + Player %1 - + Joueur %1 - + About Cockatrice - + à propos de Cockatrice - <font size="8"><b>Cockatrice</b></font><br>Version %1<br><br><br><b>Authors:</b><br>Max-Wilhelm Bruker<br>Marcus Schütz<br>Marius van Zundert<br><br><b>Translators:</b><br>Spanish: Gocho<br>Portugese: Milton Gonçalves<br> - + <font size="8"><b>Cockatrice</b></font><br>Version %1<br><br><br><b>Auteurs:</b><br>Max-Wilhelm Bruker<br>Marcus Schütz<br>Marius van Zundert<br><br><b>Tranducteurs:</b><br>Espagnol: Gocho<br>Portugais: Milton Gonçalves<br>Portugais: Milton Gonçalves<br>Français: Yannick HAMMER<br> + Version %1 + + + + + Authors: + + + + + Translators: + + + + + Spanish: + + + + + Portugese (Portugal): + + + + + Portugese (Brazil): + + + + French: + + + + + Japanese: + + + - + + + Error - - - - - Server timeout - - - - - Invalid login data. - + Erreur - Socket error: %1 - + Server timeout + Délai de la demande dépassé - - Protocol version mismatch. Local version: %1, remote version: %2. - - - - - Connecting to %1... - - - - - Disconnected - + + Invalid login data. + Information de connexion érronée - Logged in at %1 - + Socket error: %1 + Erreur de socket: %1 - - &Connect... - - - - - &Disconnect - + + Protocol version mismatch. Local version: %1, remote version: %2. + Version de protocole différente. Version locale: %1 ,version distante: %2. - Start &local game... - + Connecting to %1... + Connexion à %1... - &Deck editor - + Disconnected + Déconnecté + Logged in at %1 + Connecté à %1 + + + + &Connect... + à verifier + &Connecter... + + + + &Disconnect + &Déconnecter + + + + Start &local game... + Démarrer une partie &locale... + + + + &Deck editor + Editeur de &deck + + + &Full screen - + &Plein écran - + Ctrl+F - + Ctrl+F - + &Settings... - + &Paramètres - + &Exit - + &Quitter - + &Cockatrice - + &Cockatrice - + &About Cockatrice - + &A propos de Cockatrice - + &Help - + A&ide - + Are you sure? - + Etes vous sur? - + There are still open games. Are you sure you want to quit? - + Il y a encore des parties en cours. Etes vous sure de vouloir quitter? @@ -1183,833 +1255,860 @@ Connecting to %1... - + Connexion à %1... Connected. - + Connecté. Disconnected from server. - + Déconnecté du serveur. Invalid password. - + Mot de passe invalide Protocol version mismatch. Client: %1, Server: %2 - + Version de protocole différente. Version locale: %1 ,version distante: %2. Protocol error. - + Erreur de protocole. You have joined game #%1. - + Vous avez rejoins la partie #%1. %1 has joined the game. - + %1 a rejoins la partie. %1 has left the game. - + %1 a quitté la partie. The game has been closed. - + La partie a été fermée. %1 is now watching the game. - + %1 est maintenant spectateur. %1 is not watching the game any more. - + %1 n'est plus spectateur. %1 has loaded a local deck. - + %1 a chargé un deck local. %1 has loaded deck #%2. - + %1 a chargé le deck #%2. %1 is ready to start the game. - + %1 est prêt à démarrer la partie. %1 is not ready to start the game any more. - + %1 n'est plus prêt à démarrer la partie. %1 has conceded the game. - + partie ou jeu + %1 a concédé la partie. The game has started. - + Le jeu a commencé. %1 shuffles his library. - + %1 mélange sa bibliothèque. %1 rolls a %2 with a %3-sided die. - + is it always a dice? + %1 lance un %2 avec %3 faces. %1 draws a card. - + %1 pioche une carte. %1 draws %2 cards. - + %1 pioche %2 cartes. from table - + de la table from graveyard - + depuis le cimetière from exile - + depuis la zone d'éxil from hand - + depuis la main the bottom card of his library - + la carte du dessous de sa bibliothèque from the bottom of his library - + depuis le dessous de sa bibliothèque the top card of his library - + le carte du dessus de sa bibliothèque from the top of his library - + du dessus de sa bibliothèque from library - + de la bibliothèque from sideboard - + de la réserve from the stack - + de la pile - + %1 puts %2 into play%3. - + what is %3? plz exemple + %1 met %2 en jeu %3 - + %1 puts %2%3 into graveyard. - + %1 met %2%3 dans le cimetière - + %1 exiles %2%3. - + %1 exile %2%3. - + %1 moves %2%3 to hand. - + %1 déplace %2%3 dans sa main - + %1 puts %2%3 into his library. - + %1 met %2%3 dans sa bibliothèque. - + %1 puts %2%3 on bottom of his library. - - - - - %1 puts %2%3 on top of his library. - - - - - %1 puts %2%3 into his library at position %4. - - - - - %1 moves %2%3 to sideboard. - - - - - %1 plays %2%3. - + %1 met %2%3 en dessous de sa bibliothèque. - + %1 puts %2%3 on top of his library. + %1 met %2%3 au dessus de sa bibliothèque. + + + + %1 puts %2%3 into his library at position %4. + %1 met %2%3 dans sa bibliothèque à la position %4. + + + + %1 moves %2%3 to sideboard. + %1 déplace %2%3 vers la réserve. + + + + %1 plays %2%3. + %1 joue %2%3. + + + + a card + une carte + + + + %1 gives %2 control over %3. - + %1 flips %2 face-down. - + %1 retourne %2 face cachée. - + %1 flips %2 face-up. - + %1 retourne %2 face visible. - + %1 destroys %2. - + %1 détruit %2. - + %1 attaches %2 to %3's %4. - + need exemple + %1 attache %2 à - + %1 unattaches %2. - + %1 détache %2. - + %1 creates token: %2%3. - + %1 crée un jeton %2%3. - + %1 points from %2's %3 to %4. - + need exemple + %1 désigne - + %1 points from %2's %3 to %4's %5. + need exemple - + %1 places %n counter(s) (%2) on %3 (now %4). + need exemple - + %1 removes %n counter(s) (%2) from %3 (now %4). + need exemple - + %1 retire %n compteur(s) (%2) depuis %3 (maintenant %4). - + red - + rouge - + yellow - + jaune - + green - + vert - + his permanents - + ses permanents - + %1 %2 %3. - + wtf ? + %1 %2 %3. - + taps - + engage - + untaps - + dégage - + %1 sets counter %2 to %3 (%4%5). - + need exemple + %1 met les compteurs %2 à %3 (%4%5). - + %1 sets %2 to not untap normally. - + need exemple + %1 met %2 pour ne pas se dégager normalement. - + %1 sets %2 to untap normally. - + %1 met %2 pour ne se dégager normalement. - + %1 sets PT of %2 to %3. - + exemple plz + %1 - + %1 sets annotation of %2 to %3. - + %1 met l'annotation de %2 à %3. - + %1 is looking at the top %2 cards %3. - + exemple plz + %1 regarde les %2 cartes du dessus de%3. - + %1 is looking at %2. - + exemple plz + %1 regarde %2. - + %1 stops looking at %2. - + need exemple to be sure + %1 arrète de regarder à %2 - + %1 reveals %2 to %3. - + %1 révèle %2 à %3. - + %1 reveals %2. - + %1 révèle %2. - + %1 randomly reveals %2%3 to %4. - + %1 révèle aléatoirement %2%3 à %4. - + %1 randomly reveals %2%3. - + %1 révèle aléatoirement %2%3. - + %1 reveals %2%3 to %4. - + %1 révèle %2%3 à %4. - + %1 reveals %2%3. - + %1 révèle %2%3 - + It is now %1's turn. - - - - - untap step - - - - - upkeep step - - - - - draw step - - - - - first main phase - + C'est maintenant le tour de %1. - beginning of combat step - + untap step + étape de dégagement - declare attackers step - + upkeep step + étape d'entretien - declare blockers step - + draw step + étape de pioche - combat damage step - + first main phase + première phase principale - end of combat step - + beginning of combat step + étape de début du combat - second main phase - + declare attackers step + étape de déclaration des attaquants - ending phase - + declare blockers step + étape de déclaration des attaquants + + + + combat damage step + étape de répartition des blessures + end of combat step + étape de fin de combat + + + + second main phase + seconde phase principale + + + + ending phase + phase de fin + + + It is now the %1. - + need exemple + C'est maintenant %1. MessagesSettingsPage - + Add message - + Ajouter message - + Message: - + Message: - + &Add - + &Ajouter - + &Remove - + &Enlever PhasesToolbar - + Untap step - + Étape de dégagement - + Upkeep step - + Étape d'entretien - + Draw step - + Étape de pioche - + First main phase - + Première phase principale - + Beginning of combat step - + Étape de début du combat - + Declare attackers step - + Étape de déclaration des attaquants - + Declare blockers step - + Étape de déclaration des attaquants - + Combat damage step - + Étape de répartition des blessures - + End of combat step - + Étape de fin de combat - + Second main phase - + Seconde phase principale - + End of turn step - + Étape de fin de tour Player - + &View graveyard - + &Voir le cimetière - + &View exile - - - - - Player "%1" - - - - - &Graveyard - - - - - &Exile - + &Voir la zone d'exil - - - Move to &top of library - + Player "%1" + Joueur "%1" - - - Move to &bottom of library - + &Graveyard + &Cimetière - - Move to &graveyard - + &Exile + &Exil - - - Move to &exile - + + + + Move to &top of library + Déplacer vers le &dessus de la bibliothèque - Move to &hand - - - - - &View library - - - - - View &top cards of library... - - - - Reveal &library to - - - - - Reveal t&op card to - + Move to &bottom of library + Déplacer en des&sous de la bibliothèque + - &View sideboard - + Move to &graveyard + Déplacer vers le cimetière + + + + + Move to &exile + Déplacer vers l'&exil + + + + + Move to &hand + Déplacer vers la &main - &Draw card - + &View library + &Voir la bibliothèque - D&raw cards... - + View &top cards of library... + Voir les cartes du &dessus de la bibliothèque... - Take &mulligan - + Reveal &library to + Révéler la &bibliothèque à - &Shuffle - + Reveal t&op card to + Révéler la carte du &dessus à - Move top cards to &graveyard... - + &View sideboard + &Voir la réserve - Move top cards to &exile... - + &Draw card + &Piocher carte + + + + D&raw cards... + P&iocher plusieurs cartes... - &Hand - + Take &mulligan + Prendre un &mulligan - &Reveal to - + &Shuffle + &Mélanger - Reveal r&andom card to - + Move top cards to &graveyard... + Déplacer les cartes du dessus vers le &cimetière... - &Sideboard - + Move top cards to &exile... + Déplacer les cartes du dessus vers le &exil... - &Library + Put top card on &bottom - - &Counters - + + &Hand + &Main - &Untap all permanents - + &Reveal to + &Révéler à - R&oll die... - + Reveal r&andom card to + Révéler &aléatoirement une carte à - &Create token... - + &Sideboard + Ré&serve - C&reate another token - + &Library + &Bibliothèque - S&ay - + &Counters + &Compteurs + + + + &Untap all permanents + &Dégager tous les permanents + + + + R&oll die... + Lancer le &dé... + + + + &Create token... + &Créer un jeton... + + + + C&reate another token + C&réer un autre jeton + S&ay + D&ire + + + C&ard - + C&arte - + &All players - - - - - F3 - - - - - Ctrl+W - - - - - F4 - - - - - Ctrl+D - - - - - Ctrl+E - - - - - Ctrl+M - + &Tout les joueurs - Ctrl+S - + F3 + F3 - Ctrl+U - + Ctrl+W + Ctrl+W - Ctrl+I - + F4 + F4 - Ctrl+T - + Ctrl+D + Ctrl+D + Ctrl+E + Ctrl+E + + + + Ctrl+M + Ctrl+M + + + + Ctrl+S + Ctrl+S + + + + Ctrl+U + Ctrl+U + + + + Ctrl+I + Ctrl+I + + + + Ctrl+T + Ctrl+T + + + Ctrl+G - + Ctrl+G - + View top cards of library - + Voir les cartes du dessus de la bibliothèque - + Number of cards: - + Nombre de cartes: - + Draw cards - + Piocher des cartes - - - - + + + + Number: - + Nombre: - + Move top cards to grave - + Déplacer les cartes du dessus dans le cimetière - + Move top cards to exile - + Déplacer les cartes du dessus vers le exil - + Roll die - + Lancer le dé... - + Number of sides: - + Nombre de faces: - + Set power/toughness - + Fixer force/endurance - + Please enter the new PT: - + maybe better with / + Entrer la nouvelle F/E - + Set annotation - + Mettre annotation - + Please enter the new annotation: - + Entrez la nouvelle annotation - + Set counters - + Mettre des compteurs @@ -2017,27 +2116,27 @@ Player name - + Nom du joueur Deck - + Deck --- - + --- local - + local #%1 - + #%1 @@ -2050,22 +2149,22 @@ Sideboard - + Réserve + + + + Cockatrice decks (*.cod) + Deck Cockatrice (*.cod) - Cockatrice decks (*.cod) - + Plain text decks (*.dec *.mwDeck) + Deck au format texte (*.dec *.mwDeck) - Plain text decks (*.dec *.mwDeck) - - - - All files (*.*) - + Tous les fichiers (*.*) @@ -2073,25 +2172,58 @@ Name - + Nom ID - + ID Upload time + nedd exemple + + RoomSelector + + + Rooms + + + + + Joi&n + &Rejoindre + + + + Room + + + + + Description + Description + + + + Players + Joueurs + + + + Games + Parties + + ServerMessageLog - Server messages - + Messages serveur @@ -2099,35 +2231,69 @@ Short name - + Nom court Long name + Nom long + + + + TabAdmin + + + Update server &message + + + + + Server administration functions + + + + + &Unlock functions + + + + + &Lock functions + + + + + Unlock administration functions + + + + + Do you really want to unlock the administration functions? + + + + + Administration TabChatChannel - C&hat channel - + C&anal de discussion - &Leave channel - + &Quitter le canal - %1 has joined the channel. - + %1 a rejoint le canal. - %1 has left the channel. - + %1 a quitté le canal. @@ -2135,154 +2301,155 @@ Local file system - + Système de fichier local Server deck storage - + Serveur de stockage de deck Open in deck editor - + Ouvrir l'éditeur de deck Upload deck - + Envoyer deck Download deck - + Télécharger deck New folder - + Nouveau dossier Delete - + Supprimer Enter deck name - + Entrez le nom du deck This decklist does not have a name. Please enter a name: - + Cette decklist n'a pas de nom. +Entrez un nom s'il vous plait: Unnamed deck - + Deck sans nom Name of new folder: - + Nom du nouveau dossier: Deck storage - + Stockage de deck TabGame - - - &Game - - - - - Next &phase - - - - - Ctrl+Space - - - Next &turn - + &Game + &Partie - Ctrl+Return - - - - - Ctrl+Enter - + Next &phase + &Prochaine phase - &Remove all local arrows - + Ctrl+Space + Ctrl+Espace - Ctrl+R - + Next &turn + Prochain &Tour - &Concede - + Ctrl+Return + Ctrl+Retour + + + + Ctrl+Enter + Ctrl+Entrée - F2 - + &Remove all local arrows + &Retirer toutes les fléches locale - &Leave game - + Ctrl+R + Ctrl+R + + + + &Concede + &Concéder + F2 + F2 + + + + &Leave game + &Quitter la partie + + + &Say: - + &Dire: - + Concede - + Concéder - + Are you sure you want to concede this game? - + Etes vous sur de vouloir concéder la partie? - + Leave game - + Quitter la partie - + Are you sure you want to leave this game? - + Etes vous sur de vouloir quitter la partie? - + Game %1: %2 - + Partie %1:%2 @@ -2290,73 +2457,152 @@ Please enter a name: Personal &talk - + need exemple + &Discussion personnelle &Leave - + &Quitter %1 has left the server. - + %1 a quitté le serveur. Talking to %1 + Vous parlez à %1 + + + + TabRoom + + + &Say: + &Dire: + + + + Chat + + + + + &Room + + + + + &Leave room + + + + + %1 has joined the room. + + + + + %1 has left the room. TabServer - + Server - + Serveur UserInfoBox - - Location: + + User information - + + Real name: + + + + + Location: + Localisation: + + + User level: + Niveau utilisateur: + + + + Administrator + + + + + Judge + + + + + Registered user + + + + + Unregistered user UserInterfaceSettingsPage - + General interface settings - + Réglages généraux de l'interface - + &Double-click cards to play them (instead of single-click) - + &Double cliquer sur la carte pour la jouer (au lieu d'un simple clic) - + Animation settings - + Réglages des animations - + &Tap/untap animation - + Animation d'engagement et dégagement UserList - + Users online: %1 + Utilisateurs en ligne:%1 + + + + Users in this room: %1 + + + + + User &details + + + + + Direct &chat @@ -2365,173 +2611,189 @@ Please enter a name: &Search... - + &Chercher... &Clear search - + &Effacer la recherche &Search for: - + &Rechercher: Deck &name: - + &Nom du deck: &Comments: - + &Commentaires: Deck editor [*] - + Editeur de deck [*] &New deck - + &Nouveau deck &Load deck... - + Char&ger deck... &Save deck - + &Sauvegarder le deck Save deck &as... - + Sauvegarder le deck &sous... Load deck from cl&ipboard... - + Charger deck depuis le &presse-papier... Save deck to clip&board - + Sauvegarder le deck dans le presse-papier &Print deck... - + Im&primer le deck... &Close - + &Fermer Ctrl+Q - + Ctrl+Q &Edit sets... - + &Editer les editions... &Deck - + &Deck &Card database - + Base des &cartes Add card to &maindeck - + Ajouter carte au &jeu Return - + Retour Enter - + Entrée Add card to &sideboard - + Ajouter carte à la ré&serve Ctrl+Return - + Ctrl+Retour Ctrl+Enter - + Ctrl+Entrée &Remove row - + &Retirer la ligne Del - + Supprimer &Increment number - + to check + &Incrémenter le nombre + - + + &Decrement number - + to check + &Décrementer la valeur - - + - Are you sure? - + Etes vous sur? The decklist has been modified. Do you want to save the changes? - + Le deck a été modifié. +Voulez vous enregistrer les modifications? Load deck + Charger deck + + + + + Error + Erreur + + + + + The deck could not be saved. +Please check that the directory is writable and try again. - + Save deck - + Sauvegarder le deck @@ -2547,17 +2809,17 @@ Do you want to save the changes? sort by name - + tri par nom sort by type - + tri par type shuffle when closing - + melanger en quittant diff --git a/cockatrice/translations/cockatrice_jp.ts b/cockatrice/translations/cockatrice_jp.ts new file mode 100644 index 00000000..24943745 --- /dev/null +++ b/cockatrice/translations/cockatrice_jp.ts @@ -0,0 +1,2786 @@ + + + + + AbstractCounter + + + &Set counter... + ã‚«ã‚¦ãƒ³ã‚¿ãƒ¼ã®æ•°ã‚’決ã‚ã‚‹... + + + + Ctrl+L + + + + + F11 + + + + + F12 + + + + + Set counter + カウンターã®è¨­å®š + + + + New value for counter '%1': + カウンター '%1'ã®æ–°ã—ã„値を設定ã™ã‚‹: + + + + AppearanceSettingsPage + + + Zone background pictures + 背景画åƒã®è¨­å®š + + + + Path to hand background: + 手札ã®èƒŒæ™¯ç”»åƒã¸ã®ãƒ‘ス: + + + + Path to stack background: + スタックゾーンã®èƒŒæ™¯ç”»åƒã¸ã®ãƒ‘ス: + + + + Path to table background: + テーブルã®èƒŒæ™¯ç”»åƒã¸ã®ãƒ‘ス: + + + + Path to player info background: + プレイヤー画åƒã¸ã®ãƒ‘ス: + + + + Path to picture of card back: + カード背é¢ç”»åƒã¸ã®ãƒ‘ス: + + + + Hand layout + 手札ã®ãƒ¬ã‚¤ã‚¢ã‚¦ãƒˆ + + + + Display hand horizontally (wastes space) + 手札を横ã«ä¸¦ã¹ã‚‹ï¼ˆã‚¹ãƒšãƒ¼ã‚¹ã‚’消費ã—ã¾ã™ï¼‰ + + + + Table grid layout + テーブルグリッドã®ãƒ¬ã‚¤ã‚¢ã‚¦ãƒˆ + + + Economical layout + çœã‚¹ãƒšãƒ¼ã‚¹ãƒ¬ã‚¤ã‚¢ã‚¦ãƒˆï¼ˆã‚«ãƒ¼ãƒ‰é–“間隔を細ã‹ãã§ãã¾ã™ï¼‰ + + + + Invert vertical coordinate + 垂直å転調整 + + + + Zone view layout + ゾーンビューレイアウト + + + + Sort by name + åå‰ã§æ•´åˆ— + + + + Sort by type + ã‚¿ã‚¤ãƒ—ã§æ•´åˆ— + + + + + + + + Choose path + ç”»åƒã®æŒ‡å®š + + + + CardDatabaseModel + + + Name + カードå + + + + Sets + エクスパンション + + + + Mana cost + マナコスト + + + + Card type + カードタイプ + + + + P/T + + + + + CardInfoWidget + + + Name: + カードå: + + + + Mana cost: + マナコスト: + + + + Card type: + カードタイプ: + + + + P / T: + + + + + CardItem + + + &Play + + + + + &Hide + + + + + &Tap + タップ + + + + &Untap + アンタップ + + + + Toggle &normal untapping + 通常ã®ã‚¢ãƒ³ã‚¿ãƒƒãƒ—ã‚’ã—ãªã„ + + + + &Flip + è£ã«ã™ã‚‹ + + + + &Clone + 複製ã™ã‚‹ + + + + &Attach to card... + カードã«ä»˜ã‘ã‚‹... + + + + Ctrl+A + + + + + Unattac&h + å–り外㙠+ + + + Set &P/T... + P/Tを決ã‚ã‚‹... + + + + &Set annotation... + 注釈を付ã‘ã‚‹... + + + + red + 赤 + + + + yellow + 黄 + + + + green + ç·‘ + + + + &Add counter (%1) + カウンターを乗ã›ã‚‹ (%1) + + + + &Remove counter (%1) + カウンターをå–り除ã (%1) + + + + &Set counters (%1)... + ã‚«ã‚¦ãƒ³ã‚¿ãƒ¼ã®æ•°ã‚’決ã‚ã‚‹ (%1)... + + + + &top of library + ライブラリーã®ä¸€ç•ªä¸Šã¸ + + + + &bottom of library + ライブラリーã®ä¸€ç•ªä¸‹ã¸ + + + + &graveyard + 墓地㸠+ + + + Ctrl+Del + + + + + &exile + 追放領域㸠+ + + + &Move to + 移動ã•ã›ã‚‹ + + + + CardZone + + + his hand + nominative + + + + + %1's hand + nominative + + + + + of his hand + genitive + + + + + of %1's hand + genitive + + + + + his hand + accusative + + + + + %1's hand + accusative + + + + + his library + nominative + + + + + %1's library + nominative + + + + + of his library + genitive + + + + + of %1's library + genitive + + + + + his library + accusative + + + + + %1's library + accusative + + + + + his graveyard + nominative + + + + + %1's graveyard + nominative + + + + + of his graveyard + genitive + + + + + of %1's graveyard + genitive + + + + + his graveyard + accusative + + + + + %1's graveyard + accusative + + + + + his exile + nominative + + + + + %1's exile + nominative + + + + + of his exile + genitive + + + + + of %1's exile + genitive + + + + + his exile + accusative + + + + + %1's exile + accusative + + + + + his sideboard + nominative + + + + + %1's sideboard + nominative + + + + + of his sideboard + genitive + + + + + of %1's sideboard + genitive + + + + + his sideboard + accusative + + + + + %1's sideboard + accusative + + + + + ChatChannelSelector + + Chat channels + ãƒãƒ£ãƒƒãƒˆãƒãƒ£ãƒ³ãƒãƒ« + + + Joi&n + å‚加ã™ã‚‹ + + + Channel + ãƒãƒ£ãƒ³ãƒãƒ« + + + Description + 説明 + + + Players + プレイヤー + + + + Counter + + &Set counter... + ã‚«ã‚¦ãƒ³ã‚¿ãƒ¼ã®æ•°ã‚’決ã‚ã‚‹... + + + Set counter + カウンターã®è¨­å®š + + + New value for counter '%1': + カウンター '%1'ã®æ–°ã—ã„値を設定ã™ã‚‹: + + + + DeckListModel + + + Number + カード枚数 + + + + Card + カードå + + + + DeckViewContainer + + + Load &local deck + ローカルã‹ã‚‰ãƒ‡ãƒƒã‚­ã‚’ロード + + + + Load d&eck from server + サーãƒãƒ¼ã‹ã‚‰ãƒ‡ãƒƒã‚­ã‚’ロード + + + + Ready to s&tart + 開始準備完了 + + + + Load deck + デッキをロード + + + + Deck_PictureCacher + + + Caching card pictures... + + + + + DlgCardSearch + + + Card name: + カードå: + + + + Card text: + カードテキスト: + + + + Card type (OR): + カードタイプ(å«ã‚€ï¼‰: + + + + Color (OR): + 色(å«ã‚€ï¼‰: + + + + O&K + + + + + &Cancel + + + + + Card search + カード検索 + + + + DlgConnect + + + &Host: + ホストIP: + + + + &Port: + ãƒãƒ¼ãƒˆ: + + + + Player &name: + プレイヤーãƒãƒ¼ãƒ : + + + + P&assword: + パスワード: + + + + &OK + + + + + &Cancel + + + + + Connect to server + サーãƒãƒ¼ã«æŽ¥ç¶š + + + + DlgCreateGame + + + &Description: + 説明: + + + + &Password: + パスワード: + + + + P&layers: + プレイヤー人数: + + + + &Spectators allowed + 観戦者を許å¯ã™ã‚‹ + + + + Spectators &need a password to join + 観戦者ã¯å‚加ã«ãƒ‘スワードãŒå¿…è¦ + + + + Spectators can &chat + 観戦者ã¯ãƒãƒ£ãƒƒãƒˆã«å‚加ã§ãã‚‹ + + + + Spectators see &everything + 観戦者ã¯å…¨ã¦è¦‹ã‚Œã‚‹ + + + + Spectators + 観戦者 + + + + &OK + + + + + &Cancel + + + + + Create game + 部屋を作る + + + + Error + エラー + + + + Server error. + サーãƒãƒ¼ã‚¨ãƒ©ãƒ¼. + + + + DlgCreateToken + + + &Name: + トークンå: + + + + Token + トークン + + + + C&olor: + 色: + + + + white + 白 + + + + blue + é’ + + + + black + é»’ + + + + red + 赤 + + + + green + ç·‘ + + + + multicolor + 多色 + + + + colorless + 無色 + + + + &P/T: + + + + + &Annotation: + 補足: + + + + &Destroy token when it leaves the table + トークンãŒãƒ†ãƒ¼ãƒ–ルを離れる場åˆç ´å£Šã™ã‚‹ + + + + &OK + + + + + &Cancel + + + + + Create token + ãƒˆãƒ¼ã‚¯ãƒ³ã‚’ä½œæˆ + + + + DlgLoadDeckFromClipboard + + + &Refresh + + + + + &OK + + + + + &Cancel + + + + + Load deck from clipboard + クリップボードã‹ã‚‰ãƒ‡ãƒƒã‚­ã‚’ロード + + + + Error + エラー + + + + Invalid deck list. + 無効ãªãƒ‡ãƒƒã‚­ãƒªã‚¹ãƒˆã§ã™. + + + + DlgLoadRemoteDeck + + + O&K + + + + + &Cancel + + + + + Load deck + デッキをロード + + + + DlgSettings + + + + + Error + エラー + + + + Your card database is invalid. Would you like to go back and set the correct path? + ã‚ãªãŸã®ã‚«ãƒ¼ãƒ‰ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã¯ç„¡åйã§ã™.å‰ã«æˆ»ã£ã¦æ­£ã—ã„パスを設定ã—ã¦ãã ã•ã„. + + + + The path to your deck directory is invalid. Would you like to go back and set the correct path? + ã‚ãªãŸã®ãƒ‡ãƒƒã‚­ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã¸ã®ãƒ‘スã¯ç„¡åйã§ã™.å‰ã«æˆ»ã£ã¦æ­£ã—ã„パスを設定ã—ã¦ãã ã•ã„. + + + + The path to your card pictures directory is invalid. Would you like to go back and set the correct path? + ã‚ãªãŸã®ã‚«ãƒ¼ãƒ‰ç”»åƒãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã¸ã®ãƒ‘スã¯ç„¡åйã§ã™.å‰ã«æˆ»ã£ã¦æ­£ã—ã„パスを設定ã—ã¦ãã ã•ã„. + + + + Settings + 設定 + + + + General + 全般 + + + + Appearance + 外観 + + + + User interface + ユーザーインターフェース + + + + Messages + メッセージ + + + + &Close + + + + + GameSelector + + + C&reate + 部屋を作る + + + + &Join + å‚加ã™ã‚‹ + + + + + + + Error + エラー + + + + Wrong password. + パスワードãŒé–“é•ã£ã¦ã„ã¾ã™. + + + + Spectators are not allowed in this game. + ã“ã®è©¦åˆã¯è¦³æˆ¦è€…ã¯è¨±å¯ã•れã¦ã„ã¾ã›ã‚“. + + + + The game is already full. + ã“ã®ã‚²ãƒ¼ãƒ ã¯ã™ã§ã«æº€å“¡ã§ã™. + + + + The game does not exist any more. + ã“ã®ã‚²ãƒ¼ãƒ ã¯ã‚‚ã†å­˜åœ¨ã—ã¾ã›ã‚“. + + + + Join game + å‚加 + + + + Password: + パスワード: + + + + Games + ゲーム + + + + Show &full games + + + + &Show full games + å…¨ã¦ã®ã‚²ãƒ¼ãƒ ã‚’見る + + + + J&oin as spectator + 観戦者ã¨ã—ã¦å‚加 + + + + GameView + + + Esc + + + + + GamesModel + + + yes + ã‚り + + + + no + ãªã— + + + + Creator + 作æˆè€… + + + + Description + 説明 + + + + yes, free for spectators + ã‚り,観戦ã¯è‡ªç”± + + + + not allowed + ä¸è¨±å¯ + + + + Password + パスワード + + + + Players + プレイヤー + + + + Spectators + 観戦者 + + + + GeneralSettingsPage + + + + + Choose path + ãƒ‘ã‚¹ã‚’é¸æŠž + + + + Personal settings + 個人設定 + + + + Language: + 言語: + + + + Download card pictures on the fly + + + + + Paths + パス + + + + Decks directory: + デッキディレクトリ: + + + + Pictures directory: + カード画åƒã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª: + + + + Path to card database: + カードデータベースã®ãƒ‘ス: + + + + + English + Japanese + + + + MainWindow + + + Number of players + プレイヤー人数 + + + + Please enter the number of players. + プレイヤーã®äººæ•°ã‚’入れã¦ãã ã•ã„. + + + + + Player %1 + プレイヤー %1 + + + + About Cockatrice + Cockatriceã«ã¤ã„㦠+ + + + Version %1 + + + + + Authors: + + + + + Translators: + + + + + Spanish: + + + + + Portugese (Portugal): + + + + + Portugese (Brazil): + + + + + French: + + + + + Japanese: + + + + + + + + Error + エラー + + + + Server timeout + サーãƒãƒ¼ã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆ + + + + Invalid login data. + 無効ãªãƒ­ã‚°ã‚¤ãƒ³ãƒ‡ãƒ¼ã‚¿ã§ã™. + + + + Socket error: %1 + ソケットエラー: %1 + + + + Protocol version mismatch. Local version: %1, remote version: %2. + + + + + Connecting to %1... + %1ã¸æŽ¥ç¶šã—ã¦ã„ã¾ã™... + + + + Disconnected + 切断ã•れã¾ã—㟠+ + + + Logged in at %1 + %1ã«ãƒ­ã‚°ã‚¤ãƒ³ä¸­ + + + + &Connect... + 接続... + + + + &Disconnect + 切断 + + + + Start &local game... + ローカルゲームを開始... + + + + &Deck editor + デッキエディター + + + + &Full screen + フルスクリーン + + + + Ctrl+F + + + + + &Settings... + 設定... + + + + &Exit + 終了 + + + + &Cockatrice + + + + + &About Cockatrice + + + + + &Help + ヘルプ + + + + Are you sure? + よã‚ã—ã„ã§ã™ã‹? + + + + There are still open games. Are you sure you want to quit? + ゲームãŒã¾ã é–‹ã„ã¦ã„ã¾ã™.本当ã«é€€å‡ºã—ã¾ã™ã‹? + + + + MessageLogWidget + + + Connecting to %1... + + + + + Disconnected from server. + + + + + Invalid password. + + + + + Protocol error. + + + + + The game has been closed. + + + + + %1 is now watching the game. + + + + + %1 is not watching the game any more. + + + + + %1 is not ready to start the game any more. + + + + + %1 rolls a %2 with a %3-sided die. + + + + + from table + + + + + from graveyard + + + + + from exile + + + + + from hand + + + + + the bottom card of his library + + + + + from the bottom of his library + + + + + the top card of his library + + + + + from the top of his library + + + + + from library + + + + + from sideboard + + + + + from the stack + + + + + %1 gives %2 control over %3. + + + + + %1 puts %2 into play%3. + + + + + %1 puts %2%3 into graveyard. + + + + + %1 exiles %2%3. + + + + + %1 moves %2%3 to hand. + + + + + %1 puts %2%3 into his library. + + + + + %1 puts %2%3 on bottom of his library. + + + + + %1 puts %2%3 on top of his library. + + + + + %1 puts %2%3 into his library at position %4. + + + + + %1 moves %2%3 to sideboard. + + + + + %1 plays %2%3. + + + + + + a card + + + + + %1 flips %2 face-down. + + + + + %1 flips %2 face-up. + + + + + %1 attaches %2 to %3's %4. + + + + + %1 unattaches %2. + + + + + %1 points from %2's %3 to %4's %5. + + + + + %1 places %n counter(s) (%2) on %3 (now %4). + + %1 places a counter (%2) on %3 (now %4). + + + + + %1 removes %n counter(s) (%2) from %3 (now %4). + + %1 removes a counter (%2) from %3 (now %4). + + + + + red + + + + + yellow + + + + + green + + + + + %1 sets counter %2 to %3 (%4%5). + + + + + %1 sets PT of %2 to %3. + + + + + %1 sets annotation of %2 to %3. + + + + + %1 is looking at the top %2 cards %3. + + + + + The game has started. + + + + + Connected. + + + + + Protocol version mismatch. Client: %1, Server: %2 + + + + + You have joined game #%1. + + + + + %1 has joined the game. + + + + + %1 has left the game. + + + + + %1 has loaded a local deck. + + + + + %1 has loaded deck #%2. + + + + + %1 is ready to start the game. + + + + + %1 has conceded the game. + + + + + %1 draws a card. + + + + + %1 draws %2 cards. + + + + + %1 destroys %2. + + + + + %1 creates token: %2%3. + + + + + %1 points from %2's %3 to %4. + + + + + %1 %2 %3. + + + + + %1 is looking at %2. + + + + + %1 stops looking at %2. + + + + + %1 reveals %2 to %3. + + + + + %1 reveals %2. + + + + + ending phase + + + + + It is now %1's turn. + + + + + %1 shuffles his library. + + + + + %1 randomly reveals %2%3 to %4. + + + + + %1 randomly reveals %2%3. + + + + + %1 reveals %2%3 to %4. + + + + + %1 reveals %2%3. + + + + + untap step + + + + + upkeep step + + + + + draw step + + + + + first main phase + + + + + beginning of combat step + + + + + declare attackers step + + + + + declare blockers step + + + + + combat damage step + + + + + end of combat step + + + + + second main phase + + + + + It is now the %1. + + + + + taps + + + + + untaps + + + + + %1 sets %2 to not untap normally. + + + + + %1 sets %2 to untap normally. + + + + + his permanents + + + + + MessagesSettingsPage + + + &Add + 追加 + + + + &Remove + 削除 + + + + Add message + メッセージを追加ã™ã‚‹ + + + + Message: + メッセージ: + + + + PhasesToolbar + + + Untap step + アンタップステップ + + + + Upkeep step + アップキープステップ + + + + Draw step + ドローステップ + + + + First main phase + 第1メインフェイズ + + + + Beginning of combat step + 戦闘å‰ã‚¹ãƒ†ãƒƒãƒ— + + + + Declare attackers step + 攻撃クリーãƒãƒ£ãƒ¼æŒ‡å®šã‚¹ãƒ†ãƒƒãƒ— + + + + Declare blockers step + ブロッククリーãƒãƒ£ãƒ¼æŒ‡å®šã‚¹ãƒ†ãƒƒãƒ— + + + + Combat damage step + 戦闘ダメージステップ + + + + End of combat step + 戦闘終了ステップ + + + + Second main phase + 第2メインフェイズ + + + + End of turn step + ターン終了ステップ + + + + Player + + + + + Move to &top of library + ライブラリーã®ä¸€ç•ªä¸Šã¸ç§»å‹• + + + + + + Move to &bottom of library + ライブラリーã®ä¸€ç•ªä¸‹ã¸ç§»å‹• + + + + + Move to &graveyard + 墓地ã¸ç§»å‹• + + + + &View library + ライブラリーを見る + + + + Reveal &library to + ライブラリーを公開ã™ã‚‹ + + + + Reveal t&op card to + 一番上ã®ã‚«ãƒ¼ãƒ‰ã‚’公開ã™ã‚‹ + + + + Move top cards to &graveyard... + カードを上ã‹ã‚‰å¢“地ã¸ç½®ã... + + + + F3 + + + + + View &top cards of library... + ライブラリーã®ã‚«ãƒ¼ãƒ‰ã‚’上ã‹ã‚‰X枚見る + + + + &View graveyard + 墓地を見る + + + + F4 + + + + + &View sideboard + サイドボードを見る + + + + Player "%1" + プレイヤー "%1" + + + + &Hand + 手札 + + + + &Library + ライブラリー + + + + &Graveyard + 墓地 + + + + &Sideboard + サイドボード + + + + View top cards of library + ライブラリーã®ã‚«ãƒ¼ãƒ‰ã‚’上ã‹ã‚‰X枚見る + + + + Number of cards: + ã‚«ãƒ¼ãƒ‰ã®æžšæ•°: + + + + &Draw card + カードを引ã + + + + &View exile + 追放領域を見る + + + + &Exile + 追放領域 + + + + + Move to &hand + 手札ã«ç§»å‹•ã™ã‚‹ + + + + + Move to &exile + 追放領域ã¸ç§»å‹•ã™ã‚‹ + + + + Ctrl+W + + + + + Ctrl+D + + + + + D&raw cards... + カードをX枚引ã + + + + Ctrl+E + + + + + Take &mulligan + マリガンã™ã‚‹ + + + + Ctrl+M + + + + + &Shuffle + シャッフル + + + + Ctrl+S + + + + + &Counters + カウンター + + + + &Untap all permanents + å…¨ã¦ã®ãƒ‘ーマãƒãƒ³ãƒˆã‚’アンタップã™ã‚‹ + + + + Ctrl+U + + + + + R&oll die... + Xé¢ãƒ€ã‚¤ã‚¹ã‚’振る + + + + Ctrl+I + + + + + &Create token... + トークンを作æˆã™ã‚‹ + + + + Ctrl+T + + + + + C&reate another token + åŒã˜ãƒˆãƒ¼ã‚¯ãƒ³ã‚’作æˆã™ã‚‹ + + + + Ctrl+G + + + + + S&ay + 発言ã™ã‚‹ + + + + Move top cards to &exile... + ライブラリーã®ä¸€ç•ªä¸Šã‹ã‚‰X枚追放ã™ã‚‹ + + + + Put top card on &bottom + + + + + &Reveal to + 公開ã™ã‚‹ + + + + Reveal r&andom card to + ランダムã«å…¬é–‹ã™ã‚‹ + + + + C&ard + カード + + + + &All players + å…¨ã¦ã®ãƒ—レイヤー + + + + Draw cards + カードを引ã + + + + + + + Number: + æžšæ•° + + + + Move top cards to grave + ライブラリーã®ãƒˆãƒƒãƒ—ã‹ã‚‰X枚墓地ã¸ç½®ã + + + + Move top cards to exile + ライブラリーã®ãƒˆãƒƒãƒ—ã‹ã‚‰X枚追放領域ã¸ç½®ã + + + + Roll die + ダイスを振る + + + + Number of sides: + é¢ã®æ•°: + + + + Set power/toughness + パワーã¨ã‚¿ãƒ•ãƒã‚¹ã‚’設定ã™ã‚‹ + + + + Please enter the new PT: + æ–°ã—ã„P/Tを入力ã—ã¦ãã ã•ã„ + + + + Set annotation + 補足を付ã‘ã‚‹ + + + + Please enter the new annotation: + æ–°ã—ã„補足を付ã‘ã¦ãã ã•ã„ + + + + Set counters + カウンターを設定ã™ã‚‹ + + + + PlayerListWidget + + + Player name + プレイヤーãƒãƒ¼ãƒ  + + + + Deck + デッキ + + + + --- + + + + + local + ローカル + + + + #%1 + + + + + QObject + + + Maindeck + メインデッキ + + + + Sideboard + サイドボード + + + + Cockatrice decks (*.cod) + + + + + Plain text decks (*.dec *.mwDeck) + + + + + All files (*.*) + å…¨ã¦ã®ãƒ•ァイル (*.*) + + + + RemoteDeckList_TreeModel + + + Name + デッキå + + + + ID + + + + + Upload time + アップロード日 + + + + RoomSelector + + + Rooms + + + + + Joi&n + å‚加ã™ã‚‹ + + + + Room + + + + + Description + 説明 + + + + Players + プレイヤー + + + + Games + ゲーム + + + + ServerMessageLog + + Server messages + サーãƒãƒ¼ã€€ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ + + + + SetsModel + + + Short name + 略語 + + + + Long name + æ­£å¼åç§° + + + + TabAdmin + + + Update server &message + + + + + Server administration functions + + + + + &Unlock functions + + + + + &Lock functions + + + + + Unlock administration functions + + + + + Do you really want to unlock the administration functions? + + + + + Administration + + + + + TabChatChannel + + C&hat channel + ãƒãƒ£ãƒ³ãƒãƒ«ã§ãƒãƒ£ãƒƒãƒˆã™ã‚‹ + + + &Leave channel + ãƒãƒ£ãƒ³ãƒãƒ«ã‹ã‚‰é€€å‡º + + + %1 has joined the channel. + %1ãŒãƒãƒ£ãƒ³ãƒãƒ«ã«å‚加ã—ã¾ã—ãŸ. + + + %1 has left the channel. + %1ã¯ãƒãƒ£ãƒ³ãƒãƒ«ã‹ã‚‰é€€å‡ºã—ã¾ã—ãŸ. + + + + TabDeckStorage + + + Local file system + ローカルファイルシステム + + + + Server deck storage + サーãƒãƒ¼ãƒ‡ãƒƒã‚­ç®¡ç† + + + + + Open in deck editor + デッキエディターを開ã + + + + Upload deck + デッキをアップロード + + + + Download deck + デッキをダウンロード + + + + + New folder + æ–°ã—ã„フォルダーを作æˆã™ã‚‹ + + + + Delete + 消去 + + + + Enter deck name + デッキã®åå‰ã‚’入れã¦ãã ã•ã„ + + + + This decklist does not have a name. +Please enter a name: + ã“ã®ãƒ‡ãƒƒã‚­ãƒªã‚¹ãƒˆã«ã¯åå‰ãŒã‚りã¾ã›ã‚“.åå‰ã‚’入力ã—ã¦ãã ã•ã„: + + + + + Unnamed deck + + + + + Name of new folder: + æ–°ã—ã„フォルダã®åå‰: + + + + Deck storage + デッキストレージ + + + + TabGame + + + &Game + ゲーム + + + + Next &phase + 次ã®ãƒ•ェイズ + + + + Ctrl+Space + + + + + Next &turn + 次ã®ã‚¿ãƒ¼ãƒ³ + + + + Ctrl+Return + + + + + Ctrl+Enter + + + + + &Remove all local arrows + å…¨ã¦ã®çŸ¢å°ã‚’消㙠+ + + + Ctrl+R + + + + + &Concede + 投了ã™ã‚‹ + + + + F2 + + + + + &Leave game + ゲームを退出ã™ã‚‹ + + + + &Say: + 発言ã™ã‚‹ + + + + Concede + 投了ã™ã‚‹ + + + + Are you sure you want to concede this game? + 本当ã«ã“ã®ã‚²ãƒ¼ãƒ ã«æŠ•了ã—ã¾ã™ã‹? + + + + Leave game + ゲームã‹ã‚‰é€€å‡ºã™ã‚‹ + + + + Are you sure you want to leave this game? + 本当ã«ã“ã®ã‚²ãƒ¼ãƒ ã‹ã‚‰é€€å‡ºã—ã¾ã™ã‹? + + + + Game %1: %2 + ゲーム %1: %2 + + + + TabMessage + + + Personal &talk + 個人会話 + + + + &Leave + 退出ã™ã‚‹ + + + + %1 has left the server. + %1ã¯ã‚µãƒ¼ãƒãƒ¼ã‹ã‚‰é€€å‡ºã—ã¾ã—ãŸ. + + + + Talking to %1 + %1ã¨ä¼šè©± + + + + TabRoom + + + &Say: + 発言ã™ã‚‹ + + + + Chat + + + + + &Room + + + + + &Leave room + + + + + %1 has joined the room. + + + + + %1 has left the room. + + + + + TabServer + + + Server + サーãƒãƒ¼ + + + + UserInfoBox + + + User information + + + + + Real name: + + + + + Location: + ç¾åœ¨åœ°: + + + + User level: + ユーザーレベル: + + + + Administrator + + + + + Judge + + + + + Registered user + + + + + Unregistered user + + + + + UserInterfaceSettingsPage + + + General interface settings + インターフェースç·åˆè¨­å®š + + + + &Double-click cards to play them (instead of single-click) + ダブルクリックã§ã‚«ãƒ¼ãƒ‰ã‚’プレイã™ã‚‹ï¼ˆã‚·ãƒ³ã‚°ãƒ«ã‚¯ãƒªãƒƒã‚¯ã®ä»£ã‚り) + + + + Animation settings + アニメーション設定 + + + + &Tap/untap animation + タップ/アンタップアニメーション + + + + UserList + + + Users online: %1 + ユーザー オンライン: %1 + + + + Users in this room: %1 + + + + + User &details + + + + + Direct &chat + + + + + WndDeckEditor + + + &Search for: + 検索: + + + + Deck &name: + デッキå: + + + + &Comments: + コメント: + + + + Deck editor [*] + デッキエディター [*] + + + + &New deck + æ–°ã—ã„デッキ + + + + &Load deck... + デッキをロード... + + + + Load deck from cl&ipboard... + クリップボードã‹ã‚‰ãƒ‡ãƒƒã‚­ã‚’ロード... + + + + &Save deck + デッキをä¿å­˜ + + + + Save deck &as... + åå‰ã‚’付ã‘ã¦ãƒ‡ãƒƒã‚­ã‚’ä¿å­˜... + + + + Save deck to clip&board + クリップボードã«ãƒ‡ãƒƒã‚­ã‚’ä¿å­˜ + + + + &Print deck... + デッキをå°åˆ·... + + + + &Close + é–‰ã˜ã‚‹ + + + + Ctrl+Q + + + + + &Edit sets... + セットã®è¨­å®š... + + + + &Deck + デッキ + + + + Load deck + デッキをロード + + + + + Error + エラー + + + + + The deck could not be saved. +Please check that the directory is writable and try again. + + + + + Save deck + デッキをä¿å­˜ + + + + Add card to &maindeck + メインデッキã«ã‚«ãƒ¼ãƒ‰ã‚’加ãˆã‚‹ + + + + Return + + + + + Enter + + + + + Ctrl+Return + + + + + Ctrl+Enter + + + + + Add card to &sideboard + サイドボードã«ã‚«ãƒ¼ãƒ‰ã‚’加ãˆã‚‹ + + + + &Search... + 検索... + + + + &Clear search + 検索を解除 + + + + &Card database + カードデータベース + + + + &Remove row + å…¨ã¦å–り除ã + + + + Del + + + + + &Increment number + 枚数を増や㙠+ + + + + + + + + + &Decrement number + 枚数を減ら㙠+ + + + - + + + + + Are you sure? + 本当ã«ã‚ˆã‚ã—ã„ã§ã™ã‹? + + + + The decklist has been modified. +Do you want to save the changes? + ã“ã®ãƒ‡ãƒƒã‚­ãƒªã‚¹ãƒˆã¯å¤‰æ›´ã•れã¦ã„ã¾ã™.変更をä¿å­˜ã—ã¾ã™ã‹? + + + + WndSets + + + Edit sets + セットã®è¨­å®š + + + + ZoneViewWidget + + + sort by name + åå‰ã§ã‚½ãƒ¼ãƒˆ + + + + sort by type + タイプã§ã‚½ãƒ¼ãƒˆ + + + + shuffle when closing + é–‰ã˜ã‚‹æ™‚ã«ã‚·ãƒ£ãƒƒãƒ•ル + + + diff --git a/cockatrice/translations/cockatrice_pt-br.ts b/cockatrice/translations/cockatrice_pt-br.ts new file mode 100644 index 00000000..a69c1491 --- /dev/null +++ b/cockatrice/translations/cockatrice_pt-br.ts @@ -0,0 +1,2806 @@ + + + + + AbstractCounter + + + &Set counter... + Alterar &marcador... + + + + Ctrl+L + Ctrl+L + + + + F11 + F11 + + + + F12 + F12 + + + + Set counter + Alterar marcador + + + + New value for counter '%1': + Novo valor para o marcador '%1': + + + + AppearanceSettingsPage + + + Zone background pictures + Imagens de fundo das zonas + + + + Path to hand background: + Caminho para o fundo da mão: + + + + Path to stack background: + Caminho para o fundo da pilha: + + + + Path to table background: + Caminho para o fundo da mesa: + + + + Path to player info background: + Caminho para o fundo das informações do jogador: + + + + Path to picture of card back: + Caminho para a imagem do verso dos cards: + + + + Hand layout + Layout da mão + + + + Display hand horizontally (wastes space) + Mostrar a mão na horizontal (desperdiça espaço) + + + + Table grid layout + Layout do campo de batalha + + + Economical layout + Layout econômico + + + + Invert vertical coordinate + Inverter a coordenada vertical + + + + Zone view layout + Layout de vista da zona + + + + Sort by name + Ordenar por nome + + + + Sort by type + Ordenar por tipo + + + + + + + + Choose path + Escolher caminho + + + + CardDatabaseModel + + + Name + Nome + + + + Sets + Expansões + + + + Mana cost + Custo de mana + + + + Card type + Tipo de card + + + + P/T + P/R + + + + CardInfoWidget + + + Name: + Nome: + + + + Mana cost: + Custo de mana: + + + + Card type: + Tipo de card: + + + + P / T: + P / R: + + + + CardItem + + + &Play + + + + + &Hide + + + + + &Tap + &Virar + + + + &Untap + &Desvirar + + + + Toggle &normal untapping + &Trocar o modo de desvirar + + + + &Flip + Virar a &face + + + + &Clone + Clo&nar + + + + &Attach to card... + Ane&xar ao card... + + + + Ctrl+A + Ctrl+A + + + + Unattac&h + De&sanexar + + + + Set &P/T... + Alterar &P/R... + + + + &Set annotation... + Alterar &nota... + + + + red + vermelho + + + + yellow + amarelo + + + + green + verde + + + + &Add counter (%1) + Adicionar &marcador (%1) + + + + &Remove counter (%1) + &Remover marcador (%1) + + + + &Set counters (%1)... + &Alterar marcadores (%1)... + + + + &top of library + topo do &grimório + + + + &bottom of library + &fundo do grimório + + + + &graveyard + &cemitério + + + + Ctrl+Del + Ctrl+Del + + + + &exile + &exílio + + + + &Move to + Mo&ver para + + + + CardZone + + + his hand + nominative + sua mão + + + + %1's hand + nominative + mão de %1 + + + + of his hand + genitive + da sua mão + + + + of %1's hand + genitive + da mão de %1 + + + + his hand + accusative + sua mão + + + + %1's hand + accusative + mão de %1 + + + + his library + nominative + seu grimório + + + + %1's library + nominative + grimório de %1 + + + + of his library + genitive + do seu grimório + + + + of %1's library + genitive + do grimório de %1 + + + + his library + accusative + seu grimório + + + + %1's library + accusative + grimório de %1 + + + + his graveyard + nominative + seu cemitério + + + + %1's graveyard + nominative + cemitério de %1 + + + + of his graveyard + genitive + do seu cemitério + + + + of %1's graveyard + genitive + do cemitério de %1 + + + + his graveyard + accusative + seu cemitério + + + + %1's graveyard + accusative + cemitério de %1 + + + + his exile + nominative + seu exílio + + + + %1's exile + nominative + exílio de %1 + + + + of his exile + genitive + do seu exílio + + + + of %1's exile + genitive + do exílio de %1 + + + + his exile + accusative + seu exílio + + + + %1's exile + accusative + exílio de %1 + + + + his sideboard + nominative + seu sideboard + + + + %1's sideboard + nominative + sideboard de %1 + + + + of his sideboard + genitive + do seu sideboard + + + + of %1's sideboard + genitive + do sideboard de %1 + + + + his sideboard + accusative + seu sideboard + + + + %1's sideboard + accusative + sideboard de %1 + + + + ChatChannelSelector + + Chat channels + Canais de chat + + + Joi&n + &Entrar + + + Channel + Canal + + + Description + Descrição + + + Players + Jogadores + + + + Counter + + &Set counter... + Alterar &marcador... + + + Ctrl+L + Ctrl+L + + + F11 + F11 + + + F12 + F12 + + + Set counter + Alterar marcador + + + New value for counter '%1': + Novo valor para o marcador '%1': + + + + DeckListModel + + + Number + Número + + + + Card + Card + + + + DeckViewContainer + + + Load &local deck + Carregar dec&k local + + + + Load d&eck from server + Carregar deck do &servidor + + + + Ready to s&tart + &Pronto para começar + + + + Load deck + Carregar deck + + + + Deck_PictureCacher + + + Caching card pictures... + Obtendo as imagens dos cards... + + + + DlgCardSearch + + + Card name: + Nome do card: + + + + Card text: + Texto do card: + + + + Card type (OR): + Tipo do card (OU): + + + + Color (OR): + Cor (OU): + + + + O&K + &OK + + + + &Cancel + &Cancelar + + + + Card search + Buscar card + + + + DlgConnect + + + &Host: + &Servidor: + + + + &Port: + &Porta: + + + + Player &name: + Nome do &jogador: + + + + P&assword: + S&enha: + + + + &OK + &OK + + + + &Cancel + &Cancelar + + + + Connect to server + Conectar ao servidor + + + + DlgCreateGame + + + &Description: + &Descrição: + + + + &Password: + S&enha: + + + + P&layers: + &Jogadores: + + + + &Spectators allowed + &Permitir visitantes + + + + Spectators &need a password to join + Visitantes &precisam de senha para entrar + + + + Spectators can &chat + Visitantes podem c&onversar + + + + Spectators see &everything + Visitantes podem ver &tudo + + + + Spectators + Visitantes + + + + &OK + &OK + + + + &Cancel + &Cancelar + + + + Create game + Criar jogo + + + + Error + Erro + + + + Server error. + Erro do servidor. + + + + DlgCreateToken + + + &Name: + &Nome: + + + + Token + Ficha + + + + C&olor: + C&or: + + + + white + branco + + + + blue + azul + + + + black + preto + + + + red + vermelho + + + + green + verde + + + + multicolor + multicolorido + + + + colorless + incolor + + + + &P/T: + &P/R: + + + + &Annotation: + &Nota: + + + + &Destroy token when it leaves the table + Destruir a &ficha quando ela sair do campo de batalha + + + + &OK + &OK + + + + &Cancel + &Cancelar + + + + Create token + Criar ficha + + + + DlgLoadDeckFromClipboard + + + &Refresh + &Atualizar + + + + &OK + &OK + + + + &Cancel + &Cancelar + + + + Load deck from clipboard + Carregar deck da área de transferência + + + + Error + Erro + + + + Invalid deck list. + Lista de deck inválida. + + + + DlgLoadRemoteDeck + + + O&K + &OK + + + + &Cancel + &Cancelar + + + + Load deck + Carregar deck + + + + DlgSettings + + + + + Error + Erro + + + + Your card database is invalid. Would you like to go back and set the correct path? + O seu banco de dados de cards é inválido. Você gostaria de voltar e corrigir o caminho? + + + + The path to your deck directory is invalid. Would you like to go back and set the correct path? + O caminho para a sua pasta de decks é inválido. Você gostaria de voltar e corrigir o caminho? + + + + The path to your card pictures directory is invalid. Would you like to go back and set the correct path? + O caminho para a sua pasta de imagens de cards é inválido. Você gostaria de voltar e corrigir o caminho? + + + + Settings + Configurações + + + + General + Geral + + + + Appearance + Aparência + + + + User interface + Interface do usuário + + + + Messages + Mensagens + + + + &Close + &Fechar + + + + GameSelector + + + C&reate + &Criar + + + + &Join + &Entrar + + + + + + + Error + Erro + + + + Wrong password. + Senha incorreta. + + + + Spectators are not allowed in this game. + Não são permitidos visitantes neste jogo. + + + + The game is already full. + O jogo está cheio. + + + + The game does not exist any more. + O jogo não existe mais. + + + + Join game + Entrar no jogo + + + + Password: + Senha: + + + + Games + Jogos + + + + Show &full games + + + + &Show full games + &Mostrar os jogos cheios + + + + J&oin as spectator + E&ntrar como visitante + + + + GameView + + + Esc + Esc + + + + GamesModel + + + yes + sim + + + + no + não + + + + Creator + Criador + + + + Description + Descrição + + + + yes, free for spectators + sim, livre para visitantes + + + + not allowed + não permitidos + + + + Password + Senha + + + + Players + Jogadores + + + + Spectators + Visitantes + + + + GeneralSettingsPage + + + + + Choose path + Escolher caminho + + + + Personal settings + Configurações pessoais + + + + Language: + Língua: + + + + Download card pictures on the fly + Baixar a imagem dos cards em tempo real + + + + Paths + Caminhos + + + + Decks directory: + Pasta de decks: + + + + Pictures directory: + Pasta de imagens: + + + + Path to card database: + Caminho para o banco de dados dos cards: + + + + + English + Português do Brasil + + + + MainWindow + + + Number of players + Número de jogadores + + + + Please enter the number of players. + Por favor, entre o número de jogadores. + + + + + Player %1 + Jogador %1 + + + + About Cockatrice + Sobre o Cockatrice + + + <font size="8"><b>Cockatrice</b></font><br>Version %1<br><br><br><b>Authors:</b><br>Max-Wilhelm Bruker<br>Marcus Schütz<br>Marius van Zundert<br><br><b>Translators:</b><br>Spanish: Gocho<br>Portugese: Milton Gonçalves<br> + <font size="8"><b>Cockatrice</b></font><br>Version %1<br><br><br><b>Authors:</b><br>Max-Wilhelm Bruker<br>Marcus Schütz<br>Marius van Zundert<br><br><b>Translators:</b><br>Spanish: Gocho<br>Portugese: Milton Gonçalves<br>Brazilian Portuguese: Thiago Queiroz<br> + + + + Version %1 + + + + + Authors: + + + + + Translators: + + + + + Spanish: + + + + + Portugese (Portugal): + + + + + Portugese (Brazil): + + + + + French: + + + + + Japanese: + + + + + + + + Error + Erro + + + + Server timeout + Tempo esgotado do servidor + + + + Invalid login data. + Informações de login inválidas. + + + + Socket error: %1 + Erro de ligação:%1 + + + + Protocol version mismatch. Local version: %1, remote version: %2. + Versão dos protocolos incompatível. Versão local:%1, versão remota:%2. + + + + Connecting to %1... + Conectando a %1... + + + + Disconnected + Desconectado + + + + Logged in at %1 + Logado em %1 + + + + &Connect... + &Conectar... + + + + &Disconnect + &Desconectar + + + + Start &local game... + Iniciar jogo &local... + + + + &Deck editor + Editor de &decks + + + + &Full screen + Tela &cheia + + + + Ctrl+F + Ctrl+F + + + + &Settings... + &Configurações... + + + + &Exit + &Sair + + + + &Cockatrice + &Cockatrice + + + + &About Cockatrice + So&bre o Cockatrice + + + + &Help + &Ajuda + + + + Are you sure? + Você tem certeza? + + + + There are still open games. Are you sure you want to quit? + Ainda existem jogos abertos. Você tem certeza que deseja sair? + + + + MessageLogWidget + + + Connecting to %1... + Conectando a %1... + + + + Disconnected from server. + Desconectado do servidor. + + + + Invalid password. + Senha incorreta. + + + + Protocol error. + Erro de protocolo. + + + + The game has been closed. + O jogo foi fechado. + + + + %1 is now watching the game. + %1 está assistindo o jogo agora. + + + + %1 is not watching the game any more. + %1 não está mais assistindo o jogo. + + + + %1 is not ready to start the game any more. + %1 não está mais pronto para começar o jogo. + + + + %1 rolls a %2 with a %3-sided die. + %1 tirou um %2 com um dado de %3 lados. + + + + from table + vindo do campo de batalha + + + + from graveyard + vindo do cemitério + + + + from exile + vindo do exílio + + + + from hand + vindo da mão + + + + the bottom card of his library + o card do fundo do seu grimório + + + + from the bottom of his library + vindo do fundo do seu grimório + + + + the top card of his library + o card do topo do seu grimório + + + + from the top of his library + vindo do topo do seu grimório + + + + from library + vindo do grimório + + + + from sideboard + vindo do sideboard + + + + from the stack + vindo da pilha + + + + %1 gives %2 control over %3. + + + + + %1 puts %2 into play%3. + %1 põe %2 no campo de batalha %3. + + + + %1 puts %2%3 into graveyard. + %1 põe %2 no cemitério%3. + + + + %1 exiles %2%3. + %1 exila %2%3. + + + + %1 moves %2%3 to hand. + %1 move %2 para a mão%3. + + + + %1 puts %2%3 into his library. + %1 põe %2 no seu grimório%3. + + + + %1 puts %2%3 on bottom of his library. + %1 põe %2 no fundo do seu grimório%3. + + + + %1 puts %2%3 on top of his library. + %1 põe %2 no topo do seu grimório%3. + + + + %1 puts %2%3 into his library at position %4. + %1 põe %2 no seu grimório na posição %4%3. + + + + %1 moves %2%3 to sideboard. + %1 move %2 para o sideboard%3. + + + + %1 plays %2%3. + %1 põe %2 na pilha%3. + + + + + a card + um card + + + + %1 flips %2 face-down. + %1 vira %2 para baixo. + + + + %1 flips %2 face-up. + %1 vira %2 para cima. + + + + %1 attaches %2 to %3's %4. + %1 anexa %2 a %4 de %3. + + + + %1 unattaches %2. + %1 desanexa %2. + + + + %1 points from %2's %3 to %4's %5. + %1 aponta para %5 de %4 com %3 de %2. + + + + %1 places %n counter(s) (%2) on %3 (now %4). + + %1 põe %n marcador(es) (%2) em %3 (agora com %4). + %1 põe %n marcador(es) (%2) em %3 (agora com %4). + + + + + %1 removes %n counter(s) (%2) from %3 (now %4). + + %1 tira %n marcador(es) (%2) em %3 (agora com %4). + %1 tira %n marcador(es) (%2) em %3 (agora com %4). + + + + + red + vermelho + + + + yellow + amarelo + + + + green + verde + + + + %1 sets counter %2 to %3 (%4%5). + %1 altera o marcador %2 para %3 (%4%5). + + + + %1 sets PT of %2 to %3. + %1 altera o P/R de %2 para %3. + + + + %1 sets annotation of %2 to %3. + %1 altera a nota de %2 para%3. + + + + %1 is looking at the top %2 cards %3. + %1 está olhando para os %2 cards do topo %3. + + + + The game has started. + O jogo começou. + + + + Connected. + Conectado. + + + + Protocol version mismatch. Client: %1, Server: %2 + Versão dos protocolos incompatível. Versão do utilizador:%1, versão do servidor:%2 + + + + You have joined game #%1. + Você entrou no jogo nº %1. + + + + %1 has joined the game. + %1 entrou no jogo. + + + + %1 has left the game. + %1 saiu do jogo. + + + + %1 has loaded a local deck. + %1 carregou um deck local. + + + + %1 has loaded deck #%2. + %1 carregou o deck nº %2. + + + + %1 is ready to start the game. + %1 está pronto para começar o jogo. + + + + %1 has conceded the game. + %1 concedeu o jogo. + + + + %1 draws a card. + %1 compra um card. + + + + %1 draws %2 cards. + %1 compra %2 cards. + + + + %1 destroys %2. + %1 destrói %2. + + + + %1 creates token: %2%3. + %1 cria a ficha: %2%3. + + + + %1 points from %2's %3 to %4. + %1 aponta para %4 com %3 de %2 . + + + + %1 %2 %3. + %1 %2 %3. + + + + %1 is looking at %2. + %1 está olhando para %2. + + + + %1 stops looking at %2. + %1 para de olhar para %2. + + + + %1 reveals %2 to %3. + %1 revela %2 para %3. + + + + %1 reveals %2. + %1 revela %2. + + + + ending phase + fase final + + + + It is now %1's turn. + Agora é o turno de %1. + + + + %1 shuffles his library. + %1 embaralha o seu grimório. + + + + %1 randomly reveals %2%3 to %4. + %1 revela aleatoriamente %2%3. para %4. + + + + %1 randomly reveals %2%3. + %1 revela aleatoriamente %2%3. + + + + %1 reveals %2%3 to %4. + %1 revela %2%3 para %4. + + + + %1 reveals %2%3. + %1 revela %2%3. + + + + untap step + etapa de desvirar + + + + upkeep step + etapa de manutenção + + + + draw step + etapa de compra + + + + first main phase + primeira fase principal + + + + beginning of combat step + etapa de início de combate + + + + declare attackers step + etapa de declaracão de atacantes + + + + declare blockers step + etapa de declaração de bloqueadores + + + + combat damage step + etapa de dano de combate + + + + end of combat step + etapa de fim de combate + + + + second main phase + segunda fase principal + + + + It is now the %1. + Agora é a %1. + + + + taps + vira + + + + untaps + desvira + + + + %1 sets %2 to not untap normally. + %1 define que %2 não desvira normalmente. + + + + %1 sets %2 to untap normally. + %1 define que %2 desvira normalmente. + + + + his permanents + as suas permanentes + + + + MessagesSettingsPage + + + &Add + &Adicionar + + + + &Remove + &Remover + + + + Add message + Adicionar mensagem + + + + Message: + Mensagem: + + + + PhasesToolbar + + + Untap step + Etapa de desvirar + + + + Upkeep step + Etapa de manutenção + + + + Draw step + Etapa de compra + + + + First main phase + Primeira fase principal + + + + Beginning of combat step + Etapa de início de combate + + + + Declare attackers step + Etapa de declaracão de atacantes + + + + Declare blockers step + Etapa de declaração de bloqueadores + + + + Combat damage step + Etapa de dano de combate + + + + End of combat step + Etapa de fim de combate + + + + Second main phase + Segunda fase principal + + + + End of turn step + Etapa de fim de combate + + + + Player + + + + + Move to &top of library + Mover para o &topo do grimório + + + + + + Move to &bottom of library + Mover para o &fundo do grimório + + + + + Move to &graveyard + Mover para o &cemitério + + + + &View library + &Ver grimório + + + + Reveal &library to + Revelar o &grimório para + + + + Reveal t&op card to + Revelar o card do t&opo para + + + + Move top cards to &graveyard... + Mover os cards do topo para o ce&mitério... + + + + F3 + F3 + + + + View &top cards of library... + Ver os cards do to&po do grimório... + + + + &View graveyard + V&er cemitério + + + + F4 + F4 + + + + &View sideboard + &Ver sideboard + + + + Player "%1" + Jogador "%1" + + + + &Hand + &Mão + + + + &Library + &Grimório + + + + &Graveyard + &Cemitério + + + + &Sideboard + &Sideboard + + + + View top cards of library + Ver os cards do topo do grimório + + + + Number of cards: + Número de cards: + + + + &Draw card + Co&mprar card + + + + &View exile + &Ver exílio + + + + &Exile + &Exílio + + + + + Move to &hand + Mo&ver para a mão + + + + + Move to &exile + Mover para o &exílio + + + + Ctrl+W + Ctrl+W + + + + Ctrl+D + Ctrl+D + + + + D&raw cards... + Comprar car&ds... + + + + Ctrl+E + Ctrl+E + + + + Take &mulligan + Pedir mu&lligan + + + + Ctrl+M + Ctrl+M + + + + &Shuffle + &Embaralhar + + + + Ctrl+S + Ctrl+S + + + + &Counters + &Marcadores + + + + &Untap all permanents + Des&virar todos as permanentes + + + + Ctrl+U + Ctrl+U + + + + R&oll die... + &Jogar dado... + + + + Ctrl+I + Ctrl+I + + + + &Create token... + Criar fich&a... + + + + Ctrl+T + Ctrl+T + + + + C&reate another token + Criar &outra ficha + + + + Ctrl+G + Ctrl+G + + + + S&ay + &Falar + + + + Move top cards to &exile... + Mover os cards do topo para o e&xílio... + + + + Put top card on &bottom + + + + + &Reveal to + Re&velar para + + + + Reveal r&andom card to + Revelar card alea&tório para + + + + C&ard + C&ard + + + + &All players + To&dos os jogadores + + + + Draw cards + Comprar cards + + + + + + + Number: + Número: + + + + Move top cards to grave + Mover os cards do topo para o cemitério + + + + Move top cards to exile + Mover os cards do topo para o exílio + + + + Roll die + Jogar dado + + + + Number of sides: + Número de lados: + + + + Set power/toughness + Alterar poder/resistência + + + + Please enter the new PT: + Por favor, entre com o novo P/R: + + + + Set annotation + Alterar nota + + + + Please enter the new annotation: + Por favor, entre com a nova nota: + + + + Set counters + Alterar marcadores + + + + PlayerListWidget + + + Player name + Nome do jogador + + + + Deck + Deck + + + + --- + --- + + + + local + local + + + + #%1 + nº %1 + + + + QObject + + + Maindeck + Deck principal + + + + Sideboard + Sideboard + + + + Cockatrice decks (*.cod) + Decks Cockatrice (*.cod) + + + + Plain text decks (*.dec *.mwDeck) + Decks de texto simples (*.dec *.mwDeck) + + + + All files (*.*) + Todos os arquivos (*.*) + + + + RemoteDeckList_TreeModel + + + Name + Nome + + + + ID + ID + + + + Upload time + Hora do upload + + + + RoomSelector + + + Rooms + + + + + Joi&n + &Entrar + + + + Room + + + + + Description + Descrição + + + + Players + Jogadores + + + + Games + Jogos + + + + ServerMessageLog + + Server messages + Mensagens do servidor + + + + SetsModel + + + Short name + Nome curto + + + + Long name + Nome longo + + + + TabAdmin + + + Update server &message + + + + + Server administration functions + + + + + &Unlock functions + + + + + &Lock functions + + + + + Unlock administration functions + + + + + Do you really want to unlock the administration functions? + + + + + Administration + + + + + TabChatChannel + + C&hat channel + Canal do &chat + + + &Leave channel + &Sair do canal + + + %1 has joined the channel. + %1 entrou no canal. + + + %1 has left the channel. + %1 saiu do canal. + + + + TabDeckStorage + + + Local file system + Sistema de arquivos local + + + + Server deck storage + Armazenamento de decks no servidor + + + + + Open in deck editor + Abrir no editor de decks + + + + Upload deck + Upload do deck + + + + Download deck + Download do deck + + + + + New folder + Nova pasta + + + + Delete + Apagar + + + + Enter deck name + Entre o nome do deck + + + + This decklist does not have a name. +Please enter a name: + Este deck não tem um nome. +Por favor, entre um nome: + + + + + Unnamed deck + Deck sem nome + + + + Name of new folder: + Nome da nova pasta: + + + + Deck storage + Armazenamento de decks + + + + TabGame + + + &Game + &Jogo + + + + Next &phase + Próxima &etapa + + + + Ctrl+Space + Ctrl+Espaço + + + + Next &turn + Próximo &turno + + + + Ctrl+Return + Ctrl+Return + + + + Ctrl+Enter + Ctrl+Enter + + + + &Remove all local arrows + &Apagar todas as setas locais + + + + Ctrl+R + Ctrl+R + + + + &Concede + &Conceder + + + + F2 + F2 + + + + &Leave game + &Sair do jogo + + + + &Say: + &Falar: + + + + Concede + Conceder + + + + Are you sure you want to concede this game? + Você tem certeza que deseja conceder este jogo? + + + + Leave game + Sair do jogo + + + + Are you sure you want to leave this game? + Você tem certeza que deseja sair deste jogo? + + + + Game %1: %2 + Jogo %1: %2 + + + + TabMessage + + + Personal &talk + Chat &privado + + + + &Leave + &Sair + + + + %1 has left the server. + %1 saiu do servidor. + + + + Talking to %1 + Falando com %1 + + + + TabRoom + + + &Say: + &Falar: + + + + Chat + + + + + &Room + + + + + &Leave room + + + + + %1 has joined the room. + + + + + %1 has left the room. + + + + + TabServer + + + Server + Servidor + + + + UserInfoBox + + + User information + + + + + Real name: + + + + + Location: + Localização: + + + + User level: + Nível do usuário: + + + + Administrator + + + + + Judge + + + + + Registered user + + + + + Unregistered user + + + + + UserInterfaceSettingsPage + + + General interface settings + Configurações gerais de interface + + + + &Double-click cards to play them (instead of single-click) + &Duplo clique nos cards para jogá-los (ao invés de clique simples) + + + + Animation settings + Configurações de animação + + + + &Tap/untap animation + Animação de &virar/desvirar + + + + UserList + + + Users online: %1 + Usuários online: %1 + + + + Users in this room: %1 + + + + + User &details + + + + + Direct &chat + + + + + WndDeckEditor + + + &Search for: + &Buscar por: + + + + Deck &name: + Nome do &deck: + + + + &Comments: + &Comentários: + + + + Deck editor [*] + Editor de decks [*] + + + + &New deck + &Novo deck + + + + &Load deck... + &Abrir deck... + + + + Load deck from cl&ipboard... + Carregar deck da área de &transferência... + + + + &Save deck + &Salvar deck + + + + Save deck &as... + Salvar deck c&omo... + + + + Save deck to clip&board + Salvar deck para a área de t&ransferência + + + + &Print deck... + &Imprimir deck... + + + + &Close + &Fechar + + + + Ctrl+Q + Ctrl+Q + + + + &Edit sets... + E&ditar expansões... + + + + &Deck + &Deck + + + + Load deck + Abrir deck + + + + + Error + Erro + + + + + The deck could not be saved. +Please check that the directory is writable and try again. + + + + + Save deck + Salvar deck + + + + Add card to &maindeck + Incluir no deck &principal + + + + Return + Return + + + + Enter + Enter + + + + Ctrl+Return + Ctrl+Return + + + + Ctrl+Enter + Ctrl+Enter + + + + Add card to &sideboard + Incluir no side&board + + + + &Search... + B&uscar... + + + + &Clear search + &Limpar busca + + + + &Card database + Banco de dados de &cards + + + + &Remove row + &Apagar linha + + + + Del + Del + + + + &Increment number + &Aumentar quantidade + + + + + + + + + + + &Decrement number + &Diminuir quantidade + + + + - + - + + + + Are you sure? + Você tem certeza? + + + + The decklist has been modified. +Do you want to save the changes? + O deck foi modificado. +Você deseja salvar as alterações? + + + + WndSets + + + Edit sets + Editar expansões + + + + ZoneViewWidget + + + sort by name + ordenar por nome + + + + sort by type + ordenar por tipo + + + + shuffle when closing + embaralhar quando fechar + + + diff --git a/cockatrice/translations/cockatrice_pt.ts b/cockatrice/translations/cockatrice_pt.ts index 67f79abd..d24169af 100644 --- a/cockatrice/translations/cockatrice_pt.ts +++ b/cockatrice/translations/cockatrice_pt.ts @@ -1,84 +1,116 @@ + + AbstractCounter + + + &Set counter... + Definir &marcador... + + + + Ctrl+L + Ctrl+L + + + + F11 + F11 + + + + F12 + F12 + + + + Set counter + Definir marcador + + + + New value for counter '%1': + Novo valor para o marcador '%1': + + AppearanceSettingsPage - + Zone background pictures Zona das imagens de fundo - + Path to hand background: - Directorio da imagem de fundo da mão: + Directório da imagem de fundo da mão: - + Path to stack background: Directório da imagem de fundo da pilha: - + Path to table background: Directório da imagem de fundo do campo de batalha: - + Path to player info background: Directório da imagem de fundo da informação de jogador: - + Path to picture of card back: Directório da imagem do verso da carta: - + Hand layout Disposição da Mão - + Display hand horizontally (wastes space) Mostrar mão horizontalmente (desperdiça espaço) - + Table grid layout Esquema da mesa - Economical layout - Esquema económico + Esquema económico - + Invert vertical coordinate Inverter coordenada vertical - + Zone view layout Distribuição da zona de vizualização - + Sort by name Ordenar por nome - + Sort by type Ordenar por tipo - - - - - + + + + + Choose path Escolher directório @@ -137,112 +169,122 @@ CardItem - + + &Play + &Jogar + + + + &Hide + + + + &Tap &Virar - + &Untap Desv&irar - + Toggle &normal untapping A&lterar desvirar normalmente - + &Flip Vol&tar - + &Clone Copi&ar - + &Attach to card... Ane&xar a carta... - + Ctrl+A Ctrl+A - + Unattac&h De&sanexar - + Set &P/T... Definir &P/R... - + &Set annotation... Colocar &nota... - + red vermelho - + yellow amarelo - + green verde - + &Add counter (%1) Adicionar &marcador (%1) - + &Remove counter (%1) &Remover marcador (%1) - + &Set counters (%1)... &Denifir marcadores (%1)... - + &top of library Topo do &grimório - + &bottom of library &Fundo do grimório - + &graveyard &Cemitério - + Ctrl+Del Ctrl+Del - + &exile &Exílio - + &Move to M&over para @@ -433,62 +475,51 @@ ChatChannelSelector - Chat channels - Canais de Conversação + Canais de Conversação - Joi&n - E&ntrar + E&ntrar - Channel - Canal + Canal - Description - Descrição + Descrição - Players - Jogadores + Jogadores Counter - &Set counter... - Definir &marcador... + Definir &marcador... - Ctrl+L - Ctrl+L + Ctrl+L - F11 - F11 + F11 - F12 - F12 + F12 - Set counter - Definir marcador + Definir marcador - New value for counter '%1': - Novo valor para o marcador '%1': + Novo valor para o marcador '%1': @@ -669,12 +700,12 @@ Criar jogo - + Error Erro - + Server error. Erro do servidor. @@ -816,54 +847,54 @@ DlgSettings - - - + + + Error Erro - + Your card database is invalid. Would you like to go back and set the correct path? A sua base de dados é inválida. Gostaria de voltar atrás e corrigir o directório? - + The path to your deck directory is invalid. Would you like to go back and set the correct path? O directório do seu deck é inválido. Gostaria de voltar atrás e corrigir o directório? - + The path to your card pictures directory is invalid. Would you like to go back and set the correct path? O directório das imagens das cartas é inválido. Gostaria de voltar atrás e corrigir o directório? - + Settings Definições - + General Geral - + Appearance Aparência - + User interface Interface do utilizador - + Messages Mensagens - + &Close &Fechar @@ -871,65 +902,69 @@ GameSelector - - - - + + + + Error Erro - + Wrong password. Password incorrecta. - + Spectators are not allowed in this game. Não são permitidos espectadores neste jogo. - + The game is already full. O jogo já se encontra cheio. - + The game does not exist any more. O jogo já não existe. - + Join game Entrar no jogo - + Password: Password: - + Games Jogos - - &Show full games + + Show &full games &Mostrar jogos cheios - + &Show full games + &Mostrar jogos cheios + + + C&reate &Criar - + &Join &Entrar - + J&oin as spectator Entrar como &espectador @@ -937,7 +972,7 @@ GameView - + Esc Esc @@ -1044,136 +1079,179 @@ MainWindow - + Number of players Número de jogadores - + Please enter the number of players. Por favor introduza o número de jogadores. - - + + Player %1 Jogador %1 - + About Cockatrice Sobre o Cockatrice - <font size="8"><b>Cockatrice</b></font><br>Version %1<br><br><br><b>Authors:</b><br>Max-Wilhelm Bruker<br>Marcus Schütz<br>Marius van Zundert<br><br><b>Translators:</b><br>Spanish: Gocho<br>Portugese: Milton Gonçalves<br> - <font size="8"><b>Cockatrice</b></font><br>Versão %1<br><br><br><b>Autores:</b><br>Max-Wilhelm Bruker<br>Marcus Schütz<br>Marius van Zundert<br><br><b>Tradutores:</b><br>Espanhol: Gocho<br>Português: Milton Gonçalves<br> + <font size="8"><b>Cockatrice</b></font><br>Versão %1<br><br><br><b>Autores:</b><br>Max-Wilhelm Bruker<br>Marcus Schütz<br>Marius van Zundert<br><br><b>Tradutores:</b><br>Espanhol: Gocho<br>Português: Milton Gonçalves<br> + Version %1 + Versão %1 + + + + Authors: + Autores: + + + + Translators: + Tradutores: + + + + Spanish: + Espanhol: + + + Portugese: + Português: + + + + Portugese (Portugal): + + + + + Portugese (Brazil): + + + + French: + Francês: + + + + Japanese: + + + - + + + Error Erro - + Server timeout Tempo do servidor esgotado - + Invalid login data. Informação de login incorrecta. - + Socket error: %1 Erro de ligação:%1 - + Protocol version mismatch. Local version: %1, remote version: %2. Versão dos protocolos incompatível. Versão local:%1, versão remota:%2. - + Connecting to %1... Ligando a %1... - + Disconnected Desligado - + Logged in at %1 Logado em %1 - + &Connect... &Ligar... - + &Disconnect &Desligar - + Start &local game... Começar &jogo local... - + &Deck editor &Editor de decks - + &Full screen Ecrã &inteiro - + Ctrl+F Ctrl+F - + &Settings... &Configurações... - + &Exit &Sair - + &Cockatrice &Cockatrice - + &About Cockatrice S&obre o Cockatrice - + &Help &Ajuda - + Are you sure? Tens a certeza? - + There are still open games. Are you sure you want to quit? Ainda há jogos abertos. Tem a certeza que deseja sair? @@ -1346,103 +1424,108 @@ da pilha - + %1 puts %2 into play%3. %1 coloca %2 em jogo %3. - + %1 puts %2%3 into graveyard. %1 coloca %2%3 no cemitério. - + %1 exiles %2%3. %1 exila %2%3. - + %1 moves %2%3 to hand. %1 move %2%3 para a mão. - + %1 puts %2%3 into his library. %1 coloca %2%3 no seu grimório. - + %1 puts %2%3 on bottom of his library. %1 coloca %2%3 no topo do seu grimório. - + %1 puts %2%3 on top of his library. %1 coloca %2%3 no topo do seu grimório. - + %1 puts %2%3 into his library at position %4. %1 coloca %2%3 no seu grimório na posição %4. - + %1 moves %2%3 to sideboard. %1 move %2%3 para o sideboard. - + %1 plays %2%3. %1 joga %2%3. - - + + a card uma carta - + + %1 gives %2 control over %3. + %1 dá controlo sobre %3 a %2. + + + %1 flips %2 face-down. %1 volta a face de %2 para baixo. - + %1 flips %2 face-up. %1 volta a face de %2 para cima. - + %1 destroys %2. %1 destroí %2. - + %1 attaches %2 to %3's %4. %1 anexa %2 a %4 de %3. - + %1 unattaches %2. %1 desanexa %2. - + %1 creates token: %2%3. %1 cria ficha: %2%3. - + %1 points from %2's %3 to %4. %1 aponta de %3 de %2 para %4. - + %1 points from %2's %3 to %4's %5. %1 aponta de %3 de %2 para %5 de %4. - + %1 places %n counter(s) (%2) on %3 (now %4). %1 coloca %n marcador (%2)de %3 (agora com %4). @@ -1450,7 +1533,7 @@ - + %1 removes %n counter(s) (%2) from %3 (now %4). %1 remove %n marcador (%2)de %3 (agora com %4). @@ -1458,172 +1541,172 @@ - + red vermelho - + yellow amarelo - + green verde - + his permanents as suas permanentes - + %1 %2 %3. %1 %2 %3. - + taps vira - + untaps desvira - + %1 sets counter %2 to %3 (%4%5). %1 altera o número de marcadores %2 para %3(%4%5). - + %1 sets %2 to not untap normally. %1 define %2 para não desvirar normalmente. - + %1 sets %2 to untap normally. %1 define %2 para desvirar normalmente. - + %1 sets PT of %2 to %3. %1 define o P/R de %2 como %3. - + %1 sets annotation of %2 to %3. %1 coloca uma nota de %2 em%3. - + %1 is looking at the top %2 cards %3. %1 está a olhar para as %2 cartas do topo %3. - + %1 is looking at %2. %1 está a olhar para %2. - + %1 stops looking at %2. %1 para de olhar para %2. - + %1 reveals %2 to %3. %1 revela %2 a %3. - + %1 reveals %2. %1 revela %2. - + %1 randomly reveals %2%3 to %4. %1 revela aleatoreamente %2%3. a %4. - + %1 randomly reveals %2%3. %1 revela aleatoreamente %2%3. - + %1 reveals %2%3 to %4. %1 revela %2%3 a %4. - + %1 reveals %2%3. %1 revela %2%3. - + It is now %1's turn. É agora o turno de %1. - + untap step Etapa de Desvirar - + upkeep step Etapa de Manutenção - + draw step Etapa de Compra - + first main phase 1ª Fase Principal (pré-combate) - + beginning of combat step Etapa de Início de Combate - + declare attackers step Etapa de Declaração de Atacantes - + declare blockers step Etapa de Declaração de Bloqueadores - + combat damage step Etapa de Dano de Combate - + end of combat step Etapa de Fim de Combate - + second main phase 2ª Fase Principal (pós-combate) - + ending phase Fase Final - + It is now the %1. É agora a %1. @@ -1631,22 +1714,22 @@ MessagesSettingsPage - + Add message Adicionar mensagem - + Message: Mensagem: - + &Add &Adicionar - + &Remove &Remover @@ -1654,57 +1737,57 @@ PhasesToolbar - + Untap step Etapa de Desvirar - + Upkeep step Etapa de manutenção - + Draw step Etapa de compra - + First main phase 1ª Fase Principal (pré-combate) - + Beginning of combat step Etapa de Início de Combate - + Declare attackers step Etapa de Declaração de Atacantes - + Declare blockers step Etapa de Declaração de Bloqueadores - + Combat damage step Etapa de Dano de Combate - + End of combat step Etapa de Fim de Combate - + Second main phase 2ª Fase Principal (pós-combate) - + End of turn step Fase Final @@ -1712,302 +1795,307 @@ Player - + &View graveyard &Ver cemitério - + &View exile &Ver exílio - + Player "%1" Jogador "%1" - + &Graveyard &Cemitério - + &Exile &Exílio - - - + + + Move to &top of library Mover para o &topo do grimório - - - + + + Move to &bottom of library Mover para o &fundo do grimório - - + + Move to &graveyard Mover para o &cemitério - - + + Move to &exile Mover para o &exílio - - + + Move to &hand Mover para a &mão - + &View library &Ver grimório - + View &top cards of library... Ver as cartas do &topo do grimório... - + Reveal &library to Revelar &grimório a - + Reveal t&op card to Revelar carta do t&opo a - + &View sideboard &Ver sideboard - + &Draw card &Comprar carta - + D&raw cards... C&omprar cartas... - + Take &mulligan Fazer &mulligan - + &Shuffle &Baralhar - + Move top cards to &graveyard... Mover as cartas do topo para o &cemitério... - + Move top cards to &exile... Mover as cartas do topo para o &exílio... - + + Put top card on &bottom + Colocar carta do topo no &fundo + + + &Hand &Mão - + &Reveal to &Revelar a - + Reveal r&andom card to Revelar carta &aleatória a - + &Sideboard &Sideboard - + &Library &Grimório - + &Counters &Marcadores - + &Untap all permanents &Desvirar topas as permanentes - + R&oll die... &Lançar dado... - + &Create token... Criar fic&ha... - + C&reate another token Cr&iar outra ficha - + S&ay &Dizer - + C&ard C&arta - + &All players Todos os &jogadores - + F3 F3 - + Ctrl+W Ctrl+W - + F4 F4 - + Ctrl+D Ctrl+D - + Ctrl+E Ctrl+E - + Ctrl+M Ctrl+M - + Ctrl+S Ctrl+S - + Ctrl+U Ctrl+U - + Ctrl+I Ctrl+I - + Ctrl+T Ctrl+T - + Ctrl+G Ctrl+G - + View top cards of library Ver as cartas do topo do grimório - + Number of cards: Número de cartas: - + Draw cards Comprar cartas - - - - + + + + Number: Número: - + Move top cards to grave Mover as cartas to topo para o cemitério - + Move top cards to exile Mover as cartas to topo para o exílio - + Roll die Lançar dado - + Number of sides: Número de faces: - + Set power/toughness Definir poder/resistência - + Please enter the new PT: Por favor introduza o novo P/R: - + Set annotation Colocar nota - + Please enter the new annotation: Por favor introduza a nova nota: - + Set counters Definir marcadores @@ -2053,17 +2141,17 @@ Sideboard - + Cockatrice decks (*.cod) Decks do Cockatrice (*.cod) - + Plain text decks (*.dec *.mwDeck) Decks baseados em texto simples (*.dec *.mwDeck) - + All files (*.*) Todos os ficheiros (*.*) @@ -2086,12 +2174,44 @@ Hora de upload + + RoomSelector + + + Rooms + Salas + + + + Joi&n + E&ntrar + + + + Room + Sala + + + + Description + Descrição + + + + Players + Jogadores + + + + Games + Jogos + + ServerMessageLog - Server messages - Mensagens do serivdor + Mensagens do serivdor @@ -2107,27 +2227,61 @@ Nome longo + + TabAdmin + + + Update server &message + + + + + Server administration functions + + + + + &Unlock functions + + + + + &Lock functions + + + + + Unlock administration functions + + + + + Do you really want to unlock the administration functions? + + + + + Administration + + + TabChatChannel - C&hat channel - Ca&nal de Conversação + Ca&nal de Conversação - &Leave channel - &Abandonar canal + &Abandonar canal - %1 has joined the channel. - %1 entrou no canal. + %1 entrou no canal. - %1 has left the channel. - %1 abandonou o canal. + %1 abandonou o canal. @@ -2201,87 +2355,87 @@ Por favor introduza um nome: TabGame - + &Game &Jogo - + Next &phase Próxima &fase - + Ctrl+Space Ctrl+Space - + Next &turn Próximo &turno - + Ctrl+Return Ctrl+Return - + Ctrl+Enter Ctrl+Enter - + &Remove all local arrows &Remover todas as setas locais - + Ctrl+R Ctrl+R - + &Concede &Conceder - + F2 F2 - + &Leave game Sair do &jogo - + &Say: &Dizer: - + Concede Conceder - + Are you sure you want to concede this game? Tem a certeza que deseja conceder este jogo? - + Leave game Sair do jogo - + Are you sure you want to leave this game? Tem a certeza que deseja sair deste jogo? - + Game %1: %2 Jogo %1: %2 @@ -2309,10 +2463,43 @@ Por favor introduza um nome: Falar para %1 + + TabRoom + + + &Say: + &Dizer: + + + + Chat + + + + + &Room + &Sala + + + + &Leave room + &Abandonar a sala + + + + %1 has joined the room. + %1 entrou na sala. + + + + %1 has left the room. + %1 abandonou na sala. + + TabServer - + Server Servidor @@ -2320,35 +2507,65 @@ Por favor introduza um nome: UserInfoBox - + + User information + + + + + Real name: + + + + Location: Localização: - + User level: Nível de utilizador: + + + Administrator + Administrador + + + + Judge + Juiz + + + + Registered user + Utilizador registado + + + + Unregistered user + Utilizador não registado + UserInterfaceSettingsPage - + General interface settings Configurações gerais da interface - + &Double-click cards to play them (instead of single-click) Clicar &duas vezes nas cartas para as jogar (ao invés de clicar apenas uma vez) - + Animation settings Configurações de Animações - + &Tap/untap animation Animação de &virar/desvirar @@ -2356,10 +2573,25 @@ Por favor introduza um nome: UserList - + Users online: %1 Utilizadores online: %1 + + + Users in this room: %1 + Utilizadores nesta sala:%1 + + + + User &details + + + + + Direct &chat + + WndDeckEditor @@ -2531,7 +2763,21 @@ Gostaria de guardar as alterações? Carregar deck - + + + Error + Erro + + + + + The deck could not be saved. +Please check that the directory is writable and try again. + O deck não pode ser guardado. +Por favor confirme se é possível escrever do directório e tente de novo. + + + Save deck Guardar deck diff --git a/common/decklist.cpp b/common/decklist.cpp index ec5efbf5..1e7e0b07 100644 --- a/common/decklist.cpp +++ b/common/decklist.cpp @@ -109,7 +109,6 @@ AbstractDecklistNode *InnerDecklistNode::findChild(const QString &name) int InnerDecklistNode::height() const { - Q_ASSERT(!isEmpty()); return at(0)->height() + 1; } @@ -469,11 +468,6 @@ void DeckList::cleanList() setComments(); } -bool DeckList::isEmpty() const -{ - return root->isEmpty(); -} - DecklistCardNode *DeckList::addCard(const QString &cardName, const QString &zoneName) { InnerDecklistNode *zoneNode = dynamic_cast(root->findChild(zoneName)); diff --git a/common/decklist.h b/common/decklist.h index eca8dda0..d54959e2 100644 --- a/common/decklist.h +++ b/common/decklist.h @@ -148,7 +148,7 @@ public: static FileFormat getFormatFromNameFilter(const QString &selectedNameFilter); void cleanList(); - bool isEmpty() const; + bool isEmpty() const { return root->isEmpty() && name.isEmpty() && comments.isEmpty() && sideboardPlans.isEmpty(); } InnerDecklistNode *getRoot() const { return root; } DecklistCardNode *addCard(const QString &cardName, const QString &zoneName); diff --git a/common/protocol.cpp b/common/protocol.cpp index ccfc081a..3448de77 100644 --- a/common/protocol.cpp +++ b/common/protocol.cpp @@ -14,7 +14,7 @@ void ProtocolItem::initializeHash() initializeHashAuto(); registerSerializableItem("move_card_to_zone", MoveCardToZone::newItem); - registerSerializableItem("chat_channel", ServerInfo_ChatChannel::newItem); + registerSerializableItem("room", ServerInfo_Room::newItem); registerSerializableItem("user", ServerInfo_User::newItem); registerSerializableItem("game", ServerInfo_Game::newItem); registerSerializableItem("card_counter", ServerInfo_CardCounter::newItem); @@ -27,6 +27,7 @@ void ProtocolItem::initializeHash() registerSerializableItem("player_ping", ServerInfo_PlayerPing::newItem); registerSerializableItem("file", DeckList_File::newItem); registerSerializableItem("directory", DeckList_Directory::newItem); + registerSerializableItem("card_id", CardId::newItem); registerSerializableItem("containercmd", CommandContainer::newItem); registerSerializableItem("containergame_event", GameEventContainer::newItem); @@ -34,19 +35,23 @@ void ProtocolItem::initializeHash() registerSerializableItem("cmddeck_upload", Command_DeckUpload::newItem); registerSerializableItem("cmddeck_select", Command_DeckSelect::newItem); registerSerializableItem("cmdset_sideboard_plan", Command_SetSideboardPlan::newItem); + registerSerializableItem("cmdmove_card", Command_MoveCard::newItem); registerSerializableItem("resp", ProtocolResponse::newItem); ProtocolResponse::initializeHash(); + registerSerializableItem("respjoin_room", Response_JoinRoom::newItem); registerSerializableItem("resplist_users", Response_ListUsers::newItem); registerSerializableItem("respget_user_info", Response_GetUserInfo::newItem); registerSerializableItem("respdeck_list", Response_DeckList::newItem); registerSerializableItem("respdeck_download", Response_DeckDownload::newItem); registerSerializableItem("respdeck_upload", Response_DeckUpload::newItem); registerSerializableItem("respdump_zone", Response_DumpZone::newItem); + registerSerializableItem("resplogin", Response_Login::newItem); - registerSerializableItem("generic_eventlist_games", Event_ListGames::newItem); + registerSerializableItem("room_eventlist_games", Event_ListGames::newItem); + registerSerializableItem("room_eventjoin_room", Event_JoinRoom::newItem); registerSerializableItem("generic_eventuser_joined", Event_UserJoined::newItem); - registerSerializableItem("generic_eventlist_chat_channels", Event_ListChatChannels::newItem); + registerSerializableItem("generic_eventlist_rooms", Event_ListRooms::newItem); registerSerializableItem("game_eventjoin", Event_Join::newItem); registerSerializableItem("game_eventgame_state_changed", Event_GameStateChanged::newItem); registerSerializableItem("game_eventplayer_properties_changed", Event_PlayerPropertiesChanged::newItem); @@ -55,8 +60,6 @@ void ProtocolItem::initializeHash() registerSerializableItem("game_eventdraw_cards", Event_DrawCards::newItem); registerSerializableItem("game_eventreveal_cards", Event_RevealCards::newItem); registerSerializableItem("game_eventping", Event_Ping::newItem); - registerSerializableItem("chat_eventchat_list_players", Event_ChatListPlayers::newItem); - registerSerializableItem("chat_eventchat_join_channel", Event_ChatJoinChannel::newItem); } TopLevelProtocolItem::TopLevelProtocolItem() @@ -197,6 +200,21 @@ QList Command_SetSideboardPlan::getMoveList() const return typecastItemList(); } +Command_MoveCard::Command_MoveCard(int _gameId, const QString &_startZone, const QList &_cardIds, int _targetPlayerId, const QString &_targetZone, int _x, int _y, bool _faceDown, bool _tapped) + : GameCommand("move_card", _gameId) +{ + insertItem(new SerializableItem_String("start_zone", _startZone)); + insertItem(new SerializableItem_Int("target_player_id", _targetPlayerId)); + insertItem(new SerializableItem_String("target_zone", _targetZone)); + insertItem(new SerializableItem_Int("x", _x)); + insertItem(new SerializableItem_Int("y", _y)); + insertItem(new SerializableItem_Bool("face_down", _faceDown)); + insertItem(new SerializableItem_Bool("tapped", _tapped)); + + for (int i = 0; i < _cardIds.size(); ++i) + itemList.append(_cardIds[i]); +} + QHash ProtocolResponse::responseHash; ProtocolResponse::ProtocolResponse(int _cmdId, ResponseCode _responseCode, const QString &_itemName) @@ -221,6 +239,14 @@ void ProtocolResponse::initializeHash() responseHash.insert("spectators_not_allowed", RespSpectatorsNotAllowed); } +Response_JoinRoom::Response_JoinRoom(int _cmdId, ResponseCode _responseCode, ServerInfo_Room *_roomInfo) + : ProtocolResponse(_cmdId, _responseCode, "join_room") +{ + if (!_roomInfo) + _roomInfo = new ServerInfo_Room; + insertItem(_roomInfo); +} + Response_ListUsers::Response_ListUsers(int _cmdId, ResponseCode _responseCode, const QList &_userList) : ProtocolResponse(_cmdId, _responseCode, "list_users") { @@ -273,6 +299,14 @@ Response_DumpZone::Response_DumpZone(int _cmdId, ResponseCode _responseCode, Ser insertItem(_zone); } +Response_Login::Response_Login(int _cmdId, ResponseCode _responseCode, ServerInfo_User *_userInfo) + : ProtocolResponse(_cmdId, _responseCode, "login") +{ + if (!_userInfo) + _userInfo = new ServerInfo_User; + insertItem(_userInfo); +} + GameEvent::GameEvent(const QString &_eventName, int _playerId) : ProtocolItem("game_event", _eventName) { @@ -284,36 +318,29 @@ GameEventContext::GameEventContext(const QString &_contextName) { } -ChatEvent::ChatEvent(const QString &_eventName, const QString &_channel) - : ProtocolItem("chat_event", _eventName) +RoomEvent::RoomEvent(const QString &_eventName, int _roomId) + : ProtocolItem("room_event", _eventName) { - insertItem(new SerializableItem_String("channel", _channel)); + insertItem(new SerializableItem_Int("room_id", _roomId)); } -Event_ListChatChannels::Event_ListChatChannels(const QList &_channelList) - : GenericEvent("list_chat_channels") +Event_ListRooms::Event_ListRooms(const QList &_roomList) + : GenericEvent("list_rooms") { - for (int i = 0; i < _channelList.size(); ++i) - itemList.append(_channelList[i]); + for (int i = 0; i < _roomList.size(); ++i) + itemList.append(_roomList[i]); } -Event_ChatListPlayers::Event_ChatListPlayers(const QString &_channel, const QList &_playerList) - : ChatEvent("chat_list_players", _channel) -{ - for (int i = 0; i < _playerList.size(); ++i) - itemList.append(_playerList[i]); -} - -Event_ChatJoinChannel::Event_ChatJoinChannel(const QString &_channel, ServerInfo_User *_info) - : ChatEvent("chat_join_channel", _channel) +Event_JoinRoom::Event_JoinRoom(int _roomId, ServerInfo_User *_info) + : RoomEvent("join_room", _roomId) { if (!_info) _info = new ServerInfo_User; insertItem(_info); } -Event_ListGames::Event_ListGames(const QList &_gameList) - : GenericEvent("list_games") +Event_ListGames::Event_ListGames(int _roomId, const QList &_gameList) + : RoomEvent("list_games", _roomId) { for (int i = 0; i < _gameList.size(); ++i) itemList.append(_gameList[i]); @@ -404,9 +431,10 @@ Event_PlayerPropertiesChanged::Event_PlayerPropertiesChanged(int _playerId, Serv insertItem(_properties); } -Event_Ping::Event_Ping(const QList &_pingList) +Event_Ping::Event_Ping(int _secondsElapsed, const QList &_pingList) : GameEvent("ping", -1) { + insertItem(new SerializableItem_Int("seconds_elapsed", _secondsElapsed)); for (int i = 0; i < _pingList.size(); ++i) itemList.append(_pingList[i]); } diff --git a/common/protocol.h b/common/protocol.h index e42d5456..d23969d6 100644 --- a/common/protocol.h +++ b/common/protocol.h @@ -25,9 +25,9 @@ enum ItemId { ItemId_Command_DeckUpload = ItemId_Other + 100, ItemId_Command_DeckSelect = ItemId_Other + 101, ItemId_Command_SetSideboardPlan = ItemId_Other + 102, - ItemId_Event_ListChatChannels = ItemId_Other + 200, - ItemId_Event_ChatListPlayers = ItemId_Other + 201, - ItemId_Event_ChatJoinChannel = ItemId_Other + 202, + ItemId_Command_MoveCard = ItemId_Other + 103, + ItemId_Event_ListRooms = ItemId_Other + 200, + ItemId_Event_JoinRoom = ItemId_Other + 201, ItemId_Event_ListGames = ItemId_Other + 203, ItemId_Event_UserJoined = ItemId_Other + 204, ItemId_Event_GameStateChanged = ItemId_Other + 205, @@ -44,6 +44,8 @@ enum ItemId { ItemId_Response_DeckDownload = ItemId_Other + 303, ItemId_Response_DeckUpload = ItemId_Other + 304, ItemId_Response_DumpZone = ItemId_Other + 305, + ItemId_Response_JoinRoom = ItemId_Other + 306, + ItemId_Response_Login = ItemId_Other + 307, ItemId_Invalid = ItemId_Other + 1000 }; @@ -53,12 +55,13 @@ private: static void initializeHashAuto(); bool receiverMayDelete; public: - static const int protocolVersion = 10; + static const int protocolVersion = 11; static void initializeHash(); virtual int getItemId() const = 0; bool getReceiverMayDelete() const { return receiverMayDelete; } void setReceiverMayDelete(bool _receiverMayDelete) { receiverMayDelete = _receiverMayDelete; } ProtocolItem(const QString &_itemType, const QString &_itemSubType); + bool isEmpty() const { return false; } }; class ProtocolItem_Invalid : public ProtocolItem { @@ -78,6 +81,7 @@ public: TopLevelProtocolItem(); bool readElement(QXmlStreamReader *xml); void writeElement(QXmlStreamWriter *xml); + bool isEmpty() const { return false; } }; // ---------------- @@ -136,15 +140,15 @@ public: int getPrivatePlayerId() const { return privatePlayerId; } }; -class ChatCommand : public Command { +class RoomCommand : public Command { Q_OBJECT public: - ChatCommand(const QString &_cmdName, const QString &_channel) + RoomCommand(const QString &_cmdName, int _roomId) : Command(_cmdName) { - insertItem(new SerializableItem_String("channel", _channel)); + insertItem(new SerializableItem_Int("room_id", _roomId)); } - QString getChannel() const { return static_cast(itemMap.value("channel"))->getData(); } + int getRoomId() const { return static_cast(itemMap.value("room_id"))->getData(); } }; class GameCommand : public Command { @@ -159,6 +163,15 @@ public: void setGameId(int _gameId) { static_cast(itemMap.value("game_id"))->setData(_gameId); } }; +class AdminCommand : public Command { + Q_OBJECT +public: + AdminCommand(const QString &_cmdName) + : Command(_cmdName) + { + } +}; + class Command_DeckUpload : public Command { Q_OBJECT public: @@ -188,6 +201,22 @@ public: QList getMoveList() const; }; +class Command_MoveCard : public GameCommand { + Q_OBJECT +public: + Command_MoveCard(int _gameId = -1, const QString &_startZone = QString(), const QList &_cardIds = QList(), int _targetPlayerId = -1, const QString &_targetZone = QString(), int _x = -1, int _y = -1, bool _faceDown = false, bool _tapped = false); + QString getStartZone() const { return static_cast(itemMap.value("start_zone"))->getData(); } + QList getCardIds() const { return typecastItemList(); } + int getTargetPlayerId() const { return static_cast(itemMap.value("target_player_id"))->getData(); } + QString getTargetZone() const { return static_cast(itemMap.value("target_zone"))->getData(); } + int getX() const { return static_cast(itemMap.value("x"))->getData(); } + int getY() const { return static_cast(itemMap.value("y"))->getData(); } + bool getFaceDown() const { return static_cast(itemMap.value("face_down"))->getData(); } + bool getTapped() const { return static_cast(itemMap.value("tapped"))->getData(); } + static SerializableItem *newItem() { return new Command_MoveCard; } + int getItemId() const { return ItemId_Command_MoveCard; } +}; + // ----------------- // --- RESPONSES --- // ----------------- @@ -205,6 +234,15 @@ public: ResponseCode getResponseCode() const { return responseHash.value(static_cast(itemMap.value("response_code"))->getData(), RespOk); } }; +class Response_JoinRoom : public ProtocolResponse { + Q_OBJECT +public: + Response_JoinRoom(int _cmdId = -1, ResponseCode _responseCode = RespOk, ServerInfo_Room *_roomInfo = 0); + int getItemId() const { return ItemId_Response_JoinRoom; } + static SerializableItem *newItem() { return new Response_JoinRoom; } + ServerInfo_Room *getRoomInfo() const { return static_cast(itemMap.value("room")); } +}; + class Response_ListUsers : public ProtocolResponse { Q_OBJECT public: @@ -259,6 +297,15 @@ public: ServerInfo_Zone *getZone() const { return static_cast(itemMap.value("zone")); } }; +class Response_Login : public ProtocolResponse { + Q_OBJECT +public: + Response_Login(int _cmdId = -1, ResponseCode _responseCode = RespOk, ServerInfo_User *_userInfo = 0); + int getItemId() const { return ItemId_Response_Login; } + static SerializableItem *newItem() { return new Response_Login; } + ServerInfo_User *getUserInfo() const { return static_cast(itemMap.value("user")); } +}; + // -------------- // --- EVENTS --- // -------------- @@ -304,44 +351,35 @@ public: void setGameId(int _gameId) { static_cast(itemMap.value("game_id"))->setData(_gameId); } }; -class ChatEvent : public ProtocolItem { +class RoomEvent : public ProtocolItem { Q_OBJECT public: - ChatEvent(const QString &_eventName, const QString &_channel); - QString getChannel() const { return static_cast(itemMap.value("channel"))->getData(); } + RoomEvent(const QString &_eventName, int _roomId); + int getRoomId() const { return static_cast(itemMap.value("room_id"))->getData(); } }; -class Event_ListChatChannels : public GenericEvent { +class Event_ListRooms : public GenericEvent { Q_OBJECT public: - Event_ListChatChannels(const QList &_channelList = QList()); - int getItemId() const { return ItemId_Event_ListChatChannels; } - static SerializableItem *newItem() { return new Event_ListChatChannels; } - QList getChannelList() const { return typecastItemList(); } + Event_ListRooms(const QList &_roomList = QList()); + int getItemId() const { return ItemId_Event_ListRooms; } + static SerializableItem *newItem() { return new Event_ListRooms; } + QList getRoomList() const { return typecastItemList(); } }; -class Event_ChatListPlayers : public ChatEvent { +class Event_JoinRoom : public RoomEvent { Q_OBJECT public: - Event_ChatListPlayers(const QString &_channel = QString(), const QList &_playerList = QList()); - int getItemId() const { return ItemId_Event_ChatListPlayers; } - static SerializableItem *newItem() { return new Event_ChatListPlayers; } - QList getPlayerList() const { return typecastItemList(); } -}; - -class Event_ChatJoinChannel : public ChatEvent { - Q_OBJECT -public: - Event_ChatJoinChannel(const QString &_channel = QString(), ServerInfo_User *_info = 0); - int getItemId() const { return ItemId_Event_ChatJoinChannel; } - static SerializableItem *newItem() { return new Event_ChatJoinChannel; } + Event_JoinRoom(int _roomId = -1, ServerInfo_User *_info = 0); + int getItemId() const { return ItemId_Event_JoinRoom; } + static SerializableItem *newItem() { return new Event_JoinRoom; } ServerInfo_User *getUserInfo() const { return static_cast(itemMap.value("user")); } }; -class Event_ListGames : public GenericEvent { +class Event_ListGames : public RoomEvent { Q_OBJECT public: - Event_ListGames(const QList &_gameList = QList()); + Event_ListGames(int _roomId = -1, const QList &_gameList = QList()); int getItemId() const { return ItemId_Event_ListGames; } static SerializableItem *newItem() { return new Event_ListGames; } QList getGameList() const { return typecastItemList(); } @@ -389,9 +427,10 @@ public: class Event_Ping : public GameEvent { Q_OBJECT public: - Event_Ping(const QList &_pingList = QList()); + Event_Ping(int _secondsElapsed = -1, const QList &_pingList = QList()); static SerializableItem *newItem() { return new Event_Ping; } int getItemId() const { return ItemId_Event_Ping; } + int getSecondsElapsed() const { return static_cast(itemMap.value("seconds_elapsed"))->getData(); } QList getPingList() const { return typecastItemList(); } }; diff --git a/common/protocol_datastructures.cpp b/common/protocol_datastructures.cpp index afbf726a..20c85506 100644 --- a/common/protocol_datastructures.cpp +++ b/common/protocol_datastructures.cpp @@ -3,31 +3,24 @@ #include #include -ServerInfo_ChatChannel::ServerInfo_ChatChannel(const QString &_name, const QString &_description, int _playerCount, bool _autoJoin) - : SerializableItem_Map("chat_channel") -{ - insertItem(new SerializableItem_String("name", _name)); - insertItem(new SerializableItem_String("description", _description)); - insertItem(new SerializableItem_Int("player_count", _playerCount)); - insertItem(new SerializableItem_Bool("auto_join", _autoJoin)); -} - -ServerInfo_User::ServerInfo_User(const QString &_name, int _userLevel, const QString &_country, const QByteArray &_avatarBmp) +ServerInfo_User::ServerInfo_User(const QString &_name, int _userLevel, const QString &_realName, const QString &_country, const QByteArray &_avatarBmp) : SerializableItem_Map("user") { insertItem(new SerializableItem_String("name", _name)); insertItem(new SerializableItem_Int("userlevel", _userLevel)); + insertItem(new SerializableItem_String("real_name", _realName)); insertItem(new SerializableItem_String("country", _country)); insertItem(new SerializableItem_ByteArray("avatar_bmp", _avatarBmp)); } -ServerInfo_User::ServerInfo_User(const ServerInfo_User *other) +ServerInfo_User::ServerInfo_User(const ServerInfo_User *other, bool complete) : SerializableItem_Map("user") { insertItem(new SerializableItem_String("name", other->getName())); insertItem(new SerializableItem_Int("userlevel", other->getUserLevel())); + insertItem(new SerializableItem_String("real_name", other->getRealName())); insertItem(new SerializableItem_String("country", other->getCountry())); - insertItem(new SerializableItem_ByteArray("avatar_bmp", other->getAvatarBmp())); + insertItem(new SerializableItem_ByteArray("avatar_bmp", complete ? other->getAvatarBmp() : QByteArray())); } ServerInfo_Game::ServerInfo_Game(int _gameId, const QString &_description, bool _hasPassword, int _playerCount, int _maxPlayers, ServerInfo_User *_creatorInfo, bool _spectatorsAllowed, bool _spectatorsNeedPassword, int _spectatorCount) @@ -46,6 +39,40 @@ ServerInfo_Game::ServerInfo_Game(int _gameId, const QString &_description, bool insertItem(new SerializableItem_Int("spectator_count", _spectatorCount)); } +ServerInfo_Room::ServerInfo_Room(int _roomId, const QString &_name, const QString &_description, int _gameCount, int _playerCount, bool _autoJoin, const QList &_gameList, const QList &_userList) + : SerializableItem_Map("room") +{ + insertItem(new SerializableItem_Int("room_id", _roomId)); + insertItem(new SerializableItem_String("name", _name)); + insertItem(new SerializableItem_String("description", _description)); + insertItem(new SerializableItem_Int("game_count", _gameCount)); + insertItem(new SerializableItem_Int("player_count", _playerCount)); + insertItem(new SerializableItem_Bool("auto_join", _autoJoin)); + + gameList = _gameList; + for (int i = 0; i < _gameList.size(); ++i) + itemList.append(_gameList[i]); + userList = _userList; + for (int i = 0; i < _userList.size(); ++i) + itemList.append(_userList[i]); +} + +void ServerInfo_Room::extractData() +{ + for (int i = 0; i < itemList.size(); ++i) { + ServerInfo_User *user = dynamic_cast(itemList[i]); + if (user) { + userList.append(user); + continue; + } + ServerInfo_Game *game = dynamic_cast(itemList[i]); + if (game) { + gameList.append(game); + continue; + } + } +} + ServerInfo_CardCounter::ServerInfo_CardCounter(int _id, int _value) : SerializableItem_Map("card_counter") { diff --git a/common/protocol_datastructures.h b/common/protocol_datastructures.h index ff16b667..a6a9c9ac 100644 --- a/common/protocol_datastructures.h +++ b/common/protocol_datastructures.h @@ -20,14 +20,10 @@ enum ResponseCode { RespNothing, RespOk, RespInvalidCommand, RespInvalidData, Re // list index, whereas cards in any other zone are referenced by their ids. enum ZoneType { PrivateZone, PublicZone, HiddenZone }; -class ServerInfo_ChatChannel : public SerializableItem_Map { +class CardId : public SerializableItem_Int { public: - ServerInfo_ChatChannel(const QString &_name = QString(), const QString &_description = QString(), int _playerCount = -1, bool _autoJoin = false); - static SerializableItem *newItem() { return new ServerInfo_ChatChannel; } - QString getName() const { return static_cast(itemMap.value("name"))->getData(); } - QString getDescription() const { return static_cast(itemMap.value("description"))->getData(); } - int getPlayerCount() const { return static_cast(itemMap.value("player_count"))->getData(); } - bool getAutoJoin() const { return static_cast(itemMap.value("auto_join"))->getData(); } + CardId(int _cardId = -1) : SerializableItem_Int("card_id", _cardId) { } + static SerializableItem *newItem() { return new CardId; } }; class ServerInfo_User : public SerializableItem_Map { @@ -39,12 +35,13 @@ public: IsJudge = 0x04, IsAdmin = 0x08 }; - ServerInfo_User(const QString &_name = QString(), int _userLevel = IsNothing, const QString &_country = QString(), const QByteArray &_avatarBmp = QByteArray()); - ServerInfo_User(const ServerInfo_User *other); + ServerInfo_User(const QString &_name = QString(), int _userLevel = IsNothing, const QString &_realName = QString(), const QString &_country = QString(), const QByteArray &_avatarBmp = QByteArray()); + ServerInfo_User(const ServerInfo_User *other, bool complete = true); static SerializableItem *newItem() { return new ServerInfo_User; } QString getName() const { return static_cast(itemMap.value("name"))->getData(); } int getUserLevel() const { return static_cast(itemMap.value("userlevel"))->getData(); } void setUserLevel(int _userLevel) { static_cast(itemMap.value("userlevel"))->setData(_userLevel); } + QString getRealName() const { return static_cast(itemMap.value("real_name"))->getData(); } QString getCountry() const { return static_cast(itemMap.value("country"))->getData(); } QByteArray getAvatarBmp() const { return static_cast(itemMap.value("avatar_bmp"))->getData(); } }; @@ -64,6 +61,25 @@ public: int getSpectatorCount() const { return static_cast(itemMap.value("spectator_count"))->getData(); } }; +class ServerInfo_Room : public SerializableItem_Map { +private: + QList gameList; + QList userList; +protected: + void extractData(); +public: + ServerInfo_Room(int _id = -1, const QString &_name = QString(), const QString &_description = QString(), int _gameCount = -1, int _playerCount = -1, bool _autoJoin = false, const QList &_gameList = QList(), const QList &_userList = QList()); + static SerializableItem *newItem() { return new ServerInfo_Room; } + int getRoomId() const { return static_cast(itemMap.value("room_id"))->getData(); } + QString getName() const { return static_cast(itemMap.value("name"))->getData(); } + QString getDescription() const { return static_cast(itemMap.value("description"))->getData(); } + int getGameCount() const { return static_cast(itemMap.value("game_count"))->getData(); } + int getPlayerCount() const { return static_cast(itemMap.value("player_count"))->getData(); } + bool getAutoJoin() const { return static_cast(itemMap.value("auto_join"))->getData(); } + const QList &getGameList() const { return gameList; } + const QList &getUserList() const { return userList; } +}; + class ServerInfo_CardCounter : public SerializableItem_Map { public: ServerInfo_CardCounter(int _id = -1, int _value = 0); diff --git a/common/protocol_item_ids.h b/common/protocol_item_ids.h index 8404364b..2ed9fe3a 100644 --- a/common/protocol_item_ids.h +++ b/common/protocol_item_ids.h @@ -2,73 +2,72 @@ enum AutoItemId { ItemId_Command_Ping = 1001, ItemId_Command_Login = 1002, ItemId_Command_Message = 1003, -ItemId_Command_GetUserInfo = 1004, -ItemId_Command_DeckList = 1005, -ItemId_Command_DeckNewDir = 1006, -ItemId_Command_DeckDelDir = 1007, -ItemId_Command_DeckDel = 1008, -ItemId_Command_DeckDownload = 1009, -ItemId_Command_ListChatChannels = 1010, -ItemId_Command_ChatJoinChannel = 1011, -ItemId_Command_ChatLeaveChannel = 1012, -ItemId_Command_ChatSay = 1013, -ItemId_Command_ListGames = 1014, -ItemId_Command_ListUsers = 1015, -ItemId_Command_CreateGame = 1016, -ItemId_Command_JoinGame = 1017, -ItemId_Command_LeaveGame = 1018, -ItemId_Command_Say = 1019, -ItemId_Command_Shuffle = 1020, -ItemId_Command_Mulligan = 1021, -ItemId_Command_RollDie = 1022, -ItemId_Command_DrawCards = 1023, -ItemId_Command_MoveCard = 1024, -ItemId_Command_FlipCard = 1025, -ItemId_Command_AttachCard = 1026, -ItemId_Command_CreateToken = 1027, -ItemId_Command_CreateArrow = 1028, -ItemId_Command_DeleteArrow = 1029, -ItemId_Command_SetCardAttr = 1030, -ItemId_Command_SetCardCounter = 1031, -ItemId_Command_IncCardCounter = 1032, -ItemId_Command_ReadyStart = 1033, -ItemId_Command_Concede = 1034, -ItemId_Command_IncCounter = 1035, -ItemId_Command_CreateCounter = 1036, -ItemId_Command_SetCounter = 1037, -ItemId_Command_DelCounter = 1038, -ItemId_Command_NextTurn = 1039, -ItemId_Command_SetActivePhase = 1040, -ItemId_Command_DumpZone = 1041, -ItemId_Command_StopDumpZone = 1042, -ItemId_Command_RevealCards = 1043, -ItemId_Event_Say = 1044, -ItemId_Event_Leave = 1045, -ItemId_Event_GameClosed = 1046, -ItemId_Event_Shuffle = 1047, -ItemId_Event_RollDie = 1048, -ItemId_Event_MoveCard = 1049, -ItemId_Event_FlipCard = 1050, -ItemId_Event_DestroyCard = 1051, -ItemId_Event_AttachCard = 1052, -ItemId_Event_CreateToken = 1053, -ItemId_Event_DeleteArrow = 1054, -ItemId_Event_SetCardAttr = 1055, -ItemId_Event_SetCardCounter = 1056, -ItemId_Event_SetCounter = 1057, -ItemId_Event_DelCounter = 1058, -ItemId_Event_SetActivePlayer = 1059, -ItemId_Event_SetActivePhase = 1060, -ItemId_Event_DumpZone = 1061, -ItemId_Event_StopDumpZone = 1062, -ItemId_Event_ServerMessage = 1063, -ItemId_Event_Message = 1064, -ItemId_Event_GameJoined = 1065, -ItemId_Event_UserLeft = 1066, -ItemId_Event_ChatLeaveChannel = 1067, -ItemId_Event_ChatSay = 1068, -ItemId_Context_ReadyStart = 1069, -ItemId_Context_Concede = 1070, -ItemId_Context_DeckSelect = 1071, -ItemId_Other = 1072 +ItemId_Command_ListUsers = 1004, +ItemId_Command_GetUserInfo = 1005, +ItemId_Command_DeckList = 1006, +ItemId_Command_DeckNewDir = 1007, +ItemId_Command_DeckDelDir = 1008, +ItemId_Command_DeckDel = 1009, +ItemId_Command_DeckDownload = 1010, +ItemId_Command_ListRooms = 1011, +ItemId_Command_JoinRoom = 1012, +ItemId_Command_LeaveRoom = 1013, +ItemId_Command_RoomSay = 1014, +ItemId_Command_CreateGame = 1015, +ItemId_Command_JoinGame = 1016, +ItemId_Command_LeaveGame = 1017, +ItemId_Command_Say = 1018, +ItemId_Command_Shuffle = 1019, +ItemId_Command_Mulligan = 1020, +ItemId_Command_RollDie = 1021, +ItemId_Command_DrawCards = 1022, +ItemId_Command_FlipCard = 1023, +ItemId_Command_AttachCard = 1024, +ItemId_Command_CreateToken = 1025, +ItemId_Command_CreateArrow = 1026, +ItemId_Command_DeleteArrow = 1027, +ItemId_Command_SetCardAttr = 1028, +ItemId_Command_SetCardCounter = 1029, +ItemId_Command_IncCardCounter = 1030, +ItemId_Command_ReadyStart = 1031, +ItemId_Command_Concede = 1032, +ItemId_Command_IncCounter = 1033, +ItemId_Command_CreateCounter = 1034, +ItemId_Command_SetCounter = 1035, +ItemId_Command_DelCounter = 1036, +ItemId_Command_NextTurn = 1037, +ItemId_Command_SetActivePhase = 1038, +ItemId_Command_DumpZone = 1039, +ItemId_Command_StopDumpZone = 1040, +ItemId_Command_RevealCards = 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_LeaveRoom = 1065, +ItemId_Event_RoomSay = 1066, +ItemId_Context_ReadyStart = 1067, +ItemId_Context_Concede = 1068, +ItemId_Context_DeckSelect = 1069, +ItemId_Command_UpdateServerMessage = 1070, +ItemId_Other = 1071 }; diff --git a/common/protocol_items.cpp b/common/protocol_items.cpp index 57a32f63..0265652f 100644 --- a/common/protocol_items.cpp +++ b/common/protocol_items.cpp @@ -17,6 +17,10 @@ Command_Message::Command_Message(const QString &_userName, const QString &_text) insertItem(new SerializableItem_String("user_name", _userName)); insertItem(new SerializableItem_String("text", _text)); } +Command_ListUsers::Command_ListUsers() + : Command("list_users") +{ +} Command_GetUserInfo::Command_GetUserInfo(const QString &_userName) : Command("get_user_info") { @@ -47,34 +51,26 @@ Command_DeckDownload::Command_DeckDownload(int _deckId) { insertItem(new SerializableItem_Int("deck_id", _deckId)); } -Command_ListChatChannels::Command_ListChatChannels() - : Command("list_chat_channels") +Command_ListRooms::Command_ListRooms() + : Command("list_rooms") { } -Command_ChatJoinChannel::Command_ChatJoinChannel(const QString &_channel) - : Command("chat_join_channel") +Command_JoinRoom::Command_JoinRoom(int _roomId) + : Command("join_room") { - insertItem(new SerializableItem_String("channel", _channel)); + insertItem(new SerializableItem_Int("room_id", _roomId)); } -Command_ChatLeaveChannel::Command_ChatLeaveChannel(const QString &_channel) - : ChatCommand("chat_leave_channel", _channel) +Command_LeaveRoom::Command_LeaveRoom(int _roomId) + : RoomCommand("leave_room", _roomId) { } -Command_ChatSay::Command_ChatSay(const QString &_channel, const QString &_message) - : ChatCommand("chat_say", _channel) +Command_RoomSay::Command_RoomSay(int _roomId, const QString &_message) + : RoomCommand("room_say", _roomId) { insertItem(new SerializableItem_String("message", _message)); } -Command_ListGames::Command_ListGames() - : Command("list_games") -{ -} -Command_ListUsers::Command_ListUsers() - : Command("list_users") -{ -} -Command_CreateGame::Command_CreateGame(const QString &_description, const QString &_password, int _maxPlayers, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything) - : Command("create_game") +Command_CreateGame::Command_CreateGame(int _roomId, const QString &_description, const QString &_password, int _maxPlayers, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything) + : RoomCommand("create_game", _roomId) { insertItem(new SerializableItem_String("description", _description)); insertItem(new SerializableItem_String("password", _password)); @@ -84,8 +80,8 @@ Command_CreateGame::Command_CreateGame(const QString &_description, const QStrin insertItem(new SerializableItem_Bool("spectators_can_talk", _spectatorsCanTalk)); insertItem(new SerializableItem_Bool("spectators_see_everything", _spectatorsSeeEverything)); } -Command_JoinGame::Command_JoinGame(int _gameId, const QString &_password, bool _spectator) - : Command("join_game") +Command_JoinGame::Command_JoinGame(int _roomId, int _gameId, const QString &_password, bool _spectator) + : RoomCommand("join_game", _roomId) { insertItem(new SerializableItem_Int("game_id", _gameId)); insertItem(new SerializableItem_String("password", _password)); @@ -118,17 +114,6 @@ Command_DrawCards::Command_DrawCards(int _gameId, int _number) { insertItem(new SerializableItem_Int("number", _number)); } -Command_MoveCard::Command_MoveCard(int _gameId, const QString &_startZone, int _cardId, const QString &_targetZone, int _x, int _y, bool _faceDown, bool _tapped) - : GameCommand("move_card", _gameId) -{ - insertItem(new SerializableItem_String("start_zone", _startZone)); - insertItem(new SerializableItem_Int("card_id", _cardId)); - insertItem(new SerializableItem_String("target_zone", _targetZone)); - insertItem(new SerializableItem_Int("x", _x)); - insertItem(new SerializableItem_Int("y", _y)); - insertItem(new SerializableItem_Bool("face_down", _faceDown)); - insertItem(new SerializableItem_Bool("tapped", _tapped)); -} Command_FlipCard::Command_FlipCard(int _gameId, const QString &_zone, int _cardId, bool _faceDown) : GameCommand("flip_card", _gameId) { @@ -283,13 +268,14 @@ Event_RollDie::Event_RollDie(int _playerId, int _sides, int _value) insertItem(new SerializableItem_Int("sides", _sides)); insertItem(new SerializableItem_Int("value", _value)); } -Event_MoveCard::Event_MoveCard(int _playerId, int _cardId, const QString &_cardName, const QString &_startZone, int _position, const QString &_targetZone, int _x, int _y, int _newCardId, bool _faceDown) +Event_MoveCard::Event_MoveCard(int _playerId, int _cardId, const QString &_cardName, const QString &_startZone, int _position, int _targetPlayerId, const QString &_targetZone, int _x, int _y, int _newCardId, bool _faceDown) : GameEvent("move_card", _playerId) { insertItem(new SerializableItem_Int("card_id", _cardId)); insertItem(new SerializableItem_String("card_name", _cardName)); insertItem(new SerializableItem_String("start_zone", _startZone)); insertItem(new SerializableItem_Int("position", _position)); + insertItem(new SerializableItem_Int("target_player_id", _targetPlayerId)); insertItem(new SerializableItem_String("target_zone", _targetZone)); insertItem(new SerializableItem_Int("x", _x)); insertItem(new SerializableItem_Int("y", _y)); @@ -415,13 +401,13 @@ Event_UserLeft::Event_UserLeft(const QString &_userName) { insertItem(new SerializableItem_String("user_name", _userName)); } -Event_ChatLeaveChannel::Event_ChatLeaveChannel(const QString &_channel, const QString &_playerName) - : ChatEvent("chat_leave_channel", _channel) +Event_LeaveRoom::Event_LeaveRoom(int _roomId, const QString &_playerName) + : RoomEvent("leave_room", _roomId) { insertItem(new SerializableItem_String("player_name", _playerName)); } -Event_ChatSay::Event_ChatSay(const QString &_channel, const QString &_playerName, const QString &_message) - : ChatEvent("chat_say", _channel) +Event_RoomSay::Event_RoomSay(int _roomId, const QString &_playerName, const QString &_message) + : RoomEvent("room_say", _roomId) { insertItem(new SerializableItem_String("player_name", _playerName)); insertItem(new SerializableItem_String("message", _message)); @@ -439,23 +425,26 @@ Context_DeckSelect::Context_DeckSelect(int _deckId) { insertItem(new SerializableItem_Int("deck_id", _deckId)); } +Command_UpdateServerMessage::Command_UpdateServerMessage() + : AdminCommand("update_server_message") +{ +} void ProtocolItem::initializeHashAuto() { itemNameHash.insert("cmdping", Command_Ping::newItem); itemNameHash.insert("cmdlogin", Command_Login::newItem); itemNameHash.insert("cmdmessage", Command_Message::newItem); + itemNameHash.insert("cmdlist_users", Command_ListUsers::newItem); itemNameHash.insert("cmdget_user_info", Command_GetUserInfo::newItem); itemNameHash.insert("cmddeck_list", Command_DeckList::newItem); itemNameHash.insert("cmddeck_new_dir", Command_DeckNewDir::newItem); itemNameHash.insert("cmddeck_del_dir", Command_DeckDelDir::newItem); itemNameHash.insert("cmddeck_del", Command_DeckDel::newItem); itemNameHash.insert("cmddeck_download", Command_DeckDownload::newItem); - itemNameHash.insert("cmdlist_chat_channels", Command_ListChatChannels::newItem); - itemNameHash.insert("cmdchat_join_channel", Command_ChatJoinChannel::newItem); - itemNameHash.insert("cmdchat_leave_channel", Command_ChatLeaveChannel::newItem); - itemNameHash.insert("cmdchat_say", Command_ChatSay::newItem); - itemNameHash.insert("cmdlist_games", Command_ListGames::newItem); - itemNameHash.insert("cmdlist_users", Command_ListUsers::newItem); + itemNameHash.insert("cmdlist_rooms", Command_ListRooms::newItem); + itemNameHash.insert("cmdjoin_room", Command_JoinRoom::newItem); + itemNameHash.insert("cmdleave_room", Command_LeaveRoom::newItem); + itemNameHash.insert("cmdroom_say", Command_RoomSay::newItem); itemNameHash.insert("cmdcreate_game", Command_CreateGame::newItem); itemNameHash.insert("cmdjoin_game", Command_JoinGame::newItem); itemNameHash.insert("cmdleave_game", Command_LeaveGame::newItem); @@ -464,7 +453,6 @@ void ProtocolItem::initializeHashAuto() itemNameHash.insert("cmdmulligan", Command_Mulligan::newItem); itemNameHash.insert("cmdroll_die", Command_RollDie::newItem); itemNameHash.insert("cmddraw_cards", Command_DrawCards::newItem); - itemNameHash.insert("cmdmove_card", Command_MoveCard::newItem); itemNameHash.insert("cmdflip_card", Command_FlipCard::newItem); itemNameHash.insert("cmdattach_card", Command_AttachCard::newItem); itemNameHash.insert("cmdcreate_token", Command_CreateToken::newItem); @@ -507,9 +495,10 @@ void ProtocolItem::initializeHashAuto() itemNameHash.insert("generic_eventmessage", Event_Message::newItem); itemNameHash.insert("generic_eventgame_joined", Event_GameJoined::newItem); itemNameHash.insert("generic_eventuser_left", Event_UserLeft::newItem); - itemNameHash.insert("chat_eventchat_leave_channel", Event_ChatLeaveChannel::newItem); - itemNameHash.insert("chat_eventchat_say", Event_ChatSay::newItem); + itemNameHash.insert("room_eventleave_room", Event_LeaveRoom::newItem); + itemNameHash.insert("room_eventroom_say", Event_RoomSay::newItem); itemNameHash.insert("game_event_contextready_start", Context_ReadyStart::newItem); itemNameHash.insert("game_event_contextconcede", Context_Concede::newItem); itemNameHash.insert("game_event_contextdeck_select", Context_DeckSelect::newItem); + itemNameHash.insert("cmdupdate_server_message", Command_UpdateServerMessage::newItem); } diff --git a/common/protocol_items.dat b/common/protocol_items.dat index bc9a28e5..db617398 100644 --- a/common/protocol_items.dat +++ b/common/protocol_items.dat @@ -1,27 +1,25 @@ 0:ping 0:login:s,username:s,password 0:message:s,user_name:s,text +0:list_users 0:get_user_info:s,user_name 0:deck_list 0:deck_new_dir:s,path:s,dir_name 0:deck_del_dir:s,path 0:deck_del:i,deck_id 0:deck_download:i,deck_id -0:list_chat_channels -0:chat_join_channel:s,channel -1:chat_leave_channel -1:chat_say:s,message -0:list_games -0:list_users -0:create_game:s,description:s,password:i,max_players:b,spectators_allowed:b,spectators_need_password:b,spectators_can_talk:b,spectators_see_everything -0:join_game:i,game_id:s,password:b,spectator +0:list_rooms +0:join_room:i,room_id +1:leave_room +1:room_say:s,message +1:create_game:s,description:s,password:i,max_players:b,spectators_allowed:b,spectators_need_password:b,spectators_can_talk:b,spectators_see_everything +1:join_game:i,game_id:s,password:b,spectator 2:leave_game 2:say:s,message 2:shuffle 2:mulligan 2:roll_die:i,sides 2:draw_cards:i,number -2:move_card:s,start_zone:i,card_id:s,target_zone:i,x:i,y:b,face_down:b,tapped 2:flip_card:s,zone:i,card_id:b,face_down 2:attach_card:s,start_zone:i,card_id:i,target_player_id:s,target_zone:i,target_card_id 2:create_token:s,zone:s,card_name:s,color:s,pt:s,annotation:b,destroy:i,x:i,y @@ -46,7 +44,7 @@ 3:game_closed 3:shuffle 3:roll_die:i,sides:i,value -3:move_card:i,card_id:s,card_name:s,start_zone:i,position:s,target_zone:i,x:i,y:i,new_card_id:b,face_down +3:move_card:i,card_id:s,card_name:s,start_zone:i,position:i,target_player_id:s,target_zone:i,x:i,y:i,new_card_id:b,face_down 3:flip_card:s,zone:i,card_id:s,card_name:b,face_down 3:destroy_card:s,zone:i,card_id 3:attach_card:s,start_zone:i,card_id:i,target_player_id:s,target_zone:i,target_card_id @@ -64,8 +62,9 @@ 4:message:s,sender_name:s,receiver_name:s,text 4:game_joined:i,game_id:s,game_description:i,player_id:b,spectator:b,spectators_can_talk:b,spectators_see_everything:b,resuming 4:user_left:s,user_name -5:chat_leave_channel:s,player_name -5:chat_say:s,player_name:s,message +5:leave_room:s,player_name +5:room_say:s,player_name:s,message 6:ready_start 6:concede 6:deck_select:i,deck_id +7:update_server_message diff --git a/common/protocol_items.h b/common/protocol_items.h index 69664127..aed7c43c 100644 --- a/common/protocol_items.h +++ b/common/protocol_items.h @@ -28,6 +28,13 @@ public: static SerializableItem *newItem() { return new Command_Message; } int getItemId() const { return ItemId_Command_Message; } }; +class Command_ListUsers : public Command { + Q_OBJECT +public: + Command_ListUsers(); + static SerializableItem *newItem() { return new Command_ListUsers; } + int getItemId() const { return ItemId_Command_ListUsers; } +}; class Command_GetUserInfo : public Command { Q_OBJECT public: @@ -76,54 +83,40 @@ public: static SerializableItem *newItem() { return new Command_DeckDownload; } int getItemId() const { return ItemId_Command_DeckDownload; } }; -class Command_ListChatChannels : public Command { +class Command_ListRooms : public Command { Q_OBJECT public: - Command_ListChatChannels(); - static SerializableItem *newItem() { return new Command_ListChatChannels; } - int getItemId() const { return ItemId_Command_ListChatChannels; } + Command_ListRooms(); + static SerializableItem *newItem() { return new Command_ListRooms; } + int getItemId() const { return ItemId_Command_ListRooms; } }; -class Command_ChatJoinChannel : public Command { +class Command_JoinRoom : public Command { Q_OBJECT public: - Command_ChatJoinChannel(const QString &_channel = QString()); - QString getChannel() const { return static_cast(itemMap.value("channel"))->getData(); }; - static SerializableItem *newItem() { return new Command_ChatJoinChannel; } - int getItemId() const { return ItemId_Command_ChatJoinChannel; } + Command_JoinRoom(int _roomId = -1); + int getRoomId() const { return static_cast(itemMap.value("room_id"))->getData(); }; + static SerializableItem *newItem() { return new Command_JoinRoom; } + int getItemId() const { return ItemId_Command_JoinRoom; } }; -class Command_ChatLeaveChannel : public ChatCommand { +class Command_LeaveRoom : public RoomCommand { Q_OBJECT public: - Command_ChatLeaveChannel(const QString &_channel = QString()); - static SerializableItem *newItem() { return new Command_ChatLeaveChannel; } - int getItemId() const { return ItemId_Command_ChatLeaveChannel; } + Command_LeaveRoom(int _roomId = -1); + static SerializableItem *newItem() { return new Command_LeaveRoom; } + int getItemId() const { return ItemId_Command_LeaveRoom; } }; -class Command_ChatSay : public ChatCommand { +class Command_RoomSay : public RoomCommand { Q_OBJECT public: - Command_ChatSay(const QString &_channel = QString(), const QString &_message = QString()); + Command_RoomSay(int _roomId = -1, const QString &_message = QString()); QString getMessage() const { return static_cast(itemMap.value("message"))->getData(); }; - static SerializableItem *newItem() { return new Command_ChatSay; } - int getItemId() const { return ItemId_Command_ChatSay; } + static SerializableItem *newItem() { return new Command_RoomSay; } + int getItemId() const { return ItemId_Command_RoomSay; } }; -class Command_ListGames : public Command { +class Command_CreateGame : public RoomCommand { Q_OBJECT public: - Command_ListGames(); - static SerializableItem *newItem() { return new Command_ListGames; } - int getItemId() const { return ItemId_Command_ListGames; } -}; -class Command_ListUsers : public Command { - Q_OBJECT -public: - Command_ListUsers(); - static SerializableItem *newItem() { return new Command_ListUsers; } - int getItemId() const { return ItemId_Command_ListUsers; } -}; -class Command_CreateGame : public Command { - Q_OBJECT -public: - Command_CreateGame(const QString &_description = QString(), const QString &_password = QString(), int _maxPlayers = -1, bool _spectatorsAllowed = false, bool _spectatorsNeedPassword = false, bool _spectatorsCanTalk = false, bool _spectatorsSeeEverything = false); + Command_CreateGame(int _roomId = -1, const QString &_description = QString(), const QString &_password = QString(), int _maxPlayers = -1, bool _spectatorsAllowed = false, bool _spectatorsNeedPassword = false, bool _spectatorsCanTalk = false, bool _spectatorsSeeEverything = false); QString getDescription() const { return static_cast(itemMap.value("description"))->getData(); }; QString getPassword() const { return static_cast(itemMap.value("password"))->getData(); }; int getMaxPlayers() const { return static_cast(itemMap.value("max_players"))->getData(); }; @@ -134,10 +127,10 @@ public: static SerializableItem *newItem() { return new Command_CreateGame; } int getItemId() const { return ItemId_Command_CreateGame; } }; -class Command_JoinGame : public Command { +class Command_JoinGame : public RoomCommand { Q_OBJECT public: - Command_JoinGame(int _gameId = -1, const QString &_password = QString(), bool _spectator = false); + Command_JoinGame(int _roomId = -1, int _gameId = -1, const QString &_password = QString(), bool _spectator = false); int getGameId() const { return static_cast(itemMap.value("game_id"))->getData(); }; QString getPassword() const { return static_cast(itemMap.value("password"))->getData(); }; bool getSpectator() const { return static_cast(itemMap.value("spectator"))->getData(); }; @@ -189,20 +182,6 @@ public: static SerializableItem *newItem() { return new Command_DrawCards; } int getItemId() const { return ItemId_Command_DrawCards; } }; -class Command_MoveCard : public GameCommand { - Q_OBJECT -public: - Command_MoveCard(int _gameId = -1, const QString &_startZone = QString(), int _cardId = -1, const QString &_targetZone = QString(), int _x = -1, int _y = -1, bool _faceDown = false, bool _tapped = false); - QString getStartZone() const { return static_cast(itemMap.value("start_zone"))->getData(); }; - int getCardId() const { return static_cast(itemMap.value("card_id"))->getData(); }; - QString getTargetZone() const { return static_cast(itemMap.value("target_zone"))->getData(); }; - int getX() const { return static_cast(itemMap.value("x"))->getData(); }; - int getY() const { return static_cast(itemMap.value("y"))->getData(); }; - bool getFaceDown() const { return static_cast(itemMap.value("face_down"))->getData(); }; - bool getTapped() const { return static_cast(itemMap.value("tapped"))->getData(); }; - static SerializableItem *newItem() { return new Command_MoveCard; } - int getItemId() const { return ItemId_Command_MoveCard; } -}; class Command_FlipCard : public GameCommand { Q_OBJECT public: @@ -432,11 +411,12 @@ public: class Event_MoveCard : public GameEvent { Q_OBJECT public: - Event_MoveCard(int _playerId = -1, int _cardId = -1, const QString &_cardName = QString(), const QString &_startZone = QString(), int _position = -1, const QString &_targetZone = QString(), int _x = -1, int _y = -1, int _newCardId = -1, bool _faceDown = false); + Event_MoveCard(int _playerId = -1, int _cardId = -1, const QString &_cardName = QString(), const QString &_startZone = QString(), int _position = -1, int _targetPlayerId = -1, const QString &_targetZone = QString(), int _x = -1, int _y = -1, int _newCardId = -1, bool _faceDown = false); int getCardId() const { return static_cast(itemMap.value("card_id"))->getData(); }; QString getCardName() const { return static_cast(itemMap.value("card_name"))->getData(); }; QString getStartZone() const { return static_cast(itemMap.value("start_zone"))->getData(); }; int getPosition() const { return static_cast(itemMap.value("position"))->getData(); }; + int getTargetPlayerId() const { return static_cast(itemMap.value("target_player_id"))->getData(); }; QString getTargetZone() const { return static_cast(itemMap.value("target_zone"))->getData(); }; int getX() const { return static_cast(itemMap.value("x"))->getData(); }; int getY() const { return static_cast(itemMap.value("y"))->getData(); }; @@ -615,22 +595,22 @@ public: static SerializableItem *newItem() { return new Event_UserLeft; } int getItemId() const { return ItemId_Event_UserLeft; } }; -class Event_ChatLeaveChannel : public ChatEvent { +class Event_LeaveRoom : public RoomEvent { Q_OBJECT public: - Event_ChatLeaveChannel(const QString &_channel = QString(), const QString &_playerName = QString()); + Event_LeaveRoom(int _roomId = -1, const QString &_playerName = QString()); QString getPlayerName() const { return static_cast(itemMap.value("player_name"))->getData(); }; - static SerializableItem *newItem() { return new Event_ChatLeaveChannel; } - int getItemId() const { return ItemId_Event_ChatLeaveChannel; } + static SerializableItem *newItem() { return new Event_LeaveRoom; } + int getItemId() const { return ItemId_Event_LeaveRoom; } }; -class Event_ChatSay : public ChatEvent { +class Event_RoomSay : public RoomEvent { Q_OBJECT public: - Event_ChatSay(const QString &_channel = QString(), const QString &_playerName = QString(), const QString &_message = QString()); + Event_RoomSay(int _roomId = -1, const QString &_playerName = QString(), const QString &_message = QString()); QString getPlayerName() const { return static_cast(itemMap.value("player_name"))->getData(); }; QString getMessage() const { return static_cast(itemMap.value("message"))->getData(); }; - static SerializableItem *newItem() { return new Event_ChatSay; } - int getItemId() const { return ItemId_Event_ChatSay; } + static SerializableItem *newItem() { return new Event_RoomSay; } + int getItemId() const { return ItemId_Event_RoomSay; } }; class Context_ReadyStart : public GameEventContext { Q_OBJECT @@ -654,5 +634,12 @@ public: static SerializableItem *newItem() { return new Context_DeckSelect; } int getItemId() const { return ItemId_Context_DeckSelect; } }; +class Command_UpdateServerMessage : public AdminCommand { + Q_OBJECT +public: + Command_UpdateServerMessage(); + static SerializableItem *newItem() { return new Command_UpdateServerMessage; } + int getItemId() const { return ItemId_Command_UpdateServerMessage; } +}; #endif diff --git a/common/protocol_mc.pl b/common/protocol_mc.pl index 696915d9..31e85b1f 100755 --- a/common/protocol_mc.pl +++ b/common/protocol_mc.pl @@ -34,10 +34,10 @@ while () { } elsif ($type == 1) { $type = 'cmd'; $namePrefix = 'Command'; - $baseClass = 'ChatCommand'; - $parentConstructorCall = "$baseClass(\"$name1\", _channel)"; - $constructorParamsH = "const QString &_channel = QString()"; - $constructorParamsCpp = "const QString &_channel"; + $baseClass = 'RoomCommand'; + $parentConstructorCall = "$baseClass(\"$name1\", _roomId)"; + $constructorParamsH = "int _roomId = -1"; + $constructorParamsCpp = "int _roomId"; } elsif ($type == 2) { $type = 'cmd'; $namePrefix = 'Command'; @@ -60,12 +60,12 @@ while () { $constructorParamsH = ""; $constructorParamsCpp = ""; } elsif ($type == 5) { - $type = 'chat_event'; + $type = 'room_event'; $namePrefix = 'Event'; - $baseClass = 'ChatEvent'; - $parentConstructorCall = "$baseClass(\"$name1\", _channel)"; - $constructorParamsH = "const QString &_channel = QString()"; - $constructorParamsCpp = "const QString &_channel"; + $baseClass = 'RoomEvent'; + $parentConstructorCall = "$baseClass(\"$name1\", _roomId)"; + $constructorParamsH = "int _roomId = -1"; + $constructorParamsCpp = "int _roomId"; } elsif ($type == 6) { $type = 'game_event_context'; $namePrefix = 'Context'; @@ -73,6 +73,13 @@ while () { $parentConstructorCall = "$baseClass(\"$name1\")"; $constructorParamsH = ""; $constructorParamsCpp = ""; + } elsif ($type == 7) { + $type = 'cmd'; + $namePrefix = 'Command'; + $baseClass = 'AdminCommand'; + $parentConstructorCall = "$baseClass(\"$name1\")"; + $constructorParamsH = ""; + $constructorParamsCpp = ""; } $className = $namePrefix . '_' . $name2; $itemEnum .= "ItemId_$className = " . ++$itemId . ",\n"; diff --git a/common/serializable_item.cpp b/common/serializable_item.cpp index c7c2d913..9c1a7c81 100644 --- a/common/serializable_item.cpp +++ b/common/serializable_item.cpp @@ -1,7 +1,7 @@ #include "serializable_item.h" #include #include - +#include QHash SerializableItem::itemNameHash; SerializableItem *SerializableItem::getNewItem(const QString &name) @@ -25,6 +25,9 @@ bool SerializableItem::readElement(QXmlStreamReader *xml) void SerializableItem::write(QXmlStreamWriter *xml) { + if (isEmpty()) + return; + xml->writeStartElement(itemType); if (!itemSubType.isEmpty()) xml->writeAttribute("type", itemSubType); diff --git a/common/serializable_item.h b/common/serializable_item.h index ef1e91ad..14e383e9 100644 --- a/common/serializable_item.h +++ b/common/serializable_item.h @@ -29,6 +29,7 @@ public: const QString &getItemSubType() const { return itemSubType; } virtual bool readElement(QXmlStreamReader *xml); virtual void writeElement(QXmlStreamWriter *xml) = 0; + virtual bool isEmpty() const = 0; void write(QXmlStreamWriter *xml); }; @@ -36,6 +37,7 @@ class SerializableItem_Invalid : public SerializableItem { public: SerializableItem_Invalid(const QString &_itemType) : SerializableItem(_itemType) { } void writeElement(QXmlStreamWriter * /*xml*/) { } + bool isEmpty() const { return true; } }; class SerializableItem_Map : public SerializableItem { @@ -67,6 +69,7 @@ public: ~SerializableItem_Map(); bool readElement(QXmlStreamReader *xml); void writeElement(QXmlStreamWriter *xml); + bool isEmpty() const { return itemMap.isEmpty() && itemList.isEmpty(); } void appendItem(SerializableItem *item) { itemList.append(item); } }; @@ -81,6 +84,7 @@ public: : SerializableItem(_itemType), data(_data) { } const QString &getData() { return data; } void setData(const QString &_data) { data = _data; } + bool isEmpty() const { return data.isEmpty(); } }; class SerializableItem_Int : public SerializableItem { @@ -94,6 +98,7 @@ public: : SerializableItem(_itemType), data(_data) { } int getData() { return data; } void setData(int _data) { data = _data; } + bool isEmpty() const { return data == -1; } }; class SerializableItem_Bool : public SerializableItem { @@ -107,6 +112,7 @@ public: : SerializableItem(_itemType), data(_data) { } bool getData() { return data; } void setData(bool _data) { data = _data; } + bool isEmpty() const { return data == false; } }; class SerializableItem_Color : public SerializableItem { @@ -120,6 +126,7 @@ public: : SerializableItem(_itemType), data(_data) { } const Color &getData() { return data; } void setData(const Color &_data) { data = _data; } + bool isEmpty() const { return data.getValue() == 0; } }; class SerializableItem_DateTime : public SerializableItem { @@ -133,6 +140,7 @@ public: : SerializableItem(_itemType), data(_data) { } const QDateTime &getData() { return data; } void setData(const QDateTime &_data) { data = _data; } + bool isEmpty() const { return data == QDateTime(); } }; class SerializableItem_ByteArray : public SerializableItem { @@ -146,6 +154,7 @@ public: : SerializableItem(_itemType), data(_data) { } const QByteArray &getData() { return data; } void setData(const QByteArray &_data) { data = _data; } + bool isEmpty() const { return data.isEmpty(); } }; #endif diff --git a/common/server.cpp b/common/server.cpp index dc4125b2..4890f04f 100644 --- a/common/server.cpp +++ b/common/server.cpp @@ -20,7 +20,7 @@ #include "server.h" #include "server_game.h" #include "server_counter.h" -#include "server_chatchannel.h" +#include "server_room.h" #include "server_protocolhandler.h" #include "protocol_datastructures.h" #include @@ -69,17 +69,6 @@ AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString return authState; } -Server_Game *Server::createGame(const QString &description, const QString &password, int maxPlayers, bool spectatorsAllowed, bool spectatorsNeedPassword, bool spectatorsCanTalk, bool spectatorsSeeEverything, Server_ProtocolHandler *creator) -{ - Server_Game *newGame = new Server_Game(creator, nextGameId++, description, password, maxPlayers, spectatorsAllowed, spectatorsNeedPassword, spectatorsCanTalk, spectatorsSeeEverything, this); - games.insert(newGame->getGameId(), newGame); - connect(newGame, SIGNAL(gameClosing()), this, SLOT(gameClosing())); - - broadcastGameListUpdate(newGame); - - return newGame; -} - void Server::addClient(Server_ProtocolHandler *client) { clients << client; @@ -106,56 +95,34 @@ Server_Game *Server::getGame(int gameId) const return games.value(gameId); } -void Server::broadcastGameListUpdate(Server_Game *game) +void Server::broadcastRoomUpdate() { - QList eventGameList; - if (game->getPlayerCount()) - // Game is open - eventGameList.append(new ServerInfo_Game( - game->getGameId(), - game->getDescription(), - !game->getPassword().isEmpty(), - game->getPlayerCount(), - game->getMaxPlayers(), - new ServerInfo_User(game->getCreatorInfo()), - game->getSpectatorsAllowed(), - game->getSpectatorsNeedPassword(), - game->getSpectatorCount() - )); - else - // Game is closing - eventGameList.append(new ServerInfo_Game(game->getGameId(), QString(), false, 0, game->getMaxPlayers(), 0, false, 0)); - Event_ListGames *event = new Event_ListGames(eventGameList); - - for (int i = 0; i < clients.size(); i++) - if (clients[i]->getAcceptsGameListChanges()) - clients[i]->sendProtocolItem(event, false); - delete event; -} - -void Server::broadcastChannelUpdate() -{ - Server_ChatChannel *channel = static_cast(sender()); - QList eventChannelList; - eventChannelList.append(new ServerInfo_ChatChannel(channel->getName(), channel->getDescription(), channel->size(), channel->getAutoJoin())); - Event_ListChatChannels *event = new Event_ListChatChannels(eventChannelList); + Server_Room *room = static_cast(sender()); + QList eventRoomList; + eventRoomList.append(new ServerInfo_Room(room->getId(), room->getName(), room->getDescription(), room->getGames().size(), room->size(), room->getAutoJoin())); + Event_ListRooms *event = new Event_ListRooms(eventRoomList); for (int i = 0; i < clients.size(); ++i) - if (clients[i]->getAcceptsChatChannelListChanges()) + if (clients[i]->getAcceptsRoomListChanges()) clients[i]->sendProtocolItem(event, false); delete event; } -void Server::gameClosing() +void Server::gameCreated(Server_Game *game) { - qDebug("Server::gameClosing"); - Server_Game *game = static_cast(sender()); - broadcastGameListUpdate(game); - games.remove(games.key(game)); + games.insert(game->getGameId(), game); } -void Server::addChatChannel(Server_ChatChannel *newChannel) +void Server::gameClosing(int gameId) { - chatChannels.insert(newChannel->getName(), newChannel); - connect(newChannel, SIGNAL(channelInfoChanged()), this, SLOT(broadcastChannelUpdate())); + qDebug("Server::gameClosing"); + games.remove(gameId); +} + +void Server::addRoom(Server_Room *newRoom) +{ + rooms.insert(newRoom->getId(), newRoom); + connect(newRoom, SIGNAL(roomInfoChanged()), this, SLOT(broadcastRoomUpdate())); + connect(newRoom, SIGNAL(gameCreated(Server_Game *)), this, SLOT(gameCreated(Server_Game *))); + connect(newRoom, SIGNAL(gameClosing(int)), this, SLOT(gameClosing(int))); } diff --git a/common/server.h b/common/server.h index 3f4dfd56..d382626a 100644 --- a/common/server.h +++ b/common/server.h @@ -6,7 +6,7 @@ #include class Server_Game; -class Server_ChatChannel; +class Server_Room; class Server_ProtocolHandler; class ServerInfo_User; @@ -18,22 +18,22 @@ class Server : public QObject signals: void pingClockTimeout(); private slots: - void gameClosing(); - void broadcastChannelUpdate(); + void gameCreated(Server_Game *game); + void gameClosing(int gameId); + void broadcastRoomUpdate(); public: Server(QObject *parent = 0); ~Server(); AuthenticationResult loginUser(Server_ProtocolHandler *session, QString &name, const QString &password); QList getGames() const { return games.values(); } Server_Game *getGame(int gameId) const; - const QMap &getChatChannels() { return chatChannels; } - void broadcastGameListUpdate(Server_Game *game); + const QMap &getRooms() { return rooms; } + int getNextGameId() { return nextGameId++; } const QMap &getUsers() const { return users; } void addClient(Server_ProtocolHandler *player); void removeClient(Server_ProtocolHandler *player); virtual QString getLoginMessage() const = 0; - Server_Game *createGame(const QString &description, const QString &password, int maxPlayers, bool spectatorsAllowed, bool spectatorsNeedPassword, bool spectatorsCanTalk, bool spectatorsSeeEverything, Server_ProtocolHandler *creator); virtual bool getGameShouldPing() const = 0; virtual int getMaxGameInactivityTime() const = 0; @@ -42,12 +42,12 @@ protected: QMap games; QList clients; QMap users; - QMap chatChannels; + QMap rooms; virtual AuthenticationResult checkUserPassword(const QString &user, const QString &password) = 0; virtual ServerInfo_User *getUserData(const QString &name) = 0; int nextGameId; - void addChatChannel(Server_ChatChannel *newChannel); + void addRoom(Server_Room *newRoom); }; #endif diff --git a/common/server_cardzone.cpp b/common/server_cardzone.cpp index 07a56c15..2d417390 100644 --- a/common/server_cardzone.cpp +++ b/common/server_cardzone.cpp @@ -19,7 +19,10 @@ ***************************************************************************/ #include "server_cardzone.h" #include "server_card.h" +#include "server_player.h" #include "rng_abstract.h" +#include +#include Server_CardZone::Server_CardZone(Server_Player *_player, const QString &_name, bool _has_coords, ZoneType _type) : player(_player), name(_name), has_coords(_has_coords), type(_type), cardsBeingLookedAt(0) @@ -28,7 +31,7 @@ Server_CardZone::Server_CardZone(Server_Player *_player, const QString &_name, b Server_CardZone::~Server_CardZone() { - qDebug(QString("Server_CardZone destructor: %1").arg(name).toLatin1()); + qDebug() << "Server_CardZone destructor:" << name; clear(); } @@ -40,6 +43,13 @@ void Server_CardZone::shuffle() cards = temp; } +int Server_CardZone::removeCard(Server_Card *card) +{ + int index = cards.indexOf(card); + cards.removeAt(index); + return index; +} + Server_Card *Server_CardZone::getCard(int id, bool remove, int *position) { if (type != HiddenZone) { @@ -73,24 +83,109 @@ Server_Card *Server_CardZone::getCard(int id, bool remove, int *position) } } -int Server_CardZone::getFreeGridColumn(int y) const +int Server_CardZone::getFreeGridColumn(int x, int y, const QString &cardName) const { - int x = 0; + QMap coordMap; + for (int i = 0; i < cards.size(); ++i) + if (cards[i]->getY() == y) + coordMap.insert(cards[i]->getX(), cards[i]); - // Stupid algorithm. For large numbers of cards, it would be more - // efficient to sort the cards by their x value and only need to iterate once. - bool occupied; - do { - occupied = false; + int resultX = 0; + if (x == -1) { for (int i = 0; i < cards.size(); ++i) - if ((cards[i]->getY() == y) && (cards[i]->getX() == x)) { - occupied = true; - ++x; - break; + if ((cards[i]->getName() == cardName) && !(cards[i]->getX() % 3) && (cards[i]->getY() == y)) { + if (!cards[i]->getAttachedCards().isEmpty()) + continue; + if (!coordMap.value(cards[i]->getX() + 1)) + return cards[i]->getX() + 1; + if (!coordMap.value(cards[i]->getX() + 2)) + return cards[i]->getX() + 2; } - } while (occupied); + } else if (x == -2) { + } else { + x = (x / 3) * 3; + if (!coordMap.contains(x)) + resultX = x; + else if (!coordMap.value(x)->getAttachedCards().isEmpty()) { + resultX = x; + x = -1; + } else if (!coordMap.contains(x + 1)) + resultX = x + 1; + else if (!coordMap.contains(x + 2)) + resultX = x + 2; + else { + resultX = x; + x = -1; + } + } - return x; + if (x < 0) + while (coordMap.value(resultX)) + resultX += 3; + + return resultX; +} + +bool Server_CardZone::isColumnStacked(int x, int y) const +{ + if (!has_coords) + return false; + + QMap coordMap; + for (int i = 0; i < cards.size(); ++i) + if (cards[i]->getY() == y) + coordMap.insert(cards[i]->getX(), cards[i]); + + return coordMap.contains((x / 3) * 3 + 1); +} + +bool Server_CardZone::isColumnEmpty(int x, int y) const +{ + if (!has_coords) + return true; + + QMap coordMap; + for (int i = 0; i < cards.size(); ++i) + if (cards[i]->getY() == y) + coordMap.insert(cards[i]->getX(), cards[i]); + + return !coordMap.contains((x / 3) * 3); +} + +void Server_CardZone::moveCard(CommandContainer *cont, QMap &coordMap, Server_Card *card, int x, int y) +{ + coordMap.remove(card->getX()); + player->moveCard(cont, this, QList() << card->getId(), this, x, y, card->getFaceDown(), false); + coordMap.insert(x, card); +} + +void Server_CardZone::fixFreeSpaces(CommandContainer *cont) +{ + QMap coordMap; + QSet placesToLook; + for (int i = 0; i < cards.size(); ++i) { + coordMap.insert(cards[i]->getY() * 10000 + cards[i]->getX(), cards[i]); + placesToLook.insert(cards[i]->getY() * 10000 + (cards[i]->getX() / 3) * 3); + } + + QSetIterator placeIterator(placesToLook); + while (placeIterator.hasNext()) { + int foo = placeIterator.next(); + int y = foo / 10000; + int baseX = foo - y * 10000; + + if (!coordMap.contains(y * 10000 + baseX)) { + if (coordMap.contains(y * 10000 + baseX + 1)) + moveCard(cont, coordMap, coordMap.value(y * 10000 + baseX + 1), baseX, y); + else if (coordMap.contains(baseX + 2)) { + moveCard(cont, coordMap, coordMap.value(y * 10000 + baseX + 2), baseX, y); + return; + } else + return; + } + if (!coordMap.contains(y * 10000 + baseX + 1) && coordMap.contains(y * 10000 + baseX + 2)) + moveCard(cont, coordMap, coordMap.value(y * 10000 + baseX + 2), baseX + 1, y); + } } void Server_CardZone::insertCard(Server_Card *card, int x, int y) diff --git a/common/server_cardzone.h b/common/server_cardzone.h index fa35a728..62a129a1 100644 --- a/common/server_cardzone.h +++ b/common/server_cardzone.h @@ -26,6 +26,8 @@ class Server_Card; class Server_Player; +class Server_Game; +class CommandContainer; class Server_CardZone { private: @@ -38,6 +40,7 @@ public: Server_CardZone(Server_Player *_player, const QString &_name, bool _has_coords, ZoneType _type); ~Server_CardZone(); + int removeCard(Server_Card *card); Server_Card *getCard(int id, bool remove, int *position = NULL); int getCardsBeingLookedAt() const { return cardsBeingLookedAt; } @@ -47,7 +50,11 @@ public: QString getName() const { return name; } Server_Player *getPlayer() const { return player; } - int getFreeGridColumn(int y) const; + int getFreeGridColumn(int x, int y, const QString &cardName) const; + bool isColumnEmpty(int x, int y) const; + bool isColumnStacked(int x, int y) const; + void fixFreeSpaces(CommandContainer *cont); + void moveCard(CommandContainer *cont, QMap &coordMap, Server_Card *card, int x, int y); QList cards; void insertCard(Server_Card *card, int x, int y); void shuffle(); diff --git a/common/server_chatchannel.cpp b/common/server_chatchannel.cpp deleted file mode 100644 index 2bdd8574..00000000 --- a/common/server_chatchannel.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "server_chatchannel.h" -#include "server_protocolhandler.h" - -Server_ChatChannel::Server_ChatChannel(const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage) - : name(_name), description(_description), autoJoin(_autoJoin), joinMessage(_joinMessage) -{ -} - -void Server_ChatChannel::addClient(Server_ProtocolHandler *client) -{ - sendChatEvent(new Event_ChatJoinChannel(name, new ServerInfo_User(client->getUserInfo()))); - append(client); - - QList eventUserList; - for (int i = 0; i < size(); ++i) - eventUserList.append(new ServerInfo_User(at(i)->getUserInfo())); - Event_ChatListPlayers *eventCLP = new Event_ChatListPlayers(name, eventUserList); - client->enqueueProtocolItem(eventCLP); - - client->enqueueProtocolItem(new Event_ChatSay(name, QString(), joinMessage)); - - emit channelInfoChanged(); -} - -void Server_ChatChannel::removeClient(Server_ProtocolHandler *client) -{ - removeAt(indexOf(client)); - sendChatEvent(new Event_ChatLeaveChannel(name, client->getUserInfo()->getName())); - emit channelInfoChanged(); -} - -void Server_ChatChannel::say(Server_ProtocolHandler *client, const QString &s) -{ - sendChatEvent(new Event_ChatSay(name, client->getUserInfo()->getName(), s)); -} - -void Server_ChatChannel::sendChatEvent(ChatEvent *event) -{ - for (int i = 0; i < size(); ++i) - at(i)->sendProtocolItem(event, false); - delete event; -} diff --git a/common/server_chatchannel.h b/common/server_chatchannel.h deleted file mode 100644 index 22b2f360..00000000 --- a/common/server_chatchannel.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef CHATCHANNEL_H -#define CHATCHANNEL_H - -#include -#include -#include - -class Server_ProtocolHandler; -class ChatEvent; - -class Server_ChatChannel : public QObject, public QList { - Q_OBJECT -signals: - void channelInfoChanged(); -private: - QString name; - QString description; - bool autoJoin; - QString joinMessage; -public: - Server_ChatChannel(const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage); - QString getName() const { return name; } - QString getDescription() const { return description; } - bool getAutoJoin() const { return autoJoin; } - void addClient(Server_ProtocolHandler *client); - void removeClient(Server_ProtocolHandler *client); - void say(Server_ProtocolHandler *client, const QString &s); - - void sendChatEvent(ChatEvent *event); -}; - -#endif diff --git a/common/server_game.cpp b/common/server_game.cpp index 2b9add86..d2404706 100644 --- a/common/server_game.cpp +++ b/common/server_game.cpp @@ -18,6 +18,7 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "server.h" +#include "server_room.h" #include "server_game.h" #include "server_protocolhandler.h" #include "server_arrow.h" @@ -27,12 +28,12 @@ #include #include -Server_Game::Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QString &_description, const QString &_password, int _maxPlayers, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, Server *parent) - : QObject(parent), creatorInfo(new ServerInfo_User(_creator->getUserInfo())), gameStarted(false), gameId(_gameId), description(_description), password(_password), maxPlayers(_maxPlayers), activePlayer(-1), activePhase(-1), spectatorsAllowed(_spectatorsAllowed), spectatorsNeedPassword(_spectatorsNeedPassword), spectatorsCanTalk(_spectatorsCanTalk), spectatorsSeeEverything(_spectatorsSeeEverything), inactivityCounter(0) +Server_Game::Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QString &_description, const QString &_password, int _maxPlayers, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, Server_Room *parent) + : QObject(parent), creatorInfo(new ServerInfo_User(_creator->getUserInfo())), gameStarted(false), gameId(_gameId), description(_description), password(_password), maxPlayers(_maxPlayers), activePlayer(-1), activePhase(-1), spectatorsAllowed(_spectatorsAllowed), spectatorsNeedPassword(_spectatorsNeedPassword), spectatorsCanTalk(_spectatorsCanTalk), spectatorsSeeEverything(_spectatorsSeeEverything), inactivityCounter(0), secondsElapsed(0) { addPlayer(_creator, false, false); - if (parent->getGameShouldPing()) { + if (parent->getServer()->getGameShouldPing()) { pingClock = new QTimer(this); connect(pingClock, SIGNAL(timeout()), this, SLOT(pingClockTimeout())); pingClock->start(1000); @@ -55,6 +56,8 @@ Server_Game::~Server_Game() void Server_Game::pingClockTimeout() { + ++secondsElapsed; + QDateTime now = QDateTime::currentDateTime(); QList pingList; QMapIterator playerIterator(players); @@ -69,9 +72,9 @@ void Server_Game::pingClockTimeout() pingTime = -1; pingList.append(new ServerInfo_PlayerPing(player->getPlayerId(), pingTime)); } - sendGameEvent(new Event_Ping(pingList)); + sendGameEvent(new Event_Ping(secondsElapsed, pingList)); - const int maxTime = static_cast(parent())->getMaxGameInactivityTime(); + const int maxTime = static_cast(parent())->getServer()->getMaxGameInactivityTime(); if (allPlayersInactive) { if ((++inactivityCounter >= maxTime) && (maxTime > 0)) deleteLater(); @@ -193,7 +196,7 @@ Server_Player *Server_Game::addPlayer(Server_ProtocolHandler *handler, bool spec players.insert(playerId, newPlayer); if (broadcastUpdate) - qobject_cast(parent())->broadcastGameListUpdate(this); + qobject_cast(parent())->broadcastGameListUpdate(this); return newPlayer; } @@ -231,7 +234,7 @@ void Server_Game::removePlayer(Server_Player *player) deleteLater(); else if (!spectator) stopGameIfFinished(); - qobject_cast(parent())->broadcastGameListUpdate(this); + qobject_cast(parent())->broadcastGameListUpdate(this); } void Server_Game::setActivePlayer(int _activePlayer) @@ -391,3 +394,23 @@ void Server_Game::sendGameEventToPlayer(Server_Player *player, GameEvent *event) { player->sendProtocolItem(new GameEventContainer(QList() << event, gameId)); } + +ServerInfo_Game *Server_Game::getInfo() const +{ + if (players.isEmpty()) + // Game is open + return new ServerInfo_Game(getGameId(), QString(), false, 0, getMaxPlayers(), 0, false, 0); + else + // Game is closing + return new ServerInfo_Game( + getGameId(), + getDescription(), + !getPassword().isEmpty(), + getPlayerCount(), + getMaxPlayers(), + new ServerInfo_User(getCreatorInfo()), + getSpectatorsAllowed(), + getSpectatorsNeedPassword(), + getSpectatorCount() + ); +} \ No newline at end of file diff --git a/common/server_game.h b/common/server_game.h index 41c52698..29d2c91a 100644 --- a/common/server_game.h +++ b/common/server_game.h @@ -27,7 +27,7 @@ #include "protocol.h" class QTimer; -class Server; +class Server_Room; class ServerInfo_User; class Server_Game : public QObject { @@ -46,14 +46,16 @@ private: bool spectatorsCanTalk; bool spectatorsSeeEverything; int inactivityCounter; + int secondsElapsed; QTimer *pingClock; signals: void gameClosing(); private slots: void pingClockTimeout(); public: - Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QString &_description, const QString &_password, int _maxPlayers, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, Server *parent); + Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QString &_description, const QString &_password, int _maxPlayers, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, Server_Room *parent); ~Server_Game(); + ServerInfo_Game *getInfo() const; ServerInfo_User *getCreatorInfo() const { return creatorInfo; } bool getGameStarted() const { return gameStarted; } int getPlayerCount() const; diff --git a/common/server_player.cpp b/common/server_player.cpp index ebc34b43..a1092d39 100644 --- a/common/server_player.cpp +++ b/common/server_player.cpp @@ -8,6 +8,7 @@ #include "protocol.h" #include "protocol_items.h" #include "decklist.h" +#include Server_Player::Server_Player(Server_Game *_game, int _playerId, ServerInfo_User *_userInfo, bool _spectator, Server_ProtocolHandler *_handler) : game(_game), handler(_handler), userInfo(new ServerInfo_User(_userInfo)), deck(0), playerId(_playerId), spectator(_spectator), nextCardId(0), readyStart(false), conceded(false), deckId(-2) @@ -198,6 +199,219 @@ bool Server_Player::deleteCounter(int counterId) return true; } +ResponseCode Server_Player::moveCard(CommandContainer *cont, const QString &_startZone, const QList &_cardIds, int targetPlayerId, const QString &_targetZone, int x, int y, bool faceDown, bool tapped) +{ + Server_CardZone *startzone = getZones().value(_startZone); + Server_Player *targetPlayer = game->getPlayers().value(targetPlayerId); + if (!targetPlayer) + return RespNameNotFound; + Server_CardZone *targetzone = targetPlayer->getZones().value(_targetZone); + if ((!startzone) || (!targetzone)) + return RespNameNotFound; + + return moveCard(cont, startzone, _cardIds, targetzone, x, y, faceDown, tapped); +} + +class Server_Player::MoveCardCompareFunctor { +private: + int x; +public: + MoveCardCompareFunctor(int _x) : x(_x) { } + inline bool operator()(QPair a, QPair b) + { + if (a.second < x) { + if (b.second >= x) + return false; + else + return (a.second > b.second); + } else { + if (b.second < x) + return true; + else + return (a.second < b.second); + } + } +}; + +ResponseCode Server_Player::moveCard(CommandContainer *cont, Server_CardZone *startzone, const QList &_cardIds, Server_CardZone *targetzone, int x, int y, bool faceDown, bool tapped) +{ + // Disallow controller change between different zones. + if ((startzone->getName() != targetzone->getName()) && (startzone->getPlayer() != targetzone->getPlayer())) + return RespContextError; + + if (!targetzone->hasCoords() && (x == -1)) + x = targetzone->cards.size(); + + QList > cardsToMove; + for (int i = 0; i < _cardIds.size(); ++i) { + int position; + Server_Card *card = startzone->getCard(_cardIds[i], false, &position); + if (!card) + return RespNameNotFound; + if (!card->getAttachedCards().isEmpty() && !targetzone->isColumnEmpty(x, y)) + return RespContextError; + cardsToMove.append(QPair(card, position)); + } + + MoveCardCompareFunctor cmp(startzone == targetzone ? -1 : x); + qSort(cardsToMove.begin(), cardsToMove.end(), cmp); + + bool secondHalf = false; + int xIndex = -1; + for (int cardIndex = 0; cardIndex < cardsToMove.size(); ++cardIndex) { + Server_Card *card = cardsToMove[cardIndex].first; + int originalPosition = cardsToMove[cardIndex].second; + int position = startzone->removeCard(card); + if ((startzone == targetzone) && !startzone->hasCoords()) { + if (!secondHalf && (originalPosition < x)) { + xIndex = -1; + secondHalf = true; + } else if (secondHalf) + --xIndex; + else + ++xIndex; + } else + ++xIndex; + int newX = x + xIndex; + + // Attachment relationships can be retained when moving a card onto the opponent's table + if (startzone->getName() != targetzone->getName()) { + // Delete all attachment relationships + if (card->getParentCard()) + card->setParentCard(0); + + // Make a copy of the list because the original one gets modified during the loop + QList attachedCards = card->getAttachedCards(); + for (int i = 0; i < attachedCards.size(); ++i) + attachedCards[i]->getZone()->getPlayer()->unattachCard(cont, attachedCards[i]); + } + + if (startzone != targetzone) { + // Delete all arrows from and to the card + const QList &players = game->getPlayers().values(); + for (int i = 0; i < players.size(); ++i) { + QList arrowsToDelete; + QMapIterator arrowIterator(players[i]->getArrows()); + while (arrowIterator.hasNext()) { + Server_Arrow *arrow = arrowIterator.next().value(); + if ((arrow->getStartCard() == card) || (arrow->getTargetItem() == card)) + arrowsToDelete.append(arrow->getId()); + } + for (int j = 0; j < arrowsToDelete.size(); ++j) + players[i]->deleteArrow(arrowsToDelete[j]); + } + } + + if (card->getDestroyOnZoneChange() && (startzone != targetzone)) { + cont->enqueueGameEventPrivate(new Event_DestroyCard(getPlayerId(), startzone->getName(), card->getId()), game->getGameId()); + cont->enqueueGameEventPublic(new Event_DestroyCard(getPlayerId(), startzone->getName(), card->getId()), game->getGameId()); + card->deleteLater(); + } else { + if (!targetzone->hasCoords()) { + y = 0; + card->resetState(); + } else + newX = targetzone->getFreeGridColumn(newX, y, card->getName()); + + targetzone->insertCard(card, newX, y); + + bool targetBeingLookedAt = (targetzone->getType() != HiddenZone) || (targetzone->getCardsBeingLookedAt() > newX) || (targetzone->getCardsBeingLookedAt() == -1); + bool sourceBeingLookedAt = (startzone->getType() != HiddenZone) || (startzone->getCardsBeingLookedAt() > position) || (startzone->getCardsBeingLookedAt() == -1); + + bool targetHiddenToPlayer = faceDown || !targetBeingLookedAt; + bool targetHiddenToOthers = faceDown || (targetzone->getType() != PublicZone); + bool sourceHiddenToPlayer = card->getFaceDown() || !sourceBeingLookedAt; + bool sourceHiddenToOthers = card->getFaceDown() || (startzone->getType() != PublicZone); + + QString privateCardName, publicCardName; + if (!(sourceHiddenToPlayer && targetHiddenToPlayer)) + privateCardName = card->getName(); + if (!(sourceHiddenToOthers && targetHiddenToOthers)) + publicCardName = card->getName(); + + int oldCardId = card->getId(); + if (faceDown) + card->setId(newCardId()); + card->setFaceDown(faceDown); + + // The player does not get to see which card he moved if it moves between two parts of hidden zones which + // are not being looked at. + int privateNewCardId = card->getId(); + int privateOldCardId = oldCardId; + if (!targetBeingLookedAt && !sourceBeingLookedAt) { + privateOldCardId = -1; + privateNewCardId = -1; + privateCardName = QString(); + } + int privatePosition = -1; + if (startzone->getType() == HiddenZone) + privatePosition = position; + cont->enqueueGameEventPrivate(new Event_MoveCard(getPlayerId(), privateOldCardId, privateCardName, startzone->getName(), privatePosition, targetzone->getPlayer()->getPlayerId(), targetzone->getName(), newX, y, privateNewCardId, faceDown), game->getGameId()); + cont->enqueueGameEventOmniscient(new Event_MoveCard(getPlayerId(), privateOldCardId, privateCardName, startzone->getName(), privatePosition, targetzone->getPlayer()->getPlayerId(), targetzone->getName(), newX, y, privateNewCardId, faceDown), game->getGameId()); + + // Other players do not get to see the start and/or target position of the card if the respective + // part of the zone is being looked at. The information is not needed anyway because in hidden zones, + // all cards are equal. + if ( + ((startzone->getType() == HiddenZone) && ((startzone->getCardsBeingLookedAt() > position) || (startzone->getCardsBeingLookedAt() == -1))) + || (startzone->getType() == PublicZone) + ) + position = -1; + if ((targetzone->getType() == HiddenZone) && ((targetzone->getCardsBeingLookedAt() > newX) || (targetzone->getCardsBeingLookedAt() == -1))) + newX = -1; + + if ((startzone->getType() == PublicZone) || (targetzone->getType() == PublicZone)) + cont->enqueueGameEventPublic(new Event_MoveCard(getPlayerId(), oldCardId, publicCardName, startzone->getName(), position, targetzone->getPlayer()->getPlayerId(), targetzone->getName(), newX, y, card->getId(), faceDown), game->getGameId()); + else + cont->enqueueGameEventPublic(new Event_MoveCard(getPlayerId(), -1, QString(), startzone->getName(), position, targetzone->getPlayer()->getPlayerId(), targetzone->getName(), newX, y, -1, false), game->getGameId()); + + if (tapped) + setCardAttrHelper(cont, targetzone->getName(), card->getId(), "tapped", "1"); + } + } + if (startzone->hasCoords()) + startzone->fixFreeSpaces(cont); + + return RespOk; +} + +void Server_Player::unattachCard(CommandContainer *cont, Server_Card *card) +{ + Server_CardZone *zone = card->getZone(); + + card->setParentCard(0); + cont->enqueueGameEventPrivate(new Event_AttachCard(getPlayerId(), zone->getName(), card->getId(), -1, QString(), -1), game->getGameId()); + cont->enqueueGameEventPublic(new Event_AttachCard(getPlayerId(), zone->getName(), card->getId(), -1, QString(), -1), game->getGameId()); + + moveCard(cont, zone, QList() << card->getId(), zone, -1, card->getY(), card->getFaceDown(), card->getTapped()); +} + +ResponseCode Server_Player::setCardAttrHelper(CommandContainer *cont, const QString &zoneName, int cardId, const QString &attrName, const QString &attrValue) +{ + Server_CardZone *zone = getZones().value(zoneName); + if (!zone) + return RespNameNotFound; + if (!zone->hasCoords()) + return RespContextError; + + if (cardId == -1) { + QListIterator CardIterator(zone->cards); + while (CardIterator.hasNext()) + if (!CardIterator.next()->setAttribute(attrName, attrValue, true)) + return RespInvalidCommand; + } else { + Server_Card *card = zone->getCard(cardId, false); + if (!card) + return RespNameNotFound; + if (!card->setAttribute(attrName, attrValue, false)) + return RespInvalidCommand; + } + cont->enqueueGameEventPrivate(new Event_SetCardAttr(getPlayerId(), zone->getName(), cardId, attrName, attrValue), game->getGameId()); + cont->enqueueGameEventPublic(new Event_SetCardAttr(getPlayerId(), zone->getName(), cardId, attrName, attrValue), game->getGameId()); + cont->enqueueGameEventOmniscient(new Event_SetCardAttr(getPlayerId(), zone->getName(), cardId, attrName, attrValue), game->getGameId()); + return RespOk; +} + void Server_Player::sendProtocolItem(ProtocolItem *item, bool deleteItem) { if (handler) diff --git a/common/server_player.h b/common/server_player.h index 2381a836..5bd08d96 100644 --- a/common/server_player.h +++ b/common/server_player.h @@ -5,20 +5,24 @@ #include #include #include +#include "protocol_datastructures.h" class DeckList; class Server_Game; class Server_CardZone; class Server_Counter; class Server_Arrow; +class Server_Card; class Server_ProtocolHandler; class ProtocolItem; class ServerInfo_User; class ServerInfo_PlayerProperties; +class CommandContainer; class Server_Player : public Server_ArrowTarget { Q_OBJECT private: + class MoveCardCompareFunctor; Server_Game *game; Server_ProtocolHandler *handler; ServerInfo_User *userInfo; @@ -71,6 +75,11 @@ public: void clearZones(); void setupZones(); + ResponseCode moveCard(CommandContainer *cont, const QString &_startZone, const QList &_cardId, int _targetPlayer, const QString &_targetZone, int _x, int _y, bool _faceDown, bool _tapped); + ResponseCode moveCard(CommandContainer *cont, Server_CardZone *startzone, const QList &_cardId, Server_CardZone *targetzone, int x, int y, bool faceDown, bool tapped); + void unattachCard(CommandContainer *cont, Server_Card *card); + ResponseCode setCardAttrHelper(CommandContainer *cont, const QString &zone, int cardId, const QString &attrName, const QString &attrValue); + void sendProtocolItem(ProtocolItem *item, bool deleteItem = true); }; diff --git a/common/server_protocolhandler.cpp b/common/server_protocolhandler.cpp index 18c80565..0fa91781 100644 --- a/common/server_protocolhandler.cpp +++ b/common/server_protocolhandler.cpp @@ -3,7 +3,7 @@ #include "server_protocolhandler.h" #include "protocol.h" #include "protocol_items.h" -#include "server_chatchannel.h" +#include "server_room.h" #include "server_card.h" #include "server_arrow.h" #include "server_cardzone.h" @@ -14,7 +14,7 @@ #include Server_ProtocolHandler::Server_ProtocolHandler(Server *_server, QObject *parent) - : QObject(parent), server(_server), authState(PasswordWrong), acceptsGameListChanges(false), acceptsUserListChanges(false), acceptsChatChannelListChanges(false), userInfo(0), lastCommandTime(QDateTime::currentDateTime()) + : QObject(parent), server(_server), authState(PasswordWrong), acceptsUserListChanges(false), acceptsRoomListChanges(false), userInfo(0), lastCommandTime(QDateTime::currentDateTime()) { connect(server, SIGNAL(pingClockTimeout()), this, SLOT(pingClockTimeout())); } @@ -25,6 +25,10 @@ Server_ProtocolHandler::~Server_ProtocolHandler() // so it will not receive the game update event. server->removeClient(this); + QMapIterator roomIterator(rooms); + while (roomIterator.hasNext()) + roomIterator.next().value()->removeClient(this); + QMapIterator > gameIterator(games); while (gameIterator.hasNext()) { gameIterator.next(); @@ -37,10 +41,6 @@ Server_ProtocolHandler::~Server_ProtocolHandler() p->setProtocolHandler(0); } - QMapIterator chatChannelIterator(chatChannels); - while (chatChannelIterator.hasNext()) - chatChannelIterator.next().value()->removeClient(this); - delete userInfo; } @@ -54,22 +54,26 @@ ResponseCode Server_ProtocolHandler::processCommandHelper(Command *command, Comm { lastCommandTime = QDateTime::currentDateTime(); - ChatCommand *chatCommand = qobject_cast(command); - GameCommand *gameCommand = qobject_cast(command); - if (chatCommand) { - qDebug() << "received ChatCommand: channel =" << chatCommand->getChannel(); + RoomCommand *roomCommand = qobject_cast(command); + if (roomCommand) { + qDebug() << "received RoomCommand: roomId =" << roomCommand->getRoomId(); if (authState == PasswordWrong) return RespLoginNeeded; - Server_ChatChannel *channel = chatChannels.value(chatCommand->getChannel(), 0); - if (!channel) + Server_Room *room = rooms.value(roomCommand->getRoomId(), 0); + if (!room) return RespNameNotFound; switch (command->getItemId()) { - case ItemId_Command_ChatLeaveChannel: return cmdChatLeaveChannel(qobject_cast(command), cont, channel); - case ItemId_Command_ChatSay: return cmdChatSay(qobject_cast(command), cont, channel); + case ItemId_Command_LeaveRoom: return cmdLeaveRoom(static_cast(command), cont, room); + case ItemId_Command_RoomSay: return cmdRoomSay(static_cast(command), cont, room); + case ItemId_Command_CreateGame: return cmdCreateGame(static_cast(command), cont, room); + case ItemId_Command_JoinGame: return cmdJoinGame(static_cast(command), cont, room); + default: return RespInvalidCommand; } - } else if (gameCommand) { + } + GameCommand *gameCommand = qobject_cast(command); + if (gameCommand) { qDebug() << "received GameCommand: game =" << gameCommand->getGameId(); if (authState == PasswordWrong) return RespLoginNeeded; @@ -83,57 +87,65 @@ ResponseCode Server_ProtocolHandler::processCommandHelper(Command *command, Comm Server_Player *player = gamePair.second; switch (command->getItemId()) { - case ItemId_Command_DeckSelect: return cmdDeckSelect(qobject_cast(command), cont, game, player); - case ItemId_Command_SetSideboardPlan: return cmdSetSideboardPlan(qobject_cast(command), cont, game, player); - case ItemId_Command_LeaveGame: return cmdLeaveGame(qobject_cast(command), cont, game, player); - case ItemId_Command_ReadyStart: return cmdReadyStart(qobject_cast(command), cont, game, player); - case ItemId_Command_Concede: return cmdConcede(qobject_cast(command), cont, game, player); - case ItemId_Command_Say: return cmdSay(qobject_cast(command), cont, game, player); - case ItemId_Command_Shuffle: return cmdShuffle(qobject_cast(command), cont, game, player); - case ItemId_Command_Mulligan: return cmdMulligan(qobject_cast(command), cont, game, player); - case ItemId_Command_RollDie: return cmdRollDie(qobject_cast(command), cont, game, player); - case ItemId_Command_DrawCards: return cmdDrawCards(qobject_cast(command), cont, game, player); - case ItemId_Command_MoveCard: return cmdMoveCard(qobject_cast(command), cont, game, player); - case ItemId_Command_FlipCard: return cmdFlipCard(qobject_cast(command), cont, game, player); - case ItemId_Command_AttachCard: return cmdAttachCard(qobject_cast(command), cont, game, player); - case ItemId_Command_CreateToken: return cmdCreateToken(qobject_cast(command), cont, game, player); - case ItemId_Command_CreateArrow: return cmdCreateArrow(qobject_cast(command), cont, game, player); - case ItemId_Command_DeleteArrow: return cmdDeleteArrow(qobject_cast(command), cont, game, player); - case ItemId_Command_SetCardAttr: return cmdSetCardAttr(qobject_cast(command), cont, game, player); - case ItemId_Command_SetCardCounter: return cmdSetCardCounter(qobject_cast(command), cont, game, player); - case ItemId_Command_IncCardCounter: return cmdIncCardCounter(qobject_cast(command), cont, game, player); - case ItemId_Command_IncCounter: return cmdIncCounter(qobject_cast(command), cont, game, player); - case ItemId_Command_CreateCounter: return cmdCreateCounter(qobject_cast(command), cont, game, player); - case ItemId_Command_SetCounter: return cmdSetCounter(qobject_cast(command), cont, game, player); - case ItemId_Command_DelCounter: return cmdDelCounter(qobject_cast(command), cont, game, player); - case ItemId_Command_NextTurn: return cmdNextTurn(qobject_cast(command), cont, game, player); - case ItemId_Command_SetActivePhase: return cmdSetActivePhase(qobject_cast(command), cont, game, player); - case ItemId_Command_DumpZone: return cmdDumpZone(qobject_cast(command), cont, game, player); - case ItemId_Command_StopDumpZone: return cmdStopDumpZone(qobject_cast(command), cont, game, player); - case ItemId_Command_RevealCards: return cmdRevealCards(qobject_cast(command), cont, game, player); - } - } else { - qDebug() << "received generic Command"; - switch (command->getItemId()) { - case ItemId_Command_Ping: return cmdPing(qobject_cast(command), cont); - case ItemId_Command_Login: return cmdLogin(qobject_cast(command), cont); - case ItemId_Command_Message: return cmdMessage(qobject_cast(command), cont); - case ItemId_Command_DeckList: return cmdDeckList(qobject_cast(command), cont); - case ItemId_Command_DeckNewDir: return cmdDeckNewDir(qobject_cast(command), cont); - case ItemId_Command_DeckDelDir: return cmdDeckDelDir(qobject_cast(command), cont); - case ItemId_Command_DeckDel: return cmdDeckDel(qobject_cast(command), cont); - case ItemId_Command_DeckUpload: return cmdDeckUpload(qobject_cast(command), cont); - case ItemId_Command_DeckDownload: return cmdDeckDownload(qobject_cast(command), cont); - case ItemId_Command_GetUserInfo: return cmdGetUserInfo(qobject_cast(command), cont); - case ItemId_Command_ListChatChannels: return cmdListChatChannels(qobject_cast(command), cont); - case ItemId_Command_ChatJoinChannel: return cmdChatJoinChannel(qobject_cast(command), cont); - case ItemId_Command_ListUsers: return cmdListUsers(qobject_cast(command), cont); - case ItemId_Command_ListGames: return cmdListGames(qobject_cast(command), cont); - case ItemId_Command_CreateGame: return cmdCreateGame(qobject_cast(command), cont); - case ItemId_Command_JoinGame: return cmdJoinGame(qobject_cast(command), cont); + case ItemId_Command_DeckSelect: return cmdDeckSelect(static_cast(command), cont, game, player); + case ItemId_Command_SetSideboardPlan: return cmdSetSideboardPlan(static_cast(command), cont, game, player); + case ItemId_Command_LeaveGame: return cmdLeaveGame(static_cast(command), cont, game, player); + case ItemId_Command_ReadyStart: return cmdReadyStart(static_cast(command), cont, game, player); + case ItemId_Command_Concede: return cmdConcede(static_cast(command), cont, game, player); + case ItemId_Command_Say: return cmdSay(static_cast(command), cont, game, player); + case ItemId_Command_Shuffle: return cmdShuffle(static_cast(command), cont, game, player); + case ItemId_Command_Mulligan: return cmdMulligan(static_cast(command), cont, game, player); + case ItemId_Command_RollDie: return cmdRollDie(static_cast(command), cont, game, player); + case ItemId_Command_DrawCards: return cmdDrawCards(static_cast(command), cont, game, player); + case ItemId_Command_MoveCard: return cmdMoveCard(static_cast(command), cont, game, player); + case ItemId_Command_FlipCard: return cmdFlipCard(static_cast(command), cont, game, player); + case ItemId_Command_AttachCard: return cmdAttachCard(static_cast(command), cont, game, player); + case ItemId_Command_CreateToken: return cmdCreateToken(static_cast(command), cont, game, player); + case ItemId_Command_CreateArrow: return cmdCreateArrow(static_cast(command), cont, game, player); + case ItemId_Command_DeleteArrow: return cmdDeleteArrow(static_cast(command), cont, game, player); + case ItemId_Command_SetCardAttr: return cmdSetCardAttr(static_cast(command), cont, game, player); + case ItemId_Command_SetCardCounter: return cmdSetCardCounter(static_cast(command), cont, game, player); + case ItemId_Command_IncCardCounter: return cmdIncCardCounter(static_cast(command), cont, game, player); + case ItemId_Command_IncCounter: return cmdIncCounter(static_cast(command), cont, game, player); + case ItemId_Command_CreateCounter: return cmdCreateCounter(static_cast(command), cont, game, player); + case ItemId_Command_SetCounter: return cmdSetCounter(static_cast(command), cont, game, player); + case ItemId_Command_DelCounter: return cmdDelCounter(static_cast(command), cont, game, player); + case ItemId_Command_NextTurn: return cmdNextTurn(static_cast(command), cont, game, player); + case ItemId_Command_SetActivePhase: return cmdSetActivePhase(static_cast(command), cont, game, player); + case ItemId_Command_DumpZone: return cmdDumpZone(static_cast(command), cont, game, player); + case ItemId_Command_StopDumpZone: return cmdStopDumpZone(static_cast(command), cont, game, player); + case ItemId_Command_RevealCards: return cmdRevealCards(static_cast(command), cont, game, player); + default: return RespInvalidCommand; } } - return RespInvalidCommand; + AdminCommand *adminCommand = qobject_cast(command); + if (adminCommand) { + qDebug() << "received AdminCommand"; + if (!(userInfo->getUserLevel() & ServerInfo_User::IsAdmin)) + return RespLoginNeeded; + + switch (command->getItemId()) { + case ItemId_Command_UpdateServerMessage: return cmdUpdateServerMessage(static_cast(command), cont); + default: return RespInvalidCommand; + } + } + qDebug() << "received generic Command"; + switch (command->getItemId()) { + case ItemId_Command_Ping: return cmdPing(static_cast(command), cont); + case ItemId_Command_Login: return cmdLogin(static_cast(command), cont); + case ItemId_Command_Message: return cmdMessage(static_cast(command), cont); + case ItemId_Command_DeckList: return cmdDeckList(static_cast(command), cont); + case ItemId_Command_DeckNewDir: return cmdDeckNewDir(static_cast(command), cont); + case ItemId_Command_DeckDelDir: return cmdDeckDelDir(static_cast(command), cont); + case ItemId_Command_DeckDel: return cmdDeckDel(static_cast(command), cont); + case ItemId_Command_DeckUpload: return cmdDeckUpload(static_cast(command), cont); + case ItemId_Command_DeckDownload: return cmdDeckDownload(static_cast(command), cont); + case ItemId_Command_GetUserInfo: return cmdGetUserInfo(static_cast(command), cont); + case ItemId_Command_ListRooms: return cmdListRooms(static_cast(command), cont); + case ItemId_Command_JoinRoom: return cmdJoinRoom(static_cast(command), cont); + case ItemId_Command_ListUsers: return cmdListUsers(static_cast(command), cont); + default: return RespInvalidCommand; + } } void Server_ProtocolHandler::processCommandContainer(CommandContainer *cont) @@ -235,8 +247,9 @@ ResponseCode Server_ProtocolHandler::cmdLogin(Command_Login *cmd, CommandContain } } } - - return RespOk; + + cont->setResponse(new Response_Login(cont->getCmdId(), RespOk, new ServerInfo_User(userInfo, true))); + return RespNothing; } ResponseCode Server_ProtocolHandler::cmdMessage(Command_Message *cmd, CommandContainer *cont) @@ -266,58 +279,59 @@ ResponseCode Server_ProtocolHandler::cmdGetUserInfo(Command_GetUserInfo *cmd, Co Server_ProtocolHandler *handler = server->getUsers().value(cmd->getUserName()); if (!handler) return RespNameNotFound; - result = handler->getUserInfo(); + result = new ServerInfo_User(handler->getUserInfo()); } - + cont->setResponse(new Response_GetUserInfo(cont->getCmdId(), RespOk, result)); return RespNothing; } -ResponseCode Server_ProtocolHandler::cmdListChatChannels(Command_ListChatChannels * /*cmd*/, CommandContainer *cont) +ResponseCode Server_ProtocolHandler::cmdListRooms(Command_ListRooms * /*cmd*/, CommandContainer *cont) { if (authState == PasswordWrong) return RespLoginNeeded; - QList eventChannelList; - QMapIterator channelIterator(server->getChatChannels()); - while (channelIterator.hasNext()) { - Server_ChatChannel *c = channelIterator.next().value(); - eventChannelList.append(new ServerInfo_ChatChannel(c->getName(), c->getDescription(), c->size(), c->getAutoJoin())); - } - cont->enqueueItem(new Event_ListChatChannels(eventChannelList)); + QList eventRoomList; + QMapIterator roomIterator(server->getRooms()); + while (roomIterator.hasNext()) + eventRoomList.append(roomIterator.next().value()->getInfo(false)); + cont->enqueueItem(new Event_ListRooms(eventRoomList)); - acceptsChatChannelListChanges = true; + acceptsRoomListChanges = true; return RespOk; } -ResponseCode Server_ProtocolHandler::cmdChatJoinChannel(Command_ChatJoinChannel *cmd, CommandContainer *cont) +ResponseCode Server_ProtocolHandler::cmdJoinRoom(Command_JoinRoom *cmd, CommandContainer *cont) { if (authState == PasswordWrong) return RespLoginNeeded; - if (chatChannels.contains(cmd->getChannel())) + if (rooms.contains(cmd->getRoomId())) return RespContextError; - QMap allChannels = server->getChatChannels(); - Server_ChatChannel *c = allChannels.value(cmd->getChannel(), 0); - if (!c) + Server_Room *r = server->getRooms().value(cmd->getRoomId(), 0); + if (!r) return RespNameNotFound; - c->addClient(this); - chatChannels.insert(cmd->getChannel(), c); + r->addClient(this); + rooms.insert(r->getId(), r); + + enqueueProtocolItem(new Event_RoomSay(r->getId(), QString(), r->getJoinMessage())); + + cont->setResponse(new Response_JoinRoom(cont->getCmdId(), RespOk, r->getInfo(true))); + return RespNothing; +} + +ResponseCode Server_ProtocolHandler::cmdLeaveRoom(Command_LeaveRoom * /*cmd*/, CommandContainer *cont, Server_Room *room) +{ + rooms.remove(room->getId()); + room->removeClient(this); return RespOk; } -ResponseCode Server_ProtocolHandler::cmdChatLeaveChannel(Command_ChatLeaveChannel * /*cmd*/, CommandContainer *cont, Server_ChatChannel *channel) +ResponseCode Server_ProtocolHandler::cmdRoomSay(Command_RoomSay *cmd, CommandContainer *cont, Server_Room *room) { - chatChannels.remove(channel->getName()); - channel->removeClient(this); - return RespOk; -} - -ResponseCode Server_ProtocolHandler::cmdChatSay(Command_ChatSay *cmd, CommandContainer *cont, Server_ChatChannel *channel) -{ - channel->say(this, cmd->getMessage()); + room->say(this, cmd->getMessage()); return RespOk; } @@ -329,7 +343,7 @@ ResponseCode Server_ProtocolHandler::cmdListUsers(Command_ListUsers * /*cmd*/, C QList resultList; QMapIterator userIterator = server->getUsers(); while (userIterator.hasNext()) - resultList.append(new ServerInfo_User(userIterator.next().value()->getUserInfo())); + resultList.append(new ServerInfo_User(userIterator.next().value()->getUserInfo(), false)); acceptsUserListChanges = true; @@ -337,39 +351,12 @@ ResponseCode Server_ProtocolHandler::cmdListUsers(Command_ListUsers * /*cmd*/, C return RespNothing; } -ResponseCode Server_ProtocolHandler::cmdListGames(Command_ListGames * /*cmd*/, CommandContainer *cont) +ResponseCode Server_ProtocolHandler::cmdCreateGame(Command_CreateGame *cmd, CommandContainer *cont, Server_Room *room) { if (authState == PasswordWrong) return RespLoginNeeded; - const QList &gameList = server->getGames(); - QList eventGameList; - for (int i = 0; i < gameList.size(); ++i) { - Server_Game *g = gameList[i]; - eventGameList.append(new ServerInfo_Game( - g->getGameId(), - g->getDescription(), - !g->getPassword().isEmpty(), - g->getPlayerCount(), - g->getMaxPlayers(), - new ServerInfo_User(g->getCreatorInfo()), - g->getSpectatorsAllowed(), - g->getSpectatorsNeedPassword(), - g->getSpectatorCount() - )); - } - cont->enqueueItem(new Event_ListGames(eventGameList)); - - acceptsGameListChanges = true; - return RespOk; -} - -ResponseCode Server_ProtocolHandler::cmdCreateGame(Command_CreateGame *cmd, CommandContainer *cont) -{ - if (authState == PasswordWrong) - return RespLoginNeeded; - - Server_Game *game = server->createGame(cmd->getDescription(), cmd->getPassword(), cmd->getMaxPlayers(), cmd->getSpectatorsAllowed(), cmd->getSpectatorsNeedPassword(), cmd->getSpectatorsCanTalk(), cmd->getSpectatorsSeeEverything(), this); + Server_Game *game = room->createGame(cmd->getDescription(), cmd->getPassword(), cmd->getMaxPlayers(), cmd->getSpectatorsAllowed(), cmd->getSpectatorsNeedPassword(), cmd->getSpectatorsCanTalk(), cmd->getSpectatorsSeeEverything(), this); Server_Player *creator = game->getPlayers().values().first(); games.insert(game->getGameId(), QPair(game, creator)); @@ -378,7 +365,7 @@ ResponseCode Server_ProtocolHandler::cmdCreateGame(Command_CreateGame *cmd, Comm return RespOk; } -ResponseCode Server_ProtocolHandler::cmdJoinGame(Command_JoinGame *cmd, CommandContainer *cont) +ResponseCode Server_ProtocolHandler::cmdJoinGame(Command_JoinGame *cmd, CommandContainer *cont, Server_Room *room) { if (authState == PasswordWrong) return RespLoginNeeded; @@ -386,7 +373,7 @@ ResponseCode Server_ProtocolHandler::cmdJoinGame(Command_JoinGame *cmd, CommandC if (games.contains(cmd->getGameId())) return RespContextError; - Server_Game *g = server->getGame(cmd->getGameId()); + Server_Game *g = room->getGames().value(cmd->getGameId()); if (!g) return RespNameNotFound; @@ -503,21 +490,19 @@ ResponseCode Server_ProtocolHandler::cmdMulligan(Command_Mulligan * /*cmd*/, Com if (!game->getGameStarted()) return RespGameNotStarted; - - int number = player->getInitialCards(); - if (!number) - return RespContextError; - + Server_CardZone *hand = player->getZones().value("hand"); + int number = (hand->cards.size() <= 1) ? player->getInitialCards() : hand->cards.size() - 1; + + Server_CardZone *deck = player->getZones().value("deck"); while (!hand->cards.isEmpty()) - moveCard(game, player, cont, "hand", hand->cards.first()->getId(), "deck", 0, 0, false, false); + player->moveCard(cont, hand, QList() << hand->cards.first()->getId(), deck, 0, 0, false, false); - player->getZones().value("deck")->shuffle(); + deck->shuffle(); cont->enqueueGameEventPrivate(new Event_Shuffle(player->getPlayerId()), game->getGameId()); cont->enqueueGameEventPublic(new Event_Shuffle(player->getPlayerId()), game->getGameId()); drawCards(game, player, cont, number); - player->setInitialCards(number - 1); return RespOk; } @@ -565,130 +550,21 @@ ResponseCode Server_ProtocolHandler::cmdDrawCards(Command_DrawCards *cmd, Comman return drawCards(game, player, cont, cmd->getNumber()); } -ResponseCode Server_ProtocolHandler::moveCard(Server_Game *game, Server_Player *player, CommandContainer *cont, const QString &_startZone, int _cardId, const QString &_targetZone, int x, int y, bool faceDown, bool tapped) + +ResponseCode Server_ProtocolHandler::cmdMoveCard(Command_MoveCard *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player) { if (player->getSpectator()) return RespFunctionNotAllowed; if (!game->getGameStarted()) return RespGameNotStarted; - - Server_CardZone *startzone = player->getZones().value(_startZone); - Server_CardZone *targetzone = player->getZones().value(_targetZone); - if ((!startzone) || (!targetzone)) - return RespNameNotFound; - - // Collision detection - if (targetzone->hasCoords()) - for (int i = 0; i < targetzone->cards.size(); ++i) - if ((targetzone->cards[i]->getX() == x) && (targetzone->cards[i]->getY() == y) && (x != -1)) - return RespContextError; - - int position = -1; - Server_Card *card = startzone->getCard(_cardId, true, &position); - if (!card) - return RespNameNotFound; - if (startzone != targetzone) { - // Delete all attachment relationships - if (card->getParentCard()) - card->setParentCard(0); - - const QList &attachedCards = card->getAttachedCards(); - for (int i = 0; i < attachedCards.size(); ++i) - unattachCard(game, attachedCards[i]->getZone()->getPlayer(), cont, attachedCards[i]); - - // Delete all arrows from and to the card - const QList &players = game->getPlayers().values(); - for (int i = 0; i < players.size(); ++i) { - QList arrowsToDelete; - QMapIterator arrowIterator(players[i]->getArrows()); - while (arrowIterator.hasNext()) { - Server_Arrow *arrow = arrowIterator.next().value(); - if ((arrow->getStartCard() == card) || (arrow->getTargetItem() == card)) - arrowsToDelete.append(arrow->getId()); - } - for (int j = 0; j < arrowsToDelete.size(); ++j) - players[i]->deleteArrow(arrowsToDelete[j]); - } - } + QList cardIds; + const QList &temp = cmd->getCardIds(); + for (int i = 0; i < temp.size(); ++i) + cardIds.append(temp[i]->getData()); - if (card->getDestroyOnZoneChange() && (startzone != targetzone)) { - cont->enqueueGameEventPrivate(new Event_DestroyCard(player->getPlayerId(), startzone->getName(), card->getId()), game->getGameId()); - cont->enqueueGameEventPublic(new Event_DestroyCard(player->getPlayerId(), startzone->getName(), card->getId()), game->getGameId()); - return RespOk; - } - - if (!targetzone->hasCoords()) { - y = 0; - if (x == -1) - x = targetzone->cards.size(); - - card->resetState(); - } else if (x == -1) - x = targetzone->getFreeGridColumn(y); - - targetzone->insertCard(card, x, y); - - bool targetBeingLookedAt = (targetzone->getType() != HiddenZone) || (targetzone->getCardsBeingLookedAt() > x) || (targetzone->getCardsBeingLookedAt() == -1); - bool sourceBeingLookedAt = (startzone->getType() != HiddenZone) || (startzone->getCardsBeingLookedAt() > position) || (startzone->getCardsBeingLookedAt() == -1); - - bool targetHiddenToPlayer = faceDown || !targetBeingLookedAt; - bool targetHiddenToOthers = faceDown || (targetzone->getType() != PublicZone); - bool sourceHiddenToPlayer = card->getFaceDown() || !sourceBeingLookedAt; - bool sourceHiddenToOthers = card->getFaceDown() || (startzone->getType() != PublicZone); - - QString privateCardName, publicCardName; - if (!(sourceHiddenToPlayer && targetHiddenToPlayer)) - privateCardName = card->getName(); - if (!(sourceHiddenToOthers && targetHiddenToOthers)) - publicCardName = card->getName(); - - int oldCardId = card->getId(); - if (faceDown) - card->setId(player->newCardId()); - card->setFaceDown(faceDown); - - // The player does not get to see which card he moved if it moves between two parts of hidden zones which - // are not being looked at. - int privateNewCardId = card->getId(); - int privateOldCardId = oldCardId; - if (!targetBeingLookedAt && !sourceBeingLookedAt) { - privateOldCardId = -1; - privateNewCardId = -1; - privateCardName = QString(); - } - int privatePosition = -1; - if (startzone->getType() == HiddenZone) - privatePosition = position; - cont->enqueueGameEventPrivate(new Event_MoveCard(player->getPlayerId(), privateOldCardId, privateCardName, startzone->getName(), privatePosition, targetzone->getName(), x, y, privateNewCardId, faceDown), game->getGameId()); - cont->enqueueGameEventOmniscient(new Event_MoveCard(player->getPlayerId(), privateOldCardId, privateCardName, startzone->getName(), privatePosition, targetzone->getName(), x, y, privateNewCardId, faceDown), game->getGameId()); - - // Other players do not get to see the start and/or target position of the card if the respective - // part of the zone is being looked at. The information is not needed anyway because in hidden zones, - // all cards are equal. - if ( - ((startzone->getType() == HiddenZone) && ((startzone->getCardsBeingLookedAt() > position) || (startzone->getCardsBeingLookedAt() == -1))) - || (startzone->getType() == PublicZone) - ) - position = -1; - if ((targetzone->getType() == HiddenZone) && ((targetzone->getCardsBeingLookedAt() > x) || (targetzone->getCardsBeingLookedAt() == -1))) - x = -1; - - if ((startzone->getType() == PublicZone) || (targetzone->getType() == PublicZone)) - cont->enqueueGameEventPublic(new Event_MoveCard(player->getPlayerId(), oldCardId, publicCardName, startzone->getName(), position, targetzone->getName(), x, y, card->getId(), faceDown), game->getGameId()); - else - cont->enqueueGameEventPublic(new Event_MoveCard(player->getPlayerId(), -1, QString(), startzone->getName(), position, targetzone->getName(), x, y, -1, false), game->getGameId()); - - if (tapped) - setCardAttrHelper(cont, game, player, targetzone->getName(), card->getId(), "tapped", "1"); - - return RespOk; -} - -ResponseCode Server_ProtocolHandler::cmdMoveCard(Command_MoveCard *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player) -{ - return moveCard(game, player, cont, cmd->getStartZone(), cmd->getCardId(), cmd->getTargetZone(), cmd->getX(), cmd->getY(), cmd->getFaceDown(), cmd->getTapped()); + return player->moveCard(cont, cmd->getStartZone(), cardIds, cmd->getTargetPlayerId(), cmd->getTargetZone(), cmd->getX(), cmd->getY(), cmd->getFaceDown(), cmd->getTapped()); } ResponseCode Server_ProtocolHandler::cmdFlipCard(Command_FlipCard *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player) @@ -720,17 +596,6 @@ ResponseCode Server_ProtocolHandler::cmdFlipCard(Command_FlipCard *cmd, CommandC return RespOk; } -void Server_ProtocolHandler::unattachCard(Server_Game *game, Server_Player *player, CommandContainer *cont, Server_Card *card) -{ - Server_CardZone *zone = card->getZone(); - - card->setParentCard(0); - cont->enqueueGameEventPrivate(new Event_AttachCard(player->getPlayerId(), zone->getName(), card->getId(), -1, QString(), -1), game->getGameId()); - cont->enqueueGameEventPublic(new Event_AttachCard(player->getPlayerId(), zone->getName(), card->getId(), -1, QString(), -1), game->getGameId()); - - moveCard(game, player, cont, zone->getName(), card->getId(), zone->getName(), -1, card->getY(), card->getFaceDown(), card->getTapped()); -} - ResponseCode Server_ProtocolHandler::cmdAttachCard(Command_AttachCard *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player) { if (player->getSpectator()) @@ -796,14 +661,17 @@ ResponseCode Server_ProtocolHandler::cmdAttachCard(Command_AttachCard *cmd, Comm // Unattach all cards attached to the card being attached. const QList &attachedList = card->getAttachedCards(); for (int i = 0; i < attachedList.size(); ++i) - unattachCard(game, player, cont, attachedList[i]); + player->unattachCard(cont, attachedList[i]); + + if (targetzone->isColumnStacked(targetCard->getX(), targetCard->getY())) + targetPlayer->moveCard(cont, targetzone, QList() << targetCard->getId(), targetzone, targetzone->getFreeGridColumn(-2, targetCard->getY(), targetCard->getName()), targetCard->getY(), targetCard->getFaceDown(), false); card->setParentCard(targetCard); card->setCoords(-1, card->getY()); cont->enqueueGameEventPrivate(new Event_AttachCard(player->getPlayerId(), startzone->getName(), card->getId(), targetPlayer->getPlayerId(), targetzone->getName(), targetCard->getId()), game->getGameId()); cont->enqueueGameEventPublic(new Event_AttachCard(player->getPlayerId(), startzone->getName(), card->getId(), targetPlayer->getPlayerId(), targetzone->getName(), targetCard->getId()), game->getGameId()); } else - unattachCard(game, player, cont, card); + player->unattachCard(cont, card); return RespOk; } @@ -822,8 +690,8 @@ ResponseCode Server_ProtocolHandler::cmdCreateToken(Command_CreateToken *cmd, Co int x = cmd->getX(); int y = cmd->getY(); - if (zone->hasCoords() && (x == -1)) - x = zone->getFreeGridColumn(y); + if (zone->hasCoords()) + x = zone->getFreeGridColumn(x, y, cmd->getCardName()); if (x < 0) x = 0; if (y < 0) @@ -917,7 +785,7 @@ ResponseCode Server_ProtocolHandler::cmdDeleteArrow(Command_DeleteArrow *cmd, Co return RespOk; } -ResponseCode Server_ProtocolHandler::setCardAttrHelper(CommandContainer *cont, Server_Game *game, Server_Player *player, const QString &zoneName, int cardId, const QString &attrName, const QString &attrValue) +ResponseCode Server_ProtocolHandler::cmdSetCardAttr(Command_SetCardAttr *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player) { if (player->getSpectator()) return RespFunctionNotAllowed; @@ -925,33 +793,7 @@ ResponseCode Server_ProtocolHandler::setCardAttrHelper(CommandContainer *cont, S if (!game->getGameStarted()) return RespGameNotStarted; - Server_CardZone *zone = player->getZones().value(zoneName); - if (!zone) - return RespNameNotFound; - if (!zone->hasCoords()) - return RespContextError; - - if (cardId == -1) { - QListIterator CardIterator(zone->cards); - while (CardIterator.hasNext()) - if (!CardIterator.next()->setAttribute(attrName, attrValue, true)) - return RespInvalidCommand; - } else { - Server_Card *card = zone->getCard(cardId, false); - if (!card) - return RespNameNotFound; - if (!card->setAttribute(attrName, attrValue, false)) - return RespInvalidCommand; - } - cont->enqueueGameEventPrivate(new Event_SetCardAttr(player->getPlayerId(), zone->getName(), cardId, attrName, attrValue), game->getGameId()); - cont->enqueueGameEventPublic(new Event_SetCardAttr(player->getPlayerId(), zone->getName(), cardId, attrName, attrValue), game->getGameId()); - cont->enqueueGameEventOmniscient(new Event_SetCardAttr(player->getPlayerId(), zone->getName(), cardId, attrName, attrValue), game->getGameId()); - return RespOk; -} - -ResponseCode Server_ProtocolHandler::cmdSetCardAttr(Command_SetCardAttr *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player) -{ - return setCardAttrHelper(cont, game, player, cmd->getZone(), cmd->getCardId(), cmd->getAttrName(), cmd->getAttrValue()); + return player->setCardAttrHelper(cont, cmd->getZone(), cmd->getCardId(), cmd->getAttrName(), cmd->getAttrValue()); } ResponseCode Server_ProtocolHandler::cmdSetCardCounter(Command_SetCardCounter *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player) diff --git a/common/server_protocolhandler.h b/common/server_protocolhandler.h index d7719259..3e915f42 100644 --- a/common/server_protocolhandler.h +++ b/common/server_protocolhandler.h @@ -10,6 +10,7 @@ class Server_Player; class Server_Card; class ServerInfo_User; +class Server_Room; class QTimer; class Server_ProtocolHandler : public QObject { @@ -17,15 +18,14 @@ class Server_ProtocolHandler : public QObject { protected: Server *server; QMap > games; - QMap chatChannels; + QMap rooms; Server *getServer() const { return server; } QPair getGame(int gameId) const; AuthenticationResult authState; - bool acceptsGameListChanges; bool acceptsUserListChanges; - bool acceptsChatChannelListChanges; + bool acceptsRoomListChanges; ServerInfo_User *userInfo; private: @@ -45,14 +45,13 @@ private: virtual ResponseCode cmdDeckUpload(Command_DeckUpload *cmd, CommandContainer *cont) = 0; virtual ResponseCode cmdDeckDownload(Command_DeckDownload *cmd, CommandContainer *cont) = 0; ResponseCode cmdGetUserInfo(Command_GetUserInfo *cmd, CommandContainer *cont); - ResponseCode cmdListChatChannels(Command_ListChatChannels *cmd, CommandContainer *cont); - ResponseCode cmdChatJoinChannel(Command_ChatJoinChannel *cmd, CommandContainer *cont); - ResponseCode cmdChatLeaveChannel(Command_ChatLeaveChannel *cmd, CommandContainer *cont, Server_ChatChannel *channel); - ResponseCode cmdChatSay(Command_ChatSay *cmd, CommandContainer *cont, Server_ChatChannel *channel); + ResponseCode cmdListRooms(Command_ListRooms *cmd, CommandContainer *cont); + ResponseCode cmdJoinRoom(Command_JoinRoom *cmd, CommandContainer *cont); + ResponseCode cmdLeaveRoom(Command_LeaveRoom *cmd, CommandContainer *cont, Server_Room *room); + ResponseCode cmdRoomSay(Command_RoomSay *cmd, CommandContainer *cont, Server_Room *room); ResponseCode cmdListUsers(Command_ListUsers *cmd, CommandContainer *cont); - ResponseCode cmdListGames(Command_ListGames *cmd, CommandContainer *cont); - ResponseCode cmdCreateGame(Command_CreateGame *cmd, CommandContainer *cont); - ResponseCode cmdJoinGame(Command_JoinGame *cmd, CommandContainer *cont); + ResponseCode cmdCreateGame(Command_CreateGame *cmd, CommandContainer *cont, Server_Room *room); + ResponseCode cmdJoinGame(Command_JoinGame *cmd, CommandContainer *cont, Server_Room *room); ResponseCode cmdLeaveGame(Command_LeaveGame *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); ResponseCode cmdConcede(Command_Concede *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); ResponseCode cmdReadyStart(Command_ReadyStart *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); @@ -62,18 +61,14 @@ private: ResponseCode cmdShuffle(Command_Shuffle *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); ResponseCode cmdMulligan(Command_Mulligan *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); ResponseCode cmdRollDie(Command_RollDie *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); - // XXX Maybe the following function and others belong into Server_Player ResponseCode drawCards(Server_Game *game, Server_Player *player, CommandContainer *cont, int number); ResponseCode cmdDrawCards(Command_DrawCards *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); - ResponseCode moveCard(Server_Game *game, Server_Player *player, CommandContainer *cont, const QString &_startZone, int _cardId, const QString &_targetZone, int _x, int _y, bool _faceDown, bool _tapped); ResponseCode cmdMoveCard(Command_MoveCard *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); ResponseCode cmdFlipCard(Command_FlipCard *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); - void unattachCard(Server_Game *game, Server_Player *player, CommandContainer *cont, Server_Card *card); ResponseCode cmdAttachCard(Command_AttachCard *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); ResponseCode cmdCreateToken(Command_CreateToken *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); ResponseCode cmdCreateArrow(Command_CreateArrow *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); ResponseCode cmdDeleteArrow(Command_DeleteArrow *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); - ResponseCode setCardAttrHelper(CommandContainer *cont, Server_Game *game, Server_Player *player, const QString &zone, int cardId, const QString &attrName, const QString &attrValue); ResponseCode cmdSetCardAttr(Command_SetCardAttr *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); ResponseCode cmdSetCardCounter(Command_SetCardCounter *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); ResponseCode cmdIncCardCounter(Command_IncCardCounter *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); @@ -86,6 +81,7 @@ private: ResponseCode cmdDumpZone(Command_DumpZone *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); ResponseCode cmdStopDumpZone(Command_StopDumpZone *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); ResponseCode cmdRevealCards(Command_RevealCards *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player); + virtual ResponseCode cmdUpdateServerMessage(Command_UpdateServerMessage *cmd, CommandContainer *cont) = 0; ResponseCode processCommandHelper(Command *command, CommandContainer *cont); private slots: @@ -95,9 +91,8 @@ public: ~Server_ProtocolHandler(); void playerRemovedFromGame(Server_Game *game); - bool getAcceptsGameListChanges() const { return acceptsGameListChanges; } bool getAcceptsUserListChanges() const { return acceptsUserListChanges; } - bool getAcceptsChatChannelListChanges() const { return acceptsChatChannelListChanges; } + bool getAcceptsRoomListChanges() const { return acceptsRoomListChanges; } ServerInfo_User *getUserInfo() const { return userInfo; } void setUserInfo(ServerInfo_User *_userInfo) { userInfo = _userInfo; } const QDateTime &getLastCommandTime() const { return lastCommandTime; } diff --git a/common/server_room.cpp b/common/server_room.cpp new file mode 100644 index 00000000..865c0cd7 --- /dev/null +++ b/common/server_room.cpp @@ -0,0 +1,94 @@ +#include "server_room.h" +#include "server_protocolhandler.h" +#include "server_game.h" +#include + +Server_Room::Server_Room(int _id, const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage, Server *parent) + : QObject(parent), id(_id), name(_name), description(_description), autoJoin(_autoJoin), joinMessage(_joinMessage) +{ +} + +Server *Server_Room::getServer() const +{ + return static_cast(parent()); +} + +ServerInfo_Room *Server_Room::getInfo(bool complete) const +{ + QList gameList; + QList userList; + if (complete) { + QMapIterator gameIterator(games); + while (gameIterator.hasNext()) + gameList.append(gameIterator.next().value()->getInfo()); + + for (int i = 0; i < size(); ++i) + userList.append(new ServerInfo_User(at(i)->getUserInfo(), false)); + } + + return new ServerInfo_Room(id, name, description, games.size(), size(), autoJoin, gameList, userList); +} + +void Server_Room::addClient(Server_ProtocolHandler *client) +{ + sendRoomEvent(new Event_JoinRoom(id, new ServerInfo_User(client->getUserInfo()))); + append(client); + + QList eventUserList; + for (int i = 0; i < size(); ++i) + eventUserList.append(new ServerInfo_User(at(i)->getUserInfo())); + + emit roomInfoChanged(); +} + +void Server_Room::removeClient(Server_ProtocolHandler *client) +{ + removeAt(indexOf(client)); + sendRoomEvent(new Event_LeaveRoom(id, client->getUserInfo()->getName())); + emit roomInfoChanged(); +} + +void Server_Room::say(Server_ProtocolHandler *client, const QString &s) +{ + sendRoomEvent(new Event_RoomSay(id, client->getUserInfo()->getName(), s)); +} + +void Server_Room::sendRoomEvent(RoomEvent *event) +{ + for (int i = 0; i < size(); ++i) + at(i)->sendProtocolItem(event, false); + delete event; +} + +void Server_Room::broadcastGameListUpdate(Server_Game *game) +{ + Event_ListGames *event = new Event_ListGames(id, QList() << game->getInfo()); + + for (int i = 0; i < size(); i++) + at(i)->sendProtocolItem(event, false); + delete event; +} + +Server_Game *Server_Room::createGame(const QString &description, const QString &password, int maxPlayers, bool spectatorsAllowed, bool spectatorsNeedPassword, bool spectatorsCanTalk, bool spectatorsSeeEverything, Server_ProtocolHandler *creator) +{ + Server_Game *newGame = new Server_Game(creator, static_cast(parent())->getNextGameId(), description, password, maxPlayers, spectatorsAllowed, spectatorsNeedPassword, spectatorsCanTalk, spectatorsSeeEverything, this); + games.insert(newGame->getGameId(), newGame); + connect(newGame, SIGNAL(gameClosing()), this, SLOT(removeGame())); + + broadcastGameListUpdate(newGame); + + emit gameCreated(newGame); + emit roomInfoChanged(); + + return newGame; +} + +void Server_Room::removeGame() +{ + Server_Game *game = static_cast(sender()); + broadcastGameListUpdate(game); + games.remove(game->getGameId()); + + emit gameClosing(game->getGameId()); + emit roomInfoChanged(); +} diff --git a/common/server_room.h b/common/server_room.h new file mode 100644 index 00000000..3df55b87 --- /dev/null +++ b/common/server_room.h @@ -0,0 +1,51 @@ +#ifndef SERVER_ROOM_H +#define SERVER_ROOM_H + +#include +#include +#include +#include + +class Server_ProtocolHandler; +class RoomEvent; +class ServerInfo_User; +class ServerInfo_Room; +class Server_Game; +class Server; + +class Server_Room : public QObject, public QList { + Q_OBJECT +signals: + void roomInfoChanged(); + void gameCreated(Server_Game *game); + void gameClosing(int gameId); +private: + int id; + QString name; + QString description; + bool autoJoin; + QString joinMessage; + QMap games; +private slots: + void removeGame(); +public: + Server_Room(int _id, const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage, Server *parent); + int getId() const { return id; } + QString getName() const { return name; } + QString getDescription() const { return description; } + bool getAutoJoin() const { return autoJoin; } + QString getJoinMessage() const { return joinMessage; } + const QMap &getGames() const { return games; } + Server *getServer() const; + ServerInfo_Room *getInfo(bool complete) const; + + void addClient(Server_ProtocolHandler *client); + void removeClient(Server_ProtocolHandler *client); + void say(Server_ProtocolHandler *client, const QString &s); + void broadcastGameListUpdate(Server_Game *game); + Server_Game *createGame(const QString &description, const QString &password, int maxPlayers, bool spectatorsAllowed, bool spectatorsNeedPassword, bool spectatorsCanTalk, bool spectatorsSeeEverything, Server_ProtocolHandler *creator); + + void sendRoomEvent(RoomEvent *event); +}; + +#endif diff --git a/oracle/src/oracleimporter.cpp b/oracle/src/oracleimporter.cpp index eb9847aa..70d44dfb 100644 --- a/oracle/src/oracleimporter.cpp +++ b/oracle/src/oracleimporter.cpp @@ -196,6 +196,7 @@ QString OracleImporter::getURLFromName(QString name) const return pictureUrl.arg( name .replace("Æther", "Aether") + .replace("ö", "o") .remove('\'') .remove("//") .remove(',') diff --git a/servatrice/servatrice.ini.example b/servatrice/servatrice.ini.example index e75d0c45..e9d1246e 100644 --- a/servatrice/servatrice.ini.example +++ b/servatrice/servatrice.ini.example @@ -1,5 +1,6 @@ [server] port=4747 +statusupdate=15000 [authentication] method=none @@ -12,15 +13,12 @@ database=servatrice user=servatrice password=foobar -[messages] -login="Example line" - -[chatchannels] +[rooms] size=1 -1\name="General Chat" -1\description="Discuss anything here." +1\name="General room" +1\description="Play anything here." 1\autojoin=true -1\joinmessage="This is the general chat channel. This message is only here to show that channels can have a join message." +1\joinmessage="This message is only here to show that rooms can have a join message." [game] max_game_inactivity_time=120 diff --git a/servatrice/servatrice.pro b/servatrice/servatrice.pro index d89ecf08..9f7fcc70 100755 --- a/servatrice/servatrice.pro +++ b/servatrice/servatrice.pro @@ -27,7 +27,7 @@ HEADERS += src/servatrice.h \ ../common/server_arrow.h \ ../common/server_card.h \ ../common/server_cardzone.h \ - ../common/server_chatchannel.h \ + ../common/server_room.h \ ../common/server_counter.h \ ../common/server_game.h \ ../common/server_player.h \ @@ -48,7 +48,7 @@ SOURCES += src/main.cpp \ ../common/server.cpp \ ../common/server_card.cpp \ ../common/server_cardzone.cpp \ - ../common/server_chatchannel.cpp \ + ../common/server_room.cpp \ ../common/server_game.cpp \ ../common/server_player.cpp \ ../common/server_protocolhandler.cpp diff --git a/servatrice/src/servatrice.cpp b/servatrice/src/servatrice.cpp index 4be6b7f3..c2637d09 100644 --- a/servatrice/src/servatrice.cpp +++ b/servatrice/src/servatrice.cpp @@ -22,7 +22,7 @@ #include #include #include "servatrice.h" -#include "server_chatchannel.h" +#include "server_room.h" #include "serversocketinterface.h" #include "protocol.h" @@ -33,36 +33,44 @@ Servatrice::Servatrice(QObject *parent) connect(pingClock, SIGNAL(timeout()), this, SIGNAL(pingClockTimeout())); pingClock->start(1000); - statusUpdateClock = new QTimer(this); - connect(statusUpdateClock, SIGNAL(timeout()), this, SLOT(statusUpdate())); - statusUpdateClock->start(15000); - ProtocolItem::initializeHash(); settings = new QSettings("servatrice.ini", QSettings::IniFormat, this); + int statusUpdateTime = settings->value("server/statusupdate").toInt(); + statusUpdateClock = new QTimer(this); + connect(statusUpdateClock, SIGNAL(timeout()), this, SLOT(statusUpdate())); + if (statusUpdateTime != 0) { + qDebug() << "Starting status update clock, interval " << statusUpdateTime << " ms"; + statusUpdateClock->start(statusUpdateTime); + } + tcpServer = new QTcpServer(this); connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection())); - tcpServer->listen(QHostAddress::Any, settings->value("server/port", 4747).toInt()); + int port = settings->value("server/port", 4747).toInt(); + qDebug() << "Starting server on port" << port; + tcpServer->listen(QHostAddress::Any, port); QString dbType = settings->value("database/type").toString(); dbPrefix = settings->value("database/prefix").toString(); if (dbType == "mysql") openDatabase(); - int size = settings->beginReadArray("chatchannels"); + int size = settings->beginReadArray("rooms"); for (int i = 0; i < size; ++i) { settings->setArrayIndex(i); - Server_ChatChannel *newChannel = new Server_ChatChannel( + Server_Room *newRoom = new Server_Room( + i, settings->value("name").toString(), settings->value("description").toString(), settings->value("autojoin").toBool(), - settings->value("joinmessage").toString() + settings->value("joinmessage").toString(), + this ); - addChatChannel(newChannel); + addRoom(newRoom); } settings->endArray(); - loginMessage = settings->value("messages/login").toString(); + updateLoginMessage(); maxGameInactivityTime = settings->value("game/max_game_inactivity_time").toInt(); maxPlayerInactivityTime = settings->value("game/max_player_inactivity_time").toInt(); @@ -157,15 +165,16 @@ ServerInfo_User *Servatrice::getUserData(const QString &name) checkSql(); QSqlQuery query; - query.prepare("select admin, country, avatar_bmp from " + dbPrefix + "_users where name = :name and active = 1"); + query.prepare("select admin, realname, country, avatar_bmp from " + dbPrefix + "_users where name = :name and active = 1"); query.bindValue(":name", name); if (!execSqlQuery(query)) return new ServerInfo_User(name, ServerInfo_User::IsUser); if (query.next()) { bool is_admin = query.value(0).toInt(); - QString country = query.value(1).toString(); - QByteArray avatarBmp = query.value(2).toByteArray(); + QString realName = query.value(1).toString(); + QString country = query.value(2).toString(); + QByteArray avatarBmp = query.value(3).toByteArray(); int userLevel = ServerInfo_User::IsUser | ServerInfo_User::IsRegistered; if (is_admin) @@ -174,6 +183,7 @@ ServerInfo_User *Servatrice::getUserData(const QString &name) return new ServerInfo_User( name, userLevel, + realName, country, avatarBmp ); @@ -183,6 +193,24 @@ ServerInfo_User *Servatrice::getUserData(const QString &name) return new ServerInfo_User(name, ServerInfo_User::IsUser); } +void Servatrice::updateLoginMessage() +{ + checkSql(); + QSqlQuery query; + query.prepare("select message from " + dbPrefix + "_servermessages order by timest desc limit 1"); + if (execSqlQuery(query)) + if (query.next()) { + loginMessage = query.value(0).toString(); + + Event_ServerMessage *event = new Event_ServerMessage(loginMessage); + QMapIterator usersIterator(users); + while (usersIterator.hasNext()) { + usersIterator.next().value()->sendProtocolItem(event, false); + } + delete event; + } +} + void Servatrice::statusUpdate() { uptime += statusUpdateClock->interval() / 1000; @@ -197,4 +225,4 @@ void Servatrice::statusUpdate() execSqlQuery(query); } -const QString Servatrice::versionString = "Servatrice 0.20101116"; +const QString Servatrice::versionString = "Servatrice 0.20110114"; diff --git a/servatrice/src/servatrice.h b/servatrice/src/servatrice.h index 39a1a1a6..479af4fd 100644 --- a/servatrice/src/servatrice.h +++ b/servatrice/src/servatrice.h @@ -46,6 +46,7 @@ public: int getMaxGameInactivityTime() const { return maxGameInactivityTime; } int getMaxPlayerInactivityTime() const { return maxPlayerInactivityTime; } QString getDbPrefix() const { return dbPrefix; } + void updateLoginMessage(); protected: AuthenticationResult checkUserPassword(const QString &user, const QString &password); ServerInfo_User *getUserData(const QString &name); diff --git a/servatrice/src/serversocketinterface.cpp b/servatrice/src/serversocketinterface.cpp index a57a660c..44cf4729 100644 --- a/servatrice/src/serversocketinterface.cpp +++ b/servatrice/src/serversocketinterface.cpp @@ -34,7 +34,6 @@ ServerSocketInterface::ServerSocketInterface(Servatrice *_server, QTcpSocket *_s { xmlWriter = new QXmlStreamWriter; xmlWriter->setDevice(socket); - xmlWriter->setAutoFormatting(true); xmlReader = new QXmlStreamReader; @@ -324,3 +323,12 @@ ResponseCode ServerSocketInterface::cmdDeckDownload(Command_DeckDownload *cmd, C cont->setResponse(new Response_DeckDownload(cont->getCmdId(), RespOk, deck)); return RespNothing; } + +// ADMIN FUNCTIONS. +// Permission is checked by the calling function. + +ResponseCode ServerSocketInterface::cmdUpdateServerMessage(Command_UpdateServerMessage *cmd, CommandContainer *cont) +{ + servatrice->updateLoginMessage(); + return RespOk; +} diff --git a/servatrice/src/serversocketinterface.h b/servatrice/src/serversocketinterface.h index b5286dd7..d496026e 100644 --- a/servatrice/src/serversocketinterface.h +++ b/servatrice/src/serversocketinterface.h @@ -55,6 +55,7 @@ private: ResponseCode cmdDeckUpload(Command_DeckUpload *cmd, CommandContainer *cont); DeckList *getDeckFromDatabase(int deckId); ResponseCode cmdDeckDownload(Command_DeckDownload *cmd, CommandContainer *cont); + ResponseCode cmdUpdateServerMessage(Command_UpdateServerMessage *cmd, CommandContainer *cont); public: ServerSocketInterface(Servatrice *_server, QTcpSocket *_socket, QObject *parent = 0); ~ServerSocketInterface();